Книга: Practical Malware Analysis: The Hands-On Guide to Dissecting Malicious Software
Назад: 18. Packers and Unpacking
Дальше: Identifying Packed Programs

, nonpacked PE files include a section that tells the loader which functions to import, and another section that stores the addresses of the names of all the imported functions. The Windows loader reads the import information, determines which functions are needed, and then fills in the addresses.

The Windows loader cannot read import information that is packed. For a packed executable, the unpacking stub will resolve the imports. The specific approach depends on the packer.

The most common approach is to have the unpacking stub import only the LoadLibrary and GetProcAddress functions. After the unpacking stub unpacks the original executable, it reads the original import information. It will call LoadLibrary for each library, in order to load the DLL into memory, and will then use GetProcAddress to get the address for each function.

Another approach is to keep the original import table intact, so that the Windows loader can load the DLLs and the imported functions. This is the simplest approach, since the unpacking stub does not need to resolve the imports. However, static analysis of the packed program will reveal all the original imports, so this approach lacks stealth. Additionally, since the imported functions are stored in plaintext in the executable, the compression possible with this approach is not optimal.

A third approach is to keep one import function from each DLL contained in the original import table. This approach will reveal only one function per imported library during analysis, so it’s stealthier than the previous approach, but analysis will still reveal all the libraries that are imported. This approach is simpler for the packer to implement than the first approach, since the libraries do not need to be loaded by the unpacking stub, but the unpacking stub must still resolve the majority of the functions.

The final approach is the removal of all imports (including LoadLibrary and GetProcAddress). The packer must find all the functions needed from other libraries without using functions, or it must find LoadLibrary and GetProcAddress, and use them to locate all the other libraries. This process is discussed in , because it is similar to what shellcode must do. The benefit of this approach is that the packed program includes no imports at all, which makes it stealthy. However, in order to use this approach, the unpacking stub must be complex.

through illustrate the packing and unpacking process, as follows:

  • shows the original executable. The header and sections are visible, and the starting point is set to the OEP.

  • shows the packed executable as it exists on disk. All that is visible is the new header, the unpacking stub, and packed original code.

    shows the packed executable as it exists when it’s loaded into memory. The unpacking stub has unpacked the original code, and valid .text and .data sections are visible. The starting point for the executable still points to the unpacking stub, and the import table is usually not valid at this stage.

  • shows the fully unpacked executable. The import table has been reconstructed, and the starting point has been edited to point to the OEP.

Note that the final unpacked program is different than the original program. The unpacked program still has the unpacking stub and any other code that the packing program added. The unpacking program has a PE header that has been reconstructed by the unpacker and will not be exactly the same as the original program.

sss
sss

© RuTLib.com 2015-2018