Figure 2: Reading import descriptors
Excerpt from Intrcpt.cpp /*----------------------------------------------------------------- FUNCTION: Interceptor::iInterceptImportedFunctionsInModule PURPOSE: Intercept functions imported by the specified module as we were instructed by the config file PARAMETERS: . PVOID p_pModuleBaseAddress Base address of the module PCSTR p_pszFileName Name of the file for this module bool p_bRestore Undo the interception bool p_bUseFile - If true -read the import info from the file. NT drivers may have import descriptors in "INIT" section, which is discardable. Therefore, we will try to read it from file RETURN VALUE: int Number of intercepted functions 0 if no functions of interest were found -1 on error -----------------------------------------------------------------*/ int Interceptor::iInterceptImportedFunctionsInModule ( PVOID p_pModuleBaseAddress, PCSTR p_pszFileName, bool p_bRestore, bool p_bUseFile ) { if(!p_pModuleBaseAddress || ULONG(p_pModuleBaseAddress) < 0x80000000) return 0; // we don't work with user addresses PIMAGE_NT_HEADERS l_pNTHeader = (PIMAGE_NT_HEADERS) pCheckModuleHeader(p_pModuleBaseAddress); if(!l_pNTHeader) { MYTRACE(TF_Error, "ERROR : cannot recognize module header %s at %x", p_pszFileName, p_pModuleBaseAddress); return -1; } IMAGE_IMPORT_DESCRIPTOR* l_pImportDesc; ULONG l_dwImportsStartRVA = l_pNTHeader->OptionalHeader.DataDirectory [IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; if ( !l_dwImportsStartRVA ) { MYTRACE(TF_Error, "ERROR : cannot find import table in module %x", p_pModuleBaseAddress); return -1; } l_pImportDesc = (IMAGE_IMPORT_DESCRIPTOR*) (ULONG(p_pModuleBaseAddress) + ULONG(l_dwImportsStartRVA)); // Find the section (usually .idata) that contains the imports. PIMAGE_SECTION_HEADER l_pSection = GetEnclosingSectionHeader(l_dwImportsStartRVA, l_pNTHeader); if ( !l_pSection ) { MYTRACE(TF_Error, "ERROR : cannot find a section containing the " "import table in module %x", p_pModuleBaseAddress); return -1; } ULONG l_dwImportFileOffset = 0; NTSTATUS l_Status; MyFileLocal l_File; if(p_bUseFile) { long l_lDelta = (long)(l_pSection->VirtualAddress - l_pSection->PointerToRawData); //This delta is the difference between the location of this //section in memory and in the file. In order to find the //offset in the file of some object, which belongs to this //section, we should subtract the delta from this //object's RVA. l_dwImportFileOffset = l_dwImportsStartRVA - l_lDelta; //Some file names returned by ZwQuerySystemInformation //does not have any directory information. They seems to //always be in Winnt\system\drivers. Other have //the directory in the form "Winnt\System\". In both cases //we should make correction in the directory name to //be able to open the file. char l_szFilePath[2*_MAX_PATH]; if(!strchr(p_pszFileName, '\\')) { //this file name has no directory. //May be it is in Windows\System32\Drivers //Try to contruct a full path _snprintf(l_szFilePath, sizeof(l_szFilePath), "\\SystemRoot\\System32\\Drivers\\%s", p_pszFileName); p_pszFileName = l_szFilePath; }//if(!strchr(p_pszFileName, '\\')) else if(!_strnicmp(p_pszFileName, g_Data.m_pParams->m_szWindowsDir+2, g_Data.m_pParams->m_iLengthWindowsDir-2)) { //In this case the module name is in form //"\WinNT\some_dir\module_name" //Try to contruct a full path _snprintf(l_szFilePath, sizeof(l_szFilePath), "\\SystemRoot\\%s", p_pszFileName + g_Data.m_pParams->m_iLengthWindowsDir-1); p_pszFileName = l_szFilePath; } l_Status = l_File.OpenFile(p_pszFileName, false,false, NULL); if(!NT_SUCCESS(l_Status)) { return -1; } }//if(p_bUseFile) int l_iNumFunctions = 0; while ( 1 ) { IMAGE_IMPORT_DESCRIPTOR l_ImportDescr; if(p_bUseFile) { //Read the next IMAGE_IMPORT_DESCRIPTOR structure //from the file LARGE_INTEGER l_liOffset; l_liOffset.QuadPart = l_dwImportFileOffset; l_Status = l_File.ReadWriteFile(false, &l_ImportDescr, sizeof(l_ImportDescr), &l_liOffset, NULL); if(!NT_SUCCESS(l_Status)) { break; } l_pImportDesc = &l_ImportDescr; } //If p_bUseFile == false, we already have l_pImportDesc //pointing to the location in memory, where the import //descriptor is, unless it is discarded. // See if we've reached an empty IMAGE_IMPORT_DESCRIPTOR if ( (l_pImportDesc->TimeDateStamp==0 ) && (l_pImportDesc->Name==0) ) { break; } for (IMAGE_THUNK_DATA * l_pThunk = (IMAGE_THUNK_DATA*) (ULONG(p_pModuleBaseAddress) + ULONG(l_pImportDesc->FirstThunk)); l_pThunk->u1.Function; l_pThunk++) { if(p_bRestore) { ASM_APIFunctionStub * l_pStub = IsItInterceptedFunction(l_pThunk->u1.Function); if(l_pStub) { InterlockedExchange ((long*)&l_pThunk->u1.Function, l_pStub->dwGetOriginalFunctionAddress()); MYTRACE(TF_Intercepted, "Import %s restored in %s", l_pStub->m_dwFunctionNameOffset, p_pszFileName); l_iNumFunctions++; } } else { ASM_APIFunctionStub * l_pStub = g_Data.m_pConfigMgr->pFindStubByOrigAddress ((void*)l_pThunk->u1.Function); if (l_pStub) { ULONG l_dwHookAddress = (ULONG)&l_pStub->m_Code; InterlockedExchange ((long*)&l_pThunk->u1.Function, l_dwHookAddress); MYTRACE(TF_Intercepted, "Import %s intercepted in %s", l_pStub->m_dwFunctionNameOffset, p_pszFileName); l_iNumFunctions++; }//if(l_dwHookAddress) } }//for (l_pThunk... if(p_bUseFile) l_dwImportFileOffset += sizeof(l_ImportDescr); else l_pImportDesc++; }//while (1) l_File.CloseFile(); return l_iNumFunctions; }//int Interceptor::iInterceptImportedFunctionsInModule