For the people (and this article is dedicated for them), which have no clue about the thing and for the full coverage. PE (Portable Executable) is format of executable files of all newer Window$. In comparision with now nearly extinct NE species brings PE some substantial advantages. The most important one is the 32-bit FLAT model support. In this memory model the segments (as we know them from DOS or 16-bit protected mode) practically did lost its sense. Every process has its own adress space, we do not need to solve the old problem where to place some piece of code in order not to fuck up (overwrite) another proggy and so on. Due to this feature, can every program decide on its own, with practically no limitations, where it will store whatever it want. If the program wants to have at adress 0x1234567 some wierd string, it can expect the string will be really there. therefore it is not necessary for the program to have relacationa table (but there are some reasons why this table is linked to the program by default). As i mentioned before, segments in such a mode doesn't have any special nor important reason. Program after the start has already set CS, DS, and ES to the segments covering whole adress space (with 4GB size) and the program can access any desired adress. Of course, if the system thinks it it doesn't have access to this adress (if there is something important on this adress [this is not the case under W95 or W98] or there is nothing on this adress) attempt to access such a adress could generate exception. Such exception could be of course intercepted and the lamer at the keyboard will have no clue about it :-)... But this is far advanced for now...
As we want have the overview, how the adress space looks like, here it is:

Well, as a kick start it should be enough, let go to the PE itself. PE is format suspiciously similar to the COFF formats used on the Unix systems. It consists of header and the data area which is directly mapped to the adress space of the process. The headers itself are stored before start of code so if you want to find them align address to 4kB and track back to find page starting with 'MZ'. Of course don't forget to set exception handler for page fault.
EXE files are mapped staring at adress 0x400000. This starting adress is called ImageBase. It should be no suprise the ImageBase can be set during linking process. When the file is loaded couple of things happens (shit is none of them)

  1. headers are loaded into some buffer
  2. all the sections are mapped to some space, in order to avoid relocations, ImageBase is preffered. If the ImageBase is not free and the program has relocation table, file is mapped elsewhere and will be relocated.
  3. DLL needed by the program are mapped to the process
  4. pointers to imported functions are fixed
  5. stack is set
  6. program is executed (jump to some entry point)

note: i don't guarantee the steps above are performed in given order ;-)

As for the DLL mapping this process is similar, but jump to the entry point is not " just jump" but AL holds value which holds information whether

note: most likely calling of library entry point could be disabled by some way
note: naturally, library doen't have own stack

Due compatibility reasons every PE file starts with MZ header, where at offset 0x3C is dword ptr to the PE header.
File is divided in somethink like sectors (with variable size, by default 0x200 - FileAlignment) and file headers (all together, not every one separated) and sections are aligned to that size. This creates some space for storing the virus body (but under 4000 bytes) because on every section we can gain approx. 100h bytes and in the PE files do not use have to much sections. This strategy is used by CIH.

As for the structure of the headers, i strongly recommend to see file WINNT.H File header has following structure:

In the header i would like to point to some positions

  Machine processor, on which the file is able to run I386 = 0x14c
  NumberOfSections name says it all, for dummies number of the sections in program
  SizeOfCode size of all pages alloceted for code
  SizeOfInitializedData size of all pages allocated for data
  AddressOfEntryPoint RVA adress of entry pointu (relative 2 ImageBase)
  ImageBase starting on this adress all the sections are mapped
  SectionAlignment alignment of the sections (I386=0x1000)
  FileAlignment alignment of the file
  SizeOfImage size in bytes including all headers, has 2 be multiple of object align (allocated for code and data)
  SizeOfHeaders size of headers (including all section headers)
  CheckSum checksum - the same as in DOS - ignored
  Subsystem this tells the OS wheather it is windowed or console aplication
  DataDirectory this is a field belonging to the structure containing RVAs and sizes of some important tables

PE code and data are divided to sections. Each section has its description in header. Main purpose of this is to tell loader where in address space should be data stored, how big area should be allocated and what attributes should be set for them. For example code section should start at 4000000h and should be read only and executable. Special attribute for section is SHARED. If section is shared all instances of this program has this sections common. It means if one of them modifies something in section all instances can see it.

Some word of explanation to the RVA (RelativeVirtualAdress). All the complicated operations as e.g. relocation etc... is are performed AFTER the file is mapped to the memory. If we add to the RVA value the ImageBase, we get the pointer directly to the memory adress where the desired piece of information is mapped. Without mapping the problem is much harder, cos we need to search through all the sections and find the one RVA points to.


and offset in the file could be calculated as:

file_off = PhysicalAddress + RVA-VirtualAddress

And now there are only three problems to solve

  1. where should we store virus body
  2. how to make our fine virus the supreme commander in the system (aka we_need_to_be_first_on_the_draw)
  3. how to call API functions

1. Where to store the virus body
Before we will go any further, we should notice, that none of us known implementation of Window$ that checks if we execute the code in sections which is declared as data (cool enough ... :-P). This is the fact all the viruses (and packers as well) heavy relies on.

As for the storage of the body, i saw till now 3 different strategies.

Common strategy is based on the extending the last section. In such a case is "conditio sinne qua non" - basic condition the section should be writeable in the section attributes (Intel platform could check it). As for the implementation of this method, it easy as it could only be, but for resident viruses we can got in to the trouble.... Physical data in the section can be followed by uninitialized data, which can be changed by the program. This means our fine piece of code may become fucked up. Therefore whole viral body should be moved elsewhere.

Another method is to create new section in the file and copy virus body there. This approach has one major disadvantage (which is nearly impossible to solve) - nonstandard section name could arise a suspiction of something not very pleasant going on, not speaking of the situation header is to small for adding another section. Contrary, advantage is we have our section just for us, nobody can overwrite the virus. As for the implementation, trivial again in comparision with before mentioned method we have one aditional task - we need to know, where last section ends.

One of the non-standart method is the one used by CIH virus. This is all about the using the free space in sectors which are aligned to FileAlignment value (0x200 by default). This technique is very clever (invented by some as Germans use to say "Klugscheisser") as we get bonus in some cases there is no increase in file lenght plus the virus is harder to clean. This method will not be in the focus of this article as for the larges viruses in not suitable.

Main disadvantage of the first two methods is the code runs in the last section. And if some emulator get here, there are just and only 3 options left.

  1. virus
  2. packer
  3. some anti-whatever envelope

But solution is up to you - probably best way would be to use CIH approach and place entry point in the first sections.

2. we_need_to_be_first_on_the_draw
how to make our fine virus the supreme commander in the system

Most trivial solution is to modify AdressOfEntryPoint in the PE header to point to start of added (viral) code. In plain words put there RVA of virus entry point. Nothing more nothing less.

More rafined methods are e.g. to hook some import (let's say CreateFileA or whatevever is on 100% callled in every proggy) or even hook export in DLL's so every call to DLL goes through virus. This approach is not trivial as complicated search in structures is required. Some of the options will be covered in next section.

3. How to call API functions
This is the key problem of all the viruses. This problem could be transformed in the question - what API calls i need to get pointer to whatever API function?

Answer is GetModuleHandle and GetProcAdress. If we have pointers to this functions we can get pointer to any function we want.
Both of this two API calls are exported from kernel32.dll. As i haven't seen any application not importing something from this important system module we can perform test if the file we want to infect imports from kernel32.dll.

Then we have to search in import table and look for this two functions. If we find them, the file is suitable target for the infection.
Imports in PE file work that way they point to some dword and in this dword will be set address of imported function. All the requests in the file for specific API function will look like

call dword ptr [dddd]

Advantage for us is there is no problem to hook function and at each call to this function do "something".
To the import table we will get throug DataDirectory (i think index 1). This should point to the array of structures IMAGE_IMPORT_DESCRIPTOR. Last element of the array should have Characteristics set to 0. Name is RVA pointer to the name of the module from which the import is performed. OriginalFirstThunk points to array of type IMAGE_THUNK_DATA from which we can get the name of the function. Let's saz the function has index i. Then pointer to function f in imports will be i-th element of the dword array, to which FirstThunk points. Last element of the array of type IMAGE_THUNK_DATA is zero.

I recommend to see it all in HIEW and then in debugger search where the desired functions are.

As I mentioned before, there is no need to do all fixups while file is being infected. It is either possible to do it after file is loaded. Just find old 'MZ' header and trace file structure. (What is nice, rva are almost valid pointers so you need just to add base address and you can follow any structure). After you find first export to Kernel32 use the same method to find start of kernel32 and then follow export table ...

As for the exports it's much easier, but i had no time for experiments and will let this problem open. If you want know more, look for it in some PE doxes (RTFM).

I would like to point to the fact the article has been written more or less using just and only my memory (my degenerated gray cell mass), has not been subject to verification and thus i can't guarantee any fact presented here is true :))))))
If you are interested in the problem, you should see it again elsewhere, in some more reliable refference.

And finally, some warm closing words. If the fucking proggy doesn't work and you poor guy did check it all over and over about 10 times, try to find that bug in the Windows loader.