2009
11.30

Commonly targets chosen for demonstration of TitanEngine static unpacking functions were very simple and so the code that unpacks the target would be very short but still enough to understand the basic principal of static unpackers.  But today we do something very different. We decent into madness by testing the far limits of the TitanEngine and ourselves. Yoda's Crypter is one though nut to crack so may the force be with us on this journey.

Proof of this thesis is found at the very beginning of our task. Entry point itself lays on a challenge. Polymorphic decryption is used to decrypt most of the crypter body. Since this code is random we must do something to handle it and all similar cases found in the crypter body.

L000:
  LODS BYTE PTR DS:[ESI]
;
; Totally random decryption code
;
  STOS BYTE PTR ES:[EDI]
  LOOPD L000

Since both start and end patter can be defined with the LODS and STOS instructions code in between can be easily located. But what to do with it? Simple way of handling this would be extraction of this code and dynamic generation of decryption code with the following structure:

; __stdcall function long Decrypt(EAX, ECX)
  PUSH EBP
  MOV EBP,ESP
  MOV EAX,DWORD PTR[EBP+8]
  MOV ECX,DWORD PTR[EBP+C]
;
; Totally random decryption code pasted here
;
  LEAVE
  RET 8

Here ECX and EAX are input variables since they change. EAX is equal to byte pointed by ESI since its loaded with LODS, and ESI at start points to first byte after LOOPD instruction. Decryption size is static and its calculated and stored just before this decryption loop inside the crypter body. Since LOOPD decrements the ECX value it must be handled before every call to our decryption function. Return value of our decryption function is the value of decrypted byte. This is one way of dealing with polymorphic decryption functions and therefore this or similar approach will be used every time we encounter such obstacle while unpacking the crypter. If we were making a dynamic unpacker skipping this polymorphic decryption would be as easy as setting a hardware breakpoint on the first byte after LOOPD and waiting for it to hit.

This first layer of encryption is the most important one since all the data needed for our unpacker is encrypted by it. If you remember when coding dynamic unpacker first logical step is to collect data about imports. Situation is a bit different when it comes to static unpackers. First thing to do is of course decrypt everything that needs decrypting. With the first layer already decrypted we move on to decrypting section content. Following code processes sections:

  MOV EDI,EAX
  ADD EDI,DWORD PTR DS:[EDI+3C]
  MOV ESI,EDI
  ADD ESI,0F8
  XOR EDX,EDX
L005:
  CMP DWORD PTR DS:[ESI],63727372 ;rsrc
  JE L046
  CMP DWORD PTR DS:[ESI],7273722E ;.rsr
  JE L046
  CMP DWORD PTR DS:[ESI],6F6C6572 ;relo
  JE L046
  CMP DWORD PTR DS:[ESI],6C65722E ;.rel
  JE L046
  CMP DWORD PTR DS:[ESI],4379     ;yC
  JE L046
  CMP DWORD PTR DS:[ESI],6164652E ;.eda
  JE L046
  CMP DWORD PTR DS:[ESI],6164722E ;.rda
  JE L046
  CMP DWORD PTR DS:[ESI],6164692E ;.ida
  JE L046
  CMP DWORD PTR DS:[ESI],736C742E ;.tls
  JE L046
  CMP DWORD PTR DS:[ESI+14],0
  JE L046
  CMP DWORD PTR DS:[ESI+10],0
  JE L046
  PUSHAD
  MOV ECX,DWORD PTR DS:[ESI+10]
  OR EBX,EBX
  JNZ L035
  MOV ESI,DWORD PTR DS:[ESI+14]
  ADD ESI,EAX
  CALL 0040748B
  JMP L038
L035:
  MOV ESI,DWORD PTR DS:[ESI+C]
  ADD ESI,EAX
  CALL 0040744E  ;Decrypt content
L038:
  MOV EDX,EBP
  ADD EDX,00402D3E
  LEA EAX,DWORD PTR DS:[EDX]
  PUSH EAX
  RET
  MOV EAX,0
  INT 0D
  POPAD
L046:
  ADD ESI,28
  INC EDX
  CMP DX,WORD PTR DS:[EDI+6]
  JNZ L005
  RET

All sections are processed by names. Every section except the ones named rsrc, idata, edata, rdata, tls and yC is decrypted. That kind of logic must be incorporated in our unpacker aswell. Decryption of content is done with another polymorphic decryption loop. Same procedure as described above can be applied. After that is done all that remains is that we fix imports and correct the entry point.

Now for the imports... Not exactly a hard task once we locate yC's internal data. Scroll down to the end of the crypter code, until you find this:

  PUSH EBP
  MOV EBP,ESP
  PUSH EDI
  MOV EAX,DWORD PTR SS:[EBP+10]
  MOV EDI,DWORD PTR DS:[EAX+9C]
  MOV EDX,EDI
  ADD EDX,crackme_.00403393
  PUSH DWORD PTR DS:[EDX]
  POP DWORD PTR DS:[EAX+B8]
  MOV DWORD PTR DS:[EAX+B4],EDI
  MOV DWORD PTR DS:[EAX+9C],0
  MOV EAX,0
  POP EDI
  LEAVE
  RET

Following this is a simple data structure containing the following:

; DWORD - LoadedBase (default: ImageBase)
; DWORD - OriginalEntryPoint address (RVA)
; DWORD - yC protection options selected (All options: 0x3C)
; DWORD - File checksum (custom algorithm)
; DWORD - Crypter body memory checksum (custom algorithm)
; DWORD - Reserved; Store place for a boolean variable
;
; Simplified IID (Image Import Descriptor)
;
; DWORD - Pointer to name of the first DLL in the IAT (RVA)
; DWORD - Pointer to IAT for the first DLL(RVA)
; DWORD - Reserved; OriginalFirstTrunk
; DWORD - Pointer to name of the second DLL in the IAT (RVA)
; DWORD - Pointer to IAT for the second DLL(RVA)
; DWORD - Reserved; OriginalFirstTrunk
; etc. for all DLLs

As we can see all the data we need is decrypted with the first polymorphic decryption and easily located. What we need from this is to read the location of DLL names and API pointers for every DLL and rebuild IIDs linking this data. Additionally all strings are encrypted so we need to go through the API pointers and decrypt them with the following algorithm:

  PUSH ESI
  PUSH EDI
  MOV ESI,EAX
  MOV EDI,EAX
L004:
  LODS BYTE PTR DS:[ESI]
  ROR AL,4
  STOS BYTE PTR ES:[EDI]
  CMP BYTE PTR DS:[EDI],0
  JNZ L004
  POP EDI
  POP ESI
  RET

Once that is done we have imports sorted and since we know the address of the original entry point we only need to write it to PE header and optionally strip to crypter section to complete the unpacker. Optionally because if crypter is used on programs with TLS table it will be moved to the crypter section and if we don't want to rebuild that as well we can just keep the crypter section.

Writing an unpacker for Yoda's Crypter is a fairly complex task since there are few details to worry about. It provides an interesting challenge for any reverser. As always unpacker, source code and the samples are included with the blog. Until next week...

TitanEngine

ReversingLabs Corporation

RL!deY0daCrypter 1.x
(package contains unpacker binary, source and samples used)

VN:F [1.9.13_1145]
Rating: +2 (from 2 votes)
Share
2009
11.23

Dynamic unpacking has a couple of benefits and couple of drawbacks. Main benefit would of course be the quick unpacker writing and natural resilience to minor packer changes including multiple shell versions that use different compression and/or encryption algorithms. Our only real concern would be possibility of file malformation so that the file we are unpacking does a jail break. But since we can virtualize our unpackers with either system or application virtualization or sandboxing this isn't a huge issue any more. Also remember that TitanEngine now runs even under Linux making it as safe as possible to execute live application code. With this in mind we extend the functionality of our static unpacker functions to provide most help when it come to making such unpackers, since even though dynamic unpackers solve most of our problems static unpacking is still the best option. Further recommended reading on this topic can be found here.

However this is a "code your own dynamic unpacker" Monday. Today we take a look at nPack a straight forward packer that comes to us from Russia. Since it supports compression of both dynamic link library and executable files it should give us a nice exercise on how to write dynamic unpackers. Shall we?

Entry point of the packed file gives more useful information than we usually see with packers. Take a look.

  CMP DWORD PTR DS:[407E48],0  ;File already decompressed check
  JNZ L003
  JMP L004
L003:
  RET
L004:
  CALL 0040720A
  CALL 0040723C
  MOV EAX,
  SUB EAX,DWORD PTR DS:[407E08]
  MOV DWORD PTR DS:[407E44],EAX
  CALL 0040727A
  CALL 004073FD
  CALL 004078B2
  CALL 00407806
  MOV EAX,DWORD PTR DS:[407E44]
  MOV DWORD PTR DS:[407E48],1   ;Set file already decompressed flag
  ADD DWORD PTR DS:[407E00],EAX ;Add loaded file base to OEP RVA
  PUSH DWORD PTR DS:[407E00]	;Entry point jump
  RET

So, once again we solve the entry point location before the other pieces of the puzzle. Normally the first of our points of interest is import table processing. We find that part of the file by scrolling through the code and looking for the API call combination that utilizes GetProcAddress and LoadLibrary/GetModuleHandle. Since functions can be imported by name or ordinal number instruction TEST which does a logical compare with 0x80000000 is also a big clue on where this code is located. Most packers check for ordinal imports this way and this code part usually stands out on its own identifying the import processing part.

  MOV EBX,DWORD PTR DS:[EDI+C] ;Part I - Loading new library
  ADD EBX,DWORD PTR DS:[407E44]
  PUSH EBX
  CALL LoadLibraryA
...
  TEST EAX,80000000            ;Part II - Is API ordinal?
  JE SHORT 004074A0
  AND EAX,0FFFF
  MOV DWORD PTR SS:[ESP+18],EAX
  MOVZX EAX,AX
  PUSH EAX
  PUSH DWORD PTR SS:[ESP+18]
  CALL GetProcAddress          ;Find function via ordinal
  TEST EAX,EAX
...
  MOV ECX,DWORD PTR DS:[407E44]
  ADD EAX,ECX
  ADD EAX,2
  PUSH EAX
  MOV DWORD PTR SS:[ESP+1C],EAX
  PUSH DWORD PTR SS:[ESP+18]
  CALL GetProcAddress          ;Find function via name
...
  MOV DWORD PTR DS:[ESI],EAX   ;Part III - Write function pointer
  ADD ESI,4
  JMP SHORT 00407469

As we can see this code is segmented inside the function that processes imports. All three parts of this code have their role. First part load the necessary libraries, second one finds the functions inside the loaded libraries and the third writes the found API pointers to the import address table. Three breakpoints are needed in order to collect this data. One at the library loading part and two at function finding part. We need two breakpoints at the function finding part because only one of two GetProcAddress calls gets executed depending on whether the function is imported by ordinal or not. Similarly to this we have the following relocation code:

L000:
  MOVZX EAX,WORD PTR DS:[EBX]
  MOV EBP,EAX
  AND BP,0F000
  CMP EBP,3000
  JNZ L010
  AND EAX,EDI
  ADD EAX,DWORD PTR DS:[ECX]
  ADD EAX,EDX
  ADD DWORD PTR DS:[EAX],ESI
  MOV EDX,DWORD PTR DS:[407E44]
L010:
  MOVZX EAX,WORD PTR DS:[EBX]
  MOV EBP,EAX
  AND BP,0F000
  CMP EBP,1000
  JNZ L022
  AND EAX,EDI
  ADD EAX,DWORD PTR DS:[ECX]
  ADD EAX,EDX
  MOV EDX,ESI
  SHR EDX,10
  ADD WORD PTR DS:[EAX],DX
  MOV EDX,DWORD PTR DS:[407E44]
L022:
  MOVZX EAX,WORD PTR DS:[EBX]
  MOV EBP,EAX
  AND BP,0F000
  CMP EBP,2000
  JNZ L032
  AND EAX,EDI
  ADD EAX,DWORD PTR DS:[ECX]
  ADD EAX,EDX
  ADD WORD PTR DS:[EAX],SI
  MOV EDX,DWORD PTR DS:[407E44]
L032:
  INC EBX
  INC EBX
  DEC DWORD PTR SS:[ESP+10]
  JNZ L000

Yet again this is only the part of a really long code which can be easily identified. Test or compares with value 0x3000 indicates a 32 bit relocation is always a good clue, and if such test is a part of a loop there is a good chance that that code is a part of a relocation to new base function. We make two snapshots that fix relocations with ease. One at the beginning of this function and the other at the end of the same function. Memory to be snapshot is always the entire memory minus the packer section, which is in all cases from virtual address of the first section to virtual address of the last one. Since we already know where the entry point jump is this is the last piece of the puzzle needed to complete our unpacker.

Writing an unpacker for nPack should be an easy task since there are just a few things to look out for. If you had no trouble writing an unpacker for PackMan you shouldn't have a problem with this one. As always unpacker, source code and the samples are included with the blog. Until next week...

TitanEngine

ReversingLabs Corporation

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

VN:F [1.9.13_1145]
Rating: +1 (from 1 vote)
Share
2009
11.16

After a few weeks we return to building unpackers with an interesting packer called Packman. Even though this is a pretty straight forward packer there are a few details that make us learn a trick or two while working on this unpacker. Most interesting detail about how one could find a loaded base for the module with just some simple math waits for us in the first few instructions, here:

  PUSHAD
  CALL L002
L002:
  POP EBX
  LEA EBX,DWORD PTR DS:[EBX-3A]
  ADD DWORD PTR DS:[EBX],EBX

That's is? This code can find on which base loaded module was loaded? It can and here is why. Once the first call and POP EBX execute EBX will be equal to address on which EBX is located. That doesn't get us closer to our loaded base address but next two instructions do. Once LEA executes EBX will be pointing to data inside the same section where the entry point resides. Data at that pointer is 0xFFFF8A30 which is equal to 0x004075D0 - 0x00400000 which is the EBX data minus the default image base. Since math for this is EBX - ImageBase = Delta reversing this would be EBX + Delta = ImageBase. And from this it is simple to figure out that as long as the EBX changes and delta remains the same with this simple math formula we can always calculate the loaded base of the file. Quite a neat trick.

  MOV BYTE PTR DS:[ESI],0E9
  MOV EAX,DWORD PTR DS:[EBX+C] ;0xFFFF9CB7
  MOV DWORD PTR DS:[ESI+1],EAX

What comes next is also interesting and very simple. Code above is a dynamic entry point jump generation. Since at that point ESI always point to the address of the packed entry point data that will be written to that address changes its code content. New instruction to be written instead of fist PUSHAD is a jump to the entry point. Since the relative distance between packed and original entry point will never change there is no need to recalculate this jump and we can always write the same data for that jump regardless of the file loaded base. This works of course because jumps are relative to their location. However in order  to get this location we can do several things:

  • Set a breakpoint on the JUMP to packed entry point right after POPAD and single step twice to get to the entry point
  • Place a breakpoint at the packed entry point at some point and wait for it to hit and then single step to get to entry point
  • Read newly created entry point jump (or data used to write it) and recalculate the entry point jump placing a hardware breakpoint there

Any of the solutions above is a good choice and you can use any of those to place the final entry point breakpoint. But we are getting ahead of ourselves since we still need to work out relocations and imports before we even get to the entry point.

First thing is first, imports. And so this code blob does everything we need to know about import handling in PackMan.

L000:
  ADD EAX,DWORD PTR DS:[EBX]
  PUSH EAX
  CALL NEAR DWORD PTR SS:[EBP] ;GetModuleHandleA
  MOV EDI,DWORD PTR DS:[ESI]
  ADD EDI,DWORD PTR DS:[EBX]
  JMP L017
L006:
  BTR ECX,1F
  JB L011
  ADD ECX,DWORD PTR DS:[EBX]
  INC ECX
  INC ECX
L011:
  PUSH EAX
  PUSH ECX
  PUSH EAX
  CALL NEAR DWORD PTR SS:[EBP+4] ;GetProcAddress
  STOS DWORD PTR ES:[EDI]
  POP EAX
L017:
  MOV ECX,DWORD PTR DS:[EDI]
  TEST ECX,ECX
  JNZ L006
  ADD ESI,10
  LODS DWORD PTR DS:[ESI]
  TEST EAX,EAX
  JNZ L000

One thing to notice is that PackMan uses GetModuleHandleA to get the base of the loaded DLL file. This is because it doesn't load libraries by itself, instead it lets Windows do the loading part and it just fills in the import address table with the correct API pointers. Its easy to place two breakpoints on these function calls and grab the data we need to fill in the imports correctly. Moving on to relocations.

  MOV ECX,DWORD PTR DS:[EBX+2C] ;First snapshot
  OR ECX,ECX
  JE SHORT L015
  MOV EDI,DWORD PTR DS:[EBX+24]
  JMP L014
L005:
  XOR EAX,EAX
  LODS WORD PTR DS:[ESI]
  OR EAX,EAX
  JE L012
  AND AH,0F
  ADD EAX,DWORD PTR DS:[EBX]
  ADD DWORD PTR DS:[EDX+EAX],ECX
L012:
  CMP ESI,EDI
  JNZ L005
L014:
  MOV EDX,DWORD PTR DS:[EDI]
  LEA ESI,DWORD PTR DS:[EDI+8]
  ADD EDI,DWORD PTR DS:[EDI+4]
  TEST EDX,EDX
  JNZ L012
L015:
  POPAD ;Second snapshot

This code blob relocates the file to newly loaded base. As always we can make two snapshots that fix relocations automatically. Question is which memory segment do we snapshot? Since Packman has two memory forms we apply a solution that works for both. Packman can have two or more PE sections with the packer code in the last section. So the memory to snapshot is always the entire memory minus the packer section, which is in all cases from virtual address of the first section to virtual address of the last one. Comparing those two snapshots fixes the relocation table with ease.

Writing an unpacker for PackMan should be an easy task since there are just a few things to look out for. If you had no trouble writing an unpacker for UPX you shouldn't have a problem with this one. As always unpacker, source code and the samples are included with the blog. Until next week...

TitanEngine

ReversingLabs Corporation

RL!dePackMan 1.x
(package contains unpacker binary, source and samples used)

VN:F [1.9.13_1145]
Rating: +2 (from 2 votes)
Share
2009
11.09

Ask a developer Monday

This is the first "Ask a developer Monday" in which we try answer the number one question we received in the past weeks. And that question is: "How can I use TitanEngine as a static library?"

Even though the TitanEngine is  mostly been used as a dynamic library in our sample unpackers it can also be used as a static library. First sample that uses our engine a static library we made is TitaniumOverlay whose source will be available with the next update. Here is how we did it...

First step is to create new library files which contains the actual TitanEngine code so that the functions you use can be linked directly into your code. To do this open TitanEngine project with Visual Studio and go to Project -> TitanEngine properties (Or just hit ALT+F7). In the Configuration Properties -> General -> Configuration type select Static Library (.lib).

StaticLib

Once you select this setting next compile will generate a new .lib file inside the release folder which will be used as a substitute for existing .lib file you used in the past. For your new project copy SDK.h and this new TitanEngine.lib to your project folder and include them in the usual way. One thing to worry about is that in your project you can't use the same function names which have already been used in the TitanEngine. So the only problem you can have is if you are creating a new DLL project you can't use function named DllMain. That can be resolved by renaming DllMain to any other name and setting the option Linker -> General -> EntryPoint to that function name.

Until next time and next ask a developer Monday...

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