SHA1 Attack Program

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

adresd
Posts: 43
Joined: Sat Jan 17, 2004 11:32 am

Post by adresd »

Much congrats to djhuevo on the faster SHA1 algorithm for the search.

I have combined this with a more cache friendly searchtable, the result is here:

Code: Select all

Edited - see below for newer version of code
loser pointed out that for msvc++ you may also need time.h and malloc.h, see the comments in the code.


Have fun.
Last edited by adresd on Tue Jun 14, 2005 12:44 am, edited 1 time in total.
User avatar
Drakonite
Site Admin
Posts: 990
Joined: Sat Jan 17, 2004 1:30 am
Contact:

Post by Drakonite »

I just did a bit of performance testing on the new version to work out the best optimization flags.

If it matters, tests were performed on a athlon XP running at 2Ghz with virtually zero cpu usage in the background, compiled with gcc 3.3.5 (except for the icc test which was compiled with icc 7.1) Extra debug output was added to aid timing which ultimately causes a lower speed.

All tests with any optimization level set were around 2 million checks/sec. The difference between the worst (gcc -Os) and best (icc -O2) was about 200,000 checks/sec.

-march=athlon-xp and -fomit-frame-pointers both made large impacts in all cases.
-fomit-frame-pointer increased speed by over 45,500 checks/sec
-march=athlon-xp increased speed by around 10,000 checks/sec

-O2 was faster than -O3 in almost all tests by around 15,000 to 25,000 checks/sec though there was a lot of variance between tests. Possibly an anomoly but worth noting, though -O2 was typically faster, in one of the longer tests -O3 outperformed -O2 by around 10,000 check/sec.

Judging from the high variance in difference between -O2 and -O3 it seems numerous factors, including background processes and dictionary contents, have a noticable impact on the effectiveness of the optimization levels.

adresd reported a 13% decrease in running time on his test case while using -O2 as opposed to -O3 which leads me to believe the extra debug output I added was destroying part of -O2's cache advantage, which means the one case -O3 was faster could likely have been caused by the debug output.

Even without knowing much about it's optimization options icc beat out the best gcc scores by over 100,000 checks/sec.

So in summary, unless you have a binary compiled with icc, 'gcc -O2 -fomit-frame-pointer -march=athlon-xp' (replace athlon-xp with your cpu) should give significantly faster results, at least in most cases.
Shoot Pixels Not People!
Makeshift Development
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Post by mrbrown »

You can use gprof to give you accurate function-level profiling. Compile nidattack with "gcc -pg <optimizations>" without -fomit-frame-pointer. After your test run has completed, run "gprof -b -Q <path to nidattack executable>" to get the timing results.

In my tests, the fastSHA1() code takes up ~93% of execution time, so it's still the biggest bottleneck.
Guest

Post by Guest »

This added part of fastSHA1 appears (to the eyes) to be destructive:

Code: Select all

    buffer&#91;len&#93;=0x80;
    buffer&#91;62&#93;=&#40;len*8&#41;>>8;
    buffer&#91;63&#93;=&#40;len*8&#41;&0xff; 
Since every single character of buffer[] is significant to the outcome of the SHA1 transform, this should by all rights be destructive, completely changing every character of the the resulting transform.

But supposedly people are seeing no problems with fastSHA1 as a result. Can anyone explain why this was added to the recent code ?
loser
Posts: 25
Joined: Mon Feb 07, 2005 10:27 am
Contact:

Post by loser »

yeh i noticed that in 'release config' in msvc++ it didnt work correctly, but in 'debug config' it did. after adding the memsets to buffer and buffer2 at the top it seemed to work. that was more of a quick fix tho; this part you point out is prolly what really needs fixing
Warren
Posts: 175
Joined: Sat Jan 24, 2004 8:26 am
Location: San Diego, CA

Post by Warren »

In response to Gorim: that part is in fact a part of the SHA1 spec and is usally done in SHA1_Final. fastSHA1 as a whole looks really weird as it's all of the usual SHA1_* funcs mashed into one func and optimised for 62 char or less buffers. I found that out looking at integrating openSSL's assembly implementation of SHA1 into nidAttack.
Guest

Post by Guest »

Ahh understood now. Thanks! :)
djhuevo
Posts: 47
Joined: Thu Mar 10, 2005 3:50 pm

Post by djhuevo »

gorim wrote: But supposedly people are seeing no problems with fastSHA1 as a result. Can anyone explain why this was added to the recent code ?
this fast implementation has the limitation of hash upto 55 characters.
buffers longer than 55 bytes are hashed wrong...
Last edited by djhuevo on Tue Jun 07, 2005 2:04 pm, edited 1 time in total.
sobreviviendo en la tierra de los trolldev
Guest

Post by Guest »

Which brings up another thing...

We are doing lots of optimizing mods. It would be good to build in a "test" string analysis so that the program can automatically verify for itself that it will produce correct results.

As I am currently doing some other mods I will take a look at this, but don't let that hold back anyone who wants to do it sooner. :)
ooPo
Site Admin
Posts: 2023
Joined: Sat Jan 17, 2004 9:56 am
Location: Canada
Contact:

Post by ooPo »

pspdev: the search for a better password cracker

Sheesh. :)
Guest

Post by Guest »

Ok I still have one concern.

The latest code in CVS still produces different results than the code Adresd posted at the beginning of this topic. (as of last night's cvs version).

Basically, given the same test dictionary of 40-50 words, hashlist, and prefix, run against both programs, they find completely different hits.

Could someone else please check if they can see the same thing I am ? I am concerned about this inconsistancy...
adresd
Posts: 43
Joined: Sat Jan 17, 2004 11:32 am

Post by adresd »

I have been concerned by recent events. So started digging.

The result is here is a new version to try.

Added:
-Sanity check to SHA1 algos on startup, runtime, to make sure the return values are valid.
-Added a seperate dictionary for the 'firstword' of each string.
-nidstatus.tmp file, to track progress through firstword dictionary. Delete this file to restart a run.
-Resume function tied to above, starts at the word after the last fully completed word in the firstword dictionary.
-Splitting of results into seperate files for each firstword.
-Optional check, on #define to skip already present results files, to re-run one, simply remove or rename the file, then rerun.
-Now uses the opted SHA1 for strings under 55 chars (pointed out by djhuevo), and the reference one for strings over that length.

Commandline params are now:
<hash_list> <dictionaryfirst> <dictionarymain> [prefix]

prefix being optional.

dictionaryfirst is the firstword dictionary, and dictionarymain is the dictionary used for the later words in the string..
This dramatically cuts down the searchspace and time, and given most prefixes are amongst a small list, should aid the effort somewhat.

If run with no params, it will run the sanity check and display the result.

Thanks go to Drakonite for helping with debugging/testing.

Code: Select all

Edited - see below for newer version of code
Have fun.
Last edited by adresd on Tue Jun 14, 2005 12:45 am, edited 1 time in total.
Guest

Post by Guest »

Ok. I think the cause of my problem are endian issues. As always, I seem to be the first to try stuff on big-endian boxes. ;)

I will get back with y'all after the seek and destroy mission. Plus I hope to merge some more optimizations back in...
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Don't overexert yourself.

Post by mrbrown »

Note to those scrambling to find function names:

In case you missed it a NID is a 32-bit SHA1 hash value used to dynamically link functions and variables into a program. The majority of the time this hash value corresponds to the function name it belongs to, so sceUtilityGameSharingUpdate == 0x7853182D.

Because a NID is just a unique identifer within a library, it can be any value whatsoever, as long as the program refers to that function with the same NID. This means that NIDs do not have to correspond 1:1 with the real world function name. Sony can randomly generate NIDs and attach any function they want, and we'll never be able to figure out the real function name.

Just a heads up in case folks get stuck. I have yet to crack any of the NIDs found in the VSH modules. Has anyone else?
loser
Posts: 25
Joined: Mon Feb 07, 2005 10:27 am
Contact:

Post by loser »

wow newest version of sha1 attack goes really fast!
good work guys

sometimes i just want to check what the Nid would be for a function name without doing whole dictionary search things. i put up a html page to do this quickly and easily. this page calculates the Nid in javascript, so you should be able to save it locally to run it from your computer.

http://www.internalreality.com/nid.html
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

Post by PspPet »

> while ((hash[hashpos3++]&0xffffff00) < searchval);
BUG: no range checking on the 'hash' array. Applies to all 3 searches, and all versions.
May or may not bite you (depends on system memory management and luck and what garbage memory is past the end of the array)

Fix/Workaround (keeping the searches fast).
Change:
< hash = (unsigned int*)malloc(hash_count * sizeof(unsigned int));
To:
> hash = (unsigned int*)malloc((hash_count+1) * sizeof(unsigned int));
> hash[hash_count] = 0xFFFFFFFF; // end marker
Inopia
Posts: 1
Joined: Sun Jun 12, 2005 6:36 pm

Post by Inopia »

Hmm, has anyone of you guys even seen this?

http://www.antsight.com/zsl/rainbowcrack/

It's a generic method of reversing hashing algorithms such as sha1 and md5 by creating a huge-ass table. It can crack md5, as mr-t would put it, 'helluva fast'. You need to create a 300mb table first though, takes only a couple of hours :) It can be used to crack large quantities of hashes however.
Minor drawback is that the algorithm cannot guarantee a 100% succes rate on every hash because of the way the table is built.
Anyway, there's sourcecode that includes sha1, md5 and the thing can be extended to work with other algorithms if you please. The site also includes a paper on how it all works.

Perhaps you guys can use it :)
what is love, beep beep
adresd
Posts: 43
Joined: Sat Jan 17, 2004 11:32 am

Post by adresd »

Here is the latest version of the attack program.

Main change is: Big endian issues sorted, and now passing all sanity checks on both big and little endian.

for msvc and icc , change '__inline__' to '__inline'.
Thanks to loser and warren for this.

Thanks also to gorim for big endian testing.

Code: Select all

/*
SHA1 dictionary attack program v5.4 &#40;c&#41; 2005 adresd
based on original by djhuevo

Hash searchtable and other mods by adresd
Endian independant now, with sanity checks verified on both settings

No License, public domain, do as you want, no warranties
*/
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <malloc.h>
#include <stdlib.h>

// Comment this out for BIG endian machines
#define LITTLE_ENDIANESS
// This enables using both routines, if not enabled it will use the opted one as default
#define USEBOTHSHA1ROUTINES
// These are the sanity checks at startup
#define NEW_SHA1_CHECK
#define OLD_SHA1_CHECK
// This overrides all others, and forces using the reference implementation ALWAYS
//#define FORCE_USE_SLOW
// This forces skipping over words with an existing result file
//#define SKIP_EXISTING

#ifdef FORCE_USE_SLOW
#undef NEW_SHA1_CHECK
#endif

typedef char s8;
typedef short s16;
typedef int s32;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;

//
//  This is the original REFERENCE SHA-1 Algorithm
//
typedef struct &#123;
    unsigned long state&#91;5&#93;;
    unsigned long count&#91;2&#93;;
    unsigned char buffer&#91;64&#93;;
&#125; SHA1_CTX;

void SHA1Transform&#40;unsigned long state&#91;5&#93;, unsigned char buffer&#91;64&#93;&#41;;
void SHA1Init&#40;SHA1_CTX* context&#41;;
void SHA1Update&#40;SHA1_CTX* context, unsigned char* data, unsigned int len&#41;;
void SHA1Final&#40;unsigned char digest&#91;20&#93;, SHA1_CTX* context&#41;;

#define rol&#40;value, bits&#41; &#40;&#40;&#40;value&#41; << &#40;bits&#41;&#41; | &#40;&#40;value&#41; >> &#40;32 - &#40;bits&#41;&#41;&#41;&#41;

/* blk0&#40;&#41; and blk&#40;&#41; perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#ifdef LITTLE_ENDIANESS
#define blk0&#40;i&#41; &#40;block->l&#91;i&#93; = &#40;rol&#40;block->l&#91;i&#93;,24&#41;&0xFF00FF00&#41; \
    |&#40;rol&#40;block->l&#91;i&#93;,8&#41;&0x00FF00FF&#41;&#41;
#else
#define blk0&#40;i&#41; block->l&#91;i&#93;
#endif
#define blk&#40;i&#41; &#40;block->l&#91;i&15&#93; = rol&#40;block->l&#91;&#40;i+13&#41;&15&#93;^block->l&#91;&#40;i+8&#41;&15&#93; \
    ^block->l&#91;&#40;i+2&#41;&15&#93;^block->l&#91;i&15&#93;,1&#41;&#41;

/* &#40;R0+R1&#41;, R2, R3, R4 are the different operations used in SHA1 */
#define R0&#40;v,w,x,y,z,i&#41; z+=&#40;&#40;w&&#40;x^y&#41;&#41;^y&#41;+blk0&#40;i&#41;+0x5A827999+rol&#40;v,5&#41;;w=rol&#40;w,30&#41;;
#define R1&#40;v,w,x,y,z,i&#41; z+=&#40;&#40;w&&#40;x^y&#41;&#41;^y&#41;+blk&#40;i&#41;+0x5A827999+rol&#40;v,5&#41;;w=rol&#40;w,30&#41;;
#define R2&#40;v,w,x,y,z,i&#41; z+=&#40;w^x^y&#41;+blk&#40;i&#41;+0x6ED9EBA1+rol&#40;v,5&#41;;w=rol&#40;w,30&#41;;
#define R3&#40;v,w,x,y,z,i&#41; z+=&#40;&#40;&#40;w|x&#41;&y&#41;|&#40;w&x&#41;&#41;+blk&#40;i&#41;+0x8F1BBCDC+rol&#40;v,5&#41;;w=rol&#40;w,30&#41;;
#define R4&#40;v,w,x,y,z,i&#41; z+=&#40;w^x^y&#41;+blk&#40;i&#41;+0xCA62C1D6+rol&#40;v,5&#41;;w=rol&#40;w,30&#41;;


/* Hash a single 512-bit block. This is the core of the algorithm. */

__inline__ void SHA1Transform&#40;unsigned long state&#91;5&#93;, unsigned char buffer&#91;64&#93;&#41;
&#123;
unsigned long a, b, c, d, e;
typedef union &#123;
    unsigned char c&#91;64&#93;;
    unsigned long l&#91;16&#93;;
&#125; CHAR64LONG16;
CHAR64LONG16* block;
#ifdef SHA1HANDSOFF
static unsigned char workspace&#91;64&#93;;
    block = &#40;CHAR64LONG16*&#41;workspace;
    memcpy&#40;block, buffer, 64&#41;;
#else
    block = &#40;CHAR64LONG16*&#41;buffer;
#endif
    /* Copy context->state&#91;&#93; to working vars */
    a = state&#91;0&#93;;
    b = state&#91;1&#93;;
    c = state&#91;2&#93;;
    d = state&#91;3&#93;;
    e = state&#91;4&#93;;
    /* 4 rounds of 20 operations each. Loop unrolled. */
    R0&#40;a,b,c,d,e, 0&#41;; R0&#40;e,a,b,c,d, 1&#41;; R0&#40;d,e,a,b,c, 2&#41;; R0&#40;c,d,e,a,b, 3&#41;;
    R0&#40;b,c,d,e,a, 4&#41;; R0&#40;a,b,c,d,e, 5&#41;; R0&#40;e,a,b,c,d, 6&#41;; R0&#40;d,e,a,b,c, 7&#41;;
    R0&#40;c,d,e,a,b, 8&#41;; R0&#40;b,c,d,e,a, 9&#41;; R0&#40;a,b,c,d,e,10&#41;; R0&#40;e,a,b,c,d,11&#41;;
    R0&#40;d,e,a,b,c,12&#41;; R0&#40;c,d,e,a,b,13&#41;; R0&#40;b,c,d,e,a,14&#41;; R0&#40;a,b,c,d,e,15&#41;;
    R1&#40;e,a,b,c,d,16&#41;; R1&#40;d,e,a,b,c,17&#41;; R1&#40;c,d,e,a,b,18&#41;; R1&#40;b,c,d,e,a,19&#41;;
    R2&#40;a,b,c,d,e,20&#41;; R2&#40;e,a,b,c,d,21&#41;; R2&#40;d,e,a,b,c,22&#41;; R2&#40;c,d,e,a,b,23&#41;;
    R2&#40;b,c,d,e,a,24&#41;; R2&#40;a,b,c,d,e,25&#41;; R2&#40;e,a,b,c,d,26&#41;; R2&#40;d,e,a,b,c,27&#41;;
    R2&#40;c,d,e,a,b,28&#41;; R2&#40;b,c,d,e,a,29&#41;; R2&#40;a,b,c,d,e,30&#41;; R2&#40;e,a,b,c,d,31&#41;;
    R2&#40;d,e,a,b,c,32&#41;; R2&#40;c,d,e,a,b,33&#41;; R2&#40;b,c,d,e,a,34&#41;; R2&#40;a,b,c,d,e,35&#41;;
    R2&#40;e,a,b,c,d,36&#41;; R2&#40;d,e,a,b,c,37&#41;; R2&#40;c,d,e,a,b,38&#41;; R2&#40;b,c,d,e,a,39&#41;;
    R3&#40;a,b,c,d,e,40&#41;; R3&#40;e,a,b,c,d,41&#41;; R3&#40;d,e,a,b,c,42&#41;; R3&#40;c,d,e,a,b,43&#41;;
    R3&#40;b,c,d,e,a,44&#41;; R3&#40;a,b,c,d,e,45&#41;; R3&#40;e,a,b,c,d,46&#41;; R3&#40;d,e,a,b,c,47&#41;;
    R3&#40;c,d,e,a,b,48&#41;; R3&#40;b,c,d,e,a,49&#41;; R3&#40;a,b,c,d,e,50&#41;; R3&#40;e,a,b,c,d,51&#41;;
    R3&#40;d,e,a,b,c,52&#41;; R3&#40;c,d,e,a,b,53&#41;; R3&#40;b,c,d,e,a,54&#41;; R3&#40;a,b,c,d,e,55&#41;;
    R3&#40;e,a,b,c,d,56&#41;; R3&#40;d,e,a,b,c,57&#41;; R3&#40;c,d,e,a,b,58&#41;; R3&#40;b,c,d,e,a,59&#41;;
    R4&#40;a,b,c,d,e,60&#41;; R4&#40;e,a,b,c,d,61&#41;; R4&#40;d,e,a,b,c,62&#41;; R4&#40;c,d,e,a,b,63&#41;;
    R4&#40;b,c,d,e,a,64&#41;; R4&#40;a,b,c,d,e,65&#41;; R4&#40;e,a,b,c,d,66&#41;; R4&#40;d,e,a,b,c,67&#41;;
    R4&#40;c,d,e,a,b,68&#41;; R4&#40;b,c,d,e,a,69&#41;; R4&#40;a,b,c,d,e,70&#41;; R4&#40;e,a,b,c,d,71&#41;;
    R4&#40;d,e,a,b,c,72&#41;; R4&#40;c,d,e,a,b,73&#41;; R4&#40;b,c,d,e,a,74&#41;; R4&#40;a,b,c,d,e,75&#41;;
    R4&#40;e,a,b,c,d,76&#41;; R4&#40;d,e,a,b,c,77&#41;; R4&#40;c,d,e,a,b,78&#41;; R4&#40;b,c,d,e,a,79&#41;;
    /* Add the working vars back into context.state&#91;&#93; */
    state&#91;0&#93; += a;
    state&#91;1&#93; += b;
    state&#91;2&#93; += c;
    state&#91;3&#93; += d;
    state&#91;4&#93; += e;
    /* Wipe variables */
    a = b = c = d = e = 0;
&#125;


/* SHA1Init - Initialize new context */

__inline__ void SHA1Init&#40;SHA1_CTX* context&#41;
&#123;
    /* SHA1 initialization constants */
    context->state&#91;0&#93; = 0x67452301;
    context->state&#91;1&#93; = 0xEFCDAB89;
    context->state&#91;2&#93; = 0x98BADCFE;
    context->state&#91;3&#93; = 0x10325476;
    context->state&#91;4&#93; = 0xC3D2E1F0;
    context->count&#91;0&#93; = context->count&#91;1&#93; = 0;
&#125;


/* Run your data through this. */

__inline__ void SHA1Update&#40;SHA1_CTX* context, unsigned char* data, unsigned int len&#41;
&#123;
unsigned int i, j;

    j = &#40;context->count&#91;0&#93; >> 3&#41; & 63;
    if &#40;&#40;context->count&#91;0&#93; += len << 3&#41; < &#40;len << 3&#41;&#41; context->count&#91;1&#93;++;
    context->count&#91;1&#93; += &#40;len >> 29&#41;;
    if &#40;&#40;j + len&#41; > 63&#41; &#123;
        memcpy&#40;&context->buffer&#91;j&#93;, data, &#40;i = 64-j&#41;&#41;;
        SHA1Transform&#40;context->state, context->buffer&#41;;
        for &#40; ; i + 63 < len; i += 64&#41; &#123;
            SHA1Transform&#40;context->state, &data&#91;i&#93;&#41;;
        &#125;
        j = 0;
    &#125;
    else i = 0;
    memcpy&#40;&context->buffer&#91;j&#93;, &data&#91;i&#93;, len - i&#41;;
&#125;


/* Add padding and return the message digest. */

__inline__ void SHA1Final&#40;unsigned char digest&#91;20&#93;, SHA1_CTX* context&#41;
&#123;
unsigned long i, j;
unsigned char finalcount&#91;8&#93;;

    for &#40;i = 0; i < 8; i++&#41; &#123;
        finalcount&#91;i&#93; = &#40;unsigned char&#41;&#40;&#40;context->count&#91;&#40;i >= 4 ? 0 &#58; 1&#41;&#93;
         >> &#40;&#40;3-&#40;i & 3&#41;&#41; * 8&#41; &#41; & 255&#41;;  /* Endian independent */
    &#125;
    SHA1Update&#40;context, &#40;unsigned char *&#41;"\200", 1&#41;;
    while &#40;&#40;context->count&#91;0&#93; & 504&#41; != 448&#41; &#123;
        SHA1Update&#40;context, &#40;unsigned char *&#41;"\0", 1&#41;;
    &#125;
    SHA1Update&#40;context, finalcount, 8&#41;;  /* Should cause a SHA1Transform&#40;&#41; */
    for &#40;i = 0; i < 20; i++&#41; &#123;
        digest&#91;i&#93; = &#40;unsigned char&#41;
         &#40;&#40;context->state&#91;i>>2&#93; >> &#40;&#40;3-&#40;i & 3&#41;&#41; * 8&#41; &#41; & 255&#41;;
    &#125;
    /* Wipe variables */
    i = j = 0;
    memset&#40;context->buffer, 0, 64&#41;;
    memset&#40;context->state, 0, 20&#41;;
    memset&#40;context->count, 0, 8&#41;;
    memset&#40;&finalcount, 0, 8&#41;;
#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */
    SHA1Transform&#40;context->state, context->buffer&#41;;
#endif
&#125;
__inline__ unsigned int hashSHA1&#40;char *buffer, SHA1_CTX *context, int size&#41; 
&#123;
  unsigned char digest&#91;20&#93;;
  SHA1Init&#40;context&#41;;        
  SHA1Update&#40;context, buffer, size&#41;;
  SHA1Final&#40;digest, context&#41;;
#ifdef LITTLE_ENDIANESS
  return *&#40;&#40;unsigned int *&#41;digest&#41;;
#else
  &#123; // Swap the bytes around
    unsigned int temp = *&#40;&#40;unsigned int *&#41;digest&#41;;
    return &#40; &#40;&#40;temp&0xff000000&#41;>>24&#41; | &#40;&#40;temp&0x00ff0000&#41;>>8&#41; | &#40;&#40;temp&0x0000ff00&#41;<<8&#41; | &#40;&#40;temp&0x000000ff&#41;<<24&#41; &#41;;
  &#125;
#endif
&#125;
SHA1_CTX context;

//
//  This is the OPTIMISED SHA-1 Algorithm
//
/*
SHA-1 based on Steve Reid SHA1 code <[email protected]>
*/
#define o_rol&#40;value, bits&#41; &#40;&#40;&#40;value&#41; << &#40;bits&#41;&#41; | &#40;&#40;value&#41; >> &#40;32 - &#40;bits&#41;&#41;&#41;&#41;

/* blk0&#40;&#41; and blk&#40;&#41; perform the initial expand. */
/* I got the idea of expanding during the round function from SSLeay */
#ifdef LITTLE_ENDIANESS
#define o_blk0&#40;i&#41; &#40;block&#91;i&#93; = &#40;o_rol&#40;block&#91;i&#93;,24&#41;&0xFF00FF00&#41; \
    |&#40;o_rol&#40;block&#91;i&#93;,8&#41;&0x00FF00FF&#41;&#41;
#else
#define o_blk0&#40;i&#41; block&#91;i&#93;
#endif
#define o_blk&#40;i&#41; &#40;block&#91;i&15&#93; = o_rol&#40;block&#91;&#40;i+13&#41;&15&#93;^block&#91;&#40;i+8&#41;&15&#93; \
    ^block&#91;&#40;i+2&#41;&15&#93;^block&#91;i&15&#93;,1&#41;&#41;

/* &#40;R0+R1&#41;, R2, R3, R4 are the different operations used in SHA1 */
#define o_R0&#40;v,w,x,y,z,i&#41; z+=&#40;&#40;w&&#40;x^y&#41;&#41;^y&#41;+o_blk0&#40;i&#41;+0x5A827999+o_rol&#40;v,5&#41;;w=o_rol&#40;w,30&#41;;
#define o_R1&#40;v,w,x,y,z,i&#41; z+=&#40;&#40;w&&#40;x^y&#41;&#41;^y&#41;+o_blk&#40;i&#41;+0x5A827999+o_rol&#40;v,5&#41;;w=o_rol&#40;w,30&#41;;
#define o_R2&#40;v,w,x,y,z,i&#41; z+=&#40;w^x^y&#41;+o_blk&#40;i&#41;+0x6ED9EBA1+o_rol&#40;v,5&#41;;w=o_rol&#40;w,30&#41;;
#define o_R3&#40;v,w,x,y,z,i&#41; z+=&#40;&#40;&#40;w|x&#41;&y&#41;|&#40;w&x&#41;&#41;+o_blk&#40;i&#41;+0x8F1BBCDC+o_rol&#40;v,5&#41;;w=o_rol&#40;w,30&#41;;
#define o_R4&#40;v,w,x,y,z,i&#41; z+=&#40;w^x^y&#41;+o_blk&#40;i&#41;+0xCA62C1D6+o_rol&#40;v,5&#41;;w=rol&#40;w,30&#41;;

u32 fastSHA1&#40;unsigned char *buffer,int len&#41; &#123;
    u8 buf&#91;64&#93;;
    s32 i;
    u32 a, b, c, d, e;
    u32 *block;
    int len2;
    len2 = len;
    if &#40;len2 > 63&#41; len2 = 63;

    memcpy&#40;buf, buffer, len2&#41;;
    block=&#40;u32 *&#41;buf;

    for&#40;i=len2; i<=63; i++&#41; &#123;
      buf&#91;i&#93;=0x00;
    &#125;

    buf&#91;len2&#93;=0x80;
    buf&#91;62&#93;=&#40;len2*8&#41;>>8;
    buf&#91;63&#93;=&#40;len2*8&#41;&0xff;

    a = 0x67452301;
    b = 0xEFCDAB89;
    c = 0x98BADCFE;
    d = 0x10325476;
    e = 0xC3D2E1F0;

    /* 4 rounds of 20 operations each. Loop unrolled. */
    o_R0&#40;a,b,c,d,e, 0&#41;; o_R0&#40;e,a,b,c,d, 1&#41;; o_R0&#40;d,e,a,b,c, 2&#41;; o_R0&#40;c,d,e,a,b, 3&#41;;
    o_R0&#40;b,c,d,e,a, 4&#41;; o_R0&#40;a,b,c,d,e, 5&#41;; o_R0&#40;e,a,b,c,d, 6&#41;; o_R0&#40;d,e,a,b,c, 7&#41;;
    o_R0&#40;c,d,e,a,b, 8&#41;; o_R0&#40;b,c,d,e,a, 9&#41;; o_R0&#40;a,b,c,d,e,10&#41;; o_R0&#40;e,a,b,c,d,11&#41;;
    o_R0&#40;d,e,a,b,c,12&#41;; o_R0&#40;c,d,e,a,b,13&#41;; o_R0&#40;b,c,d,e,a,14&#41;; o_R0&#40;a,b,c,d,e,15&#41;;
    o_R1&#40;e,a,b,c,d,16&#41;; o_R1&#40;d,e,a,b,c,17&#41;; o_R1&#40;c,d,e,a,b,18&#41;; o_R1&#40;b,c,d,e,a,19&#41;;
    o_R2&#40;a,b,c,d,e,20&#41;; o_R2&#40;e,a,b,c,d,21&#41;; o_R2&#40;d,e,a,b,c,22&#41;; o_R2&#40;c,d,e,a,b,23&#41;;
    o_R2&#40;b,c,d,e,a,24&#41;; o_R2&#40;a,b,c,d,e,25&#41;; o_R2&#40;e,a,b,c,d,26&#41;; o_R2&#40;d,e,a,b,c,27&#41;;
    o_R2&#40;c,d,e,a,b,28&#41;; o_R2&#40;b,c,d,e,a,29&#41;; o_R2&#40;a,b,c,d,e,30&#41;; o_R2&#40;e,a,b,c,d,31&#41;;
    o_R2&#40;d,e,a,b,c,32&#41;; o_R2&#40;c,d,e,a,b,33&#41;; o_R2&#40;b,c,d,e,a,34&#41;; o_R2&#40;a,b,c,d,e,35&#41;;
    o_R2&#40;e,a,b,c,d,36&#41;; o_R2&#40;d,e,a,b,c,37&#41;; o_R2&#40;c,d,e,a,b,38&#41;; o_R2&#40;b,c,d,e,a,39&#41;;
    o_R3&#40;a,b,c,d,e,40&#41;; o_R3&#40;e,a,b,c,d,41&#41;; o_R3&#40;d,e,a,b,c,42&#41;; o_R3&#40;c,d,e,a,b,43&#41;;
    o_R3&#40;b,c,d,e,a,44&#41;; o_R3&#40;a,b,c,d,e,45&#41;; o_R3&#40;e,a,b,c,d,46&#41;; o_R3&#40;d,e,a,b,c,47&#41;;
    o_R3&#40;c,d,e,a,b,48&#41;; o_R3&#40;b,c,d,e,a,49&#41;; o_R3&#40;a,b,c,d,e,50&#41;; o_R3&#40;e,a,b,c,d,51&#41;;
    o_R3&#40;d,e,a,b,c,52&#41;; o_R3&#40;c,d,e,a,b,53&#41;; o_R3&#40;b,c,d,e,a,54&#41;; o_R3&#40;a,b,c,d,e,55&#41;;
    o_R3&#40;e,a,b,c,d,56&#41;; o_R3&#40;d,e,a,b,c,57&#41;; o_R3&#40;c,d,e,a,b,58&#41;; o_R3&#40;b,c,d,e,a,59&#41;;
    o_R4&#40;a,b,c,d,e,60&#41;; o_R4&#40;e,a,b,c,d,61&#41;; o_R4&#40;d,e,a,b,c,62&#41;; o_R4&#40;c,d,e,a,b,63&#41;;
    o_R4&#40;b,c,d,e,a,64&#41;; o_R4&#40;a,b,c,d,e,65&#41;; o_R4&#40;e,a,b,c,d,66&#41;; o_R4&#40;d,e,a,b,c,67&#41;;
    o_R4&#40;c,d,e,a,b,68&#41;; o_R4&#40;b,c,d,e,a,69&#41;; o_R4&#40;a,b,c,d,e,70&#41;; o_R4&#40;e,a,b,c,d,71&#41;;
    o_R4&#40;d,e,a,b,c,72&#41;; o_R4&#40;c,d,e,a,b,73&#41;; o_R4&#40;b,c,d,e,a,74&#41;; o_R4&#40;a,b,c,d,e,75&#41;;
    o_R4&#40;e,a,b,c,d,76&#41;; o_R4&#40;d,e,a,b,c,77&#41;; o_R4&#40;c,d,e,a,b,78&#41;; o_R4&#40;b,c,d,e,a,79&#41;;

    a+=0x67452301;     
    // Swap the bytes around
    return &#40;a>>24&#41;|&#40;&#40;a>>8&#41;&0xff00&#41;|&#40;&#40;a<<8&#41;&0xff0000&#41;|&#40;&#40;a<<24&#41;&#41;;
&#125;

typedef struct &#123;
char **dict;
char *dict_member_length;
int dict_count;
&#125; dictionary_struct;

dictionary_struct dicfirstword,dicmain;

unsigned int *hash;
int hash_count;

int load_hash_list&#40;char *filename&#41;
&#123;
  int i;
  unsigned int t;
  FILE *fp;
  printf&#40;"Reading hash file '%s'\n", filename&#41;;
  if &#40;&#40;fp = fopen&#40;filename, "rt"&#41;&#41; == NULL&#41;
    return -1;
  hash_count = 0;
  while &#40;fscanf&#40;fp, "0x%x\n", &t&#41; == 1&#41;
    hash_count++;
  printf&#40;"hash_count = %d\n", hash_count&#41;;
  fseek&#40;fp, 0, SEEK_SET&#41;;
  hash = malloc&#40;hash_count * sizeof&#40;unsigned int&#41;&#41;;
  i = 0;
  while &#40;fscanf&#40;fp, "0x%x\n", &hash&#91;i++&#93;&#41; == 1&#41;;
  fclose&#40;fp&#41;;
  return 0;
&#125;

int load_dictionary&#40;dictionary_struct *dic,char *filename&#41;
&#123;
  int i;
  char buffer&#91;0x200&#93;;
  FILE *fp;
  printf&#40;"Reading dictionary file '%s'\n", filename&#41;;
  if &#40;&#40;fp = fopen&#40;filename, "rt"&#41;&#41; == NULL&#41;
    return -1;
  dic->dict_count = 0;
  while &#40;fscanf&#40;fp, "%s\n", buffer&#41; != EOF&#41;
    dic->dict_count++;
  printf&#40;"dict_count = %d\n", dic->dict_count&#41;;
  fseek&#40;fp, 0, SEEK_SET&#41;;
  dic->dict = &#40;char **&#41; malloc&#40;dic->dict_count * sizeof&#40;char *&#41;&#41;;
  dic->dict_member_length = malloc&#40;dic->dict_count&#41;;
  i = 0;
  while &#40;fscanf&#40;fp, "%s\n", buffer&#41; == 1&#41; &#123;
    if &#40;&#40;buffer&#91;0&#93; == '-'&#41; || &#40;buffer&#91;0&#93; == '/'&#41;&#41; &#123; // This handles comments in the dic file
    &#125; else &#123;        // Not a comment, so do duplicate check
      int count;
      int found = 0;
      for &#40;count = 0; count < &#40;i - 1&#41;; count++&#41;
        if &#40;strcmp&#40;buffer, dic->dict&#91;count&#93;&#41; == 0&#41;
          found = 1;
      if &#40;found == 0&#41; &#123; // If not already in dictionary, then add
        dic->dict_member_length&#91;i&#93; = strlen&#40;buffer&#41;;
        dic->dict&#91;i&#93; = malloc&#40;dic->dict_member_length&#91;i&#93; + 1&#41;;
        strcpy&#40;dic->dict&#91;i&#93;, buffer&#41;;
        i++;
      &#125;
    &#125;
  &#125;
  dic->dict_count = i;
  fclose&#40;fp&#41;;
  return 0;
&#125;

FILE *fout;

// Hash seems to be where the program spends most of its time, so we need to speedup the
// search somehow -  32 bit value, 4 bytes
// what we do, is pre-sort the hashlist, so they are in order AABBCCDD
// Then index each byte into the list, hence cutting down the search space considerably
#define VER2_SIZE  256
// midsearch should hopefully fit in cache, so will help quite a lot with rejection testing.
int midsearch&#91;VER2_SIZE*VER2_SIZE&#93;;
// bigsearch is really a cop out, will not fit in cache, but still quicker than checking many elements.
int bigsearch&#91;VER2_SIZE*VER2_SIZE*VER2_SIZE&#93;;

void fillsearchtable&#40;&#41;
&#123;
  unsigned int searchval;
  int hashpos,hashpos2,hashpos3;
  int count,count2,count3;
  int found = 1;
  // Firstly Sort the hashlist, order AABBCCDD
  printf&#40;"Sorting Hashlist\n"&#41;;
  while &#40;found == 1&#41; &#123;
    found = 0;
    for &#40;count=0;count<&#40;hash_count-1&#41;;count++&#41; &#123;
      if &#40;hash&#91;count&#93; > hash&#91;count+1&#93;&#41; &#123; //  swap entries if wrong way around
        unsigned int temp = hash&#91;count+1&#93;;
        hash&#91;count+1&#93; = hash&#91;count&#93;;
        hash&#91;count&#93; = temp;
        found = 1;
      &#125;
    &#125;
  &#125;
  // Really lazy slow clear array, but who cares only done once
  printf&#40;"Clearing Search Tree\n"&#41;;
  for &#40;count=0;count<&#40;VER2_SIZE*VER2_SIZE&#41;;count++&#41;
    midsearch&#91;count&#93; = -1;
  for &#40;count=0;count<&#40;VER2_SIZE*VER2_SIZE*VER2_SIZE&#41;;count++&#41;
    bigsearch&#91;count&#93; = -1;
  // Now build the toplevel &#40;first&#41; byte
  printf&#40;"Building Search Tree\n"&#41;;
  for &#40;count=0;count<256;count++&#41; &#123; //  Find the first firstbyte in the hashlist that matches this value
    hashpos = 0;
    searchval = &#40;count<<24&#41;;
    while &#40;&#40;hash&#91;hashpos++&#93;&0xff000000&#41; < searchval&#41;;
    hashpos--;
    if &#40;&#40;hash&#91;hashpos&#93;&0xff000000&#41; == searchval&#41; &#123; // Now Search for a twobyte combo
      for &#40;count2=0;count2<256;count2++&#41; &#123; //  Find the first secondbyte in the hashlist from this pos
        hashpos2 = hashpos;
        searchval = &#40;count<<24&#41; | &#40;count2<<16&#41;;
        while &#40;&#40;hash&#91;hashpos2++&#93;&0xffff0000&#41; < searchval&#41;;
        hashpos2--;
        if &#40;&#40;hash&#91;hashpos2&#93;&0xffff0000&#41; == searchval&#41; &#123; //  Add this entry
          midsearch&#91;&#40;count<<8&#41;+count2&#93; = hashpos2;

          // Now Search for a threebyte combo
          for &#40;count3=0;count3<256;count3++&#41; &#123; //  Find the first thirdbyte in the hashlist from this pos
            hashpos3 = hashpos2;
            searchval = &#40;count<<24&#41; | &#40;count2<<16&#41; | &#40;count3<<8&#41;;
            while &#40;&#40;hash&#91;hashpos3++&#93;&0xffffff00&#41; < searchval&#41;;
            hashpos3--;
            if &#40;&#40;hash&#91;hashpos3&#93;&0xffffff00&#41; == searchval&#41;
            &#123; //  Add this entry
              bigsearch&#91;&#40;count<<16&#41;+&#40;count2<<8&#41;+count3&#93; = hashpos2;
&#125; &#125; &#125; &#125; &#125; &#125; &#125;

int findhash&#40;char *buffer, int size&#41;
&#123;
  unsigned int hashvalue;
  int pos;
#ifdef FORCE_USE_SLOW
  hashvalue = hashSHA1&#40;buffer,&context, size&#41;;
#else
#ifdef USEBOTHSHA1ROUTINES
  if &#40;size < 55&#41;  // If small string, use the optimised version
    hashvalue = fastSHA1&#40;buffer, size&#41;;
  else  // else use the standard reference implementation
    hashvalue = hashSHA1&#40;buffer,&context, size&#41;;
#else
  hashvalue = fastSHA1&#40;buffer, size&#41;;
#endif
#endif
  //  get twobyte position
  pos = midsearch&#91;&#40;hashvalue &0xffff0000&#41;>>16&#93;;
  if &#40;pos != -1&#41; &#123; // Get threebyte position
    pos = bigsearch&#91;&#40;hashvalue &0xffffff00&#41;>>8&#93;;
    if &#40;pos != -1&#41; &#123; // Found a position, so search from here
      int h;
      for&#40;h=pos; h<hash_count; h++&#41; &#123;
        if &#40;hashvalue >= hash&#91;h&#93;&#41;
          if&#40;hashvalue == hash&#91;h&#93;&#41; &#123; //  If equal, found
            printf&#40;"0x%08x %s\n",hashvalue,buffer&#41;;
            fprintf&#40;fout,"<FUNC><NID>0x%08x</NID><NAME>%s</NAME></FUNC>\n",hashvalue,buffer&#41;;
            return 1;
          &#125; 
          else  //  If not, reject as above
            return 0;
  &#125; &#125; &#125;
  return 0;
&#125;

int sanity_SHA1&#40;char *teststring, unsigned int testhash&#41;
&#123;
 // As a first task, perform a sanity check, verify SHA1 routines
  unsigned int hashvalue1;
  unsigned int hashvalue2;
  unsigned int size;
  int failed = 0;

  size= strlen&#40;teststring&#41;;
  printf&#40;"Running SHA1 Check &#58; '%s'&#40;%d&#41;  ",teststring,size&#41;;
#ifdef OLD_SHA1_CHECK
  //  Check reference version
  hashvalue2 = hashSHA1&#40;teststring,&context, size&#41;;
  if &#40;hashvalue2 != testhash&#41; &#123;
    printf&#40;"\nReference Version Failed Sanity Check &#40;0x%08X&#41;\n",hashvalue2&#41;;
    failed = 1;
  &#125;
#endif
#ifdef NEW_SHA1_CHECK
  //  Check optimized version
  hashvalue1 = fastSHA1&#40;teststring, size&#41;;
  if &#40;hashvalue1 != testhash&#41; &#123;
    printf&#40;"\nOptimised Version Failed Sanity Check &#40;0x%08X&#41;\n",hashvalue1&#41;;
    failed = 1;
  &#125;
#endif
#ifdef NEW_SHA1_CHECK
#ifdef OLD_SHA1_CHECK
  //  Both Together, so check against each other
  if &#40;hashvalue1 != hashvalue2&#41; &#123;
    printf&#40;"\nSHA1 return values differ &#40;0x%08X&#41;,&#40;0x%08X&#41;\n",hashvalue1,hashvalue2&#41;;
    failed = 1;
  &#125;
#endif
#endif
  if &#40;failed == 0&#41;
    printf&#40;"- Sanity Check Passed\n"&#41;;
  else 
    printf&#40;"- Sanity Check Failed, should be 0x%08X\n",testhash&#41;;
  return failed;
&#125;

int main&#40;int argc, char **argv&#41;
&#123;
  int i; 
  int x, y, z, zz; 
  int firstword;
  char buffer&#91;0x200&#93;;
  time_t start, end;
  time_t start2, end2;
  char xmlfilename&#91;200&#93;;

  char *ptr, *ptr0, *ptr1, *ptr2, *ptr3;

  char *prefix = "";
  int prefixlen = 0;

  printf&#40;"SHA1 hash dictionary attack v5.4 by adresd\n"&#41;;
  printf&#40;"based on the original by djhuevo\n\n"&#41;;

  if &#40;argc == 2&#41; &#123;
    unsigned int hash;
    unsigned char *ptr = argv&#91;1&#93;;
    int length = strlen&#40;ptr&#41;;
#ifdef FORCE_USE_SLOW
    hash = hashSHA1&#40;ptr,&context, length&#41;;
#else
#ifdef USEBOTHSHA1ROUTINES
    if &#40;length > 55&#41;
      hash = hashSHA1&#40;ptr,&context, length&#41;;
    else
      hash = fastSHA1&#40;ptr, length&#41;;
#else
    hash = fastSHA1&#40;ptr, length&#41;;
#endif
#endif
    printf&#40;"Input string '%s'  - hash 0x%08X\n",ptr,hash&#41;;
    return&#40;0&#41;;
  &#125;
 
  &#123; //  Perform the sanity checks
    int failed = 0; // All test hashes under 55 chars so can check both old and new vers of SHA1 algo
    failed += sanity_SHA1&#40;"MyTestString",0x0CC01ABB&#41;;
    failed += sanity_SHA1&#40;"abc",0x363E99A9&#41;;
    failed += sanity_SHA1&#40;"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopn",0x2d96FE59&#41;;
    failed += sanity_SHA1&#40;"This!is+another_test*string$zebra@~&#125;&#123;@!!£'$^&*&#40;&#41;&#91;&#93;&#123;&#125;=",0x4916E3FD&#41;;
    if &#40;failed > 0&#41; 
    &#123;
      printf&#40;"\n\nFAILED SANITY CHECK!!!\n\n"&#41;;
      exit&#40;1&#41;;
    &#125;
    printf&#40;"\n"&#41;;
  &#125;

  if &#40;argc < 3&#41; &#123;
    printf&#40;"usage&#58;\n\t%s <hash_list> <dictionaryfirst> <dictionarymain> &#91;prefix&#93;\n", argv&#91;0&#93;&#41;;
    return 1;  
  &#125;

  if &#40;load_hash_list&#40;argv&#91;1&#93;&#41; < 0&#41; &#123;
    fprintf&#40;stderr, "can't open the hash file %s\n", argv&#91;1&#93;&#41;;
    return 2;  
  &#125;

  if &#40;load_dictionary&#40;&dicfirstword,argv&#91;2&#93;&#41; < 0&#41; &#123;
    fprintf&#40;stderr, "can't open the first word dictionary file %s\n", argv&#91;2&#93;&#41;;
    return 3;  
  &#125;

  if &#40;load_dictionary&#40;&dicmain,argv&#91;3&#93;&#41; < 0&#41; &#123;
    fprintf&#40;stderr, "can't open the main dictionary file %s\n", argv&#91;3&#93;&#41;;
    return 3;  
  &#125;

  if &#40;argc > 4&#41; &#123;
    prefix = argv&#91;4&#93;;
    strcpy&#40;buffer, prefix&#41;;
    prefixlen = strlen&#40;prefix&#41;;
  &#125;

  if &#40;hash_count < 1 || dicmain.dict_count < 1  || dicfirstword.dict_count < 1&#41; &#123;
    fprintf&#40;stderr, "error on input data.\n"&#41;;
    fprintf&#40;stderr, "hash_count = %d, dict_count = %d, dict_count = %d\n", hash_count, dicmain.dict_count,dicfirstword.dict_count&#41;;
    return 4;  
  &#125;
#ifdef FORCE_USE_SLOW
  printf&#40;"Forcing using REFERENCE SHA1 algo\n"&#41;;
#endif
  printf&#40;"\nprefix &#58; '%s'\n", prefix != "" ? prefix &#58; "<None>"&#41;;
  printf&#40;"hash count &#58; %d\n", hash_count&#41;;
  printf&#40;"dictionary words &#40;firstword&#41; &#58; %d\n", dicfirstword.dict_count&#41;;
  printf&#40;"dictionary words &#40;main&#41;      &#58; %d\n\n", dicmain.dict_count&#41;;

  fillsearchtable&#40;&#41;;

  firstword = 0;
  &#123; // Check for resuming a run
    FILE *fpt;
    if &#40;&#40;fpt = fopen&#40;"nidstatus.tmp", "rt"&#41;&#41; != NULL&#41; &#123;
      char bufferstr&#91;200&#93;;
      fscanf&#40;fpt,"%s",bufferstr&#41;;
      fclose&#40;fpt&#41;;
      //  Now find the string in dic
      for &#40;x = 0; x < dicfirstword.dict_count; x++&#41; &#123;
        if &#40;strcmp&#40;dicfirstword.dict&#91;x&#93;,bufferstr&#41; == 0&#41;
          firstword = x + 1;  // Match, so select next word
      &#125;
      if &#40;firstword == 0&#41; &#123; //  means we had a status file, but the word doesnt match
        printf&#40;"\nResume file contains invalid word, please remove\n"&#41;;
        exit&#40;1&#41;;
      &#125;
      if &#40;firstword != 0&#41;
        printf&#40;"\nResuming from &#58; %s\n",dicfirstword.dict&#91;firstword&#93;&#41;;
  &#125;  &#125;

  printf&#40;"\nsearching...\n\n"&#41;;
  fflush&#40;stdout&#41;;
  time&#40;&start&#41;;
  ptr = buffer + prefixlen;
  // First Word
  for &#40;x = firstword; x < dicfirstword.dict_count; x++&#41; &#123;
    time&#40;&start2&#41;;
    ptr0 = ptr;
    for &#40;i = 0; i < dicfirstword.dict_member_length&#91;x&#93;; i++&#41; &#123;
      *&#40;ptr0++&#41; = dicfirstword.dict&#91;x&#93;&#91;i&#93;;
    &#125;
    *&#40;ptr0&#41; = 0;
    printf&#40;"// processing word&#58; %s\n", buffer&#41;;
    sprintf&#40;xmlfilename,"results_%s.xml",buffer&#41;;
#ifdef SKIP_EXISTING
    // Open results file for this word, see if it already exists
    if &#40;&#40;fout = fopen&#40;xmlfilename,"rt"&#41;&#41; > 0&#41; &#123; // Output file exists
      printf&#40;"Skipping Word &#58; %s - Output Exists\n",buffer&#41;;
      fclose&#40;fout&#41;;
    &#125;
    else
#endif
    &#123; // Open the results file, ready for writing
      printf&#40;"// opening results file &#58; %s\n",xmlfilename&#41;;
      if &#40;&#40;fout = fopen&#40;xmlfilename, "wt"&#41;&#41; <= 0&#41; &#123;
        printf&#40;"Failed to open output file\n"&#41;;
        exit&#40;1&#41;;
      &#125;
      fprintf&#40;fout,"<NIDFUNCLIST>\n"&#41;;
      fflush&#40;stdout&#41;;
      // Second word
      for &#40;y = 0; y < dicmain.dict_count; y++&#41; &#123;
        ptr1 = ptr0;
        for &#40;i = 0; i < dicmain.dict_member_length&#91;y&#93;; i++&#41; &#123;
          *&#40;ptr1++&#41; = dicmain.dict&#91;y&#93;&#91;i&#93;;
        &#125;
        *&#40;ptr1&#41; = 0;
        //printf&#40;"// processing word&#58; %s\n",buffer&#41;;
  
        // Only do next loop if first and second dont match
        if &#40;strcmp&#40;dicmain.dict&#91;x&#93;, dicmain.dict&#91;y&#93;&#41; != 0&#41; &#123;
          // Third Word
          for &#40;z = 0; z < dicmain.dict_count; z++&#41; &#123;
            ptr2 = ptr1;
            for &#40;i = 0; i < dicmain.dict_member_length&#91;z&#93;; i++&#41; &#123;
              *&#40;ptr2++&#41; = dicmain.dict&#91;z&#93;&#91;i&#93;;
            &#125;
            // Only do next loop if second and third dont match
            if &#40;strcmp&#40;dicmain.dict&#91;y&#93;, dicmain.dict&#91;z&#93;&#41; != 0&#41; &#123;
              // Fourth Word
              for &#40;zz = 0; zz < dicmain.dict_count; zz++&#41; &#123;
                ptr3 = ptr2;
                for &#40;i = 0; i < dicmain.dict_member_length&#91;zz&#93;; i++&#41; &#123;
                  *&#40;ptr3++&#41; = dicmain.dict&#91;zz&#93;&#91;i&#93;;
                &#125;
  #if 0
                // Only do next loop if third and fourth dont match
                if &#40;strcmp&#40;dicmain.dict&#91;z&#93;, dicmain.dict&#91;zz&#93;&#41; != 0&#41; &#123;
                  // Fifth Word
                  for &#40;z2 = 0; z2 < dicmain.dict_count; z2++&#41; &#123;
                    ptr4 = ptr3;
                    for &#40;i = 0; i < dicmain.dict_member_length&#91;z2&#93;; i++&#41; &#123;
                      *&#40;ptr4++&#41; = dicmain.dict&#91;z2&#93;&#91;i&#93;;
                    &#125;
                    *&#40;ptr4&#41; = 0x00;
                    findhash&#40;buffer, ptr4 - buffer&#41;;
                  &#125;
                &#125;
#endif
                *&#40;ptr3&#41; = 0x00;
                findhash&#40;buffer, ptr3 - buffer&#41;;
              &#125;
            &#125;
            *&#40;ptr2&#41; = 0x00;
            findhash&#40;buffer, ptr2 - buffer&#41;;
          &#125;
        &#125;
        *&#40;ptr1&#41; = 0x00;
        findhash&#40;buffer, ptr1 - buffer&#41;;
      &#125;
      *&#40;ptr0&#41; = 0x00;
      findhash&#40;buffer, ptr0 - buffer&#41;;

      //  Print out end time for word
      time&#40;&end2&#41;;
      printf&#40;"\n\ntime &#58; %f minutes.\n", difftime&#40;end2, start2&#41;/60&#41;;
      
      // Close results file
      fprintf&#40;fout,"</NIDFUNCLIST>\n"&#41;;
      fflush&#40;fout&#41;;
      fclose&#40;fout&#41;;
    &#125;
    
    &#123; // Write out toplevel word, for resuming a run from last first word
      FILE *fpt;
      if &#40;&#40;fpt = fopen&#40;"nidstatus.tmp", "wt"&#41;&#41; != NULL&#41; &#123;
        fprintf&#40;fpt,"%s",buffer+prefixlen&#41;;
        fclose&#40;fpt&#41;;
      &#125;
    &#125;
  &#125;
  time&#40;&end&#41;;
  printf&#40;"\n\nhash count &#58; %d\n", hash_count&#41;;
  printf&#40;"dictionary words &#40;firstword&#41; &#58; %d\n", dicfirstword.dict_count&#41;;
  printf&#40;"dictionary words &#40;main&#41;      &#58; %d\n", dicmain.dict_count&#41;;
  printf&#40;"\n\ntime &#58; %f seconds.\n\n", difftime&#40;end, start&#41;&#41;;

  return 0;
&#125;

florinsasu
Posts: 47
Joined: Wed Dec 15, 2004 4:23 am

Post by florinsasu »

...a bit late to add this to this thread :)
loser wrote:yeh i noticed that in 'release config' in msvc++ it didnt work correctly, but in 'debug config' it did. after adding the memsets to buffer and buffer2 at the top it seemed to work. that was more of a quick fix tho; this part you point out is prolly what really needs fixing
i also have a sha12psp attack program and it does work correctly if built with vc6 debug, vc6 release, vc7 debug, vc71 debug, vc8 debug.
any release from vc7 and up are messed ?!? very strange
also amd64 debug builds work and releases dont...
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

Post by PspPet »

> Here is the latest version of the attack program.
Please incorporate the hash[] array bug fix mentioned above (or something similar) . The latest version still has this problem (crashes on me 100% of the time without it -- VC6 -Ot)

For people still having problems with the VC debug/release options, apply the fix yourself and your problem will hopefully go away.

The current version may not crash for you depending on memory randomness. Even if it doesn't crash, it may make the algorithm run slower than it should (in unpredicatable ways)
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

(NIDs for VSH modules)

Post by PspPet »

mrbrown wrote:
>I have yet to crack any of the NIDs found in the VSH modules. Has anyone else?

Just started looking into the VSH modules. Lots of good stuff there.
Found a few NIDs -- searching for more now (fortunately it appears they use the same technique)
The trick, as always is finding the prefix they use. "sceSystem" appears to be used for the shared utilities.

eg: "sceSystemFileLoadAll" in module sceVshCommonUtil (and a bunch of other "sceSystemFile*" helpers)
More to come when I get a more complete list. I guess the database will have to be expanded for these modules too.
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Post by mrbrown »

Yeah, I have the sceSystem ones found when looking at a plaintext vsh module. I also have vsh* from vshbridge, which match the same names with an sce prefix, i.e. vshKernelLoadModule for sceKernelLoadModule.

Guess we'll have to crack the whip to get our big NID list out the door. There's way too much duplication going on :).

Now if you have some names from scePaf, we need to talk :). I've even thought about setting up a bounty for those.
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

Post by PspPet »

> Guess we'll have to crack the whip to get our big NID list out the door. There's way too much duplication going on :).

How about placing them in the public database ? http://pspdev.ofcode.com/api.php
(or at least post them on the "Library function list" thread and someone will move them over)

FWIW: that's what I've been doing lately, and then automatically grab all the entries from the web and reformat it to a simple text file (for disassembler use).
mrbrown
Site Admin
Posts: 1537
Joined: Sat Jan 17, 2004 11:24 am

Post by mrbrown »

We have a huge XML file that we use to keep track of NIDs. Without an automated script it would take too long to add those NIDs using a web interface.
PspPet
Posts: 210
Joined: Wed Mar 30, 2005 2:13 am
Contact:

Post by PspPet »

FWIW: There is an automated way of adding hundreds of entries at once (you need a login ID). Checks the SHA1 values and reports if the names are new or old
[those reports "neofar" posts in the other top sticky thread]

I just did that myself (converting my discovered entries from disassembler format to the trivial web input format for posting)
FWIW2: My name dictionary is pretty small and I came up with about 200 new names, which tells me the public database is far from complete. ie. still some low hanging fruit.
Now with VSH NIDs and others to look for there is more work to do!
Post Reply