Book note _ WINDOWS mixed hook _ Part 2
1. Analyze PE files
Next we will look at the analysis of the PE file to find the DLL to be imported.
First, let's take a look at the import data. idata segment of the PE file .. The idata segment is the imported data, including the import and export address name tables. The data directory defined in winnt. H is:
// Directory Entry
// Export the Directory
# Define image_directory_entry_export 0
// Import directory
# Define image_directory_entry_import 1
// Resource Directory
# Define image_directory_entry_resource 2
// Exception directory
# Define image_directory_entry_exception 3
// Security directory
# Define image_directory_entry_security 4
// Relocate the basic table
# Define image_directory_entry_basereloc 5
// DEBUG directory
# Define image_directory_entry_debug 6
// Description string
# Define image_directory_entry_copyright 7
// Machine value (MIPs GP)
# Define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
// TLS directory
# Define IMAGE_DIRECTORY_ENTRY_TLS 9
// Load the configuration directory
# Define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
When analyzing the PE, you must first obtain the RVA of the import segment (that is, IMAGE_DIRECTROY_ENTRY_IMPORT of DataDirectory. Add the starting address (base address) of the RVA and the module in the memory to obtain the virtual address, which is the pointer to IMAGE_IMPORT_DESCRIPTOR.
The description of IMAGE_IMPORT_DESCRIPTOR is as follows:
IMAGE_IMPORT_DESCRIPTOR is in the import Section (Imports Section). The import points of the DataDirectory entry point all point to the IMAGE_IMPORT_DESCRIPTOR structure. The specific structure is shown in the following table:
Size |
Member |
Description |
DWORD |
OriginalFirstThunk |
This field is badly named. it contains the RVA of the Import Name Table (INT ). this is an array of IMAGE_THUNK_DATA structures. this field is set to 0 to indicate the end of the array of IMAGE_IMPORT_DESCRIPTORs. |
DWORD |
Timedatestamp |
This is 0 if this executable is not bound against the imported DLL. when binding in the old style (see the section on binding), this field contains the time/date stamp (number of seconds since 1/1/1970 GMT) when the binding occurred. when binding In the new style, this field is set to-1. |
DWORD |
Forwarderchain |
This is the index of the first forwarded API. Set to-1 if no forwarders. Only used for old-style binding, which cocould not handle forwarded APIs efficiently. |
DWORD |
Name |
The RVA of the ASCII string with the name of the imported DLL. |
DWORD |
Firstthunk |
Contains the RVA of the import Address Table (IAT). This is array of image_thunk_data structures. |
Each import execution block has an IMAGE_IMPORT_DESCRIPTOR structure.
After obtaining the first IMAGE_IMPORT_DESCRIPTOR structure, because all the DLL has the corresponding IMAGE_IMPORT_DESCRIPTOR structure, when the Characteristics domain is 0, it has reached the last DLL imported by this module.
Each IMAGE_IMPORT_DESCRIPTOR structure contains pointers pointing to two independent arrays. One of them is the address Data Pointer of all the functions imported by this module from the given DLL. It is obtained through the FirstThunk member of IMAGE_IMPORT_DESCRIPTOR, the OriginalFirstThunk in IMAGE_IMPORT_DESCRIPTOR is used to find a pointer array pointing to the IMAGE_IMPORT_BY_NAME structure. These structures contain the name of the function to be imported, unless the function is imported according to the serial number.
2. HookImportsOfImage Function
Let's look at the HookImportsOfImage function. Its function is to scan all modules and determine whether they have imported the GetProcAddress function from Kernel32.dll. If this IAT function is found, you can first modify the IAT memory protection mechanism, after changing the permission, use the hook to override the address in IAT. For more information, see the HookImportsOfImage function,
Ntstatus hookimportsofimage (pimage_dos_header image_addr, handle h_proc) { Pimage_dos_header dosheader; Pimage_nt_headers pntheader; Pimage_import_descriptor importdesc; Pimage_import_by_name p_ibn; DWORD importsstartrva; Pword pd_iat, pd_into; Int count, index; Char * dll_name = NULL; Char * pc_dlltar = "kernel32.dll "; Char * pc_fnctar = "GetProcAddress "; PMDL p_mdl; PDWORD MappedImTable; DosHeader = (PIMAGE_DOS_HEADER) image_addr; PNTHeader = MakePtr (PIMAGE_NT_HEADERS, dosHeader, dosHeader-> e_lfanew ); // First, verify that the e_lfanew field gave us a reasonable // Pointer, then verify the PE signature. If (pNTHeader-> Signature! = IMAGE_NT_SIGNATURE) Return STATUS_INVALID_IMAGE_FORMAT; ImportsStartRVA = pNTHeader-> OptionalHeader. DataDirectory [IMAGE_DIRECTORY_ENTRY_IMPORT]. VirtualAddress; If (! ImportsStartRVA) Return STATUS_INVALID_IMAGE_FORMAT; Importdesc = (pimage_import_descriptor) (importsstartrva + (DWORD) dosheader ); For (COUNT = 0; importdesc [count]. characteristics! = 0; count ++) { Dll_name = (char *) (importdesc [count]. Name + (DWORD) dosheader ); Pd_iat = (pdword) (DWORD) dosheader) + (DWORD) importdesc [count]. firstthunk ); Pd_into = (pdword) (DWORD) dosheader) + (DWORD) importdesc [count]. originalfirstthunk ); For (Index = 0; pd_iat [Index]! = 0; index ++) { // If this is an import by ordinal // The high bit is set If (pd_int [Index] & image_ordinal_flag )! = Image_ordinal_flag) { P_ibn = (PIMAGE_IMPORT_BY_NAME) (pd_INTO [index] + (DWORD) dosHeader )); If (_ stricmp (dll_name, pc_dlltar) = 0) & (strcmp (p_ibn-> Name, pc_fnctar) = 0 )) { // Use the trick you already learned to map a different // Virtual address to the same physical page so no permission problems // // Map the memory into our domain so we can change // Permissions on the MDL P_mdl = MmCreateMdl (NULL, & pd_IAT [index], 4 ); If (! P_mdl) Return status_unsuccessful; Mmbuildmdlfornonpagedpool (p_mdl ); // Change the flags of MDL P_mdl-> MdlFlags = p_mdl-> MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; Mappedimtable = mmmaplocakedpages (p_mdl, kernelmode ); // Address of the "new function" * MappedImTable = d_shareM; // Free MDL Mmunmaploackedpages (mappedimtable, p_mdl ); Iofreemdl (p_mdl ); } } } Return STATUS_SUCCESS; } |
HookImportsOfImage is a callback function that is called whenever an image (process, device driver, DLL, etc.) is loaded into the memory. The Code has searched every image and checked whether it has imported the Hook's target function. If the target function is found, it will replace its address in IAT.