HOW TO REVERSE ENGINEER SERV-U32(FTP Daemon) (Reconstruction of a missing file) by TheChineese
Well this target, called SERV-U32, is a ftp daemon for win95 (and Windows NT). I think it could be useful for our trade. It seems interesting because of his "missing file" protection. It's protection scheme is in fact based on a MISSING file (KEY.TXT, as we will see) that you would get (via email) when and if you'll register the software. "A priori" we do not know what this file looks like... a pretty widespread protection scheme nowadays: "Cracker won't be able to crack my crap, because some pieces are completely missing, Ah ah!". But how does the target "know" that a piece is missing? So the purpose of this lesson is to learn how to crack these kind of protection schemes. We must therefore understand the format of the missing KEY.TXT file. I'll use for this essay, as target, SERV-U32.EXE, version 2.2, 22 February 1997 (Serv-U32.exe 495 613 bytes) You will be able to find it, for example, at Tucows. You'll find the dead listing snippets AT THE BOTTOM of this essay, they are worth following, and interesting, but let me first explain you HOW this protection scheme works, and how to defeat it, you'll then be able to follow more easily the relevant code.- First of all use Filemon.exe by Mark Russinovitch (you'll find it here). Filemon will show you that the target looks for a KEY.TXT file (now we know that there is indeed a missing file :-) - then use a disassembler (wdasm8.5 for example), disassemble the target and search for the STRING "KEY.TXT" inside the dead listing... you should find the following piece of code (FIRST CHECK for KEY.TXT and in KEY.TXT) and you will notice that the code we have found uses the GetPrivateProfileStringA API, which we better examinate a littel deeper. You will find here the description of GetPrivateProfileStringA (It's important! It will help you to determine the Format of the missing KEY.TXT file) The KEY.TXT format should be something like that [KEY] RegistrationKey=anignoredvalueforthemoment
The GetPrivateProfileString function retrieves a string from the specified section in an initialization file. This function is provided for compatibility with 16-bit Windows-based applications. Win32-based applications should store initialization information in the registry. DWORD GetPrivateProfileString( LPCTSTR lpAppName, // points to section name LPCTSTR lpKeyName, // points to key name LPCTSTR lpDefault, // points to default string LPTSTR lpReturnedString, // points to destination buffer DWORD nSize, // size of destination buffer LPCTSTR lpFileName // points to initialization filename ); Parameters lpAppName Points to a null-terminated string that specifies the section containing the key name. If this parameter is NULL, the GetPrivateProfileString function copies all section names in the file to the supplied buffer. lpKeyName Points to the null-terminated string containing the key name whose associated string is to be retrieved. If this parameter is NULL, all key names in the section specified by the lpAppName parameter are copied to the buffer specified by the lpReturnedString parameter. lpDefault Points to a null-terminated string that specifies the default value for the given key if the key cannot be found in the initialization file. This parameter cannot be NULL. lpReturnedString Points to the buffer that receives the retrieved string. nSize Specifies the size, in characters, of the buffer pointed to by the lpReturnedString parameter. lpFileName Points to a null-terminated string that names the initialization file. If this parameter does not contain a full path to the file, Windows searches for the file in the Windows directory. Return Value If the function succeeds, the return value is the number of characters copied to the buffer, not including the terminating null character. If neither lpAppName nor lpKeyName is NULL and the supplied destination buffer is too small to hold the requested string, the string is truncated and followed by a null character, and the return value is equal to nSize minus one. If either lpAppName or lpKeyName is NULL and the supplied destination buffer is too small to hold all the strings, the last string is truncated and followed by two null characters. In this case, the return value is equal to nSize minus two. Remarks The GetPrivateProfileString function searches the specified initialization file for a key that matches the name specified by the lpKeyName parameter under the section heading specified by the lpAppName parameter. If it finds the key, the function copies the corresponding string to the buffer. If the key does not exist, the function copies the default character string specified by the lpDefault parameter. A section in the initialization file must have the following form: [section] key=string . . . If lpAppName is NULL, GetPrivateProfileString copies all section names in the specified file to the supplied buffer. If lpKeyName is NULL, the function copies all key names in the specified section to the supplied buffer. An application can use this method to enumerate all of the sections and keys in a file. In either case, each string is followed by a null character and the final string is followed by a second null character. If the supplied destination buffer is too small to hold all the strings, the last string is truncated and followed by two null characters. If the string associated with lpKeyName is enclosed in single or double quotation marks, the marks are discarded when the GetPrivateProfileString function retrieves the string. The GetPrivateProfileString function is not case-sensitive; the strings can be a combination of uppercase and lowercase letters. To retrieve a string from the WIN.INI file, use the GetProfileString function.
You read all the above, you better? Okay... We notice that our target uses another function called Writeprivateprofilestringa in order to write some stuff inside Serv-U.ini(in the GLOBAL section). The target in fact writes the RegistrationKey (and at the same time changes KEY.TXT into KEY.OLD) So now we want to know which is the exact form of the "anignoredvalueforthemoment" So let's use a zen method (thanks to +ORC for his Inspiration...), We have noticed that KEY.TXT is changed in KEY.OLD after Copying the Registrationkey in Serv-u.ini. So we can suppose that the protection scheme is going to check in Serv-u.ini for the "anignoredvalueforthemoment" using the function GetPrivateProfileString. So we can search for "Registrationkey" and "GLOBAL" inside the Wdasm listing (see bottom) or/and we can use Softice... So we fire softice 3.0.1(or 3.0) We also put inside the Serv-u subdirectory a "faked" file called KEY.TXT (as described here...) CTRL+D ;gets us inside Winice bpx GetPrivateProfileString ;sets the relevant breakpoint launch Serv-u32.exe ;fire the target into sice bd 0 (for GetPrivateProfileString ;breakpoint disable, after F12 to ;be inside the serv-u code segment bpx 004440AA then be 0 ;to enable GetPrivateProfileString then F5 until you have found the piece of code called ROUTINE for checking inside our target's serv-u.ini file if the registrationkey has the correct format and if the encrypted registered code is the same as the registrationkey inside serv-u.ini You notice, in the following piece of code, that it checks inside serv-u.ini for the Registrationkey -the "anignoredvalueforthemoment" must be > 0E (15) -and the 12thd character of "anignoredvalueforthemoment" must be equal to "," (2C in Hexadecimal notation, i.e. "comma") -so Now ve can suppose that "anignoredvalueforthemoment" must have the format ############,YOURNAME And that YOURNAME must be at least 3 characters (that's the purpose of the "more than 15 bytes" check. ########### is an 11(decimal) digits registration code Thereforeow we can now modify our faked KEY.TXT (for example as follows) [KEY] Registrationkey=12121212121,TheChineese Let's go! Pop into winice! CRTL+D bpx 44CA4A d ebx ;this ebx is the address of the REAL "good-guy" Key for our Example, for instance, d ebx -> ArV004LxGIs. Therefore the registrationkey in our case is the following: ArV004LxGIs,TheChineese... you dig it? That all folks, we reverse engineered a "missing file" protection scheme, you may now study the following code in order to understand better the protection scheme and/or build a key generator...Code section FIRST CHECK for KEY.TXT and in KEY.TXT
* Referenced by a Jump at Address:004440A5(C) | :004440AA 8D86B6030000 lea eax, [esi+000003B6] :004440B0 50 push eax :004440B1 8D8518F8FFFF lea eax, [ebp+FFFFF818] :004440B7 50 push eax :004440B8 E8CB7FFEFF call 0042C088 :004440BD 83C408 add esp, 00000008 :004440C0 8D86B8030000 lea eax, [esi+000003B8] :004440C6 50 push eax :004440C7 8D8518F8FFFF lea eax, [ebp+FFFFF818] :004440CD 50 push eax :004440CE E8B57FFEFF call 0042C088 :004440D3 83C408 add esp, 00000008 :004440D6 8D86C0030000 lea eax, [esi+000003C0] :004440DC 50 push eax :004440DD 8D8518F8FFFF lea eax, [ebp+FFFFF818] :004440E3 50 push eax :004440E4 E87FA7FEFF call 0042E868 :004440E9 83C408 add esp, 00000008 :004440EC 85C0 test eax, eax :004440EE 0F8443010000 je 00444237 :004440F4 50 push eax :004440F5 E8E2A2FEFF call 0042E3DC :004440FA 59 pop ecx :004440FB 8D8518F8FFFF lea eax, [ebp+FFFFF818] <-- for file KEY.TXT* Reference To: KERNEL32.GetPrivateProfileStringA, Ord:0000h | :00444123 E8A3150200 Call 004656CB :00444128 894594 mov [ebp-6C], eax <-- eax= size of the regitrationkey :0044412B 837D9400 cmp [ebp-6C], 00000000 <-- compare to 0 :0044412F 751B jne 0044414C <-- if eax=0 then jmp good, continue :00444131 68A0000000 push 000000A0 <-- else bad guy :00444136 8D85D8F6FFFF lea eax, [ebp+FFFFF6D8] :0044413C 50 push eax * Possible Reference to String Resource ID=02036: "NO REGISTRATION KEY FOUND IN KEY.TXT!?" | :0044413D 68F4070000 push 000007F4 :00444142 FF7348 push [ebx+48] * Reference To: USER32.LoadStringA, Ord:0000h | :00444145 E8E1180200 Call 00465A2B :0044414A EB19 jmp 00444165 * Referenced by a Jump at Address:0044412F(C) | :0044414C 68A0000000 push 000000A0 :00444151 8D85D8F6FFFF lea eax, [ebp+FFFFF6D8] :00444157 50 push eax * Possible Reference to String Resource ID=02037: "Loaded registrationkey from KEY.TXT" | :00>44158 68F5070000 push 000007F5 :0044415D FF7348 push [ebx+48] * Reference To: USER32.LoadStringA, Ord:0000h | :00444160 E8C6180200 Call 00465A2B * Referenced by a Jump at Address:0044414A(U) | :00444165 8D85D8F6FFFF lea eax, [ebp+FFFFF6D8] :0044416B 50 push eax :0044416C 6A12 push 00000012 * Possible Reference to String Resource ID=01027: "550 No path names in filename allowed" | :0044416E 6803040000 push 00000403 :00444173 8B03 mov eax, [ebx] :00444175 8B00 mov eax, [eax] :00444177 FF7010 push [eax+10] * Reference To: USER32.SendMessageA, Ord:0000h | :0044417A E842160200 Call 004657C1 :0044417F 837D9400 cmp [ebp-6C], 00000000 :00444183 741E je 004441A3 :00444185 8D434C lea eax, [ebx+4C] <-- for the file serv-u.ini :00444188 50 push eax :00444189 8D8578F7FFFF lea eax, [ebp+FFFFF778] :0044418F 50 push eax :00444190 8D86DF030000 lea eax, [esi+000003DF] <-- for Registrationkey :00444196 50 push eax :00444197 8D86D8030000 lea eax, [esi+000003D8] <-- for GLOBAL :0044419D 50 push eax * Reference To: KERNEL32.WritePrivateProfileStringA, Ord:0000h | :0044419E E894150200 Call 00465737 <-- write to serv-u.ini Registrationkey=what is in key.txt * Referenced by a Jump at Address:00444183(C) | :004441A3 56 push esi :004441A4 57 push edi :004441A5 8DB538F6FFFF lea esi, [ebp+FFFFF638] :004441AB 8DBD18F8FFFF lea edi, [ebp+FFFFF818] :004441B1 33C0 xor eax, eax :004441B3 83C9FF or ecx, FFFFFFFF :004441B6 F2 repnz :004441B7 AE scasb :004441B8 F7D1 not ecx :004441BA 2BF9 sub edi, ecx :004441BC 87F7 xchg edi, esi :004441BE 8BC7 mov eax, edi :004441C0 8BD1 mov edx, ecx :004441C2 C1E902 shr ecx, 02 :004441C5 F3 repz :004441C6 A5 movsd :004441C7 8BCA mov ecx, edx :004441C9 83E103 and ecx, 00000003 :004441CC F3 repz :004441CD A4 movsb :004441CE 5F pop edi :004441CF 5E pop esi :004441D0 6A5C push 0000005C :004441D2 8D8538F6FFFF lea eax, [ebp+FFFFF638] :004441D8 50 push eax :004441D9 E89681FEFF call 0042C374 :004441DE 83C408 add esp, 00000008 :004441E1 85C0 test eax, eax :004441E3 7403 je 004441E8 :004441E5 C60000 mov byte ptr [eax], 00 * Referenced by a Jump at Address:004441E3(C) | :004441E8 8D86EF030000 lea eax, [esi+000003EF] :004441EE 50 push eax :004441EF 8D8538F6FFFF lea eax, [ebp+FFFFF638] :004441F5 50 push eax :004441F6 E88D7EFEFF call 0042C088 :004441FB 83C408 add esp, 00000008 :004441FE 8D86F1030000 lea eax, [esi+000003F1] :00444204 50 push eax :00444205 8D8538F6FFFF lea eax, [ebp+FFFFF638] :0044420B 50 push eax :0044420C E8777EFEFF call 0042C088 :00444211 83C408 add esp, 00000008 :00444214 8D8538F6FFFF lea eax, [ebp+FFFFF638] :0044421A 50 push eax :0044421B E834A1FEFF call 0042E354 :00444220 59 pop ecx :00444221 8D8538F6FFFF lea eax, [ebp+FFFFF638] :00444227 50 push eax :00444228 8D8518F8FFFF lea eax, [ebp+FFFFF818] :0044422E 50 push eax :0044422F E82CCBFEFF call 00430D60 :00444234 83C408 add esp, 00000008 * Referenced by a Jump atAddress:004440EE(C) | :00444237 833D842D470000 cmp dword ptr [00472D84], 00000000 :0044423E 7509 jne 00444249 :00444240 833D942D470001 cmp dword ptr [00472D94], 00000001 :00444247 740D je 00444256 * Referenced by a Jump at Address:0044423E(C) | :00444249 833D942D470003 cmp dword ptr [00472D94], 00000003 :00444250 0F85E1000000 jne 00444337 * Referenced by a Jump at Address:00444247(C) | :00444256 6A28 push 00000028 :00444258 E877EDFEFF call 00432FD4 :0044425D 59 pop ecx :0044425E 8945E4 mov [ebp-1C], eax :00444261 85C0 test eax, eax :00444263 7434 je 00444299 :00444265 66C745D0A400 mov [ebp-30], 00A4 :0044426B FF7348 push [ebx+48] :0044426E 8B03 mov eax, [ebx] :00444270 8B00 mov eax, [eax] :00444272 FF7010 push [eax+10] :00444275 8D86F9030000 lea eax, [esi+000003F9] :0044427B 50 push eax :0044427C FF75E4 push [ebp-1C] :0044427F E8D6030200 call 0046465A :00444284 83C410 add esp, 00000010 :00444287 A1D41A4800 mov eax, [00481AD4] :0044428C FF08 dec dword ptr [eax] :0044428E 66C745D09800 mov [ebp-30], 0098 :00444294 8B45E4 mov eax, [ebp-1C] :00444297 EB03 jmp 0044429C
ROUTINE for checking inside serv-u.ini if the registrationkey has the good format and if the encrypted registred code is the same as the registrationkey in serv-u.ini
* Referenced by a Jump at Addresses:0044C8C0(U), :0044C8D5(C), :0044C8EF(C), :0044C900(C) | :0044C923 53 push ebx <-- for serv-u.ini :0044C924 689F000000 push 0000009F :0044C929 8D852CFDFFFF lea eax, [ebp+FFFFFD2C] :0044C92F 50 push eax :0044C930 68BC514700 push 004751BC * Possible StringData Ref from Data Obj ->"RegistrationKey" <-- for Registrationkey | :0044C935 68AC514700 push 004751AC * Possible StringData Ref from Data Obj ->"GLOBAL" <-- for GLOBAL | :0044C93A 68A5514700 push 004751A5 * Reference To: KERNEL32.GetPrivateProfileStringA, Ord:0000h | :0044C93F E8878D0100 Call 004656CB :0044C944 85C0 test eax, eax <-- eax= size of the registration key :0044C946 0F8442010000 je 0044CA8E <-- if zero bad guy :0044C94C 8D852CFDFFFF lea eax, [ebp+FFFFFD2C] :0044C952 50 push eax :0044C953 E89C6F0100 call 004638F4 :0044C958 59 pop ecx :0044C959 8D852CFDFFFF lea eax, [ebp+FFFFFD2C] :0044C95F 50 push eax :0044C960 E8E3F7FDFF call 0042C148 :0044C965 59 pop ecx :0044C966 83F80E cmp eax, 0000000E <-- eax= size of the regitration key :0044C969 731C jnb 0044C987 <-- if > 0E=15 then jmp ok let's go :0044C96B C706FEFFFFFF mov dword ptr [esi], FFFFFFFE <-- else bad guy :0044C971 6A00 push 00000000 :0044C973 6A00 push 00000000 * Possible Reference to String Resource ID=01031: "150 Opening %s mode data connection for %s (%ld bytes)." | :0044C975 6807040000 push 00000407 :0044C97A FF750C push [ebp+0C] * Reference To: USER32.PostMessageA, Ord:0000h | :0044C97D E873900100 Call 004659F5 :0044C982 E90A020000 jmp 0044CB91 * Referenced by a Jump at Address:0044C969(C) | :0044C987 0FBE8537FDFFFF movsx byte ptr eax, [ebp+FFFFFD37] <-- eax=the 12thd character of the registrationkey :0044C98E 83F82C cmp eax, 0000002C <-- compare to "," (2C) :0044C991 741C je 0044C9AF <-- if equal ok let's go :0044C993 C706FEFFFFFF mov dword ptr [esi], FFFFFFFE <-- else bad guy :0044C999 6A00 push 00000000 so here we can suppose that the key form is: ###########,NAME :0044C99B 6A00 push 00000000 * Possible Reference to String Resource ID=01031: "150 Opening %s mode data connection for %s (%ld bytes)." | :0044C99D 6807040000 push 00000407 :0044C9A2 FF750C push [ebp+0C] * Reference To: USER32.PostMessageA, Ord:0000h | :0044C9A5 E84B900100 Call 004659F5 :0044C9AA E9E2010000 jmp 0044CB91 * Referenced by a Jump at Address:0044C991(C) | :0044C9AF 8D8538FDFFFF lea eax, [ebp+FFFFFD38] <-- first part of encryption :0044C9B5 8945F0 mov [ebp-10], eax :0044C9B8 66BB45F3 mov bx, F345 :0044C9BC 33FF xor edi, edi :0044C9BE EB26 jmp 0044C9E6 * Referenced by a Jump at Address:0044C9F1(C) | :0044C9C0 8B45F0 mov eax, [ebp-10] :0044C9C3 0FBE0438 movsx byte ptr eax, [eax + edi] :0044C9C7 C1E008 shl eax, 08 :0044C9CA 6633D8 xor bx, ax :0044C9CD 33C0 xor eax, eax * Referenced by a Jump at Address:0044C9E3(C) | :0044C9CF F6C780 test bh, 80 :0044C9D2 7409 je 0044C9DD :0044C9D4 03DB add ebx, ebx :0044C9D6 6681F32110 xor ebx, 1021 :0044C9DB EB02 jmp 0044C9DF * Referenced by a Jump at Address:0044C9D2(C) | :0044C9DD 03DB add ebx, ebx * Referenced by a Jump at Address:0044C9DB(U) | :0044C9DF 40 inc eax :0044C9E0 83F808 cmp eax, 00000008 :0044C9E3 7CEA jl 0044C9CF :0044C9E5 47 inc edi * Referenced by a Jump at Address:0044C9BE(U) | :0044C9E6 FF75F0 push [ebp-10] :0044C9E9 E85AF7FDFF call 0042C148 :0044C9EE 59 pop ecx :0044C9EF 3BC7 cmp eax, edi :0044C9F1 77CD ja 0044C9C0 :0044C9F3 33FF xor edi, edi * Referenced by a Jump at Address:0044CA0A(C) | :0044C9F5 8BC3 mov eax, ebx :0044C9F7 240F and al, 0F :0044C9F9 0441 add al, 41 :0044C9FB 88843D18FDFFFF mov [ebp + edi - 000002E8], al :0044CA02 66C1EB04 shr ebx, 04 :0044CA06 47 inc edi :0044CA07 83FF04 cmp edi, 00000004 :0044CA0A 7CE9 jl 0044C9F5 :0044CA0C C6851CFDFFFF00 mov byte ptr [ebp+FFFFFD1C], 00 * Possible StringData Ref from Data Obj ->"y&wF%" | :0044CA13 68BD514700 push 004751BD :0044CA18 8D8518FDFFFF lea eax, [ebp+FFFFFD18] :0044CA1E 50 push eax :0044CA1F E864F6FDFF call 0042C088 :0044CA24 83C408 add esp, 00000008 * Possible StringData Ref from Data Obj ->"CS" | :0044CA27 68C3514700 push 004751C3 :0044CA2C 8D8518FDFFFF lea eax, [ebp+FFFFFD18] :0044CA32 50 push eax :0044CA33 E837E1FFFF call 0044AB6F <--- here there the second and third part of the encryption :0044CA38 83C408 add esp, 00000008 :0044CA3B 8BD8 mov ebx, eax :0044CA3D 6A0B push 0000000B :0044CA3F 83C302 add ebx, 00000002 :0044CA42 53 push ebx <-- good registration key :0044CA43 8D852CFDFFFF lea eax, [ebp+FFFFFD2C] <-- key we enter in key.txt :0044CA49 50 push eax :0044CA4A E861F7FDFF call 0042C1B0 <-- check the two keys :0044CA4F 83C40C add esp, 0000000C :0044CA52 85C0 test eax, eax <-- test if eax=0 :0044CA54 751C jne 0044CA72 <-- if eax<>0 jmp bad guy :0044CA56 C70602000000 mov dword ptr [esi], 00000002 :0044CA5C 6A00 push 00000000 :0044CA5E 6A00 push 00000000 * Possible Reference to String Resource ID=01031: "150 Opening %s mode data connection for %s (%ld bytes)." | :0044CA60 6807040000 push 00000407 :0044CA65 FF750C push [ebp+0C] * Reference To: USER32.PostMessageA, Ord:0000h | :0044CA68 E8888F0100 Call 004659F5 :0044CA6D E91F010000 jmp 0044CB91 * Referenced by a Jump at Address: |:0044CA54(C) | :0044CA72 C706FEFFFFFF mov dword ptr [esi], FFFFFFFE :0044CA78 6A00 push 00000000 :0044CA7A 6A00 push 00000000 * Possible Reference to String Resource ID=01031: "150 Opening %s mode data connection for %s (%ld bytes)." | :0044CA7C 6807040000 push 00000407 :0044CA81 FF750C push [ebp+0C] * Reference To: USER32.PostMessageA, Ord:0000h ...
2nd and 3thd part of encryption
* Referenced by a CALL at Addresses:0044A54E , :0044CA33 , :0045445D | :0044AB6F 55 push ebp :0044AB70 8BEC mov ebp, esp :0044AB72 833D4C4B470000 cmp dword ptr [00474B4C], 00000000 :0044AB79 750F jne 0044AB8A :0044AB7B E839990100 call 004644B9 <-- (2nd part) call for the matrix with 0 and 1 :0044AB80 C7054C4B470001000000 mov dword ptr [00474B4C], 00000001 * Referenced by a Jump atAddress:0044AB79(C) | :0044AB8A FF750C push [ebp+0C] :0044AB8D FF7508 push [ebp+08] :0044AB90 E8E6950100 call 0046417B <-- (3thd part) final encryption for good KEY :0044AB95 83C408 add esp, 00000008 :0044AB98 5D pop ebp :0044AB99 C3 ret
2nd part the matrix
* Referenced by a CALL at Address: 0044AB7B | :004644B9 55 push ebp :004644BA 8BEC mov ebp, esp :004644BC 6888084800 push 00480888 :004644C1 6888104800 push 00481088 :004644C6 6A00 push 00000000 :004644C8 E8AAFEFFFF call 00464377 <--- each routine write a matrix (of 1 and 0) at the same location (480740) :004644CD 83C40C add esp, 0000000C :004644D0 6888094800 push 00480988 :004644D5 6888114800 push 00481188 :004644DA 6A01 push 00000001 :004644DC E896FEFFFF call 00464377 <--- :004644E1 83C40C add esp, 0000000C :004644E4 68880A4800 push 00480A88 :004644E9 6888124800 push 00481288 :004644EE 6A02 push 00000002 :004644F0 E882FEFFFF call 00464377 <--- :004644F5 83C40C add esp, 0000000C :004644F8 68880B4800 push 00480B88 :004644FD 6888134800 push 00481388 :00464502 6A03 push 00000003 :00464504 E86EFEFFFF call 00464377 <---
--- 3thd part
* Referenced by a CALL at Address:0044AB90 | :0046417B 55 push ebp :0046417C 8BEC mov ebp, esp :0046417E 53 push ebx :0046417F 56 push esi :00464180 8B4D08 mov ecx, [ebp+08] :00464183 BEC0074800 mov esi, 004807C0 :00464188 8BD6 mov edx, esi :0046418A B812000000 mov eax, 00000012 :0046418F EB07 jmp 00464198 * Referenced by a Jump at Address:0046419F(C) | :00464191 33DB xor ebx, ebx :00464193 891A mov [edx], ebx :00464195 83C204 add edx, 00000004 * Referenced by a Jump at Address:0046418F(U) | :00464198 8BD8 mov ebx, eax :0046419A 83C0FF add eax, FFFFFFFF :0046419D 85DB test ebx, ebx :0046419F 75F0 jne 00464191 :004641A1 33C0 xor eax, eax :004641A3 EB53 jmp 004641F8 * Referenced by a Jump atAddress:00464202(C) | :004641A5 8BDA mov ebx, edx :004641A7 C1FB06 sar ebx, 06 :004641AA 80E301 and bl, 01 :004641AD 881C06 mov [esi + eax], bl :004641B0 40 inc eax :004641B1 8BDA mov ebx, edx :004641B3 C1FB05 sar ebx, 05 :004641B6 80E301 and bl, 01 I hope that my English is not so "bizarre", and that the pieces of code that I have published above will be useful to people who want to understand deeper the whole encryption scheme for the key used in this target, in order to build a keygenerator (which is a sound exercise for any reverse engineer) or simply to be prepared for other, similar, protection schemes. Let me know about it and feel free to send any comments to: Email: chineese@mygale.org