unpacking Asprotect version 1.05
Manually unpacking Asprotect version 2000
Building a fake import table
Written by Tsehp
Asprotect is a well know target, this packer was studied a lot and often used as a target practice for newbies. If you don't know anything about packing, improve your knowledge on the past essays, then come back, I'll try to explain you their last tricks. I use to find this target while looking for the sandman's newbie msgboard. Thanks to a Fravia called SV that explained very well the protection on his threads, his work made me save a lot of time.
Important : This essay can bring you a working app with your actual windows version. But the import table that is rebuilt will work only on win nt 4.0/2000, why ? The commview's version I cracked is designed for win nt4/2000 , on win98 another version is installed, with a different import table. So if you want to unpack on windows 98, you can't use the build_table file I provided, use my method anyway, the code will generate a working table for win 9x.
I also used this method for picturestoexe, this app doesn't use export ordinals and the cracked target fully works on my win2000 and win 98.
This essay is provided to teach you a new technique when you unpack a target with a completly destroyed import table, so read carefully and practice everything step by step.
1) The anti-softice routines
Before lauching this app, you have to hide your debugger. This prog uses two typical anti softice tricks:
-Is the driver loaded ? : bpx createfileA do "d esp-4"
Commview tries to see if three different versions of softice are loaded. You will hit three times : SIWDEBUG SICE NTICE
Well it depends on the system you're on, press F12 at each time, the createfilea must return 0xFFFFFFFF If not, press F12 again and set your eip to the address pointed by the second jnz below, you will pass all the tests.
-The boundschecker trick. Sice uses int3 for its breakpoints, but when special values are set to register, especially ebp containing 'BCHK' 0x4243484b, then if an int3 is encountered, the normal interrupt handler just returns after this Int3 inside your target, so the code just after is executed if sice is present. To avoid this, press F10 several times after setting your eip, go slowly through the code until you see the int3 in sice. When you're on it, change your ebp to something else than 0x4243484b, then the program will run normally until a last check detected by bpx createfilea, just as above.
For the final check, just invert the jz after the createfileA, all the tests are now defeated.
Note : I used to munually do that, because frogsice is not actually implemented on win NT, the actual copy on nt called Ntall is not fully working, so I couldn't use a loaded device to avoid those manipulations.
2) Locating the Entry point.
If you want to dump your packed program, you must stop the target here, so all the sections would be loaded. I have to admit that I directly used the technique that Eternal Bliss found on the newbie's forum. Here it is, untouched :
Steps: 1) bpx on getprocaddress 2) Once you break, look at the .idata section by "dd 4E3000". This is found by doing "map32 cv" 3) bpm on the 1st byte (just to break there) and disable getprocaddress breakpoint 4) F5 and let the program run 5) Upon breaking, disable all breakpoints 6) F12 4 times and you will land at a Xor EAX, EAX 7) Start tracing with F10 8) Everytime you come across a CALL, check that a few instructions below are JMP 9) If it is, you can trace over it 10) If it is a ret, you have to trace into that CALL with F8 11) Then step over the 2 subsequent CALLs 12) You will see the OEP moved into EAX somewhere there 13) Then you will come across a POPAD 14) The JMP stuff appears again like the start of the unpacking code. 15) Trace into the next (3rd) Call and F8 all the way till you hit a ret 16) Continue with it and you will land in on the OEP.
Just apply this and you will find it, 0x4de384 on my system. Just remember that you will find almost all the time a POPAD instruction just before the final jump.
You have to dump the exe, using icedump and procdump to rebuild the pe (this will not be explained here, if you don't know how to do this, just look at the past packer/unpacker essays).
Very important : Use those procump options when rebuilding the pe : Structure : disable optimize pe structure Import : don't rebuild import Leave other options untouched. You have to manually copy the .aspr section from cv.exe (original) to cv_dumped.exe, using your favorite hexeditor. As an example I found inside original raw offset : 5aa00 length 14800 dumped raw offset : ff400 length 14800, this manipulation will copy back the original import table.
But this dumped will not work, just try to load your dumped exe inside ida and you will notice that the import table is damaged, some virtual addresses in other sections are also pointed to wrong places. In fact we have a legal import table located inside .aspr section but almost all its imports are not used, except for loadlibrarya, getmodulehandleA and getprocaddress, the rest is here to fool us, stupid crackers ;-)
The main protection of Asprotect is just here : Some imports are fine and pointing directly to the api's addresses some other are pointing to a table (located in mem at 0x00CDxxxx) normally containing some decrypted import's addresses, and this table originally contains also some routines to decrypt other addresses when commview needs them, even if this prog is unpacked.
Well we have here a big problem : You can manually fix the import table if you convert all the tables addresses to the .idata at the right place.
So if inside you dumped app, inside .idata you have
4e328c : jmp [cd4950] and cd4950 containing 77db858e (a valid import address)
you could convert the jump at 4e328c to directly point at 77db858e.
You will spend a lot of time (about 520 addresses) then it will not work. Because inside the cdxxxx table, some addresses points to code like this : cd4950 push cd495a call 182f68 (for example)
Whats happening ? When commview does call 4e328c (import table) the routine located at cd4950 just decrypts the right import adress AT RUNTIME ! You can also try to dump the cdxxxx table, the decrypting code will still be here and definitely not working. This feature is the real improvement made since the last Asprotect versions. And they actually offer to download a version that doesn't apply that kind of protection, strange ;-) "Next thing to do is getting a virgin importtable, as the one inside our dumped file is corrupt. This is how we will work: 1. Inserting some code to build our import table 2. Dumping our import table to the harddisk 3. Fixing the adresses of the import table with a self coded program." (thanks blackb ;-) ) the previous asprotect version was more easy to unpack, the IAT was possible to locate and put back, my previous asprotect essay provided some direct mem jumps inside the import table, not generated by a getprocaddress. This works but, the target only runs on your pc, and if you update some dll's, the addresses are not the same and your target crashes.
3) Generating our string table
You are still on the int3 instruction, just do a S 0 L FFFFFFFF AC 08 C0 74 E4 and you will localize the *culprit* loop that builds the asprotect import table, just do a bpmb at the start. I found this place while logging the getmodulehandle/getprocaddress usual loop, when you pret you land after the call at 19a53a.
Here is what you find :
001B:0018A51E AC LODSB 001B:0018A51F 08C0 OR AL,AL 001B:0018A521 74E4 JZ 0018A507 001B:0018A523 4E DEC ESI 001B:0018A524 56 PUSH ESI 001B:0018A525 53 PUSH EBX 001B:0018A526 80F802 CMP AL,02 001B:0018A529 7407 JZ 0018A532 001B:0018A52B 0FB64E01 MOVZX ECX,BYTE PTR [ESI+01] 001B:0018A52F 41 INC ECX 001B:0018A530 EB05 JMP 0018A537 001B:0018A532 B904000000 MOV ECX,00000004 001B:0018A537 41 INC ECX 001B:0018A538 01CE ADD ESI,ECX 001B:0018A53A E8B5FDFFFF CALL 0018A2F4 <- redirect this point note the address 0x18a2f4. 001B:0018A53F AB STOSD 001B:0018A540 EBDC JMP 0018A51E <- note this address too, it's the loop back jump.
All we have to do is to find a free mem location filled with 0 so we can write a small code to modify this routine. The address 0x180000 will be used as an example.
What are we doing : to rebuild the import table, I will generate something to make it. I reversed asprotect for this and found that it's building a fake import table for the target that interacts with your app.
The thunk import table looks like this if we don't, commview calls this :
402000 call [4ebc38]; 4ebc38=cdec08 ; cdec08=jump kernel32!compareStringA a indirected api call. or cdec08:push dfef04 , call 18ffe4 ; this one is more devious, at runtime when this is called, the generated table at CDxxxx calls a decryption routine that feeds the target's thunk import table with the right address. You can't find the original IAT before all this is generated at first, because it doesn't exist anymore, so you can't use procdump or a IAT rebuilder to make the app work, you have to rebuild everything this time.
The IAT will be rebuilded in two steps :
1)generate a dump, looking like this : <moduleName>0<procName/ordinal_number>0<corresponding target's address to copy the API address> for example :
GetcurrentThreadId0Kernel32.dll068bc4e00 and so on....about 530 groups generated, this could take a long time to do manually. Asprotect must use getmodulehandlea and getprocaddress to generate the right addresses for his Daxxxx table, so I just found the occurences inside its code and traced all the functions parameters, to get them back inside my call fixer.
2)write a code at the end of this dump to regenerate the real IAT thunk (the place where apis addresses are normally set by the os at load time)
NOTE : all the addresses are different at each run of your target.
First patch 18a53a jmp 180000
Then write the following code in mem with softice :
Fake import table builder for commview 2.1 do a s 0 l ffffffff ac 08 c0 74 e4 , this search is constant. redirect the call just before the stosd to some free mem space (here at 180000) by a jump 180000, note the next address op, (here 195004) note the address called and repeat it at the beginning of this code (here 19ff00) for the last part of this code, the decryptor, find the address to call by : s 0 l ffffffff 55 8b ec 81 c4 f8 fe ff ff 53 56 note the address here (19ff08), don't forget to patch this decryptor inside asprotect by doing a d 19ff08+95 and write three nops 90 90 90, this will make a normal ret after your call. put 00 00 50 00 on address 17fff0, just at the beginning, this will start the copy at 500000 (using commview committed mem) dont forget to fill this place with 00's, with a length of 4000, just to clean up the place.
Note : This call fixer must be adapted to your target, especially for the
three different cases (legal procname, ordinal and encrypted one), the tests
be different, depending on the asprotect version and the the way it's implemented inside the target.
data 17fff0:00 00 50 00 ;we start to generate our dump at 500000 in mem beginning for example at 1b:00180000 CALL 19ff00 ;we put back the call that we redirected here PUSHAD ;better save them CMP DWORD PTR [0012FDF3],00 ;12fdf3 points to proc_name, otherwise it's a crypted one or an ordinal (*2) JZ 00180065 ;goes to ordinal/crypted procedure PUSH 0012FDF3 ;copy from (*1) 1b:180014 PUSH DWORD PTR [0017FFF0] ;copy to CALL 78281E39 ;call lstrcpy (your address could differ) PUSH DWORD PTR [0017FFF0] ;just to see CALL 78291334 ;how long this string is INC EAX INC EBX ADD [0017FFF0],EAX ;set the mem pointer to the next place, for the procname string PUSH EBX ;ebx points to the module_name string (result from call 19ff00) (*3) PUSH DWORD PTR [0017FFF0] CALL 78281E39 ;copy again PUSH DWORD PTR [0017FFF0] CALL 78291334 ;check the length INC EAX ADD [0017FFF0],EAX ;adjust the table's offset MOV ECX,[0017FFF0] ;ecx contains a pointer to our table next location, to set the iat address MOV [ECX],EDI ; edi always contains the target's address where we have to put the api's address ADD DWORD PTR [0017FFF0],05 ;set the offset to next group POPAD ;get the registers back JMP 00195004 ;and continue the asprotect loop 1b:180065 CMP ECX,00 ;if ecx<>0 the procname is an ordinal number JNZ 00180079 ;so we go to the ordinal procedure PUSH DWORD PTR [EAX+01] ;to pass the right parameter to the asprotect decrypting procedure, normally called at runtime CALL 0019FF08 ;decrypt the procname (*4) PUSH 0012FDEC ;set the procname string that is now decrypted JMP 00180014 ;we have the procname string decrypted, lets continue inside my fixer 1b:180069 SUB ESI,4 ;ESI points here to the export ordinal number (*5) PUSH ESI ;set the pointer to ordinal,so we copy it inside the table JMP 180014 ;we have the ordinal, let's copy it inside the table
(*1) and (*3)this 12fdf3 address was found while dwelling inside the call 19ff00, it is pushed with the one in (*3) just before a call to a getmodulehandleA and getprocaddress sequence.
(*2) I checked this value several times just after the call 19ff00, it's a constant one.
(*4) this address I found while looking into the original jumps inside the IAT, some jumps calls directly the apis, the encrypted ones always begin by push xxxxxx, call this address.
(*5) same method as (*1) I writed the mem loc and did a pret, esi is always +4 after this address in this case. Put a bpmb on the popad after the call you redirected, it will trigger when the copy is finished. finally dump your table for later use.
PAGEIN D 500000 3ba0 (for example) Just look inside the mem from 500000 down until you find the table's end, we have here all the three components needed to rebuild commview's import table, the procname or ordinal number, its dll name and the target's address to copy the imported address.
Shortcut to test your dumped commview:
If you're lazy, you have here the final result : dumped table with the rebuilder added at the end. Just take your dumped commview, you have to realign it so the rva offsets=raw offsets, add a new section (length = 3c0e) at the target's end, paste this file on the new section and change the commview's entry point at 530b45 (130b45 on procdump, the imagebase is at 400000) and watch what's happening with softice, everything is explained on the following lines.
4)Setting the rebuilder
Now that you have your dumped table and your dumped commview, we need to add this table at the end of the dumped target,to ease your work the dumped commview must have the rva offsets corresponding to raw offsets, use pe-editor to add a new section 4000 length, here are the results :
for the sections :
Your dumped table consists of about 500 group of three members : module name, proc name or ordinal and address to copy the result.
I had to code a rebuilder at the dumped table's end :
He globally takes the first two members : module name and proc name / ordinal, uses getmodulenameA and getprocaddress to get the function's address in mem and copy this address back in commview, heres the listing fully explained.
00530AE7 db 4Fh ; O HERES THE LAST MEMBER OF YOUR DUMPED TABLE, you see openSCManagerA, 00530AE8 db 70h ; p advapi32.dll and 004e3994 is the last address to copy inside commview, 00530AE9 db 65h ; e 4e3994 corresponds to the last thunk of commview's original IAT. 00530AEA db 6Eh ; n 00530AEB db 53h ; S 00530AEC db 43h ; C 00530AED db 4Dh ; M 00530AEE db 61h ; a 00530AEF db 6Eh ; n 00530AF0 db 61h ; a 00530AF1 db 67h ; g 00530AF2 db 65h ; e 00530AF3 db 72h ; r 00530AF4 db 41h ; A 00530AF5 db 0 ; 00530AF6 db 61h ; a 00530AF7 db 64h ; d 00530AF8 db 76h ; v 00530AF9 db 61h ; a 00530AFA db 70h ; p 00530AFB db 69h ; i 00530AFC db 33h ; 3 00530AFD db 32h ; 2 00530AFE db 2Eh ; . 00530AFF db 64h ; d 00530B00 db 6Ch ; l 00530B01 db 6Ch ; l 00530B02 db 0 ; 00530B03 db 94h ; ö 00530B04 db 39h ; 9 00530B05 db 4Eh ; N 00530B06 db 0 ; 00530B07 unk_530B07 db 0 ; ; DATA XREF: start+85o 00530B08 db 0 ; 00530B09 db 0 ; 00530B0A db 0 ; 00530B0B db 0 ; 00530B0C db 0 ; 00530B0D db 0 ; 00530B0E db 0 ; 00530B0F db 0 ; 00530B10 db 0 ; 00530B11 db 0 ; 00530B12 db 0 ; 00530B13 db 0 ; 00530B14 db 0 ; 00530B15 db 0 ; 00530B16 db 0 ; 00530B17 db 0 ; 00530B18 db 0 ; 00530B19 db 0 ; 00530B1A db 0 ; 00530B1B db 0 ; 00530B1C db 0 ; 00530B1D db 0 ; 00530B1E db 0 ; 00530B1F db 0 ; 00530B20 dword_530B20 dd 0 ; DATA XREF: start+ACw 00530B20 ; start+B9r 00530B24 db 0 ; 00530B25 db 0 ; 00530B26 db 0 ; 00530B27 db 0 ; 00530B28 adr_lstrlen dd 0 ; DATA XREF: start+18w 00530B28 ; start+32r ... 00530B2C db 0 ; 00530B2D db 0 ; 00530B2E db 0 ; 00530B2F db 0 ; 00530B30 db 0 ; 00530B31 aLstrlen db 'lstrlen',0 ; DATA XREF: start+Co ;Write lstrlen to retrieve this procedure's address in your rebuilder. 00530B39 align 4 00530B3C lpProcName dd 0 ; DATA XREF: start+2Cw 00530B3C ; start+51r ... 00530B40 current dd 0 ; DATA XREF: start+22w 00530B40 ; start+27r ... 00530B44 db 0 ; 00530B45 00530B45 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ 00530B45 00530B45 ; this prog uses a table pasted above : 00530B45 ; <procname>0<modulename/export ordinal >0<address to copy into thunk import table> 00530B45 ; it gets the real addresses to put into the app's import thunk table 00530B45 00530B45 public start 00530B45 start proc near 00530B45 mov eax, offset aKernel32_dll ; get an offset to kernel.dll, at the start of the table 00530B4A push eax ; lpModuleName 00530B4B call ds:GetModuleHandleA 00530B51 push offset aLstrlen ; get offset to lstrlen string 00530B56 push eax ; hModule 00530B57 call ds:GetProcAddress 00530B5D mov ds:adr_lstrlen, eax 00530B62 mov eax, offset aGetcurrentthre ; pos the offset at the table beginning 00530B67 mov ds:current, eax ; its a procname, we save it temporarly 00530B6C 00530B6C loc_530B6C: ; CODE XREF: start+8Fj 00530B6C mov eax, ds:current 00530B71 mov ds:lpProcName, eax ; save this procname offset at the right place 00530B76 push eax 00530B77 call ds:adr_lstrlen ; calculate procname string length 00530B7D cmp eax, 1 ; is it an ordinal import ? 00530B80 jz short loc_530BDB ; go to ordinal treatment 00530B82 inc eax 00530B83 add ds:current, eax ; adjust the current offset to the next string 00530B89 mov ebx, ds:current ; its a modulename now, we get the address 00530B8F push ebx ; lpModuleName 00530B90 call ds:GetModuleHandleA ; calculate the modulename handle for getprocaddress 00530B96 push ds:lpProcName ; get the previous procname to calculate the real address 00530B9C push eax ; hModule 00530B9D call ds:GetProcAddress 00530BA3 nop 00530BA4 00530BA4 loc_530BA4: ; CODE XREF: start+C7j 00530BA4 mov ebx, eax ; save the procname address for the import table in ebx 00530BA6 push ds:current 00530BAC call ds:adr_lstrlen ; calculate the modulename length 00530BB2 inc eax 00530BB3 add ds:current, eax ; actualise the current offset, it points now to the apps thunk import table address 00530BB9 mov ecx, ds:current 00530BBF mov eax, [ecx] ; get the app's address 00530BC1 mov [eax], ebx ; save the procname's address into import thunk table 00530BC3 add ds:current, 5 ; actualise the current offset to point to the next modulename 00530BCA cmp ds:current, offset unk_530B07 ; are we at the table's end ? 00530BD4 jl short loc_530B6C ; repeat to the next import table address 00530BD6 jmp loc_4DE384 ; jump to app's entry point 00530BDB ; --------------------------------------------------------------------------- 00530BDB 00530BDB loc_530BDB: ; CODE XREF: start+3Bj 00530BDB xor edx, edx 00530BDD mov ecx, ds:lpProcName ; get the ordinal import offset 00530BE3 mov dl, [ecx] ; get the export ordinal number 00530BE5 inc eax 00530BE6 add ds:current, eax ; actualise the current offset to point to modulename 00530BEC mov eax, ds:current 00530BF1 mov ds:dword_530B20, edx ; save the ordinal 00530BF7 push eax ; lpModuleName 00530BF8 call ds:GetModuleHandleA ; get the modulename's handle 00530BFE mov edx, ds:dword_530B20 ; retrieve the procname's exported ordinal 00530C04 push edx ; lpProcName 00530C05 push eax ; hModule 00530C06 call ds:GetProcAddress ; get the exported ordinal address, kernel32 comparestringa is 25 for example 00530C0C jmp short loc_530BA4 ; save the procname address for the import table in ebx 00530C0C start endp 00530C0C 00530C0C
When you're finished, arm softice with a bpx getversion, launch commview (from the commview's original directory) at the third hit, do a bpx at 530b45 so you can check if the rebuilder works. If everything is fine, the rebuilder must generate valid api addresses until commview's last address at 4e3994.
It it works, congratulations, you've builded a fake import inside your dumped commview.
When the rebuilder finish its work, it jumps to the commview's entry point 4de384.
It will direct exit, because there is a crc check, we have to patch this code inside the dumped commview : 004DE3B9 call sub_4524A0 004DE3BE mov eax, [ebp+var_10] 004DE3C1 call sub_465118 004DE3C6 cmp eax, 6F200h 004DE3CB jz short loc_4DE3D2 <- patch to jmp 4de3d2 004DE3CD call sub_403BB4
Don't forget one thing, there is still an anti softice left. Reactivate the bpx createfilea do "d esp->4"; press F12 when it hits then invert the jz just after.
Launch again, it's now working and you're ready to continue the reversing of this crippled, time trial exe.
5) What's left to crack ?
Now the real work is finished, we can patch whatever we want inside. I will easily give you the patches, just because this section was not the main part of my essay, this will surely save you some work. To finish its agony, we dwelve with :
-Anti softice routine : typical one, just after the well known createfileA : 0046573E call sub_406D0C (createfileA with softice driver as an argument) 00465743 00465743 crack5: 00465743 cmp eax, 0FFFFFFFFh is it loaded ? 00465746 jz short loc_465750 <- patch this to jump 00465748 push eax 00465749 call sub_406CEC 0046574E mov bl, 1 -The time limit :You usually find those after a bpx to getlocaltime, and trace after.
004D8D5B call sub_44EB74 ; this call contains a call to getlocaltime 004D8D60 004D8D60 loc_4D8D60: ; CODE XREF: sub_4D899C+386j 004D8D60 mov eax, ds:dword_4E051C 004D8D65 cmp byte ptr [eax], 0 ;is the trial finished ? 004D8D68 004D8D68 jnz short loc_4D8DB8 <- force this to jump 004D8D6A mov eax, ds:dword_4E0378
another place :
004D8D60 loc_4D8D60: ; CODE XREF: sub_4D899C+386j 004D8D60 mov eax, ds:dword_4E051C 004D8D65 cmp byte ptr [eax], 0 004D8D68 004D8D68 crack4: ; time limit, force to jump 004D8D68 jmp short loc_4D8DB8
and also : 00489688 crack6: ; time trial fix patch to jump 00489688 jmp short loc_48968E 0048968A ; --------------------------------------------------------------------------- 0048968A mov byte ptr [ebp-1], 1 0048968E 0048968E loc_48968E: ; CODE XREF: sub_4894A0+72j 0048968E ; sub_4894A0+7Cj ... 0048968E cmp [ebp+var_1], 1 00489692 jnz short crack7 ; time trial fix 00489694 mov ds:byte_4E1C19, 1 0048969B 0048969B crack7: ; CODE XREF: sub_4894A0+1F2j 0048969B mov eax, 120020h ; time trial fix force this value and nop 004896A0 nop 004896A1 mov ds:byte_4E1C1A, 1
another patches, otherwise random exits
004DA57C mov eax, ds:dword_4E02EC 004DA581 cmp byte ptr [eax], 1 004DA584 004DA584 crack9: 004DA584 jmp short loc_4DA5AB ;patch to jump 004DA586 ; --------------------------------------------------------------------------- 004DA586 call sub_4D03AC 004DA58B lea ecx, [ebp-4] 004D8F3B loc_4D8F3B: ; CODE XREF: CODE:004D8F11j 004D8F3B call sub_4894A0 004D8F40 test al, al 004D8F42 004D8F42 crack10: 004D8F42 jmp short loc_4D8F7D ;patch to jump 004D8F44 ; --------------------------------------------------------------------------- 004D8F44 mov eax, ds:dword_4E02EC 004D8F49 cmp byte ptr [eax], 1 call sub_4894A0 004DA8D9 test al, al 004DA8DB 004DA8DB crack11: ; patch to nop 004DA8DB nop 004DA8DC nop 004DA8DD call sub_4D085C 004DA8E2 retn
-half of the packets displayed : an easy one with ida, just find the reference to string :
0048B5A4 push offset loc_48BB1C 0048B5A9 push dword ptr fs:[eax] 0048B5AC mov fs:[eax], esp 0048B5AF cmp byte ptr [ebx+5Fh], 0 0048B5B3 0048B5B3 nop ; nop those so it never jumps to 48b5c2, you guessed why 0048B5B4 nop 0048B5B5 lea edx, [ebp-14h] 0048B5B8 mov eax, [ebx+22h] 0048B5BB call sub_48A7C0 0048B5C0 jmp short loc_48B5CF 0048B5C2 ; --------------------------------------------------------------------------- 0048B5C2 lea eax, [ebp-14h] 0048B5C5 mov edx, offset aDataThisEvalua ; "DATA:THIS EVALUATION VERSION DISPLAYS O"... 0048B5CA call sub_403E08 you have two more places to do the same, find them and correct the *bug* .
-the annoying nag when you leave commview: I found it after a bpx to createwindowsexa, you have to press F12 a lot of times to find this routine : 00459718 loc_459718: ; CODE XREF: sub_45969C+6Cj 00459718 ; sub_45969C+70j 00459718 mov eax, [ebp+var_C] 0045971B mov edx, [eax] 0045971D nop <- you have to nop this call to avoid the nag 0045971E nop 0045971F nop 00459720 nop 00459721 nop 00459722 nop 00459723 mov [ebp-8], eax 00459726 xor eax, eax 00459728 pop edx 00459729 pop ecx 0045972A pop ecx 0045972B mov fs:[eax], edx 0045972E push offset loc_459743 00459733 00459733 loc_459733: ; CODE XREF: CODE:00459741j 00459733 mov eax, [ebp+var_C] 00459736 call sub_403024 0045973B retn Now you can enjoy your new portsniffer, auto rebuilded by itself, just like it always should be.
I need your feedback for this essay, so please write your comments after trying it at the msgboard : http://www.insidetheweb.com/mbs.cgi/mb155985
You can join all the Fravia's forums at sandman's , where I had this idea : http://www.insidetheweb.com/mbs.cgi/mb628842
Or on the Fravia msgboard, for intermediate and advanced ones : http://www.insidetheweb.com/mbs.cgi/mb155985
Thanks to Eternal Bliss ,r!sc and SV for their preliminary work on that interesting target.