Next: Limitations
Up: Prototype Implementation
Previous: Software Architecture
The .RAD section is set as read/write/executable. It needs to be writable since the RAR is also a part of this section in addition to the RAD code. However, At run time the non-RAR part of this section needs to be set to read-only, through a Win32 API call VirtualProtect(). This is to create mine-zones on both the sides of the RAR to prevent attackers from overflowing the RAR. The key issue here is how to locate the entry point of VirtualProtect(). There are several cases to consider. First, it is possible that the input program also uses VirtualProtect() for some other purpose and thus the pointer to its entry point can be located by scanning the binary statically. Otherwise, if the input program does not need VirtualProtect(), the PE component needs to add code to locate its entry point at run-time.
For the first case, two PE headers of interest here are the Import Address Table (IAT) and the Import Name Table (INT). The two tables can be reached from the import directory, whose location in turn is obtained from the DataDirectory array in the PE OptionalHeader. Each entry in the IAT, at run time, contains the address of an imported function and the on-disk binary file. For each IAT entry there is a corresponding entry in the INT, which points to the name of the corresponding imported function. At load time, the loader overwrites the IAT entries with the virtual addresses where the corresponding functions are mapped. To locate the entry point of VirtualProtect(), we look up the INT by its name and retrieve the index of the associated IAT entry if there is a match. If VirtualProtect() is already imported by the input program, then its entry point is readily available from its IAT entry. If there is a match in the INT but the corresponding IAT entry is empty, then we need to dynamically resolve the entry point of VirtualProtect() by calling GetModuleHandle(), which gets the base address of the DLL containing the API function in question, and then calling GetProcAddress(), which gets the address of the desired API function from the export directory of its containing DLL. The entry points of GetModuleHandle() and GetProcAddress() themselves are obtained from the IAT through their containing DLL, kernel32.dll. In the case that none of these API functions are themselves imported, which is quite rare, then the PE component needs to emulate the operation of GetModuleHandle() and GetProcAddress(). This emulation idea is derived from an undocumented virus code and is based on the following observation: At the program entry point, the top of the stack contains a return address, which points to somewhere inside the function CreateProcess(), which in turn belongs to the DLL kernel32.dll. With this address, one can scan through the memory until where kernel32.dll is mapped is found. Once the base address of kernel32.dll is known, the entry points of GetModuleHandle() and GetProcAddress() are available through the DLL's export table, and in turn the entry point of any API function can be identified through these two functions.
Finally, the entry point of the executable in the PE header should be changed to the new initialization code, which locates the entry point of VirtualProtect(), and calls it to protect two pages surrounding the RAR.
Next: Limitations
Up: Prototype Implementation
Previous: Software Architecture
Manish Prasad
2003-04-05