Figure 2: Excerpt from intrcpt.cpp
/*----------------------------------------------------------------- FUNCTION: Interceptor::bIsItInterceptedFunction PURPOSE: Determine whether the specified function was intercepted by us. We can do it because all our stubs has the same structure and points to our IntrerceptEntry function PARAMETERS: . void * p_pAddress Address of the function (or our stub) RETURN VALUE: BOOL TRUE if it is our stub there -----------------------------------------------------------------*/ BOOL Interceptor::bIsItInterceptedFunction ( void * p_pAddress ) { ASM_APIFunctionStub * l_pStub = (ASM_APIFunctionStub * ) (DWORD(p_pAddress) - offsetof(ASM_APIFunctionStub, instr_PUSHAD)); if(IsBadReadPtr(l_pStub, sizeof(ASM_APIFunctionStub))) return FALSE; if(l_pStub->instr_PUSHAD != PUSHAD_INSTR) return FALSE; if(l_pStub->offset_LogFunction != (DWORD)Logger::IntrerceptEntry - ((DWORD)(&l_pStub->instr_CALL)+5)) return FALSE; return TRUE; }//BOOL Interceptor::bIsItOurStubAddress /*----------------------------------------------------------------- FUNCTION: Interceptor::bInterceptVTableFunction PURPOSE: Intercept a function in the specified slot in the specified VTable. PARAMETERS: . ASM_APIFunctionStub * p_pStub - This is a stub which was prepared by the config file parser to intercept this function. But we may find many implementations of the same interface. Each implementation will require a separate stub. They will be different only by address of the original function. Therefore, we will use this stub the first time and allocate a new stub on the following calls. void * p_pVTable - Pointer to the VTable Our caller must verify that this is a good read pointer and enough memory is accessible to cover the slot in the table with the specified index. Normally the caller will intercept several functions and may check the memory only once for all. int p_iIndexOfFunction Index of slot in the VTable MemoryWithChangedAttributes & p_rMemChangedAttrib - object to control memory attributes change RETURN VALUE: BOOL TRUE on success, FALSE on failure -----------------------------------------------------------------*/ BOOL Interceptor::bInterceptVTableFunction ( ASM_APIFunctionStub * p_pStub, void * p_pVTable, int p_iIndexOfFunction,//non-negative MemoryWithChangedAttributes & p_rMemChangedAttrib ) { PVOID * l_ppPlaceInVTable = ((PVOID*)p_pVTable)+p_iIndexOfFunction; PVOID l_pCurrentFunction = *l_ppPlaceInVTable; if(bIsItInterceptedFunction((ASM_APIFunctionStub * ) l_pCurrentFunction)) return TRUE; ASM_APIFunctionStub * l_pUseStub = NULL; if(!p_pStub->m_dwOriginalFunctionAddress) { //This stub is not used. We may start using it p_pStub->m_dwOriginalFunctionAddress = (DWORD)l_pCurrentFunction; l_pUseStub = p_pStub; }//if(!p_pStub->m_dwOriginalFunctionAddress) else { //The stub is already used. We should try to //allocate a copy of it. MYTRACE(TF_NewStub, "Building a new stub for function %s::%s", p_pStub->m_dwModuleNameOffset, p_pStub->m_dwFunctionNameOffset); l_pUseStub = (ASM_APIFunctionStub * ) HeapAlloc(g_Data.m_hHeap, 0, sizeof(ASM_APIFunctionStub)); if(!l_pUseStub) { MYTRACE(TF_Error, "HeapAlloc(%d) failed. %s", sizeof(ASM_APIFunctionStub), ERR_EXPL(GetLastError())); return FALSE; } l_pUseStub->vInitInDll( p_pStub->m_dwModuleNameOffset, p_pStub->m_dwFunctionNameOffset, p_pStub->m_iFunctionIndex, p_pStub->m_dwParamsOffset, Logger::IntrerceptEntry, l_pCurrentFunction); } DWORD l_dwNumBytesWritten = 0; DWORD l_dwAddressOfCode = (DWORD)&l_pUseStub->instr_PUSHAD; //write the address of the stub to the VTable slot if(!bWriteMemory(l_ppPlaceInVTable, &l_dwAddressOfCode, sizeof(DWORD), p_rMemChangedAttrib)) return FALSE; return TRUE; }//BOOL Interceptor::bInterceptVTableFunction /*----------------------------------------------------------------- FUNCTION: Interceptor::bProcPInterface PURPOSE: Process a newly discovered interface. Intercept it's methods if it was prescribed by the config file PARAMETERS: . DWORD p_dwPointerToPIUnknown Address of the stack location where a pointer to the COM interface is stored. Pointer to the COM interface, in it's turn, points to a pointer to VTable. int p_iInterfaceIndex Index of the interface (in the config data) DWORD * p_rdwReturnedPIUnknown Return pointer to the interface DWORD * p_rdwReturnedVTBL Return pointer to the VTable char * p_pszReturnInterfaceName Return interface name char p_iInterfaceBufferSize Size of the buffer for the name RETURN VALUE: BOOL TRUE on success, FALSE on failure -----------------------------------------------------------------*/ BOOL Interceptor::bProcPInterface ( DWORD p_dwPointerToPIUnknown, int p_iInterfaceIndex, DWORD * p_rdwReturnedPIUnknown, DWORD * p_rdwReturnedVTBL, char * p_pszReturnInterfaceName, char p_iInterfaceBufferSize ) { if(p_rdwReturnedPIUnknown) *p_rdwReturnedPIUnknown = 0; if(p_rdwReturnedVTBL) *p_rdwReturnedVTBL = 0; if(p_pszReturnInterfaceName) *p_pszReturnInterfaceName = 0; if(IsBadReadPtr((void*)p_dwPointerToPIUnknown, 4)) { MYTRACE(TF_Error, "ERROR: wrong pointer to return addr. %x", p_dwPointerToPIUnknown); return FALSE; } DWORD l_dwReturnedPointer = *((DWORD*)p_dwPointerToPIUnknown); if(p_rdwReturnedPIUnknown) *p_rdwReturnedPIUnknown = l_dwReturnedPointer; FARPROC * l_ppVTable = 0; if(!l_dwReturnedPointer) return FALSE; if(IsBadReadPtr((void*)l_dwReturnedPointer, 4)) { MYTRACE(TF_Error, "ERROR: wrong pointer to interface. %x", l_dwReturnedPointer); return TRUE; } l_ppVTable = (FARPROC*) *((DWORD*)l_dwReturnedPointer); if(p_rdwReturnedVTBL) *p_rdwReturnedVTBL = (DWORD)l_ppVTable; MyInterface * l_pInterface = g_Data.m_pConfigMgr-> pGetInterfaceByIndex(p_iInterfaceIndex); if(!l_pInterface) return FALSE; if(p_pszReturnInterfaceName) lstrcpyn(p_pszReturnInterfaceName, l_pInterface->pszGetName(), p_iInterfaceBufferSize); if(!l_ppVTable || DWORD(l_ppVTable) >= 0x80000000 || IsBadReadPtr(l_ppVTable, l_pInterface->m_iMaxFunctionIndex*4)) { MYTRACE(TF_Error, "ERROR: wrong pointer to vtable. %x", l_ppVTable); return FALSE; } MemoryWithChangedAttributes l_MemChangedAttrib; for(int i = 0; i < l_pInterface->m_iNumFunctions; i++) { ASM_APIFunctionStub * l_pStub = l_pInterface->pGetStub(i); if(l_pStub) { bInterceptVTableFunction(l_pStub,l_ppVTable, l_pStub->m_iFunctionIndex, l_MemChangedAttrib); }//if(l_pStub) }//for(int i = 0; i < l_pInterface->m_iNumFunctionsFilled; return TRUE; }//BOOL Interceptor::bProcPInterface