2010
02.23

Today we finish our AlexProtector unpacker. We started creating it last week with file format analysis. We initially intended to create a dynamic unpacker for this protection, but since it is just as "easy" to create a static one, we went for that option. We are a day late with our blog as a result, and we are glad we are, since we noticed some bugs in the Importer module that we have since resolved. But we did more then just bug fixing - we made some tweaks to the existing functions, improving import elimination protection support.

Since we already did the analysis, let's go straight to coding an unpacker and describe everything that needs to be done to complete it. We'll start by reserving enough space for the section data that needs to be decompressed. This can be a complex task if we try to manually re-size the file and move all data to the appropriate locations. However TitanEngine comes with two functions which can do the hard work for us, even though they are not meant to do this exact task.

But before we go into that let's explain what is really needed. The problem: some sections are compressed by aPLib which means that the protected file size is most likely smaller than the original file size. To ensure there is enough extra space to hold the decompressed data, we have to re-size the sections so they can hold the physical data. But how much space is needed? As it turns out, that part is simple, because AlexProtector stores compressed section data inside its original sections. This means that if the first PE section has been compressed, its compressed data will still be located in the first section. After decompression that data will still need to be written in the first section, but will require more physical space, since the compressed data is up to ~70% smaller than the original data. However, since the original data is still in the section, we know that the maximum physical size of that data is equal to the virtual size of that section. As a result, we can simply re-size all sections so that their physical size is equal to their rounded up virtual size.

Doing this is just like dumping the memory of a running process with the TitanEngine's DumpProcess function, but since we're making a static unpacker, we don't want to start the process, so we will do it a little differently. We will use StaticFileLoad to simulate the file load, which has the same effect.  Then we will dump that memory to disk with DumpMemory. But that doesn't complete the task - we need to correct the PE section values of  the dumped image to make the file a valid PE image. To do this, we set the raw size of each section to the rounded up virtual size, and set the raw offset of each section to its virtual offset. Once that is done, all virtual locations in the file will be equal to their physical counterparts. For example, the virtual address 0x1000 will be on the 0x1000 byte from the start of the file.

Once we have the file re-sized to its approximate original size, we can start decompressing data. However we don't want to guess which section is compressed and which isn't, so we will directly read the protector data to reverse the compression. To find out where this data is stored, we monitor calls to the aPLib decompression code and find a call to it from the second protection layer, which is exactly what we need:

;Layer base: 0x00220000
;--------------------------------------------------------------------
/*2202D1*/  LEA ESI,DWORD PTR SS:[EBP+4023C1]  ;Internal section data
/*2202D7*/  MOV EAX,DWORD PTR DS:[ESI+4]
/*2202DA*/  PUSH 4
/*2202DC*/  PUSH 1000
/*2202E1*/  PUSH EAX
... Junk removed with DeJunk ...
/*220387*/  PUSH 0
/*220389*/  CALL NEAR DWORD PTR SS:[EBP+402411] ;VirtualAlloc
/*22038F*/  MOV DWORD PTR SS:[EBP+40239D],EAX
/*220395*/  PUSH ESI
/*220396*/  MOV EBX,DWORD PTR DS:[ESI]
/*220398*/  ADD EBX,DWORD PTR SS:[EBP+402399]
/*22039E*/  PUSH EAX
... Junk removed with DeJunk ...
/*220444*/  PUSH EBX
/*220445*/  LEA ECX,DWORD PTR SS:[EBP+401108]
/*22044B*/  CALL NEAR ECX                       ;aPLib decompress
/*22044D*/  ADD ESP,8
/*220450*/  MOV ECX,EAX
/*220452*/  MOV EDI,DWORD PTR DS:[ESI]
... Junk removed with DeJunk ...
/*2204F9*/  ADD EDI,DWORD PTR SS:[EBP+402399]
/*2204FF*/  MOV ESI,DWORD PTR SS:[EBP+40239D]
/*220505*/  REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
/*220507*/  POP ESI
/*220508*/  MOV EAX,DWORD PTR SS:[EBP+40239D]
/*22050E*/  PUSH 8000
/*220513*/  PUSH 0
/*220515*/  PUSH EAX
/*220516*/  CALL NEAR DWORD PTR SS:[EBP+402415] ;VirtualFree
... Junk removed with DeJunk ...
/*2205C1*/  ADD ESI,8
/*2205C4*/  CMP DWORD PTR DS:[ESI],0
/*2205C7*/  JNZ 002202D7
 

As we can see from this code snippet, the protector is reading data located at EBP+0x004023c1. Here both numbers are constants with EBP being calculated at the start of the protector code and referred to as "protector delta." It is determined here:

  PUSHAD
  CALL L002
L002:
  POP EBP
  SUB EBP,00401006
 

Most protections use this kind of coding which is popularly called offset independent coding. Protection authors who use this method don't need to know the exact offset at which their protection will be written. Since we are only coding an unpacker for this one protection version, we will use the same internal constants that the protector uses. So, at the location Delta+0x004023c1 we will find and read the internal AlexProtector data about the compressed sections. That data is a two dimensional array with the following structure:

typedef struct AlexProt_SectionData{
	DWORD SectionVirtualOffset;
	DWORD SectionVirtualSize;
}AlexProt_SectionData, *PAlexProt_SectionData;
 

After we decompress that data, all the sections are restored to their original state - with a couple of small exceptions: we need to identify the original entry point for the code section, and we need to remove import elimination protection. Of those two things, we will fix the import protection first, because removing that protection will correct the code section data.

When we were analyzing the file format, we determined the internal format that AlexProtector uses for storing import data. Now that we are creating an unpacker, we need that data, so we need to determine where it is stored and if it's encrypted at any point. With some tracing we determine that this code does the decryption of the compressed import data:

;Layer base: 0x00220000
;--------------------------------------------------------------------
/*22080F*/  LEA EDI,DWORD PTR SS:[EBP+402531] ;Pointer to import data
/*220815*/  ADD EDI,DWORD PTR SS:[EBP+4023B5]
/*22081B*/  XOR EDX,EDX
/*22081D*/  MOV ECX,100
/*220822*/  DIV ECX
/*220824*/  MOV EBX,EDX
/*220826*/  DIV ECX
/*220828*/  ADD EBX,EDX
/*22082A*/  DIV ECX
/*22082C*/  ADD EBX,EDX
/*22082E*/  DIV ECX
/*220830*/  ADD EBX,EDX
/*220832*/  POP ECX
/*220833*/  MOV EAX,EBX
/*220835*/  MOV ECX,DWORD PTR SS:[EBP+4023B9] ;Size of the import data
/*22083B*/  XOR BYTE PTR DS:[EDI],AL          ;Decryption loop
/*22083D*/  INC EDI
/*22083E*/  DEC ECX
/*22083F*/  JNZ 0022083B
 

Internal import data is compressed and then encrypted. In order to use it, we must reverse this process by decrypting the memory content, then decompressing it. To decrypt it, we need the decryption key and the decryption algorithm. Since the algorithm is known - it is a simple XOR - we  simply need the decryption key in order to continue. Here is where the protection author made a mistake: he used a decryption key which is a CRC hash of the selected memory part. Now this is a only partly a "mistake," since it does prevent us from using software breakpoints in some areas, but it makes the decryption key calculation unnecessary because that key can't change for this particular protector version. Since the EAX value at the start of this code snippet is 0xD0340178 we can calculate that the decryption key is 0x7D.

Once this memory is decrypted, it can be decompressed and then processed in order to correct both the import table and the code section. If we remember our analysis from the last time, here is how the internal import data is packed:

typedef struct ALEX_IAT_DLL{
       BYTE DLLSignature; //0xC3
       BYTE DLLNameLength;
       // DLLName[DLLNameLength] followed by 0x00
}ALEX_IAT_DLL, *PALEX_IAT_DLL;
 
typedef struct ALEX_IAT_APIENTRY{
       // 0xC4 indicates Ordinal import
       BYTE APINameLength;
       // APIName[APINameLength] followed by 0x00
       BYTE RedirectionNumber; //Number of redirections
       DWORD RedirectionAddress[RedirectionNumber];
}ALEX_IAT_APIENTRY, *PALEX_IAT_APIENTRY;

Above is the pseudo C code that describes the internal import data structure. Here, "redirection data" refers to the addresses in the code section that need to be corrected to point to the correct API pointers. We can consider this table as a sort of relocation table, because the data that needs to be written at that location corresponds to a random location in memory at which the import redirection is allocated. Since that memory allocation is outside the PE image file memory, we call that kind of import protection "import eliminations." To repair it, we must estimate the location at which to reconstruct the import table, and create a table aligned to that location on the fly. There are two ways to do this and we decided to go with the more complex one. Its logic goes like this:

  • Initialize the importer and say that the import table will be moved
  • Create a relative virtual import table with no point of reference
  • Relocate the virtual import table to the reserved spot
  • Write the new import table

While the term "relative virtual import table" sounds confusing, it can be described simply as an import table whose references start with zero and increment by four. That would look something like this:

  1. New DLL: Kernel32.dll
  2. TrunkValue: 0x00000000; GetProcAddress (e.g.)
  3. TrunkValue: 0x00000004; LoadLibraryA (e.g.)
  4. TrunkValue: 0x00000008; FreeLibrary (e.g.); Remember its +8 for the last item
  5. New DLL: User32.dll
  6. TrunkValue: 0x00000010; MessageBoxA (e.g.)
  7. TrunkValue: 0x00000014; MessageBoxW (e.g.)

Once we compile the table, we simply relocate it by adding the correct value to its trunk relative address. That value is the virtual address of the section we will add to the file to hold the import table. During unpacking, that address will be a SectionAlignment aligned value of NtSizeOfImage. We could have built our table like this from the start, without relocating it, but we wanted to show a more general approach. Now we just need to write the correct pointers to the redirection addresses found in  the AlexProtector internal data to connect the code section with the new import table.

With imports sorted, we move on the last item on our list, the entry point protection. It is processed by this code here:

;Layer base: 0x00220000
;--------------------------------------------------------------------
/*220D0B*/  LEA EBX,DWORD PTR SS:[EBP+402531] ;Pointer to EP data
... Junk removed with DeJunk ...
/*220DB6*/  ADD EBX,DWORD PTR SS:[EBP+4023B5]
/*220DBC*/  ADD EBX,DWORD PTR SS:[EBP+4023B9] ;Pointer correction
... Junk removed with DeJunk ...
/*220E67*/  MOV ECX,DWORD PTR SS:[EBP+402395]
... Junk removed with DeJunk ...
/*220F12*/  MOV EAX,DWORD PTR SS:[EBP+4023AD]
/*220F18*/  PUSH EAX
/*220F19*/  PUSH EBX
/*220F1A*/  LEA EDX,DWORD PTR SS:[EBP+401108]
/*220F20*/  CALL NEAR EDX                     ;aPLib
... Junk removed with DeJunk ...
/*220FC7*/  ADD ESP,8
/*220FCA*/  MOV EAX,DWORD PTR SS:[EBP+4023AD]
/*220FD0*/  MOV EBX,DWORD PTR SS:[EBP+402391]
... Junk removed with DeJunk ...
/*22107B*/  MOV ESI,DWORD PTR SS:[EBP+402385] ;EP resumes here
/*221081*/  ADD EAX,EBX
/*221083*/  MOV BYTE PTR DS:[EAX],0E9         ;Write OEP jump
/*221086*/  INC EAX
/*221087*/  MOV ECX,ESI
... Junk removed with DeJunk ...
/*22112E*/  SUB ECX,EAX
/*221130*/  SUB ECX,4
/*221133*/  MOV DWORD PTR DS:[EAX],ECX
... Junk removed with DeJunk ...
/*2211DA*/  MOV EAX,DWORD PTR SS:[EBP+4023AD]
/*2211E0*/  MOV DWORD PTR SS:[ESP+1C],EAX
/*2211E4*/  POPAD
/*2211E5*/  JMP NEAR EAX                      ;Jump to stolen EP
 

As we can see, the stolen entry point data is decompressed and a new jump to the first non-stolen instruction is written. To reverse this we must decompress the buffer with EP jump correction, after which we need to write it to a new section. It is possible to extract the correct the entry point to its original state, but that would mean that we would have to disassemble and analyze the decompressed buffer which contains those original functions riddled with junk code. Such disasesmbly and analysis is an error-prone process, however, so keeping the junk is the simplest and safest option.

Writing an unpacker for AlexProtector is a nice exercise for any reverser. We have shown in detail how it can be done statically. If you have any questions about any of the steps in writing this unpacker feel free to contact us. Until next week....

TitanEngine

ReversingLabs Corporation

Samples and Protector / RL!deAlexProtector
(package contains protector binary, unpacker with source and the samples used)

VN:F [1.9.3_1094]
Rating: +2 (from 2 votes)
  • Share/Bookmark
2010
02.18

ReversingLabs is giving a presentation at the Barcelona BlackHat conference in April. Here is the short description of our presentation:

"Exploiting archive formats can lead to steganographic data hiding and to processing errors with serious forensic consequences. These formats are very interesting as they are commonly found on every PC, Apple or Linux machine, and it is popularly believed that they are well understood and trusted. Can exploits ever be present in file formats that have been in use for over ten or even twenty years?

Through deep format analysis, beyond fuzzing, we look at what goes wrong when the format specifications are interpreted differently. Can you trust programs that work with archives? Can you even trust your antivirus? We will answer these questions and disclose for the first time 15 newly discovered vulnerabilities in ZIP, 7ZIP, RAR, CAB and GZIP file formats revealing the impact they have on anti-malware scanners, digital forensic, security gateways and IPS appliances.

This talk will include demo of ArchiveInsider, a new forensics tool that detects and extracts hidden data and fully validates vulnerable file formats. We will demonstrate file format steganography, file malformation, and even data "self destruction," all with tools that you use and trust."

See you there...

VN:F [1.9.3_1094]
Rating: +3 (from 3 votes)
  • Share/Bookmark
2010
02.18
blah

With over 385 functions, TitanEngine is surely overwhelming at first sight. To help you get over this initial barrier we have included many sample applications with the TitanEngine SDK. However that still involves learning the use of 20 - 30 functions and the general layout we envisioned for our dynamic unpackers. And even this can be a lot for someone who wants to perform simple tasks such as creating an unpacker for FSG packer. With that in mind, we designed a basic set of 5 functions that are simple to use, because they automate most of the steps needed to create simple dynamic unpackers. These 5 new functions create the debugging process, search for patterns, set breakpoints and handle the memory dumping and file fixing steps.

To demonstrate what is coming in the next TitanEngine 2.0.3 release we asked one of our reverse engineers to show us how he would create an unpacker for FSG using these new functions. This sngle breath video capture, which only took 16 minutes to make, shows how to create a simple FSG 2.0 unpacker from scratch, for the first time showing the entire unpacker coding process. We have accelerated the video 4x for your viewing pleasure. The final result of this exercise is a fully functional FSG 2.0 unpacker - in only 40 lines of code.

This is just one of the features that you can expect to see in the next TitanEngine major version upgrade. Stay tuned for more...

VN:F [1.9.3_1094]
Rating: +5 (from 5 votes)
  • Share/Bookmark
2010
02.15

There is hardly a software protection nowadays that has only a single layer of code containing the whole stub code. Even some software packers such as PeCompact implement multiple layers in the process of software decompression. It is common for these additional layers to do the most interesting protection operations, such as memory decompression, import table processing and entry point protection and redirection. Therefore in order to fully dynamically unpack these kinds of protections we need to move through the layers and collect the needed data along the way. The protection we have chosen to analyze is AlexProtector because it uses a multiple layer protection model along with other interesting protection features. During analysis of this protection, we will encounter: obfuscations, antidebugging, antitracing, antiemulation, checksum checks, import elimination and stolen bytes at the entry point. Quite an impressive list of protections found in software protection from 2004, which is why we at the ReversingLabs commonly use it as an introduction to more complex protection solutions.

The entry point of the packed file gives us a vague clue on how interesting this analysis will be. It looks like this:

  PUSHAD
  CALL L002
L002:
  POP EBP
  SUB EBP,00401006
  CALL 00407036
  JMP L007
  DB E9
L007:
  MOV EAX,DWORD PTR SS:[ESP+C]
  JMP SHORT 0040701E

The usual method of getting the code offset delta via CALL/POP, followed by simple obfuscations and the first packer controlled exception. Luckily for us the whole first protection layer is unprotected, so basic stub functions are accessible from start. They include antidebugging functions and more importantly, the decompression of the main protection layer and the transfer of control to it. This first layer's primary point of interest is the layer control transfer. To locate that part of the code we scroll down a bit and spot the aplib decompression code. That recognizable code:

  PUSHAD
  MOV ESI,DWORD PTR SS:[ESP+24]
  MOV EDI,DWORD PTR SS:[ESP+28]
  CLD
  MOV DL,80
  XOR EBX,EBX
  MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
...
  SUB EDI,DWORD PTR SS:[ESP+28]
  MOV DWORD PTR SS:[ESP+1C],EDI
  POPAD
  RET

It is located at offset +0x108 relative to the entry point. Since it is common for protectors to compress and/or encrypt their layers, setting a hardware breakpoint here seems like a good place to start. After a few exceptions we finally hit it, and we can collect the needed data from this function's input parameters. If we take a look at the stack we can see these numbers:

0012FF50   00407AB9  RETURN to 00407AB9 from 00407108 ;Called from
0012FF54   00408531  00408531 ;Packed layer content
0012FF58   00330000           ;Allocated layer buffe

If we look at the address from which the layer decompression was called, we see:

  CALL 00407108 ;aPLib decompression
  ADD ESP,8
  PUSHAD ;AntiTracing via RDTSC
 ...
  ADD ESP,4
  RDTSC
  MOV EBX,EAX
...
  ADD ESP,4
  MOV ECX,EDX
...
  ADD ESP,4
  RDTSC
  SUB EAX,EBX
...
  ADD ESP,4
  SBB EDX,ECX
  RDTSC
  ADD EAX,EBX
...
  ADD ESP,4
  ADC EDX,ECX
  RDTSC
  SUB EAX,EBX
...
  ADD ESP,4
...
  ADD ESP,4
  SBB EDX,ECX
...
  ADD ESP,4
  TEST EDX,EDX
  JNZ SHORT 00407B36 ;Executed if code is traced
  POPAD

This antitrace code is repeated throughout the code many times, and it is also present in all API redirections. Following this is a single exception that is executed just before control  is transferred to second protection layer. Instruction JMP EDI, which is located just above the custom memory checksum algorithm, transfers the control to the next layer. That next layer starts like this:

  JMP L003
L001:
  JMP L004
  ???
L003:
  JMP L001
L004:
  CALL L036
  TEST AL,83
  LES EAX,FWORD PTR DS:[EAX+EDX*4]
  NOP
  NOP
  NOP
  NOP
 

This protection layer holds all information necessary for unpacker coding in this layer. Imports are handled at these locations:

+0x9A5:  PUSH EBX
  LEA EDX,DWORD PTR SS:[EBP+401108]
  CALL NEAR EDX                       ;decompress IAT data
  ADD ESP,8
  MOV EDI,DWORD PTR SS:[EBP+4023A9]
+0x9B7:  CMP BYTE PTR DS:[EDI],0C3
  JNZ 00330A8C
  ADD EDI,2
  PUSH EDI
  CALL NEAR DWORD PTR SS:[EBP+4024C8] ;GetModuleHandleA
  TEST EAX,EAX
...
+0xA95:  INC EDI
  PUSH EDI
  PUSH DWORD PTR SS:[EBP+40247C]
  CALL NEAR DWORD PTR SS:[EBP+4024C4] ;GetProcAddress
  XOR EBX,EBX
  PUSHAD
 

And this is where we have a choice to either place breakpoints at these locations or analyze a memory buffer holding IAT data. That buffer is decompressed just before it is processed. If we examine it, we see the following pattern:

typedef struct ALEX_IAT_DLL{
       BYTE DLLSignature; //0xC3
       BYTE DLLNameLength;
       // DLLName[DLLNameLength] followed by 0x00
}ALEX_IAT_DLL, *PALEX_IAT_DLL;
 
typedef struct ALEX_IAT_APIENTRY{
       BYTE APINameLength;
       // APIName[APINameLength] followed by 0x00
       BYTE RedirectionNumber; //Number of redirections
       DWORD RedirectionAddress[RedirectionNumber];
}ALEX_IAT_APIENTRY, *PALEX_IAT_APIENTRY;

Either choice is a good one. However AlexProtector uses a protection technique called "import elimination" which means that parts of the code section which are used as call gates to Windows API are damaged and must be fixed. This data is stored in the import structure we just analyzed. However there is a problem with this since we don't know the original location of the import table and we must reserve some space for it. The solution to this problem is to reserve space in the new section but a detailed description on how to do this will be done next week in part two, when we create the unpacker for AlexProtector.

Solving the problem of imports leaves us with just one more problem, the entry point. After some quick tracing we find this code part:

+0x107B:  MOV ESI,DWORD PTR SS:[EBP+402385] ;SS:[00408385]=004012E6
  ADD EAX,EBX
  MOV BYTE PTR DS:[EAX],0E9 ;Write jump to EP
  INC EAX
  MOV ECX,ESI
...
+0x11E5:  MOV DWORD PTR SS:[ESP+1C],EAX
  POPAD
  JMP NEAR EAX              ;Jump to stolen EP code
...
  MOV EDI,DFB4AF72
  LEA EDI,DWORD PTR DS:[1A58BA5F]
  DEC EDI
  SHRD EDI,ESI,0F2
  BSR EDI,ESI
  TEST EDI,2730DC5C
  TEST EDI,874CDC1C
  AND EDI,9378C643
  JMP 004012E6              ;True jump to EP
 

The first part of this code at +0x107B writes the jump to entry point, more specifically the first instruction after a few instructions that have been stolen. Since those stolen instructions must be executed, the protector creates yet another layer which is executed just before the jump to entry point. That layer contains the stolen instructions, and a jump at the end of that code leads to the protected file code section. Stolen instructions are mixed with the junk instructions so its easiest to dump this layer to new sections and fix the jump to entry point. This was the last piece of information needed to create an unpacker for this protection, which is the topic for next week when we continue working on AlexProtector.

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

blah

Writing an unpacker for AlexProtector should be a nice exercise for any reverser. However we will do that next week, until then...

TitanEngine

ReversingLabs Corporation

Samples and Protector
(package contains protector binary and samples used)

VN:F [1.9.3_1094]
Rating: +4 (from 4 votes)
  • Share/Bookmark
2010
02.08

TitanEngine and Python SDK

blah

As we said in the blog dedicated to our latest TitanEngine release we are continuously working on expanding our SDK to support as much programming languages as possible. That is why the next major version update for TitanEngine will feature a support for Python scripting language. We are looking forward to seeing multiple unpacking scripts appearing with the next TitanEngine major release.  Until next week...

VN:F [1.9.3_1094]
Rating: +3 (from 3 votes)
  • Share/Bookmark
2010
02.01
blah

During our every day work as reverse engineers we encounter problems that affect the tools we use. Most commonly to try to detect their presence and/or crash them. Whatever is their purpose we must work our way around them. One of such problems we encountered recently is a theoretical scenario in which OllyDBG can't resolve data about the loaded modules. This scenario is possible do the fact that OllyDBG doesn't use unicode APIs to access files on the disk. However question remains, how can you load a DLL file with non English characters? That isn't possible via import table since all DLL names in that table are ASCII. In fact only way to do this is to use the unicode version of LoadLibrary API, which seems odd because it isn't really clear why this is even possible. Simply put there is no need for such a feature because files with names that consist of non English characters can't be statically loaded because PECOFF documentation specifies that those strings are ASCII. But this is just a minor inconvenience we can work around since that memory can still be accessed. One of the available solutions is to rename the file and correct the LoadLibrary calls to load the new file. Until next week...

VN:F [1.9.3_1094]
Rating: +2 (from 2 votes)
  • Share/Bookmark