Beginner Tutorial #6
By: Shub-Nigurrath /ARTeam
http://cracking.accessroot.com

Packers theory v1.1

The Target:
none
The Tools:
Ollydbg 1.10
The Protection:
packers

Other Information:
This tutorial will cover some basic concepts about protectors packers, such as AsProtect and other, which have been left out of the previous beginner tutorials. I think that with this last beginner tutorials you will be ready to start cracking at a sufficient level and you'll be able one day to do the jump to another level...

Best viewed in Firefox at 1280x1024

Introduction:

Reading a lot of tutorials I realized that some of them do not simply contains complex tricks and solutions, but also very elegant descriptions of some basic concepts. The problem is that these descriptions are not read often with the proper attention: beginners will not read those tutorials and experienced crackers most of the times already know those concepts. So, those little "gems" remains mostly unknown to who could benefits from them most.

I then decided to collect some of these descriptions into an unique tutorial about the packing of exe application and the theory of what happens behind. Moreover this arguments perfectly fits into the secuence of the arguments already described in the previous beginner tutorials... so as usual fasten your seat belts..

I integrated the text coming from different papers to make an organic text and I will cite the original sources only if needed and only in the final references section..

 



Description of a Packer:

A packer is a program aimed to prevent somebody else from examining how our program works or from modifying it. Typically, the entry point of the protected program is diverted to run the packer first. When it runs, the packer will carry out the following (main) steps:

  • Decrypt the sections of the target (target = packed program).
  • Rebuild its imports table.
  • Jump to the actual entry point of the target.

The first step, sections decryption, isn’t important for us. Normally, it doesn’t use to be much of a problem to await until they are decrypted in memory and simply dump them to a file and glue them up together. However, points 2 and 3 are crucial. The imports protection can be done with several degrees
of sophistication, some of the implementations (in reallife packers) are quite weak and do not need at all our methods to be broken. We will always suppose that a strong protection has been applied to the IAT, meaning:

  1. The Imports Table has been removed, the packer saves only (in a secure place) the hashes of the API names and their addresses at the IAT.
  2. The algorithm is well obfuscated and has lots of anti-debug, anti-trace...
  3. The packer doesn’t use GetProcAddress. Instead, it implements its own algorithm to find the APIs at the exports  table of the DLLs.
  4. The IAT has been redirected

It’s amazing to see how many ”commercial” products don’t comply neither with (1) nor with (3).

What about 4 (API redirection)?. Let’s try to see what ”API redirection” means: Open any application, it’s sure
that it imports kernel32.ExitProcess. Now, look for a call to it, you will find something like the following:

  call [XXXXXXXXh]      ; call to kernel32.ExitProcess XXXXXXXXh inside the IAT
  ...                   ;
  XXXXXXXXh: YYYYYYYYh  ; address of Kernel32.ExitProcess
 

The other most common possibility is to have a call XXXXXXXXh instead, the argument would be the same. The Windows loader ”sees” the imports table and fills the IAT with the addresses of the imported APIs. Packers destroy the information at the imports table of the protected program, therefore the IAT will have incorrect values when the packer yields control to the target. Then, the consequence is that the packer needs to fill the IAT of the target with the right values.

If you take a packed program, under a packer satisfying (4) - examples: Asprotect, Slovak Protector,...- the IAT looks like:


  XXXXXXXXh: ZZZZZZZZh      ; ZZZZZZZZh is inside a buffer dynamically
                            ; allocated by the packer, so it will
                            ; not exist if you remove the packer.
  ZZZZZZZZh: push ebp       ; (*)
            ror eax, 16h
            pushf
            popf
            mov ebp, esp    ; (*)
            call @@1
            db 68h
       @@1:
            add eax, 134h
            ....
            jmp ACTUAL_ENTRY_POINT_OF_API + k

The packer mixes the first instructions of the API with some garbage code (in the example, those instructions having a ”*” beside were in the original API code), it can include some trivial anti-debug trick too, and finally writes a jump (or something similar) to the entry point of the API + k, where k is the number of original instructions already run among the garbage code. This way, it is essentially impossible to find the actual API called through ZZZZZZZZh or to hook it.

The imports table is not a straightforward structure, going into details is out of the scope of this tutorial, see [2] for more references.

Some programs, called import rebuilders, are able to emulate a few instructions to search for the address in the DLL we jump to. Then, you can retrieve the API name from the exports table. However, import rebuilders are usually very limited in what they can sniff and will not overcome the latest packers (which, obviously, are tested against them before their release).

Let’s see what’s the matter with the entry point. As we commented, the packer - once it has done its job (decrypted the target, reconstruct the IAT,...)- has to give control to the protected application. This can be done running it as a new thread, with kernel32.CreateThread, or simply jumping to it in some exotic way. Running it as a new thread is not a good idea, the starting address of the thread will be too evident and so, we (again) suppose the worst case:
The packer jumps to the entry point after a long time of well obfuscated and protected code, the jump is well hidden (self-modifying code, etc...).

Stolen Bytes
Another problem one usually has to deal with is ”stolen bytes”: The packer takes a pre-defined set of APIs, a very common one is GetModuleHandleA, and does the following:

  • Calls GetModuleHandleA and stores the return.
  • Looks inside the protected app for patterns like:
      call XXXXXXXXh
           ; call to kernel32.GetModuleHandleA
      mov [handle], eax

Now, it removes the call and, on every startup, substitutes the mov [handle], eax by a simple mov [handle], harcoded_value, where hardcoded_value was returned before by the packer’s call to GetModuleHandleA.

If the cracker doesn’t detect this trick then the unpacked program will not run on all OS versions or will have another defect. These bytes the packer removes are called ”stolen bytes”. A full description of a packer is well out the scope of this tutorial, please refer to [1] for a detailed explanation.

Understanding the problem of stolen bytes
As we briefly reviewed above, the packer will emulate the first k instructions of the API and will jump to the (k+1)-th. This k first instructions can be metamorphosed, for example, for k=2 we might have:

; not changed entry point of
; kernel32.ExitProcess inside
; KERNEL32.DLL.

77E55CB5 kernel32.ExitProcess    push ebp
77E55CB6                         mov ebp,esp
77E55CB8                         push -1

; example of instructions you could
; find at the buffer:
           xchg eax, esp
           sub eax, 4
           jmp @@1
           db 68h
       @@1:xchg eax, esp
           mov dword ptr [esp], ebp
           push esp
           pop ebp
           push (77E55CB8+RANDOM_VALUE)
           sub dword ptr [esp], RANDOM_VALUE
           ret


They both do the same, however the second one is not easy to follow. The longer and more difficult to emulate is the buffer the harder is to reconstruct the imports table. Now, observe that if you set a breakpoint on the entry point of kernel32.ExitProcess this will be easily bypassed by the packer. Of course, one can set this breakpoint later but then knowing the call parameters can be difficult (or impossible).

Having the possibility of setting breakpoints on (suitable) places of the APIs is an important problem, control over their behaviour yields immediate control over the packer.

Packers are the preferred way to protect middle-price applications, virtually all shareware depends on their security. Thus, studying their advantages and disadvantages is an important field in RCE (Reverse Code Engineering)

 

 

How AsProtect works:

ASProtect, from ASPack Software (http://www.aspack.com), isn't just another commercial anti-cracking program; it is a truly revolutionary advance in software protection. It may be the prepackaged solution to software protection for those who don't want to spend long hours studying and programming custom protection for their own software.

ASProtect's creator Alexey Solodovnikov learned a lot from his work on ASPack and applied that experience to ASProtect. He claims that because all anti-cracking defenses can be defeated, the only important thing is under what circumstances they can be broken.

While it was created especially for shareware developers, ASProtect can be used for professional software as well. While it's not as versatile as FLEXlm (discussed later in this chapter), and it works only under Windows, I daresay that it is currently the most difficult commercial software protection to break. Its only weakness is that it doesn't have the best anti-debugging tricks.

Compared to other commercial software protection, ASProtect is simple and well-programmed, reflecting the simple but wonderful idea behind it. Like similar programs, the original program is compressed and then uncompressed by ASProtect before it is run.

ASProtect's compression is based on the ASPack algorithm, which is among the best. While it adds about 60KB of code to the original program, this additional code doesn't matter at all, since the resulting compressed program is much smaller then the original one.

ASProtect's decompression routine checks to see whether there have been attempts to change the file, and it tries to prevent changes in memory. Naturally, without decompression, the original program can't be disassembled, and it isn't easy to decompress ASProtect because it tries to prevent memory dumps by programs like ProcDump. Once the import section has been dumped from memory, the PE file will not be correct. Still, there is a way to decompress ASProtect (not by just dumping), but ASProtect is still not defeated even after successful decompression.

Like FLEXlm, ASProtect tries to prevent the use of certain functions in the protected program when it is unregistered, and it does so beautifully compared with other software. For example, if a programmer wants to disable Preview in the unregistered version, he need only encode this function with ASProtect (as shown in Figure 6.2). After registration, the disabled part is decoded using a constant from the registration key, and it is not possible to decode it without this registration key. ASProtect's exceptionally strong encoding prevents even direct (brute-force) attacks.

There are three ways to secure an application with ASProtect. The first way uses classic compression and
is not recommended because it's relatively easy to decode.

The second possibility is much more interesting, though still not the best. With this method, the original protection is first authenticated after the ASProtect API is called with a constant for decoding the encoded part of the program. You might use this method if, for example, the program you want to protect already has its own registration control and you don't want to change it. This method would be a poor choice if the original protection is weak, since it would not prevent the cracker from getting the correct constant.

The third and best possibility doesn't add any protection to your program (although additional protections are possible). Basically, when using this third method, you specify in the Registration Keys tab in ASProtect that you want your project to contain a registration key (as shown in Figure 6.3 on page 80). The program then creates a basic constant that will serve as a base for other keys, and that will also be used to encode the protected part of the program. You can generate the keys according to user names, and you can also save them. Finally, you determine where the registration key will be saved in the registry following registration.

Note ASProtect's key files have KEY endings but are essentially REG files that are imported into registers once they have been double-clicked. This is an advantage, because ASProtect's registration keys are rather long, and it would be tedious for users to enter them by hand.

The next step is to verify the registration. If you have only a registration key, the program will print the name of the registered user. You can also specify keys that have been illegally made public if you don't want them to function in future versions of the program. Subsequent versions of ASProtect will probably be able to generate keys for only one computer, which will prevent the illegal distribution of registration keys.

Finally, in the program code you specify the parts of the program that you want to encode—this is a simple procedure that can be performed by almost any programmer. Currently ASProtect contains code examples for Delphi, Visual C++, and Visual Basic. For instance, here's a short example in Visual C++:

include <windows.h>
#include "include\asprotect.h"
char *message;
void RegisterAction ()
{
   REG_CRYPT_BEGIN
   message = "Registered version !";
   REG_CRYPT_END
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
   message = "Unregistered version !";
   RegisterAction();
   MessageBox (0,message,"",0);
   return 0;
}


You must add REG_CRYPT_BEGIN to the beginning of the encoded program and REG_CRYPT_END to the end.

In other words, at the beginning of the encoded part of the program, you must add the following data:

0EBh, 04h, 0EBh, 05h, 89h, 89h, 0E9h, 0, 0, 0, 0

And the following data is added at the end:

0EBh, 04h, 0EBh, 05h, 99h, 99h

This data enables ASProtect to find the areas that you want to encode.

Next, you need only call the procedure and the rest will be done for you. If a program isn't registered, the encoded part will be skipped, or else an error will occur. If the program is registered, this part will be decoded at the start of the program, and it will be used later when it is called.

You can get the user's name with the apiGetRegInfo() API function.

Should you need to create many registration keys at once, ASProtect makes it easy by supplying the library keygen.dll. You can generate registration keys with its two functions. The GenerateKeyAsRegFile() function creates a registration file based on user information. Alternatively, the GenerateKeyAsString() function returns the memory pointer to where the registration key was created.

ASProtect allows you to set the number of times that a program can be run or the number of days it will be useable. Unlike similar commercial programs, all protection is placed in the PE file, and not in added DLL or OCX files.

As of this writing, it is impossible for a cracker to correctly remove ASProtect's protection (that means to decode the encoded portion of the program). To do so, he would need to use the correct registration key to decode the program and then dump it from memory. Of course, should the program's creators consider this attack, they may prevent it too by adding additional protections.
 

 

References:

I suggest the following further readings from now on to complete your beginner's training, than you'll be free to specialize in anything you like most, unpacking protectors, writing loaders or other things..

  1. Havok, “Asprotected notepad” Codebreakers-Journal, First Issue 2004.
  2. Labir, E., “Adding imports by hand” Codebreakers-Journal, First Issue 2004.
  3. Matt Pietrek, An In-Depth Look into the Win32 Portable Executable File Format Part 1, Inside Windows, http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx
  4. Matt Pietrek, An In-Depth Look into the Win32 Portable Executable File Format Part 2, Inside Windows, http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/default.aspx
  5. BiW tutorials pages, http://biw.rult.at/index.php?page=tuts
  6. Codebreakers Journal, http://www.codebreakers-journal.com/

and obviously our tutorial's page ^__^
 

 

Conclusion:

Thanks to the whole ARTeam:
[Nilrem] [JDog45] [Shub - Nigurrath] [MaDMAn_H3rCuL3s] [Ferrari] [Kruger] [Teerayoot] [R@dier] [ThunderPwr] [Eggi] [EJ12N] [Stickman 373] [Bone Enterprise] [KaGra]

Thanks to all the people who take time to write tutorials.
Thanks to all the people who continue to develop better tools.
Thanks to Exetools, Woodmann, SND, TSRH, MP2K, TEAMICU and all the others for being a great place of learning.
Thanks also to The Codebreakers Journal, and the Anticrack forum.

If you have any suggestions, comments or corrections contact me in usual places..