Writing Your Own Packer - by BigBoote
Writing Your Own Packer - by BigBoote
Why write your own packer when there are so many existing ones to choose from? Well, aside from making your executables smaller,
packing is a good way to quickly and easily obfuscate your work. Existing well-know packers either have an explicit 'unpack' function, or there are readily available procdump scripts for generating an
Since this document has quickly exploded in length I'm going to break it up into separate installments. In this installment I
will cover the qualitative aspects of producing a packer. I'll discuss what you're getting into and how the packer is
structured in general. I'll briefly discuss some pitfalls, and I'll give some links to technical information you will need
to be familiar with before going into the next installments.
In the next two installments I'll go into details of how to implement the components of the packer and how I usually go about producing them.
What You're Getting Into
It's not really hard, per se, but it is rather tedious code. Lots of pointer manipulation and translation to keep track of. Aside from
that, if you can write code to add and subtract integers and do file IO, you've got all the skill needed! As mentioned, it is tedious
code so you will probably do well to not attempt this coding on a hangover; trust me, I know.
FYI, the last packer I produced was fairly full-functioned (exes and dlls, several compression algorithms with debug capability and advanced support such as TLS (critical for Delphi
apps)) and it weighed in at about 3700 lines for the packer tool and about 1000 lines for the decompression stub it embeds in the target.
That's somewhere around 70 printed pages of code. So, not a huge app, but not a tiny one either. The first one I produced took about 1.5
weeks to produce including research and bug fixing. Subsequent ones took far less since I had already done the hard part, which is
figuring out how. Hopefully this document will save you that time as well!
FYI，我做的最新的一个功能相当完备的加壳机（EXEs 和 DLLs, 几种压缩算法，具有调试功能，高级技术的使用入TLS（对于Delphi的程序可能有点错误）），该程序差不多有3700行代码用于加壳工具，还有1000行用于嵌入目标程序的解压块。打印了70页纸。也就是说，不是很大的程序，但也不是一个小的。我第一个开发的差不多花了一个半星期（包括开发和调试）。接下来的几个花的时间就少了，因为我已经将困难的部分做好了。希望这个文档同样可以给你省下时间。
You do not have to use assembler for the most part. If you can part with supporting some esoteric features, you won't have to use it at all.
All of that is relevant for the decompression stub only anyway. The packer can be in Logo or Object-Oriented COBOL if you like.
OK, enough of the blahblahblah, on to technical stuff....
Simple. Executable is analyzed, transformed, and an extra piece of code is attached which gets invoked instead of the original program. This
piece is called a 'stub' and decompresses the image to its original location. Then it jumps to that original location. But you know this already.
Sounds simple, but there are pitfalls that await you. Some of these include:
* Support for simplified Thread Local Storage, which is key in supporting Delphi applications
支持单一的线程局部存储器(Thread Local Storage),支持Delphi程序的关键。
* Support for code relocation fixups in dlls if you care about packing dlls. Recall ActiveX controls are dlls too, as are other common things
you might be interested in packing
* Support for some stuff that must be available even in the compressed form. This includes some of your resources and export names in dlls
* Dealing with bound imports
* Support for stripping out directory entries that will confuse the Windows loader since the decompression won't have happened and they will
point to nothing useful, like the IAT and debug info
* Support for doing relocation fixups manually on your decompression stub since it will certainly be in a different memory location than where
the linker thought it would be when it was compiled
* Dealing with differences in interpretation of the PE spec between different vendor's linkers. Borland linkers interpret aspects of the spec
differently from Microsoft's so you need to be ready for that.
* Working around bugs in Microsoft code. There is an infamous one relating to OLE and the resource section. Many packers do not accommodate this
and this is important for ActiveX support.
OK, enough of the horror stories. The first step is to get painfully familiar with the file format of executables. This is called the 'Portable
Executable' format, or PE for short. I will discuss it briefly here. You will need more detail in reality. Rather than attempting to duplicate
that, here are some references you will find helpful:
The Portable Executable File Format from Top to Bottom
a good and readable discussion, but not totally accurate when it comes to the import section.
Dead wrong in implying that these sections always exist -- they easily can not exist. Still, a good read.
An In-Depth Look into the Win32 Portable Executable File Format pts 1 and 2
great article, weak on discussion of resource section
Microsoft Portable Executable and Common Object File Format Specification
horse's mouth. Dry. Accurate.
OK, after you've gotten familiar with those, we can start to write some code. I'm going to save that for the next installments
(probably two). They will detail:
* Making the Unpacker Stub
The stub has several responsibilities aside from the obvious decompression. It also has to perform duties normally done by the
* Making the Packer Application
The packer application does all the hard work. This makes since when you realize the stub is supposed to do as little as possible
to have a minimum impact on runtime.
I'll try to keep code examples to a minimum but there may be some reference to structure members when describing what's going on
and maybe a snippet or two where code is clearer than human language. Most of the important structures can be found in WINNT.H for those who wish to read ahead
This series is about creating exe packers for Windows 32-bit files.
Last installment I mentioned some of the big-picture aspects of creating an exe packer. In this installment I am going to talk about a particular part of the packer, the
decompression stub. This is the simpler part. In the next installment(s) I'll talk about the packer application itself.
Again, this isn't going to be source for a packer, but I might do a straightforward one and publish it as an addendum to this
series if folks are interested in having some working source as a starting point.
The decompression stub has several responsibilities:
* Find the packed data
* Restore data contents
* Perform relocation fixups
* Resolve all imports since the Windows loader couldn't do it
* Perform thread local storage duties since the Windows loader couldn't do it
充当线程局部存储器（thread local storage）的功能，因为Windows载入器无法使用。
* Boink over to the original program
* You may also have to handle being reentered if you are packing a dll
Oh, and it also has to run. So lets start with that...
A Stub That Runs
It's useful to remember that your decompression stub is actually a parasite onto a program that was never expecting for it to be
there. As such, you should try to minimize your impact on the runtime environment in your packer. I had mentioned before that you
could make a packer in Logo or Object-Oriented COBOL, and that really was only partially true. You can make the packer application
that way fer sure -- and you might even
be able to make the unpacker that way sometimes -- but you will really be much happier with C/C++/ASM for the stub part. I personally
like C++. Anyway, it will be smaller. If you don't care about the size, still using stuff like Delphi or VB for the stub would be
problematic because it hoists in subtle stuff like TLS and runtimes, and they don't have primitives needed to thunk over to the
original program. Plus it can hose COM stuff that the original app isn't expecting. So let's assume the unpacker will be in the
lower-level languages I spoke of and take solace that this is pretty straightforward code, and that the packer still can be in whatever.
是，假如你用C/C++/ASM来编写你的程序段会更令人高兴。我个人喜欢C++，它做的会比较小。假如你不介意程序大小，仍旧使用Delphi 或 VB
可能会有一些问题，因为它在敏感信息（像线程局部存储器thread local storage）和运行时间处理上不是很好，而且无法跳至原程序。加上
Since the stub is a parasite, and since it will have to be located in a spot at the original application's convenience, we will have to
be relocating it dynamically in the packer application. To help with this we will make the stub with relocation records. These are
usually used for dlls when they can't be loaded at their preferred address. We will make use of them when binding the stub to the
If you're an avid ASM coder, many things are more straightforward since you can take care to produce position-independent code.
This won't necessarily free you from all relocation concerns, however. The decompression library of choice may well not be
position independent. Also, and references to global data will need to be fixed up.