Hi and welcome to my tElock unpacking tutorial :)!
I was thinking to write more detailed tutorial about tElock, but such text would become too large and I didn't have strength to explain all things that I would love to say, so I wrote this shorter version. Consider this tutorial as a simple guideline for unpacking and not as brief explanation of tElock features.
Tutorial is dedicated for beginers who has some experience with simple packers and who are familiar with usuall tools like Olly, LordPE and ImpREC.
tElock 0.98 is simple protector. It's main features are:
- obfuscated code with exceptions, encrypted sections with couple layers
- some antidebug stuff
- first CRC check that checking is file modified
- second CRC check that checks file in memory and discover breakpoints
- imorts splitting and redirection, this is tE best weapon.
Our way of unpacking is:
- find OEP
- restore redirected imports
- dump file and use ImpREC to rebuild IAT.
3. EXAMING tElock CODE
3.1. tElock API's
Uncheck all exceptions in Olly options but those in KERNEL. Press Shift+F9 three times and you'll stop here:
When you came to this location, tE has already decrypted lot of code that it need for it's work. One part of that code is below this point. Scroll down and place bp on this place:
Now press Shift+F9 untill you break on your bp and then remove bp. In this procedure below, tE will search some API's names in kernel32.dll. Those API's tE needs for unpacking/protecting file. Search goes like this: tE will take name of every single API in kernel32.dll in alphabetic order, starting from the first one "ActivateActCtx" to the last, and compare it's name to the names that it has in it's own list. If some API name coresponds to one from list, it will take that API address and place it to some place for further usage. This is not important for our OEP finding, but it's interesting to see what API's tE uses. Let's see how it does. Trace with F7 untill you reach this line:
It will check does first 12 bytes/characters of API name corespnds to 64616F4C7262694C41797261 bytes. If you translate those bytes from ACII to characters, you will se that they mean "LoadLibraryA". First API that tE search is LoadLibrary. If you remember, I sad that tE has list of those API's, but as you can see, that list isn't in the form of of some strings written someware. List is made like bunch of comparations. Scroll down and you'll see that there is 12 more this similar comparations. That means that tE will use 13 API functions. Check next check:
Rest of 12 this checks all ends with jump to 406203 location. That mean, if API name is found, it will jump to this location so put bp on 406203 and press F9. After you break on bp, trace to this line:
Here, tE will store address of founded API to some location. Remove last bp and place new on to this line and press F9. You will see what is next API that tE wants. Do this 13 times and you'll see name of all API's:
That are some interesting API's. But let's go on. Place bp at
00406437 F8 CLC
and press F9, remove bp and trace further with F7. You will stuck on exception at address 004066A8, but nevermind that. Take a look below at:
004066DB 49 DEC ECX
004066DC ^7F ED JG SHORT Packed_I.004066CB
004066DE 3A82 C69E00CE CMP AL,BYTE PTR DS:[EDX+CE009EC6]
This is one decrypting loop that will decript code below that JG SHORT opcode. Place bp on JG SHORT instruction and press F9 untill you break on it. Leave bp and keep pressing F9 untill instruction below JG doesn't change to:
004066DB 49 DEC ECX
004066DC ^7F ED JG SHORT Packed_I.004066CB
004066DE 8D7415 00 LEA ESI,DWORD PTR SS:[EBP+EDX]
Now remove bp and place new bp on 4066DE and press F9. When you break on bp, code below JG is now decrypted. If you are corious how decryption goes, you could just pass it couple times with F7 to better see what it does. It's not much interesting. After this decryption is done, you'll notice another similar below at:
004066FC 49 DEC ECX
004066FD ^7F F0 JG SHORT Packed_I.004066EF
004066FF F9 STC
Do the same as first time. Then, again you will notice couple more loops that decrypts each other and you just do the same. These loops are:
0040671A 86D8 XCHG AL,BL
0040671C ^E2 F2 LOOPD SHORT Packed_I.00406710
0040671E A8 0C TEST AL,0C
0040673B 49 DEC ECX
0040673C ^7F F0 JG SHORT Packed_I.0040672E
0040673E 40 INC EAX
00406765 49 DEC ECX
00406766 ^7F E9 JG SHORT Packed_I.00406751
00406768 B0 58 MOV AL,58
00406788 49 DEC ECX
00406789 ^7F ED JG SHORT Packed_I.00406778
0040678B 05 B560A3C5 ADD EAX,C5A360B5
004067AB 49 DEC ECX
004067AC ^7F EB JG SHORT Packed_I.00406799
004067AE 8E4E 9D MOV CS,WORD PTR DS:[ESI-63]
00406880 49 DEC ECX
00406881 ^7F E0 JG SHORT Packed_I.00406863
00406883 F8 CLC
After you pass these decryption layers, scrol down and you will notice some calls.
Place bp on each CALL and press F9. You will stop at first call that calls kernel32.GetModuleFileNameA. From API reference: "The GetModuleFileName function retrieves the full path and filename for the executable file containing the specified module." tElock is searching for it's packed file. Press F9 and you'll stop on next bp where kernel32.CreateFileA is called. tE is opening packed file. Next, F9 again and you stop on next bp where kernel32.ReadFile is called - tE is reading our exe file. And next is kernel32.CloseHandle. This is begining of first CRC check. Next you have lots of some code which is not so interesting so scroll down to:
00406C4B 8B85 80D24000 MOV EAX,DWORD PTR SS:[EBP+40D280]
00406C51 50 PUSH EAX
00406C52 35 BB2C7E8E XOR EAX,8E7E2CBB
00406C57 2D 8F6EEDAC SUB EAX,ACED6E8F
00406C5C 5B POP EBX
00406C5D 6A 01 PUSH 1
00406C5F 58 POP EAX
00406C60 6A 08 PUSH 8
00406C62 59 POP ECX
00406C63 0F85 12060000 JNZ Packed_I.0040727B
00406C69 74 19 JE SHORT Packed_I.00406C84
00406C6B 78 50 JS SHORT Packed_I.00406CBD
This is end of first CRC check. Place bp on first above line and press Shift+F9 untill you stop on bp. Remove it. [ebp+40d280] holds calculated checksum that will be XOR-ed and substracted. Finally EAX must be equal to 0 so that JNZ wouldn't be executed. That JNZ at 406C63 leads to CRC error message and exits file.
3.4. Second CRC - checking memory
In a command bar or command line place bp on VirtualAlloc+1. Press Shift+F9 untill you break in kernel, than remove bp and return to user code. We placed bp on second opcode in VirtualAlloc API because tE checks is there bp on that API. We are now in second CRC procedure. This procedure is checking does file is modified in memory so it can find our breakpoints. Scroll little up and you'll see:
That first jump abowe (below POPAD) is end of this CRC check and it leads to error message. Place bp on it and press Shift+F9 to break on it. This CRC check is now passed.
3.5 To the OEP
Next, tE will allocated some blocks of memory for redirecting imports, but about that latter. Press Shift+F9 three times untill you break here:
00407824 ^73 DC JNB SHORT Packed_I.00407802
00407826 CD 20 INT 20
00407828 64:67:8F06 0000 POP DWORD PTR FS:[0]
0040782E 58 POP EAX
0040782F 61 POPAD
00407830 EB 02 JMP SHORT Packed_I.00407834
Place bp on POPAD, Shift+F9, remove bp. This was the last exception. Now, you could trace with F7 for hours and finaly you would get to last RETN at 407902, so you just press Ctrl+F9. That return will throw you to:
0040773F 8B9D 82D34000 MOV EBX,DWORD PTR SS:[EBP+40D382]
00407745 33F6 XOR ESI,ESI
00407747 F7D3 NOT EBX
00407749 0BF3 OR ESI,EBX
...
...
004077A7 66:AB STOS WORD PTR ES:[EDI]
004077A9 EB 02 JMP SHORT Packed_I.004077AD
004077AB CD 20 INT 20
004077AD 61 POPAD
004077AE FF6424 D0 JMP DWORD PTR SS:[ESP-30]
This last jump after POPAD will throw you to the OEP at 401000.
4. QUICK FINDING OEP
So we finaly found OEP. But we spend quite some time on that , are we ;) Isn't that little slow? Don't wory, you shouldn't alway search OEP by this way. Now when you know something more about tE you can use fast way to reach OEP:
Press Shift+F9 20 times and you'll stop at last exception, place bp below on POPAD, again Shift+F9 and remove bp. Press Ctrl+F9 to run to RETN opcode, F8 one time, find jump below popad that leads to OEP. And that's it ;)
5. RESTORING REDIRECTED IMPORTS
Now when we had reach the OEP, we need to restore imports. tElock has allocated (reserved) couple memory blocks in which he splitted and redirected imports. The number of allocated blocks is usually 4~5. When you're at OEP of our target, scroll down to this address:
These jumps where originaly jumps to imports. Those [xxxxxxxx] dwords where holding addresses of API's functions, but tE has placed in their place values that leads to allocated blocks of memory. From there, API functions will be called, but before that they are little messed to prevent tools and dumper engines like ImpREC or ProcDump. This is biggest problem when unpacking tElock and this is (or it should be) core of this tutorial. If you dump file and try to use ImpREC, you will fail to repair IAT and fille will crush. We will fix that by this way:
You'll see below that DS:[00403014]=009B0052. In your computer that value will probably be different. Right click on CPU window, select "Go to" and "Expression" and enter 009B0052 in the field. Click OK and you'll land here:
009B0052 EB 01 JMP SHORT 009B0055 ; This is only junk.
009B0054 66:90 NOP
009B0056 2BC5 SUB EAX,EBP
009B0058 B8 09019B00 MOV EAX,9B0109 ; This is only important to us, EAX=9b0109,
009B005D 40 INC EAX ; Add 1 to EAX,
009B005E FF30 PUSH DWORD PTR DS:[EAX] ; Push that address,
009B0060 C3 RETN ; Jump to that address.
This small pice of code above is our cloacked import jump. EAX=9B0109+1=9B010A. Follow that address in dump and you will found that it points to some API address:
009B010A D7 3C 00 7F
Select that four bytes and Binary copy them. Then return to JMP at 402D18 and follow it's walue in dump window:
00403014 52 00 9B 00
Select those four bytes and Binary paste. You have just restored one import to it's original place. Go again to 9B010A in dump and scroll little up. You'll see five more imports:
Now Binary copy those values and return to that one import that you have restored. Scroll up and Binary paste five new import values to five places above first restored. You have just restored whole one block of redirected imports. This block is small and contains only six imports.
Binary copy them, return to unresolved jump JMP DWORD PTR DS:[403098] and follow it in dump and paste copyed bytes. Return again to place fom where you have taken bytes, scroll up and you'll see couple more imports:
Copy them and paste them above those first fixed, just like in the first example. Just watch that you properly count lines so that you don't mess values because you will get wrong imports. With this you have fixed second redirected imports.
and paste them above first ones. You have just restored last redirected import block. Now, all the imports should be on their original places.
Now dump file to hard drive with LordPE.
Open ImpREC, enter OEP, click IAT auto search and get imports. You will see that it found one thunk, but it 3 invalid pointers. Cut that three invalid and fix dumped file. Open dumped file and olay a little with it and you'll see that it works fine.
6. ANTI-DEBUGGER CHECK
tE has old SoftICE check that is no comatibile with XP and that is the reason why I didn't descover it in the first way. If you have Windows 98 or some other that support this check, you will probably have problems following this tutorial because one window will popup teling you that file wont run with active debugger. Now we gona find that check. Restart target and press Shift+F9 about 13 times untill you break here:
00406B67 F7F3 DIV EBX
...
...
00406B93 C3 RETN
00406B94 66:B8 0043 MOV AX,4300
00406B98 EB 02 JMP SHORT Packed_I.00406B9C
00406B9A CD 20 INT 20
00406B9C 81B5 591C0000 AD>XOR DWORD PTR SS:[EBP+1C59],0B4806AD
00406BA6 CD 68 INT 68
00406BA8 66:05 7B0C ADD AX,0C7B
00406BAC 66:48 DEC AX
00406BAE 74 55 JE SHORT Packed_I.00406C05
This last jump must not be executed because it leads to error message. This check will not work on XP machines.
7. FINAL WORDS
tElock isn't hard protector and it's quite old one (2001 was relised). I don't believe that you will found many targets packed with it. Today most of programs use ASProtect or Armadillo or some other more pwerfull protector. But point of this tutorial was to learn something.
If this method of fixing IAT will look confusing to you, pack couple programs with tE by your self and try to unpack them. To test this method, I packed Mozilla Thunderbird which is 7 MB big and it has 2090 imports. After packing there were about 300 redirected imports to 6 allocated blocks of memory. With copy-paste I manage to restore them all really fast. ImpREC found then 6 invalid pointer which I just cutted. It seams that ImpREC will always find one invalid pointer in every allocated block. Maybe bug or something.
That's all. I hope you like this tutorial and that it would be of some help for somebody. I was planing to write shorter one, as I sad on the begining, but it again become prety large tut. If you had some questions, feel free to post comment here or on the forum.
I posted attachment in which you will find target and this tutorial in rtf format.
Big greets goes to detten and all crew at BIW reversing.
Authored by:
allko on
Friday, June 23 2006 @ 11:51 PM CEST
thx
but
after finishing point 5 and dumping the file
then i press IAT auto search (After changing the oep)
but it said : nothing could be found at this oep...
whats going on ?
Authored by:
haggar on
Saturday, June 24 2006 @ 04:50 PM CEST
Then you made something wrong while copy-pasting imports.
But there is easier way to fix imports by changing one jump. I don't remember now how it was, but I will post script for ODbgScript plugin that can fix imports and find OEP. Check forum under unpacking.
pretty neat and exhaustive explanation
thanks and hope we see some more tutorials
of same caliber
keep up the good work haggar