2009
12.28

Today's blog post brings TitanEngine to the test and its a good way to end this years series of our blog posts dedicated to unpacking. The reason why TitanEngine is put to the test is because tELock is a protector riddled with protection tricks. That is why some modifications were needed so that we can debug files protected with this protection without getting detected by its anti-debugging tricks. Furthermore because of the specific packing method used our PE file validation routine needed some tweaks too. These small inconveniences resulted in today's publishing of two tools named: PEValidate and LogException. Those two tools are used to test the engine's performance with file execution and validation.

PEValidate is used to validate any PE32/PE32+ file. It evaluates the plausibility of file execution and provides detail error description about every found problem. This tool is a wrapper around TitanEngine function IsPE32FileValidEx and its used as a test for it.

LogException is used to track all exceptions that occur while debugging any PE32 file. It does execute the file fully so run it in the safe environment for suspicious samples. This tool also demonstrates the usage of TitanEngine debugging features and it is used as a test for detection from debugging tricks. What this tool showed us is that tELock uses debug registers to decode data and to place hardware breakpoints it itself handles. That made us redo the part of engine that handles hardware breakpoints for TitanEngine 2.0.3. This way plugins such as AntiDRx for OllyDBG are not needed for our engine.

Writing a blog that describes in detail how tELock works isn't an easy task because files protected with it are riddled with protection tricks, polymorphic decryption loops and exceptions specifically targeting possible errors in debuggers. Simply put tELock is roller coaster made of fun. For the purpose of this blog we are using a sample packed by tELock 0.99 with all protection options turned on.

After the first jump instruction in the sample we land on the start of the protector's section. Executing several obfuscations leads us to first poly decryptor code. Right here:

  MOV ECX,1DC9
  MOV EAX,ECX
  ADD ESI,36
DecryptionLoop:
  LEA EAX,DWORD PTR DS:[ECX+EAX*4+67]
  CALL DummyLabel
DummyLabel:
  XOR BYTE PTR DS:[ESI],AL
  INC ESI
  POP EDX
  DEC ECX
  JG DecryptionLoop

After the first encrypted layer has been decrypted we continue tracing until the first exception:

  SUB ECX,ECX
  PUSH DWORD PTR FS:[ECX]
  MOV DWORD PTR FS:[ECX],ESP
  INC BYTE PTR DS:[ECX]

Which is in this case an access violation. Just after we return from its handler execution next decryption awaits us here:

  MOV EDX,DWORD PTR SS:[ESP]
  POP EAX
  SUB EDX,004128BF
  MOV EAX,729017A8
  MOV EDI,EAX
  SUB EDI,724EEF46
  STC
  ADD EDI,EDX
  MOV EAX,72901D20
  MOV ECX,EAX
  SUB ECX,72901D12
  DEC EAX
  MOV EBX,72900C26
DecryptionLoop:
  XOR DWORD PTR DS:[EDI],EBX
  ADD EBX,72900C76
  XOR EAX,ESI
  CLC
  MOV EAX,4
  ADD EDI,EAX
  SBB EAX,72BFB05C
  SUB EAX,72BFB131
  SUB ECX,1
  STC
  OR EAX,ESI
  PUSH ECX
  MOV ECX,ECX
  JECXZ ExitDecryption
  POP ECX
  JMP DecryptionLoop

And this is immediately followed by the next decryption loop:

DecryptionLoop:
  OR CX,CX
  JNZ OverDummy
  INT 20
OverDummy:
  ROL BYTE PTR DS:[EBX+ECX],5
  ADD BYTE PTR DS:[EBX+ECX],CL
  XOR BYTE PTR DS:[EBX+ECX],0F1
  INC BYTE PTR DS:[EBX+ECX]
  DEC ECX
  JG DecryptionLoop

From this execution pattern we see two things. One, tELock decrypts internal data with multiple polymorphic decryption loops followed by exceptions and two this blog would be too long to list them all. Therefore we will only focus on two important parts: imports and entry point. To find the import filling part we reset our sample and set a breakpoint on the RET instruction of GetModuleHandleA API. First time that breakpoint hits tELock is just locating EnumWindows API to try to locate debugger windows. But the second time that breakpoint hits its going to take us exactly where we want to be. Here:

  PUSH EAX ;Get DLL base
  CALL NEAR DWORD PTR SS:[EBP+4036D1]
  TEST EAX,EAX
  JNZ DLLFound
...
DLLFound:
  PUSHAD ;Check if that DLL can be redirected
L001:
  XOR ECX,ECX
  SUB DH,DH
L003:
  MOV DL,BYTE PTR DS:[EBX]
  TEST DL,40
  JE L007
  AND DL,5F
L007:
  OR DL,DL ;Check ASCII "GDI32.DLLUSER32.DLLSHELL32.DLLKERNEL32.DLL"
  JE L021
  INC EBX
  INC DH
  INC ECX
  CMP DL,BYTE PTR DS:[EAX+ECX-1]
  JE L003
  CMP DL,BYTE PTR DS:[EAX+ECX+8]
  JE L003
  CMP DL,BYTE PTR DS:[EAX+ECX+12]
  JE L003
  CMP DL,BYTE PTR DS:[EAX+ECX+1D]
  JE L003
  JMP L001
L021:
  OR DH,DH
  MOV DWORD PTR SS:[ESP+1C],EDX
  POPAD
...
  AND EBX,7FFFFFFF ;Get API address
  PUSH EBX
  PUSH DWORD PTR SS:[EBP+40374B]
  CALL NEAR DWORD PTR SS:[EBP+401C6E]
  INC EAX
  DEC EAX
...
  PUSHAD ;Check whether to write a redirection
  AND DWORD PTR DS:[EDI],0
  MOV EAX,DWORD PTR SS:[EBP+403853]
  INC EAX
  JE WriteAPIPointer ;Patch to always jump!
WriteAPIPointer:
  POPAD
  XOR DWORD PTR DS:[EDI],EAX
  POP EAX
  DEC EAX
  JE NextAPIPointe

Quite a long piece of code which does the following:

  • Get the base of loaded DLL with GetModuleHandleA or load new DLL with LoadLibraryA
  • Check the name of current DLL in the import table to see if that DLL can be redirected
  • Allocate memory for redirection of APIs inside kernel32, user32, gdi32 and shell32 dlls
  • Check whether to redirect the API (if yes then redirect, if no the write normal pointer)
  • Process next API and next DLL

From this we can easily collect all the data we need to fix the import table. Only one jump needs to be patched to prevent tELock from ever redirecting APIs. This patch isn't necessary for our unpacker but can be used as a work around tELock's redirection. Due to the fact that everything inside the packers import table is encrypted with layers of polymorphic encryption data gathering with dynamic unpacking is much easier then static option.

After the import table has been filled tELock will execute a couple of exceptions more before it jumps to the entry point. Last polymorphic decryption loop which decrypts the entry point jump is here:

  XOR DWORD PTR DS:[EDI],EDX
  DEC EBX
  SBB EAX,EDI
  ADD EDX,726C7434
  CMP EAX,-7C
...
  CWDE
  POPAD
  ADD EAX,ESP
  RET

After POPAD and RET instructions execute you will land here:

  MOV EBX,DWORD PTR SS:[EBP+403783]
...
  MOV ECX,39E
  REP STOS BYTE PTR ES:[EDI]  ;Zero out packer code
  LEA EDI,DWORD PTR SS:[EBP+4015DC]
  MOV ECX,1BFF
  REP STOS BYTE PTR ES:[EDI]  ;Zero out packer code
  STOS WORD PTR ES:[EDI]
  LEA EDI,DWORD PTR SS:[EBP+4015DC]
  TEST ESI,ESI
  JNZ L011
  MOV DWORD PTR DS:[EDI],C340C033
  JMP L016
L011:
  MOV BYTE PTR DS:[EDI],0E9  ;Write OEP JUMP
  INC EDI
  SUB EBX,EDI
  SUB EBX,4
  MOV DWORD PTR DS:[EDI],EBX ;Write OEP JUMP
L016:
  LEA EDI,DWORD PTR SS:[EBP+4031DB]
  MOV ECX,2C
  REP STOS BYTE PTR ES:[EDI]
  STOS WORD PTR ES:[EDI]
  JMP L022
  INT 20
L022:
  POPAD
  CALL L024
L024:
  POP EDX
  SUB EDX,0E
  PUSH EDI
  PUSH ECX
  XOR EAX,EAX
  LEA EDI,DWORD PTR DS:[EDX]
  MOV ECX,20
  REP STOS BYTE PTR ES:[EDI]
  STOS WORD PTR ES:[EDI]
  POP ECX
  POP EDI
  RET   ;JUMP TO OEP

This code erases the protector memory and creates a new jump at the start of the tELock section which leads to the entry point. Purpose of that jump is to provide a redirection to entry point when tELock is used to protect DLL files. However we couldn't make tELock protect any DLL file successfully which is why our unpacker only supports executable files.

If you only want to unpack tELock protected file you can see how it is done in our video tutorial which shows ImportStudio usage:

http://www.youtube.com/watch?v=R4m2wFY_m1I

Writing an unpacker for tELock should be a nice exercise for any reverser. As always unpacker, source code and the samples are included with the blog. Until next week...

TitanEngine

ReversingLabs Corporation

RL!deTELock
(package contains unpacker binary, source and samples used)

VN:F [1.9.13_1145]
Rating: +4 (from 4 votes)
Share

Comments are closed.