Manual Unpacking Project - FAQ


A Newbies guide to manual unpacking,
(part of +Sandman's ongoing projects)

Last Revision: July 16th 1999
Email: muproject@hotmail.com
Latest versions
available from:
http://members.tripod.com/~MUProject/Latest.zip


Questions:

  1. What is the purpose of this FAQ?

  2. How can we ask questions and/or contribute to this project?

  3. How do we know when this FAQ/Project has been updated?

  4. I have completed 'PartX' of the mini-projects where do I post the tutorial?

  5. Why would we want to unpack an executable?

  6. I've seen unpack utilities for BrandX, why can't I simply use them?

  7. What sort of utilities are available to pack/encrypt a program?

  8. I'm experienced at reversing, but this area is relatively new to me.
    Where's a good place to start?

  9. Blimey! All I want to do is patch a single byte in the uncompressed exe.
    Do I really have to do all this?

  10. Is packing a program like zipping a proggy? [Jeff]

  11. Is packing that simple and quick? [Jeff]

  12. What is the purpose behind packing up a proggy? [Jeff]

  13. Who would use such a packed proggy and why? [Jeff]

  14. Are the changes to the proggy always the same? [Jeff]

  15. HOW do we KNOW when we dl a proggy that it is packed? [Jeff]

  16. What, if any, tell-tale signs tell us this proggy may be packed? [Jeff]

  17. Does something happen in SoftIce or Win32Dasm to give us a clue? [Jeff]

  18. What tools would we need in our unpacking arsenal? [Jeff]

  19. Packers/encryptors/virri, etc, seem to be mentioned together quite often.
    Are they so similar?

  20. What is a PE Header? [Jeff]

  21. Can u tell at a glance, without tools, that the PE Header is screwy? [Jeff]

  22. What do the numbers we see in PE Header mean to us?
    (e.g. Entry point, Image Base, Virtual size, Virtual Offset, etc. etc.)

  23. Is ProcDump the only way to fix a PE Header?

  24. What happens in the proggy when its packed? [Jeff]

  25. What happens when our packed proggy is run?

  26. So for a simple target, as described above, how would I go about unpacking it?

  27. Ok, so what type of 'Sections' are there?
    What exactly are they, what do they mean, and where do they come from?

  28. It's been mentioned here that sections are unpacked over themselves.
    How can this work?
    Surely, if some sections are packed and others are not then some data
    would get overwritten because the unpacked data must be bigger!

  29. How did u KNOW to change a C00000040 to a E00000020 (<-in your initial post?)
    What are the significance of those numbers?

  30. 'I have applied the the things described here and in 'Further Reading' and have successfully reversed a 'BrandX' packed file! I am indestructible! I am 'master reverser', hear me roar!'

  31. Your Questions/Answers/Comments/Corrections/Contributions

  32. Further Reading


Reasons for FAQ

[Miz]
This FAQ is intended to give *basic* background information on the topic of executable packers and how to manually unpack and rebuild such files.

It will also serve as an introduction to the much more detailed unpacking project which will be created shortly.

It came about after several requests for information on +Sandman's Newbie messageboard. The topic is so broad the posts were often fragmented. As a result, a suggestion was made to centralize many of the questions people had, and to create a project that will offer real world examples. Hopefully it will help to de-mystify this area of reversing, as well as stimulate some interest in associated areas such as API hooking, decompilation, virii, anti-anti-Sice measures, encryption, etc.

This 'open' FAQ will be updated as frequently as possible and readers are actively encouraged to submit queries and/or contribute answers/ideas/knowledge.

How can we ask questions and/or contribute to this project?

Email: muproject@hotmail.com

How do we know when this FAQ/Project has been updated?

[Miz]
Once the full project is underway there will probably be some sort of mail-list or dedicated messageboard. In the meantime, please check for news on +Sandman's Newbie Forum. Details will be posted there when more information is available.

I have completed 'PartX' of the mini-projects where do I post the tutorial?

[Miz]
Please do NOT publicly release your tutorials. Please send them here (see the address above). They will be published along with this project as it gets updated. Once they are there (obviously), send them wherever you like.

This is to stop the mini-projects becoming a race and spoiling things for others.

Please read the 'Intro.txt' for more information.

Thanks.

Why would we want to unpack an executable?
[Miz]
There are several reasons, but IMO the main one is so that you remain informed about exactly what a specific program is doing. Deliberately hiding a programs code and hiding which DLL's and API functions it uses should set off warning lights with people concerned with even basic privacy and security.

In a Win9x environment any program has access to anything on your machine. Anything. I have no problem with the actual compression programs themselves, they provide a useful service and are excellent study material in their own right. My problem is with programs that can potentially abuse the side-effects of executable compression to hinder a target's examination and (if necessary) reversing. 'Baloney, you just want to patch the pants off it!' - purely a side effect, honest. Anyway, if a program's author has nothing to hide then he surely would not mind us checking for ourselves ;) By unpacking an executable down to the point that we can remove all traces of the original packer, repairing all the relevant PE data, we end up being able to dead-list code, use API monitors, make patches etc.etc.

We unpack so we can see.

I've seen unpack utilities for BrandX, why can't I simply use them?

[Miz]
Obviously you can if you want(!). But what if no unpacker yet exists for BrandZ? What do you do then? As mentioned previously, an increasing number of programs are being packed, and newer generations are coming out all the time. Learning how to do it manually will help you in such times.

On top of that, it is (IMO) a very interesting area for study, and touches on many other interesting areas. I've seen some hostile discussions on the importance of understanding/ignoring the PE format. Maybe studying such things as manual unpacking, virri, API hooking, etc, may make people understand it's relevance more, and give some more insight into what the system is up to in the background.

What sort of utilities are available to pack/encrypt a program?

[Miz]
Not so long ago the tools available were quite limited and often flaky. Lately they have become much more sophisticated, becoming commercial ventures, and as such, have been adopted by other developers. Why is it that developers only seem to trust things they have to pay for? Strange! The number of programs released with packed executables is on the increase, and is likely to keep increasing.

Programs such as Petite, Neolite, Shrinker, ASPack, etc, are widely used schemes, having been around for some time and consequently being more refined than others. Check out those programs. Many have evaluation periods. Reading their documentation gives a good background to the topic. Also check out the more basic ones from tools sites. Sometimes you find gems, like ones that come with source code or a 'how it was done' doc.

I'm experienced at reversing, but this area is relatively new to me.
Where's a good place to start?

[Miz]
Get hold of as much information as possible. Check the Further Reading section below.

Read, Read, then Re-read; particularly documentation like MattP's. Then, get hold of a small, simple executable - one you are familiar with. Pack it with an uncomplicated packer (suggest ASPack) and make it your aim to reverse it to being as close a copy of the original as you possibly can. Make it an ongoing project while you continue to search and read.

If you want to dive in straight away then check out Torn@do's packed crackme and its accompanying unpacking doc (included in the 'Library/OldStuff' directory). It skirts around the huge 'import' problem (that will be covered in much more detail as part of the main project), but it may be of some help. Please bear in mind the 'doc' was never intended to be a tutorial as such. Much more information will be provided here.

Alternatively, (and the way I learnt), after reading as much info as your brain can handle, write your own PE 'modifiers'. My first attempt was a modifier that reversed the order of all the bytes in the code section and swapped them back at runtime. Pointless, I know ;) But it didn't involve delving in the PE format that much, and its surprising how much such a trivial task can teach you. From there you can move to more involved tasks like packing the code section. From there packing the import section. etc.etc.

Sounds scary? Not with the resources available. I will keep referring to the excellent work that Stone did long ago in this area. I'm sure others have contributed equally as much, but for me Stone's work was a revelation. There's a simple pe-encryptor with source and docs on his site that can work as an great reference.

Blimey! All I want to do is patch a single byte in the uncompressed exe, do I really have to do all this?

[Miz]
If that's *all* you want to do then you're in the wrong place.
But to answer you more properly.....No.

Leave the executable packed but divert the final 'jump' (to the original entry point) to some of your own code that can then apply the patch to the now unpacked code/data. For you to be able to do this properly however, you will need some knowledge of caving or section construction; you'll need to write relocatable code that references the patch address in a OS friendly way (i.e. uses the ACTUAL base address, not the PREFERRED base address), etc.

This project, FAQ, and the references in Further Reading will give you the knowledge to do these things, and hopefully much more besides.

Is packing a program like zipping a proggy? [Jeff]

[Miz]
No.
In terms of compression they may use similar algorithms, but the difference is the way in which the compression is applied.,

  • An Archiver (like zip) just compresses the entire file as a binary image into a compressed binary image. It makes no decisions as to the type of file being packed, it will treat an .exe just like a .zzz, and makes no changes to the image other than compressing it as a big bag of bits.
  • An Executable packer has to make many more decisions about what it can and can not pack, working to restrictions imposed by the OS. For it to work it will need to modify the actual format of the executable, thereby creating the myth that they are not 100% reversible.
Is packing that simple and quick? [Jeff]

[Miz]
In terms of use, yes.
In terms of programming, no.
As mentioned above, packing executables involves many more details than simply compressing a chunk of raw data.

What is the purpose behind packing up a proggy? [Jeff]

[Miz] Allegedly, just to make it smaller - 40-60% of original size is about normal.
However, the things that get our attention are claims such as:

  • "'BrandX'...adding security against reverse engineering..."
  • "'BrandY'...protects code from prying eyes, disassemblers..."
  • "'BrandZ'...packed files can never be unpacked, please keep a backup..."
Who would use such a packed proggy and why? [Jeff]

[Miz]
Either someone who wants smaller files, or someone who is fooled by the false security promises.
The suspicious (I know...;)) will be more concerned with the 'why' than the 'who'.

Are the changes to the proggy always the same? [Jeff]

[Miz]
No. (If they were then it would all be rather dull - LOL). The beauty/bane of this topic is that it is constantly changing. With every generation of packers/encryptors/virri, etc, you will find something new.

Again the OS dictates some limitations, but other than that a packer/virus/encryptor can be as creative as its creator ;) It is because of this that this FAQ and the resulting full project will try to avoid direct descriptions of particular versions of packers. Instead we hope it will provide enough background knowledge for people to be able to cope with new 'generations' of packers as they emerge.

HOW do we KNOW when we dl a proggy that it is packed? [Jeff]

[Miz]
You probably won't be able to tell just by running it.
They usually claim to run totally transparent to the user. You can check it manually (by looking at the PE structure or examining the code) or by using some Exe checker such as GetTyp.

NOTE: Exe checkers will only know about packers they have been programmed to know about. They normally just check for signatures (byte strings) in the same way that virus checkers do. If you rely on an exe checker and it says a program is not packed then be sure to check it manually. It may be a latest revision of an existing packer which is not recognised yet.

What, if any, tell tale signs tell us this proggy may be packed? [Jeff]

[Miz]
Without inspecting the code itself, the biggest clues are additional sections, particularly if the entry point goes there. Sometimes additional sections are even named by the packer to the packers name (!) Also, taking a quick look with a hex editor around suspect areas may also uncover strings such as 'BrandX Packer v1.04 by UmBongo!', etc. Other clues are the lack of a readable import section (if that has been compressed) and subtle changes to Section Characteristics (eg '.TEXT' section becomes writable, etc).

Does something happen in SoftIce or Win32Dasm to give us a clue? [Jeff]

[Miz]
Disassemblers such as W32dasm may display garbage, nothing at all, or sometimes even crash. This is because they rely completely on the integrity of the PE structures. Softice is the initial tool of choice. We will use it, along with tools like ProcDump, to reverse an exe to the point that we can dead-list it again with something like W32dasm.

What tools would we need in our unpacking arsenal? [Jeff]

[Miz]
Useful tools to get familiar with are:

  • Softice (say no more)
  • A PE viewer (like PEBrowsePro)
  • ProcDump (Awesome, awesome, tool)
  • A 'temp-dumper' like +Quines SoftDump is very useful for cut and pasting blocks of memory.
  • An Exe checker (eg GetTyp) may help in identification, although this step is not necessary.
We will be using these tools in more detail in the main project, so if they're new to you, it may be handy to get familiar with their functions now.

Check any decent tools site and you will find dozens of utils for studying and modifying pe-files. Take a look at as many as you can, sometimes they even include source. Anything you can get your hands on may be of help.

Also, (it should go without saying), try writing your own. Check out Stone's site for some great starting points. The pe-encryptor he presents is a great foundation to this topic. Start with simple things and gradually work your way up.

Packers/encryptors/Virri, etc, seem to be mentioned together quite often.
Are they so similar?

[Miz]
The programming concepts are very similar. Like a virus an unpacker typically bolts itself on to a host executable. Hooking itself in as the first thing to run, doing 'something' (in this case unpacking the host), before allowing the host to continue.

Like a virus, unpackers often have to be resourceful in how they initialise. They may use similar steps to find API addresses, memory etc. Unpackers often decrypt part of their unpacking code, like exe-encryptors, to make examination more difficult. They may also employ similar anti-debugging measures. Packers/Encryptors/Virri quite often have to use fully relocatable code, and as such, use many of the same tricks (like the call [NextInstruction]/pop pair used to get the current eip).

Links to some virri descriptions are provided in Further Reading. Search for some more to see the similarities. Take a look at the cabanas one, hmmm ;)

What is a PE Header? [Jeff]

[Miz]
In general its the term used to describe the all the 'system' type information used by the OS to work out the resources, memory (size and type of), import/export information (eg DLL's required and API calls used), entry point, stack size, etc, of an executable.

The important thing to grasp early on is that an executable is not just a binary image of your code/data and nothing else. There are many pieces of additional system information attached so that the OS knows exactly what resources your executable will need.

It may be easier to think of an executable as a directory. In that directory are some files and some sub-folders containing more files. The structure of the whole directory tree will change from executable to executable. For example if your executable doesn't have any resources then the .RSRC section will be missing. If it contains debug information then a .DBG section may exist etc.

A simple scheme may be:
(Hint: The example here is actually Notepad.exe, so you can examine it yourself...)

DOS HEADER
FILE HEADER
OPTIONAL HEADERS
---IMPORT
---RESOURCE
---BASE RELOCATIONS
---IAT
SECTION HEADERS
---.TEXT
---.DATA
---.IDATA
-------IMPORT
-------IAT
---.RSRC
-------RESOURCE
---.RELOC
-------BASE RELOCATIONS
IMPORTS
----ADVAPI32.DLL
--------RegCloseKey
--------etc.etc.
----COMDLG32.DLL
--------ChooseFontA
--------etc.etc.
----GDI32.DLL
--------AbortDoc
--------etc.etc.
----KERNEL32.DLL
--------lclose
--------etc.etc.
----SHELL32.DLL
--------DragAcceptFiles
--------etc.etc.
----USER32.DLL
--------CharNextA
--------etc.etc.
RESOURCES
----ICON
--------1
--------etc.etc.
----MENU
--------1
--------etc.etc.
----DIALOG
--------12
--------etc.etc.
----STRING
--------1
--------etc.etc.
----ACCELERATOR
--------1
--------etc.etc.
----GROUPICON
--------1
--------etc.etc.
----VERSION
--------1
--------etc.etc.

(Still with us? ;))

If you're more familiar with older COM files you'll be amazed at the amount of information that is stored. It does indeed make unpacking more involved that before, however, it also makes certain areas (like API monitoring etc) very easy. More on that later.

If this structure is pretty new to you then I recommend you get hold of a decent PE viewer and get a feel for the structure of a PE file before delving deeper. Alot of tools exist, but my own favorite is PEBrowse Professional. There's also MattP's PEDUMP util, complete with source to study, see Further Reading below.

Look again at the above layout.

  • Can you see now how things like APISpy utils could work? Hmmm....
  • Can you see now how Resource grabbers could work? Hmmm.....
  • You can also probably see how a 'theoretical' packer could work. Aahhh....
Note: 'Sections' themselves are covered in greater detail later on in this FAQ.

[From MattP's Windows Secrets]

"Like all other Microsoft executable file formats, the PE file has a collection of fields at a known (or easy-to-find) location that define what the rest of the file looks like. The PE header contains vital pieces of information such as the location and size of the code and data areas, what operating system the file is intended to be used with, and the initial stack size."
Can u tell at a glance, without tools, that the PE Header is screwy? [Jeff]

[Miz]
Thankfully, there's very little that can be 'screwy' without causing major complications. Remember, packers/encryptors/virii etc, are limited in the amount they can mess with header structures due to OS restrictions. For them to work on all versions of OS they have to remain fairly compliant. As many virii writers found out, even structure elements that are marked as 'UNUSED' are very often used and cause problems with some OS when written to with 'ID' bytes or whatever.....

Anyways, 'screwy' PE Headers are normally a result of incorrect unpacking - something we will hopefully be avoiding ;)

What do the numbers we see in PE Header mean to us?
(eg Entry point, Image Base, Virtual size, Virtual Offset, etc. etc.)

[From MattP's Windows Secrets]

Image Base
When the linker creates an executable, it assumes that the file will be memory mapped to a specific location in memory. That address is stored in this field. Assuming a load address allows linker optimizations to take place. If the file really is memory mapped to that address by the loader, the code doesn't need any patching before it can be run. I'll talk more about this in the discussion of the base relocations. In NT 3.1 executables, the default image base was 0x10000. For DLLs, the default was 0x400000. In Windows 95, the address 0x10000 can't be used to load 32-bit EXEs because it lies within a linear address region that's shared by all processes. Therefore, in Windows NT 3.5, Microsoft changed the default base address for Win32 Executables to 0x400000. Older programs that were linked assuming a base address of 0x10000 will take longer to load under Windows 95 because the loader needs to apply the base relocations.

RVA (Relative Virtual Address) AKA Relative Offset
Many fields in PE files are specified in terms of RVAs. An RVA is simply the offset of some item, relative to where the file is memory mapped to. For example, let's say the Windows loader mapped a PE file into memory starting at address 0x400000 in the virtual address space. If a certain table in the image starts at address 0x401464, the table's RVA is 0x1464:

(virtual address 0x401464) - (base address 0x400000) = RVA 0x1464

Virtual Offset AKA Virtual Address
In EXEs, this field holds the RVA for where the loader should map the section to. To calculate the real starting address of a given section in memory, add the base address of the image to the section's Virtual Address stored in this field. With Microsoft tools, the first section defaults to an RVA of 0xl000. In OBJs, this field is meaningless and is set to 0.

VirtualSize
This field has different meanings, depending on whether it occurs in an EXE or an OBJ. In an EXE, it holds the virtual size of the code or data section. This is the size before rounding up to the nearest file-alignment multiple. The SizeOfRawData field later on in the structure holds this rounded-up value. Interestingly, Borland's TLINK32 reverses the meaning of this field and the SizeOfRawData field, and appears to be the correct linker. For OBJ files, this field indicates the physical address of the section. The first section starts at address 0. To find the physical address of the next section, add the SizeOfRawData value to the physical address of the current section.

Entry Point AKA AddressOfEntry
The address where the image begins execution. This is an RVA, and usually can be found in the .text section. This field is valid for both EXEs and DLLs.

[Miz]
Of course there are many more elements than these. We will explain the ones we encounter as the projects progress, but get a full overview by reading other references (like MattP or the official PE docs).

Is ProcDump the only way to fix a PE Header?

[Miz]
Not necessarily, most packers leave this up to the user.

As mentioned earlier, the '.TEXT' section is the general name for the section containing code. Early versions of packers and encryptors only modified this section as it was by far the easiest to do, and 'protected' the main code. More modern packers give the ability to pack/encrypt most section types including imports and resources. Doing this stops people using APISpy programs and Resource grabbers as well as complicating the whole unpack operation. Sometimes packers pack all but the first Icon group so that your program still retains its own icons when in explorer etc.

Remember, by the time the first instruction of the executable is executed most of the usual headers have been processed by the OS. So if you choose to pack these as well (for example the import section) then the system will have no knowledge of it and so the unpacker has to build it up itself.

This is where most people get confused and the sub-topic of import/reloc, etc, rebuilding, will be covered in detail in another section.

What happens in the proggy when its packed? [Jeff]

[Miz]
That depends on the packer. However the OS determines some limitations.

Say you just wanted to pack the '.TEXT' (usually code) section.
(NOTE: You should always verify a sections contents by checking its Characteristics).

A *very* simplified flow could be:

  1. Pack and replace the original section.
  2. Make necessary changes to the 'SizeOfRawData' etc. for that section.
  3. Make necessary changes to the RawOffsets of other structures.
  4. Append new section containing decompression routine and any relevant data (like which sections were packed and original entry point) to the executable.
  5. Add an additional section header to the Section Headers describing our new one.
  6. Change the number of sections in the main header.
  7. Change the entry point to our decompressor's entry point.

Like I said, a *very* simplified overview, but it should give you some idea what is going on. Not all packers will create additional sections, for example. They may (if there's enough room) choose to cave an existing section or even extend the size of existing sections, techniques used by some virii.
What happens when our packed proggy is run?

[Miz]
As above, it depends on the packer. But a simple flow could be:

  1. Initialisation
    The unpack code will probably need to get hold of some API function addresses. Routines like GetModuleHandle, LoadLibrary, and GetProcAddress, are very commonly used and so need to be found by the unpacker. Memory function addresses may also be required if the unpack is not in-situ.
    (Note: Some packers use their own import section and consequently do not need this 'find addresses' stage).

    What is meant by 'In-situ'?
    Some packers unpack over the source data (section). Others may unpack to a buffer and then copy the entire buffer down to the relevant section. The In-situ method requires no external memory other than that already allocated by the OS. The other method will require something like a VirtualAlloc/Free pair.

  2. Main unpack
    Get next packed section and unpack it. If no more then goto stage 4, otherwise....

  3. Extra processing
    If the section was simple (like a '.TEXT' code section) then goto 2.
    If the code was more complex, like an import section or a reloc section then some extra processing will need to be done. For import sections you will see the unpacker filling the IAT manually by calling LoadLibrary (if not already loaded) for each DLL listed and GetProcAddress for each API function used in the executable. Many will also cover their tracks by destroying the original import data. This is very important.

  4. Calculate the Original entry point, using the pre-known offset and the ACTUAL imagebase.

  5. 'Jump' to it.
So for a simple target, as described above, how would I go about unpacking it?

[Miz]
You don't - the unpacker unpacks for you ;)
Your task is really one of rebuilding, rather than unpacking.

What you would like is an unpacked image, as close as possible to the original, and one that works with the OS correctly.

Here's an example you may be more familiar with:

  • ProgX, when run, decrypts a small block of code, then runs it.
    The standard way of tackling this is to let ProgX decrypt the block, copy it to the relevant place and nop out the decrypt. That way, next time it runs, it still works but is not decrypting anymore. The block is now stored as plaintext (or plaincode ;)).
In principle, unpacking is exactly the same.

Now imagine a '.TEXT' section is packed. You know that depacker encounters it, unpacks it and continues. *In principle* it's simply a case of letting the unpacker unpack it, then stopping the unpacker unpacking it next time.

Why *in principle*?

Because there are many caveats, which we will see later, but it's the concept that is important to grasp.

Think now about what wrapper-style packers (like Petite, Neolite, Shrinker, ASPack etc.) can and can not do.
Specifically: at the time control is passed to the original executable's entry point, all relevant code and data must be functionally identical to the original (unpacked) exe. If this were not true then programs would obviously not run correctly. At the point that the Original Entry Point (OEP) is called, the unpacker has completed all it's tasks and waves goodbye.

'If this is the case, then (again, in principle) surely 'dumping' the executable's image to disk at this point would be all that was needed, yes?'

Again, yes and no ;)
It is correct to assume that is all your code/data would need to be 100% correct at this point but it is incorrect to assume that all the OS information stored in the PE header would be correct. Remember, the windows loader uses this information to allocate resources, process imports/exports, the loading and linking to DLL's, etc, on your behalf. If this information is no longer correct then running a program dumped in this way would cause a crash, probably at system level. Boom, SIce pops up in Kernel. Grrr.

'Ah, that's just because the entry point is pointing to the wrong place, soon fix that.....'.

No (patience grasshopper...) - remember, the entry point is just a *tiny* bit of the information needed by the OS in order to correctly process an exe. We really need to be sure we are fixing *all* the relevant information required by the OS. This is the (assumed) difficult part of unpacking. For us to be confident in our ability to restore executables then we really need to be familiar with the actions of unpackers, very familiar with the structure and [and functionality of] the PE Header, as well as the actions of the Windows loader.

Ok, so what type of 'Sections' are there?
What exactly are they, what do they mean, and where do they come from?

[Miz]
Remember, the 'Section Headers' part of the PE Header refers to the *location* (offset) within the main executable's image of the sections' data. They also detail the type, size, characteristics (flags), etc, of that section. Remember, the actual data for that section is stored elsewhere. If you are unfamiliar with structures and pointers then think of these 'structures' as card indices in a library. If you want to find the location in a book in a library you will look at the card indices. When you find the correct card it will give more details as to the type of book, location, etc. By reading the card you know where in the library to look. (ok, so maybe the standard 'letter/address/house' description would have been better ;))

Sections themselves can be thought of as chunks of distinct code, data, system resources, user resources, etc.

'But when I program I have no knowledge of these!'

It depends on what type of assembler/compiler/linker you use. The data is orgainized in this way because it is an OS requirement, not a programming one. It makes no real difference to most programs WHERE the stuff is stored, but it very important that everything is in the right place and correct for the OS.

'So if I wrote a simple program like a messagebox that says 'UmBongo!' then how would that look when compiled/linked into and executable?'

Your code would be placed in it's own section. The string (data) 'UmBongo!' would be placed in its own section. You would have and import section that described what relevant DLL's and API calls you used (User32 and MessageBox), any icons that were created would go in a resource section, etc.

Here's some brief descriptions of commonly encountered section types:

  • .TEXT
    Normally the name of the section that contains all the executable's code.
    Normally? Well, like all sections here, it could be any name, but this is the convention.
    Borland C++ put code in a more properly named 'CODE' section, although it's linker did some more problematic things as well. Most however follow these conventions.

  • .DATA
    Speaks for itself really. This is where all the executable's data is stored. *Stored* is an important word here. There are two types of data in terms of the storage they require - initialised data, and you guessed it, uninitialised data.

    Think of initialised data as things like strings (text), or a block of data to decrypt; ie chunks of data with some predetermined value.

    Think of uninitialised data as being variables (not predefined ones), empty arrays, etc; ie blocks of data that will be filled by the executable with some data at runtime, but at startup have no preset values.

    'Why are these treated separately?'

    Initialised data obviously needs room in the exe to be stored, whereas uninitialised data does not. The Windows loader will MAKE the room for this data when a file is loaded, but it requires no storage in the executable itself, other than the section description. Hence the two types of data section.

  • .BSS
    The uninitialised data section (see above).

  • .IDATA
    Ah, this (along with reloc) is the painful one ;) [Deep breath.......]

    The '.IDATA' section provides all the information the OS needs about what DLL's and API calls were explicitly linked with the executable.

    'explicitly linked?'
    Yes - 99% of executables will use this method, although it is possible for an executable to control it's own DLL loading via LoadLibrary calls in the main code.

    'So just by looking at this section, and without running the program itself, I can figure out whether it uses winsock, mapi, even if it uses a messagebox?!'

    Yes. That's how programs like QuickView/DLLShow etc. work, and more interestingly how API spy programs can monitor API calls from executables. It is because of this that many packers choose to pack this section. Obviously by packing it you are 'hiding' it from such programs and (more importantly) us!

    'So why is this 'painful' in terms of unpacking?'

    Well, judging by the number of emails and posts, this is the thing that confuses people the most. Understanding the concept of dumping, etc, comes quickly, but many do not see the importance of correctly fixing this section. It is *vital*, in order for an executable to work correctly all the time, in all enviroments, that it has a correct import section.

    'So why can't I just dump it, just before control passes to the original exe?'

    Remember we said that for the original program to function correctly then all it's code and data must be correct? Remember also that we said that an executable's image contains much more information that just that? Remember that we said the OS relies on this information to correctly provide the resources for an executable? Also remember that by the time control passes to the original exe then all of it's OS initialisation has already taken place?

    'Well, if a packer has packed the import table then how on earth can the OS know what's going on?'

    The answer is it doesn't need to, *IF* the unpacker has done the work that the OS would normally do for itself.

    'What does the OS do with this section then?'

    Take a look at an ascii-dump of any '.IDATA' section. You'll see strings; names of DLL's and API functions. These are no use to an executable in that format. Somewhere, somehow, these must be processed into a format more usable for the exe.

    I'm going to divert for a bit, but you'll see why.......

    Imagine your messagebox program again. When you do a call to 'MessageBox' the compiler/linker does something that may at first seem very strange. If you look at it in Softice you will see something like Call [USER32!MessageBox].

    What is strange about that? Look more closely. This explanation from MattP's book should clarify things. If not, keep re-reading. Its an important thing to grasp.

    [Extract From MattP's Windows Secrets]

    "...I was surprised to find out that there was additional code in the ..text section beyond what I created with the compiler or used from the runtime libraries. In a PE file, when you call a function in another module (for example, GetMessage() in USER32.DLL), the CALL instruction emitted by the compiler doesn't transfer control directly to the function in the DLL. Instead, the call instruction transfers control to a JMP DWORD PTR [XXXXXXXX] instruction that's also in the ..text section. The JMP instruction jumps to an address stored in a DWORD in the .idata section. This .idata section DWORD contains the real address of the operating system function entry point, as shown in Figure 8-4. After contemplating this for awhile, I came to understand why calls to DLLs are implemented this way. By funneling all calls to a given DLL function through one location, there's no longer any need for the loader to patch every instruction that calls a DLL. All the PE loader has to do is put the correct address of the target function into the DWORD in the .idata section. No CALL instructions need to be patched. This is markedly different from NE files, where each segment contains a list of fixups that need to be applied to the segment. If the segment calls a given DLL function 20 times, the loader must copy the function's address into that segment 20 times. The downside to the PE method is that you can't initialize a variable with the true address of a DLL function."
    ....skips a few pages....
    "....Visual C++ 2.0 (and onwards).....introduced a new twist to calling imported functions. If you look in the system header files from Visual C++ 2.0 (for example, WINBASE.H), you'll see a difference from the Visual C++ 1.0 headers. In Visual C++ 2.0, the operating system function prototypes in the system DLLs include a __declspec(dllimport) as part of their definition. The __declspec(dllimport) turns out to have quite a useful effect when calling imported functions. When you call an imported function prototyped with __ declspec(dllimport), the compiler doesn't generate a call to a JMP DWORD PTR [XXXXXXXX] instruction elsewhere in the module. Instead, the compiler generates the function call as CALL DWORD PTR [XXXXXXXX]. The [XXXXXXXX] address is in the .idata section. It's the same address that would have been used had the old JMP DWORD PTR [XXXXXXXX] form been used."
    [Miz again...]
    Ok, can you see now what the OS is doing with the '.IDATA' section before your executable starts? Yup, it builds an indirect 'jump table', filling it with the correct addresses of all the DLL functions used by an exe. The exe calls these functions indirectly via this table of offsets. As you can see it means that we don't have to fix hundreds of calls within the actual code section itself. Readers familiar with other operating systems will understand how helpful this really is!

    'So for an unpacker to correctly initialise this table it must process the names stored in the '.IDATA' section. How does it do this?'

    API functions exist for this, they were mentioned previously, and are used by programs that load and handle DLL's themselves. The more relevant calls are GetModuleHandle, LoadLibrary, and GetProcAddress. Full docs on these functions are supplied in separate .txt files with this package. Read them and see how they would be applied to create the table.

    'Alot of information to absorb, so where does that leave us in terms of unpacking files and correctly restoring their PE Headers?'

    As you can hopefully see by now, if we are intending to bypass (and remove!) the unpacker completely then we really have to make sure that we have valid information in the PE header so the OS can do all this for us again.

    'How do we tackle this?'

    There are many ways, and the way you choose will depend on how the unpacker handles these things. Here's a simple example for a simple unpacker's scheme:

    • Say 'BrandX' packer treats all sections the same when they are unpacking (not uncommon...). When you step through the code, you would see the '.idata' section being filled with the text we are expecting. This is nice! Later it will process this section itself, generating the IAT, by using GetModuleHandle / LoadLibrary / GetProcAddress calls. Then it may deliberately destroy the 'names' in the '.idata' section. This is bad!

      What we can do here is let it unpack the '.idata' section, but *importantly* stop it from generating the IAT and wiping the contents of the original data. If we can do this then we have a valid import table again, ready for the OS to process. All we would need to do then is to alter the relevant 'Directory' settings in the PE Header to point to the correct offset and size of this new (original!) import section. Remember, we are doing all this so, eventually, we no longer have to rely on ANY of the unpacker's code, and so can even remove the unpacker completely.
      Virginity restoration.

    This is a simple explanation of a simple scheme. It's the thing I 'glossed over' in the original post on Torn@do's ASPack packed crackme. I'm sure you can appreciate why now ;) The version of ASPack used made this easy to do, but not particularly easy to explain (I didn't want to confuse people too much!). Other packers, and I'm sure future versions of ASPack, will not make things this simple so make sure you understand the information here - read as many other resources as you can (See Further Reading). The concepts will always be similar, but expect things to be get tricky soon ;)

    Now, where were we.....oh yes, section descriptions....

  • .RELOC
    'Fixups', if you like.

    Remember that 'ImageBase' was our PREFERRED loading address, but that the OS could, in theory, put it anywhere it wants? (It is very rare for the OS to do this, but it's the fact that it can that is important).

    If a .RELOC section exists, then in unpackers, just like in the windows loader, you will see the code checking the preferred and actual imagebases. If they are the same then the info in the .RELOC section will be ignored, otherwise it will need to make some 'fixups' to anything that assumed it would be located at the preferred image base. The areas to 'fix' are stored in this (.RELOC) section.

    'How does this affect us?'

    Well, if we have (in effect) dumped the code/data and fixed the import issue, but NOT fixed the reloc section then we have code, etc, that will ONLY work if it is located at the imagebase when the dump occurred. Like the import section, we need to fix this so that we have a valid one for the OS to process should it decide later that it wants the imagebase to be something else. Here's something that explains a real world example:

    [Extract From MattP's Windows Secrets]

    "Not having a correct .RELOC section....might cause the executable to not work on other Win32 platforms. For example, let's say you built an EXE for NT and based the EXE at 0x10000. If..(the reloc section was not there or invalid)....the EXE wouldn't run under Windows 95, where the address 0x10000 isn't available (the minimum load address in Windows 95 is 0x400000; that is, 4MB).

    It's important to note that the JMP and CALL instructions generated by a compiler use offsets relative to the instructions, rather than actual offsets in the 32-bit fiat segment. If the image needs to be loaded somewhere other than the location the linker assumed was a base address, these instructions don't need to change, since they use relative addressing. As a result, there are not as many relocations as you might think. Relocations are usually needed only for instructions that use a 32-bit offset to some data.

    For example, let's say you had the following global variable declarations:

    int i;
    int *ptr = &i;

    If the linker assumed an image base of 0x10000, the address of the variable 'i' will end up containing something like 0x12004. At the memory used to hold the pointer ptr, the linker will have written out 0x12004, since that's the address of the variable 'i'. If the loader (for whatever reason) decided to load the file at a base address of 0x70000, the address of 'i' would then be 0x72004. However, the pre-initialized value of the ptr variable would then be incorrect because i is now 0x60000 bytes higher in memory. This is where the relocation information comes into play. The .reloc section is a list of places in the image where the difference between the linker-assumed load address and the actual load address needs to be taken into account."

    [Miz again....]
    Ahhh! Something else to make sure we fix in the PE Header so that the OS can process our executable correctly. The methods of identifying and fixing ..RELOC sections are almost identical to the way we should handle the '.IDATA' section. We need to make sure we do this else we are not doing a correct job of reversing the executable. We want something that works, not something that works sometimes ;)

  • .EDATA
    The opposite of a .IDATA section. I=Import, E=Export.

    Like the .IDATA section, the .EDATA contains a list of functions, only this time they are the names of functions WITHIN the executable that are EXPORTED to other modules. .EDATA sections are more frequent with DLL's (because they obviously EXPORT the functions that the executable IMPORTs), but they can also (rarely) occur within executables themselves. You will probably have noticed the 'Import Functions / Export Functions' controls within W32dasm. Load a few executables into it and see. Then take alook at some dll's.....

    If you want to read more on this (and things like export forwarding ;)) then take alook at MattP's stuff. He goes into some detail there. For our purposes (ie unpacking), it's just another section we'll have to deal with.

  • .RSRC
    Resources. Menus, Dialogs, Strings, Icons, Bitmaps, Accelerators, Versions etc.etc.

    Everything a resource grabber grabs, and now you know how ;) Again, just like any other section.

    Note: If a program chose to pack this section then things like correct icons would not be displayed in Desktop, explorer etc. For that reason many (if packing the .RSRC section) strip out the first icon group and store it unpacked elsewhere. That way the executable 'looks' correct when viewed by other programs via icons.

  • .OTHERS ;)
    There are many others (check out other documentation), but these are the main ones we will be encountering.
As I'm sure you've seen above, the practice of manual unpacking is far more involved that simply doing a 'dump'. Hopefully the above (brief!?) descriptions give some further insight into the importance of fixing the PE Header so the OS doesn't go ballistic when something is not correct.
It's been mentioned here that sections are unpacked over themselves.
How can this work?
Surely, if some sections are packed and others are not then some data would get overwritten because the unpacked data must be bigger!

[Miz]
Another important concept to grasp.....
The disk image of the executable is not the same as its memory image.

Another slight digression now, but something you may wondered about before......

Imagine you wanted to patch some code in an exectable and have found the relevant location using SIce (or whatever). It may give an address like 0x401234, and from what you have learnt from the PE header, you know that the preferred ImageBase was (say) 0x400000. If the disk image and the memory image were the same then the offset in the executables disk image to patch would be 0x401234-0x400000 = 0x1234, right?

Wrong.

'So, what happens for these to be different?'

Well, the way the executables MEMORY image is layed out is specified by some information within the PE Header. The OS uses this information to organize and create the memory for the executable. It 'maps' the sections based on information stored in the PE header.

Remember before, when we looked at the differences between initialised and uninitialised data? Remember we said that for uninitialised data the PE Header only specified how much 'room' it would need but required no actual storage in the disk image? Lets look at how this was done. It's a simple example that can be extended when looking at other section types.

Each section description within the section table has the following fields:

[..Extract from WinNT.h, remember to look here for the structure definitions....]

typedef struct _IMAGE_SECTION_HEADER {
    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
    union {
            DWORD   PhysicalAddress;
            DWORD   VirtualSize;
    } Misc;
    DWORD   VirtualAddress;
    DWORD   SizeOfRawData;
    DWORD   PointerToRawData;
    DWORD   PointerToRelocations;
    DWORD   PointerToLinenumbers;
    WORD    NumberOfRelocations;
    WORD    NumberOfLinenumbers;
    DWORD   Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
[..Back again..]

The answer lies in VirtualSize, VirtualAddress, SizeOfRawData and PointerToRawData.

Now go and take a look at a few section descriptions using a PE viewer before continuing to read the rest of this answer. Get a feel for the type of numbers in them and how they differ. Look at some unpacked files' sections as well as packed ones. You should immediately see some big differences.

Done that? Good. Then the following will make more sense....

VirtualAddress vs PointerToRawData:

  • The PointerToRawData is the OFFSET from the *disk* image base (start of the file if that's easier) to the beginning of that section's data.
  • The VirtualAddress however is the OFFSET (RVA) that the OS will map that section to in the MEMORY image, relative to the ACTUAL imagebase used.
(It should also be noted that both the PointerToRawData and VirtualAddress are multiples of numbers dictated to by the OS - see MattP's for details on these - suffice to say there are often (very!) useful 'holes' at the ends of sections that have been used to pad the sections to whatever alignment size used.)

So, can you see how we could use this information to calculate the file offset for a patch address (given it's address in the memory image) using the PE Header?

Heres an example:

Memory Address we want to patch = 0x401234
ImageBase used                  = 0x400000
RVA from imagebase therefore    = 0x001234  (0x401234-0x400000)

In our imaginary PE File we also see the following for the .TEXT section

VirtualAddress                  = 0x001000  (say)
PointerToRawData                = 0x000200  (say)
From that you can see that the offset in the exe to patch would be 0x434.

(0x1234 - 0x1000 = 0x234, so our data is 0x234 bytes 'into' this particular section, and the DISK image of this section is 0x200, so our the diskimage address would be 0x200+0x234 = 0x434!).

'This is all very interesting, but I don't see the relevance!'

It is very relevant if you are going to manually dump files and sections as we will see later. But for now the important ones to understand are the differences in the 'size' members - VirtualSize and SizeOfRawData.

As you have some knowledge now about the differences between RVAs and raw offsets, VirtualSize and SizeOfRawData should be quite simple. VirtualSize is the size of the block of memory the OS will allocate for this particular section and the SizeOfRawData is the size that section takes up in the diskimage.

'Why would these be different?'

For a number of reasons. We already have seen one big one in how the OS will map an uninitialised data section. In this case it will set SizeOfRawData to zero, and set the VIRTUALSIZE to the size actually needed by the program.

'But how does it apply to packing/unpacking?'

Well, imagine the following scenario:

Unpacked Section size  =  0x008000
Packed Section size    =  0x004000   (Packed to half it's original size)
Given these numbers, how could we keep the disk image small (the whole point of packing!) but also make sure the system prepared us enough room for the unpacked data to go?

Read it again if the answer is not immediately obvious.

Got it? Cool.
Yup, simply set SizeOfRawData to the (aligned) PACKED size, and set the VirtualSize to the size of the UNPACKED data.

'Is it really that simple?'

Well, these changes obviously have knockon effects for the other sections. They can not be changed in isolation. If you change the sizes of addresses for a section then all the others would need to have THEIR addresses/offsets moved up or down to compensate. Remember that we said some packers packed in-situ and others used blocks of memory allocated by the unpacker? The reasons why they choose different methods is normally determined by the compression algorithm used. But you should now be able to see how an in-situ packer can work with out overwriting other sections.

How did u KNOW to change a C00000040 to a E00000020 (<-in your initial post?)
What are the significance of those numbers?

[Miz]
I was puzzled as to why the SIce loader would not break on entry.
Bearing in mind that no packing code could execute before the break meant that the reason must be in the executable's PE header somewhere. The obvious section to look at was the section that the break was to be applied and when I looked at the characteristics they didn't tally with what I KNEW was there. A quick look at the WinNT.h header file showed what bits needed to be set and after changing them SIce broke at the entry point.

If you refer to the original post and the WinNT.h header the significance should be clear. We are basically changing the section characteristics back to what they really represent. For example, packers may change the system charateristics to make sections writable (because they write the unpacked code back to the section's memory, as allocated by the OS) and to fool SIce and disassemblers, etc.

I would have thought this would screw up some OS, particularly NT with it's stricter policy on memory management, but it apparently works......most packers seem to have adopted it.

Anyway, by changing it back we may even be fixing bugs in the packers ;)

[From MattP's Windows Secrets]

"What most programmers call flags, the COFF/PE format refers to as characteristics. This field is a set of flags that indicate the section's attributes (code/data, readable, writeable, and so on). For a complete list of all possible section attributes, see the IMAGE_SCN_XXX XXX #defines in WINNT.H.

Some of the more important flags.....

0x00000020 This section contains code. It is usually set
           in conjunction with the executable flag (0x80000000).
0x00000040 This section contains initialized data. Almost all
           sections except executable and the .bss section have
		   this flag set.
0x00000080 This section contains uninitialized data
           (for example, the .bss section).
0x00000200 This section contains comments or some other type of
           information. A typical use of this section is the
		   .drectve section emitted by the compiler, which contains
		   commands for the linker.
0x00000800 This section's contents shouldn't be put in the final
           EXE file. This section is used by the compiler/assembler
           lo pass information to the linker
0x02000000 This section can be discarded, since it's not needed by
           the process once it's been loaded. The most common
           discardable section is the base relocations section (.reloc).
0x10000000 This section is shareable. When used with a DLL,
           the data in this section is shared among all processes
           using the DLL. The default is for data sections to be
           nonshared, meaning that each process using a DLL gets
           its own separate copy of this section's data.
           In more technical terms, a shared section tells the
           memory manager to set the page mappings for this section
           so that all processes using the DLL refer to the same
           physical page in memory. To make a section shareable,
           use the SHARED attribute at link time. For example:

           LINK/SECTION:MYDATA, RWS ...

           tells the linker that the section called MYDATA should be
           readable, write able, and shared. By default, Borland C++
           DLL data segments have the shared attribute.
0x20000000 This section is executable. This flag is usually set
           whenever the Contains Code flag (0x00000020) is set.
0x40000000 This section is readable. This flag is almost always set
           for sections in EXE flies.
0x80000000 The section is writeable. If this flag isn't set in an EXE's
           section, the loader should mark the memory mapped pages
           as read-only or execute-only.
           Typical sections with this attribute are .data and .bss.
'I have applied the the things described here and in 'Further Reading' and have successfully reversed a 'BrandX' packed file! I am indestructible! I am 'master reverser', hear me roar!'

[Miz]
Congratulations sir/madam, you have now dipped your toe into this area. But I'm afraid that is not all. Although the background information presented here should stand you in good stead for life, many of the techniques will no doubt be out of date within months, especially as more and more people tackle such targets. It's an ongoing saga, and that is its real beauty. Very rarely are new ideas and approaches offered up by targets on their own. For far too long have we been bored by mind-numbingly tedious 'protections' against reversing. Countless keyboards must have their 'B','P','X','G','E','T','D','L','I', and 'M' keys worn down to stumps.

Unpackers/encryptors etc have been adopted as 'protections' by many developers too lazy to do their own. As such, when shown to have weaknesses, they will improve. Remember, they are now commercial ventures, and it makes no commercial sense for them to remain trivial to bypass. Expect new versions, new ideas and techniques. More fun for us. At last, something interesting we can use to pass those long lunchtimes and late night sessions that isn't all over in 3 seconds ;)

Your Questions/Answers/Comments/Corrections/Contributions

Further Reading