Removing ASProtect 1.22 - 1.23 Beta 21 and hacking Lemonade Tycoon v1.1.6
Removing ASProtect 1.22 - 1.23 Beta 21 and hacking Lemonade Tycoon v1.1.6
Target: Lemonade Tycoon v1.1.6 (2100kb)
What else is needed:
1. OllyDbg + OllyDump plugin
2. ImpRec 1.6 Final
3. IDA
4. Hiew or any other hexadecimal editor
4. Beck's beer, 0.5;)
Victim
Our target is one uncomplicated toy. But the most important is that it is spoiled with "ASProtect 1.22 - 1.23 Beta 21", which PEID has kindly told us about:The victim is still unreachable for the brutal intrigues of the disassembler;)
Search OEP
We will not use autocompackers like AsprStripperXP and therefore we will run OllyDbg and open the executable file of the program in the debugger.Entry Point
To successfully find the original entry point of the victim, we must include memory access voilation, access violation. We go into the debugging option (by pressing Alt + O) and set the checkboxes as in the picture below:
Enabling Exception Handling
Return to the "CPU" window OllyDbg and begin to pass exceptions (by pressing Shift + F9). After 27 times (if you press Shift + F9 one more time, our program will run OEP and start), we will appear at .D405CC
The "CPU" window after processing 27 exceptions
Next, you need to put a breakpoint on the command RETN (.D40609) and order the olk to "get" to it by pressing Shift + F9 again. The final step in the OEP search will be to install a crack on Asprom access to the code section of the protected application. To do this, press Alt + M (to bring up the "Memory Map" window) and press F2 on the second section of the specified process. In our case, this is Lemonade codesection at 00401000.
A crack to access the code section
Last time press on Shift + F9 and EVERYTHING !!! We are at OEP. In order to believe it all, you can press Ctrl + A and olka will analyze the code and the disassembler listing instead of incomprehensible single-byte expressions will find the "human" form =)
And here is OEP!
We make a dump
Select the Plugins-OllyDump-Dump debugged process from the main menu and click "Dump" in the pop-up window (before removing the "Rebuild import" flag so that OllyDump does not attempt to restore the import of the dump itself).
We make a dump using the plugin OllyDump
About addresses of an entry point and sections it is possible not to worry, as OllyDump itself calculates them.
Import recovery
Simply so a dump (I named a file dumped.exe) will not be launched - it needs to restore the table of the imported functions. To do this, run ImpRec and select our explored Lemonade.exe process in it (it will still "stand" on OEP, because Olly we have not closed with it yet). In the "OEP" field, enter the address of our OEP (which is 4FB6B) and click on "IAT AutoSearch" - "Get Imports" - "Show Invalid". We get a couple of hundred undefined functions. To restore them, we will try to trace in 2 stages. In the first one, right-click on one of the highlighted undefined functions and select "Trace Level1 (Disasm)" in me. In the second step, we click on "Show invalid" again, and then restore the functions with Plugin Tracers plug-in - Asprotect 1.22.
Imprec restores import ...
After the manipulations in the log window will appear such an inscription
Import successfully restored ...
This indicates that the import is restored and you can modify our dump (dumped.exe) by clicking on the "Fix Dump"
Dump successfully modified ...
So, we got a fully working unpacked file (dumped_.exe)!
PEID confirms that aspr is successfully removed
Let's start analyzing it ...
Debugging and hacking the victim with a patch
Download the unpacked prog in the debugger. Since to enter the registration data it uses standard input windows,
The login screen
And a standard error window, it was decided in the old fashion to set breakpoints on calls to the MessageBoxA functions (output error messages) or GetDlgItemTextA (reading the input text).
Installing the bugs on the call to the MessageBoxA functions
Clicking on the "Enter License Information" button resulted in such a piece of code in the olk:
Interrupted on the output error length of the regcode (it should be equal to 20)
What was my surprise when I traced the sections checking the length of the entered registration data (.0042563A), a bunch of string and arithmetic conversions with them (.00425692) and writing the questionable keys to the registry, I did not find their subsequent reading either by installing the bryaks on the appropriate api, Nor with the help of RegMon (of course, everything was tested after the program was reloaded)! It turned out that the reason for this was the following section of the code:
Seg000: 00425D99 call esi ; DialogBoxParamA ; Create a modal dialog box from a Seg000: 00425D99 ; Dialog box template resource Seg000: 00425D9B mov edi , eax seg000: 00425D9D Seg000: 00425D9D loc_425D9D:; CODE XREF: sub_425C59 + 12Dj Seg000: 00425D9D cmp edi , 3EBh seg000: 00425DA3 jnz short loc_425DAA ; Jmp if no data were entered Seg000: 00425DA5 call sub_425228 ; CreateProcessA Seg000: 00425DAA Seg000: 00425DAA loc_425DAA:; CODE XREF: sub_425C59 + 14Aj Seg000: 00425DAA mov eax , edi seg000: 00425DAC Seg000: 00425DAC loc_425DAC:; CODE XREF: sub_425C59 + 178j Seg000: 00425DAC pop edi seg000: 00425DAD pop esi seg000: 00425DAE pop ebx seg000: 00425DAF leave Seg000: 00425DB0 retnIe, after entering reg.data, the main application window was simply deactivated and the application was closed. But the most interesting is that before that (.00425DA5) there was a call to a function that created a new process-a copy of the process that was just started by us-the victim (ala CopeMemII armas, although in the process of hacking this feint, in my opinion, did not add any complexity, except Unusualness). Here is a piece of the procedure code sub_425228, which it confirms.
Seg000: 00425278 lea eax , [ebp + ProcessInformation ] Seg000: 0042527B mov [ebp + StartupInfo.cb ] , 44h seg000: 00425282 mov [ebp + StartupInfo.dwFlags ] , 40h seg000: 00425289 push eax ; LpProcessInformation Seg000: 0042528A lea eax , [ebp + StartupInfo ] Seg000: 0042528D push eax ; LpStartupInfo Seg000: 0042528E push esi ; LpCurrentDirectory Seg000: 0042528F push esi ; LpEnvironment Seg000: 00425290 push esi ; DwCreationFlags Seg000: 00425291 push esi ; BInheritHandles Seg000: 00425292 push esi ; LpThreadAttributes Seg000: 00425293 push esi ; LpProcessAttributes Seg000: 00425294 lea eax , [ebp + ApplicationName ] seg000: 0042529A push esi ; LpCommandLine Seg000: 0042529B push eax ; LpApplicationName Seg000: 0042529C call ds: CreateProcessA seg000: 004252A2 pop esi seg000: 004252A3 leave Seg000: 004252A4 retn Seg000: 004252A4 sub_425228 endp Seg000: 004252A4By flipping the code a bit higher, I understood why the registers recorded in the registry were not read at startup. It turned out that when creating the process, a unique mutex was created that "let know" to the parent process whether the child process was started as a "launch toy" or as "to verify the correctness of the data." Since the checks after entering the name-code were already in the pre-process, and in OllyDbg they could not be caught (at the time of connection to the newly created process all the checks were already passed, and there was no possibility of using a decent ring0-mode debugger), then I decided to go On some trick: modify the binaries of the file being examined in such a way that the first of the lines of its executable functions (for example, WinMain) was a loop (EBFE opcode). So the process created was looped and I would be able to connect to it on time and restore the original 2 bytes of code quietly to search for the necessary areas. But, unfortunately, trying to implement the described method was spent half an hour, and the child process was not obsessed with anything! Not wanting to spend any more time finding the cause (which apparently consisted of duplicating Main functions in the victim), I decided to go with a more "traditional" method and put the parsers in the parent process to call TerminateProcess and ExitProcess;)
Put brushes on the calls to the application shutdown functions
We launch our file, enter the required reg data (I entered the name: ProTeuS and the code: 1234567890abcdeABCDE) and without problems get the desired point (.44A841)
Detect call point for the application's shutdown function
Rising several levels up the structure of the disassembled listing in IDA we see the following code:
Seg000: 004247A0 Seg000: 004247A0 ; --------------- SUBROUTINE ---------------------------------- ----- Seg000: 004247A0 Seg000: 004247A0 ; Attributes: bp-based frame Seg000: 004247A0 Seg000: 004247A0 sub_4247A0 proc near ; CODE XREF: sub_437940 + 26p Seg000: 004247A0 ; Sub_437940 + 3Bp Seg000: 004247A0 Seg000: 004247A0 var_200 = dword ptr -200h Seg000: 004247A0 Seg000: 004247A0 push ebp seg000: 004247A1 mov ebp , esp seg000: 004247A3 sub esp , 200h seg000: 004247A9 push esi seg000: 004247AA push dsi seg000: 004247AB call sub_437940 seg000: 004247B0 mov dword ptr [eax + 20h ] , offset aLemonade ; "Lemonade" Seg000: 004247B7 call sub_437940 seg000: 004247BC mov dword ptr [eax + 24h ] , offset aLemonadeTycoon ; "Lemonade Tycoon" Seg000: 004247C3 call sub_437940 seg000: 004247C8 mov dword ptr [eax + 28h ] , offset a1_1_5 ; "1.1.5" Seg000: 004247CF call sub_437940 seg000: 004247D4 mov dword ptr [eax + 28h ] , offset a1_1_6 ; "1.1.6" Seg000: 004247DB call sub_437940 seg000: 004247E0 mov dword ptr [eax + 1Ch ] , offset aB6081ca706b415 ; "{B6081CA-706B-415E-AE52-910C4FB06016}" Seg000: 004247E7 call sub_437940 seg000: 004247EC mov dword ptr [eax + 10h ] , offset a1_0 ; "1.0" Seg000: 004247F3 call sub_437940 seg000: 004247F8 mov dword ptr [eax + 14h ] , offset a72733b3Ac0f4d4 ; "{72733B3-AC0F-4D43-BED1-25EE1194A7BA}" Seg000: 004247FF call sub_437940 seg000: 00424804 mov dword ptr [eax + 18h ] , offset a48033dc6A54144 ; "{48033DC6-A541-4454-A9CE-3186C3365B75}" Seg000: 0042480B call sub_437940 seg000: 00424810 mov dword ptr [eax + 88h ] , 96h seg000: 0042481A call sub_437940 seg000: 0042481F xor edi , edi seg000: 00424821 push 68h seg000: 00424823 mov [eax + 34h ] , edi seg000: 00424826 pop esi seg000 : 00424827 Seg000: 00424827 loc_424827:; CODE XREF: sub_4247A0 + 98j Seg000: 00424827 call sub_437940 seg000: 0042482C mov [eax + esi] , edi seg000: 0042482F add esi , 4 seg000: 00424832 cmp esi , 84h seg000: 00424838 jl short loc_424827 seg000: 0042483A call sub_4263DD ; Check function Seg000: 0042483F test eax , eax seg000: 00424841 jz short loc_42484A seg000: 00424843 push 1 ; Int Seg000: 00424845 call _exit seg000: 0042484A ; -------------------------------------------------- ------------------------- Seg000: 0042484A Seg000: 0042484A loc_42484A:; CODE XREF: sub_4247A0 + A1j Seg000: 0042484A call sub_4264BC ; Eax = ds: dword_57F99C Seg000: 0042484F test eax , eax seg000: 00424851 jz short loc_42489B ; JMP if eax = 1 (in the other process) Seg000: 00424853 mov esi , ds: GetModuleHandleA seg000: 00424859 lea eax , [ebp + var_200 ] seg000: 0042485F push eax ; Char * Seg000: 00424860 push edi ; LpModuleName Seg000: 00424861 call esi ; GetModuleHandleA Seg000: 00424863 push eax ; HInstance Seg000: 00424864 call sub_426404 seg000: 00424869 pop ecx seg000: 0042486A lea eax , [ebp + var_200 ] seg000: 00424870 pop ecx seg000: 00424871 mov ds: dword_57F988 , edi seg000: 00424877 push eax ; Int Seg000: 00424878 push edi ; LpModuleName Seg000: 00424879 call esi ; GetModuleHandleA Seg000: 0042487B push eax ; HInstance Seg000: 0042487C call sub_425C59 ; ReadParametrs Seg000: 00424881 pop ecx seg000: 00424882 cmp eax , 3EBh seg000: 00424887 pop ecx seg000: 00424888 jnz short loc_424891 seg000: 0042488A push 1 ; Int Seg000: 0042488C call _exit ; Close the application after entering the data. Seg000: 00424891 ; -------------------------------------------------- ------------------------- Seg000: 00424891 Seg000: 00424891 loc_424891:; CODE XREF: sub_4247A0 + E8j Seg000: 00424891 mov ds: dword_57F988 , 1 seg000: 0042489B Seg000: 0042489B loc_42489B:; CODE XREF: sub_4247A0 + B1j Seg000: 0042489B pop edi seg000: 0042489C pop esi seg000: 0042489D leave ; Jump to .4365C9 Seg000: 0042489E retn Seg000: 0042489E sub_4247A0 endp Seg000: 0042489EIt's easy to guess that 0042483A call sub_4263DD is nothing more than a call to the check function, which affects the scan at .0042484F. It is from its test results that it depends on whether the ExitProcess function is called, or whether the normal order of operation will be restored in case of entering the user's registration and launching the toy.
Looking at the called function 0042484A call sub_4264BC, we see that the register eax is entered 1, the contents of the memory location at address 57F99C.
Seg000: 004264BC Seg000: 004264BC ; --------------- SUBROUTINE ---------------------------------- ----- Seg000: 004264BC Seg000: 004264BC Seg000: 004264BC sub_4264BC proc near ; CODE XREF: sub_413B78 + 5Cp Seg000: 004264BC ; Sub_4157E8 + 531p ... Seg000: 004264BC mov eax , ds: dword_57F99C seg000: 004264C1 retn Seg000: 004264C1 sub_4264BC endp Seg000: 004264C1It is logical to assume that before this, during the check in this same cell, a record is made in the case of entering the wrong data. And if the cell contains 0, then the program will constantly skip the verification phase for registration and immediately start the game. To find the place of verification, restart the victim and set the breakpoint to write to the specified memory location:
Bryak to write to the memory cell, the filthy registration status
Click on F9 and before us there is such a piece of code:
Seg000: 00426296 seg000: 00426296 push ebp seg000: 00426297 mov ebp, esp seg000: 00426299 sub esp, 530h seg000: 0042629F push esi seg000: 004262A0 xor esi, esi seg000: 004262A2 cmp ds: dword_57F9A0, esi seg000: 004262A8 jnz loc_4263DA seg000: 004262AE lea eax , [ Ebp + KeyName ] seg000: 004262B4 push offset a1831 ; "183-1" Seg000: 004262B9 push eax seg000: 004262BA mov ds: dword_57F99C , 1 ; Writes 1 to the memory in the case of incorrect data entry Seg000: 004262C4 call ds: lstrcpyAddress .004262A2 see an interesting team compared the cell 57F9A0 to 0. This is the place to check the countdown 60 seconds since the start of the game (click on .4262A2, click the right mouse button, select "Find References to - Address constant" and see the address. appropriate code 00426046 MOV DWORD PTR DS:. [57F9A0 ], 1 It is executed only if you are registred user, and "lets you know" game that does not need to be interrupted after a minute runtime). If the content of the cell 57F9A0 is 0, the game will crash even after the registration status variable has been patched! So, to complete a security breach is necessary to change the result of checking at 004262A2, that at least one of the operands, and amounted to 1, instead of comparing the content 57F9A0 to 0 (address .4261D6) cells burn to 1. To not use a massive operation with the modification of memory cells can be simply Enter 1 in the esi register. To do this, you can replace the command xor esi, esi at 004262A0 with inc esi and nop (opcodes 46 90). Instead of CMP DWORD PTR DS: [57F9A0], 0 should be written INC DWORD PTR DS: [57F9A0], because by default the program will store the unregistered 0 there and we thus optimizing the code introduce into the contents of the memory cell 1. At the request of the next conditional branch JNE Cracked.00426292 can be replaced by an unconditional JMP cracked.00426292. This is done in any hex editor. I chose the Hiew. Patching To open it dumped_.exe file 2 times we press Enter, then the F5, enter .4262A0, click the F3, enter 46 90. The same is done for the other teams, which can oppkody will see on the screenshot below. Save the changes F9.
Patches a binary game in hex editor Hiew
Now the program is fully operational. Running the game takes place immediately, without outputting any naga and interrupts in the middle of the game process.
Files to article:
Target: Lemonade Tycoon v1.1.6 (2100kb)
Dump with restored import: dumped_.rar
Gl hf 2 all
05.01.2006
Comments
When commenting on, remember that the content and tone of your message can hurt the feelings of real people, show respect and tolerance to your interlocutors even if you do not share their opinion, your behavior in the conditions of freedom of expression and anonymity provided by the Internet, changes Not only virtual, but also the real world. All comments are hidden from the index, spam is controlled.