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

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




صفحه 8 از 17 اولاول ... 456789101112 ... آخرآخر
نمايش نتايج 71 به 80 از 163

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

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

    پيش فرض

    Level : newbie
    Cracking and finding the name to serial algorithm in Chainie1 Crackme



    This is my first crackme tutorial: I wrote it to try and help other real newbie’s like me to better understand the simple basics of cracking. Although this is supposed to be a very simple crackme I found it quite hard to understand what was really going on and very nearly fell into a little trap of thinking I had found the name to serial algorithm too soon.






    Tools: PeID, OllyDbg 1.10 and a pencil and paper

    Target:
    کد:
    برای مشاهده محتوا ، لطفا وارد شوید یا ثبت نام کنید
    Well where do we begin? First I check the Chainie.exe with PeID. We see that this crackme is not packed and was created with Borland Delphi 6.0 – 7.0 so hopefully we won’t have any nasty surprises like anti-debug or other tricks.



    Ok let’s have a look at our target; double click Chainie.exe and a dialog box asking for a name and a serial will appear.



    Enter name LucyE and enter serial 47806 and press Check.

    Bam a message box appears saying, ‘Your name is too short’

    Press OK and close Chainie.exe. Then right click on Chainie.exe and open with Olly.



    In Olly right click and select Search for all referenced text strings. You will see this:




    Text strings referenced in Chainie: CODE



    Address Disassembly Text string




    ………………………………………....S nip……………………………………… …



    0045012F ASCII "Unit1"

    004501F5 PUSH Chainie.0045027C ASCII "Correct"

    004501FA PUSH Chainie.00450284 ASCII "Good job you did it!!!"

    00450213 PUSH Chainie.0045029C ASCII "WRONG!!!"

    00450218 PUSH Chainie.004502A8 ASCII "Incorrect Serial try again...." (2)

    0045022F PUSH 10 (Initial CPU selection)

    00450231 PUSH Chainie.004502C8 ASCII "Oops...”

    00450236 PUSH Chainie.004502D0 ASCII "Your name is too short" (1)




    ………………………………………....S nip……………………………………… …



    I didn’t want to guess how long may name should be so I decided to double click on (1) and see if I could fix this problem first and then come back and double click on (2) to see what I could see and learn from that.



    After double clicking we land here at place marked (1)



    0045022F > 6A 10 PUSH 10 ß---------------------------- ; Entry point to MessageBox function

    00450231 . 68 C8024500 PUSH Chainie.004502C8 ; ASCII "Oops.."

    (1) 00450236 68 D0024500 PUSH Chainie.004502D0 ; ASCII "Your name is too short" 0045023B . A1 D43B4500 MOV EAX, DWORD PTR DS:[453BD4]

    00450240 . E8 EF58FEFF CALL Chainie.00435B34

    00450245 . 50 PUSH EAX ; |hOwner = NULL

    00450246 . E8 5562FBFF CALL ; MessageBoxA

    0045024B > 33C0 XOR EAX, EAX





    To find out where the check that called this function right click on the entry point at 0045022F and select ‘Go to JLE from 0045017C’ and we land here:




    00450179 83F8 05 CMP EAX, 5 ; is name length less than 6 letters?

    0045017C 0F8E AD000000 JLE Chainie.0045022F If yes then Jump to Bad Name




    There are probably many ways to fix this name check like NOP the JLE, but I like the idea of entering a name so I will patch this by changing the 5 to 1. This means that your name must have more than 2 letters to be valid. We do this by clicking on the location 00450179 pressing the Space bar, change the 5 to 1, then choose assemble followed by cancel. The code will now look like this:




    00450179 83F8 01 CMP EAX, 1

    0045017C 0F8E AD000000 JLE Chainie.0045022F




    Now the name length check has been patched our next job is to find the correct serial for our name.




    Looking at the code snippet below we see that at 004501F1 there is a check which if we fail we go to the “Good job you did it!!!” message. This tells me that there is a check for a valid serial in the Call on the line above that returns with a non-zero value if our serial is valid. Therefore, put a breakpoint (press F2) on the Call at 004501EC and Press F9 to run the crackme. Enter LucyE for the name and 47806 as the serial then Check to find out if the serial we entered is legitimate.




    004501EC . E8 2B40FBFF CALL Chainie.0040421C ß----------we break here

    004501F1 . 75 1E JNZ SHORT Chainie.00450211




    004501F3 . 6A 30 PUSH 30

    004501F5 . 68 7C024500 PUSH Chainie.0045027C ; ASCII "Correct"

    004501FA . 68 84024500 PUSH Chainie.00450284 ; ASCII "Good job you did it!!!"

    004501FF . A1 D43B4500 MOV EAX, DWORD PTR DS:[453BD4]

    00450204 . E8 2B59FEFF CALL Chainie.00435B34

    00450209 . 50 PUSH EAX ; |hOwner = 00E924E8

    0045020A . E8 9162FBFF CALL ; MessageBoxA

    0045020F . EB 3A JMP SHORT Chainie.0045024B




    Hey look at the memory dump (stack) what do you see?




    0012F604 00E924E8 ASCII "48706" ; the serial we entered

    0012F608 0012F968 Pointer to next SEH record

    0012F60C 0045026E SE handler

    0012F610 0012F638

    0012F614 0012F7B4

    0012F618 00428FD0 Chainie.00428FD0

    0012F61C 00E936A8

    0012F620 00E924FC ASCII "3443972" ; maybe a valid serial

    0012F624 00E924E8 ASCII "48706" ; the serial we entered

    0012F628 00E924D4 ASCII "LucyE"

    0012F62C 00E924C0 ASCII "LucyE" ; the name we entered

    0012F630 00E924AC ASCII "LucyE"

    0012F634 00000006




    Let’s be brave and remove our breakpoint then hit F9 to run Chainie.exe.

    After clicking OK at the ‘Incorrect serial try again…’ message enter this number (3443972) as the serial and press check. BINGO! We cracked it!




    Our next job is to find out how this programme calculates the serial for our name.




    Press Alt-E to view the Executable Modules then right click on Chanie.exe and select view names. Scroll down the list a bit and double click on the LoadStringA API then press F2 to set a breakpoint on the line highlighted in Olly at 00450152. Run Chainie.exe and press check; we break in Olly at 00450152.




    00450152 . 55 PUSH EBP ß----------------------- We Break Here

    00450153 . 68 6E024500 PUSH Chainie.0045026E

    00450158 . 64:FF30 PUSH DWORD PTR FS:[EAX]

    0045015B . 64:8920 MOV DWORD PTR FS:[EAX],ESP

    0045015E . BB DBC10800 MOV EBX, 8C1DB

    00450163 . 8D55 F8 LEA EDX, DWORD PTR SS:[EBP-8]

    00450166 . 8B87 08030000 MOV EAX, DWORD PTR DS:[EDI+308]

    0045016C . E8 E7F1FDFF CALL Chainie.0042F358

    00450171 . 8B45 F8 MOV EAX, DWORD PTR SS:[EBP-8] ; name put in location EBP-8

    00450174 . E8 573FFBFF CALL Chainie.004040D0 ; Length of Name = 5

    00450179 83F8 05 CMP EAX, 5




    Trace through the code with F8 but STOP when you reach the Call at 0045C01E3. I have commented the code to try and explain how our name is converted into a hex number.




    00450182 . 8D55 F4 LEA EDX, DWORD PTR SS: [EBP-C]

    00450185 . 8B87 08030000 MOV EAX, DWORD PTR DS: [EDI+308]

    0045018B . E8 C8F1FDFF CALL Chainie.0042F358

    00450190 . 8B45 F4 MOV EAX, DWORD PTR SS:[EBP-C] ; Name (LucyE)

    00450193 . E8 383FFBFF CALL Chainie.004040D0

    00450198 . 8BF0 MOV ESI, EAX ; Length of Name = 5

    0045019A . 85F6 TEST ESI, ESI

    0045019C . 7E 2E JLE SHORT Chainie.004501CC

    0045019E . C745 FC 01000> MOV DWORD PTR SS:[EBP-4],1

    004501A5 > 8D55 F0 LEA EDX,DWORD PTR SS:[EBP-10]

    004501A8 . 8B87 08030000 MOV EAX, DWORD PTR DS:[EDI+308]

    004501AE . E8 A5F1FDFF CALL Chainie.0042F358

    004501B3 . 8B45 F0 MOV EAX, DWORD PTR SS:[EBP-10] ; Name in EAX (LucyE)

    004501B6 . 8B55 FC MOV EDX, DWORD PTR SS:[EBP-4] ; 1 in EDX

    004501B9 . 0FB64410 FF MOVZX EAX, BYTE PTR DS:[EAX+EDX-1] ; letter into EAX

    004501BE . 03D8 ADD EBX, EAX ; Add letter to EBX (init EBX=8C1DB)

    004501C0 . 81C3 DBC10800 ADD EBX, 8C1DB ; Add 8C1DB to EBX

    004501C6 . FF45 FC INC DWORD PTR SS: [EBP-4] ; inc ss: [EBP-4] to get next letter

    004501C9 . 4E DEC ESI ; Decrease name counter by 1

    004501CA . ^ 75 D9 JNZ SHORT Chainie.004501A5 ; Get next letter until none left

    004501CC > 8D55 EC LEA EDX, DWORD PTR SS:[EBP-14]

    004501CF . 8B87 10030000 MOV EAX, DWORD PTR DS:[EDI+310]

    004501D5 . E8 7EF1FDFF CALL Chainie.0042F358

    004501DA . 8B45 EC MOV EAX, DWORD PTR SS:[EBP-14] ; Serial we entered

    004501DD . 50 PUSH EAX ; Notice both serial and name entered are on the stack

    004501DE . 8D55 E8 LEA EDX, DWORD PTR SS:[EBP-18]

    004501E1 . 8BC3 MOV EAX, EBX ; result of manipulating our name in EAX

    004501E3 . E8 6879FBFF CALL Chainie.00407B50 ; STOP HERE




    The name LucyE is converted by the above code as follows:



    L u c y E

    8C1DB+4C+8C1DB+75+8C1DB+63+8C1DB+79+8C1DB+45+8C1DB = 348D04




    Make a note or remember that EAX = 00348D04


    You might think that this is the end of the name to serial algorithm but it’s not! So we will now continue from where we stopped above by pressing F7 to trace into the Call at 004501E3 until we reach here:




    00407B04 /$ 08C9 OR CL, CL if result is not zero

    00407B06 | 75 17 JNZ SHORT Chainie.00407B1F then Jump

    00407B08 | 09C0 OR EAX, EAX if result is not signed

    00407B0A | 79 0E JNS SHORT Chainie.00407B1A then Jump




    …………….If both above checks fail algorithm is completed in this section…………….


    00407B0C | F7D8 NEG EAX makes value in EAX positive

    00407B0E | E8 07000000 CALL Chainie.00407B1A

    00407B13 | B0 2D MOV AL, 2D

    00407B15 | 41 INC ECX

    00407B16 | 4E DEC ESI

    00407B17 | 8806 MOV BYTE PTR DS: [ESI], AL ; adds value in AL to our serial

    00407B19 | C3 RETN




    …………………..…………Second part of algorithm………………………………

    00407B1A |$ B9 0A000000 MOV ECX,0A ; Put the divisor x0A (10) in ECX

    00407B1F |> 52 PUSH EDX

    00407B20 | 56 PUSH ESI

    00407B21 |> 31D2 /XOR EDX,EDX ; Zero EDX

    00407B23 | F7F1 |DIV ECX ; Divide EAX by 0A Result in EAX remainder in EDX

    00407B25 | 4E |DEC ESI ; Make room for next number of correct Serial

    00407B26 | 80C2 30 |ADD DL, 30 ; Add 30 to low byte in EDX

    00407B29 | 80FA 3A |CMP DL, 3A ; if DL is less than 3A

    00407B2C | 72 03 |JB SHORT Chainie.00407B31 ; then Jump

    00407B2E | 80C2 07 |ADD DL, 7

    00407B31 |> 8816 |MOV BYTE PTR DS:[ESI],DL ; the correct serial is built here

    00407B33 | 09C0 |OR EAX, EAX

    00407B35 |^ 75 EA JNZ SHORT Chainie.00407B21 ; Get next number until EAX is zero

    00407B37 | 59 POP ECX ; Chainie.00407B60

    00407B38 | 5A POP EDX ; Chainie.00407B60

    00407B39 | 29F1 SUB ECX, ESI ; the length of the correct serial

    00407B3B | 29CA SUB EDX, ECX ; if EDX is bigger than ECX

    00407B3D | 76 10 JBE SHORT Chainie.00407B4F ; then Jump

    00407B3F | 01D1 ADD ECX, EDX

    00407B41 | B0 30 MOV AL, 30

    00407B43 | 29D6 SUB ESI, EDX ; Length of serial

    00407B45 | EB 03 JMP SHORT Chainie.00407B4A

    00407B47 |> 880432 /MOV BYTE PTR DS:[EDX+ESI],AL

    00407B4A > 4A DEC EDX

    00407B4B |^ 75 FA JNZ SHORT Chainie.00407B47 ; loop until EDX is zero

    00407B4D | 8806 MOV BYTE PTR DS:[ESI],AL ; add AL i.e. 30 to our serial

    00407B4F > C3 RETN




    STOP pressing F7 when you reach RETN at 0407BF4 and note that ESI=3443972




    Do you remember the number calculated from our name in the first part of the algorithm and do you recall where it was stored? Yes EAX = 348D04. Well to calculate the real valid serial this number is divided step by step by 0A at location 00407B23 until EAX is zero.

    At each step the remainder of this integer division, if it is less than 0A (i.e. a single digit), is stored in ESI.


    If the remainder is greater than 0A then 07 is added to DL before it is stored as a single digit in ESI.




    If you recollect the serial for LucyE, was 344392. So in my case the first remainder was 2, the second 9, the third 3 and so on.




    Press F8 seven times and look at the stack, at the bottom right of your screen you will see what we saw earlier, the name we entered, the serial we entered and the correct serial computed from our name. Also note that EDX = 3443972




    So what have we learned?


    1. How to check if a target is packed


    2. How to patch a name length check


    4 How to fish for a valid serial


    5. How to find and understand the code that converts our name into a valid serial


    6. Go slowly and keep our eye on what is happening with the registers and what is showing in the memory dump.

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

    پيش فرض

    Level : beginner

    ----------------------------------------------------------------------------------------
    Thinstall 2.521 - unpacking dependencies and injecting a DLL
    ---------------------------------------------------------------------------------------





    Intro, hmm.... what to say for intruduction? I wrote already one tutorial for Thinstall 2.521. There I explained how to unpack target protected with DebugBlocker feature but Thinstall is not packer/protector with some strong anti-debug layer. Thinstall is bundler which is able to pack all kinds of files into one executable file. What hard at Thinstall is, to unpack target that has dependencies - bundled files into one exe. In this tutorial we will try to unpack one file that have such dependencies. It is Teddy Rogers UnPackMe_Thinstall2.521.f.exe which contains three dependencies.





    1. Tools that we will need

    - OllyDbg 1.10
    - LordPE
    - some hex editor





    2. Few words before we start

    In this tutorial I will not explain how to reach OEP and how to fix IAT. It is all well explained in first Thinstall tutorial. For finding OEP and to speed-up a little I wrote one script for OllyScript plugin. That script will find OEP, kill DebugBlocker, and it will kill splash bitmap at the start. Bitamp is killed by patching CreateThread API and restoring back after we reach OEP. Finding OEP is easy, just like fixing IAT. As I sad, it is already explained in first tutorial.

    In case of dependencies, we cannot just restore back old good IAT. If we would just put it back, target couldn't extract dependencies when it needs them. So we would get just main executable without needed files. Thisntall doesn't exctract that file on hard drive. Instead, it places them directly to memory. Dependencies , or such virtual files, can be any type of file and number of such files is not limited. Now we have problem: How to get working unpacked target? There is 4 theoretical solutions:

    - Unpack main executable and extract all virtual files to hard drive. This can be veeery hard.
    - Inline patch target. Good and easy solution.
    - Code loader to patch target in memory to crack application.
    - Partialy unpack target, attach all blocks to main dump so protection is removed but executable is still able to extract needed files in memory. This sounds like SF but it's probably possible.

    In this tutorial we will use first way. That is actually the most hardest one because target can have large number of files packed within. For example, what if our target have 100 DLL's packed inside, 100 .txt files, or if it is some game that can have thousands of files packed? Now you see the problem. We could spend days or weeks extracting those files. Ofcourse, better examning inside Thinstall work could result a smart unpacker tool that would be able to extract all files.


    As said before, we will unpack Teddy's unpackme which has three dependencies. It will not be too hard. Those dependencies are three DLL's that are loaded in memory after OEP is reached. First that I noticed is, that target can be just patched after LoadLibraryA and unpackme will run fine cracked without need of those DLL's. But that is lame thing because our target is dummy application that doesn't needs those files. In case that we have "reall" app, our file would just crush.





    3. OEP , API's and main dump

    Run Olly, load UnPackMe_Thinstall2.521.f.exe in it and use my script to find OEP. Fix imports like I described it in first tutorial (second way in that tutorial is better and cleaner, it is even easier). And you will have main dump. So this is OEP:

    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 ; SE handler installation
    004271BF . 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
    004271C5 . 50 PUSH EAX
    004271C6 . 64:8925 000000>MOV DWORD PTR FS:[0],ESP
    004271CD . 83C4 A8 ADD ESP,-58
    004271D0 . 53 PUSH EBX
    004271D1 . 56 PUSH ESI ; <&KERNEL32.GetModuleFileNameA>
    004271D2 . 57 PUSH EDI ; <&KERNEL32.GetModuleFileNameA>
    004271D3 . 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
    004271D6 . FF15 DC0A4600 CALL DWORD PTR DS:[460ADC] ; kernel32.GetVersion

    And here is our target wants DLL's:

    00409FBF |. 53 PUSH EBX ;Pointer to DLL name
    00409FC0 |. FF15 3C0B4600 CALL DWORD PTR DS:[460B3C] ;Thinstall LoadLibraryA code
    00409FC6 |. 85C0 TEST EAX,EAX ;EAX = base of loaded DLL


    Thinstall substitutes some API's with own code. API's that are replaced are all those what executable uses for accessing outside files and libraries. So all LoadLibararyA, LoadLibraryW, CreateFileA, ReadFile, etc... are replaced with Thinstall functions. If our file wants to open some file, Thisntall will check is that file bundled as a virtual file. It just compares name of that file with internal list. If file is bundled, it will allocate block for it, extract it and return it's handle to main exe. If file is not bundled, then it will use acctuall API to open that file.

    In case of our DLL, Thinstall will extract it to ome virtual block, then fill it with imports and return it's block base as module handle. EBX points to DLL name, CALL calls Thinstall LoadLibraryA code, and EAX will return module base of such DLL in memory.

    There are several problems that we have while traying to dump these DLL's. Dumping is easy. We use LordPE to dump that memory block. But we need to repair those DLL's and that is interesting part.





    4. Dumping first DLL

    Try to run dump and you will get error message:

    An error has occured
    Line number: 1
    Please contact the program vendor
    53


    First DLL is very easy to dump. We load UnPackMe_Thinstall2.521.f.exe in Olly, then we find OEP with script. We place breakpoint on 409fbf line and we just run. In registeres window we can see that target wants "updatechecker_english" file to load as library. We place second breakpoint below API call, at the line 409fc6 to see EAX value. At my computer EAX=10000000 and that is base of first DLL. Now we just use LordPE to dump memory range at 10000000, size 3000. Note that this library will probably be loaded at different base. Not important, just dump your memory block and save it as updatechecker_english.dll. It can be without .dll extension.

    We can check now our first dumped dll withth LordPE. You will see that this is just resource dll with two sections. Dll can be loaded in memory and we dumped first file, but if our target is not just dummy one, we still would have problem. It is because file on disk have image alignment (like in memory) but in PE header is information for file alignment. So just set these values:

    FileAlignment: 00001000

    Sections info:

    Name VOffset VSize ROffset RSize Flags
    .rsrc 1000 1000 1000 1000 E00000E0
    .reloc 2000 1000 2000 1000 E20000E0

    Now check resources info and you will see that it is ok. That is all, this dll doesn't have imports or exports.






    5. Dumping second DLL

    If we run now, we get another error message:

    An error has occured
    Line number: 2
    Please contact the program vendor
    53

    We need to extract second DLL, which is called at the same place. It is updatechecker_german and it's base address on my machine is 03320000, size 0000E000. But this DLL have imports and exports. We can dump it like first one, but problem would be to repair imports since ImpREC cannot attach to this "virtual DLL". We could just dump it, then fix header info, load it in olly, load needed DLL's somehow and then use ImpREC for fixing. But it can be much easier. Also more interesting too. We restart target , find OEP again and then place two breakpoints at our old spot. We run to break when second dll is wanted, ei. when we see "updatechecker_german" in registeres window.

    Then we place bp on VirtualAlloc. We know that dll will be loaded on 03320000 address (in my case) so we will wait untill Thinstall allocates that block. So Run untill you can follow in dump that address. When you can follow in dump, place memory breakpoint on first couple bytes, then run again. Thinstall has allocated this block for PE header. Then it will allocate next at 03321000 for code section, etc... You should brek at part where it writes to blocks:

    00A0AE93 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
    00A0AE95 FF2495 A8AFA000 JMP DWORD PTR DS:[EDX*4+A0AFA8]

    Second line is good for breakpoint because we controll writing to blocks. As said, first block is for PE header. When it breaks second time at VirtualAlloc, PE header is written. Check that block:

    03320000 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ..............
    03320010 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ........@.......
    ...cut to reduce snippet
    033200E0 00 00 00 00 00 00 00 00 50 45 00 00 4C 01 03 00 ........PE..L...
    033200F0 84 B2 75 3C 00 00 00 00 00 00 00 00 E0 00 0E 21 ..u<...........!
    03320100 0B 01 06 00 00 40 00 00 00 70 00 00 00 00 00 00 .....@...p......
    03320110 E9 10 00 00 00 10 00 00 00 50 00 00 00 00 00 10 .........P......
    03320120 00 10 00 00 00 02 00 00 04 00 00 00 00 00 00 00 ................
    03320130 04 00 00 00 00 00 00 00 00 E0 00 00 00 04 00 00 ................
    03320140 A2 7C 00 00 02 00 00 00 00 00 10 00 00 10 00 00 .|..............
    03320150 00 00 10 00 00 10 00 00 00 00 00 00 10 00 00 00 ................
    03320160 00 00 00 00 00 00 00 00 14 C1 00 00 8F 00 00 00 ................
    03320170 00 C0 00 00 E8 00 00 00 00 00 00 00 00 00 00 00 ................
    03320180 00 00 00 00 00 00 00 00 00 D0 00 00 18 00 00 00 ................
    ...cut to reduce snippet
    033201E0 2E 74 65 78 74 00 00 00 00 B0 00 00 00 10 00 00 .text...........
    033201F0 00 36 00 00 00 04 00 00 50 45 43 32 00 00 00 00 .6......PEC2....
    03320200 00 00 00 00 20 00 00 E0 00 00 00 00 00 00 00 00 .... ...........
    03320210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    ...

    Select PE header view:

    03320000 4D 5A ASCII "MZ" ; DOS EXE Signature
    03320002 9000 DW 0090 ; DOS_PartPag = 90 (144.)
    03320004 0300 DW 0003 ; DOS_PageCnt = 3
    03320006 0000 DW 0000 ; DOS_ReloCnt = 0
    03320008 0400 DW 0004 ; DOS_HdrSize = 4
    0332000A 0000 DW 0000 ; DOS_MinMem = 0
    0332000C FFFF DW FFFF ; DOS_MaxMem = FFFF (65535.)
    0332000E 0000 DW 0000 ; DOS_ReloSS = 0
    03320010 B800 DW 00B8 ; DOS_ExeSP = B8
    03320012 0000 DW 0000 ; DOS_ChkSum = 0
    03320014 0000 DW 0000 ; DOS_ExeIP = 0
    03320016 0000 DW 0000 ; DOS_ReloCS = 0
    03320018 4000 DW 0040 ; DOS_TablOff = 40
    0332001A 0000 DW 0000 ; DOS_Overlay = 0
    ...


    Now we can see information about that DLL. Interesting for us is:

    03320110 E9100000 DD 000010E9 ; AddressOfEntryPoint = 10E9
    ...
    03320168 14C10000 DD 0000C114 ; Import Table address = C114
    0332016C 8F000000 DD 0000008F ; Import Table size = 8F (143.)


    We now know where OEP is and where is import table. Import table is the most important thing because that is last data that will be written before jumping to OEP. So I placed memory breakpoint at 0332C114 and size 8F (ofcourse, after another block is allocated for that part of image). After breaking there:


    0332C100 4C C1 00 00 5C C1 00 00 70 C1 00 00 80 C1 00 00 L......p.......
    0332C110 00 00 00 00 00 C1 00 00 00 00 00 00 FF FF FF FF ................
    0332C120 3C C1 00 00 00 C1 00 00 00 00 00 00 00 00 00 00 <...............
    0332C130 00 00 00 00 00 00 00 00 00 00 00 00 6B 65 72 6E ............kern
    0332C140 65 6C 33 32 2E 64 6C 6C 00 00 00 00 00 00 4C 6F el32.dll......Lo
    0332C150 61 64 4C 69 62 72 61 72 79 41 00 00 00 00 47 65 adLibraryA....Ge
    0332C160 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 00 00 tProcAddress....
    0332C170 00 00 56 69 72 74 75 61 6C 41 6C 6C 6F 63 00 00 ..VirtualAlloc..
    0332C180 00 00 56 69 72 74 75 61 6C 46 72 65 65 00 00 EB ..VirtualFree...
    0332C190 89 2C FF D0 0C C9 6F 06 23 00 0B 04 4E 70 5E A0 .,....o.#...Np^.
    0332C1A0 67 C7 FE FF FF 89 45 0C 17 5E 87 99 37 57 50 5F g.....E..^..7WP_


    Data from 0332C100 to 0332C114 are thunks. They will be filled last. I bynary copied all that data for later. Now go and check OEP=03320000+10E9. It looks like junk:

    033210E9 B8 B0C90010 MOV EAX,1000C9B0
    033210EE 50 PUSH EAX
    033210EF 64:FF35 00000000 PUSH DWORD PTR FS:[0]
    033210F6 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
    033210FD 33C0 XOR EAX,EAX
    033210FF 8908 MOV DWORD PTR DS:[EAX],ECX
    03321101 50 PUSH EAX
    03321102 45 INC EBP
    03321103 43 INC EBX
    03321104 6F OUTS DX,DWORD PTR ES:[EDI]
    03321105 6D INS DWORD PTR ES:[EDI],DX
    03321106 70 61 JO SHORT 03321169
    03321108 637432 00 ARPL WORD PTR DS:[EDX+ESI],SI
    0332110C 1F POP DS
    0332110D F6B9 78F42226 IDIV BYTE PTR DS:[ECX+2622F478]
    03321113 0321 ADD ESP,DWORD PTR DS:[ECX]
    03321115 DB847F 42837D74 FILD DWORD PTR DS:[EDI+EDI*2+747D8342]
    0332111C 112CF9 ADC DWORD PTR DS:[ECX+EDI*8],EBP
    0332111F DB51 08 FIST DWORD PTR DS:[ECX+8]
    03321122 8B6CE4 36 MOV EBP,DWORD PTR SS:[ESP+36]
    03321126 205F 5E AND BYTE PTR DS:[EDI+5E],BL
    03321129 5B POP EBX
    0332112A 5D POP EBP
    0332112B A1 44F1A23D MOV EAX,DWORD PTR DS:[3DA2F144]
    03321130 8B740D 1B MOV ESI,DWORD PTR SS:[EBP+ECX+1B]
    03321134 79 5C JNS SHORT 03321192
    03321136 9B WAIT
    03321137 0E PUSH CS
    03321138 48 DEC EAX

    Don't worry, it is not junk ;-) I will tell you later why, just place bp on first line. Run to break there and when you break, remove bp. Then paste back that thunks and dump whole block with LordPE. Save it as updatechecker_german.dll. Dump is good, but needs some PE header correction just like when I was fixing first DLL. Set FileAlignment=1000, set sections values on 1000 round numbers (if section size is 1234, set it to first bigger - 2000), RawOffset's set to be same as virtual. Now run main dump and it will gave you:

    An error has occured
    Line number: 3
    Please contact the program vendor
    53

    That means our second DLL is repaired.


    Ok, but why OEP of that dll looks like junk? It is because that dll was first packed with PECompact :-). Teddy probably packed dll first with PECompact. Or maybe Thinstall uses PECompact compression libraries? I don't know, but DLL is good even if it is still packed with PECompact. Even better, it was easier unpacking (less imports to resolve). But if you want, you can unpack PECompact to get totaly unpacked dlls.





    6. Dumping 3. DLL

    Third DLL is also packed by PECompact first so unpacking is same. Block is at 03350000 (on my machine), OEP=10E9,IAT=C114. For some reason, IAT was little screwed so I fixed it manually. And now target runs ok :-)


    - The End of first part -









    7. Inline patching

    What the hell, why do not show this solution too, when it's so easy.

    Idea is, to inject code that will load one DLL which will then patch application during runtime, just like loader. Since target is packed, there are not empty space inside exe to inject enough code for creating inline patch. We cannot add new sections because that would corrupt executable. PE header doesn't have any empty space for that too. But Thinstall doesn't have PE Header integrity check so we are allowed to change PE header a bit. It also doesn't check it's own code. This is PE header:

    00400000 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ..............
    00400010 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ........@.......
    00400020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    00400030 00 00 00 00 00 00 00 00 00 00 00 00 D0 00 00 00 ................
    00400040 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ........!..L.!Th
    00400050 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F is program canno
    00400060 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 t be run in DOS
    00400070 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 mode....$.......
    00400080 75 92 03 D8 31 F3 6D 8B 31 F3 6D 8B 31 F3 6D 8B u...1.m.1.m.1.m.
    00400090 31 F3 6C 8B 25 F3 6D 8B 53 EC 7E 8B 34 F3 6D 8B 1.l.%.m.S.~.4.m.
    004000A0 37 D0 7B 8B 33 F3 6D 8B 65 D0 5C 8B 30 F3 6D 8B 7.{.3.m.e..0.m.
    004000B0 52 69 63 68 31 F3 6D 8B 00 00 00 00 00 00 00 00 Rich1.m.........
    004000C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004000D0 50 45 00 00 4C 01 01 00 40 34 00 42 00 00 00 00 PE..L...@4.B....
    004000E0 00 00 00 00 E0 00 0E 01 0B 01 06 00 00 92 04 00 ................
    004000F0 00 00 00 00 00 00 00 00 94 1A 00 00 00 10 00 00 ................
    00400100 00 B0 04 00 00 00 40 00 00 10 00 00 00 02 00 00 ......@.........
    00400110 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ................
    00400120 00 B0 06 00 00 02 00 00 00 00 00 00 02 00 00 00 ................
    00400130 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00 ................
    00400140 D7 F2 06 00 10 00 00 00 00 00 00 00 00 00 00 00 ................
    00400150 90 5B 00 00 D8 02 00 00 70 5E 00 00 80 77 00 00 .[......p^...w..
    00400160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    00400170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    00400180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    00400190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004001A0 00 00 00 00 00 00 00 00 B0 53 00 00 58 00 00 00 .........S..X...
    004001B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004001C0 00 00 00 00 00 00 00 00 2E 74 65 78 74 20 20 20 .........text
    004001D0 00 A0 06 00 00 10 00 00 F0 C5 00 00 00 02 00 00 ................
    004001E0 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 E0 ............ ...


    I reduced "This program cannot be run in DOS mode" to "X" , ended it by 0D 0D 0A 24 00, and then I filled all that space to PE header signature with 90:


    00400000 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 MZ..............
    00400010 B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ........@.......
    00400020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    00400030 00 00 00 00 00 00 00 00 00 00 00 00 D0 00 00 00 ................
    00400040 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 58 0D ........!..L.!X.
    00400050 0D 0A 24 00 90 90 90 90 90 90 90 90 90 90 90 90 ..$.............
    00400060 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
    00400070 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
    00400080 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
    00400090 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
    004000A0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
    004000B0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
    004000C0 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 ................
    004000D0 50 45 00 00 4C 01 01 00 40 34 00 42 00 00 00 00 PE..L...@4.B....
    004000E0 00 00 00 00 E0 00 0E 01 0B 01 06 00 00 92 04 00 ................
    004000F0 00 00 00 00 00 00 00 00 94 1A 00 00 00 10 00 00 ................
    00400100 00 B0 04 00 00 00 40 00 00 10 00 00 00 02 00 00 ......@.........
    00400110 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ................
    00400120 00 B0 06 00 00 02 00 00 00 00 00 00 02 00 00 00 ................
    00400130 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00 ................
    00400140 D7 F2 06 00 10 00 00 00 00 00 00 00 00 00 00 00 ................
    00400150 90 5B 00 00 D8 02 00 00 70 5E 00 00 80 77 00 00 .[......p^...w..
    00400160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    00400170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    00400180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    00400190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004001A0 00 00 00 00 00 00 00 00 B0 53 00 00 58 00 00 00 .........S..X...
    004001B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004001C0 00 00 00 00 00 00 00 00 2E 74 65 78 74 20 20 20 .........text
    004001D0 00 A0 06 00 00 10 00 00 F0 C5 00 00 00 02 00 00 ................
    004001E0 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 E0 ............ ...

    That place is enough to inject some code that will load one DLL.


    Thinstall first loads it's own loader and then it jumps to it. It uses JMP EAX right above EP:

    00401A8D . FFE0 JMP EAX ; Jump to EntryPoint of Thinstall loader.
    00401A8F . 5F POP EDI
    00401A90 . 5E POP ESI
    00401A91 . 5B POP EBX
    00401A92 . C9 LEAVE
    00401A93 . C3 RETN
    00401A94 > $ 55 PUSH EBP ; EP of Thinstall target.
    00401A95 . 8BEC MOV EBP,ESP
    00401A97 . B8 DA00B39C MOV EAX,9CB300DA
    00401A9C . BB 597B1C10 MOV EBX,101C7B59
    00401AA1 . 50 PUSH EAX
    00401AA2 . E8 00000000 CALL UnPackMe.00401AA7

    I redirected that jump (code below jump is useless) to PE Header cave:

    00401A8D . 60 PUSHAD ;Save registeres.
    00401A8E .-E9 CBE5FFFF JMP injected.0040005E ;Jump to injected code.
    00401A93 . C3 RETN
    00401A94 > $ 55 PUSH EBP
    00401A95 . 8BEC MOV EBP,ESP
    00401A97 . B8 DA00B39C MOV EAX,9CB300DA
    00401A9C . BB 597B1C10 MOV EBX,101C7B59
    00401AA1 . 50 PUSH EAX
    00401AA2 . E8 00000000 CALL injected.00401AA7

    And inside PE header I loaded my DLL:

    0040005E 68 54004000 PUSH injected.00400054 ; ASCII "X.DLL"
    00400063 FF15 D0534000 CALL DWORD PTR DS:[<&KERNEL32.LoadLibraryA>] ; kernel32.LoadLibraryA
    00400069 05 00100000 ADD EAX,1000
    0040006E -FFE0 JMP EAX

    0040004E 58 0D 0D 0A 24 00 58 2E 44 4C 4C 00 90 90 90 90 X...$.X.DLL.....
    0040005E 68 54 00 40 00 FF 15 D0 53 40 00 05 00 10 00 00 hT.@....S@......

    I called my dll X.DLL (short name because small free space). Below it I placed injected code which loads X.DLL in memory using LoadLibraryA API. I pointed call to Thinstall it's own IAT since it uses this API. I didn't code DLL, instead I just copied that "updatechecker_english.dll". I erased everything out of it and Injected few lines of code in it. It is easier than code some DLL.

    So process is this: Thinstall unpacks it's own loader and then it uses JMP EAX to jump in it. I patched that jump to PE Header (before jump I used PUSHAD to save registeres) where my X.DLL is loaded. Then it jumps into my dll. Inside my dll, it restores original registers first:

    10001000 61 POPAD ;Restore registers back.
    10001001 60 PUSHAD ;Then save them again.
    10001002 8BC8 MOV ECX,EAX ;ECX=EAX= EP of thinstall loader.
    10001004 81E9 A98E0300 SUB ECX,38EA9 ;Difference to part where it calls target's OEP.
    1000100A C601 68 MOV BYTE PTR DS:[ECX],68 ;I will redirect that with PUSH xxxxxxxx.
    1000100D 41 INC ECX
    1000100E E8 00000000 CALL 10001013 ;This trick retrieves current offset
    10001013 5A POP EDX ;to EDX.
    10001014 83C2 2D ADD EDX,2D ;EDX will point little further (to empty space).
    10001017 8911 MOV DWORD PTR DS:[ECX],EDX ;PUSH that_empty_space_in_my_dll
    10001019 83C1 04 ADD ECX,4
    1000101C C601 C3 MOV BYTE PTR DS:[ECX],0C3 ;And I'm placing RETN that will redirect flow.
    1000101F 61 POPAD ;Restore registers.
    10001020 ^FFE0 JMP EAX ;And now it jumps to Thinstall loader EP.
    10001022 90 NOP
    10001023 90 NOP
    10001024 90 NOP
    10001025 90 NOP

    This code has changed OEP call to redirection in my dll. Before:

    7FF52C4B FF95 48FCFFFF CALL DWORD PTR SS:[EBP-3B8]

    and after my code has changed it:

    7FF52C4B 68 40100010 PUSH 10001040
    7FF52C50 C3 RETN


    Then, Thinstall will run normally. It will do all unpacking, it will check for debugger presence, it will even use DebugBlocker. So it will be two processes and both processes will use my dll, but only second process will jump to last part of my dll code which is final patch that patches target. Since this is just simple app and there is nothing to patch, I will just change text in message box. In my dll I placed new text:

    10002000 54 68 69 73 20 69 73 20 61 20 54 68 69 6E 73 74 This is a Thinst
    10002010 61 6C 6C 20 32 2E 35 32 31 20 55 6E 50 61 63 6B all 2.521 UnPack
    10002020 4D 45 0D 28 49 74 20 63 6F 6E 74 61 69 6E 73 20 ME.(It contains
    10002030 33 20 64 65 70 65 6E 64 65 6E 63 69 65 73 29 0D 3 dependencies).
    10002040 0D 41 6C 6C 20 50 72 6F 74 65 63 74 69 6F 6E 73 .All Protections
    10002050 20 45 6E 61 62 6C 65 64 20 2B 20 53 70 6C 61 73 Enabled + Splas
    10002060 68 20 53 63 72 65 65 6E 20 2B 20 4D 61 78 69 6D h Screen + Maxim
    10002070 75 6D 20 43 6F 6D 70 72 65 73 73 69 6F 6E 20 2B um Compression +
    10002080 20 52 6F 6C 6C 69 6E 67 20 43 68 65 63 6B 73 75 Rolling Checksu
    10002090 6D 20 45 6E 61 62 6C 65 64 0D 0D 7E 7E 20 43 52 m Enabled..~~ CR
    100020A0 41 43 4B 45 44 20 42 59 20 48 41 47 47 41 52 20 ACKED BY HAGGAR
    100020B0 7E 7E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ~~..............

    Then I found where it shows that message box so my patch can patch it. Here is finall code:

    10001040 60 PUSHAD ;Save registers.
    10001041 C705 09E54000 68>MOV DWORD PTR DS:[40E509],68 ;Place PUSH.
    1000104B C705 0DE54000 00>MOV DWORD PTR DS:[40E50D],90909000 ;NOP all.
    10001055 C605 11E54000 90 MOV BYTE PTR DS:[40E511],90
    1000105C 90 NOP
    1000105D 90 NOP
    1000105E 90 NOP
    1000105F E8 00000000 CALL X.10001064 ;Get current offset to EAX and point
    10001064 58 POP EAX ;my text. DLL can be loaded at any base
    10001065 05 9C0F0000 ADD EAX,0F9C ;so this will make ure that it works OK.
    1000106A A3 0AE54000 MOV DWORD PTR DS:[40E50A],EAX ;Place PUSH destination.
    1000106F 61 POPAD ;Registers back.
    10001070 68 B0714200 PUSH 4271B0 ;OEP value. It is static always.
    10001075 C3 RETN ;Jump to it.
    10001076 90 NOP
    10001077 90 NOP
    10001078 90 NOP
    10001079 90 NOP

    And that is it! Target is inline patched.








    8. For the end

    And that would be all. Script is included in archive along with dumped files. I included my X.DLL and patch too.

    Greets goes to everybody on BIW, ARTEAM , Morteza_SOS, CRACKMES.DE, .... and many more....


    See you :-)

    haggar (c) 2006














    PS

    I forgot to include script in archive so I'll place it here.




    /*
    -----------------------------------------------------------------
    Thinstall v2.5xx (v2.521 tested)- OEP finder script, by haggar
    -----------------------------------------------------------------
    ¤ Script features:
    + finds OEP,
    + kills DebugBlocker,
    + kills SPLASH window,
    + prevents allocating blocks in top memory (7xxxxxxx).
    - it doesn't repair IAT since it can be manually fixed.
    - script needs Windows XP.

    -----------------------------------------------------------------
    */

    var thread_patch
    var version
    var alloc
    var alloc_end
    var oep_call
    var loader
    var opcode
    var addr
    var counter
    var AllocType

    //------------ Patch CreateThread API to kill splash window --------------
    gpa "CreateThread","kernel32.dll"
    mov thread_patch,[$RESULT]
    mov [$RESULT],#900018c2#


    //-------------- Breakpoints ---------------
    gpa "VirtualAlloc","kernel32.dll"
    mov alloc,$RESULT
    findop alloc,#c21000#
    mov alloc_end,$RESULT

    gpa "GetVersionExA","kernel32.dll"
    findop $RESULT,#c20400#
    mov version,$RESULT

    bp alloc
    bp alloc_end
    bp version

    dbh //Hide from IsDebuggerPresent API.

    //--------- Get loader base , Check & kill DebugBlocker , find OEP ----------
    mov counter,0 //Counter, just to check is it first VirtualAlloc.
    LABEL_01:
    esto
    cmp eip,version //Stopped on GetVersionExA?
    jne NEXT_01a //If not, go on VirtualAlloc part.
    sti //If yes, check opcodes (are we at the right place).
    mov addr,eip
    mov opcode,[addr]
    and opcode,0ff
    cmp opcode,0a1
    jne LABEL_01
    add addr,5
    mov opcode,[addr]
    cmp opcode,25
    jne LABEL_01
    sti
    sti
    mov eax,0 //Right place, so kill DebugBlocker.
    bc version //I don't need this breakpoint anymore.

    sti //This is leftover from first script. Trace to CreateThread.
    sti
    sti
    sti
    mov eax,0 //Don't run thread. I don't need this part since I patched API.
    //Then find OEP call and place bp on it.
    find loader,#FF9548FCFFFF6A00E8????020083A544FCFFFF0080 65FC0083BDD4FDFFFF007412#
    cmp $RESULT,0
    je ABORT
    mov oep_call,$RESULT
    bp oep_call //Place breakpoint on OEP call.
    jmp LABEL_01

    NEXT_01a:
    cmp eip,alloc //Are we at VirtualAlloc?
    jne NEXT_01b
    mov AllocType,esp
    add AllocType,0c
    and [AllocType],0FFFF //Yes? Then prevent allocating above 7xxxxxxx.
    esto
    cmp counter,0 //Is it first stop?
    jne NEXT_01c
    mov counter,1
    mov loader,eax //Then get loader base.
    NEXT_01c:
    log eax
    jmp LABEL_01

    NEXT_01b:
    bc alloc
    bc alloc_end
    bc eip
    sti
    an eip
    cmt eip,"<-- I found OEP, imports are your problem."

    log loader

    //------------ Restore original bytes at CreateThread API --------------
    gpa "CreateThread","kernel32.dll"
    mov [$RESULT],thread_patch

    dbs //Restore debugger.
    ret
    ABORT:
    msg "Error or aborted by user."
    dbs
    ret

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

    پيش فرض

    Level : advanced

    ------------------------------------------
    Obsidium 1.3.0.4 - unpacking
    ------------------------------------------



    This tutorial is not exact solution for unpacking obsidium, instead it will just discuss some protection features and new implemented tricks in this version of obsidium. The new version of obsidium, 1.3.0.4 one, is pretty much the same as 1.2.5.0 one. One new trick is implemented, more junk code is added and that would be it.









    1. Tools and stuff

    Tools that you will need:

    - OllyDbg (with OllyScript plugin, one by SHaG or Epsylon3)
    - ImpREC
    - LordPE
    - CFF Explorer
    - some hex editor
    - DAMN hash calculator can be usefull


    Anti debug tricks that Obsidium uses:

    - UnhandledExceptionFilter
    - FindWindowA
    - CheckRemoteDebuggerPresent
    - IsDebuggerPresent
    - CreateToolhelp32Snapshot


    First four tricks are described in previous obsidium tutorial, so here only goes explanation for CreateToolhelp32Snapshot.
    This API creates snapshot of all running processes. Than, that snapshot is examned by Process32First and Process32Next APIs. In our target, we place breakpoint at the end of this API and we break there. EAX returns handle of snapshot, in my case EAX = 0000003C which is handle of snapshot. But main part is just comming. Now, that snapshot is examned with Process32Next and Process32First APIs. Process32First examnes only first process in snapshot, while second API examnes all others.

    These two APIs returns some very usefull informations about specific process. Part of that information is name of process, it's PID and it's "father" PID. "Father" PID is PID of process that started some process. So protector can see does OLLYDBG.EXE is running in background. But that is not some smart trick since we can just rename olly and obsidium will not do that.

    Obsidium will find it's own process and it will take PID of it's "father", the process who started it. Then it will examne all processes to find process with "father" PID, and it will check something. I din't trace to see what and how obsidium checking. Code is full of junk and I didn't want to waste time. I assumed that obsidium checking is "father" process explorer.exe, but I think that it is not exactly that. Nevermind, here is simple trick how to avoid olly detection:


    After breaking at CreateToolhelp32Snapshot , I place bp on end of Process32Next API. End because obsidium checks couple bytes for breakpoints, and it also emulate first couple opcodes. Then I check stack window:

    0012FD04 009074A1 RETURN to 009074A1
    0012FD08 0000003C
    0012FD0C 0012FD18

    Note that in your case, these values will probably be different, but that is not important. Third line from the top shows address of buffer for process info 0012FD18. Now I go there in dump window:

    0012FD18 28 01 00 00 00 00 00 00[04 00 00 00]00 00 00 00 (...............
    0012FD28 00 00 00 00 46 00 00 00(00 00 00 00)08 00 00 00 ....F...........
    0012FD38 00 00 00 00 53 79 73 74 65 6D 00 20 50 72 6F 63 ....System. Proc
    0012FD48 65 73 73 5D 00 00 00 00 00 00 00 00 00 00 00 00 ess]............

    We can see what process now this API examnes - System. It's PID is between [] while it's "father" PID is in (). This process doesn't have father PID. I'm searching for explorer.exe, ollydbg.exe and target.exe. Kep pressing F9:

    0012FD18 28 01 00 00 00 00 00 00 E0 04 00 00 00 00 00 00 (...............
    0012FD28 00 00 00 00 13 00 00 00 C8 04 00 00 08 00 00 00 ................
    0012FD38 00 00 00 00 65 78 70 6C 6F 72 65 72 2E 65 78 65 ....explorer.exe
    0012FD48 00 73 73 5D 00 00 00 00 00 00 00 00 00 00 00 00 .ss]............

    0012FD18 28 01 00 00 00 00 00 00 60 04 00 00 00 00 00 00 (.......`.......
    0012FD28 00 00 00 00 05 00 00 00 E0 04 00 00 08 00 00 00 ................
    0012FD38 00 00 00 00 4F 4C 4C 59 44 42 47 2E 45 58 45 00 ....OLLYDBG.EXE.
    0012FD48 00 73 73 5D 00 00 00 00 00 00 00 00 00 00 00 00 .ss]............

    0012FD18 28 01 00 00 00 00 00 00 28 01 00 00 00 00 00 00 (.......(.......
    0012FD28 00 00 00 00 02 00 00 00(60 04 00 00)08 00 00 00 ........`.......
    0012FD38 00 00 00 00 74 61 72 67 65 74 2E 65 78 65 00 00 ....target.exe..
    0012FD48 00 73 73 5D 00 00 00 00 00 00 00 00 00 00 00 00 .ss]............

    We can see: name of process - PID - father's PID

    explorer.exe - 4E0 - 4C8
    OLLYDBG.EXE - 460 - 4E0
    target.exe - 128 - 460

    Those PID's will always be different, but you can see that Olly is "father" for target.exe. Obsidium will see that too. But, we can simply change that return value in buffer. We change "father" PID from Olly's to eplorer.exe:

    0012FD18 28 01 00 00 00 00 00 00 28 01 00 00 00 00 00 00 (.......(.......
    0012FD28 00 00 00 00 02 00 00 00(E0 04 00 00)08 00 00 00 ................
    0012FD38 00 00 00 00 74 61 72 67 65 74 2E 65 78 65 00 00 ....target.exe..
    0012FD48 00 73 73 5D 00 00 00 00 00 00 00 00 00 00 00 00 .ss]............

    And now obsidium will not notice that it's been debugged. It will search again all processes for explorer.exe and it will see that explorer.exe is good buddy.


    Now we can run file under olly, but obsidium created one thread that check for debugger presence all the time. We can simply suspend that thread in olly and then run target normally under olly. Red thread in thread window is our main process, so you can suspend second one (first in this example):

    Threads
    Ident Entry Data block Last error Status Priority User time System time
    000001D0 7C810856 7FFDB000 ERROR_SUCCESS (000 Active 32 - 2 0.0000 s 0.0000 s
    000004EC 00408000 7FFDD000 ERROR_SUCCESS (000 Active 32 + 0 0.0000 s 0.0000 s

    Threads
    Ident Entry Data block Last error Status Priority User time System time
    000001D0 7C810856 7FFDB000 ERROR_SUCCESS (000 Suspended 32 - 2 0.0000 s 0.0000 s
    000004EC 00408000 7FFDD000 ERROR_SUCCESS (000 Active 32 + 0 0.0000 s 0.0000 s





    2. OEP

    OEP can be found like in previous tutorial, but obsidium code it to much filled with crappy opcodes. Since my target is Delphi one, first import that it uses is GetModuleHandleA. I placed bp on the end of that API,stopped there and returned to code:

    003B45BC BA 98803B00 MOV EDX,3B8098
    003B45C1 52 PUSH EDX
    003B45C2 8905 B4943B00 MOV DWORD PTR DS:[3B94B4],EAX
    003B45C8 8942 04 MOV DWORD PTR DS:[EDX+4],EAX
    003B45CB E8 98FFFFFF CALL 003B4568
    003B45D0 5A POP EDX
    003B45D1 58 POP EAX
    003B45D2 E8 DDE7FFFF CALL 003B2DB4
    003B45D7 C3 RETN
    003B45D8 55 PUSH EBP
    003B45D9 8BEC MOV EBP,ESP
    003B45DB 33C0 XOR EAX,EAX
    003B45DD 55 PUSH EBP
    003B45DE 68 FD453B00 PUSH 3B45FD
    003B45E3 64:FF30 PUSH DWORD PTR FS:[EAX]
    003B45E6 64:8920 MOV DWORD PTR FS:[EAX],ESP
    003B45E9 FF05 B8943B00 INC DWORD PTR DS:[3B94B8]
    003B45EF 33C0 XOR EAX,EAX
    003B45F1 5A POP EDX
    003B45F2 59 POP ECX
    003B45F3 59 POP ECX
    003B45F4 64:8910 MOV DWORD PTR FS:[EAX],EDX
    003B45F7 68 04463B00 PUSH 3B4604
    003B45FC C3 RETN
    003B45FD ^E9 92E4FFFF JMP 003B2A94
    003B4602 ^EB F8 JMP SHORT 003B45FC
    003B4604 5D POP EBP
    003B4605 C3 RETN
    003B4606 8BC0 MOV EAX,EAX
    003B4608 832D B8943B00 01 SUB DWORD PTR DS:[3B94B8],1
    003B460F C3 RETN
    003B4610 -FF25 A8A13B00 JMP DWORD PTR DS:[3BA1A8] <--- Imports.
    003B4616 8BC0 MOV EAX,EAX
    003B4618 -FF25 A4A13B00 JMP DWORD PTR DS:[3BA1A4]
    003B461E 8BC0 MOV EAX,EAX
    003B4620 -FF25 A0A13B00 JMP DWORD PTR DS:[3BA1A0]
    003B4626 8BC0 MOV EAX,EAX
    003B4628 -FF25 9CA13B00 JMP DWORD PTR DS:[3BA19C]
    003B462E 8BC0 MOV EAX,EAX


    Knowing Delphi apps, first RETN below leads back close to OEP:

    003B79D0 55 PUSH EBP <----------------- This is OEP.
    003B79D1 8BEC MOV EBP,ESP
    003B79D3 83C4 F4 ADD ESP,-0C
    003B79D6 53 PUSH EBX
    003B79D7 56 PUSH ESI
    003B79D8 57 PUSH EDI
    003B79D9 B8 98793B00 MOV EAX,3B7998
    003B79DE E8 D1CBFFFF CALL 003B45B4
    003B79E3 BE CC953B00 MOV ESI,3B95CC <----------- Here I am right now.
    003B79E8 BF E4953B00 MOV EDI,3B95E4
    003B79ED BB A0953B00 MOV EBX,3B95A0
    003B79F2 33C0 XOR EAX,EAX
    003B79F4 55 PUSH EBP
    003B79F5 68 847C3B00 PUSH 3B7C84
    003B79FA 64:FF30 PUSH DWORD PTR FS:[EAX]
    003B79FD 64:8920 MOV DWORD PTR FS:[EAX],ESP
    003B7A00 A1 80823B00 MOV EAX,DWORD PTR DS:[3B8280]
    003B7A05 8B00 MOV EAX,DWORD PTR DS:[EAX]
    003B7A07 A3 C8953B00 MOV DWORD PTR DS:[3B95C8],EAX
    003B7A0C C703 C0000000 MOV DWORD PTR DS:[EBX],0C0
    003B7A12 C743 04 90783B00 MOV DWORD PTR DS:[EBX+4],3B7890
    003B7A19 A1 C8953B00 MOV EAX,DWORD PTR DS:[3B95C8]
    003B7A1E 8943 10 MOV DWORD PTR DS:[EBX+10],EAX
    003B7A21 C743 1C 10000000 MOV DWORD PTR DS:[EBX+1C],10
    003B7A28 B8 947C3B00 MOV EAX,3B7C94
    003B7A2D 8943 24 MOV DWORD PTR DS:[EBX+24],EAX
    003B7A30 68 007F0000 PUSH 7F00
    003B7A35 6A 00 PUSH 0
    003B7A37 E8 44CCFFFF CALL 003B4680

    Ok, I didn't packed this file with stolen code option so we know OEP bytes. Problem in this file are imports and fact that whole code is relocated to this 003B0000 block. Maybe this can be prevented during obsidium runtime execution, but I have no will to trace trough obsidium junk code. Instead I will go around this, making weird dump. But I will leave that as a last thing. First imports.






    3. Imports

    Imports can be found like in previous tutorial, but script needs some changes because Delphi uses JMP DWORD[IMPORT] which affects stack diffrent. Also , obsidum has lot of junk there so I needed to clean it somehow (I manually patched lot of those small jumps). From previous tutorial (obsidium 1.2.5.0) I sow how obsidium handles imports. Obsidium has some internal table that consist from two parts (three, third was DLL names but they are erased after unpacking):

    First part are two DWORDS, first one is base of DLL and second is FFFFFFFF flag which probably means that DLL is loaded in memory. If that flag is 0, it means that API which is called is Obsidium protection API.

    Second is decrypted imports. It consinst from 1. WORD value, which determs type of protection, 2. WORD value and 3. DWORD value. Everything depends about 1. WORD value. Let's call that value "import code". There are couple such codes types:




    - "code 2" type:

    "Code 2" means that import is stored as first character of import and import CRC32 hash, information in table looks like this:

    code number - first char - CRC32 hash
    02 00 47 00 A0 F7 BF 08

    After decrypting, that import becomes "code 4" import, where code number is changed to 4, first char info is erased and hash is replaced with xor-ed import with value that it seams to be some unique constant for target. That is probably for speeding up execution. In executables who uses imports via CALL -> JMP DWORD[API] combination, such as ASM, Borland C++, Delphi, etc. compiled programs, CALL is then replaced with direct jump to import CALL API. For MSVC++ and similar compilers, who use CALL DWORD[API], that is not case.



    - "code 4" type:

    It seams that these imports are already used ones. Some targets doesn't have these ones by default because I checked every single import in some of them, but I notced that there are such values in their obsidium table. Question stays.



    - "code 1" type:

    code number - ? - ?
    01 00 00 00 11 00 00 00

    Code number is 1, first char is zero, hash is not hash. I didn't tried to find what those values means since this import can be retrieved similar to "type 2". Also, this type becames then type 4 too.


    - "code 80" type:

    Something similar to "code 1".

    code number - ? - ?
    80 00 00 00 04 00 00 00

    This type goes in little longer way. It returns to main image where emulation is performed and then it jumps to import. Again, import can be retrieved at one point, but this import doesn't becomes type 4 after.



    - "code 40" type:

    code number - ? - ?
    40 00 00 00 03 00 00 00

    This one doesn't seem to be emulated or obfuscated. ExitProcess is usually one of this type. Little harder for script but probably there are no many these ones.



    - "code 10" type:

    code number - ? - CRC32 hash
    10 00 00 00 C2 2E C7 4E

    This is internal Obsidium API. There are about 10 such API's whic are used to check registration information or trial one. Information about these API's can be found in obsidium help file.

    00905FBA 3D C22EC74E CMP EAX,4EC72EC2 -> isRegistered
    00905FCE 3D A1A0C163 CMP EAX,63C1A0A1 -> getRegInfo
    00905FE1 3D 09586CFC CMP EAX,FC6C5809 -> ??? maybe setExternalKey
    00905FF6 3D 8019A9B7 CMP EAX,B7A91980 -> getSystemID
    0090600D 3D B4D93687 CMP EAX,8736D9B4 -> setKeyfile
    00906020 3D 261923D3 CMP EAX,D3231926 -> getTrialDays
    00906037 3D 5F9EFDB8 CMP EAX,B8FD9E5F -> getTrialRuns
    0090604A 3D 925D522F CMP EAX,2F525D92 -> getLicenseExpiration
    00906060 3D E4234726 CMP EAX,264723E4 -> setShortKey
    00906072 3D 057EC561 CMP EAX,61C57E05 -> getCustomValue




    - rest of possible imports

    I noticed some code 8 type. Don't know what is that.



    Below code snippet is taken from previous obsidium tutorial (example target) and shows how imports type 1 and 2 can be found using script. It is indentical in both versions , only 1.3.0.4 one have tons of junk between "real" code (and that is reason why I didn't show that snippet).

    00394505 MOVZX EDX,CL
    00394508 MOVZX EAX,AX
    0039450B CALL 00394510
    00394510 POP EBX
    00394511 MOV EBP,EBX
    00394513 MOV EBX,DWORD PTR DS:[EBX-74]
    00394516 SUB EBP,0A8A0CB
    0039451C CALL 00394521
    00394521 ADD DWORD PTR SS:[ESP],0D
    00394525 MOV ECX,DWORD PTR SS:[EBP+A8A0BC]
    0039452B CALL ECX
    0039452D RETN
    0039452E MOV ESI,DWORD PTR DS:[EBX+44]
    00394531 XOR DL,BYTE PTR SS:[EBP+A8A18C]
    00394537 XOR AX,WORD PTR SS:[EBP+A8A18D]
    0039453E SHL EDX,3
    00394541 MOV ECX,EDX
    00394543 SHL EDX,1
    00394545 ADD ECX,EDX
    00394547 LEA EDI,DWORD PTR DS:[ESI+ECX+4]
    0039454B CMP DWORD PTR DS:[EDI+4],0 <--------------------- DLL check.
    0039454F JE 00394768
    00394555 ADD ESI,DWORD PTR DS:[EDI+14]
    00394558 LEA ESI,DWORD PTR DS:[ESI+EAX*8]
    0039455B MOVZX EAX,WORD PTR DS:[ESI] <-------------------- Obsidium import table.
    0039455E CMP EAX,4 <-------------------------------------- "code 4" check.
    00394561 JE 003945FE
    00394567 CMP EAX,1 <-------------------------------------- "code 1" check.
    0039456A JE SHORT 003945D4
    0039456C CMP EAX,80
    00394571 JE 00394830
    00394577 CMP EAX,40
    0039457A JE 0039462A
    00394580 MOVZX EAX,WORD PTR DS:[ESI+2]
    00394584 PUSH 1
    00394586 PUSH EAX
    00394587 PUSH 0
    00394589 PUSH DWORD PTR DS:[ESI+4]
    0039458C PUSH DWORD PTR DS:[EDI]
    0039458E CALL DWORD PTR DS:[EBX+50]
    00394591 TEST EAX,EAX <----------------------- Here we can retrieve "code 2" import.
    00394593 JNZ SHORT 003945E6
    ....
    ....
    003945D9 JBE SHORT 003945DF
    003945DB PUSH 0
    003945DD PUSH DWORD PTR DS:[EDI]
    003945DF CALL DWORD PTR DS:[EBX+50]
    003945E2 TEST EAX,EAX <------------------------- Here we can retrieve "code 1" import.
    003945E4 JE SHORT 003945B5
    003945E6 MOV EDX,EAX




    Before trying script or manually tracing, set access on image to "full access". Ok, after writting script here is partially found IAT, it misses about 20 imports:

    003BA0B4 8A 18 91 7C ED 10 90 7C 05 10 90 7C A1 9F 80 7C ...|...|...|...|
    003BA0C4 14 9B 80 7C 81 9A 80 7C 5D 99 80 7C BD 99 80 7C ...|...|]..|...|
    003BA0D4 60 00 3C 00 C7 A0 80 7C AD 9C 80 7C 78 67 90 00 `.<....|...|xg..
    003BA0E4 29 C7 80 7C 9C 00 3C 00 05 A4 80 7C EE 1E 80 7C )..|..<....|...|
    003BA0F4 57 B3 80 7C 7E D4 80 7C 31 03 91 7C CF 01 3C 00 W..|~..|1..|..<.
    003BA104 F0 00 3C 00 FC 00 3C 00 08 01 3C 00 14 01 3C 00 ..<...<...<...<.
    003BA114 50 F8 81 7C 40 7A 93 7C 38 01 3C 00 E1 EA 81 7C P..|@z.|8.<....|
    003BA124 A9 2C 81 7C 5C 01 3C 00 69 10 81 7C 74 01 3C 00 ©,.|.<.i..|t.<.
    003BA134 80 01 3C 00 8C 01 3C 00 46 FA D6 77 98 EC D6 77 ..<...<.F..w...w
    003BA144 0B 05 D8 77 FD 01 3C 00 83 78 DD 77 1B 76 DD 77 ...w..<..x.w.v.w
    003BA154 F0 6B DD 77 2D 02 3C 00 C4 65 12 77 48 D3 14 77 .k.w-.<..e.wH..w
    003BA164 C0 48 12 77 3B 4C 12 77 50 48 12 77 59 4B 12 77 .H.w;L.wPH.wYK.w
    003BA174 81 02 3C 00 F5 9B 80 7C 50 97 80 7C BD 99 80 7C ..<....|P..|...|
    003BA184 29 B5 80 7C 57 B3 80 7C C9 02 3C 00 78 67 90 00 )..|W..|..<.xg..
    003BA194 E1 02 3C 00 51 28 81 7C 05 A4 80 7C 57 B3 80 7C ..<.Q(.|...|W..|
    003BA1A4 7E D4 80 7C E6 2B 81 7C 29 03 3C 00 80 AD F3 77 ~..|.+.|).<....w
    003BA1B4 41 03 3C 00 64 C0 D4 77 CE 8B D4 77 DC E5 D4 77 A.<.d..w...w...w
    003BA1C4 AE E2 D4 77 16 23 D5 77 0B 05 D8 77 98 EC D6 77 ®..w.#.w...w...w
    003BA1D4 FA E8 D4 77 2E F8 D6 77 75 8F D4 77 45 EA D6 77 ...w...wu..wE..w
    003BA1E4 BD BC D4 77 6B DF D4 77 0B 19 D5 77 F5 03 3C 00 ...wk..w...w..<.

    After long and painfull, manually tracing, I found some others:

    003BA0B4 8A 18 91 7C ED 10 90 7C 05 10 90 7C A1 9F 80 7C ...|...|...|...|
    003BA0C4 14 9B 80 7C 81 9A 80 7C 5D 99 80 7C BD 99 80 7C ...|...|]..|...|
    003BA0D4 59 B8 80 7C C7 A0 80 7C AD 9C 80 7C E0 C6 80 7C Y..|...|...|...|
    003BA0E4 29 C7 80 7C 4F 1D 80 7C 05 A4 80 7C EE 1E 80 7C )..|O..|...|...|
    003BA0F4 57 B3 80 7C 7E D4 80 7C 31 03 91 7C 8D 2C 81 7C W..|~..|1..|.,.|
    003BA104 66 AA 80 7C A2 CA 81 7C 9F 0F 81 7C A6 0D 81 7C f..|...|...|...|
    003BA114 50 F8 81 7C 40 7A 93 7C 0E 18 80 7C E1 EA 81 7C P..|@z.|...|...|
    003BA124 A9 2C 81 7C 8F 0C 81 7C 69 10 81 7C 24 1A 80 7C ©,.|...|i..|$..|
    003BA134 77 9B 80 7C 8C 01 3C 00 46 FA D6 77 98 EC D6 77 w..|..<.F..w...w
    003BA144 0B 05 D8 77 FD 01 3C 00 83 78 DD 77 1B 76 DD 77 ...w..<..x.w.v.w
    003BA154 F0 6B DD 77 2D 02 3C 00 C4 65 12 77 48 D3 14 77 .k.w-.<..e.wH..w
    003BA164 C0 48 12 77 3B 4C 12 77 50 48 12 77 59 4B 12 77 .H.w;L.wPH.wYK.w
    003BA174 81 02 3C 00 F5 9B 80 7C 50 97 80 7C BD 99 80 7C ..<....|P..|...|
    003BA184 29 B5 80 7C 57 B3 80 7C C9 02 3C 00 E0 C6 80 7C )..|W..|..<....|
    003BA194 59 B8 80 7C 51 28 81 7C 05 A4 80 7C 57 B3 80 7C Y..|Q(.|...|W..|
    003BA1A4 7E D4 80 7C E6 2B 81 7C 29 03 3C 00 80 AD F3 77 ~..|.+.|).<....w
    003BA1B4 41 03 3C 00 64 C0 D4 77 CE 8B D4 77 DC E5 D4 77 A.<.d..w...w...w
    003BA1C4 AE E2 D4 77 16 23 D5 77 0B 05 D8 77 98 EC D6 77 ®..w.#.w...w...w
    003BA1D4 FA E8 D4 77 2E F8 D6 77 75 8F D4 77 45 EA D6 77 ...w...wu..wE..w
    003BA1E4 BD BC D4 77 6B DF D4 77 0B 19 D5 77 F5 03 3C 00 ...wk..w...w..<.

    It looks like 7 of them are still unknown but searching all intermodular calls, I didn't find any missing one. Maybe if I check jumps !?! Hmm, no, everything looks fine. Those leftovers are probably just space between thunks. I will not use ImpREC now, because it cannot get imports (image is relocated). Ok, now dumping problem.





    4. Dumping

    Buah, how to dump now, when target is totally crippled? This is how target looks in memory:

    Memory map
    Address Size Owner Section Contains Type Access Initial Mapped as
    003B0000 0000E000 Priv RWE RWE
    003C0000 00001000 Priv RWE RWE
    003D0000 00004000 Priv RW RW
    003E0000 00003000 Map R R
    00400000 00001000 target PE header Imag RWE RWE
    00401000 00001000 target code,imports Imag RWE RWE
    00402000 00004000 target .rsrc code,resourc Imag RWE RWE
    00406000 00001000 target code,resourc Imag RWE RWE
    00407000 00001000 target code,resourc Imag RWE RWE
    00408000 0000C000 target SFX,data,res Imag RWE RWE


    Our target is located at 00400000 while code is relocated in 003B0000 to prevent dumping. So I dumped my target with lor PE, then I dumped whole block from 003B0000 to 00400000. Difference from 003B0000 to 00400000 is 50000. Then I added to dump 50000 bytes, but at the beggining of file! Now, PE header in dump is at 50000 offset and dump is totally invalid. At the beggining of file, in that 0-50000 range, I paste that dumped block from 003B0000-00400000. Now, in my dump is all that I need, but everything is screwed. Ok, time to fix dump.


    I moved header from 50000 to 0 offset (simply copying 400 bytes from 50000 and paste it to 0 offset). Now dump has header (old one at 50000 can be erased - filled with zeros), but it's invalid. Using LordPE, of maybe better CFF Explorer, I need to shift all values up for 50000 bytes. These are values that I set in LordPE:

    OEP = 000079D0
    ImageBase = 003B0000
    ImageSize = 00064000
    BaseOfCode = 00001000
    BaseOfData = 00001000
    NumberOfSections = 0002
    NumOfRvaAndSizes = 00000010

    Notice that I set file to have only 2 sections. Rest of them will not be erased, I will just expand those two. Sections are set like this, again LordPE is used:

    First section:
    Name = CODE
    VOffset = 1000
    VSize = 51000
    ROffset = 1000
    RSize = 51000
    Flags = E00000E0

    Second section
    Name = .rsrc
    VOffset = 52000
    VSize = 12000
    ROffset = 52000
    RSize = 12000
    Flags = E00000E0

    Sections are on the place now, but resources, imports and TLS data needs to be corrected. TLS and resources I changed with CFF (but it can be done with LordPE too):

    TLS table:
    RVA = 00057000 (it was 7000, I added 50000)

    Resurce:
    RVA = 00052000 (shifted up for 50000)

    Resources can be viewed clicking on "..." button by the resurce info. My first two entries are incorrect. I fix them to:

    first one (which shows as bitamp when fixed):
    RVA = 00052910
    Offset = 00052910

    second (icon)
    RVA = 000520C0
    Offset = 000520C0


    Now is everything almost fixed. Imports are only that's left. In LordPE, I set ImportTable RVA and Size to 00000000. Now I can load it in olly without problem.





    5. Rebuilding import table

    What is wrong with imports? We don't have IAT, DLLs are not loaded in memory, but jumps point to some pointers/thunks who are correct pointers to imports if DLLs are loaded. So if I load DLLs in memory, this dump will work on my machine. If I load DLLs , I could then use ImpREC to get imports (since pointers now are in main image an ImpREC can find thm).

    How to load DLLs? Simply, by injecting two lines of code that will push DLL name and then call LoadLibraryA API. And that for all DLLs. What DLLs I need? When I'm at OEP of my unpacked (not yet dumped , or you can just attach to target if you don't want to search OEP again) target, I check modules window:

    Executable modules
    Base Size Entry Name File version Path
    77DD0000 0009B000 77DD70D4 advapi32 5.1.2600.2180 (x C:WINDOWSsystem32advapi32.dll
    77F10000 00046000 77F163CA GDI32 5.1.2600.2180 (x C:WINDOWSsystem32GDI32.dll
    7C800000 000F4000 7C80B436 kernel32 5.1.2600.2180 (x C:WINDOWSsystem32kernel32.dll
    77C10000 00058000 77C1F2A1 msvcrt 7.0.2600.2180 (x C:WINDOWSsystem32msvcrt.dll
    7C900000 000B0000 7C913156 ntdll 5.1.2600.2180 (x C:WINDOWSsystem32ntdll.dll
    774E0000 0013C000 774F20C1 ole32 5.1.2600.2180 (x C:WINDOWSsystem32ole32.dll
    77120000 0008C000 77121558 oleaut32 5.1.2600.2180 C:WINDOWSsystem32oleaut32.dll
    77E70000 00091000 77E76284 RPCRT4 5.1.2600.2180 (x C:WINDOWSsystem32RPCRT4.dll
    77FE0000 00011000 77FE2131 Secur32 5.1.2600.2180 (x C:WINDOWSsystem32Secur32.dll
    77D40000 00090000 77D50EB9 USER32 5.1.2600.2180 (x C:WINDOWSsystem32USER32.DLL
    00400000 00014000 00408000 target 1.0.0.0 D:Obsidium 1.3.0.4target.exe

    Some of those DLLs are not needed, but nevermind. Now I find some empty place in my dump, I write in that DLL names, then I just inject three lines for every DLL:

    push offset_to_dll_name (example ASCII "advapi32.dll")
    call LoadLibraryA
    nop

    After doing that and executing that code, all DLLs are loaded and now I use ImpREC. Dump is fixed now.






    6. The end

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

    پيش فرض

    Level : intermediate

    ------------------------------------------
    Obsidium 1.2.5.0 - unpacking
    ------------------------------------------



    I didn't unpack anything for a while due to my coledge obligations, but today I gave on examne and I'm in good mood. Obsidium is pretty good protector that comes from chinese author. I didn't notice any apps packed with it and I don't know why, since it has some pretty cool options. In this tutorial I will try 1.2.5.0 version which is older one, but it's good as starting point. I think that this unpackme doesn't have all protection options enabled since I know that obsidium has option to relocate whole image. That is probably only possible with Borland applications.



    1. Intro

    Tools that we need are usual:

    Windows XP; OllyDbg; ImpREC; LordPE; some hex editor; PEiD is not important but if you have good external database, at least it can detect correct version of packer.

    Obsidium has some cool anti-debug trickcs:

    - CheckRemoteDebuggerPresent; this API detects debugger on XP machines,
    - UnhandledExceptionFilter; trick to crush application which runs under debugger,
    - FindWindowA; it finds olly window class "OLLYDBG",
    - IsDebuggerPresent; detects debugger,
    - threads; obsidium runs one or two threads that uses previous tricks,
    - stolen OEP code; it steal couple bytes from OEP,
    - cool import protection.


    Also, obsidum code is full of junk opcodes like short jumps that makes tracing very annoying. That is actually one thing that I realy hate. Obsidium doesn't use GetProcAddress to find imports, instead it have custom procedure that find imports. It also checks for breakpoints at API's and emulate them partialy, so we need to place bp's on end of API's.


    Anti-debug tricks, CheckRemoteDebuggerPresent, FindWindowA and IsDebuggerPresent, can be bypassed simply by placing bp's at the end of those API's and then seting return value EAX=0.

    UnhandledExceptionFilter is used to handle some exceptions that protector generate on purpose. Problem is that if we are in debugger, application expects that debugger will take control instead system debugger (Dr. Watson). We can force system to think that application is not running within debugger. This is UnhandledExceptionFilter function and below shows how to trick it:

    PUSH 248 <------------------------- UnhandledExceptionFilter function starts here.
    PUSH kernel32.7C8635E0
    CALL kernel32.7C8024CB
    MOV EAX,DWORD PTR DS:[7C8836CC]
    MOV DWORD PTR SS:[EBP-1C],EAX
    MOV EBX,DWORD PTR SS:[EBP+8]
    MOV DWORD PTR SS:[EBP-178],EBX
    MOV DWORD PTR SS:[EBP-148],4
    XOR EDI,EDI
    MOV DWORD PTR SS:[EBP-13C],EDI
    MOV DWORD PTR SS:[EBP-16C],EDI
    MOV EAX,DWORD PTR DS:[EBX]
    TEST BYTE PTR DS:[EAX+4],10
    JE SHORT kernel32.7C862BD4
    PUSH DWORD PTR DS:[EAX]
    PUSH -1
    CALL DWORD PTR DS:[<&ntdll.NtTerminatePr>; ntdll.ZwTerminateProcess
    MOV EAX,DWORD PTR DS:[EBX]
    MOV ESI,C0000005
    CMP DWORD PTR DS:[EAX],ESI
    JNZ SHORT kernel32.7C862BF9
    CMP DWORD PTR DS:[EAX+14],1
    JNZ SHORT kernel32.7C862BF9
    PUSH DWORD PTR DS:[EAX+18]
    CALL kernel32.7C862874
    CMP EAX,-1
    JNZ SHORT kernel32.7C862BF9
    OR EAX,EAX
    JMP kernel32.7C863458
    MOV DWORD PTR SS:[EBP-124],EDI
    PUSH EDI
    PUSH 4
    LEA EAX,DWORD PTR SS:[EBP-124]
    PUSH EAX
    PUSH 7
    CALL kernel32.GetCurrentProcess <------------- Here is trick! This API returns FFFFFFFF. Change EAX to 0.
    PUSH EAX
    CALL DWORD PTR DS:[<&ntdll.NtQueryInform>; ntdll.ZwQueryInformationProcess
    TEST EAX,EAX
    ...
    ...




    2. OEP and stolen code

    While writing this text, I didn't find some genereic way to find OEP that would be suitable for writing script. Instead that, I traced and experimented with code, exceptions , breakpoints. I found where import jumps are allocated, conclusion is that when crackme is unpacked, it will try to use some import so I just placed memory bp on whole import block. Crackme is small so it is not problem to find starting point.

    But let's go in other direction. I placed breakpoints on all checks to kill anti tricks. When new thread started, I took a look in log window. Last occured exception is interesting:

    Log data
    Address Message
    00415022 Access violation when reading [00000000]
    0041EFA5 Access violation when reading [FFFFFFFF]

    77DD0000 Module C:WINDOWSsystem32advapi32.dll
    00390295 Access violation when reading [FFFFFFFF]
    7C85994E Breakpoint at kernel32.7C85994E
    7C901230 INT3 command at ntdll.DbgBreakPoint
    Access violation when executing [00000000]
    7C862C10 Breakpoint at kernel32.7C862C10
    003907E8 Illegal instruction
    00390854 Integer division by zero
    77D6F3DC Breakpoint at USER32.77D6F3DC
    Access violation when executing [00000000]
    7C862C10 Breakpoint at kernel32.7C862C10
    00395F82 Integer division by zero
    00395F84 Access violation when reading [00000000]
    0039655D Access violation when reading [8003F41E]
    0039654A Integer division by zero
    0039654C Access violation when reading [00000000]
    0039654F Access violation when reading [FFFFFFFF]
    0039654D Access violation when reading [FFFFFFFF]
    0039655D Access violation when reading [8003F418]
    00396550 Illegal instruction
    003965BC Integer division by zero
    7C812E10 Breakpoint at kernel32.7C812E10
    00396555 INT3 command at 00396555
    00395041 Integer division by zero
    00395041 Integer division by zero
    0039520A Integer division by zero
    00395041 Integer division by zero
    0039520A Integer division by zero
    0039520A Integer division by zero
    00415DA1 Illegal instruction
    00415F9B Integer division by zero <---------------- This one.
    7C810856 New thread with ID 00000304 created
    7C85994E Breakpoint at kernel32.7C85994E


    Last exception is in main image (last section, protectors one) and it is "Integer division by zero". So I done it all again, only this time I unchecked "Intiger divison by 0" in olly options, so I could break on that exception. After couple ones, here is last one:

    00415F9B F7F0 DIV EAX <------------------------- Exception.
    00415F9D 55 PUSH EBP
    00415F9E 8BEC MOV EBP,ESP
    00415FA0 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
    00415FA3 6A 00 PUSH 0
    00415FA5 68 CC971025 PUSH 251097CC
    00415FAA 6A 00 PUSH 0
    00415FAC FF50 18 CALL DWORD PTR DS:[EAX+18]
    00415FAF 5D POP EBP
    00415FB0 C2 0800 RETN 8
    00415FB3 55 PUSH EBP
    00415FB4 8BEC MOV EBP,ESP
    00415FB6 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
    00415FB9 8B00 MOV EAX,DWORD PTR DS:[EAX]
    00415FBB 3D 1D0000C0 CMP EAX,C000001D
    00415FC0 74 0E JE SHORT UnPackMe.00415FD0
    00415FC2 3D 940000C0 CMP EAX,C0000094
    00415FC7 75 41 JNZ SHORT UnPackMe.0041600A
    00415FC9 B9 AB92AD01 MOV ECX,1AD92AB
    00415FCE EB 05 JMP SHORT UnPackMe.00415FD5
    00415FD0 B9 4E90AD01 MOV ECX,1AD904E
    00415FD5 E8 00000000 CALL UnPackMe.00415FDA
    00415FDA 5A POP EDX
    00415FDB 8B45 10 MOV EAX,DWORD PTR SS:[EBP+10]
    00415FDE 81EA 893CBA00 SUB EDX,0BA3C89
    00415FE4 8D940A EFAB0CFF LEA EDX,DWORD PTR DS:[EDX+ECX+FF0CABEF]
    00415FEB 8990 B8000000 MOV DWORD PTR DS:[EAX+B8],EDX
    00415FF1 33C9 XOR ECX,ECX
    00415FF3 8948 04 MOV DWORD PTR DS:[EAX+4],ECX
    00415FF6 8948 08 MOV DWORD PTR DS:[EAX+8],ECX
    00415FF9 8948 0C MOV DWORD PTR DS:[EAX+C],ECX
    00415FFC 8948 10 MOV DWORD PTR DS:[EAX+10],ECX
    00415FFF C740 18 55003333 MOV DWORD PTR DS:[EAX+18],33330055
    00416006 33C0 XOR EAX,EAX
    00416008 5D POP EBP
    00416009 C3 RETN
    0041600A 33C0 XOR EAX,EAX
    0041600C 40 INC EAX
    0041600D 5D POP EBP
    0041600E C3 RETN
    0041600F 33C0 XOR EAX,EAX
    00416011 8D44C0 03 LEA EAX,DWORD PTR DS:[EAX+EAX*8+3]
    00416015 010424 ADD DWORD PTR SS:[ESP],EAX
    00416018 C3 RETN


    By this time, crackme code section is already unpacked. I could place memory breakpoint on it and I would land on "false oep". First, this crackme has code section at 404000. Second, Obsidium ALWAYS JUMPS ON FALSE OEP. Even if it doesn't steal bytes, it jumps couple opcodes further (I've been little examning obsidium work).

    If we check stack, we can see where is SEH handler that will handle exception:

    0012FF94 0012FFE0 Pointer to next SEH record
    0012FF98 00415FB3 SE handler

    That is code below our exception, so we can place bp there 00415FB3. We came to RETN that throw us to ntdll.dll:

    00416009 C3 RETN

    That is Ok, let's enter in and then place memory breakpoint on last section to return to obsidium code.

    004161EB E8 67000000 CALL UnPackMe.00416257 <------------- We returning here.

    Tracing in we find some decryptor loop which ends here:

    004162BF ^0F85 D4FFFFFF JNZ UnPackMe.00416299
    004162C5 EB 05 JMP SHORT UnPackMe.004162CC
    004162C7 BD 7C3BF3D8 MOV EBP,D8F33B7C
    004162CC 61 POPAD
    004162CD C3 RETN

    Then we go here:

    004161EB FF96 8C010000 CALL DWORD PTR DS:[ESI+18C]
    004161F1 8B7E 04 MOV EDI,DWORD PTR DS:[ESI+4]
    004161F4 FFB6 44010000 PUSH DWORD PTR DS:[ESI+144]
    004161FA FF96 80000000 CALL DWORD PTR DS:[ESI+80]
    00416200 25 FF030000 AND EAX,3FF
    00416205 8DBC07 00010000 LEA EDI,DWORD PTR DS:[EDI+EAX+100]
    0041620C 56 PUSH ESI
    0041620D 57 PUSH EDI
    0041620E 8DB5 C83CBA00 LEA ESI,DWORD PTR SS:[EBP+BA3CC8]
    00416214 B9 D2010000 MOV ECX,1D2
    00416219 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
    0041621B 5F POP EDI
    0041621C 5E POP ESI
    0041621D 8D85 F63EBA00 LEA EAX,DWORD PTR SS:[EBP+BA3EF6]
    00416223 68 80000000 PUSH 80
    00416228 50 PUSH EAX
    00416229 FF76 04 PUSH DWORD PTR DS:[ESI+4]
    0041622C FF76 20 PUSH DWORD PTR DS:[ESI+20]
    0041622F FF96 80000000 CALL DWORD PTR DS:[ESI+80]
    00416235 6A 3A PUSH 3A
    00416237 57 PUSH EDI
    00416238 50 PUSH EAX
    00416239 FF76 04 PUSH DWORD PTR DS:[ESI+4]
    0041623C FF76 28 PUSH DWORD PTR DS:[ESI+28]
    0041623F FF96 80000000 CALL DWORD PTR DS:[ESI+80]
    00416245 -FFE7 JMP EDI <--------------------- Skip all and go here!


    Skipp all calls before JMP EDI (some decrypting is performed there) and to it (be aware of possible breakpoin checks if you place bp on JMP EDI). That JMP EDI leads to part which throws you at false oep. Trace through that code and it will transform to:

    00398305 E8 00000000 CALL 0039830A
    0039830A 5D POP EBP
    0039830B 81ED CD3CBA00 SUB EBP,0BA3CCD
    00398311 64:67:8F06 0000 POP DWORD PTR FS:[0]
    00398317 83C4 04 ADD ESP,4
    0039831A C685 FD3CBA00 E9 MOV BYTE PTR SS:[EBP+BA3CFD],0E9
    00398321 8B95 063DBA00 MOV EDX,DWORD PTR SS:[EBP+BA3D06]
    00398327 0356 10 ADD EDX,DWORD PTR DS:[ESI+10]
    0039832A 8D8D 023DBA00 LEA ECX,DWORD PTR SS:[EBP+BA3D02]
    00398330 2BD1 SUB EDX,ECX
    00398332 8995 FE3CBA00 MOV DWORD PTR SS:[EBP+BA3CFE],EDX
    00398338 61 POPAD
    00398339 9D POPFD
    0039833A -E9 D0BC0600 JMP UnPackMe.0040400F <----------------------- Jump to false OEP.


    And here it is:

    0040400F E8 01040000 CALL UnPackMe.00404415
    00404014 68 00000000 PUSH 0
    00404019 FF15 F4114000 CALL DWORD PTR DS:[4011F4]
    0040401F A3 07F04000 MOV DWORD PTR DS:[40F007],EAX
    00404024 60 PUSHAD
    00404025 8925 0BF04000 MOV DWORD PTR DS:[40F00B],ESP
    0040402B E9 30000000 JMP UnPackMe.00404060
    00404030 8B25 0BF04000 MOV ESP,DWORD PTR DS:[40F00B]
    00404036 61 POPAD
    00404037 E8 19090000 CALL UnPackMe.00404955
    0040403C E8 6D040000 CALL UnPackMe.004044AE
    00404041 89EC MOV ESP,EBP
    00404043 5D POP EBP
    00404044 FF35 D4F14000 PUSH DWORD PTR DS:[40F1D4]
    0040404A FF15 EC114000 CALL DWORD PTR DS:[4011EC]
    00404050 9B WAIT
    00404051 DBE2 FCLEX
    00404053 D92D 00604000 FLDCW WORD PTR DS:[406000]
    00404059 C3 RETN
    0040405A 0000 ADD BYTE PTR DS:[EAX],AL
    0040405C 0000 ADD BYTE PTR DS:[EAX],AL
    0040405E 0000 ADD BYTE PTR DS:[EAX],AL
    00404060 68 00000000 PUSH 0
    00404065 B8 7C604000 MOV EAX,UnPackMe.0040607C ; ASCII "Coded by Teddy Rogers / SnD Team 2005"
    0040406A 89C2 MOV EDX,EAX
    0040406C 52 PUSH EDX
    0040406D B8 54604000 MOV EAX,UnPackMe.00406054 ; ASCII "If you unpack it write a tutorial... "
    00404072 89C6 MOV ESI,EAX
    00404074 56 PUSH ESI
    00404075 E8 8B0F0000 CALL UnPackMe.00405005
    0040407A 89C7 MOV EDI,EAX
    0040407C 57 PUSH EDI
    0040407D B8 0D000000 MOV EAX,0D
    00404082 50 PUSH EAX
    00404083 E8 4D030000 CALL UnPackMe.004043D5
    00404088 89C6 MOV ESI,EAX
    0040408A 56 PUSH ESI
    0040408B E8 750F0000 CALL UnPackMe.00405005


    Problem is that OEP should be at 404000. That couple instructions are junk now, and they where probably obfuscated trough obsidium layer. But in this crackme, those few bytes are not important and file will work without it, so just leave it like that. So, make dump now.





    3. Imports

    Ah, imports are realy pain in the ass. If you check where calls lead, you will see this:

    00B00000 60 PUSHAD
    00B00001 66:BE 22A2 MOV SI,0A222
    00B00005 B7 66 MOV BH,66
    00B00007 -E9 1D5489FF JMP 00395429
    00B0000C 60 PUSHAD
    00B0000D 66:BE 23A2 MOV SI,0A223
    00B00011 B7 66 MOV BH,66
    00B00013 -E9 115489FF JMP 00395429
    00B00018 60 PUSHAD
    00B00019 66:BE 20A2 MOV SI,0A220
    00B0001D B7 66 MOV BH,66
    00B0001F -E9 055489FF JMP 00395429
    ...
    ...

    Import call goes in some obsidium procedure. There, obsidim doesn't use GetProcAddress. Intead, import is saved as

    - dll image base (handle),
    - some flag (FFFFFFFF is good one),
    - import code (which is 2,4,1,80, or 40),
    - first character of import,
    - CRC32 hash.


    Obsidium will get info which dll program needs, then it will do some internal checks (is this import already used, is it emulated whole or partially, etc...), then it will search in that DLL export (which is our import) which first character corespond with one in "obsidium import info" table, then it will search for such import which CRC32 hash is equal to one in table. When it finds it, then it will do some emulation and finaly jump to it.




    Let's see on one example, our import call:

    00404453 |. FF15 08124000 CALL DWORD PTR DS:[401208]

    leads to

    00B000B4 60 PUSHAD
    00B000B5 66:BE 25A2 MOV SI,0A225 <------ These two values gives info about host DLL.
    00B000B9 B7 67 MOV BH,67 <--------/
    00B000BB -E9 695389FF JMP 00395429

    then

    MOVZX EDX,BH
    MOVZX EAX,SI
    CALL 00395434
    POP EBX
    MOV EBP,EBX
    MOV EBX,DWORD PTR DS:[EBX-74]
    SUB EBP,0B8A0CB
    CALL 00395445
    ADD DWORD PTR SS:[ESP],0D
    MOV ECX,DWORD PTR SS:[EBP+B8A0BC]
    CALL ECX
    RETN
    MOV ESI,DWORD PTR DS:[EBX+44]
    XOR DL,BYTE PTR SS:[EBP+B8A18C]
    XOR AX,WORD PTR SS:[EBP+B8A18D]
    SHL EDX,3
    MOV ECX,EDX
    SHL EDX,1
    ADD ECX,EDX
    LEA EDI,DWORD PTR DS:[ESI+ECX+4]
    CMP DWORD PTR DS:[EDI+4],0 <---------- [1] Check, probably is DLL loaded. Must be FFFFFFFF.
    JE 0039568C
    ADD ESI,DWORD PTR DS:[EDI+14]
    LEA ESI,DWORD PTR DS:[ESI+EAX*8]
    MOVZX EAX,WORD PTR DS:[ESI] <--------- [2] It takes from table "import code" (2,4,1,80, or 40).
    CMP EAX,4
    JE 00395522
    CMP EAX,1
    JE SHORT 003954F8
    CMP EAX,80
    JE 00395754
    CMP EAX,40
    JE 0039554E
    MOVZX EAX,WORD PTR DS:[ESI+2]
    PUSH 1
    PUSH EAX
    PUSH 0
    PUSH DWORD PTR DS:[ESI+4]
    PUSH DWORD PTR DS:[EDI]
    CALL DWORD PTR DS:[EBX+50] <--------- If "import code" is 2, it finds that import here.
    TEST EAX,EAX <----------------------- [3] EAX will be API value.
    JNZ SHORT 0039550A


    Most of imports in some file are "code 2" type. It is just what type of obfuscation obsidium will use.




    I repaired imports like this using OllyScript. First, this is import table in our unpackme:

    0040119C 00 00 B0 00 0C 00 B0 00 18 00 B0 00 24 00 B0 00 ............$...
    004011AC 30 00 B0 00 3C 00 B0 00 48 00 B0 00 54 00 B0 00 0...<...H...T...
    004011BC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004011CC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004011DC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004011EC 60 00 B0 00 6C 00 B0 00 78 00 B0 00 84 00 B0 00 `...l...x.......
    004011FC 90 00 B0 00 9C 00 B0 00 A8 00 B0 00 B4 00 B0 00 ................
    0040120C C0 00 B0 00 CC 00 B0 00 D8 00 B0 00 E4 00 B0 00 ................

    It is very small. I placed breakpoints on [1], [2] and [3] lines in obsidium code. Then I wrote small script that will find one import call, place eip=that_line, run, check if DLL is OK [1] , check if "import code" is 2 [2], and in that case it will break on [3]. There eax holds correct import, now my script will take that API, place it in IAT, restore stack to default value and go searching for next one.

    Basicly, I'm just using obsidium import algorithm against itself. Better would be, ofcourse, to code some app or plugin that could just do this by itself. After using script, IAT is:

    0040119C 6E ED D4 77 BB D7 D4 77 7C B5 D4 77 0B 05 D8 77 n..w...w|..w...w
    004011AC B2 02 D7 77 54 05 D5 77 9F F2 D6 77 54 00 B0 00 ...wT..w...wT...
    004011BC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004011CC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004011DC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    004011EC 60 00 B0 00 37 97 80 7C 29 B5 80 7C 2D FF 80 7C `...7..|)..|-..|
    004011FC 2F FE 80 7C D4 05 91 7C AE 30 82 7C 29 29 81 7C /..|...|®0.|)).|
    0040120C 10 11 81 7C 3D 04 91 7C B9 8F 83 7C E4 00 B0 00 ...|=..|...|....

    Three imports are not repaired because they are not "code 2" type. I could write new script for those types, or rewrite this one, but that would first need examning obsidium code again (I'm little tired now) , so I will just try to fix it manually.


    If I check "all intermodular calls", I see that only one call is bad:

    0040404A CALL DWORD PTR DS:[4011EC] DS:[004011EC]=00B00060
    00404EF2 CALL DWORD PTR DS:[40119C] USER32.CallNextHookEx
    00404F89 CALL DWORD PTR DS:[4011F0] kernel32.GetCurrentThreadId
    00404C66 CALL DWORD PTR DS:[4011A0] USER32.GetDesktopWindow
    00404019 CALL DWORD PTR DS:[4011F4] kernel32.GetModuleHandleA
    00404C7F CALL DWORD PTR DS:[4011A4] USER32.GetWindowRect
    004057CE CALL DWORD PTR DS:[4011F8] kernel32.GlobalAlloc
    00405614 CALL DWORD PTR DS:[4011FC] kernel32.GlobalFree
    00404622 CALL DWORD PTR DS:[401204] kernel32.HeapCompact
    00404453 CALL DWORD PTR DS:[401208] kernel32.HeapCreate
    00404584 CALL DWORD PTR DS:[40120C] kernel32.HeapDestroy
    00404326 CALL DWORD PTR DS:[401214] kernel32.lstrcatA
    00404FC9 CALL DWORD PTR DS:[4011A8] USER32.MessageBoxA
    004045EF CALL DWORD PTR DS:[401200] ntdll.RtlAllocateHeap
    0040463E CALL DWORD PTR DS:[401200] ntdll.RtlAllocateHeap
    004046DD CALL DWORD PTR DS:[401210] ntdll.RtlFreeHeap
    00404FA4 CALL DWORD PTR DS:[4011AC] USER32.SetWindowsHookExA
    00404C17 CALL DWORD PTR DS:[4011B0] USER32.SystemParametersInfoA
    00404FDB CALL DWORD PTR DS:[4011B4] USER32.UnhookWindowsHookEx

    I traced that call, it is "code 40" type which then lead to ExitProcess:

    0039562E FFD0 CALL EAX ; kernel32.ExitProcess

    When I found that import, I repaired dump and it worked.






    4. Final words

    Altough target works, job is not completed. Stolen OEP code can be easily restored if target is not compiled in ASM since obsidium steals only few opcodes. Imports that are not used in target need to be examned.

    Obsidium has some more tricks like relocating image and little different import protection, but I will maybe onother tutorial on obsidium. It jus needs little more researching.


    I hope that this tutorial will be of some use to somebody. Scripts that I used are included in archive, OEP one should work one evry Obsidium 1.2.5.0 target, while IAT one needs to be used as described in this tutorial. I'm not sure will my dump work on other machines, this was simply first touch on this good protector.

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

    پيش فرض

    Level : newbie

    Victim: MSN Messenger
    Goal: Patching it so we can run multiple sessions at once instead of just one.
    Tools: A Debugger (I use Ollydbg)
    Author: Devoney




    --------------------------------------------------------------------------------
    intro:
    When you already have a MSN running you can not launch another MSN at the same time of the same version. When creating your own program you have to build in some security if you want people to be able to run only one session at the same time. So MSN has a moment where it checks if there is a previous version running. We need to find out where that is!



    Get to work:
    Ok, open msnmsgr.exe with your favorite debugger. Normally its localized in this dir: C:Program FilesMSN Messenger. Now set a breakpoint on every reference on th CreateEvent API. Maybe you will notice that its CreateEventA in MSN. The A only stand for 32-bit. Now run the program tru the debugger (in ollydbg press F9 or the play button). The debugger probarly breaks a couple of times, not much. In my case it breaks 3 times. Now we are not interested in all those CreateEventA moments. We are only interested in this piece of code:

    005575E3 |> 68 4C4A4100 PUSH msnmsgr.00414A4C ; /EventName = "MSNMSGR"
    005575E8 |. 53 PUSH EBX ; |InitiallySignaled
    005575E9 |. 6A 01 PUSH 1 ; |ManualReset = TRUE
    005575EB |. 53 PUSH EBX ; |pSecurity
    005575EC |. FF15 58134000 CALL DWORD PTR DS:[; CreateEventA

    The addresses might differ from yours but the way the security is coded is the same in every MSN so far. Take a look at the EventName (the first parameter pushed). Its MSNMSGR.

    Now read this:
    "Return Values
    A handle to the event object indicates success. If the named event object existed before the function call, the function returns a handle to the existing object and GetLastError returns ERROR_ALREADY_EXISTS. NULL indicates failure. To get extended error information, call GetLastError."

    Now scroll a couple of lines down in the code of the debugger and notice this piece:
    00557600 |. FF15 74144000 CALL DWORD PTR DS:[; [GetLastError
    00557606 |. 3D B7000000 CMP EAX,0B7
    0055760B |. 0F85 B5010000 JNZ msnmsgr.005577C6

    So GetLastError api checks the value which was returned from CreateEventA. It compares it with 0B7. 0B7 probarly is the hex value for constant which says SUCCES or somekind. When there is no SUCCES (so there is already a version running) the API CreateEvent does not return SUCCES. And EAX wont be 0B7. So this jump isn't made when there is already a version running. So we have to be sure the jump is made no mather what! SO change the JNZ (which is a conditional jump) to a unconditional jump JMP. (still to the same address ofcourse). Now save the modifcations. In Ollydbg you do that by right mouse click in the screen -> Copy to executable -> All Modifications -> Copy All -> Right mouse button in the new screen -> Save file. (this is not exactly the same for older versions of ollydbg.)

    Now start the app as many times if you like and you see that it does not terminated itself anymore when there is another session running.

    We could also speed up the code little. This jump can be made earlier because CreateEvent is not neccesary because the result of the checkup isn't important anymore. So go back to the CreateEventA api. Replace the first Parameter pushed "PUSH 414A4C" by "JMP " (in my case the address is "005577C6").

    Outro:
    Hopefully you have understood what I was trying to explain and that you have learned out of this! How did I know it was all about this CreateEvent? I started to set a breakpoint on ExitProcess and worked my way back to see where it came from when there was already a version of msn running. Then I compared the code when there was no MSN running so that I knew I was not too far already. Finally after 2 hours I ended up with CreateEvent.

    Devoney

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

    پيش فرض

    Level : beginner

    =======================
    PESpin 1.304 public - repairing IAT
    =======================



    This version of PESpin is completly indentical as previous 1.3. There are no new things in this public version interesting for unpacking, because this version is out just for compability issues. But in previous tutorials there was no explanation for proper IAT fixing , just some tricks to run dump on user machine, so that part will be covered in this tutorial better.




    1. Tools and stuff

    Tools are usual:

    - OllyDbg 1.10
    - ImpREC
    - LordPE
    - Windows XP


    This tutorial will be short, so it would not be bad that you check previous ones which are more detailed.




    2. OEP and stolen code

    If you remember from past tutorials, last API that PESpin will use before jumping to OEP is GetTickCount. It will probably use it to get some random value, to destroy code/data that it doesn't need anymore. So we can place breakpoint at the end of that API (PESpin checks first bytes for CC bytes) and return to protectors code. So we are now very close to OEP jump. PESpin will use long jump to jump into original code section. So we can go to beggining of this PESpin section and search for bytes E9??????FF which corespond to long jump. Then we find all those possible jumps and first one that jumps in 401000 section is good one. I found this jump:

    00417BC4 -E9 0F9AFEFF JMP KeygenMe.004015D8

    But PESpin also can stole some bytes from OEP, as said before. That stolen code is obfuscated, but it always start with POPAD opcode which is 61 in hexadecimal. So scroll up and search for this byte. You will find it obfuscated within call opcode:

    00417AD8 E8 61F7D239 CALL 3A14723E

    Patch first byte:

    00417AD8 90 NOP
    00417AD9 61 POPAD

    Now place bp on POPAD , run and you will break there. There starts execution of stolen code, right after POPAD. But stolen bytes are obfuscated with junk code. It is not big problem to find it if we know that our target is Visual C++ program. Code obfuscation isn't hard and I can find exact bytes:


    00417B36 55 PUSH EBP
    00417B3A 8BEC MOV EBP,ESP
    00417B3F 6A FF PUSH -1

    00417B44 68 3482111F PUSH 1F118234 <------------------ These 4 opcodes are just obfuscation of two PUSH.
    00417B49 812C24 6421D11E SUB DWORD PTR SS:[ESP],1ED12164
    00417B50 68 48F020F7 PUSH F720F048
    00417B55 810424 B03D1F09 ADD DWORD PTR SS:[ESP],91F3DB0

    00417B5C 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
    00417B65 50 PUSH EAX
    00417B69 64:8925 00000000 MOV DWORD PTR FS:[0],ESP
    00417B73 83EC 58 SUB ESP,58
    00417B79 53 PUSH EBX
    00417B7D 56 PUSH ESI
    00417B81 57 PUSH EDI
    00417B85 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
    00417B8B FF15 CDA44100 CALL DWORD PTR DS:[41A4CD] <---- Obfuscated API call!
    00417B94 33D2 XOR EDX,EDX
    00417B99 8AD4 MOV DL,AH
    00417B9E 8915 5C764000 MOV DWORD PTR DS:[40765C],EDX
    00417BA7 8BC8 MOV ECX,EAX
    00417BAC 81E1 FF000000 AND ECX,0FF
    00417BB5 890D 58764000 MOV DWORD PTR DS:[407658],ECX
    00417BBE C1E1 08 SHL ECX,8
    00417BC4 -E9 0F9AFEFF JMP KeygenMe.004015D8 <------ Not stolen, it's jump to false OEP.

    And we can restore later those bytes. But these 4 ones:

    PUSH 1F118234
    SUB DWORD PTR SS:[ESP],1ED12164
    PUSH F720F048
    ADD DWORD PTR SS:[ESP],91F3DB0

    with:

    PUSH 4060D0
    PUSH 402DF8


    But all that is not necessery at all. We could just dump at this line:

    00417B36 55 PUSH EBP

    and dump would be good. Just OEP would be in PESpin section and not in first one.




    3. Redirected code

    If we execute OEP jump:

    00417BC4 -E9 0F9AFEFF JMP KeygenMe.004015D8

    we will be in code section where we can see redirected code

    004015EB . E8 E8EBFFFF CALL KeygenMe.004001D8

    It is all well known from previous version. CALL leads to

    004001D8 -E9 E6160000 JMP KeygenMe.004018C3

    and that JMP just returns to some location. So CALL to PE header was in original file CALL to some address.



    Second redirection looks like this:

    0040169E .-E9 95EBFFFF JMP KeygenMe.00400238

    jumps to

    00400238 68 FF000000 PUSH 0FF <--------------- This is redirected opcode.
    0040023D -E9 61140000 JMP KeygenMe.004016A3 <-- Returning back.

    Jumps are substitution pushes.



    There is new redirection that I didn't see in 1.3 version of PEspin:

    00401687 $-E9 94EBFFFF JMP KeygenMe.00400220
    0040168C 90 NOP
    0040168D 90 NOP

    jumps to

    00400220 833D 38764000 01 CMP DWORD PTR DS:[407638],1 <------ Redirected code.
    00400227 -E9 62140000 JMP KeygenMe.0040168E <------------ Returning back.



    And now I can write small script for OllyScrip plugn that can fix that code. See it in attachment. That script will work (it should) for all 1.x versions of PESpin.

    Blocks of code that are decrypted during runtime, so called "clear and crypt markers" will not be discussed in this tutorial. Check last one for that.

    And that is almost all. Just IAT is left to fix




    4. Problem with IAT

    This is not hard problem, but in previous tutorial I didn't have enough knowlege about ImpREC, PE structure, etc. First we need to see what happened with our imports and then we will think how to fix them. I was placing breakpoints on LoadLibraryA and GetProcAddress to catch where imports are being processed, but I found nothing. That means PESpin doesn't use use those api's to load libraries and find api's, instead it may have custom coded functions to do such job. Then I checked already loaded modules when target is opened in olly and sow that all needed dll's are already loaded by windows loader:

    Executable modules
    Base Size Entry Name File version Path
    00400000 0001C000 004160D4 KeygenMe D:PESpinPESpin v1.304KeygenMe.exe
    77340000 0008B000 773419ED COMCTL32 5.82 (xpsp1.0208 C:WINDOWSsystem32COMCTL32.DLL
    77D40000 0008C000 77D53A05 USER32 5.1.2600.1561 (x C:WINDOWSsystem32USER32.DLL
    77DD0000 0008D000 77DD1D3D ADVAPI32 5.1.2600.1106 (x C:WINDOWSsystem32ADVAPI32.dll
    77E60000 000E6000 77E7ADB3 kernel32 5.1.2600.1560 (x C:WINDOWSsystem32kernel32.dll
    77F50000 000A7000 ntdll 5.1.2600.1106 (x C:WINDOWSSystem32ntdll.dll
    78000000 00087000 78001E0D RPCRT4 5.1.2600.1361 (x C:WINDOWSsystem32RPCRT4.dll
    7F000000 00041000 GDI32 5.1.2600.1561 (x C:WINDOWSsystem32GDI32.dll

    If I just run target in olly, no new module is loaded. That give us first possible answer why LoadLibraryA isn't used. Actually it is used couple times, but not for API redirecting purpose. GetProcAddress is also used couple times but not for our api's. So I tok another approach to save time tracing trough code.


    Let's find OEP and see where first import jump leads. This is first import jump, ie. call:

    00401605 . FF15 C8A44100 CALL DWORD PTR DS:[41A4C8]

    we see that is points to PESpin section and not to 406000 which should be IAT one. Check dump at that address:

    0041A4C8 4B 02 3B 00 00 6A 02 3B 00 00 8E 02 3B 00 00 A9 K.;..j.;....;..©
    0041A4D8 02 3B 00 00 BD 02 3B 00 00 DD 02 3B 00 00 F9 02 .;....;....;....
    0041A4E8 3B 00 00 11 03 3B 00 00 30 03 3B 00 00 48 03 3B ;....;..0.;..H.;
    ...

    We see that PESpin created table with pointers to 003B0000 section. Pointer dwords are separated with 0 bytes. That probably disturb ImpREC to get table, because pointers should be separated with zero terminating dword. And pointer leads to obfuscated api jump, or whole emulated api (if it's very small one, just one line):

    003B024B EB 01 JMP SHORT 003B024E
    003B024D D9A1 1476ED77 FLDENV (28-BYTE) PTR DS:[ECX+77ED7614]
    003B0253 C3 RETN

    It is easy to write small script for Olly that could rebuild new table, but we can remove obfuscation from import jumps. As easies option, I decide to place memory breakpoint on 003B0000 section so I could find place where PESpin writes obfuscated code there. Ok, bp on VirtualAlloc, and wait untill it allocates that section. Then memory bp on it. And I stopped here:

    00416BCE 66:C706 EB01 MOV WORD PTR DS:[ESI],1EB
    00416BD3 C646 02 D9 MOV BYTE PTR DS:[ESI+2],0D9
    00416BD7 83C6 03 ADD ESI,3
    00416BDA 2BD2 SUB EDX,EDX
    00416BDC EB 01 JMP SHORT KeygenMe.00416BDF
    00416BDE EA EB04EAEB 0400 JMP FAR 0004:EBEA04EB
    ...
    ...

    PESpin writes here something. We are in part of code where obfuscation is in progress. If we remember from previous tutorial, this procedure starts with POPAD and ends with PUSHAD. Scroll up to find PUSHAD:

    00416BAF 60 PUSHAD <----------------------- Yep, here it is.
    00416BB0 EB 01 JMP SHORT KeygenMe.00416BB3
    00416BB2 ^71 EB JNO SHORT KeygenMe.00416B9F
    00416BB4 04 D5 ADD AL,0D5
    00416BB6 EB 04 JMP SHORT KeygenMe.00416BBC
    00416BB8 6BEB FB IMUL EBP,EBX,-5
    ...
    ...

    We are very close to the end of our task, Place hardware bp on execution on that PUSHAD and restart target. Run it in Olly and you should break there. Ance again, in previous tutorial we sow that this procedure can be NOP-ed from PUSHAD to POPAD and we will kill obfuscation:

    00416BAF 60 PUSHAD
    00416BB0 90 NOP
    00416BB1 90 NOP
    00416BB2 90 NOP
    ...
    ...
    ...
    00416C95 90 NOP
    00416C96 90 NOP
    00416C97 90 NOP
    00416C98 61 POPAD
    00416C99 C9 LEAVE
    00416C9A C2 0800 RETN 8

    This code also isn't checked with integrity checks so we can just leave it. Now we find stolen code like described in first part of this tutorial (beware, GetTickCount is already used so you need find address of code before this step), and we restore it on right OEP:

    00401591 /. 55 PUSH EBP
    00401592 |. 8BEC MOV EBP,ESP
    00401594 |. 6A FF PUSH -1
    00401596 |. 68 D0604000 PUSH KeygenMe.004060D0
    0040159B |. 68 F82D4000 PUSH KeygenMe.00402DF8 ; SE handler installation
    004015A0 |. 64:A1 00000000 MOV EAX,DWORD PTR FS:[0]
    004015A6 |. 50 PUSH EAX
    004015A7 |. 64:8925 000000>MOV DWORD PTR FS:[0],ESP
    004015AE |. 83EC 58 SUB ESP,58
    004015B1 |. 53 PUSH EBX
    004015B2 |. 56 PUSH ESI
    004015B3 |. 57 PUSH EDI ; KeygenMe.004188EA
    004015B4 |. 8965 E8 MOV DWORD PTR SS:[EBP-18],ESP
    004015B7 |. FF15 CDA44100 CALL DWORD PTR DS:[41A4CD] ; kernel32.GetVersion
    004015BD |. 33D2 XOR EDX,EDX
    004015BF |. 8AD4 MOV DL,AH
    004015C1 |. 8915 5C764000 MOV DWORD PTR DS:[40765C],EDX
    004015C7 |. 8BC8 MOV ECX,EAX
    004015C9 |. 81E1 FF000000 AND ECX,0FF
    004015CF |. 890D 58764000 MOV DWORD PTR DS:[407658],ECX
    004015D5 |. C1E1 08 SHL ECX,8

    Then we use script for fixing redirected code.




    5. Fixing IAT

    And now we can fix IAT. I wrote small script just for this VC++ app that will change all pointers to new tab. Example, this call:

    004015B7 |. FF15 CDA44100 CALL DWORD PTR DS:[41A4CD] ; kernel32.GetVersion

    will now point to new place

    004015B7 |. FF15 90604100 CALL DWORD PTR DS:[416090] ; kernel32.GetVersion

    and there I created new tab:

    00416000 00 00 00 00 00 00 00 00 E0 56 D6 77 00 00 00 00 .........V.w....
    00416010 1F 97 D4 77 00 00 00 00 1D 5F D4 77 00 00 00 00 ...w....._.w....
    00416020 52 65 D6 77 00 00 00 00 52 65 D6 77 00 00 00 00 Re.w....Re.w....
    00416030 52 65 D6 77 00 00 00 00 E4 D9 D4 77 00 00 00 00 Re.w.......w....
    00416040 FE 65 D6 77 00 00 00 00 FE 65 D6 77 00 00 00 00 .e.w.....e.w....
    00416050 >FE 65 D6 77 00 00 00 00 0F 6E D5 77 00 00 00 00 .e.w.....n.w....
    00416060 >0F 6E D5 77 00 00 00 00 0F 6E D5 77 00 00 00 00 .n.w.....n.w....
    00416070 93 5A E7 77 00 00 00 00 0C 16 E6 77 00 00 00 00 .Z.w.......w....
    00416080 53 95 E7 77 00 00 00 00 A1 16 F5 77 00 00 00 00 S..w.......w....
    00416090 95 D0 E7 77 00 00 00 00 AB E2 E7 77 00 00 00 00 ...w.......w....
    004160A0 7E 17 E6 77 00 00 00 00 D9 AC E7 77 00 00 00 00 ~..w.......w....
    004160B0 63 98 E7 77 00 00 00 00 25 E2 E7 77 00 00 00 00 c..w....%..w....
    004160C0 7C 88 E7 77 00 00 00 00 A1 16 F5 77 00 00 00 00 |..w.......w....
    004160D0 6B 15 F5 77 00 00 00 00 5F 8C F5 77 00 00 00 00 k..w...._..w....
    004160E0 A1 16 F5 77 00 00 00 00 C5 AB E7 77 00 00 00 00 ...w.......w....
    004160F0 6B 15 F5 77 00 00 00 00 C5 AB E7 77 00 00 00 00 k..w.......w....
    00416100 0C E6 E7 77 00 00 00 00 B8 16 E6 77 00 00 00 00 ...w.......w....
    00416110 63 98 E7 77 00 00 00 00 95 9B E9 77 00 00 00 00 c..w.......w....
    00416120 FC AC E7 77 00 00 00 00 3B 95 E6 77 00 00 00 00 ...w....;..w....
    00416130 E8 E4 E7 77 00 00 00 00 3B 95 E6 77 00 00 00 00 ...w....;..w....
    00416140 2F E0 E9 77 00 00 00 00 7E 17 E6 77 00 00 00 00 /..w....~..w....
    00416150 4E E3 E7 77 00 00 00 00 E7 E3 E7 77 00 00 00 00 N..w.......w....
    00416160 4E E3 E7 77 00 00 00 00 A4 E2 E7 77 00 00 00 00 N..w.......w....
    00416170 FC AC E7 77 00 00 00 00 E7 E3 E7 77 00 00 00 00 ...w.......w....
    00416180 8D F0 E7 77 00 00 00 00 53 95 E7 77 00 00 00 00 ...w....S..w....
    00416190 1B E0 E7 77 00 00 00 00 7F C9 E6 77 00 00 00 00 ...w.......w....
    004161A0 7F C9 E6 77 00 00 00 00 4F A7 E7 77 00 00 00 00 ...w....O..w....
    004161B0 4F A7 E7 77 00 00 00 00 1B E0 E7 77 00 00 00 00 O..w.......w....
    004161C0 B1 E2 E7 77 00 00 00 00 B1 E2 E7 77 00 00 00 00 ...w.......w....
    004161D0 6B 15 F5 77 00 00 00 00 A1 16 F5 77 00 00 00 00 k..w.......w....
    004161E0 B4 D8 E7 77 00 00 00 00 D1 DD E7 77 00 00 00 00 ...w.......w....
    004161F0 84 9F E7 77 00 00 00 00 84 9F E7 77 00 00 00 00 ...w.......w....
    00416200 4F A7 E7 77 00 00 00 00 4F A7 E7 77 00 00 00 00 O..w....O..w....
    00416210 D1 DD E7 77 00 00 00 00 D1 DD E7 77 00 00 00 00 ...w.......w....
    00416220 D1 DD E7 77 00 00 00 00 9C A8 E7 77 00 00 00 00 ...w.......w....
    00416230 E8 D8 E7 77 00 00 00 00 23 5D E7 77 00 00 00 00 ...w....#].w....
    00416240 23 5D E7 77 00 00 00 00 B1 E2 E7 77 00 00 00 00 #].w.......w....
    00416250 4F A7 E7 77 00 00 00 00 4F A7 E7 77 00 00 00 00 O..w....O..w....
    00416260 E8 D8 E7 77 00 00 00 00 B4 90 E6 77 00 00 00 00 ...w.......w....
    00416270 A1 16 F5 77 00 00 00 00 5F 8C F5 77 00 00 00 00 ...w...._..w....
    00416280 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
    00416290 C2 25 E7 77 00 00 00 00 DE AF E7 77 00 00 00 00 .%.w.......w....
    004162A0 44 0C F6 77 00 00 00 00 00 00 00 00 00 00 00 00 D..w............
    004162B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ...............


    Now we have thunks where every import value is separated with 4 zero terminating bytes and ImpREC can easily read this. Now we just run ImpREC and fix dumped file. Save file, run,..., yep, it works


    It is not perfect work because thunks that belong to same dll should be sticked together which would reduce size of file, also we could remove PESpin section, but hey, now dump works on every machine

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

    پيش فرض

    Level : intermediate

    ==============================================
    ASProtect 2.0 - unpacking and repairing IAT
    ==============================================




    1. Tools and stuff

    In this tutorial we will see how can ASPR 2.0 be unpacked manually. It is not so hard , but you should have experience in manually unpacking, some knowledge about PE structure, and ASProtect shouldn't be new to you. If you never played with ASPR before, check my tutrial about ASPR 1.23RC4 that will intruduce you.

    Target for this tutorial is black-eye's "nightmare keygenme". I think that it is protected with all options that ASPR2.0 has.

    - Windows XP
    - OllyDbg 1.10
    - ImpREC
    - LordPE
    - hex editor




    2. OEP and stolen code

    After loading target in Olly, I ignored all exceptions and just runned target trough olly. After keygenme opened, I checked log window to see what exceptions ASPR produced:

    ************************************************** ********************
    Log data
    Address Message
    77C00000 Module C:WINDOWSsystem32version.dll
    71AD0000 Module C:WINDOWSSystem32wsock32.dll
    71AB0000 Module C:WINDOWSSystem32WS2_32.dll
    00987758 Access violation when writing to [00000000]
    00986BE6 Access violation when writing to [00000000]
    00986C6B Access violation when writing to [00000000]
    00986EA2 Access violation when writing to [00000000]
    0098703B Access violation when writing to [00000000]
    00987174 Access violation when writing to [00000000]
    009871BD Access violation when writing to [00000000]
    00984760 Access violation when writing to [00000000]
    009847D8 Access violation when writing to [00000000]
    00984966 Access violation when writing to [00000000]
    00984C0F Access violation when writing to [00000000]
    00984D5B Access violation when writing to [00000000]
    00984E3D Access violation when writing to [00000000]
    009872D8 Access violation when writing to [00000000]
    0098732F Access violation when writing to [00000000]
    009874F1 Access violation when writing to [00000000]
    009875AA Access violation when writing to [00000000]
    00987683 Access violation when writing to [00000000]
    0098341E INT3 command at 0098341E
    009850B4 Access violation when writing to [00000000]
    0098418C Access violation when writing to [00000000]
    00984328 Access violation when writing to [00000000]
    00985268 Access violation when writing to [00000000]
    00985389 Access violation when writing to [00000000]
    00986487 Access violation when writing to [00000000]
    00985616 Access violation when writing to [00000000]
    00985AAF Access violation when writing to [00000000]
    00985BF0 Access violation when writing to [00000000]
    0097CC59 Access violation when writing to [00000000]
    00985DD4 Access violation when writing to [00000000]
    00985F95 Access violation when writing to [00000000]
    00986050 Access violation when writing to [00000000]
    00987995 Access violation when writing to [00000000]
    00987A9A Access violation when writing to [00000000]
    00987C95 Access violation when writing to [00000000]
    00987EAD Access violation when writing to [00000000]
    0098806A Access violation when writing to [00000000]
    009881EF Access violation when writing to [00000000]
    009833BC INT3 command at 009833BC
    0098341E INT3 command at 0098341E
    00986807 Access violation when writing to [00000000]
    00986A16 Access violation when writing to [00000000]
    71AA0000 Module C:WINDOWSSystem32WS2HELP.dll
    ************************************************** *******************

    What we can see from this log? ASPR produces lot of memory acces violation exceptions and three INT3 ones. In many tutorials you can read "uncheck all exceptions and press Shift+F9 untill you reach last one...". In ASPR we can use exceptions for getting close to OEP, that is correct, but we can make that little bit easier. Since we have only three INT3 exceptions and two of them are very close to the end, we can ignore all exceptions and uncheck only INT3. Then we press Shift+F9 3 times to stop on last INT3, we place memory bp on CODE section, Shift+F9 again and we will break on false OEP:

    00406E1A E8 E1918900 CALL 00CA0000
    00406E1F 36:31D2 XOR EDX,EDX
    00406E22 8AD4 MOV DL,AH
    00406E24 8915 B4D04000 MOV DWORD PTR DS:[40D0B4],EDX
    00406E2A 89C1 MOV ECX,EAX
    00406E2C 81E1 FF000000 AND ECX,0FF
    00406E32 890D B0D04000 MOV DWORD PTR DS:[40D0B0],ECX
    00406E38 C1E1 08 SHL ECX,8
    00406E3B 01D1 ADD ECX,EDX
    00406E3D 890D ACD04000 MOV DWORD PTR DS:[40D0AC],ECX
    00406E43 C1E8 10 SHR EAX,10
    ...
    ...

    First call that you see is some redirected import and that will be explained in next part, but scroll up to see what happened with OEP code:

    00406DF4 -E9 7F937100 JMP 00B20178
    00406DF9 54 PUSH ESP
    00406DFA DEC0 FADDP ST,ST
    00406DFC 888F 99E23384 MOV BYTE PTR DS:[EDI+8433E299],CL
    00406E02 AD LODS DWORD PTR DS:[ESI]
    00406E03 0F71B7 30B961C3 >PSLLW QWORD PTR DS:[EDI+C361B930],0C4
    00406E0B 1B27 SBB ESP,DWORD PTR DS:[EDI]
    00406E0D 3A5E 01 CMP BL,BYTE PTR DS:[ESI+1]
    00406E10 A3 AA614693 MOV DWORD PTR DS:[934661AA],EAX
    00406E15 B1 4B MOV CL,4B
    00406E17 2F DAS
    00406E18 FA CLI
    00406E19 81E8 E1918900 SUB EAX,8991E1
    ...
    ...


    We can see lot of weird junky code. That is just garbage. Real code is redirected and obfuscated. Real OEP should be on this address instead this jump:

    00406DF4 -E9 7F937100 JMP 00B20178

    That jump leads to some block where stolen code is hidden. Follow that jump and you will find it:

    00B20178 55 PUSH EBP
    00B20179 89E5 MOV EBP,ESP
    00B2017B 6A FF PUSH -1
    00B2017D F3: PREFIX REP:
    00B2017E EB 02 JMP SHORT 00B20182
    00B20180 CD 20 INT 20
    00B20182 FF7424 1C PUSH DWORD PTR SS:[ESP+1C]
    ...
    ...
    00B20242 5E POP ESI
    00B20243 5B POP EBX
    00B20244 F3: PREFIX REP:
    00B20245 EB 02 JMP SHORT 00B20249
    00B20247 CD 20 INT 20
    00B20249 66:9D POPFW
    00B2024B ^E9 62FFFFFF JMP 00B201B2
    00B20250 F4 HLT
    00B20251 6D INS DWORD PTR ES:[EDI],DX
    00B20252 0000 ADD BYTE PTR DS:[EAX],AL
    00B20254 0000 ADD BYTE PTR DS:[EAX],AL
    00B20256 0000 ADD BYTE PTR DS:[EAX],AL
    ...
    ...

    Ofcourse, code is obfuscated. There is two ways for fixing stolen code. First way is to binary copy all that bytes and after dumping just attach them to main dump and set OEP there. Second way is to find exact bytes which is not hard, app is VC++ and since we know how VC++ OEP looks we know what to look for. I will leave this for end. That is easy job. But lets write down some important information:


    00406DF4 - jump to stolen code




    3. Import problems

    There is couple different ways how imports are processed.

    3.a) First way:

    First is that ASPR replaces import jumps/calls with calls:

    00406E1A E8 E1918900 CALL 00CA0000
    00406E1F 36:31D2 XOR EDX,EDX

    Instead this CALL CONSTANT (which is 5 bytes long opcode), in original file was CALL DWORD[IMPORT] (6 bytes long). Restarting target and placing memory breakpoint on that line will get us to place where ASPR writes this calls (we will break couple times before this location):

    0097377E 8BC0 MOV EAX,EAX
    00973780 53 PUSH EBX
    00973781 8BD8 MOV EBX,EAX
    00973783 8BC3 MOV EAX,EBX
    00973785 E8 56FFFFFF CALL 009736E0
    0097378A C603 E8 MOV BYTE PTR DS:[EBX],0E8 <----- Here it writes CALL
    0097378D 43 INC EBX
    0097378E 8903 MOV DWORD PTR DS:[EBX],EAX <---- And here it writes destination.
    00973790 5B POP EBX
    00973791 C3 RETN

    But check registers window:

    EAX 008991E1 <------------------------ Redirection destination.
    ECX 0012FF01
    EDX 008991E1
    EBX 00406E1A ASProtec.00406E1A <------ Address where import jump is.
    ESP 0012FEF0
    EBP 77E7D095 kernel32.GetVersion <---- This is API that is beeing redirected!
    ESI 00406E1C ASProtec.00406E1C
    EDI 009B48E8
    EIP 0097378A

    Since we see what API call should be there, we can change this code to write good import:

    00973780 66:C700 FF15 MOV WORD PTR DS:[EAX],15FF
    00973785 40 INC EAX ; ASProtec.004011A4
    00973786 40 INC EAX ; ASProtec.004011A4
    00973787 8910 MOV DWORD PTR DS:[EAX],EDX
    00973789 892A MOV DWORD PTR DS:[EDX],EBP ; kernel32.GetVersionExA
    0097378B 90 NOP
    0097378C 90 NOP
    0097378D 90 NOP
    0097378E 90 NOP
    0097378F 90 NOP
    00973790 90 NOP
    00973791 C3 RETN

    66 C7 00 FF 15 40 40 89 10 89 2A 90 90 90 90 90 90

    Now , our call will look like this:

    00406E1A . FF15 0000CA00 CALL DWORD PTR DS:[CA0000] ; kernel32.GetVersion
    00406E20 . 31D2 XOR EDX,EDX

    Not bad for start, keygenme works OK with all these calls changed altough this is not yet good for ImpREC.


    3.b) Second way:

    00401043 FF15 FC489B00 CALL DWORD PTR DS:[9B48FC] ; kernel32.CreateFileA

    Well, this is same thing as to what we bring our first example. We are skipping this for now.


    3.c) Third way:

    004030A8 FF15 8C499B00 CALL DWORD PTR DS:[9B498C]

    Again, memory bp on it and find the routine:

    0097CEAD 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C]
    0097CEB1 8902 MOV DWORD PTR DS:[EDX],EAX
    0097CEB3 8B4424 0C MOV EAX,DWORD PTR SS:[ESP+C]
    0097CEB7 8906 MOV DWORD PTR DS:[ESI],EAX <------- Here it writes pointer!
    0097CEB9 0FB74424 04 MOVZX EAX,WORD PTR SS:[ESP+4]
    0097CEBE 0143 08 ADD DWORD PTR DS:[EBX+8],EAX
    0097CEC1 ^E9 ADFDFFFF JMP 0097CC73 <--------------------- I have decided to redirect this jump.
    0097CEC6 3C 04 CMP AL,4
    0097CEC8 0F85 F4000000 JNZ 0097CFC2

    Again, check registeres:

    EAX 009B498C
    ECX 00000000
    EDX 009B498C <------------------------- Destination.
    EBX 009B04D4
    ESP 0012FEF8
    EBP 77D47DE3 user32.ReleaseCapture <--- API.
    ESI 004030AA ASProtec.004030AA <------- CALL pointer.
    EDI 009B48E8
    EIP 0097CEB7

    I will redirect jump to beggining of loader section because it has empty space there. Then I will inject code there that will write API where call points. Changing this:

    0097CEC1 ^E9 ADFDFFFF JMP 0097CC73

    to this:

    0097CEC1 ^E9 3A31FEFF JMP 00960000

    And there, injection:

    00960000 892A MOV DWORD PTR DS:[EDX],EBP <---- Place API to destination.
    00960002 E9 6CCC0100 JMP 0097CC73 <------------------ Return to normal ASPR code.

    After this , our api call looks:

    004030A8 FF15 8C499B00 CALL DWORD PTR DS:[9B498C] ; user32.ReleaseCapture


    Now I made one script that can do all these changes. After using it, target runs fine under Olly. Problem is that all this pointer needs to be placed inside main image of file. I explained how and way in many tutorials before, so I made new script that will do that. So I fixed IAT, then I dumped and attached OEP stolen code, and I used ImpREC to rebuild new IAT, but dump crashed. Why? Because VC++ has one more way to access imports.

    You see, usually imports are acessed via JMP DWORD PTR[API_HERE] or CALL DWORD PTR[API_HERE], but VC++ also uses

    MOV REGISTER,address
    JMP REGISTER

    where REGISTER holds API address, and couple more variations.


    3.d) Fourth way:

    Dump crashes at:

    00408208 8B2D F44A9B00 MOV EBP,DWORD PTR DS:[9B4AF4]

    I checked that line under Olly after using script:

    00408208 8B2D F44A9B00 MOV EBP,DWORD PTR DS:[9B4AF4] ; kernel32.GetEnvironmentStringsW

    Import is there. I should include it my script to move pointer in main image. Couple more examples:

    0040827D 8B3D 0C4B9B00 MOV EDI,DWORD PTR DS:[9B4B0C]
    0040344E 8B35 F8499B00 MOV ESI,DWORD PTR DS:[9B49F8]


    After including it in script, I used it, dumped, rebuilded IAT with ImpREC, attached stolen code and saved all that. I double clicked on keygenme and it opened just fine ! Yep, ASProtect 2.0 is defeated! Now try to keygen this crackme...



    4. Couple words for end

    Scripts that I have included here my not work for all other files packed with ASProtect 2.0. There are lot of builds of ASPR 2.0 which has some small differences that can disturb scripts. For example, script for finding OEP will not work if there is no stolen code. But this way of unpacking is pretty much the same for all ASPR 2.0 versions. Acctually, almost every ASPR version before 2.0 can be unpacked like this.


    And that would be all for this tutorial. See you in next one

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

    پيش فرض

    Level : beginner

    =========================
    Fishing and keygenning games CD keys
    =========================



    Maybe the best protection today are game protections. Although such protections are very hard to unwrap, it's interesting how their key checks stay very simple in most cases.
    Indeed, they are simple but the hardest problem is to actually find where the keygen algo lies in application. This tutorial will show a couple of examples on how game CD keys can be fished or keygened more or less with ease in some cases.



    1. HL1

    Half Life 1 is now pretty much old game from 10/30/98, but still impressive one and better than some todays. Game has very simple key check and this was first game that I manage to keygen. CD check is very simple too, but that is not objective of this tutorial. After installing game you will probably want to play it. At game start we get nice dialog asking us for game key. On inserting some fake key , we will normally get BadBoy message. Loading game exe in Olly, placing bp on GetWindowTextA, we can break when game is grabbing key from dialog:



    But main problem is to find where key check is. Games are big and find such algo is usually mayor problem. But after returning from api, I placed memory bp on serial in memory and found where algo reading it. This first check will read my serial:

    It will count how many there is digits in serial and if there is no 0D(hex) digits, I will get BadBoy message. That mean, serial can be long as we wish and non-numeric characters are not important. Conclusion – serial is all in numbers and it's length is 13.


    00442FB1 . 8A10 MOV DL,BYTE PTR DS:[EAX]
    00442FB3 . 84D2 TEST DL,DL

    00442FB5 . 74 0E JE SHORT hl.00442FC5
    00442FB7 . 80FA 30 CMP DL,30
    00442FBA . 7C 09 JL SHORT hl.00442FC5
    00442FBC . 80FA 39 CMP DL,39
    00442FBF . 7F 04 JG SHORT hl.00442FC5
    00442FC1 . 8813 MOV BYTE PTR DS:[EBX],DL
    00442FC3 . 43 INC EBX
    00442FC4 . 46 INC ESI
    00442FC5 > 40 INC EAX
    00442FC6 . 83FE 0D CMP ESI,0D 8D7D BC LEA EDI,DWORD PTR SS:[EBP-44]
    00442FCE . B9 FFFFFFFF MOV ECX,-1
    00442FD3 . 2BC0 SUB EAX,EAX
    00442FD5 . C603 00 MOV BYTE PTR DS:[EBX],0
    00442FD8 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
    00442FDA . F7D1 NOT ECX
    00442FDC . 49 DEC ECX
    00442FDD . 75 21 JNZ SHORT hl.00443000 85F6 TEST ESI,ESI
    00442FE3 . 0F84 A5000000 JE hl.0044308E


    I entered new serial to pass that check, 1111222233334. GoodBoy jump throws us below:

    00443000 > 8D45 BC LEA EAX,DWORD PTR SS:[EBP-44]
    00443003 . 8D4D F0 LEA ECX,DWORD PTR SS:[EBP-10]
    00443006 . 50 PUSH EAX
    00443007 . E8 D1020500 CALL hl.004932DD
    0044300C . C645 FC 04 MOV BYTE PTR SS:[EBP-4],4
    00443010 . E8 C2000000 CALL hl.004430D7
    00443015 . C645 FC 01 MOV BYTE PTR SS:[EBP-4],1
    00443019 . E8 C1000000 CALL hl.004430DF
    0044301E > 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
    00443021 . 8B4D EC MOV ECX,DWORD PTR SS:[EBP-14]
    00443024 . 50 PUSH EAX
    00443025 . E8 D6FCFFFF CALL hl.00442D00
    0044302A . 85C0 TEST EAX,EAX
    0044302C . 0F85 B8000000 JNZ hl.004430EA


    This TEST EAX,EAX and CALL abowe are interesting. Tracing in we can see another length check:


    00442D1C |. 83F9 0D CMP ECX,0D 33C0 XOR EAX,EAX
    00442D38 |. 5F POP EDI
    00442D39 . C2 0400 RETN 4


    If we pass that check, we enter to serial algo routine which is very small and simple:

    00401000 PUSH ESI
    00401001 MOV EAX,3 31-30=1,
    0040101D |XOR EDX,EDI

    That algo will take al characters except last one. Then that summ in EAX is divided by 0Ah and we get reminder in EDX. Reminder is placed in AL then, and to EDX is placed last

    00401026 MOV ECX,0A
    0040102B SUB EDX,EDX
    0040102D DIV ECX
    0040102F MOVSX EAX,DL


    And here is end. Remider must be equal to last character of serial. So my serial 111122223333(4) must be 111122223333(3) and CD key will be correct.

    2. STEF2

    Star Treck Elite Force 2 is shooting 3D game from 5/21/2003. Altough newer, keycheck is still very simple. Main problem would be to find actuall keycheck algorithm. Upon inserting CD and lounching installer, "CD key" dialog box shows:



    Todays games/games protections create couple temp files in temp folders which are actually dll’s. Some of those dll’s are checking CD key. But in this example, dll that check key is ordinal dll on CD, ef2dll.dll. There is also ef2dll.ini file in same folder. This ini file just holds GoodBoy/BadBoy messages.

    Easy approach for finding key routine is to attach Olly to main exe, which is probably install louncher. In this example, application gets key characters using GetWindowTextA api. After entering fake serial, Olly stopped in user32.dll on api. Returning from api brings me to subroutine which is part of another one:

    00AE13B0 . 53 PUSH EBX
    00AE13B1 . 56 PUSH ESI
    00AE13B2 . 8B7424 0C MOV ESI,DWORD PTR SS:[ESP+C] ; ef2dll.00AED059
    00AE13B6 . 57 PUSH EDI
    00AE13B7 . 8BF9 MOV EDI,ECX
    00AE13B9 . 8D5F 5C LEA EBX,DWORD PTR DS:[EDI+5C]
    00AE13BC . 53 PUSH EBX ; /Arg3 = 0013DAE8
    00AE13BD . 68 D0070000 PUSH 7D0 ; |Arg2 = 000007D0
    00AE13C2 . 56 PUSH ESI ; |Arg1 = 0013D4BC
    00AE13C3 . E8 34DC0000 CALL ef2dll.00AEEFFC ; ef2dll.00AEEFFC
    00AE13C8 . 6A 04 PUSH 4
    00AE13CA . 53 PUSH EBX
    00AE13CB . 56 PUSH ESI
    00AE13CC . E8 7DDC0000 CALL ef2dll.00AEF04E



    00AE1447 . E8 02DC0000 CALL ef2dll.00AEF04E
    00AE144C . 83C7 74 ADD EDI,74
    00AE144F . 57 PUSH EDI ; /Arg3 = 0013DA8C
    00AE1450 . 68 D5070000 PUSH 7D5 ; |Arg2 = 000007D5
    00AE1455 . 56 PUSH ESI ; |Arg1 = 0013D4BC
    00AE1456 . E8 A1DB0000 CALL ef2dll.00AEEFFC ; ef2dll.00AEEFFC
    00AE145B . 68 FF000000 PUSH 0FF
    00AE1460 . 57 PUSH EDI
    00AE1461 . 56 PUSH ESI
    00AE1462 . E8 E7DB0000 CALL ef2dll.00AEF04E
    00AE1467 . 5F POP EDI ; 00159448
    00AE1468 . 5E POP ESI ; 00159448
    00AE1469 . 5B POP EBX ; 00159448
    00AE146A . C2 0400 RETN 4


    This subroutine just collects characters from those 5 fields. And that routine is subroutine of main key check one:

    00AE1620 . 83EC 0C SUB ESP,0C
    00AE1623 . 53 PUSH EBX
    00AE1624 . 55 PUSH EBP
    00AE1625 . 56 PUSH ESI
    00AE1626 . 57 PUSH EDI
    00AE1627 . 8BE9 MOV EBP,ECX
    00AE1629 . 6A 01 PUSH 1
    00AE162B . C64424 17 00 MOV BYTE PTR SS:[ESP+17],0
    00AE1630 . C74424 1C E8A4>MOV DWORD PTR SS:[ESP+1C],ef2dll.00AFA4E>
    00AE1638 . E8 C7B90000 CALL ef2dll.00AED004
    00AE16FF . 8BCA MOV ECX,EDX
    00AE1701 . 83E1 03 AND ECX,3
    00AE1704 . F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
    00AE1706 . BF D8A4AF00 MOV EDI,ef2dll.00AFA4D8
    00AE170B . 83C9 FF OR ECX,FFFFFFFF
    00AE170E . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
    00AE1710 . F7D1 NOT ECX
    00AE1712 . 49 DEC ECX
    00AE1713 . 51 PUSH ECX
    00AE1714 . E8 9A8B0000 CALL ef2dll.00AEA2B3
    00AE1719 . 8BD8 MOV EBX,EAX
    00AE171B . BF D8A4AF00 MOV EDI,ef2dll.00AFA4D8
    00AE1720 . 83C9 FF OR ECX,FFFFFFFF
    00AE1723 . 33C0 XOR EAX,EAX
    00AE1725 . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
    00AE1727 . F7D1 NOT ECX
    00AE1729 . 2BF9 SUB EDI,ECX
    00AE172B . 68 D8A4AF00 PUSH ef2dll.00AFA4D8
    00AE1730 . 8BC1 MOV EAX,ECX
    00AE1732 . 8BF7 MOV ESI,EDI
    00AE1734 . 8BFB MOV EDI,EBX
    00AE1736 . C1E9 02 SHR ECX,2
    00AE1739 . F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
    00AE173B . 8BC8 MOV ECX,EAX
    00AE173D . 83E1 03 AND ECX,3
    00AE1740 . F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
    00AE1742 . E8 79FEFFFF CALL ef2dll.00AE15C0


    My serial is 11112222333344445555. In this call above, real serial will be calculated:

    00AE15C0 PUSH
    00AE15C1 MOV ESI,DWORD PTR SS:[ESP+8]
    00AE15C5 XOR EAX,EAX
    00AE15C7 XOR ECX,ECX
    00AE15C9 SUB ESI,ef2dll.00AFA4C0
    00AE15CF /MOV DL,BYTE PTR DS:[ESI+ECX+AFA4C0]


    So correct serial is 11112222333444457EF. That check will be performed below:

    00AE178F . BF D4A4AF00 MOV EDI,ef2dll.00AFA4D4 ; ASCII "57ef"
    00AE1794 . C1E9 02 SHR ECX,2
    00AE1797 . F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
    00AE1799 . 8BCA MOV ECX,EDX
    00AE179B . 83E1 03 AND ECX,3
    00AE179E . F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
    00AE17A0 . 33F6 XOR ESI,ESI
    00AE17A2 > 33C0 XOR EAX,EAX
    00AE17A4 . 8A86 D4A4AF00 MOV AL,BYTE PTR DS:[ESI+AFA4D4]
    00AE17AA . 50 PUSH EAX
    00AE17AB . E8 A20F0000 CALL ef2dll.00AE2752
    00AE17B0 . 8B7C24 1C MOV EDI,DWORD PTR SS:[ESP+1C]
    00AE17B4 . 33C9 XOR ECX,ECX
    00AE17B6 . 83C4 04 ADD ESP,4
    00AE17B9 . 8A0F MOV CL,BYTE PTR DS:[EDI]
    00AE17BB . 47 INC EDI
    00AE17BC . 3BC1 CMP EAX,ECX B2 01 MOV DL,1
    00AE17D2 > 8BFB MOV EDI,EBX
    00AE17D4 . 83C9 FF OR ECX,FFFFFFFF
    00AE17D7 . 33C0 XOR EAX,EAX
    00AE17D9 . 6A 00 PUSH 0
    00AE17DB . F2:AE REPNE SCAS BYTE PTR ES:[EDI]
    00AE17DD . F7D1 NOT ECX
    00AE17DF . 2BF9 SUB EDI,ECX
    00AE17E1 . 68 5C72AF00 PUSH ef2dll.00AF725C ; ASCII "CD Key"
    00AE17E6 . 8BC1 MOV EAX,ECX
    00AE17E8 . 8BF7 MOV ESI,EDI
    00AE17EA . BF D8A4AF00 MOV EDI,ef2dll.00AFA4D8
    00AE17EF . C1E9 02 SHR ECX,2
    00AE17F2 . F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS>
    00AE17F4 . 8BC8 MOV ECX,EAX
    00AE17F6 . 83E1 03 AND ECX,3
    00AE17F9 . 84D2 TEST DL,DL
    00AE17FB . F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[>
    00AE17FD . 74 13 JE SHORT ef2dll.00AE1812
    00AE17FF . 8B4D 7C MOV ECX,DWORD PTR SS:[EBP+7C]
    00AE1802 . 51 PUSH ECX
    00AE1803 . 8BCD MOV ECX,EBP
    00AE1805 . E8 9EB00000 CALL ef2dll.00AEC8A8 8B55 78 MOV EDX,DWORD PTR SS:[EBP+78]
    00AE1815 . 8BCD MOV ECX,EBP
    00AE1817 . 52 PUSH EDX
    00AE1818 . E8 8BB00000 CALL ef2dll.00AEC8A8


    As we sow, serial routine is very small and simple. It is easy to make small keygen that would give correct random keys and all games from this publisher (Activision) has similar algorithm , from older RTCW (2001) to newer Doom3 (2005).

    3. FF

    Freedom fighters is game from well known Electronic Arts developers. Date of game is 29-July-2003. Game has interesting registration algo, very easy to find it. In a one folder on CD, there is "Freedom Fighters_Code.exe" that is doing registration check. Running it gives registration dialog:



    Finding place where serial is taken from dialog is not easy since all api's that can do that are triggered numerous times. GetWindowsTextA is api that takes serial, but I tok different approach. On "Next>" click, program shows error message giving user information that serial is invalid. I just placed bp on MessageBoxA and found routine that calls it. Then I placed bp on beggining of that procedure. Rest was easy , just tracing and I found algo. However, there is second way. This registration app uses CRC32 table while producing serial. We can simply scan app with PEiD and found where is CRC32 referenced. And all EA games have same registration scheme (that means hundreds of games).

    Algo is little long so I want paste it here. I entered 1234567890ABCDEFGHIJ as serial. First algo creates CRC32 table with constants. Then it swaps places of 14 characters in my serial

    ASCII "1234567890ABCDEFGHIJ"

    ASCII "1IDJEF7G90ABH3568C24"


    It takes 13 chars from such serial and caculate some summ of it:

    ASCII "1IDJEF7G90ABH"

    16FA0346
    16FBC8B8

    then is some string calculated:

    ASCII "6MRZU9A"

    which is concated to 13 char one:

    ASCII "1IDJEF7G90ABH6MRZU9A"

    On a base of that string characters, algo picks dwords from CRC32 table and calculates some summ's and then new string is created:

    ASCII "FTGLRUP"

    again attached to that 13 chars:

    ASCII "1IDJEF7G90ABHFTGLRUP")

    and chars are swaped again like first time:

    ASCII "1UFPTG7L90ABRDEFGHIJ"

    And that makes valid CD key.

    Algo easily can be ripped for making generic keygen. As said before, ALL EA games from that year has same register algo. I sow that in "Medal Of Honnor - Paccific Assault" , algo is little different. They probably every year change algo a little.

    4. Conclusion

    As you can see, it is not so hard to fish serial or to keygen some game. Some games uses Wise Installer and there serial check differ because wise installer uses scripts (.msi files). In this case finding serial can be hard but there are some decompilers like "Wise For Windows Installer" that can help.
    Last edited by Morteza_SOS; 17-01-2008 at 09:26. دليل: اضافه کردن عکس ها

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

    پيش فرض

    Level : newbie

    Type: Patching
    Victim: Taskmgr.exe
    Protection: register value
    Tool: Ollydbg

    Intro:
    Ever had the problem when you try to start taskmanager it says it has been disabled by your administrator? Well that can be solved, off course There is place in the registry where you can disable or enable the use of Taskmg.exe (I am talking about the original one which comes with your windows installation).



    Get to work:
    Fire up ollydbg and open taskmgr.exe, (probably located in the system or system32 folder in your windows installation map). Get to the main window (press ALT + C to get there). You see a lot of code. Now go to the following line:

    010039EB |. FF15 28100001 CALL DWORD PTR DS:[; RegOpenKeyExW

    How did I get to this line? I was just searching for this api, since I know the security works by communicated with the registry to check if you are allowed to use Taskmgr.exe. You can not set a breakpoint on every reference of this api in ollydbg because it will generate some memory access errors (or something like that). So get to the line Right mouse button in the main window -> Goto -> Expression. Fill in the address of the line. Which will be 010039EB. Press ok. You can set a breakpoint here and check if ollydbg breaks.

    So this line you have found gets a value out the registry (which probably checks if you are allowed to access the taskmgr.exe). Take a look at the two lines below 010039EB.

    010039F1 |. 85C0 TEST EAX,EAX 010039F3 |. 74 6F JNZ SHORT TASKMGR.01003A64

    It checks the returned value of EAX, and it doesn’t jump when they returned value is zero. Look a bit further down the code and you will run into this line:

    01003A09 |. 68 98160001 PUSH TASKMGR.01001698 ; |ValueName = "DisableTaskMgr" 01003A0E |. FF75 EC PUSH DWORD PTR SS:[EBP-14] ; |hKey 01003A11 |. FF15 2C100001 CALL DWORD PTR DS:[; RegQueryValueExW

    You see it has a text line: DiableTaskMgr. That doesn’t sound very good. Now take a look at the conditional jump we saw earlier. If it DOES jump, it jumps to line 01003A64 and skips the lines which will disable you taskmgr.exe. So change that jump to JMP or JE so it does jump to skip the security check . (Change it by clicking on the code or by selecting the line and press SPACEBAR).

    Now rightmouse button in the mainwindow -> Copy to executable -> All modifications.
    Press copy call, a new window will pop-up. Right mouse button in that window and choose to save your file! Now open up your file and it should work now!

    Outro:
    I have included the original Taskmg.exe, the tutorial itself in .Doc format and the patched version (called Taskmgr_patched.exe) Hopefully you learned something and understood me.

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

    پيش فرض

    به نام خدا

    به زودی مقالات سطح متوسط و پیشرفته و فوق پیشرفته قرار می دهم .

Thread Information

Users Browsing this Thread

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

User Tag List

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

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