تبلیغات :
خرید لپ تاپ استوک
ماهان سرور
آکوستیک ، فوم شانه تخم مرغی ، پنل صداگیر ، یونولیت
دستگاه جوجه کشی حرفه ای
فروش آنلاین لباس کودک
خرید فالوور ایرانی
خرید فالوور اینستاگرام
خرید ممبر تلگرام

[ + افزودن آگهی متنی جدید ]




صفحه 6 از 17 اولاول ... 234567891016 ... آخرآخر
نمايش نتايج 51 به 60 از 163

نام تاپيک: آموزش کرک و قفل شکنی ( انگلیسی ) از بهترین کرکرهای روس و ...

  1. #51
    پروفشنال Morteza_SOS's Avatar
    تاريخ عضويت
    Apr 2006
    پست ها
    577

    پيش فرض

    Yoda's Protector v1.03.2 – manually unpacking tutorial
    Contributed by: haggar
    Level : beginner

    1. Intro

    Hi and welcome to my new small tutorial about unpacking latest yoda’s protector. This tutorial will not go in the depth of new yoda’s anti-debug tricks, we will work around that field simply because got lost in all that SetThreadPriority, Block input and all that s**t that Ashkbiz Danehkar has thrown inside.
    Restarting computer every time when you forget to place bp on a right place is not funny.

    Anyway, here is content:

    You will need next tools:
    - OllyDbg 1.10 (ollydump plugin too)
    - ImpREC
    - PEiD
    - LordPE
    - dUP2 - diablo2oo2's Universal Patcher
    - هدف تمامی فایل های محافظت شده با این پروتکتور.

    2. Unpacking

    As we said, yoda doesn’t steal OEP bytes, it does not interferes with the unpacked program in memory, even IAT redirection is very simple – it’s not changed from the early beginning. This all goes to our favor. We will not approach to unpacking in usual way, tracing to OEP and avoiding anti-debug tricks, but let’s not just talk.
    Grab target “keygenme1.exe” that I packed with latest yoda. I used all options that yoda offers, except header erasing because target crushed with that option.
    So run target and open OllyDbg.
    In Olly menu chose “File” ->“Attach”, select path to our target and click attach button.
    Target will freeze and Olly will stop at system bp:



    77F767CE C3 RETN
    77F767CF > CC INT3
    77F767D0 C3 RETN
    77F767D1 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+4]
    77F767D5 CC INT3
    77F767D6 C2 0400 RETN 4
    77F767D9 > 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
    77F767DF C3 RETN
    77F767E0 > 57 PUSH EDI
    77F767E1 8B7C24 0C MOV EDI,DWORD PTR SS:[ESP+C]

    Open executables window and double click on our target. Then press Ctrl+A to analyze module.

    You should be here:


    00401000 /$ 33C0 XOR EAX,EAX
    00401002 |. 394424 08 CMP DWORD PTR SS:[ESP+8],EAX
    00401006 |. 7E 14 JLE SHORT Crackme_.0040101C
    00401008 |> 8B4C24 04 /MOV ECX,DWORD PTR SS:[ESP+4]
    0040100C |. 8B0C81 |MOV ECX,DWORD PTR DS:[ECX+EAX*4]
    0040100F |. 3B4C24 0C |CMP ECX,DWORD PTR SS:[ESP+C]
    00401013 |. 74 0A |JE SHORT Crackme_.0040101F
    00401015 |. 40 |INC EAX
    00401016 |. 3B4424 08 |CMP EAX,DWORD PTR SS:[ESP+8]
    0040101A |.^7C EC JL SHORT Crackme_.00401008
    0040101C |> 32C0 XOR AL,AL
    0040101E |. C3 RETN
    0040101F |> B0 01 MOV AL,1
    00401021 . C3 RETN
    00401022 /$ 55 PUSH EBP
    00401023 |. 8BEC MOV EBP,ESP
    00401025 |. 51 PUSH ECX
    00401026 |. 51 PUSH ECX

    You are in the target code now. Press F9 and target will run normally, you could now do whatever you want with it. Our next step would be to find where is OEP of packed file.
    This part that could be the hardest thing for us, but not necessary. There are couple ways to find where OEP should be. This is one approach. Open memory window:


    Memory map
    Address Size Owner Section Contains Type Access Initial

    Mapped as
    00400000 00001000 Crackme_ PE header Imag RW RWE
    00401000 00004000 Crackme_ code,data Imag RW RWE
    00405000 0000E000 Imag RW RWE
    00420000 00006000 Map R E R E
    004E0000 00002000 Map R E R E
    004F0000 00103000 Map R R

    Place memory bp on access to code section and then try to click on crackme. You will probably stop here:

    0040129C /. 55 PUSH EBP
    0040129D |. 8BEC MOV EBP,ESP
    0040129F |. 8B45 0C MOV EAX,DWORD PTR SS:[EBP+C]
    004012A2 |. 83E8 10 SUB EAX,10
    004012A5 |. 0F84 A0000000 JE Crackme_.0040134B
    004012AB |. 2D 00010000 SUB EAX,100
    004012B0 |. 74 50 JE SHORT Crackme_.00401302
    004012B2 |. 48 DEC EAX
    004012B3 |. 0F85 9D000000 JNZ Crackme_.00401356
    004012B9 |. 0FB745 10 MOVZX EAX,WORD PTR SS:[EBP+10]

    If you are not there – it doesn’t matters. Important is that crackme is suspended so we can dump now. So dump it with OllyDump plugin, but uncheck “Rebuild import” option.
    Entry point of this dump also isn’t important for now (don’t close olly after dumping). Now scan dumped file with PEiD. It will show “Microsoft Visual C++ 6.0”. This is important because programs compiled with same version of compilers have similar OEP. Using PEiD, find on your drive some exe that is compiled with this version Visual C++. I found flashget.exe, a download manager.
    Its OEP looks like this:


    004A2F61 >/$ 55 PUSH EBP
    004A2F62 |. 8BEC MOV EBP,ESP
    004A2F64 |. 6A FF PUSH -1
    004A2F66 |. 68 000D4F00 PUSH flashget.004F0D00
    004A2F6B |. 68 5C7F4A00 PUSH flashget.004A7F5C ; SE handler installation
    004A2F70 |. 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
    004A2F76 |. 50 PUSH EAX
    004A2F77 |. 64:8925 000000> MOV DWORD PTR FS:[0],ESP
    004A2F7E |. 83EC 58 SUB ESP,58
    004A2F81 |. 53 PUSH EBX
    004A2F82 |. 56 PUSH ESI
    004A2F83 |. 57 PUSH EDI ; ntdll.77F5164E
    004A2F84 |. 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
    004A2F87 |. FF15 0C234E00 CALL DWORD PTR DS:[<&KERNEL32.GetVersion
    004A2F8D |. 33D2 XOR EDX,EDX
    004A2F8F |. 8AD4 MOV DL,AH
    004A2F91 |. 8915 186A5100 MOV DWORD PTR DS:[516A18],EDX
    004A2F97 |. 8BC8 MOV ECX,EAX
    004A2F99 |. 81E1 FF000000 AND ECX,0FF

    OEP in our packed crackme will be very similar to this one so we need to find these combinations of opcodes in it. Of course, scrolling down and trying to recognize something like this is impossible with bigger file, but we can speed that.
    Binary copy all bytes from flasget.exe (or some app that you found on your hard drive starting from 4A2F70 to 4A2F84.

    Close that olly and go to first one, in which is our target.
    Scroll to the 401000 address, left click on the first line, then right-click and chose “Search for” -> “Binary String” and paste content of clipboard to “Hex + xx” field. Then check “Entire block” and click “OK” button.

    First address where olly found same bytes is here:


    004014B4 /. 55 PUSH EBP
    004014B5 |. 8BEC MOV EBP,ESP
    004014B7 |. 6A FF PUSH -1
    004014B9 |. 68 C0504000 PUSH 4050C0
    004014BE |. 68 9C224000 PUSH 40229C ; SE handler installation
    004014C3 |. 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
    004014C9 |. 50 PUSH EAX
    004014CA |. 64:8925 000000>MOV DWORD PTR FS:[0],ESP
    004014D1 |. 83EC 58 SUB ESP,58
    004014D4 |. 53 PUSH EBX
    004014D5 |. 56 PUSH ESI ; Crackme_.0040129C
    004014D6 |. 57 PUSH EDI
    004014D7 |. 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
    004014DA |. FF15 30504000 CALL DWORD PTR DS:[405030]
    004014E0 |. 33D2 XOR EDX,EDX
    004014E2 |. 8AD4 MOV DL,AH
    004014E4 |. 8915 80854000 MOV DWORD PTR DS:[408580],EDX

    Bold opcodes are our match. But there are more locations with same bytes so we need to be more sure.
    Click on 4014DA line and press ENTER to follow that address in CPU window.
    You will land here:


    0014B684 -E9 0C1AD377 JMP kernel32.GetVersion
    0014B689 -E9 D5E1D277 JMP kernel32.ExitProcess
    0014B68E -E9 D85EE077 JMP ntdll.RtlFreeHeap
    0014B693 -E9 0960E077 JMP ntdll.RtlAllocateHeap
    0014B698 -E9 1B60D177 JMP kernel32.TerminateProcess
    0014B69D -E9 6A2FD377 JMP kernel32.GetCurrentProcess
    ….
    ….

    You can see that it points to redirected API and not any API, but to GetVersion. That API is usually the first one used in this version of VC++ so we are at the right place, our OEP is:


    004014B4 /. 55 PUSH EBP
    004014B5 |. 8BEC MOV EBP,ESP
    004014B7 |. 6A FF PUSH -1



    If you cannot find OEP, or you find more possible OEP’s, then experiment a little and open different files on your drive to learn how OEP’s looks. You can close all olly’s now.
    You could now fix IAT with ImpREC and repair dump with this OEP, but with bigger files that dump will crush. I don’t know the actual reason, but we shouldn’t allow target to run and then dump it.
    We need to STOP target at the OEP and THEN dump it and fix imports.
    How we gonna stop file in memory without having target in debugger?
    I get one idea there, we could make a loader that will find OEP and replace it with EBFE bytes. That is infinite loop jump, a jump that jumps to itself. It means that such file in memory will be fully unpacked , but it will not be executed. Then we can attach to target and make good working dump.

    For making loader we will use dUP2 - diablo2oo2's Universal Patcher, a excellent pathing engine made by diablo2oo2 (well, you could use any loader engine that you like, I just lately often use this one which is very good). To learn how to use patcher read help files inside dUP2 packet. If you are lazy, mine loader “YodaOEP.exe” is included in this archive.

    You need to substitute these bytes (address --> byte):


    4014B4 --> 55
    4014B5 --> 8B
    with this ones:
    4014B4 --> EB
    4014B5 --> FE

    Make that loader and run it in the same folder with target “keygenme1.exe”. Uuuuups, CPU usage goes to 100%, remember that’s because infinite jump. Good sign, our loader has done it’s job.

    Now open Olly and attach to the target, double click to keygen1.exe process in the executables window, press Ctrl+A and in the memory window place memory bp on access to code section.
    Press F9 and you are at the program OEP:


    004014B4 >-EB FE JMP SHORT Crackme1.004014B4
    004014B6 EC DB EC
    004014B7 . 6A FF PUSH -1
    004014B9 . 68 C0504000 PUSH 4050C0
    004014BE . 68 9C224000 PUSH 40229C ; SE handler

    installation
    004014C3 . 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
    004014C9 . 50 PUSH EAX
    004014CA . 64:8925 000000>MOV DWORD PTR FS:[0],ESP
    004014D1 . 83EC 58 SUB ESP,58
    004014D4 . 53 PUSH EBX
    004014D5 . 56 PUSH ESI
    004014D6 . 57 PUSH EDI
    004014D7 . 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
    004014DA . FF15 30504000 CALL DWORD PTR DS:[405030]
    004014E0 . 33D2 XOR EDX,EDX
    004014E2 . 8AD4 MOV DL,AH
    004014E4 . 8915 80854000 MOV DWORD PTR DS:[408580],EDX

    Do you see first line? Our infinite jump is there. Before dumping we need to restore original bytes instead infinite jump EBEF. Replace it with 558B with binary editing:

    004014B4 55 PUSH EBP
    004014B5 8BEC MOV EBP,ESP
    004014B7 . 6A FF PUSH -1
    004014B9 . 68 C0504000 PUSH 4050C0
    004014BE . 68 9C224000 PUSH 40229C ; SE handler

    installation
    004014C3 . 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
    004014C9 . 50 PUSH EAX
    004014CA . 64:8925 000000>MOV DWORD PTR FS:[0],ESP
    004014D1 . 83EC 58 SUB ESP,58
    004014D4 . 53 PUSH EBX
    004014D5 . 56 PUSH ESI
    004014D6 . 57 PUSH EDI
    004014D7 . 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
    004014DA . FF15 30504000 CALL DWORD PTR DS:[405030]
    004014E0 . 33D2 XOR EDX,EDX
    004014E2 . 8AD4 MOV DL,AH

    That’s it! Now dump file with ollydump (uncheck import fixing) and run ImpREC. There attach to keygenme1.exe, input 14B4 as OEP and search for imports. I get two thunks and both are not valid. Newermind, trace with level 1 and you’ll find all imports.
    If maybe couple bad thunk has left, just cut it.
    Now fix dump and run it.
    It works great! Yep, you have defeated yoda’s protector 1.03.2

    منتظر سری جدید باشید به زودی ...

  2. #52
    پروفشنال Morteza_SOS's Avatar
    تاريخ عضويت
    Apr 2006
    پست ها
    577

    پيش فرض

    *** Armadillo – MANUALLY skinning the mutant ***

    ***** ***** by crUsAdEr ***** ****


    This tutorial aims to discuss about Armadillo 2.61 protection and how to MANUALLY remove the armadillo protection layer! Hopefully this will demonstrate some manual unpacking techniques that have been forgotten as crackers get more and more dependent on tools.

    TOOLS used :
    IDA 4.15
    Soft Ice on Win2k SP3
    LordPE Deluxe

    Targets : Get Right 5.0 beta 1


    Prologue

    Armadillo 2.61 just released with a few new features that make it slightly more interesting to reverse. The fact that Armadillo debugs its own protected program make it harder for us, crackers to debug the target but the good side is that Armadillo code is not obfuscated or encrypted in anyway so we can disassemble the protection layer and study it in IDA.

    i)All code snippets in this tutorial are taken from IDA disassembly, beside the IAT redirection part, code snippets in other parts of this tutorial can be found at the same address in IDA if you can obtain the same version of “getright.exe” file.

    ii) Throughout this essay, I used variable names like “d ebp+someName” to make it easier for readers to follow, when you are in sice, you have to type out the actual value, for example “d enp+FFFFFAE0”.

    iii)Armadillo protected programs starts 2 process, the protecting layer debugs the protected target so I shall refer to the debugger as “server” and the debugee as “client”.

    iv) Also note that IAT redirection on WIN9x is different from winNT/2k/XP so this essay only discuss IAT redirection on win2k though you can find the redirection routine on win9x in a similar way!

    (Finally, please READ those threads in Fravia board about Armadillo protection and also make SURE you have a solid understanding of PE format as it is essential to rebuild a working PE image!)




    1. Defeating copy-mem II

    OK, I hope you have already known what copy-mem II is and what it does. Standard routine, to find OEP do "bpx SetProcessWorkingSetSize"
    Once sice break, check it that sice is in Get Right context, if not then press F5 till sice breaks in Get Right context. Then press F12 and trace with F10 for a few instructions till you see a "call edi", stop there and note down the value of edi. That is OEP. Remove all breakpoint and "bpx WriteProcessMemory". Press F5, once sice breaks press F12 twice you will be at the usual decrypting routine of Armadillo that you have seen in previous version of Armadillo.

    005E03FF 6A 00 push 0 ; flag to indicate Decrypt if 0
    ; if flag is 1 then encrypt
    005E0401 8B 4D 0C mov ecx, [ebp+key_address]
    005E0404 51 push ecx
    005E0405 8B 55 08 mov edx, [ebp+block_no]
    005E0408 52 push edx
    005E0409 E8 76 01 00 00 call Decrypt_Encrypt
    005E040E 83 C4 0C add esp, 0Ch ; YOU SHOULD LAND HERE!!!!
    Try looping around these instructions to force it to decrypt all code section and you will get garbage because now each memory block of 1000h bytes has a diff decrypt key. So we will have to find the decrypt key generation routine.
    Trace a bit more down you will see this :

    0044E421 A1 88 9A 45 00 mov eax, ds:block_count
    0044E426 83 C0 01 add eax, 1 ; increment decrypted memory block
    0044E429 A3 88 9A 45 00 mov ds:block_count, eax ; in process counter

    0044E470 mov edx, ds:block_count ; compare number if decrypted blocks
    0044E476 3B 15 70 66 45 00 cmp edx, ds:max_number_of_decrypted_block ; with maximum no. allowed
    0044E47C 0F 8E FA 00 00 00 jle ok
    As you can guess, Armadillo store number of memory block already decrypted to make sure that not all blocks are decrypted in memory at anytime. If you do a “bpm max_number_of_decrypted_block” you will see that Armadillo calculates this value from text code section size divide by 1000h (number of memory blocks) then divide by 2. Here we now have 2 ways, patch the jump to make sure it always jump or we can change the value at ds:max_number_of_decrypted_block to 1000h, something big!!!!
    Once done, press F12 we will be in the middle of Debug loop of the Armadillo "server".

    0044D697 LOOP: ; Start looping here to force
    0044D697 8B 8D 2C FA FF FF mov ecx, [ebp+mem_block] ; decrypt the whole code section
    0044D69D 3B 0D 84 9A 45 00 cmp ecx, ds:text_section_size
    0044D6A3 0F 8D C7 00 00 00 jge continue_1 ;change to "jmp eip", infinite loop when finished
    0044D6A9 8B 95 9C FA FF FF mov edx, [ebp+trap_flag_not_set_flag]
    0044D6AF 81 E2 FF 00 00 00 and edx, 0FFh ;armadillo set trap flag at the beginning of
    0044D6B5 85 D2 test edx, edx ;its debug loop to check if it is being traced
    0044D6B7 0F 84 A9 00 00 00 jz continue_ok ; and it is checking for the flag now!
    0044D6BD 6A 00 push 0 ; instruct to decrypt code
    0044D6BF 8B B5 2C FA FF FF mov esi, [ebp+mem_block]
    0044D6C5 C1 E6 04 shl esi, 4 ;
    0044D6C8 8B 85 2C FA FF FF mov eax, [ebp+mem_block]
    ; Decrypt key Generation
    0044D73F 83 E7 0F and edi, 0Fh ; codes removed but u can refer to IDA
    0044D742 03 F7 add esi, edi ; disassembly
    0044D744 8B 15 74 9A 45 00 mov edx, ds:key_address_table
    0044D74A 8D 04 B2 lea eax, [edx+esi*4]
    0044D74D 50 push eax
    0044D74E 8B 8D 2C FA FF FF mov ecx, [ebp+mem_block]
    0044D754 51 push ecx
    0044D755 E8 86 0B 00 00 call Decrypt_codes ; push crypt_flag
    0044D755 ; push key_add
    0044D755 ; push memaddress
    0044D75A 83 C4 0C add esp, 0Ch ;YOU SHOULD LAND HERE!!!!
    0044D75D 25 FF 00 00 00 and eax, 0FFh
    0044D762 85 C0 test eax, eax ; here patch to increment the mem block
    0044D762 ; value to force decrypting the next block
    0044D764 74 0A jz short bad_jump ; then jump to LOOP0067B0E8
    Now we can see how Armadillo generates keys for each memory block and passed it to the Decrypt_codes routine. Also, we can understand why Armadillo exit silently if we single step on the "server-debugger" code. Here, we shall make the big loop containing the key generation routine to force armadillo decrypt the whole code section. At address 44D75D do

    a eip
    inc dword ptr [ebp+mem_block]
    jmp LOOP:44D697

    Then we edit the value at "ebp+mem_block" to 0 (tell Armadillo to start decrypting from first memory block), and set the end point at 44D6A3 by changing the instruction there to "jge 46D6A3". Here Armadillo is checking if the mem block is above the code section, we simply put an infinite loop there. Let the program runs on, wait a while and then fire up LordPE to make a full image dump. If LordPE reports "Can't grab memory" then you probably did something wrong and Armadillo hasn’t fully decrypted the code section. Once this is done, we can proceed to rebuild IAT.

    2. Rebuild Import data

    Open the packed file with LordPE and study the section header, you will notice import data should be in section .idata! Why? Because the name already say it... and you can also double check by open the file in Hex Workshop and go to that section offset, you will see scattering words like "kernel32.dll" and "user32.dll" etc... Import data should be there!

    Our task is to find the API redirection routine, study it and based on this routine to rebuild our Import.

    To find the IAT redirection routine, use "addr" command of sice to get into the context of the protected (client) program then
    bpm IAT_address W (Once break, disable this breakpoint)
    bpx GetProcAddress (Once break, disable this breakpoint)
    F12 twice and we should be here now

    10006622 39 3D E8 C7 01 10 cmp dll_handle_table, edi ; check if pointer is 0 because edi = 0 here
    10006628 B8 E8 C7 01 10 mov eax, offset dll_handle_table ; here is the Table listing
    1000662D 74 0C jz short no_special_IAT ; special DLL and their handles
    1000662F ; the APIs in these DLL will be redirected
    1000662F loop:
    1000662F 3B 48 08 cmp ecx, [eax+8] ; is dll handle same as handle listed
    10006632 74 1B jz short special_dll
    10006634 83 C0 0C add eax, 0Ch ; next dll on the table
    10006637 39 38 cmp [eax], edi
    10006639 75 F4 jnz short loop
    1000663B
    1000663B no_special_IAT: ; Get API address normally, no redirection!!!
    1000663B push dword ptr [ebp+0Ch] ; lpProcName
    1000663E FF 75 08 push [ebp+dll_handle] ; int
    10006641 E8 41 00 00 00 call GetProcAddr
    10006646 59 pop ecx WE SHOULD LAND HERE!!!!
    10006647 59 pop ecx
    >
    1000664F ; ---------------------------------------------------------------------------
    1000664F special_dll:
    1000664F 8B 40 04 mov eax, [eax+4] ; get Special IAT table
    10006652 3B C7 cmp eax, edi ; if eax = 0
    10006654 74 E5 jz short no_special_IAT
    10006656 39 78 08 cmp [eax+8], edi
    10006659 8B F0 mov esi, eax ; esi points to start of special API
    1000665B 74 DE jz short no_special_IAT ; name table… these APIs will be redirected
    1000665D
    1000665D API_name_check_loop:
    1000665D 66 3B DF cmp bx, di
    10006660 74 06 jz short loc_10006668
    10006662 66 3B 5E 04 cmp bx, [esi+4]
    10006666 EB 0E jmp short loc_10006676
    10006668
    10006668 loc_10006668:
    10006668 FF 36 push dword ptr [esi] ; The API name in special API table
    1000666A FF 75 0C push dword ptr [ebp+0Ch] ; our API name
    1000666D E8 8E 2B 01 00 call StringCompare
    10006672 59 pop ecx
    10006673 59 pop ecx
    10006674 85 C0 test eax, eax ; if API name is found on the table
    10006676 ; jump to Redirect_API_now
    10006676 loc_10006676:
    10006676 74 0A jz short Redirect_API_now
    10006678 83 C6 10 add esi, 10h ; if not, update pointer on table to next API
    1000667B 39 7E 08 cmp [esi+8], edi ; Is there anymore API on the table?
    1000667E 75 DD jnz short API_name_check_loop ; if Yes then loop back to check this API
    10006680 EB B9 jmp short no_special_IAT ; else go ahead and find API address normally
    10006682 ; ---------------------------------------------------------------------------
    10006682
    10006682 Redirect_API_now:
    10006682 8B 46 08 mov eax, [esi+8] ; eax = redirected API address
    10006685 EB C1 jmp short end_routine00A4A496 load_next_dl_import:
    The dll_handle_Table looks like this :

    1001C7E8 18 C8 01 10 dd offset strKernel32_dll ; "kernel32.dll"
    1001C7EC A8 C4 01 10 dd offset kernel32_API_table
    1001C7F0 00 00 00 00 kernel32_handle dd 0
    1001C7F4 0C C8 01 10 dd offset strUser32_dll ; "user32.dll"
    1001C7F8 C8 C7 01 10 dd offset User32_API_table
    1001C7FC 00 00 00 00 User32_handle dd 0
    The kernel32_API_table looks like this :

    1001C4A8 1C CB 01 10 dd offset strExitprocess ; "ExitProcess"
    1001C4AC 00 00 00 00 dd 0
    1001C4B0 77 6C 00 10 dd offset Fake_ExitProcess ; if string compare is same, this
    1001C4B4 00 00 00 00 dd ExitProcess_Address ; Fake_ExitProcess routine is used!!!
    1001C4B8 08 CB 01 10 dd offset strTerminateprocess ; "TerminateProcess"
    1001C4BC 00 00 00 00 dd 0
    1001C4C0 CA 6C 00 10 dd offset Fake_TerminateProcess
    1001C4C4 00 00 00 00 dd TerminateProcess_Address
    1001C4C8 FC CA 01 10 dd offset strExitthread ; "ExitThread"
    1001C4CC 00 00 00 00 dd 0
    1001C4D0 00 6D 00 10 dd offset Fake_ExitThread
    1001C4D4 00 00 00 00 dd ExitThread_Address
    etc...
    The User32_API_table looks similar of course!

    At this point, if you are lazy, you can simply patch the program to jump over the dll_handle_table scanning part, then our IAT will never be redirected and we can simply run Imprec or Revirgin on the running process to re-build IAT... BUT we are doing everything manually aren’t we ? So let's trace on. If you press F12 one more time, you will be in the middle Import loading loop,

    10010DED FF B5 70 FD FF FF push [ebp+API_name]
    10010DF3 FF B5 94 FD FF FF push [ebp+dll_handle]
    10010DF9 E8 FA 57 FF FF call Get_API_address
    10010DFE 89 85 78 FD FF FF mov [ebp+API_add], eax WE SHOULD LAND HERE!!!!
    10010E04 83 BD 78 FD FF FF 00 cmp [ebp+API_add], 0
    10010E0B 75 38 jnz short API_add_found

    10010E45 API_add_found :
    10010E45 8B 85 80 FD FF FF mov eax, [ebp+IAT_add]
    10010E4B 8B 8D 78 FD FF FF mov ecx, [ebp+API_add]
    10010E51 89 08 mov [eax], ecx HERE is where first thunk is updated!!!
    10010E53 8B 85 80 FD FF FF mov eax, [ebp+IAT_add]
    10010E59 83 C0 04 add eax, 4
    10010E5C 89 85 80 FD FF FF mov [ebp+IAT_add], eax
    My comments already say it all, put a breakpoint on the Call Get_API_Address then trace around the loop to get the hang of it. Then you will see [ebp+API_name] store the pointer to Import ASCIIs and follow this pointer, you will see a long list of API and DLL names… WOW is this our Import ASCII ? Make a dump of the whole Table and you will see the dump looking like this :

    WINMM.dll009C511D0001000000PlaySoundA0000KE
    RNEL32.dll00744B1D009F000000ExitProcess00T
    erminateProcess00ExitThread00HeapReAlloc
    Study this table we'll see that it start with a DLL name, then the RVA of first thunk corresponding with that DLL, then the number of Import from that DLL and list of all Imports ASCII from that DLL. For example, WIMM.dll first thunk start at 001D519C, (remember reversed order of bytes) and there is one import form this DLL which is PlaySoundA. Kernel32.dll first thunk starts at 1D4B74 and there are 9Fh Imports from kernel32.dll...etc

    Moreover if you take a look at the first thunk, by "d eax" when you are at instruction 10010E51 you will notice that the First Thunk is untouched by Armadillo! Which means that we know the original location of ASCII entries of API, however take a look at those location and we see only zeros :(...so Import ASCII are deleted but hey at least we know where each entry of Import ASCII should be stored.

    So now what do we have to do? We need to rebuild Import Table, in other words copy Import ASCII to location where they should be. Time for some patching on the fly! Set a break point "bpm 10010DF3 x" then restart the program. Once it break,

    a eip
    mov ecx, [ebp+IAT_add] ; get the RVA of Import ASCII
    add ecx, 400002h ; calculate VA of Import ASCII by adding image base and 2 is size of HINT
    push ecx
    call lstrcpy
    jmp API_add_found

    Yep, I hope you understand what the little inline patch codes do. The next task is stopping Armadillo from destroying our First Thunk, simply NOP the instruction at 10010E51. Finally, press F12 and let Armadillo rebuilt IAT for you :>... once sice break again dump the whole .idata segment.

    Of course you will notice that the Import Directory is missing so it is your task to rebuild this directory. I shall leave as an exercise for readers. If you are wondering about Import by ordinal because we can’t copy the Import ASCII like import by name case, don’t worry! Import by ordinal is handled separately by Armadillo (if you scroll up code window in sice for one or two pages, you will see that “Call Get_API_address” is called there as well to handle ordinal cases. However, as I have said, our First Thunk is intact so Ordinals are already stored in First Thunk and as long as we NOP the instruction at 10010E51, our Import by ordinals are preserved!

    Note : Another more generic approach would be coding a small utility that reads the Import ASCII dump and insert Import ASCII into our exe dump file and rebuild the Import Directory. This would be usable on all current Armadillo target!!!

    3. New int3 tricks

    Run the exe now and BOOM, you will get a big message from Windows saying int3 occurs and is not handled. that is the newest trick of Armadillo to prevent dumping. Time to get into sice and IDA to trace again, just look through the Debug loop of the "server" and you will see the int3 handling routine.

    0044DAAC 8B 85 38 FA FF FF mov eax, [ebp+lpDebugEvent]
    0044DAB2 81 78 0C 03 00 00 80 cmp dword ptr [eax+0Ch], 80000003h ; ç INT 3 exception code
    0044DAB9 0F 85 96 03 00 00 jnz loc_44DE55
    0044DABF INT3_occur:
    0044DABF 33 C9 xor ecx, ecx
    0044DAC1 8A 0D 6E 9A 45 00 mov cl, ds:int3_feature_installed
    Here begins our quest to kill int3. Start tracing from this point, you will see that the "server" reads a block of data from the "client" memory space and divide this into 4 tables and then decrypt this 4 tables into 4 separate virtually allocated memory space. Then the "server" use GetThreadContext to check for location of eip of the "client". This eip is one byte after the location int3 exception occurs! Trace on and we'll see that armadillo performs binary search on Table_1 to find the position of eip. Once eip location in Table_1 found, we are here :

    005DFDD5 8D 95 28 F7 FF FF lea edx, [ebp+Context]
    005DFDDB 52 push edx
    005DFDDC A1 58 BA 5E 00 mov eax, ds:table_2
    005DFDE1 03 85 20 F7 FF FF add eax, [ebp+relative_location] ; location in table_1 where eip is found
    005DFDE7 8A 08 mov cl, [eax]
    005DFDE9 51 push ecx
    005DFDEA E8 24 12 00 00 call Get_Jump_Type ; determine which kind of Jump it is
    005DFDEF 83 C4 08 add esp, 8
    005DFDF2 25 FF 00 00 00 and eax, 0FFh
    005DFDF7 85 C0 test eax, eax
    005DFDF9 74 1C jz short it_is_NOT_a_jump ;if al = 1 then it is a jump
    005DFDFB 8B 95 20 F7 FF FF mov edx, [ebp+relative_location] ; if al = 0 then it is not a jump
    005DFE01 A1 48 BA 5E 00 mov eax, ds:Table_4
    005DFE06 8B 8D E0 F7 FF FF mov ecx, [ebp+Context.Eip]; add eip with corresponding value in Table_3
    005DFE0C 03 0C 90 add ecx, [eax+edx*4] ; relative location = location of eip
    005DFE0F 89 8D E0 F7 FF FF mov [ebp+Context.Eip], ecx ; in Table 1
    005DFE15 EB 1E jmp short Update_eip
    005DFE17 ; ---------------------------------------------------------------------------
    005DFE17 it_is_NOT_a_jump:
    005DFE17 8B 15 5C BA 5E 00 mov edx, ds:Table_3
    005DFE1D 03 95 20 F7 FF FF add edx, [ebp+relative_location] ;set edx to corresponding value in Table_4
    005DFE23 33 C0 xor eax, eax
    005DFE25 8A 02 mov al, [edx] ; get distance eip to be moved by
    005DFE27 8B 8D E0 F7 FF FF mov ecx, [ebp+Context.Eip]
    005DFE2D 03 C8 add ecx, eax
    005DFE2F 89 8D E0 F7 FF FF mov [ebp+Context.Eip], ecx ; update eip
    005DFE35
    005DFE35 Update_eip:
    005DFE35 8D 95 28 F7 FF FF lea edx, [ebp+Context]
    005DFE3B 52 push edx ; lpContext
    005DFE3C 8B 85 F4 F9 FF FF mov eax, [ebp+hThread]
    005DFE42 50 push eax ; hThread
    005DFE43 FF 15 80 80 5E 00 call ds:SetThreadContext ; SetThreadContext:
    Basically, Armadillo has replaced some of the jumps (conditional & unconditional) in the original exe with int3 and generate these 4 tables storing information about position, distances of all these jumps. All done during packing time. As you can see, when and int3 occurs in the "client" process, the "server" will check for eip where int3 occurs, look it up in Table_1, once found, the "server" will check corresponding value in table_2 which is what kind of Jump it is at this eip. Then "the server" will check eflags register on “client” context (inside the call Get_Jump_type" routine) to see if the "client" should jump or not. If jump then the "client" eip will be moved by a corresponding value in Table_4 (jump distance), if not then the "client" eip will be moved by a corresponding value in table_3 (length of jump instruction). Take a look into the Get_Jump_Type routine.

    005E1046 jump type 9:
    005E1046 B0 01 mov al, 1 ;al always 1 => always jump no matter what
    005E1048 E9 AF 01 00 00 jmp end ;==>> JMP

    005E104D jump type E:
    005E104D 8B 55 0C mov edx, [ebp+context]
    005E1050 8B 82 C0 00 00 00 mov eax, [edx+0C0h] ; get eflags register
    005E1056 83 E0 41 and eax, 41h ; check Zero and Carry flag
    005E1059 F7 D8 neg eax ; eax is negative if either flag set
    005E105B 1B C0 sbb eax, eax ; eax = -1 if either flag is set
    ; eax = 0 if neither flag is set
    005E105D 40 inc eax ; al = 1 when neither flag set
    005E105E E9 99 01 00 00 jmp loc_5E11FC ; ==> jump when CF=0 and ZF=0 => JA

    005E108C jump type 4: ; CODE XREF: Get_Jump_Type+2Cj
    005E108C 8B 55 0C mov edx, [ebp+context]
    005E108F 8B 82 C0 00 00 00 mov eax, [edx+0C0h] ; get eflags register
    005E1095 25 80 00 00 00 and eax, 80h ; check Sign Flag
    005E109A F7 D8 neg eax
    005E109C 1B C0 sbb eax, eax
    005E109E 40 inc eax ; eax = 0 is S flag set, else eax = 1
    005E109F 8B 4D 0C mov ecx, [ebp+context]
    005E10A2 8B 91 C0 00 00 00 mov edx, [ecx+0C0h] ; get eflags
    005E10A8 81 E2 00 08 00 00 and edx, 800h ; check Overflow flag
    005E10AE F7 DA neg edx
    005E10B0 1B D2 sbb edx, edx
    005E10B2 42 inc edx ; edx = 0 if O flag set, else edx = 1
    005E10B3 33 C9 xor ecx, ecx
    005E10B5 3B C2 cmp eax, edx ; compare eax with edx
    005E10B7 0F 95 C1 setnz cl ; al = 1 if not equal
    005E10BA 8A C1 mov al, cl
    005E10BC E9 3B 01 00 00 jmp end ; jump if SF != OF ==>> JL
    Yep, all together there are 11h type of jump. Finally, it is out task to fix those int3 so I coded a small utility to scan through Table_1, check each virtual address entry in table_1 with our dump, if the opcode is "CC" then it is out int3, check the corresponding value in Table_2 to determine what kind of jump it is (JNZ or JZ or JMP etc). Then it check table_3 to see how long the jump instruction should be and assign write the correct jump opcodes into our exe dump. Finally, it check the corresponding value in Table_4 which is the distance how far the jump is and update the value in the exe again. Thus, run the protected program, dump the for tables into 4 separate files, (make sure that Table_1 size is same as table_4 size and is 4 times the table_2 and 3 size. Why?). I have attached the masm source code of this little program for your reference.

    4. The Final Touch

    After fixing int3, the dump still refused to run, exiting with some stupid beeping noise. This got me baffled for a while... tracing doesn’t seem to get me anywhere, double check my int3 patching routine, double check IAT... everything seems fine. I was at my wits end when I decide, hey the Beep sound doesn’t come out when I run the original exe, voila, bpx MessageBeep then press F12 we land here...

    00438E03 68 C4 0E 5C 00 push offset strDellatsnisyad ; "DELLATSNISYAD"
    00438E08 8D 4D E4 lea ecx, [ebp-1Ch]
    00438E0B 89 46 6C mov [esi+6Ch], eax
    00438E0E E8 F4 42 10 00 call ??4CString@@QAEABV0@PBD@Z ; CString::operator=(char const *)
    00438E13 8D 4D E4 lea ecx, [ebp-1Ch]
    00438E16 E8 91 46 10 00 call ?MakeReverse@CString@@QAEXXZ ; The name says it all :>
    00438E1B 8B 7D E4 mov edi, [ebp-1Ch]
    00438E1E B8 FF 00 00 00 mov eax, 0FFh
    00438E23 50 push eax ; nSize
    00438E24 50 push eax
    00438E25 8D 4D E8 lea ecx, [ebp-18h]
    00438E28 E8 84 45 10 00 call ?GetBuffer@CString@@QAEPADH@Z ; CString::GetBuffer(int)
    00438E2D 50 push eax ; lpBuffer
    00438E2E 57 push edi ; lpName
    00438E2F FF 15 8C 4C 5D 00 call ds:GetEnvironmentVariableA ; GetEnvironmentVariableA:
    00438E35 85 C0 test eax, eax ; check how many days installed ?
    00438E37 6A FF push 0FFFFFFFFh
    00438E39 8D 4D E8 lea ecx, [ebp-18h]
    00438E3C 75 36 jnz short GOOD_JUMP ; if variable not found, BEEP n exit
    00438E3E E8 BD 45 10 00 call ?ReleaseBuffer@CString@@QAEXH@Z ; CString::ReleaseBuffer(int)
    00438E43 6A 01 push 1 ; uType
    00438E45 FF 15 64 50 5D 00 call ds:MessageBeep ; MessageBeep:
    00438E4B 53 push ebx ;
    SO our task is to patch the conditional jump at 438E3C to JMP... play around with the program, like try resuming a download you will received a another beep :

    Here is summary of all the patches

    438E3C 75 DAYSINSTALLED
    4720EE 75 DAYSINSTALLED
    4E6B7F 75 ALTUSERNAME
    Now Get Right runs like a baby :>... though I find the downloading really slow. Personally I don’t recommend you to use this download manager :>, so once you crack it uninstall it immediately!

    5. The end

    That is it, phew. What a long tutorial! I hope you find it useful. I tried my best to explain things but I realise I can’t explain everything in details or else the tutorial will be too long for anyone to bother read it. So if there is any part that you find unclear, drop me a message on fravia board and I will make the appropriate changes.

    For the enthusiasts: If you notice that the IAT redirection routine is in some unknown memory space, you can try scrolling up to the beginning of this memory section and you will find a PE header! Check out the image size in the header, put a bpm at the end of the image (to make sure the whole image is loaded in memory) then re-run Get Right, once sice breaks, check that image is fully loaded in memory… dump it and rename it as “arma.dll” you will get a virgin dll that export functions like "LoadProgramInfo", "NukeNow", "CheckNetLicense", "ArmAccess" and "RunUserProgram". Promising enough :>???

  3. #53
    داره خودمونی میشه
    تاريخ عضويت
    Jun 2006
    پست ها
    102

    12 Lalipa

    ممنون عزیز
    همینجوری ادامه بده
    منم دارم سعی می کنم که اینا رو به Pdf تبدیل کنم
    آخه میدونی که .....
    اگه شما اجازه اینکار را میدین من Pdf کنم

  4. #54
    پروفشنال Morteza_SOS's Avatar
    تاريخ عضويت
    Apr 2006
    پست ها
    577

    پيش فرض

    Hello,

    well today I'm gonna teach you *censored*ers an easy way of 'reversing' crc32. CRC stands for Cyclic Redundancy Check and 32 the size of the result in bits, 32 bits = 1 dword = 4 bytes. Ok, enough of this crap. My method of finding out the values necessary for resulting in a given crc goes like this:

    Let's suppose we need a sequence of bytes that results in the crc of 0xA02DD7CB. Analysing the crc32 routine:

    lea esi, [message]
    mov edx, -1
    crcloop:
    lodsb
    mov ecx, edx
    and eax, 0ffh
    and ecx, 0ffh
    xor eax, ecx ; let's call it X
    shr edx, 8
    xor edx, dword ptr [eax*4+crctable]
    dec contagem
    jnz crcloop

    We can figure out which value was the last one in X by looking up in the crctable a dword with the highest byte equal to 0xA0, so. eg: 0xA0YYYYYY. Then we save the position of this dword and the rest of the dword, YYYYYY. Why save YYYYYY? because it's the value that has been XOR'd with another one to result in (A0)2DD7CB. Now we XOR YYYYYY with 2DD7CB. Now we do the mentioned operation till the last byte. Here goes a table of the operations:

    __________ __________ __________ ___________
    | VALUE | O.DWORD | Position | XOR'ing |
    |----------|----------|----------|-----------|
    | A02DD7CB | A00AE278 | E0 | 002735B3 |
    | 2735B300 | 270241AA | 71 | 000037F2 |
    | 37F20000 | 37D83BF0 | EB | 0000002A |
    | 2A000000 | 2A6F2B94 | FB | 00000000 |
    | | | | |
    ¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯¯

    Ok, so the values we got are the ones that must be the X's. And, as we did this process backwards, we need to put the result backwards as well, so our values are 0xFB, 0xEB, 0x71 and 0xE0 So, we just need to recode a crc32 routine to retrieve the chars to be xored with the current crc in order to result the X's and also replace them in execution so we can keep processing good values. Here it goes:

    invoke lstrlen, addr message
    mov contagem, eax
    lea esi, [message]
    lea edi, [temporary]
    mov edx, -1
    crcloop:
    lodsb
    mov ecx, edx
    and eax, 0ffh
    and ecx, 0ffh
    xor eax, ecx
    cmp contagem, 4
    jg skipitt
    stosb
    mov al, byte ptr [esi-1]
    skipitt:
    shr edx, 8
    xor edx, dword ptr [eax*4+crctable]
    dec contagem
    jnz crcloop

    ; Notes:
    ; message db 0FBh, 0EBh, 71h, 0E0h ; our precious values
    ; temporary dd 00 ; buffer for the last 4 bytes

    After executing this routine we find out that the needed four bytes are 'fuss' (this is only when there's nothing before it. If there are bytes before it then it's probably gonna change .

    So, as you can see it's rather easy to reverse crc32. If you didn't understand this tutorial, just cont... .. .no if you didn't, you're such a moronic dumbass...

  5. #55
    پروفشنال Morteza_SOS's Avatar
    تاريخ عضويت
    Apr 2006
    پست ها
    577

    پيش فرض

    ممنون عزیز
    همینجوری ادامه بده
    منم دارم سعی می کنم که اینا رو به Pdf تبدیل کنم
    آخه میدونی که .....
    اگه شما اجازه اینکار را میدین من Pdf کنم
    اختیار داری من کوچک شما هم هستم
    اگه پی دی کنی عالی می شه فقط اگر امکان داره لینک پی دی اف ها را برام بفرست تا در همون قسمت مربوط به خود مقاله قرار بدم ( اگه تونستی برام PM کن لینک دانلود مقالات را ) اگر خواستی بفرستی عنوان را هم بفرست تا موقع ویرایش پست مربوطه به مشکل نخوریم

  6. #56
    پروفشنال Morteza_SOS's Avatar
    تاريخ عضويت
    Apr 2006
    پست ها
    577

    پيش فرض

    این یکی از آموزش های عالیه که توش نحوه نوشتن اسکریپت را هم داده !

    Level : intermediate

    This is very short tutorial that brings just some small update for previous ones. Target is ExeCryptor 2.3.9 itself which can be found on official protector site. Tutorial shows unpacking and not cracking target. You will need OllyDbg (some script plugin, and some hide plugin), LordPE, ImpREC and Windows XP.





    - Loading in Olly and preparing for debugging -

    First open Olly and in "Debugging options", under "events" set "Make first pause at: System breakpoint". That will prevent auto start that is coused by TLS callback. Now load target in Olly.

    Open breakpoint window and delete breakpoint that Olly has placed on OEP:
    0076E427 EXECrypt One-shot CALL EXECrypt.0076E323

    Use some plugin to hide Olly from (or check previous tutorials to learn manually way):
    IsDebuggerPresent/BeingDebugged
    NtGlobalFlag
    HeapFlag
    CheckRemoteDebuggerPresent

    Do not check anything else in your plugin because EC (ExeCryptor) might detect it. EC detects hooks on APIs.

    Go to OutputDebugStringA API and place RETN 4 opcode at it's start. This is to prevent "s%s%" exploit.




    - Hardware exception trick -

    This is new trick. It seams that EC sets temporary hardware breakpoint somehow. I do not know yet how this is performed, but within Olly this will couse file crushing/detection.

    Under exceptions options in Olly, CHECK ALL boxes. But delete all custom exceptions! Be sure that you didn't place any memory, software or hardware breakpoint. Now hit Shift+F9 to run target under Olly. You will stop on first exception:

    007637D0 F0:F1 LOCK INT1

    Hit Shift+F9 three more times and then check hardware breakpoints (Debug menu -> Hardware breakpoints). You will see that one hardware breakpoint is placed:

    Hardware breakpoints
    # Base Size Stop on
    1 0076098F Temporary

    This is new trick in EC. If you continue to running with this hwbp, target will crush eventualy. Therefor, delete it at this point. Also, go to exception options and add last exception (C000001E INVALID LOCK SEQUENCE) to custom ones.




    - FindWindowA check -

    Hardware breakpoint rick is defeated. Next we have IsDebuggerPresent check which is defeated by our plugin. Then FindWindowA check which searches for window with "OLLYDBG" class. Place memory breakpoint on first opcode in FindWindowA API and run. You will stop on breakpoint check on API that is performed as small calculus to not be so obvious (junk removed from snippet):

    0055A3DB 8A00 MOV AL,BYTE PTR DS:[EAX]
    00595A6F 2C 99 SUB AL,99
    00595A71 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
    00595A74 F62A IMUL BYTE PTR DS:[EDX]
    005DEE5C 3C A4 CMP AL,0A4
    005DEE5E ^0F85 2BFFF7FF JNZ EXECrypt.0055ED8F
    005DEE64 E9 598A0000 JMP EXECrypt.005E78C2

    Then some EC checks for type of first opcode for some reason:

    005F8C87 0FB600 MOVZX EAX,BYTE PTR DS:[EAX]
    005F8C8A 833C85 00004E00 >CMP DWORD PTR DS:[EAX*4+4E0000],0
    005F8C92 ^0F84 D4A2F1FF JE EXECrypt.00512F6C
    005F8C98 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; user32.FindWindowA
    005F8C9B 8038 CF CMP BYTE PTR DS:[EAX],0CF
    005F8C9E ^0F84 C1A2F1FF JE EXECrypt.00512F65
    005F8CA4 ^E9 8571FFFF JMP EXECrypt.005EFE2E

    Then it checks API for possible hooks or redirections:

    005EFE2E 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; user32.FindWindowA
    005EFE31 8038 E9 CMP BYTE PTR DS:[EAX],0E9 ; Is JMP?
    005EFE34 ^0F84 2B31F2FF JE EXECrypt.00512F65
    005EFE3A 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; user32.FindWindowA
    005EFE3D 8038 EB CMP BYTE PTR DS:[EAX],0EB ; Is JMP SHORT?
    005EFE40 ^0F84 1F31F2FF JE EXECrypt.00512F65
    005EFE46 E9 38770100 JMP EXECrypt.00607583

    Checks is API patched with RETN xxxx:

    004EB930 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; user32.FindWindowA
    004EB933 8A00 MOV AL,BYTE PTR DS:[EAX]
    004EB935 24 F6 AND AL,0F6
    004EB937 3C C2 CMP AL,0C2
    0060CCB1 ^0F84 AE62F0FF JE EXECrypt.00512F65

    Checks is first opcode JMP DWORD [EAX] which is again redirection:

    0060CCBA 66:8B00 MOV AX,WORD PTR DS:[EAX]
    0060CCBD 66:25 FF38 AND AX,38FF
    005F0C95 66:3D FF20 CMP AX,20FF
    005F0C99 ^0F84 C622F2FF JE EXECrypt.00512F65

    Checks for CALL XXXXXXXX type redirection:

    00546361 8038 E8 CMP BYTE PTR DS:[EAX],0E8
    00546364 0F85 DBED0300 JNZ EXECrypt.00585145
    0054636A ^E9 5DF7FCFF JMP EXECrypt.00515ACC

    Some more examning is performed and then it jumps to FindWindowA that finds "OLLYDBG" class in memory. Just set EAX=0 when retrning from this API and this check is killed.




    - ReadProcessMemory check -

    EC examnes all processes in order to find Olly running. It uses GetWindowThreadProcessId to retrieve PID of processes, then it opens each proces. It uses ReadProcessMemory to examne them. We cannot place bp on ReadProcessMemory since it will be detected, we could use memory breakpoints but that would be too slow. Since ReadProcessMemory uses ZwReadVirtualMemory, we can place bp on this one that is not checked. Then we can run. When we break at that API, return to kernel and then to EC code trace little untill you see that some bytes are checked (if you cannot find that check, hit F9 to break on new memory reading):

    005ABBE2 81BD 38FEFFFF 45>CMP DWORD PTR SS:[EBP-1C8],2B584245
    005ABBEC ^0F85 8A8BFAFF JNZ EXECrypt.0055477C
    005ABBF2 ^E9 6371F6FF JMP EXECrypt.00512D5A

    Follow in dump that opcode:

    005ABBE2 81 BD 38 FE FF FF 45 42 58 2B ..8...EBX+

    It checks for one string in Olly , "EBX+". Change 2B584245 bytes to something as 12345678 so it will fail to detect Olly. EC doesn't check this code for bp's or with checksums.

    You will find similar checks if you search all EC sections. Search for CMP DWORD[EAX],CONST and you'll get results:

    Found commands
    Address Disassembly Comment
    00514CDB CMP DWORD PTR DS:[EAX],47424454 ; TDBG
    0053A13B CMP DWORD PTR DS:[EAX],47424454
    0055DF80 CMP DWORD PTR DS:[EAX],4742444F ; ODBG
    0057FD31 CMP DWORD PTR DS:[EAX],47424454
    00599B86 CMP DWORD PTR DS:[EAX],4742444F
    005A6EC7 CMP DWORD PTR DS:[EAX],4742444F
    005AF1DF CMP DWORD PTR DS:[EAX],4742444F
    005BA618 CMP DWORD PTR DS:[EAX],47424454
    005C88BD CMP DWORD PTR DS:[EAX],47424454
    005C96FF CMP DWORD PTR DS:[EAX],4742444F
    005D77C5 CMP DWORD PTR DS:[EAX],4742444F
    005E0B5A CMP DWORD PTR DS:[EAX],4742444F
    005EC439 CMP DWORD PTR DS:[EAX],4742444F
    005EEDDE CMP DWORD PTR DS:[EAX],47424454
    005F6512 CMP DWORD PTR DS:[EAX],47424454
    006004FA CMP DWORD PTR DS:[EAX],47424454


    There are more similar checks for sysinternals tools:

    Found commands
    Address Disassembly Comment
    00525A2A CMP DWORD PTR SS:[EBP-10C],656C6946 ;File
    0056A41F CMP DWORD PTR SS:[EBP-10C],6D676552 ;Regm
    00593828 CMP DWORD PTR SS:[EBP-10C],6D676552
    005BE5A2 CMP DWORD PTR SS:[EBP-10C],76676264 ;dbgv
    005DF3F9 CMP DWORD PTR SS:[EBP-10C],36343831 ;1846
    005E95A7 CMP DWORD PTR SS:[EBP-10C],36343831
    0060BCE9 CMP DWORD PTR SS:[EBP-10C],76676264




    - Threads -

    Threads are used to perform continious protection. Just NOP whole CreateThread API (except last RETN xxxx).





    - OEP -

    This is Delphi program and OEP should be at the end of code section. But OEP is scrambled and on OEP there will be jump to moved OEP. Use memory breakpoints to land in code section as described in previous tutorials. OEP should be here:

    004D2AB8 -E9 81560D00 JMP EXECrypt.005A813E
    004D2ABD 45 INC EBP
    004D2ABE 91 XCHG EAX,ECX ; EXECrypt.005A8100
    004D2ABF 3D 6F43525F CMP EAX,5F52436F
    004D2AC4 35 92C3E6E9 XOR EAX,E9E6C392
    004D2AC9 DA87 0900D6AD FIADD DWORD PTR DS:[EDI+ADD60009]
    004D2ACF 9E SAHF
    004D2AD0 D7 XLAT BYTE PTR DS:[EBX+AL]
    ...

    Jump leads to good OEP:

    005A813E 55 PUSH EBP
    005A813F ^E9 7C52FAFF JMP EXECrypt.0054D3C0
    005A8144 ^FF25 58D74D00 JMP DWORD PTR DS:[4DD758] ; EXECrypt.0051256B
    005A814A ^0F88 670CF7FF JS EXECrypt.00518DB7
    ...

    From here we can start fixing imports.




    - Imports -

    This protection is already explained. Use my script to fix them, then dump file and rebuild new IAT with ImpREC.

    //-------------------------------- SCRIPT START -----------------------------------------
    //ExeCryptor 2.x IAT for asm/Delphi/BorlandC++ type - by haggar
    var addr
    var oep
    var pointer
    var counter
    var esp_ref
    var temp

    mov addr,401000
    mov oep,eip

    LABEL_01:
    find addr,#ff25????4D00#
    cmp $RESULT,0
    je END_01
    mov addr,$RESULT
    add addr,2
    mov pointer,addr
    mov pointer,[pointer]
    mov pointer,[pointer]
    cmp pointer,10000000 //Check is import placed in thunk, or redirection.
    ja LABEL_01
    cmp pointer,0 //For delphi!!!!!!!!!!!!!!!!
    je LABEL_01

    sub addr,2
    mov eip,addr
    add addr,2

    mov esp_ref,esp //Stack reference.
    mov counter,0
    LABEL_02: //Trace some code.
    sti
    add counter,1
    cmp counter,30
    jne LABEL_02

    mov temp,esp
    LABEL_03: //Find referenced stack value.
    add temp,4
    cmp temp,esp_ref
    jne LABEL_03
    sub temp,4

    mov temp,[temp] //Go to "Magic address".
    bp temp
    esto
    bc eip

    mov temp,[eip]
    and temp,0ffff
    cmp temp,025ff //SelfWriting import type? No need to fix it then.
    je LABEL_01

    cmp eax,10000000 //If EAX=!IMPORT, then it is a first type.
    jb LABEL_01

    mov temp,addr //In this case EAX=IMPORT.
    mov temp,[temp]
    mov [temp],eax
    jmp LABEL_01

    END_01:
    mov eip,oep
    ret
    //------------------------- END SCRIPT ------------------------------------------------




    - Fixing dump -

    Change TLS pointer with LordPE to 000E2000. Dump should work now, but probably with some problems. Problem is with serial so you will get exception message, plus dump might not work on other machines. Read official Excryptor crackme solution for more info about that.




    - The End -

  7. #57
    پروفشنال Morteza_SOS's Avatar
    تاريخ عضويت
    Apr 2006
    پست ها
    577

    پيش فرض

    ¤ ExeCryptor 2.2.50 - unpacking MSVC+ target - by haggar ¤


    ExeCryptor targets differ from one to second, but differences are minor. Once you understand one version, you will have open door for other ones. Most of differences are Olly detections which are changed from version to version so patching Olly is useless. Every new version will find easy Olly in memory. ExeCryptor checks all processes and reads couple bytes from specific adddresses. Example, it checks some exports, or ODBG strings in every process to recognize Olly. If it finds some process, it terminate it. Processes are enumerated with GetWindowThreadProcessId.



    - Killing debugger checks -

    Ok, enough of talking. Open Olly and in debugging options, under events, set Olly to break on System Breakpoint. This is to avoid target autorun in Olly. Olly will set breakpoint on EP of target and that breakpoint is detected by ExeCryptor (EC). Open bp window and delete that bp.

    EC has several debugger checks:
    BeingDebugged
    NtGlobalFlag
    HeapFlag
    IsDebuggerPresent
    CheckRemoteDebuggerPresent

    I already explained these checks in one my tutorial so look there for explanation. If you don't want to waste time to manually disable checks, use some plugin like HideOlly or OllyAdvanced. But warning! Plugins can be detected by EC. Plugins sometimes (depending on type of plugin and hide method) hooks APIs and EC checks for such redirections. So select only features for these checks.



    - Killing threads -

    EC uses a lot of threads to perform active monitoring and protection. These threads checks for debuggers, breakpoints, hostile windows, etc... To disable these checks , we can patch CreateThread API so threads are never started. Go to CreateThread and NOP whole API till the last RETN xxxx opcode. I sad already that EC versions have minor changes. In my previous tutorials, it was enough to patch CreateThread API. But this version uses CloseHandle to close handle of thread after it is created. If threads are not created, CloseHandle will couse exception and target will crush. So we must patch CloseHandle API in the same way as CreateThread.



    - OllyDbg targeted tricks -

    EC really hate Olly and because of that it tries to detect and kill Olly by any means. One trick that is used to crush Olly is OutputDebugStringA exploit. This is probably nothing new for reader of this small tutorial because this trick is used in lot of protectors, but in case that you didn't know for it:
    There is some bug in Olly that will couse Olly to crush if debugged executable file name is "%s%s", or if OutputDebugStringA send this string to Olly. To prevent crushing we can patch that API just like we patched CreateThread and CloseHandle. Instead of NOPing whole API, you can just place RETN 4 opcode at the API start.

    EC can use FindWindowA, ReadProcessMemory tricks too for detecting Olly, but in this version those checks are performed just with threads. And we killed threads so this not we can run target under Olly.



    - Finding OEP and restoring OEP code -

    After we patched all checks, we need to break on OEP. We will use memory breakpoints for this. Place mem bp on first section and run. First time we will stop at unpacking procedure:

    00519E01 AA STOS BYTE PTR ES:[EDI]
    00519E02 ^EB E9 JMP SHORT UnPackMe.00519DED
    00519E04 E8 FC000000 CALL UnPackMe.00519F05
    00519E09 0F82 97000000 JB UnPackMe.00519EA6
    00519E0F E8 F1000000 CALL UnPackMe.00519F05
    00519E14 73 5B JNB SHORT UnPackMe.00519E71
    00519E16 B9 04000000 MOV ECX,4
    00519E1B E8 FD000000 CALL UnPackMe.00519F1D
    00519E20 48 DEC EAX
    ...
    ...
    00519F33 E8 CDFFFFFF CALL UnPackMe.00519F05
    00519F38 ^72 F2 JB SHORT UnPackMe.00519F2C
    00519F3A C3 RETN
    00519F3B 8BE5 MOV ESP,EBP
    00519F3D 5D POP EBP
    00519F3E C3 RETN
    00519F3F 90 NOP

    When you break, remove mem bp, place bp at the last RETN. Last RETN is last opcode of this unpacking procedure and when you break there, code is unpacked. Remove that bp and place new mem bp. Run and you will break in procedure that writes destination of CALLs:

    004B613E AC LODS BYTE PTR DS:[ESI]
    004B613F D0E8 SHR AL,1
    004B6141 80F8 74 CMP AL,74
    004B6144 75 0E JNZ SHORT UnPackMe.004B6154
    004B6146 8B06 MOV EAX,DWORD PTR DS:[ESI]
    004B6148 0FC8 BSWAP EAX
    004B614A 01C8 ADD EAX,ECX
    004B614C 8906 MOV DWORD PTR DS:[ESI],EAX
    004B614E 83C6 04 ADD ESI,4
    004B6151 83E9 04 SUB ECX,4
    004B6154 49 DEC ECX
    004B6155 ^7F E7 JG SHORT UnPackMe.004B613E
    004B6157 59 POP ECX
    004B6158 5E POP ESI
    004B6159 C3 RETN

    Again, remove mem bp, place bp at the RETN, run and remove that bp. If you place next memory breakpoint on first section, you will break at OEP or first code that is executed in code section:

    004271C5 50 PUSH EAX
    004271C6 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
    004271CD 83C4 A8 ADD ESP,-58
    004271D0 53 PUSH EBX
    004271D1 56 PUSH ESI
    004271D2 57 PUSH EDI ; UnPackMe.00400000
    004271D3 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
    004271D6 FF15 DC0A4600 CALL DWORD PTR DS:[460ADC]
    004271DC 33D2 XOR EDX,EDX
    004271DE 8AD4 MOV DL,AH
    004271E0 8915 34E64500 MOV DWORD PTR DS:[45E634],EDX
    004271E6 8BC8 MOV ECX,EAX

    But this is not OEP. OEP is stolen and code that was at OEP is already executed within EC code. Scroll up and you will see that OEP should be at the 004271B0:

    004271B0 -E9 6CD10500 JMP UnPackMe.00484321
    004271B5 58 POP EAX ; UnPackMe.004DC082
    004271B6 C1C0 18 ROL EAX,18
    004271B9 -E9 424E0400 JMP UnPackMe.0046C000
    004271BE 70 12 JO SHORT UnPackMe.004271D2
    004271C0 6C INS BYTE PTR ES:[EDI],DX ; I/O command
    004271C1 90 NOP
    004271C2 321F XOR BL,BYTE PTR DS:[EDI]
    004271C4 ED IN EAX,DX ; I/O command

    At that adres is not some jump. That jump leads to obfuscated reall OEP code that is placed inside EC section:

    00484321 E8 FDA60000 CALL UnPackMe.0048EA23
    00484326 F005 DCA804E>LOCK ADD EAX,E004A8DC
    0048432D A5 MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
    0048432E E8 33E40100 CALL UnPackMe.004A2766
    ...

    Proof that this place is OEP is also fact that EC checks this exact address for breakpoint:

    0052286C 8A00 MOV AL,BYTE PTR DS:[EAX]
    0052286E 2C 99 SUB AL,99
    ...
    00525EBE F62A IMUL BYTE PTR DS:[EDX]
    00525EC0 3C A4 CMP AL,0A4
    00525EC2 0F85 C1040000 JNZ UnPackMe.00526389 <---- NO BP.
    00525EC8 ^E9 D74FFFFF JMP UnPackMe.0051AEA4 <---- BP detected!


    EC has strong obfuscation that makes impossible to reconstruct OEP code. But in this example number of stolen opcodes is small and most opcodes can be recovered by experience. Open some MSVC++ 6.0 file in second Olly and binary copy first 0x15 bytes. Paste them to our target at OEP. I have used Mozilla Firefox OEP bytes:

    004271B0 55 PUSH EBP
    004271B1 8BEC MOV EBP,ESP
    004271B3 6A FF PUSH -1
    004271B5 68 60ED9C00 PUSH 9CED60
    004271BA 68 CE688A00 PUSH 8A68CE
    004271BF 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
    004271C5 50 PUSH EAX

    Two PUSH values are wrong but they can be found in stack:

    0012FFB4 004292C8 UnPackMe.004292C8
    0012FFB8 00450E60 UnPackMe.00450E60
    0012FFBC FFFFFFFF
    0012FFC0 0012FFF0
    ...

    Now OEP has correct opcodes:

    004271B0 55 PUSH EBP
    004271B1 8BEC MOV EBP,ESP
    004271B3 6A FF PUSH -1
    004271B5 68 600E4500 PUSH UnPackMe.00450E60
    004271BA 68 C8924200 PUSH UnPackMe.004292C8
    004271BF 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]




    - Decrypting imports -

    IAT section is 00460000. Most of imports are redirected in EC code where they are decrypted. In my past two tutorials I have explained how IAT is protected and how to recover it. But that was case when for imports are used jumps. VC++ use calls so I had to write new script. This script doesn't search for JMP/CALL, instead it just walks trough thunks in IAT section and decrypts protected ones. Script is below, paste it to some text file and use by some script plugin. My comments exapain most of things altough you don't need to understand it or change for this target:

    // ----------- ExeCryptor 2.2.50 - for VC++ IAT ------------------
    var oep
    var thunk
    var pointer
    var ref_esp
    var temp

    mov oep,eip
    mov thunk,00460000

    LABEL_01: //Examne thunks label.
    cmp thunk,00461000 //Is it end of IAT? Then finish.
    je END_01
    cmp [thunk],0 //Is thunk empty? Then go to next.
    add thunk,4
    je LABEL_01
    sub thunk,4
    cmp [thunk],10000000 //Does thunk holds API? Go to next again.
    add thunk,4
    ja LABEL_01
    sub thunk,4 //Thunk holds redirected import.
    mov pointer,[thunk]

    mov eip,pointer
    mov ref_esp,esp //Stack reference (start ESP value).
    mov temp,0
    LABEL_02: //Trace untill return ESP value is decrypted.
    sti
    add temp,1
    cmp temp,30 //Trace first 30 opcodes.
    jne LABEL_02

    mov temp,esp
    LABEL_03: //Find referenced stack value.
    add temp,4
    cmp temp,ref_esp
    jne LABEL_03
    sub temp,4

    mov temp,[temp] //Get "Magic return address".
    bp temp
    esto
    bc eip

    cmp eax,10000000 //Is EAX<10000000 (EAX<IMPORT) ?
    add thunk,4
    jb LABEL_01 //Then it is self-fixed import.

    sub thunk,4 //If not self-fix, fix it!
    mov [thunk],eax
    add thunk,4

    jmp LABEL_01

    END_01:
    mov eip,oep //Restore OEP.
    ret
    //------------------------ End of script ------------------------------


    When script is finished, dump image with LordPE (note that you'll had to correct ImageSize before you dump), load ImpREC and set OEP to 271B0, then rebuild IAT on dumped file.




    - Fixing dump -

    As a last touch, you need to erase TLS information from PE header. Use LordPE or CFF Explorer, set TLS offset and size to 0. You can also delete EC 3 sections to ge smaller dump. If you want to make perfect dump, you can place IAT in original IAT section at 00460000. Check my dump how I did it.




    - The end -
    Last edited by Morteza_SOS; 17-01-2008 at 08:32.

  8. #58
    پروفشنال Morteza_SOS's Avatar
    تاريخ عضويت
    Apr 2006
    پست ها
    577

    پيش فرض

    1. Quick Intro

    Hi folks, this is my second tutorial about ExeCryptor , altough I don't know will I publish it before one that I wrote first (for official ExeCryptor crackme). Target for this tutorial is diProtector v1.0 (google it). I don't know is it latest since I had it on my hard drive for a while. Target is compiled in MASM and it doesn't have stolen OEP or functions, plus there are very few imports in the file. All that makes unpacking much easier. Tools that I used for this job are OllyDbg 1.10, LordPE, ImpREC, some hex editor. You will not need any plugins or patches to hide Olly. We will do all manually.




    2. Running protected file under Olly

    Let's see what tricks ExeCryptor has prepared for us:


    - Because TLS callbacks, our target will run before OEP is reached. Olly will be detected by other debugging tricks and protected program will exit. To avoid that , we must set Olly to break on system breakpoint. You can set that in "debugging options" , under "events" (make first pause at - system, breakpoint). Now we can load target in Olly. But here we have first EC (ExeCryptor) trap. When you loaded target in Olly, check breakpoints window and you will see one breakpoint:

    Breakpoints
    Address Module Active Disassembly Comment
    0045F3D0 diProtec One-shot CALL diProtec.0045F2CC

    Olly places that one-shot breakpoint at the ModuleEntryPoint of file. That breakpoint will be detected by EC and target will close. Here is temp breakpoint:

    0045F3D0 > E8 F7FEFFFF CALL diProtec.0045F2CC <-------- Here!
    0045F3D5 05 57840000 ADD EAX,8457
    0045F3DA -FFE0 JMP EAX
    0045F3DC E8 EBFEFFFF CALL diProtec.0045F2CC
    0045F3E1 05 8B0A0000 ADD EAX,0A8B
    0045F3E6 -FFE0 JMP EAX
    0045F3E8 E8 04000000 CALL diProtec.0045F3F1
    0045F3ED FFFF ??? ; Unknown command
    0045F3EF FFFF ??? ; Unknown command
    0045F3F1 5E POP ESI ; diProtec.0045591F
    0045F3F2 C3 RETN
    0045F3F3 0000 ADD BYTE PTR DS:[EAX],AL
    0045F3F5 0000 ADD BYTE PTR DS:[EAX],AL
    0045F3F7 0000 ADD BYTE PTR DS:[EAX],AL
    0045F3F9 0000 ADD BYTE PTR DS:[EAX],AL
    0045F3FB 0000 ADD BYTE PTR DS:[EAX],AL
    0045F3FD 0000 ADD BYTE PTR DS:[EAX],AL


    And this is where breakpoint is detected:

    00455EB1 AC LODS BYTE PTR DS:[ESI]

    In Olly pane you can see information that on that address is E8 byte

    DS:[ESI]=[0045F3D0]=E8

    but when we step in with trace over the opcode and byte is loaded to AL, check registers window:

    EAX 000000CC <----------------------- EAX = CC = BREAKPOINT IS DETECTED !!!
    ECX 00000018
    EDX 5A266E6B
    EBX 00000000
    ESP 0012F998
    EBP 0012F9AC
    ESI 0045F3D1 diProtec.0045F3D1
    EDI 00400000 diProtec.00400000
    EIP 00455EB2 diProtec.00455EB2

    This doesn't have to be breakpoint check on that opcode. It could be some checksup on code block which is same thing. It's not important. To avoid this trick just delete breakpoint in bp window and problem is solved.




    - Further EC debugger tricks are described in PNLUCK's tutorial. These are:

    BeingDebuged
    ProcessHeap
    NtDebugFlag

    These flags needs to be set to 0 so EC doesn't detect debugger. You can use any plugin for this, but we will see how manually this can be resolved. Open memory window , scroll down to the block "data block of main thread":

    Memory map
    Address Size Owner Section Contains Type Access Initial Mapped as
    ...
    ...
    00400000 00001000 diProtec PE header Imag R RWE
    00401000 00002000 diProtec .text Imag R RWE
    00403000 00001000 diProtec c3o2hlw9 Imag R RWE
    00404000 00001000 diProtec .data data Imag R RWE
    00405000 00004000 diProtec WCE_ARM Imag R RWE
    00409000 00002000 diProtec KG Imag R RWE
    0040B000 00003000 diProtec .rsrc resources Imag R RWE
    0040E000 00001000 diProtec bjmdft2e Imag R RWE
    0040F000 00025000 diProtec n9cjl4.c Imag R RWE
    00434000 0002C000 diProtec g0qnncsj code,imports Imag R RWE
    ...
    ...loaded DLLs
    ...
    7F6F0000 00007000 Map R E R E
    7FFB0000 00024000 Map R R
    7FFDA000 00001000 Priv RW RW
    7FFDF000 00001000 data block o Priv RW RW <------------ HERE!!!
    7FFE0000 00001000 Priv R R

    Double click on that block to open new dump window:

    7FFDF000 0012FD0C (Pointer to SEH chain)
    7FFDF004 00130000 (Top of thread's stack)
    7FFDF008 0012E000 (Bottom of thread's stack)
    7FFDF00C 00000000
    7FFDF010 00001E00
    7FFDF014 00000000
    7FFDF018 7FFDF000
    7FFDF01C 00000000
    7FFDF020 00000284
    7FFDF024 000002F8 (Thread ID)
    7FFDF028 00000000
    7FFDF02C 00142A18 (Pointer to Thread Local Storage)
    7FFDF030 7FFDA000 <----------------- FOLLOW IN DUMP!!!
    7FFDF034 00000000 (Last error = ERROR_SUCCESS)
    7FFDF038 00000000
    7FFDF03C 00000000
    7FFDF040 00000000
    ...

    Follow that address in dump (this block and that address will be different for you, but block is always labeled by olly as "data block of main thread" and addres that we want inside is data_block_base+30). In dump:

    7FFDA000 00 00 01 00 FF FF FF FF 00 00 40 00 A0 1E 24 00 ..........@...$.
    7FFDA010 00 00 02 00 00 00 00 00 00 00 14 00 C0 E4 97 7C ...............|
    7FFDA020 05 10 90 7C ED 10 90 7C 01 00 00 00 00 00 00 00 ...|...|........
    7FFDA030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    7FFDA040 80 E4 97 7C 01 00 00 00 00 00 00 00 00 00 6F 7F ...|..........o.
    7FFDA050 00 00 6F 7F 88 06 6F 7F 00 00 FB 7F 00 10 FC 7F ..o...o.........
    7FFDA060 00 20 FD 7F 01 00 00 00 70 00 00 00 00 00 00 00 . ......p.......

    01 byte, which is placed at block_base+2 is BeingDebug byte that is also used by IsDebuggerPresent API. If program is debugged, that byte is 1, if not then 0. We must set it to 0.

    At block_base+68 we have NtGlobalFlag byte. It is set to 70 if program is debugged and if not, then 0. Again , set it to 0.

    At block_base+18 we have address of heap block 00001400=00140000. It will differ on your machine. Follow that address in dump:

    00140000 C8 00 00 00 31 01 00 00 FF EE FF EE 62 00 00 50 ....1.......b..P
    00140010 60 00 00 40 00 FE 00 00 00 00 10 00 00 20 00 00 `..@......... ..
    00140020 00 02 00 00 00 20 00 00 B6 00 00 00 FF EF FD 7F ..... ..........

    DWORD at block_base+10 must be 0 if program is not debugged. In this case it is 60000040=40000060. So set it to 0.

    And these three checks are now disabled. This is also the same thing what hide plugins for Olly do.




    - Almost every import that EC uses is checked for breakpoints, but also it is checked for hooks and redirections. So if some plugin redirects some API to it's own code (like some hide plugins do for ZwQueryInformationProcess) it will be detected.


    - IsDebuggerPresent API is used , but we already disabled that check.


    - CheckRemoteDebuggerPresent API is used to detect debugger. It is big API and we can place bp at the and to break there. EC didn't check whole API for bp. Just set return value in EAX to 0.






    3. Finding OEP

    When you have disabled all debugger checks, just place memory breakpoint on access on first section and run. First time we will break in the unpacking procedure:

    00454D55 AA STOS BYTE PTR ES:[EDI]
    00454D56 ^EB E9 JMP SHORT diProtec.00454D41
    00454D58 E8 FC000000 CALL diProtec.00454E59
    00454D5D 0F82 97000000 JB diProtec.00454DFA
    ...
    ...
    00454E85 11C9 ADC ECX,ECX
    00454E87 E8 CDFFFFFF CALL diProtec.00454E59
    00454E8C ^72 F2 JB SHORT diProtec.00454E80
    00454E8E C3 RETN
    00454E8F 8BE5 MOV ESP,EBP
    00454E91 5D POP EBP
    00454E92 C3 RETN <------------ Place bp and run.

    This procedure unpacks code to 401000 section. Remove mem bp, place bp at RETN (one belov MOV ESP,EBP and POP EBP) and run. Remove that bp, code section is unpacked now. Olace memory bp again and run. You will stop here:

    00434142 AC LODS BYTE PTR DS:[ESI]
    00434143 D0E8 SHR AL,1
    00434145 80F8 74 CMP AL,74
    00434148 75 0E JNZ SHORT diProtec.00434158
    0043414A 8B06 MOV EAX,DWORD PTR DS:[ESI]
    0043414C 0FC8 BSWAP EAX ; diProtec.00401000
    0043414E 01C8 ADD EAX,ECX
    00434150 8906 MOV DWORD PTR DS:[ESI],EAX ; diProtec.00401000
    00434152 83C6 04 ADD ESI,4
    00434155 83E9 04 SUB ECX,4
    00434158 49 DEC ECX
    00434159 ^7F E7 JG SHORT diProtec.00434142
    0043415B 59 POP ECX
    0043415C 5E POP ESI ; diProtec.00401000
    0043415D C3 RETN <------------- Place bp here !

    Again , remove mem bp, place bp at RETN and run, remove that bp and place again mem bp on code. You will break on OEP:

    00401000 6A 00 PUSH 0
    00401002 68 1C104000 PUSH diProtec.0040101C
    00401007 6A 00 PUSH 0
    00401009 68 D0304000 PUSH diProtec.004030D0 ; ASCII "diProtector"
    0040100E 6A 00 PUSH 0
    00401010 E8 5F1A0000 CALL diProtec.00402A74
    00401015 6A 00 PUSH 0
    00401017 E8 B21A0000 CALL diProtec.00402ACE
    0040101C 55 PUSH EBP
    0040101D 8BEC MOV EBP,ESP
    0040101F 817D 0C 10010000 CMP DWORD PTR SS:[EBP+C],110
    00401026 75 1A JNZ SHORT diProtec.00401042
    00401028 FF75 08 PUSH DWORD PTR SS:[EBP+8] ; diProtec.<ModuleEntryPoint>
    0040102B 8F05 54414000 POP DWORD PTR DS:[404154] ; kernel32.7C816D4F
    00401031 E8 B8050000 CALL diProtec.004015EE
    00401036 68 DC304000 PUSH diProtec.004030DC ; ASCII "diProtector v1.0 started..."
    0040103B E8 AB080000 CALL diProtec.004018EB
    00401040 EB 67 JMP SHORT diProtec.004010A9
    ...
    ...

    EC has some more checks but they are performed with threads and they aren't running yet. Why? I don't know really. But if you run app it will close Olly. We will talk about this more later.





    4. Imports

    There are just few imports in this target and they can be fixed manually , but it is possible to write script that will fix them. Program is MASM app and it has small numbers of imports:

    00402A68 -FF25 BC304000 JMP DWORD PTR DS:[4030BC] ; diProtec.00410531
    00402A6E -FF25 B8304000 JMP DWORD PTR DS:[4030B8] ; diProtec.00413D26
    00402A74 -FF25 B4304000 JMP DWORD PTR DS:[4030B4] ; diProtec.00415AB7
    00402A7A -FF25 B0304000 JMP DWORD PTR DS:[4030B0] ; diProtec.0041AEF6
    00402A80 -FF25 AC304000 JMP DWORD PTR DS:[4030AC] ; diProtec.00420D0B
    00402A86 -FF25 A8304000 JMP DWORD PTR DS:[4030A8] ; diProtec.0041F637
    00402A8C -FF25 A4304000 JMP DWORD PTR DS:[4030A4] ; diProtec.00431355
    00402A92 -FF25 A0304000 JMP DWORD PTR DS:[4030A0] ; diProtec.00421441
    00402A98 -FF25 9C304000 JMP DWORD PTR DS:[40309C] ; diProtec.0042F9A8
    00402A9E -FF25 94304000 JMP DWORD PTR DS:[403094] ; diProtec.0042E1A0
    00402AA4 -FF25 98304000 JMP DWORD PTR DS:[403098] ; diProtec.00413226
    00402AAA -FF25 8C304000 JMP DWORD PTR DS:[40308C] ; diProtec.00417665
    00402AB0 -FF25 90304000 JMP DWORD PTR DS:[403090] ; diProtec.00421BC4
    00402AB6 -FF25 58304000 JMP DWORD PTR DS:[403058] ; diProtec.0041D62D
    00402ABC -FF25 44304000 JMP DWORD PTR DS:[403044] ; diProtec.00421F2F
    00402AC2 -FF25 40304000 JMP DWORD PTR DS:[403040] ; diProtec.00428B7D
    00402AC8 -FF25 70304000 JMP DWORD PTR DS:[403070] ; diProtec.004127A6
    00402ACE -FF25 48304000 JMP DWORD PTR DS:[403048] ; diProtec.00418D4A
    00402AD4 -FF25 4C304000 JMP DWORD PTR DS:[40304C] ; diProtec.00428FD5
    00402ADA -FF25 50304000 JMP DWORD PTR DS:[403050] ; diProtec.00427DE5
    00402AE0 -FF25 54304000 JMP DWORD PTR DS:[403054] ; diProtec.00412D68
    00402AE6 -FF25 6C304000 JMP DWORD PTR DS:[40306C] ; diProtec.0041D5CD
    00402AEC -FF25 5C304000 JMP DWORD PTR DS:[40305C] ; diProtec.00419CEF
    00402AF2 -FF25 60304000 JMP DWORD PTR DS:[403060] ; diProtec.00416D00
    00402AF8 -FF25 64304000 JMP DWORD PTR DS:[403064] ; diProtec.0040FEF3
    00402AFE -FF25 68304000 JMP DWORD PTR DS:[403068] ; diProtec.0041A1AE
    00402B04 -FF25 24304000 JMP DWORD PTR DS:[403024] ; comdlg32.GetOpenFileNameA
    00402B0A -FF25 34304000 JMP DWORD PTR DS:[403034] ; GDI32.BitBlt
    00402B10 -FF25 30304000 JMP DWORD PTR DS:[403030] ; GDI32.CreateCompatibleDC
    00402B16 -FF25 2C304000 JMP DWORD PTR DS:[40302C] ; GDI32.DeleteDC
    00402B1C -FF25 38304000 JMP DWORD PTR DS:[403038] ; GDI32.SelectObject
    00402B22 -FF25 80304000 JMP DWORD PTR DS:[403080] ; ntdll.memcpy
    00402B28 -FF25 7C304000 JMP DWORD PTR DS:[40307C] ; ntdll.memset
    00402B2E -FF25 78304000 JMP DWORD PTR DS:[403078] ; ntdll.strcat
    00402B34 -FF25 84304000 JMP DWORD PTR DS:[403084] ; ntdll.strtol
    00402B3A -FF25 1C304000 JMP DWORD PTR DS:[40301C] ; diProtec.004207F7
    00402B40 -FF25 18304000 JMP DWORD PTR DS:[403018] ; diProtec.0042DC7C
    00402B46 -FF25 14304000 JMP DWORD PTR DS:[403014] ; diProtec.00420F76
    00402B4C -FF25 10304000 JMP DWORD PTR DS:[403010] ; diProtec.00411957
    00402B52 -FF25 0C304000 JMP DWORD PTR DS:[40300C] ; diProtec.0041A2D3
    00402B58 -FF25 08304000 JMP DWORD PTR DS:[403008] ; diProtec.0043229B
    00402B5E -FF25 04304000 JMP DWORD PTR DS:[403004] ; diProtec.0041C5F3
    00402B64 -FF25 00304000 JMP DWORD PTR DS:[403000] ; diProtec.0041946F

    As we can see, some imports are OK, but most of them are redirected. Imports are hashed, EC decrypts them, then it jumps to them with JMP or RETN. If JMP is used, then original import is decrypted and placed in IAT. In case of RETN, import is never writen in IAT and decrypting will always be performed. Note that these types can have sub-types and these are just examples. Also these subtypes are not important, we can write script that will fix all imports. I will descrybe how did I managed to fix imports.



    First type:

    00402A68 -FF25 BC304000 JMP DWORD PTR DS:[4030BC] ; diProtec.00410531

    If we enter into jump and trace, we will see some random opcodes:

    00410531 53 PUSH EBX
    00410532 68 DC55D60F PUSH 0FD655DC
    00410537 5B POP EBX ; kernel32.7C816D4F
    00410538 81F3 DEF8E860 XOR EBX,60E8F8DE
    0041053E E9 DE2F0000 JMP diProtec.00413521
    00413521 81EB AFB951E4 SUB EBX,E451B9AF
    00413527 81F3 D6E9A330 XOR EBX,30A3E9D6
    0041352D 81C3 DEE4F145 ADD EBX,45F1E4DE
    00413533 871C24 XCHG DWORD PTR SS:[ESP],EBX
    00413536 ^E9 2ECAFFFF JMP diProtec.0040FF69
    0040FF69 0F88 AB7D0000 JS diProtec.00417D1A
    0040FF6F 5A POP EDX ; diProtec.0040FF63
    0040FF70 8B0424 MOV EAX,DWORD PTR SS:[ESP] ; diProtec.0040FF63
    0040FF73 52 PUSH EDX
    0040FF74 52 PUSH EDX
    0040FF75 68 E91D47E8 PUSH E8471DE9
    0040FF7A 5A POP EDX ; diProtec.0040FF63
    0040FF7B E9 EF150000 JMP diProtec.0041156F
    ...etc

    But check stack now:

    $-8 > 0040FF63 diProtec.0040FF63
    $-4 > 0040FF63 diProtec.0040FF63
    $ ==> > 7C816D4F RETURN to kernel32.7C816D4F <--- This is start esp value.
    $+4 > 7C910738 ntdll.7C910738
    $+8 > FFFFFFFF
    $+C > 7FFD7000
    ...

    There was some changes in stack. All above opcodes will push to stack some value and change it. That value (at $-4 from staring esp value) is return address. Place bp on that address and run:

    0040FF63 -FF25 BC304000 JMP DWORD PTR DS:[4030BC] ; user32.wsprintfA

    This is first type of import. Import is decrypted from and here it jumps to it. Also that import is written in IAT section and this decryption is performed only once. Check stack and you will see that it is maintained , ei. ESP again points to starting value.



    Second type:

    00402A74 -FF25 B4304000 JMP DWORD PTR DS:[4030B4] ; diProtec.00415AB7

    Traced opcodes:

    00415AB7 ^0F84 E0D3FFFF JE diProtec.00412E9D
    00415ABD 8B05 24014100 MOV EAX,DWORD PTR DS:[410124]
    00415AC3 E9 12080100 JMP diProtec.004262DA
    004262DA 09C0 OR EAX,EAX
    004262DC ^0F85 F0F4FFFF JNZ diProtec.004257D2
    004262E2 ^E9 8937FFFF JMP diProtec.00419A70
    00419A70 E9 5FEB0000 JMP diProtec.004285D4
    004285D4 ^0F84 67F9FEFF JE diProtec.00417F41
    00417F41 68 28C8DC1D PUSH 1DDCC828
    00417F46 58 POP EAX ; kernel32.7C816D4F
    00417F47 81F0 28008F23 XOR EAX,238F0028
    00417F4D 81F8 8ABFB3C1 CMP EAX,C1B3BF8A
    00417F53 E9 063B0000 JMP diProtec.0041BA5E
    0041BA5E E9 495F0100 JMP diProtec.004319AC
    004319AC ^0F8D 6D41FFFF JGE diProtec.00425B1F
    00425B1F 81C8 EFE9A6F2 OR EAX,F2A6E9EF
    00425B25 81F0 D6C68BEA XOR EAX,EA8BC6D6
    00425B2B 81E8 052CBAC5 SUB EAX,C5BA2C05
    00425B31 ^E9 3B99FEFF JMP diProtec.0040F471
    0040F471 E9 D08A0100 JMP diProtec.00427F46
    00427F46 81C0 94005B72 ADD EAX,725B0094
    00427F4C E8 FA120000 CALL diProtec.0042924B
    0042924B E8 438F0000 CALL diProtec.00432193
    00432193 873C24 XCHG DWORD PTR SS:[ESP],EDI ; ntdll.7C910738
    00432196 5F POP EDI ; diProtec.00429250
    00432197 ^0F84 FE22FFFF JE diProtec.0042449B
    ...
    ...etc...

    I check stack:

    $-4 > 00427F51 RETURN to diProtec.00427F51 from diProtec.0042924B
    $ ==> > 7C816D4F RETURN to kernel32.7C816D4F
    ...

    I place bp on that addres and run:

    00427F51 E8 4E91FFFF CALL diProtec.004210A4

    But check value in EAX register:

    EAX 77D588E1 user32.DialogBoxParamA

    And that is good import. Plus, stack is again maintained. Note this! If at that addres EAX doesn't hold IMPORT, it means that it will just after that trace couple opcodes to the final JMP_IMPORT. So it can be a sub-type of first type. Always check EAX at that point.


    So we see, that address in stack is return address where we will see EAX=IMPORT or JMP_IMPORT. Problem is that we need to trace some code untill stack value is formed. But that is not problem for a script, only that it will take some time to trace (my script traces 30 opcodes , then finds return address in stack, places bp there, checks type and fixes import if needed).






    5. Dumping

    We can dump image from memory with LordPE. But notice that ImageSize is 00001000. In LordPE, right click on target process and select "Correct ImageSize". New image size will be set to 00060000. Now dump file.

    Funny part is, that if we leave EC sections in dump and we doesn't change TLS data, then we use ImpREC to rebuild IAT, unpacked target will detect debugger! It is because EC layer is present and activated with TLS callbacks. If we delete EC sections but leave TLS info, target will fail to work. So open dump with LordPE and set TLS table address and size to 0. Then fix imports with ImpREC and unpacking is finished


    To make perfect dump, you first dump it, then erase last three sections (EC sections) and then fix imports. Such dump is around 60Kb while with EC code it is 300kb big.






    6. Last words

    Btw, about threads. They check for Olly, regmon, filemon, and maybe some other tools with FindWindowA (for olly) and EnumWindows/GetClassNameA (for rest). Some "EBX+" string exist in Olly which is also used for detection. Also, they use ReadProcessMemory for checking all processes. I didn't examne that, just throw quick look. You can disable threads by just patching CreateThread API. Oh, yeah, OutputDebugStringA is also used to crush Olly.

    I will not include my dump for obvious reasons, neither ImpREC tree, but you can check how my IAT script works. I wrote it just for this tutorial, but I unpacked ExeCryptor 2.2.4 itself using this script.

    In this tutorial we didn't see case when OEP is stolen. That part is indentical as in my first tutorial.



    Greets .........


    haggar 2006





    //----------- ExeCryptor 2.2.4 IAT (ASM,Delphi,BorlandC++) - by haggar -----------
    var addr
    var oep
    var pointer
    var counter
    var esp_ref
    var temp

    mov addr,401000
    mov oep,eip

    LABEL_01:
    find addr,#ff25????4E00#
    cmp $RESULT,0
    je END_01
    mov addr,$RESULT
    add addr,2
    mov pointer,addr
    mov pointer,[pointer]
    mov pointer,[pointer]
    cmp pointer,10000000 //Check is import placed in thunk, or redirection.
    ja LABEL_01
    cmp pointer,0 //For delphi.
    je LABEL_01

    sub addr,2
    mov eip,addr
    add addr,2

    mov esp_ref,esp //Stack reference.
    mov counter,0
    LABEL_02: //Trace some code without purpose.
    sti
    add counter,1
    cmp counter,30
    jne LABEL_02

    mov temp,esp
    LABEL_03: //Find referenced stack value.
    add temp,4
    cmp temp,esp_ref
    jne LABEL_03
    sub temp,4

    mov temp,[temp] //Go to "Magic address".
    bp temp
    esto
    bc eip


    mov temp,[eip]
    and temp,0ffff
    cmp temp,025ff //SelfWriting import type? No need to fix it then.
    je LABEL_01

    cmp eax,10000000 //If EAX=!IMPORT, then it is a first type.
    jb LABEL_01

    mov temp,addr //In this case EAX=IMPORT.
    mov temp,[temp]
    mov [temp],eax

    jmp LABEL_01

    END_01:
    mov eip,oep
    ret
    //---------------------- end of script -------------------------------

  9. #59
    پروفشنال Morteza_SOS's Avatar
    تاريخ عضويت
    Apr 2006
    پست ها
    577

    پيش فرض

    Level : intermediate

    SafeDisc 3.20 - 4.00


    If you ever played games in your life, then you for sure know what is SafeDisc. SafeDisc is one of the today most used CD protections. In a previous tutorial we met SafeDisc "small brother" - SafeCast. SafeDisc is product of the same company and it is almost indentical as SafeCast. Main difference is that SafeDisc checks for bad sectors on the CD to be sure that program is running from original one. Bad sectors cannot be copied to another CD. Well it shouldn't be, but programs like Alcohol 120% and similar can do that. It also depends of SafeDisc version. I'm not quite sure about that, copying CDs doesn't interest me. Removing protection layer is objective of this tutorial. For this tutorial you need original CD and Windows XP.








    1. Introduction to SafeDisc


    Target for this tutorial is "Need For Speed Underground 2", protected probably with some version in range from 3.20 up to 4.00. It is not possible to detect exact version because SafeCast above 3.20 have erased version numbers. PEiD fails to detect protection at all, but Protection_ID v5.1f gives solid information:

    Scanning -> C:Need for Speed Underground 2speed2.exe
    File Type : Exe, Size : 5987981 (05B5E8Dh) Bytes
    -> File has 1166989 (011CE8Dh) bytes of appended data starting at offset 0499000h
    [!] Safedisc v3.20 - v4.xx or newer [removed version] detected !
    [!] removed version is Safedisc v4.00.000 - v4.00.003
    [!] Possible CD/DVD-Check String -> Please insert
    - Scan Took : 1.938 Seconds


    Protection in this version of SafeDisc consits from:

    [1] CD check - bad sectors, we have original CD so this is not problem for unpacking.
    [2] Debugger checks - easy to defeat, same as in SafeCast.
    [3] Import protection - same as in SafeCast, requires little work but it is not hard.
    [4] Emulated opcodes - again, same as in SafeCast.
    [5] DebugBlocker and nanomites - the hardest part of protection.






    2. OEP, debugger checks and SafeDisc debugger

    It is very easy to find whre OEP should be. We open protected file in Olly and we can spot OEP jump:

    0093309E > 55 PUSH EBP
    0093309F 8BEC MOV EBP,ESP
    009330A1 60 PUSHAD
    009330A2 BB 9E309300 MOV EBX,speed2.<ModuleEntryPoint>
    009330A7 33C9 XOR ECX,ECX
    009330A9 8A0D 3D309300 MOV CL,BYTE PTR DS:[93303D]
    009330AF 85C9 TEST ECX,ECX
    009330B1 74 0C JE SHORT speed2.009330BF
    009330B3 B8 13319300 MOV EAX,speed2.00933113
    009330B8 2BC3 SUB EAX,EBX
    009330BA 83E8 05 SUB EAX,5
    009330BD EB 0E JMP SHORT speed2.009330CD
    009330BF 51 PUSH ECX
    ...
    ...
    00933146 8B40 04 MOV EAX,DWORD PTR DS:[EAX+4]
    00933149 FFD0 CALL EAX
    0093314B 58 POP EAX ; kernel32.7C816D4F
    0093314C FF35 53319300 PUSH DWORD PTR DS:[933153]
    00933152 C3 RETN
    00933153 72 16 JB SHORT speed2.0093316B
    00933155 61 POPAD
    00933156 1360 0D ADC ESP,DWORD PTR DS:[EAX+D]
    00933159 -E9 9388E2FF JMP speed2.0075B9F1
    0093315E CC INT3
    0093315F CC INT3
    00933160 81EC E8020000 SUB ESP,2E8
    00933166 53 PUSH EBX
    00933167 55 PUSH EBP
    00933168 56 PUSH ESI
    00933169 57 PUSH EDI ; ntdll.7C910738
    0093316A 8D4424 60 LEA EAX,DWORD PTR SS:[ESP+60]

    At address 00933159 is jump that points in first section. That is OEP jump.



    Debugger checks are same as in SafeCast. We can place breakpoint on IsDebuggerPresent and then return to code:

    6670D9F0 56 PUSH ESI
    6670D9F1 68 80A77A66 PUSH 667AA780
    6670D9F6 33F6 XOR ESI,ESI
    6670D9F8 E8 72C00000 CALL 66719A6F
    6670D9FD 50 PUSH EAX
    6670D9FE E8 90C00000 CALL 66719A93
    6670DA03 83C4 08 ADD ESP,8
    6670DA06 85C0 TEST EAX,EAX
    6670DA08 74 1C JE SHORT 6670DA26
    6670DA0A FFD0 CALL EAX <------------------------ IsDebuggerPresent call.
    6670DA0C 8BF0 MOV ESI,EAX
    6670DA0E 66:85F6 TEST SI,SI
    6670DA11 74 13 JE SHORT 6670DA26
    6670DA13 E8 6238FFFF CALL 6670127A <------------------- "BadBoy" procedure!
    6670DA18 66:8BF0 MOV SI,AX
    6670DA1B 66:F7DE NEG SI
    6670DA1E 1BF6 SBB ESI,ESI
    6670DA20 46 INC ESI
    6670DA21 66:85F6 TEST SI,SI
    6670DA24 75 13 JNZ SHORT 6670DA39
    6670DA26 8B4424 08 MOV EAX,DWORD PTR SS:[ESP+8]
    6670DA2A 8B08 MOV ECX,DWORD PTR DS:[EAX]
    6670DA2C 81E1 EA894267 AND ECX,674289EA
    6670DA32 8908 MOV DWORD PTR DS:[EAX],ECX
    6670DA34 66:8BC6 MOV AX,SI
    6670DA37 5E POP ESI ; 0012FB10
    6670DA38 C3 RETN
    6670DA39 8B4424 08 MOV EAX,DWORD PTR SS:[ESP+8]
    6670DA3D 8B08 MOV ECX,DWORD PTR DS:[EAX]
    6670DA3F 81E1 119800EF AND ECX,EF009811
    6670DA45 8908 MOV DWORD PTR DS:[EAX],ECX
    6670DA47 66:8BC6 MOV AX,SI
    6670DA4A 5E POP ESI ; 0012FB10
    6670DA4B C3 RETN

    When we break there, we trace into "BadBoy" procedure. When we enter in it, we just place RETN on first opcode inside and all debugger checks are killed. It is already explained in SafeCast tutorial.



    SafeDisc debugger, or self-debugging is something new. Protected program will create couple temporyr files in temp older. One of those files (they all have random names) is executable. Main protected file starts that executable and then waits (WaitForSingleObject) signal that is can continue. Temp executable will attach to protected exe , give it signal and continue to debug it. This prevents debugging with Olly or any RING3 debugger. That can be prevented by not executing CreateProcessA , WaitForSingleObject, and performing couple more small changes to prevent crushing.


    Here is how OEP can be found with Olly:

    - We place breakpoint on OEP jump:

    00933159 -E9 9388E2FF JMP speed2.0075B9F1

    - Then we place bp on CreateProcessA and break there:


    7C802367 > 8BFF MOV EDI,EDI
    7C802369 55 PUSH EBP
    7C80236A 8BEC MOV EBP,ESP
    7C80236C 6A 00 PUSH 0
    7C80236E FF75 2C PUSH DWORD PTR SS:[EBP+2C]
    7C802371 FF75 28 PUSH DWORD PTR SS:[EBP+28]
    7C802374 FF75 24 PUSH DWORD PTR SS:[EBP+24]
    7C802377 FF75 20 PUSH DWORD PTR SS:[EBP+20]
    7C80237A FF75 1C PUSH DWORD PTR SS:[EBP+1C]
    7C80237D FF75 18 PUSH DWORD PTR SS:[EBP+18]
    7C802380 FF75 14 PUSH DWORD PTR SS:[EBP+14]
    7C802383 FF75 10 PUSH DWORD PTR SS:[EBP+10]
    7C802386 FF75 0C PUSH DWORD PTR SS:[EBP+C]
    7C802389 FF75 08 PUSH DWORD PTR SS:[EBP+8]
    7C80238C 6A 00 PUSH 0
    7C80238E E8 0BB70100 CALL kernel32.CreateProcessInternalA
    7C802393 5D POP EBP ; speed2.00935424
    7C802394 C2 2800 RETN 28

    We don't execute it, instead we set "new origin" at RETN 28. We run and return to main code.

    - We must avoid CloseHandle execution after returning from CreateProcessA because process is not created, there is no handle and we would get INVALID_HANDLE exception. So we set new origin below:

    00935424 85C0 TEST EAX,EAX
    00935426 5D POP EBP
    00935427 74 1E JE SHORT speed2.00935447
    00935429 8B5424 20 MOV EDX,DWORD PTR SS:[ESP+20]
    0093542D 52 PUSH EDX
    0093542E FF53 1C CALL DWORD PTR DS:[EBX+1C] ; kernel32.CloseHandle
    00935431 8B4424 24 MOV EAX,DWORD PTR SS:[ESP+24]
    00935435 50 PUSH EAX
    00935436 FF53 1C CALL DWORD PTR DS:[EBX+1C] ; kernel32.CloseHandle
    00935439 5F POP EDI
    0093543A 5E POP ESI
    0093543B 66:B8 0100 MOV AX,1
    0093543F 5B POP EBX

    00935440 81C4 70060000 ADD ESP,670
    00935446 C3 RETN

    - Then we place bp at IsDebuggerPresent and we enter in "BadBoy" procedure where we patch first opcode with RETN.

    - After that, we can place bp at the end (end because SafeDisc checks some imports for CC bytes) of SetEvent API. That will bring ous very close to WaitForSingleObject part:

    667250A8 |> FF75 FC PUSH DWORD PTR SS:[EBP-4] ; /hEvent = 000000A0 (window)
    667250AB |. FF15 64407966 CALL DWORD PTR DS:[<&KERNEL32.SetEvent>] ; SetEvent
    667250B1 |. 85C0 TEST EAX,EAX <--------------------------- You should be here!!!
    667250B3 |. 75 0C JNZ SHORT ~df394b.667250C1
    667250B5 |. FFD3 CALL EBX ; ntdll.RtlGetLastWin32Error
    667250B7 |. FF75 FC PUSH DWORD PTR SS:[EBP-4]
    667250BA |. FFD6 CALL ESI ; kernel32.CloseHandle
    667250BC |. E8 8FC7FEFF CALL ~df394b.66711850
    667250C1 |> 6A FF PUSH -1 ; /Timeout = INFINITE
    667250C3 |. 57 PUSH EDI ; |hObject = 00000098 (window)
    667250C4 |. FF15 90407966 CALL DWORD PTR DS:[<&KERNEL32.WaitForSin>; WaitForSingleObject
    667250CA |. FF75 FC PUSH DWORD PTR SS:[EBP-4] <-------------- Set origin here to avoid above API.
    667250CD |. 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
    667250D0 |. FFD6 CALL ESI ; kernel32.CloseHandle
    667250D2 |. 57 PUSH EDI
    667250D3 |. FFD6 CALL ESI ; kernel32.CloseHandle
    667250D5 |. 837D F8 00 CMP DWORD PTR SS:[EBP-8],0
    667250D9 |. 5F POP EDI
    667250DA |. 5E POP ESI ; kernel32.CloseHandle
    667250DB |. 74 07 JE SHORT ~df394b.667250E4 <-------------- Execute this jump to avoid error detection.
    667250DD |. FFD3 CALL EBX ; ntdll.RtlGetLastWin32Error
    667250DF |. E8 6CC7FEFF CALL ~df394b.66711850
    667250E4 |> 5B POP EBX ; ntdll.RtlGetLastWin32Error
    667250E5 |. C9 LEAVE
    667250E6 . C3 RETN

    - Run and you'll break at OEP jump. Trace in and you will see OEP:

    0075B9F1 > 6A 18 PUSH 18
    0075B9F3 . 68 98397D00 PUSH speed2.007D3998
    0075B9F8 . E8 D3500000 CALL speed2.00760AD0
    0075B9FD . BF 94000000 MOV EDI,94
    0075BA02 . 8BC7 MOV EAX,EDI ; ntdll.7C910738
    0075BA04 . E8 E7070000 CALL speed2.0075C1F0
    0075BA09 . 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
    0075BA0C . 8BF4 MOV ESI,ESP
    0075BA0E . 893E MOV DWORD PTR DS:[ESI],EDI ; ntdll.7C910738
    0075BA10 . 56 PUSH ESI ; /pVersionInformation = FFFFFFFF
    0075BA11 . FF15 64317800 CALL DWORD PTR DS:[783164] ; GetVersionExA
    0075BA17 . 8B4E 10 MOV ECX,DWORD PTR DS:[ESI+10]
    ...






    3. Restoring imports

    This feature is completly the same as in SafeCast and it is described in previous tutorial. I will not write whole thing again so please check SafeCast tutorial.

    First Type:
    Import points to some virtual addres where is code that calls FIND_CORRECT_IMPORT algo. When correct import is found, it jumps there. Using algo against itself we can decrypt all imports.

    Second Type:
    We have jumps that leads outside of main image. It leads to some code and eventualy it jumps to import.







    4. Emulated opcodes

    Again, same thing as in SafeCast. This JMP EAX jumps outside of code:

    004011E3 $ B8 FB0E0000 MOV EAX,0EFB
    004011E8 . 59 POP ECX ; kernel32.7C816D4F
    004011E9 . 8D0408 LEA EAX,DWORD PTR DS:[EAX+ECX]
    004011EC . 8B00 MOV EAX,DWORD PTR DS:[EAX]
    004011EE . FFE0 JMP EAX

    And that part of code is called from:

    00401089 /$ 51 PUSH ECX
    0040108A |. 50 PUSH EAX
    0040108B |. E8 53010000 CALL speed2.004011E3

    And that part is called from different locations:

    References in speed2:.text to 00401089
    Address Disassembly Comment
    005B7869 CALL speed2.00401089
    005B788E CALL speed2.00401089
    005B78F5 CALL speed2.00401089
    005B7921 CALL speed2.00401089
    005C08D7 CALL speed2.00401089
    005C08EC CALL speed2.00401089
    005C0916 CALL speed2.00401089
    005C0923 CALL speed2.00401089
    005C0945 CALL speed2.00401089
    005C0954 CALL speed2.00401089
    005CFDBD CALL speed2.00401089
    005D2243 CALL speed2.00401089
    005D2569 CALL speed2.00401089
    0065A71D CALL speed2.00401089
    00670CE1 CALL speed2.00401089
    006D9D8F CALL speed2.00401089
    006D9EF9 CALL speed2.00401089
    006D9FE0 CALL speed2.00401089
    006F5D87 CALL speed2.00401089
    006FEC11 CALL speed2.00401089

    JMP EAX will jump to procedure which will emulate "stolen" opcode, but it will write original back so emulation is performed only one time. Simply by executing those calls we will force SafeDisc to restore stolen code. there can be several this JMP EAX routines.I found two in this example.






    5. Nanomites

    Nanomites are by far the hardest part. Code section of protected program is full of INT 3 opcodes on unusuall places. For example let's check this procedure:

    006717FF /$ 8BFF MOV EDI,EDI ; speed2_.00803F90
    00671801 |. 55 PUSH EBP
    00671802 |. 8BEC MOV EBP,ESP
    00671804 |. 51 PUSH ECX ; ntdll.7C91056D
    00671805 |. 8365 FC 00 AND DWORD PTR SS:[EBP-4],0
    00671809 |. 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
    0067180C |. 50 PUSH EAX
    0067180D |. 68 94B47A00 PUSH speed2_.007AB494 ; ASCII "SoftwareMicrosoftDirect3D"
    00671812 |. 68 02000080 PUSH 80000002
    00671817 |. FF15 10307800 CALL DWORD PTR DS:[783010]
    0067181D |. CC INT3
    0067181E |. CC INT3
    0067181F |. CC INT3
    00671820 |. CC INT3
    00671821 |. 56 PUSH ESI
    00671822 |. 8D45 14 LEA EAX,DWORD PTR SS:[EBP+14]
    00671825 |. 50 PUSH EAX
    00671826 |. FF75 10 PUSH DWORD PTR SS:[EBP+10]
    00671829 |. 8D45 10 LEA EAX,DWORD PTR SS:[EBP+10]
    0067182C |. 50 PUSH EAX
    0067182D |. 6A 00 PUSH 0
    0067182F |. FF75 0C PUSH DWORD PTR SS:[EBP+C] ; speed2_.007AB4DC
    00671832 |. FF75 FC PUSH DWORD PTR SS:[EBP-4]
    00671835 |. FF15 08307800 CALL DWORD PTR DS:[783008]
    0067183B |. FF75 FC PUSH DWORD PTR SS:[EBP-4]
    0067183E |. 8BF0 MOV ESI,EAX
    00671840 |. FF15 14307800 CALL DWORD PTR DS:[783014]
    00671846 |. 85F6 TEST ESI,ESI
    00671848 |. 5E POP ESI
    00671849 |. CC INT3
    0067184A |. CC INT3
    0067184B |. 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10]
    0067184E |. 3B45 08 CMP EAX,DWORD PTR SS:[EBP+8]
    00671851 |. 75 05 JNZ SHORT speed2_.00671858
    00671853 |. 33C0 XOR EAX,EAX
    00671855 |. 40 INC EAX
    00671856 |. EB 02 JMP SHORT speed2_.0067185A
    00671858 |> 33C0 XOR EAX,EAX
    0067185A |> C9 LEAVE
    0067185B . C2 1000 RETN 10

    INT 3 opcode represent one nanomite. When nanmite is executed, it couse exception. SafeDisc debugger takes control, checks what type of exception occured and where, then it emulate that opcode or it writes original opcode there.

    To better understand how does this work, we need to debug SafeDisc debugger. With SoftICE it is easy to see what is going on, but if we want to do that with Olly, we need to perform small ritual. OK, so this is how I was able to attach olly to SafeDisc debugger:

    - Load main protected file in Olly and break on CreateProcessA. Stop there and wait.

    - Go to "Cocuments and SettingsYour_Name_HereLocal SettingsTemp" and open temporary executable in second Olly. Temp exe is hidden with some random name, in my case it is "~e5.0001". Change it's OEP to infinite jump, EB FE. Save changes and close that Olly.

    - Execute CreateProcessA (place bp at the end of API). New process is created and it's looping forever. Wait with this olly.

    - Open again second Olly and attach to new created process. F9 to run, F12 to pause. Restore oly OEP bytes. Minimize this olly.

    - In first Olly, break at IsDebuggerPresent to kill debugger checks by patching "badboy" procedure. After that just run program. Program will wait for second process to attach. It will wait forever (WaitForSingleObject with PUSH -1 parameter) and that is good for us.

    - Now here is confusing part: Open THIRD Olly instance, attach to the FIRST one, and detach FIRST OLLY INSTANCE from main proteced executable. Close third olly and that will close first one too, but protected program will be free in memory.

    - Now, only one Olly is left and that Olly debugs SafeDisc debugger. From here you can continue on WaitForDebugEvent.



    When INT 3 is executed, SD debugger checks where exception occured. Then it emulates that opcode. If same nanomite is executed second time, SD debugger will write (WriteProcessMemory) original opcode to main executable. That is probably to gain on speed. Non-stop emulation would slow down game to the death. Since opcode is second time written, there must be some check for that. Check is very simple, it is one CMP AX,1 and after it JNZ DONT_WRITE. Patching jump forces SD to always write opcode. Now I patched jump and played game within Olly a little. then I minimized, dumped, fixed IAT and code. I started dump and it worked! Game loaded perfect, but it crushed after some time what is expected because most of nanomites are not restored. So how to fix that?

    To tell you the truth, I didn't came out with generic solution so I fixed them manually. I attched olly to temp executable and I patched that check CMP AX,1 - JNZ DONT_WRITE. Then I played game a little, tried all kinds of races, tried online game, etc... everything to make sure that I trigered (and by that restored) as much as possible nanomites. Then I dumped code section. After that, I found OEP in instance without SafeDisc debugger and I pasted this dumped code there. Then I fixed imports and stolen opcodes. Now I got second dump from which I could play game. But on exit it would crush. I decide to open dump and check hom many there is nanomites.

    But amounth of CC bytes was huge due to reason that executable has tons of CC bytes that are not nanomites, but leftovers from VC++ compiler. For example:

    004017C8 . C3 RETN
    004017C9 CC INT3
    004017CA CC INT3
    004017CB CC INT3
    004017CC CC INT3
    004017CD CC INT3
    004017CE 90 NOP
    004017CF 90 NOP

    005AFD43 . E9 58220000 JMP dumped1.005B1FA0
    005AFD48 CC INT3
    005AFD49 CC INT3
    005AFD4A CC INT3
    005AFD4B CC INT3
    005AFD4C CC INT3
    005AFD4D CC INT3
    005AFD4E CC INT3
    005AFD4F CC INT3

    I wrote script for NOPing those CC bytes, then I found some nanomites and fixed them by examning SafeDisc debugg loop. In SD debugg loop, I would place bp on WaitForDebugEvent, then I would set address in buffer to point on my nanomite. Then in GetThreadContext buffer I would do the same. SafeDisc would decrypt code and I would just copy it. But as said, this is unfinished buisnes. I will have to examne it better or in a updated version of this tutorial, or in a new tutorial with new target (possible higher version of SafeDisc).

    I assume that SafeDisc must have some table with all addresses where are nanomites, table with original code, but I didn't had will to trace trough code whole day. I'm already tired.





    6. Custom CD check and a final touch

    I assume that this is not part of SafeDisc protection. I removed original CD and started dump, but it asked me for CD 2. Breakpoint on GetDriveTypeA got me to CD check procedure:

    005BF120 /$ 83EC 0C SUB ESP,0C
    005BF123 |. 53 PUSH EBX
    005BF124 |. 55 PUSH EBP
    005BF125 |. 56 PUSH ESI
    005BF126 |. 57 PUSH EDI
    005BF127 |. B3 41 MOV BL,41
    005BF129 |. BF 01000000 MOV EDI,1
    005BF12E |. 885C24 10 MOV BYTE PTR SS:[ESP+10],BL
    005BF132 |. FF15 60518F00 CALL DWORD PTR DS:[<&kernel32.GetLogical>; [GetLogicalDrives
    005BF138 |. 33ED XOR EBP,EBP
    005BF13A |. 68 00040000 PUSH 400
    005BF13F |. 894424 18 MOV DWORD PTR SS:[ESP+18],EAX
    005BF143 |. 896C24 1C MOV DWORD PTR SS:[ESP+1C],EBP
    005BF147 |. E8 5461FBFF CALL dump.005752A0
    005BF14C |. 8BF0 MOV ESI,EAX
    005BF14E |. 83C4 04 ADD ESP,4
    005BF151 |. 3BF5 CMP ESI,EBP
    005BF153 |. C605 7F058000 >MOV BYTE PTR DS:[80057F],0
    005BF15A |. 0F84 A1000000 JE dump.005BF201
    005BF160 |> 857C24 14 /TEST DWORD PTR SS:[ESP+14],EDI
    005BF164 |. 74 3E |JE SHORT dump.005BF1A4
    005BF166 |. 0FBEC3 |MOVSX EAX,BL
    005BF169 |. 50 |PUSH EAX
    005BF16A |. 68 D4387A00 |PUSH dump.007A38D4 ; ASCII "%c:"
    005BF16F |. 56 |PUSH ESI
    005BF170 |. E8 2FD31900 |CALL dump.0075C4A4
    005BF175 |. 83C4 0C |ADD ESP,0C
    005BF178 |. 56 |PUSH ESI ; /RootPathName = "A:"
    005BF179 |. FF15 5C518F00 |CALL DWORD PTR DS:[<&kernel32.GetDriveT>; GetDriveTypeA
    005BF17F |. 83F8 05 |CMP EAX,5
    005BF182 |. 74 0A |JE SHORT dump.005BF18E
    005BF184 |. 8B0D 60DC7900 |MOV ECX,DWORD PTR DS:[79DC60]
    005BF18A |. 85C9 |TEST ECX,ECX
    005BF18C |. 74 16 |JE SHORT dump.005BF1A4
    005BF18E |> 83F8 02 |CMP EAX,2
    005BF191 |. 74 11 |JE SHORT dump.005BF1A4
    005BF193 |. 8B4C24 10 |MOV ECX,DWORD PTR SS:[ESP+10]
    005BF197 |. 51 |PUSH ECX
    005BF198 |. E8 03FFFFFF |CALL dump.005BF0A0
    005BF19D |. 83C4 04 |ADD ESP,4
    005BF1A0 |. 84C0 |TEST AL,AL
    005BF1A2 |. 75 14 |JNZ SHORT dump.005BF1B8
    005BF1A4 |> FEC3 |INC BL
    005BF1A6 |. D1E7 |SHL EDI,1
    005BF1A8 |. 45 |INC EBP
    005BF1A9 |. 83FD 20 |CMP EBP,20
    005BF1AC |. 885C24 10 |MOV BYTE PTR SS:[ESP+10],BL
    005BF1B0 |.^7C AE JL SHORT dump.005BF160
    005BF1B2 |. 8B7C24 18 MOV EDI,DWORD PTR SS:[ESP+18]
    005BF1B6 |. EB 05 JMP SHORT dump.005BF1BD
    005BF1B8 |> BF 01000000 MOV EDI,1
    005BF1BD |> 56 PUSH ESI
    005BF1BE |. E8 FD60FBFF CALL dump.005752C0
    005BF1C3 |. 83C4 04 ADD ESP,4
    005BF1C6 |. 85FF TEST EDI,EDI
    005BF1C8 |. 74 30 JE SHORT dump.005BF1FA
    005BF1CA |. 881D 7F058000 MOV BYTE PTR DS:[80057F],BL
    005BF1D0 |. 881D B0E88600 MOV BYTE PTR DS:[86E8B0],BL
    005BF1D6 |. C605 B1E88600 >MOV BYTE PTR DS:[86E8B1],3A
    005BF1DD |. C605 B2E88600 >MOV BYTE PTR DS:[86E8B2],5C
    005BF1E4 |. C605 B3E88600 >MOV BYTE PTR DS:[86E8B3],0
    005BF1EB |. E8 4085FFFF CALL dump.005B7730
    005BF1F0 |. 5F POP EDI
    005BF1F1 |. 5E POP ESI
    005BF1F2 |. 5D POP EBP
    005BF1F3 |. 8AC3 MOV AL,BL
    005BF1F5 |. 5B POP EBX
    005BF1F6 |. 83C4 0C ADD ESP,0C
    005BF1F9 |. C3 RETN
    005BF1FA |> C605 7F058000 >MOV BYTE PTR DS:[80057F],0
    005BF201 |> 5F POP EDI
    005BF202 |. 5E POP ESI
    005BF203 |. 5D POP EBP
    005BF204 |. 32C0 XOR AL,AL
    005BF206 |. 5B POP EBX
    005BF207 |. 83C4 0C ADD ESP,0C
    005BF20A . C3 RETN

    This one is 3 times called. If this procedure returns EAX=0, CD check fails. This checks wants some files on CD etc. We just make some patch that will return EAX=1 and problem is solved.

    EA Games usually have couple logo movies that are shown uppon startup. They are very annoying because they cannot be skiped so I patched them too. But that is not part of protection.






    7. The end

    And that was it. It was not too hard, but again, my dump is not fully rebuilded. Just as much it needs for playing the game. Some nanomites are stil left unresolved but we learned something about SafeDisc protection features.

    Btw, here is script for finding OEP:

    //======================= START ================================
    /*
    ================================================== ============
    SafeDisc v4.0 - Kill debug checks and find OEP script
    ================================================== ============
    */

    var OEP

    find eip,#E9????????CCCC81ECE802000053555657#
    mov OEP,$RESULT

    find eip,#751A8B4C243C8B5424348B44242C51525350#
    bp $RESULT
    esto
    bc eip

    add eip,1c

    gpa "IsDebuggerPresent","kernel32.dll"
    bp $RESULT
    esto
    bc eip
    rtr
    sti
    sti
    sti
    sti
    sti
    fill eip,1,0c3

    gpa "SetEvent","kernel32.dll"
    bphws $RESULT,"x"
    esto
    bphwc $RESULT
    rtr
    sti

    sti
    sti
    add eip,9

    sto
    sto
    sto
    sto
    sto
    sto
    sto
    sto
    add eip,9

    bp OEP
    esto
    bc eip
    sti
    ret
    //=========================== END ==============================

  10. #60
    پروفشنال Morteza_SOS's Avatar
    تاريخ عضويت
    Apr 2006
    پست ها
    577

    پيش فرض

    Level : intermediate

    ---------------------------------
    Unpacking SafeCast 2.4
    ---------------------------------


    What is SafeCast? Dou you know what is SafeDisc maybe? SafeDisc is well known CD protection from Macrovision, used in many software that comes on CD/DVD (games, etc...) . SafeCast is the same thing except it is made for programs that doesn't came on CD (downloadable programs, trial versions, etc...). In this tutorial we will see how version 2.4 can be unpacked. It is little older one, but I had program protected with it. Target for my tutorial is Adobe Photoshop 8.0, but this should be generic aproach for all 2.4 versions.



    1. Introduction

    Tools that I used for unpacking are usual ; PEiD, OllyDbg, ImpREC, LordPE, and some hex editor. Oh yeah, and Win XP.


    I installed program and I scanned installation folder with PEiD. PEiD gave two positive results:

    C:Program FilesAdobePhotoshop CSAdobeLM.dll SafeDisc 2.41.000 -> Macrovision [Overlay]
    C:Program FilesAdobePhotoshop CSTw10122.dat SafeDisc 2.41.000 -> Macrovision [Overlay]

    PEiD detects SafeCast as SafeDisc, what is correct because both are the same protection. You can manually check version of protection. Open protected file in Olly and check PE header at the end:

    10000FD0 00 00 00 00 42 6F 47 5F 20 2A 39 30 2E 30 26 21 ....BoG_ *90.0&!
    10000FE0 21 20 20 59 79 3E 00 00 00 00 00 00 00 00 00 00 ! Yy>..........
    10000FF0 00 00 00 00 02 00 00 00 29 00 00 00 00 00 00 00 ........).......

    String "BoG_" is unique in SafeDisc versions. Last 3 DWORDS hold version information number. You just need to translate hex numbers to decimal system:

    02 00 00 00 -> 2
    29 00 00 00 -> 41
    00 00 00 00 -> 0

    And you get 2.41.0 as version.





    2. Anti-debug layer

    Now, examning protection code is not so easy. SC (SafeCast in the rest of this tutorial) extracts couple files in temp folder that have different purpose. First file that is extracted , with some random name such is ~e5d141.tmp , is executable file. That file is only file that will remain in temp folder after protected program closes. This executable is a cleanup application. It's purpose is to delete all other protection files extracted in temporary folder. Other files are more interesting because one of them is responsable for debugging protection (ei, it holds couple anti debug tricks). This file can be dumped and examned, but it has some encrypted parts of code, plus some obfuscation and there is no need indeed to spend time on that.

    First file that I decided to unpack is that AdobeLM.dll. LM probably stands for License Manager. First check that I noticed in protected file is IsDebuggerPresent one. So I placed bp on that api and returned from kernel32. I was in temporary file:

    00879A70 /$ 56 PUSH ESI
    00879A71 |. 68 C8E18C00 PUSH ~df394b.008CE1C8
    00879A76 |. 33F6 XOR ESI,ESI
    00879A78 |. E8 B8B70000 CALL ~df394b.00885235
    00879A7D |. 50 PUSH EAX
    00879A7E |. E8 D6B70000 CALL ~df394b.00885259
    00879A83 |. 83C4 08 ADD ESP,8
    00879A86 |. 85C0 TEST EAX,EAX
    00879A88 |. 74 1C JE SHORT ~df394b.00879AA6
    00879A8A |. FFD0 CALL EAX <------------------------------- Here was IsDebuggerPresent call.
    00879A8C |. 8BF0 MOV ESI,EAX <---------------------------- I'm Here!!!
    00879A8E |. 66:85F6 TEST SI,SI
    00879A91 |. 74 13 JE SHORT ~df394b.00879AA6 <-------------- Good jump.
    00879A93 |. E8 E277FFFF CALL ~df394b.0087127A <------------------ BadBoy procedure.
    00879A98 |. 66:8BF0 MOV SI,AX
    00879A9B |. 66:F7DE NEG SI
    00879A9E |. 1BF6 SBB ESI,ESI
    00879AA0 |. 46 INC ESI
    00879AA1 |. 66:85F6 TEST SI,SI
    00879AA4 |. 75 13 JNZ SHORT ~df394b.00879AB9
    00879AA6 |> 8B4424 08 MOV EAX,DWORD PTR SS:[ESP+8]
    00879AAA |. 8B08 MOV ECX,DWORD PTR DS:[EAX]
    00879AAC |. 81E1 EA894267 AND ECX,674289EA
    00879AB2 |. 8908 MOV DWORD PTR DS:[EAX],ECX
    00879AB4 |. 66:8BC6 MOV AX,SI
    00879AB7 |. 5E POP ESI ; 0006F46C
    00879AB8 |. C3 RETN
    00879AB9 |> 8B4424 08 MOV EAX,DWORD PTR SS:[ESP+8]
    00879ABD |. 8B08 MOV ECX,DWORD PTR DS:[EAX]
    00879ABF |. 81E1 119800EF AND ECX,EF009811
    00879AC5 |. 8908 MOV DWORD PTR DS:[EAX],ECX
    00879AC7 |. 66:8BC6 MOV AX,SI
    00879ACA |. 5E POP ESI ; 0006F46C
    00879ACB . C3 RETN

    Now, what we can see is that CALL EAX was call to IsDebuggerPresent. If SI=0, jump below it will be executed and that is good jump. If SI=1, debugger is detected. Procedure below jump is executed if debugger is detected. Ofcourse, logic says that we just change SI from 1 to 0 and we can pass this check, but I was wondering how many times that "BadBoy" procedure is used. So I traced in it:

    0087127A /$ 55 PUSH EBP
    0087127B |. 8BEC MOV EBP,ESP
    0087127D |. 81EC 14010000 SUB ESP,114
    00871283 |. 56 PUSH ESI
    00871284 |. 33F6 XOR ESI,ESI
    00871286 |. E8 DC450100 CALL ~df394b.00885867
    0087128B |. 50 PUSH EAX
    0087128C |. E8 91000000 CALL ~df394b.00871322
    00871291 |. 66:85C0 TEST AX,AX
    00871294 |. 59 POP ECX ; ~df394b.00879A98
    00871295 |. 0F84 81000000 JE ~df394b.0087131C
    0087129B |. 8D85 ECFEFFFF LEA EAX,DWORD PTR SS:[EBP-114]
    008712A1 |. 68 04010000 PUSH 104 ; /BufSize = 104 (260.)
    008712A6 |. 50 PUSH EAX ; |PathBuffer = 00000001
    008712A7 |. 56 PUSH ESI ; |hModule = 00000001
    008712A8 |. FF15 B8118C00 CALL DWORD PTR DS:[<&KERNEL32.GetModuleF>; GetModuleFileNameA
    008712AE |. 56 PUSH ESI ; /hTemplateFile = 00000001
    008712AF |. 56 PUSH ESI ; |Attributes = READONLY
    008712B0 |. 6A 03 PUSH 3 ; |Mode = OPEN_EXISTING
    008712B2 |. 56 PUSH ESI ; |pSecurity = 00000001
    008712B3 |. 6A 01 PUSH 1 ; |ShareMode = FILE_SHARE_READ
    008712B5 |. 8D85 ECFEFFFF LEA EAX,DWORD PTR SS:[EBP-114] ; |
    008712BB |. 68 00000080 PUSH 80000000 ; |Access = GENERIC_READ
    008712C0 |. 50 PUSH EAX ; |FileName = 00000001 ???
    008712C1 |. FF15 BC118C00 CALL DWORD PTR DS:[<&KERNEL32.CreateFile>; CreateFileA
    008712C7 |. 83F8 FF CMP EAX,-1
    008712CA |. 8945 F0 MOV DWORD PTR SS:[EBP-10],EAX
    008712CD |. 75 08 JNZ SHORT ~df394b.008712D7
    008712CF |. FF15 E0108C00 CALL DWORD PTR DS:[<&KERNEL32.GetLastErr>; [GetLastError
    008712D5 |. EB 45 JMP SHORT ~df394b.0087131C
    008712D7 |> 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10]
    008712DA |. 6A 65 PUSH 65
    008712DC |. 50 PUSH EAX
    008712DD |. 8975 F4 MOV DWORD PTR SS:[EBP-C],ESI
    008712E0 |. E8 8C490100 CALL ~df394b.00885C71
    008712E5 |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10] ; |
    008712E8 |. 56 PUSH ESI ; |Arg2 = 00000001
    008712E9 |. 50 PUSH EAX ; |Arg1 = 00000001
    008712EA |. E8 B5450100 CALL ~df394b.008858A4 ; ~df394b.008858A4
    008712EF |. 83C4 10 ADD ESP,10
    008712F2 |. 66:85C0 TEST AX,AX
    008712F5 |. 74 1C JE SHORT ~df394b.00871313
    008712F7 |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10]
    008712FA |. 68 B0C18C00 PUSH ~df394b.008CC1B0 ; ASCII "stxt371"
    008712FF |. 50 PUSH EAX
    00871300 |. E8 46000000 CALL ~df394b.0087134B
    00871305 |. 8BF0 MOV ESI,EAX
    00871307 |. 8D45 F0 LEA EAX,DWORD PTR SS:[EBP-10]
    0087130A |. 50 PUSH EAX
    0087130B |. E8 BD460100 CALL ~df394b.008859CD
    00871310 |. 83C4 0C ADD ESP,0C
    00871313 |> FF75 F0 PUSH DWORD PTR SS:[EBP-10] ; /hObject = 00007B8E
    00871316 |. FF15 EC108C00 CALL DWORD PTR DS:[<&KERNEL32.CloseHandl>; CloseHandle
    0087131C |> 66:8BC6 MOV AX,SI
    0087131F |. 5E POP ESI ; ~df394b.00879A98
    00871320 |. C9 LEAVE
    00871321 . C3 RETN

    Inside we can see that it finds executable that loaded this dll (which is in this case LOADDLL.EXE from Olly) and then it reads some information from it, etc... But that is not important for us. I checked from how many locations this procedure is called. Olly says:

    EBP=0006F464
    Local calls from 008796CF, 00879789, 00879865, 00879A93

    This procedure can be called 4 times. So we have 4 anti-debug tricks. Let's check those locations.



    [1] First reference to that procedure is from 008796CF:

    008796B4 |. 64:A1 18000000 MOV EAX,DWORD PTR FS:[18]
    008796BA |. 8B48 20 MOV ECX,DWORD PTR DS:[EAX+20]
    008796BD |. 85C9 TEST ECX,ECX
    008796BF |. 75 05 JNZ SHORT ~df394b.008796C6
    008796C1 |. 33C0 XOR EAX,EAX
    008796C3 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
    008796C6 |> 61 POPAD
    008796C7 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; ~df394b.008713E9
    008796CA |. 66:85C0 TEST AX,AX
    008796CD |. 74 10 JE SHORT ~df394b.008796DF
    008796CF |. E8 A67BFFFF CALL ~df394b.0087127A
    008796D4 |. 66:F7D8 NEG AX
    008796D7 |. 1BC0 SBB EAX,EAX
    008796D9 |. 40 INC EAX
    008796DA |. 66:85C0 TEST AX,AX
    008796DD |. 75 10 JNZ SHORT ~df394b.008796EF
    008796DF |> 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]
    008796E2 |. 8121 E16AFEFE AND DWORD PTR DS:[ECX],FEFE6AE1
    008796E8 |. 5F POP EDI ; 0006F46C
    008796E9 |. 5E POP ESI ; 0006F46C
    008796EA |. 5B POP EBX ; 0006F46C
    008796EB |. 8BE5 MOV ESP,EBP
    008796ED |. 5D POP EBP ; 0006F46C
    008796EE |. C3 RETN
    008796EF |> 8B4D 08 MOV ECX,DWORD PTR SS:[EBP+8]
    008796F2 |. 5F POP EDI ; 0006F46C
    008796F3 |. 5E POP ESI ; 0006F46C
    008796F4 |. 5B POP EBX ; 0006F46C
    008796F5 |. 8121 005CE46A AND DWORD PTR DS:[ECX],6AE45C00
    008796FB |. 8BE5 MOV ESP,EBP
    008796FD |. 5D POP EBP ; 0006F46C
    008796FE . C3 RETN

    We can see that it is a custom IsDebuggerPresent check.



    [2] Second reference is at 00879789 and it is the same thing - a custom IsDebuggerPresent check.



    [3] Third reference at 00879865 is ZwQueryInformationProcess check:

    0087983E |. 6A 00 PUSH 0
    00879840 |. 8D4C24 10 LEA ECX,DWORD PTR SS:[ESP+10]
    00879844 |. 6A 04 PUSH 4
    00879846 |. 51 PUSH ECX
    00879847 |. 6A 07 PUSH 7 <----------------------------- Parameter for checking debugger presence!
    00879849 |. FF15 B4108C00 CALL DWORD PTR DS:[<&KERNEL32.GetCurrentProcess>]
    0087984F |. 50 PUSH EAX
    00879850 |. FFD7 CALL EDI <--------------------------- ZwQueryInformationProcess call!
    00879852 |. 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
    00879856 |. 85C0 TEST EAX,EAX
    00879858 |. 75 02 JNZ SHORT ~df394b.0087985C
    0087985A |. 33F6 XOR ESI,ESI
    0087985C |> 8BC6 MOV EAX,ESI
    0087985E |. 5F POP EDI
    0087985F |. 66:85F6 TEST SI,SI
    00879862 |. 5E POP ESI
    00879863 |. 74 10 JE SHORT ~df394b.00879875
    00879865 |. E8 107AFFFF CALL ~df394b.0087127A
    0087986A |. 66:F7D8 NEG AX
    0087986D |. 1BC0 SBB EAX,EAX
    0087986F |. 40 INC EAX
    00879870 |. 66:85C0 TEST AX,AX
    00879873 |. 75 12 JNZ SHORT ~df394b.00879887
    00879875 |> 8B0B MOV ECX,DWORD PTR DS:[EBX]
    00879877 |. 81E1 E3EEAB96 AND ECX,96ABEEE3
    0087987D |. 890B MOV DWORD PTR DS:[EBX],ECX
    0087987F |. 5B POP EBX
    00879880 |. 81C4 98000000 ADD ESP,98
    00879886 |. C3 RETN
    00879887 |> 8B8C24 A000000>MOV ECX,DWORD PTR SS:[ESP+A0]
    0087988E |. 5B POP EBX
    0087988F |. 8121 524C6AA7 AND DWORD PTR DS:[ECX],A76A4C52
    00879895 |. 81C4 98000000 ADD ESP,98
    0087989B . C3 RETN


    [4] And a final reference is our IsDebuggerPresent check at 00879A93, already explained.



    So we have only IsDebuggerPresent and ZwQueryInformationProcess. Now , weird is that I used OllyAdvanced plugin to hide from these checks , but sometimes photoshop would run within olly and sometimes don't. I don't know why. But there is no need for any plugins. I realized that we can just patch (fill with NOPs) whole "BadBoy" procedure and neither one debugger check will affect our debugging session

    Oh , I forgot: be carefull where to place breakpoints. SC checks some APIs:

    12F794E3 |. 803C03 CC |CMP BYTE PTR DS:[EBX+EAX],0CC






    3. Reaching OEP

    Finding OEP is not hard after this. If you check Entry Point of protected file (adobelm.dll in my case), you will see obvious OEP jump:

    1005A05E > 55 PUSH EBP <-------------------------------- Entry Point of protected dll.
    1005A05F 8BEC MOV EBP,ESP
    1005A061 60 PUSHAD
    1005A062 BB 5EA00510 MOV EBX,OFFSET AdobeLM.<ModuleEntryPoint>
    1005A067 33C9 XOR ECX,ECX
    1005A069 8A0D 3DA00510 MOV CL,BYTE PTR DS:[1005A03D]
    ...
    cut
    ...
    1005A10B 58 POP EAX
    1005A10C FF35 13A10510 PUSH DWORD PTR DS:[1005A113]
    1005A112 C3 RETN
    1005A113 72 16 JB SHORT AdobeLM.1005A12B
    1005A115 61 POPAD
    1005A116 1360 0D ADC ESP,DWORD PTR DS:[EAX+D]
    1005A119 -E9 A6CEFCFF JMP AdobeLM.10026FC4 <-------------------- Jump to first section, OEP jump.
    1005A11E CC INT3
    1005A11F CC INT3

    That jump is always there, we just needed to decrypt code.






    4. Import protection

    This is the hardest part. Most of imports are redirected to procedure that will find correct import. Let's see how imports look in unpacked dll.

    First we have import call:

    10026EF8 |. FF15 C0610310 CALL DWORD PTR DS:[100361C0]

    That call points to allocated memory block:

    00BBB117 68 8C11EABF PUSH BFEA118C
    00BBB11C 9C PUSHFD
    00BBB11D 60 PUSHAD
    00BBB11E 54 PUSH ESP
    00BBB11F 68 57B1BB00 PUSH 0BBB157
    00BBB124 E8 6C32D0FF CALL ~df394b.008BE395
    00BBB129 83C4 08 ADD ESP,8
    00BBB12C 6A 00 PUSH 0
    00BBB12E 58 POP EAX ; AdobeLM.10026EFE
    00BBB12F 61 POPAD
    00BBB130 9D POPFD
    00BBB131 C3 RETN
    00BBB132 0000 ADD BYTE PTR DS:[EAX],AL

    Call in this block leads to procedure in one of temporary dlls and that procedure finds correct import and jumps to it with RETN:

    008BE504 61 POPAD
    008BE505 9D POPFD
    008BE506 C3 RETN

    I acctually tought that this will be the easiest part in SafeCast unpacking. But I was wrong.



    - My failure

    My first attempt (and second , and third , and ... untill I gone totaly mad), was to write simple script for finding right imports. And that is very easy since IAT is filled with pointers and imports:

    ...
    ...
    thunk GDI32.DLL
    ...
    10036034 00BC4A80
    10036038 77F15E10 GDI32.CreateCompatibleDC
    1003603C 00BC5406
    10036040 00BC58C9
    10036044 00BC5D8C
    10036048 00BC624F
    1003604C 00BC6712
    10036050 00BC6BD5
    10036054 00BC7098
    10036058 00BC755B
    1003605C 00000000
    10036060 00BA0E0F
    ...
    thunk KERNEL32.DLL
    ...
    10036208 7C812BE6 kernel32.GetCPInfo
    1003620C 00BC0B90
    10036210 00BC1053
    10036214 00000000
    10036218 00BD04BF
    ...
    thunk USER32.DLL
    ...
    100362C0 00BDCCBD
    100362C4 77D8050B USER32.MessageBoxA
    100362C8 00000000
    100362CC 00000000

    So idea for script was to trace those pointers and obtain imports. That worked and I retrieved all imports. All three thunks was filled with imports. But! Imports was messed. It means that GetCommandLine would be placed on wrong thunk, and many more. I don't know the reason why. I have ome ideas but I'm not sure. After that, I traced trought temporary files, decrypting , removing junk obfuscation, all that in order to se can I find where SC fills imports into IAT. I found it with hardware breakpoints, but I just couldn't find some "magic jump". After some time I noticed that I get good imports if I trace calls and jumps, not the IAT itself.



    - Heureka !

    Ok. I can retrieve whole IAT, but imports are mixed in thunks. But, I can save that IAT, then use tracing calls to find good mports, than just redirect those references to new IAT. First I found IAT:

    12EF6000 77DFD5BB ADVAPI32.RegCreateKeyA
    ...
    12EF6018 77DD77B3 ADVAPI32.SetSecurityDescriptorDacl
    12EF601C 00000000
    12EF6020 5D093439 comctl_1.InitCommonControlsEx
    12EF6024 00000000
    12EF6028 77F16A3B GDI32.DeleteObject
    ...
    12EF6058 77F159A0 GDI32.SelectObject
    12EF605C 00000000
    12EF6060 7C80EFD7 kernel32.FindClose
    12EF6064 7C80180E kernel32.ReadFile
    ...
    12EF6210 7C801E16 kernel32.TerminateProcess
    12EF6214 00000000
    12EF6218 77D4DB62 USER32.PostMessageA
    12EF621C 77D4E2AE USER32.SendMessageA
    ...
    12EF62C0 77D4C6BC USER32.RedrawWindow
    12EF62C4 77D8050B USER32.MessageBoxA

    I saved binary in text file. Then I restarted AdobeLM.dll (within main photoshop exe), found OEP of DLL, and I placed IAT in one SC section (Section=stxt774). Then I started to write scripts for redirecting references. We have these possibilities:

    JMP DWORD [IMPORT/POINTER]
    CALL DWORD [IMPORT/POINTER]
    MOV REG, DWORD [IMPORT/POINTER] (reg=eax,ebx,ecx,edx,esi,edi,ebp)


    Here is nasty trick (?!?) that also confused me:

    12EC26D8 FF15 20600310 CALL DWORD PTR DS:[10036020]

    If I load DLL in Olly, this call will point to walue in IAT (because image base of dll is 10000000). BUT, that is false call - a junk. If I load DLL within photoshop, it doesn't point to IAT (because it is loaded on different addres due lack of space in memory caused by lot of other dlls loaded)! In first case, it affects my scripts! In second, it is only junk.

    Fixing JMP/CALL references was easy, but registers references I fixed manually (huh, I took me long to do that). Ok, after imports are fixed, I checked them one more time to be sure that I didn't missed something.





    5. More imports

    I runned DLL trough Olly and it crushed with message "LOADDLL.EXE: Unable to load dll". In case that DLL is OK, I should get message in olly status bar "Initialization of dll finished". So I traced again to see where it crushes and I found this jump:

    12EEAF9B .-E9 70C90200 JMP dump.12F17910
    12EEAFA0 85 DB 85
    12EEAFA1 . 834E 04 FF OR DWORD PTR DS:[ESI+4],FFFFFFFF
    12EEAFA5 . 6A 01 PUSH 1
    12EEAFA7 . 8906 MOV DWORD PTR DS:[ESI],EAX
    12EEAFA9 . 58 POP EAX
    12EEAFAA . 5E POP ESI
    12EEAFAB . C3 RETN

    Ah, crap >:( This jump points to section where I placed new IAT. Let's see what is it in original DLL:

    12F17910 ? 53 PUSH EBX ; AdobeLM.12EC0000
    12F17911 ? E8 B9100000 CALL AdobeLM.12F189CF

    Then:

    12F189CF /$ 870424 XCHG DWORD PTR SS:[ESP],EAX
    12F189D2 |. 9C PUSHFD
    12F189D3 |. 05 15040000 ADD EAX,415
    12F189D8 |. 8B18 MOV EBX,DWORD PTR DS:[EAX]
    12F189DA |. 6BDB 21 IMUL EBX,EBX,21 ; AdobeLM.12EC0000
    12F189DD |. 0358 04 ADD EBX,DWORD PTR DS:[EAX+4]
    12F189E0 |. 9D POPFD
    12F189E1 |. 58 POP EAX ; 13298DDA
    12F189E2 |. 871C24 XCHG DWORD PTR SS:[ESP],EBX ; AdobeLM.12EC0000
    12F189E5 . C3 RETN

    Then:

    13298DDA 68 A1AFEE12 PUSH 12EEAFA1
    13298DDF 68 BD13EABF PUSH BFEA13BD
    13298DE4 9C PUSHFD
    13298DE5 60 PUSHAD
    13298DE6 54 PUSH ESP
    13298DE7 68 1A8E2913 PUSH 13298E1A
    13298DEC E8 A455CDFF CALL ~df394b.12F6E395
    13298DF1 83C4 08 ADD ESP,8
    13298DF4 6A 00 PUSH 0
    13298DF6 58 POP EAX
    13298DF7 61 POPAD
    13298DF8 9D POPFD
    13298DF9 C3 RETN

    This RETN jumps to same import algo that ends with:

    12F6E74A 8B65 0C MOV ESP,DWORD PTR SS:[EBP+C]
    12F6E74D 61 POPAD
    12F6E74E 9D POPFD
    12F6E74F C3 RETN

    Return to 7C809737 (kernel32.GetCurrentThreadId)

    And after import is executed, it returns to code below jump and one junky byte. So this is another replace for import call of type CALL DWORD[IMPORT]!?! It seams that it is. But code is little different after every jump. Different or not, I wrote easy script for finding all imports. Now, this was all pretty messy because I didn't expect this, so I won't describe how I fixed these imports. It's up to your skills - or do it manually, or write scripts, or code some plugin.





    6. Emulated opcodes

    Just when I tought that DLL is finaly unpacked - I stumbled on new problem. I tried to run DLL in Olly, but it stoped on exception. I located problem:

    12EC34E3 $ B8 7BEFFFFF MOV EAX,-1085
    12EC34E8 . 59 POP ECX ; dump.12EC41D0
    12EC34E9 . 8D0408 LEA EAX,DWORD PTR DS:[EAX+ECX]
    12EC34EC . 8B00 MOV EAX,DWORD PTR DS:[EAX]
    12EC34EE .-FFE0 JMP EAX <------------------------------ It jumps to nowhere.

    In original file, that jump jumps to temporary DLL:

    12F31507 . 58 59 68 00 ASCII "XYh",0
    12F3150B 00 DB 00
    12F3150C 40 DB 40 ; CHAR '@'
    12F3150D 00 DB 00
    12F3150E . 9C PUSHFD
    12F3150F . 60 PUSHAD
    12F31510 . 54 PUSH ESP
    12F31511 . E8 D2FFFFFF CALL ~df394b.12F314E8
    12F31516 . 5C POP ESP
    12F31517 . 61 POPAD
    12F31518 . 9D POPFD
    12F31519 . C3 RETN

    12F314F4 |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX ; ~df394b.12F727F4
    12F314F7 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; ~df394b.12F8CD68
    12F314FA |. 8B00 MOV EAX,DWORD PTR DS:[EAX] ; ~df394b.12F31277
    12F314FC |. 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4] ; ~df394b.12F8CD68
    12F314FF |. FF50 08 CALL DWORD PTR DS:[EAX+8] ; ~df394b.?PerformFixup@CJumpRun@@UAEKK@Z
    12F31502 |. 8945 08 MOV DWORD PTR SS:[EBP+8],EAX ; ~df394b.12F727F4
    12F31505 |. C9 LEAVE
    12F31506 . C3 RETN

    It countinues inside that DLL and enters in function which has interesting name: PerformFixup@CJumpRun@@UAEKK@Z. After that it returns to some location in main DLL.

    That JMP EAX is accessed trugh this small procedure inside of main DLL:

    12EC41C9 /$ 51 PUSH ECX
    12EC41CA |. 50 PUSH EAX
    12EC41CB |. E8 13F3FFFF CALL dump.12EC34E3
    12EC41D0 |$ 8B4424 04 MOV EAX,DWORD PTR SS:[ESP+4] ; dump.12EC0000
    12EC41D4 |. 56 PUSH ESI
    12EC41D5 |. 8BF1 MOV ESI,ECX
    12EC41D7 |. 8B08 MOV ECX,DWORD PTR DS:[EAX]
    12EC41D9 |. 890E MOV DWORD PTR DS:[ESI],ECX
    12EC41DB |. E8 30F6FFFF CALL dump.12EC3810
    12EC41E0 |. 8BC6 MOV EAX,ESI
    12EC41E2 |. 5E POP ESI ; ntdll.7C9011A7
    12EC41E3 . C2 0400 RETN 4

    And that procedure is called from these places:

    References in AdobeLM:.text to 12EC41C9
    Address Disassembly Comment
    12EC109B CALL AdobeLM.12EC41C9
    12EC1EE1 CALL AdobeLM.12EC41C9
    12EC2463 CALL AdobeLM.12EC41C9
    ...
    lot of calls
    ...
    12ED439B CALL AdobeLM.12EC41C9
    12ED441B CALL AdobeLM.12EC41C9

    I executed couple these calls and it semas that this code just emulates some calls, maybe jumps too (judging on stack). No registeres are changed uppon return. But, I was reading tutorial from mr. anonymous. He noticed that these calls emulate stolen opcodes. Also, to speed up execution of protected program (I guess) these opcodes are written to the place of call. I followed that PerformFixup@CJumpRun@@UAEKK@Z function in temp dll:

    12F3141C >/$ 55 PUSH EBP
    12F3141D |. 8BEC MOV EBP,ESP
    12F3141F |. 81EC D0020000 SUB ESP,2D0
    12F31425 |. 53 PUSH EBX ; AdobeLM.<ModuleEntryPoint>
    12F31426 |. 8BD9 MOV EBX,ECX
    12F31428 |. 56 PUSH ESI
    12F31429 |. 57 PUSH EDI
    12F3142A |. 8D43 20 LEA EAX,DWORD PTR DS:[EBX+20]
    12F3142D |. 50 PUSH EAX ; /pCriticalSection = 0012E68C
    12F3142E |. 8945 FC MOV DWORD PTR SS:[EBP-4],EAX ; |
    12F31431 |. FF15 7010F712 CALL DWORD PTR DS:[<&KERNEL32.EnterCriti>; EnterCriticalSection
    12F31437 |. 8D85 30FDFFFF LEA EAX,DWORD PTR SS:[EBP-2D0]
    12F3143D |. 8BCB MOV ECX,EBX ; AdobeLM.<ModuleEntryPoint>
    12F3143F |. 50 PUSH EAX
    12F31440 |. FF75 08 PUSH DWORD PTR SS:[EBP+8] ; AdobeLM.<ModuleEntryPoint>
    12F31443 |. E8 E5FEFFFF CALL ~df394b.12F3132D
    12F31448 |. 8B85 E8FDFFFF MOV EAX,DWORD PTR SS:[EBP-218]
    12F3144E |. B9 30CDF812 MOV ECX,~df394b.12F8CD30
    12F31453 |. 8BF8 MOV EDI,EAX
    12F31455 |. 2B43 04 SUB EAX,DWORD PTR DS:[EBX+4]
    12F31458 |. 50 PUSH EAX ; /Arg1 = 0012E68C
    12F31459 |. E8 5CEC0300 CALL ~df394b.12F700BA ; ~df394b.12F700BA
    12F3145E |. 50 PUSH EAX
    12F3145F |. E8 F1010000 CALL ~df394b.12F31655
    12F31464 |. 8BC8 MOV ECX,EAX
    12F31466 |. E8 FC010000 CALL ~df394b.12F31667
    12F3146B |. 8BF0 MOV ESI,EAX
    12F3146D |. 85F6 TEST ESI,ESI
    12F3146F |. 74 3F JE SHORT ~df394b.12F314B0
    12F31471 |. 66:837B 08 01 CMP WORD PTR DS:[EBX+8],1
    12F31476 |. 75 3D JNZ SHORT ~df394b.12F314B5
    12F31478 |. 8D85 30FDFFFF LEA EAX,DWORD PTR SS:[EBP-2D0]
    12F3147E |. 8BCE MOV ECX,ESI
    12F31480 |. 50 PUSH EAX
    12F31481 |. E8 15560100 CALL ~df394b.12F46A9B
    12F31486 |. 8BCB MOV ECX,EBX ; AdobeLM.<ModuleEntryPoint>
    12F31488 |. E8 8AFEFFFF CALL ~df394b.12F31317
    12F3148D |. 83F8 04 CMP EAX,4 <------------------------- Compares number of CALL exceutions.
    12F31490 |. 72 14 JB SHORT ~df394b.12F314A6
    12F31492 |. 8BCE MOV ECX,ESI
    12F31494 |. E8 E8540100 CALL ~df394b.12F46981
    12F31499 |. 83F8 04 CMP EAX,4
    12F3149C |. 72 08 JB SHORT ~df394b.12F314A6
    12F3149E |. 57 PUSH EDI ; /Arg1 = 00000001
    12F3149F |. 8BCE MOV ECX,ESI ; |
    12F314A1 |. E8 2C550100 CALL ~df394b.12F469D2 ; ~df394b.12F469D2
    12F314A6 |> 56 PUSH ESI
    12F314A7 |. 8BCB MOV ECX,EBX ; AdobeLM.<ModuleEntryPoint>
    12F314A9 |. E8 33FEFFFF CALL ~df394b.12F312E1
    12F314AE |. EB 05 JMP SHORT ~df394b.12F314B5
    12F314B0 |> 66:8363 08 00 AND WORD PTR DS:[EBX+8],0
    12F314B5 |> 81EC CC020000 SUB ESP,2CC
    12F314BB |. B9 B3000000 MOV ECX,0B3
    12F314C0 |. 8DB5 30FDFFFF LEA ESI,DWORD PTR SS:[EBP-2D0]
    12F314C6 |. 8BFC MOV EDI,ESP
    12F314C8 |. F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
    12F314CA |. 8D45 08 LEA EAX,DWORD PTR SS:[EBP+8]
    12F314CD |. 8BCB MOV ECX,EBX ; AdobeLM.<ModuleEntryPoint>
    12F314CF |. 50 PUSH EAX
    12F314D0 |. E8 DBFEFFFF CALL ~df394b.12F313B0
    12F314D5 |. FF75 FC PUSH DWORD PTR SS:[EBP-4] ; /pCriticalSection = 002456B8
    12F314D8 |. FF15 6C10F712 CALL DWORD PTR DS:[<&KERNEL32.LeaveCriti>; LeaveCriticalSection
    12F314DE |. 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8] ; AdobeLM.<ModuleEntryPoint>
    12F314E1 |. 5F POP EDI ; ntdll.7C9011A7
    12F314E2 |. 5E POP ESI ; ntdll.7C9011A7
    12F314E3 |. 5B POP EBX ; ntdll.7C9011A7
    12F314E4 |. C9 LEAVE
    12F314E5 . C2 0400 RETN 4

    CMP EAX,4 compares number of execution of one CALL. So after call is used 3 times, 4-th time it will write original opcode instead of CALL. I patched both jumps and then used script to execute all those calls. That restored original opcodes:

    References in AdobeLM:.text to 12EC41C9
    Address Disassembly Comment
    12EC109B JE F34910A1
    12EC1EE1 CALL AdobeLM.12EE558E
    12EC2463 CALL AdobeLM.12EE5B40
    12EC2F0B JNZ AdobeLM.12EC343F
    12EC41C9 PUSH ECX (Initial CPU selection)
    12EC41EB JMP AdobeLM.12EC41C9
    12EC476B JE 12EB0571
    12EC486E CALL AdobeLM.12EE5B40
    12EC4AFA CALL AdobeLM.12EE6624
    12EC4ED2 CALL AdobeLM.12EC22A0
    12EC4FBB JNZ AdobeLM.12EC4E02
    12EC5022 CALL AdobeLM.12EE5B40
    12EC5301 CALL AdobeLM.12EE6624
    12EC5643 CALL AdobeLM.12EC22A0
    12EC57AB CALL AdobeLM.12ECFE40
    12EC5BA6 CALL AdobeLM.12EC22A0
    12EC5C61 CALL AdobeLM.12EC22A0
    12EC6476 CALL AdobeLM.12ECDE40
    12EC64E0 JMP AdobeLM.12EC6694
    12EC6527 JMP AdobeLM.12EC6694
    12EC657E JMP AdobeLM.12EC6694
    12EC65C5 JMP AdobeLM.12EC6694
    12EC6663 CALL AdobeLM.12ECDE40
    12EC66AB JE AdobeLM.12EC6E63
    12EC6776 CALL AdobeLM.12EC22A0
    12EC67D6 CALL AdobeLM.12EC22A0
    12EC6892 CALL AdobeLM.12EC22A0
    12EC68E3 CALL AdobeLM.12EC22A0
    12EC6978 CALL AdobeLM.12EC22A0
    12EC69C7 CALL AdobeLM.12EC22A0
    12EC6A6D CALL AdobeLM.12EC22A0
    12EC6AA8 JE AdobeLM.12EC7126
    12EC6C60 CALL AdobeLM.12EC4770
    12EC6E80 JE AdobeLM.12EC6F4B
    12EC6F67 CALL AdobeLM.12ED14A0
    12EC7394 CALL AdobeLM.12EC22A0
    12EC7459 CALL AdobeLM.12EC22A0
    12EC7D60 JE AdobeLM.12EC81DE
    12EC7F04 CALL AdobeLM.12ECDE40
    12EC8007 CALL AdobeLM.12ECDE40
    12EC80DA CALL AdobeLM.12ED0DA0
    12EC83F7 CALL AdobeLM.12EC22A0
    12EC88FF CALL AdobeLM.12EC4CD0
    12EC8983 JMP AdobeLM.12EC8AF5
    12EC89AE CALL AdobeLM.12ECDE40
    12EC8AC4 CALL AdobeLM.12ECDE40
    12EC8BE7 CALL AdobeLM.12EC22A0
    12EC90F0 CALL AdobeLM.12EC5440
    12EC9175 JMP AdobeLM.12EC92E7
    12EC91A0 CALL AdobeLM.12ECDE40
    12EC92B6 CALL AdobeLM.12ECDE40
    12EC941C CALL AdobeLM.12EC22A0
    12EC96C0 CALL AdobeLM.12EC22A0
    12ECA12B CALL AdobeLM.12EC22A0
    12ECA18C CALL AdobeLM.12EE6A30
    12ECA77C CALL AdobeLM.12EC22A0
    12ECA86F CALL AdobeLM.12EC22A0
    12ECAB07 CALL AdobeLM.12ECDE40
    12ECB23C CALL AdobeLM.12ECDE40
    12ECB3A2 CALL AdobeLM.12EC22A0
    12ECB3EB CALL AdobeLM.12EC22A0
    12ECB571 CALL AdobeLM.12EC22A0
    12ECBE10 CALL AdobeLM.12ECDE40
    12ECBE5D JE AdobeLM.12ECC013
    12ECBE6C JE AdobeLM.12ECBFF3
    12ECBE79 JE AdobeLM.12ECBFF3
    12ECBE87 JE AdobeLM.12ECBFF3
    12ECBFE0 CALL AdobeLM.12ECFEF0
    12ECC30B CALL AdobeLM.12ECDE40
    12ECC423 CALL AdobeLM.12EC22A0
    12ECC47D CALL AdobeLM.12EC22A0
    12ECFE3B JNZ 12EAFE41
    12ECFEEB JNZ AdobeLM.12EDFE34
    12ED3C3B JE AdobeLM.12EE6F41
    12ED439B JE AdobeLM.12F058A1
    12ED441B JNZ 12E66A21

    If some opcode is not good, I can just undo it. Some opcodes (as first on this list) can be wrong because byte combination that make script think that they are CALL..







    7. Testing

    All protection of SafeCast is defeated now. But since I deal with protected DLL, relocations should be also fixed in case that DLL will be loaded on different locations (what will happen for sure in this program). That can be done with ImpREC brother tool - ReloX. I didn't fix them because I would had to do all this unpacking again on different base addres. But there are work arounds for that. For example, we pack main executabe (photoshop.exe) with some simple packer and then we inject code that will load our DLL first.

    I decided to test my unpacked DLL. Photoshop started with some error, diferent than one for debugger/file_change detection. And after clicking OK, photoshop continued. Problem could be that my dump is "dirty". So second time I created new dump, but this time I didn't deleted two SC sections. I added 2000 Kb to the end of file and expanded last section. SC doesn't check for file size and section sizes! Good. After fixing this new dump (in which I have more faith), I got again error message and this time Photoshop wouldn't start ?!? Ok, dump should be good , so I traced to see usage of AdobeLM.dll.

    Photoshop first loads DLL:

    00F4723B |. 50 PUSH EAX ; /FileName = "C:...AdobeLM.dll"
    00F4723C |. F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ; |
    00F4723E |. FF15 74D51501 CALL DWORD PTR DS:[<&KERNEL32.LoadLibraryA>] ; LoadLibraryA

    Then it calls these functions in DLL:

    00F4728A |. FFD0 CALL EAX ; AdobeLM.CreateCAdobeLM_Object

    00F472BF |. FF52 04 CALL DWORD PTR DS:[EDX+4] ; AdobeLM.InitOfAdobeLM

    And while in this one, it shows error message:

    00F46F47 |. FF50 08 CALL DWORD PTR DS:[EAX+8] ; AdobeLM.CheckSigOfAdobeLM

    This one returns to EAX=FFFFFFF6. But if EAX=0, it loads second DLL protected with SC:

    00F39D8C |> FF75 C8 PUSH DWORD PTR SS:[EBP-38] ; /FileName = "Tw10122.dat"
    00F39D8F |. FF15 74D51501 CALL DWORD PTR DS:[<&KERNEL32.LoadLibraryA>] ; LoadLibraryA

    So, if we patch AdobelLM.dll a little, it will tought that program is in registered state and it will go load next protected dll.






    8. Summary

    Anti-debug tricks described in this tutorial (IsDebuggerPresent & ZwQueryInformationProcess) are same in all versions of SafeCast/Disc up to 3.20.024 version of protection (Medal of Honor Pacific Assault checked). Also, OEP jump is same on all those versions so script for finding OEP "01.SafeCast2-3_OEP.txt" should work on all targets in that range, even on protected CDs (if you have original CD).

    In the archive you will find some scripts that I used while unpacking. They are just here if you are curious to see what they do.

    01.SafeCast2-3_OEP.txt - for finding OEP.
    02.Decrypt_IAT.txt - to decrypt IAT.
    03.Decrypt_CALL-IAT.txt - to decrypt CALL/JMP import references.
    04.Decrypt_Jumps.txt - to decrypt jumps that again lead to imports.
    05.Decrypt_REG_IAT.txt - just for help to redirect registers references to iat.
    06.EmulatedCode.txt - for decrpting emulated opcodes.
    07.Dejunk.txt - for removing junk from temporary DLLs.

Thread Information

Users Browsing this Thread

هم اکنون 1 کاربر در حال مشاهده این تاپیک میباشد. (0 کاربر عضو شده و 1 مهمان)

User Tag List

قوانين ايجاد تاپيک در انجمن

  • شما نمی توانید تاپیک ایحاد کنید
  • شما نمی توانید پاسخی ارسال کنید
  • شما نمی توانید فایل پیوست کنید
  • شما نمی توانید پاسخ خود را ویرایش کنید
  •