Developing PE file packer step-by-step. Step 9. Delay-loaded DLLs and Image Config

Previous step is here.

Today we will do that little things, which I've put aside during my old packer development. Our new packer can do everything already, but we have a couple of small nuances and it will be good to finish with them. The first one is delay-loaded import. It allows to load required PE file libraries when they are really needed, thus saving time on loading image to memory. This mechanism is implemented by compilers/linkers only and it is not related to the loader. However, there is IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT directory in PE header, which points to delayed import data. I don't know whether this is used by linker and built program, but the loader ignores it, but we better leave this directory and don't zero it. Let's remove the line

This article tells about some unscientific bullshit.
If you are a physicist, biologist or just remember school program too well, you should not read it for your own good. Otherwise you risk to die by laugh. We warned you.

I see what you did there.
Information about this article is given as of undefined date. Probably it is hopelessly outdated and can be interesting only to Slowpokes.

That's all with delayed import. The next thing to pay attention to is image load configuration. There is such directory in PE file header, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG. This directory may contain IMAGE_LOAD_CONFIG_DIRECTORY32 structure for x86 PE files (IMAGE_LOAD_CONFIG_DIRECTORY64 for PE+), which provides information about how the image should be loaded. It also contains the address list of commands with LOCK prefix, which is replaced with NOP on single-processor systems, and the list of all SEH handlers (it is used to prevent SEH-hacking and it is actually the list of all legal and allowed exception handlers in PE file). Latest versions of MSVC++ compilers sometimes generate this directory and place there application SEH handlers list and a pointer to their security cookie (the variable to control buffer/stack overflow and corruption). Judging by Win 2000 kernel sources, all this is read by the loader, so it is not right to completely destroy IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG directory, although I didn't see any problems with PE files operation after zeroing it. Let's keep this directory by moving it to second packed file section ("coderpub"). Firstly, let's remove the following line from the packer code:

My PE library will always help us to deal with the rest. We will just move SE handlers list to our second added section. But we have to process LOCK prefixes address list manually in the unpacker (we won't move it, as the loader doesn't have to fix them at this stage - a file is not unpacked yet). In the unpacker, after the lines

add

These lines read image load configuration, if it exists. The code is similar to TLS. Further, change the line

to

because we will place the load configuration directory to "coderpub" section. Further, similarly change the line

to

and

to

and, at last

to

Then, we add a couple of new fields to packed_file_info structure (structs.h file):

We will need these fields in the unpacker, and we will fill them in packer for now by writing after

the following lines:

and after

the following:

I will explain why this is necessary. The loader determines, that our LOCK prefix table consists of a single element, which points to lock_opcode field of basic_info structure (we will build it that way, of course). On a single-processor system LOCK command opcode (0xf0), which we saved to this field, will be replaced with NOP instruction opcode (0x90), and we can check in the unpacker, whether we need to process original LOCK prefix table. In general, I'm not sure if this functionality exists in loaders of the systems starting from XP (it looks like all systems don't care about these tables), however, let it be, you never know when it may arise. Actually, I never saw any files with LOCK tables, and possibly I'm doing useless things. I saw those tables actually, in Win 2000 sources, but I will discuss that further :D

OK, that's all with editing, now we turn to configuration directory rebuilding. Right after the piece of code, which is responsible for exports rebuilding, we add the following code:

We rebuild load configuration directory and place it to the end of the second added to packed file section. We set in the unpacker options, that it is necessary to rebuild SE handler and LOCK prefix tables. We will process the original LOCK prefix table in the unpacker. That is all with the packer. Now we turn to the unpacker project. It looks like that the offsets specified in parameters.h file are corrupted again, and we can't be sure that they were correct at the previous step (MSVC++ builds the project in its own way, optimizing it by size, thus small changes can make the compiler to use other assembler commands). That's why I decided to set them once and for all, by doing this:

Now the assembler commands offsets [mov eax, 0x11111111] etc will be always the same, because the commands opcodes [mov eax/ecx/edx, number] are always the same. Let's edit the offset values in parameters.h file to fit the new code:

Further we write the following code before TLS processing code:

So we completed to work with, as it seems, not highly demanded functionality, because modern single-core processors ignore LOCK prefix, and the loader ignores LOCK prefix table. :)
It is curious, by the way, but EXE files from Win 2000 are being packed normally and work on it.

P.S. It seems, that in Win 2000 the loader doesn't care about LOCK prefixes too. The only thing it does while loading is checking that there are no NOP (0x90) instruction opcodes written at LOCK prefix addresses in multiprocessor systems. That time Windows had two kernels - single-processor and multi-processor, one of them was selected during installation. It looks like nobody implemented the Load Configuration directory described functionality since that time, but the fields with descriptions are still remaining. By the way, in Win 2000 the directory structure itself is completely different and some fields are missing. My PE library can't read it. But I decided to leave the functionality in the packer. Now the packer corresponds to open Microsoft documentation. However, their loader doesn't correspond it. :) At last, it is somehow useful to rebuild load configuration directory with keeping SE handlers addresses.

Full solution for this step: Own PE Packer Step 9

Leave a Reply

Your email address will not be published. Required fields are marked *