Saturday, July 08 2006 @ 07:14 PM CEST Contributed by: haggar Views: 12909
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.
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:
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
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:
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
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:
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:
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
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:
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:
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 , SND, CRACKMES.DE, .... and many more....
See you :-)
haggar (c) 2006
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.
//--------- Get loader base , Check & kill DebugBlocker , find OEP ----------
mov counter,0 //Counter, just to check is it first VirtualAlloc.
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 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.
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.
bp oep_call //Place breakpoint on OEP call.
cmp eip,alloc //Are we at VirtualAlloc?
and [AllocType],0FFFF //Yes? Then prevent allocating above 7xxxxxxx.
cmp counter,0 //Is it first stop?
mov loader,eax //Then get loader base.
cmt eip,"<-- I found OEP, imports are your problem."
//------------ Restore original bytes at CreateThread API --------------
dbs //Restore debugger.
msg "Error or aborted by user."