📄 spyengine.cpp
字号:
PFNVOID SpyEngine::SetPrivateApiMethod
(
PFNVOID p_pHookMethod
)
{
//We need to find an unused slot in our private API.
//Start searching from slot #2 because slots #0 and #1 are
//used for special purposes by the system.
int i;
for(i = 2; i < m_pHookAPISet->m_wNumMethods; i++)
{
if(m_pHookAPISet->m_ppMethods[i] == DummyRoutine)
{
break;
}
}
if(i == m_pHookAPISet->m_wNumMethods)
{
HTRACE(TG_Error,
_T("ERROR: not enough free slots in hook table"));
return NULL;
}
//Replace the DummyRoutine in our API table by the target method.
m_pHookAPISet->m_ppMethods[i] = p_pHookMethod;
//Now create a special "trap" address for this method:
PFNVOID l_pHookTrap = (PFNVOID)GetAPIAddress(m_iHookAPISetID, i);
return l_pHookTrap;
}
/*-------------------------------------------------------------------
FUNCTION: HookMethod
PURPOSE: HookMethod is the main routine of the SpyEngine.
It is used to intercept the specified method in the specified API.
PARAMETERS:
int p_iAPISetId - the API set ID (index) to intercept
int p_iMethodIndex - method index in the given API to intercept
PFNVOID p_pHookMethod - interceptor method in the Spy DLL.
RETURNS:
Pointer to the original method. This pointer must be stored
by the caller and used by the interceptor routine to call the
original method.
NULL is returned on error.
-------------------------------------------------------------------*/
PFNVOID SpyEngine::HookMethod
(
int p_iAPISetId,
int p_iMethodIndex,
PFNVOID p_pHookMethod
)
{
HTRACE(TG_DebugSpyBrief, _T("HookMethod %x %x %x\r\n"),
p_iAPISetId, p_iMethodIndex, p_pHookMethod);
//First call CreateDuplicateApi to create a copy of the original
//API and swap pointers, so the copy will immediately be used.
//Note that CreateDuplicateApi can be called many
//times for the same API - it will only create a copy once, the
//following calls will simply return the copy created earlier.
//This allows calling HookMethod for several method from the
//same API.
if(!CreateDuplicateApi(p_iAPISetId))
return NULL;
HookedAPI & l_rAPI = m_HookedAPI[p_iAPISetId];
//Then prepare an address to the method table of the target API:
PFNVOID * l_pOrigMethods = (PFNVOID *)ConvertAddr(
l_rAPI.m_pOrigApiSet->m_ppMethods,
l_rAPI.m_pOrigApiSet->m_pProcessServer);
HTRACE(TG_DebugSpyBrief,
_T("Replace method #%x(%x) in API %x by hook %x"),
p_iMethodIndex,
((PFNVOID*)l_rAPI.m_pOurApiSet->m_ppMethods)[p_iMethodIndex],
l_rAPI.m_iOrigApiSetId,
p_pHookMethod);
PFNVOID l_pOrig = ((PFNVOID *)l_pOrigMethods)[p_iMethodIndex];
//Finally, put our interceptor to the table of the target API:
((PFNVOID *)l_rAPI.m_pOurApiSet->m_ppMethods)[p_iMethodIndex] =
p_pHookMethod;
//Check whether the method is duplicated in the "extra" table
//and hook it there.
for(int i = 0; i < SIZE_EXTRA_TABLE; i++)
{
if(m_ppHookExtraMethods[i] == l_pOrig)
{
HTRACE(TG_DebugSpyDetailed,
_T("Replace method #%x(%x) in Extra table by %x\r\n"),
i, m_ppHookExtraMethods[i], p_pHookMethod);
m_ppHookExtraMethods[i] = p_pHookMethod;
break;
}
}
return l_pOrig;
}//PFNVOID SpyEngine::HookMethod
/*-------------------------------------------------------------------
FUNCTION: HookGetRomFileInfo
PURPOSE: HookGetRomFileInfo is an interceptor for undocumented
function GetRomFileInfo, which is called by coredll when a new
process started to retrieve pointers to 2 system API method
tables: Win32Methods and ExtraMethods. We must always intercept
GetRomFileInfo to substitute these 2 pointers and also to load
the Spy DLL into the new process.
PARAMETERS:
DWORD p_dwType - type of information. Value 3 is used to
retrieve a pointer to Win32Methods, 4 - ExtraMethods.
Other values are used to enumerate ROM files.
LPWIN32_FIND_DATA p_pFindData - pointer to a structure to fill
DWORD p_dwSize - size of structure pointed by p_pFindData
RETURNS:
TRUE on success, FALSE on failure
-------------------------------------------------------------------*/
PFNVOID g_pOrigGetRomFileInfo = NULL;
BOOL HookGetRomFileInfo
(
DWORD p_dwType,
LPWIN32_FIND_DATA p_pFindData,
DWORD p_dwSize
)
{
InterlockedIncrement(&g_SpyEngine.m_lNumCalls);
InterlockedIncrement(&g_SpyEngine.m_lNumHooksActive);
HANDLE l_hCaller = GetCallerProcess();
HTRACE(TG_DebugSpyDetailed,
_T("HookGetRomFileInfo enter type = %d\r\n"), p_dwType);
BOOL l_bResult = FALSE;
if(g_pOrigGetRomFileInfo)
{
CALLBACKINFO l_CallbackInfo;
l_CallbackInfo.m_hDestinationProcessHandle = l_hCaller;
l_CallbackInfo.m_pFunction = (FARPROC)g_pOrigGetRomFileInfo;
l_CallbackInfo.m_pFirstArgument = (LPVOID)p_dwType;
l_bResult = (BOOL)PerformCallBack4(&l_CallbackInfo,
(DWORD)p_pFindData, p_dwSize, 0);
//Type 3 and 4 are special backdoors used by coredll to
//retrieve pointers to the system method tables.
//We need to replace these system tables by our copy.
//Also we know that coredll calls this routine when a
//new process starts, so it is a good opportunity to load
//the Spy dll into the new process.
if(p_dwType == 3)
{
LPVOID * l_pRetVal = (LPVOID *)MapPtrToProcess
((LPVOID)p_pFindData, l_hCaller);
HTRACE(TG_DebugSpyBrief,
_T("Replace SH_WIN32 methods %x by %x at %x ")
_T("AllKMode %d\r\n"),
*l_pRetVal, g_SpyEngine.m_ppHookWin32Methods,
l_pRetVal, *(BOOL*)p_dwSize);
*l_pRetVal = g_SpyEngine.m_ppHookWin32Methods;
HTRACE(TG_DebugSpyBrief, _T("Replaced\r\n"));
DWORD l_dwIdx = GetProcessIndexFromID(l_hCaller);
HTRACE(TG_InterceptedInfo,
_T("Process %x #%d started\r\n"),
l_hCaller, l_dwIdx);
}
if(p_dwType == 4)
{
LPVOID * l_pRetVal = (LPVOID *)MapPtrToProcess
((LPVOID)p_pFindData, l_hCaller);
HTRACE(TG_DebugSpyBrief,
_T("Replace Extra methods %x by %x at %x\r\n"),
*l_pRetVal,
g_SpyEngine.m_ppHookExtraMethods, l_pRetVal);
*l_pRetVal = g_SpyEngine.m_ppHookExtraMethods;
HTRACE(TG_DebugSpyBrief, _T("Replaced\r\n"));
//Pull ourselves to this new process
DWORD l_dwIdx = GetProcessIndexFromID(l_hCaller);
g_SpyEngine.m_hSpyDllLoaded[l_dwIdx] =
g_SpyEngine.LoadHookDllIntoProcess(l_hCaller);
}
}//if(g_pOrigGetRomFileInfo)
HTRACE(TG_DebugSpyDetailed,
_T("HookGetRomFileInfo(%x,%x,%x) ret %x\r\n"),
p_dwType, p_pFindData, p_dwSize, l_bResult);
InterlockedDecrement(&g_SpyEngine.m_lNumHooksActive);
return l_bResult;
}//BOOL HookGetRomFileInfo
/*-------------------------------------------------------------------
FUNCTION: DoStart
PURPOSE: Spy engine startup routine. Called by StartSpy
under an exception handler.
RETURNS:
TRUE on success, FALSE on failure
-------------------------------------------------------------------*/
BOOL SpyEngine::DoStart()
{
m_dwOrigThreadId = GetCurrentThreadId();
//Load toolhelp library and initialize pointers to it's functions
if(!LoadToolHelp())
{
return FALSE;
}
//Use toolhelp to enumerate running processes and keep the info.
InitProcessList();
//Calculate the beginning of the current process's memory slot.
//Use undocumented function GetProcessIndexFromID.
//There is a confusion: name of the function suggests, that it
//expects process ID, but argument is declared as HANDLE.
//In fact, CE process handles and IDs are identical.
//Also rely on fact that each process's memory slot is 32 MB.
//To get the base address shift 0x2000000 left by the process
//index.
//WARNING: using 3 undocumented features here.
HANDLE hCurrent = GetCurrentProcess();
m_dwCurrentProcBase = 0x2000000 *
(1 + GetProcessIndexFromID(hCurrent));
//Now get access to the kernel data structures.
m_pSystemAPISets = (CINFO**)(UserKInfo[KINX_APISETS]);
DWORD dwMask = UserKInfo[KINX_API_MASK];
HTRACE(TG_DebugSpyBrief,
_T("KernelInfo: UserKInfo = %x SystemAPISets = %x Mask =%x"),
UserKInfo, m_pSystemAPISets, dwMask);
//Need to keep a trap to the original LoadLibrary.
m_pOriginalLoadLibrary = m_pSystemAPISets[SH_WIN32]->
m_ppMethods[W32_LoadLibraryW];
//Allocate memory in the kernel (NK.EXE), which will be
//accessible from all processes. We will use this memory as
//argument to LoadLibrary to load the Spy DLL into all processes.
m_pszSpyDllPathInKernelMemory = (LPTSTR)
AllocateMemInKernelProc(_MAX_PATH * sizeof(TCHAR));
//g_hInst is a instance of the Spy DLL.
//Put the path of Spy DLL to the shared memory:
GetModuleFileName(g_hInst,
m_pszSpyDllPathInKernelMemory, _MAX_PATH);
//Finally, pull the Spy DLL into all running processes.
LoadHookDllInAllProcesses();
//Do the same as coredll itself is doing when each new process
//is loaded: get direct pointers to a table of Win32 methods
//and extra methods.
BOOL bKernelMode;
GetRomFileInfo(3, (LPWIN32_FIND_DATA)&m_ppWin32Methods,
(DWORD)&bKernelMode);
GetRomFileInfo(4, (LPWIN32_FIND_DATA)&m_ppExtraMethods,
NULL);
//Substitute the system API by our own.
//Later custom interceptors may hook other APIs as well,
//but we always need to intercept the SH_WIN32 because:
//1. we must intercept W32_GetRomFileInfo
//2. pointer to SH_WIN32 is cached by coredll and we need to
// replace this cached pointer.
CreateDuplicateApi(SH_WIN32);
//Also create a copy of special "Extra methods" table.
//This table is kept in the kernel and a pointer to is is
//cached by coredll. Coredll uses it as a backdoor to some
//system services. We, obviously, need to substitute this
//pointer as well.
CreateDuplicateMethodTable(SIZE_EXTRA_TABLE,
(PFNVOID *)m_ppExtraMethods, NULL,
&m_ppHookExtraMethods,
&m_pdwHookExtraSignatures);
//Replace pointers to SH_WIN32 table and "Extra Methods" table,
//which are cached by coredll, by our copies.
if(!HookCoredll(m_ppWin32Methods, m_ppHookWin32Methods) ||
!HookCoredll(m_ppExtraMethods, m_ppHookExtraMethods))
{
//Undo the hooking:
HookCoredll(m_ppHookWin32Methods, m_ppWin32Methods);
HookCoredll(m_ppHookExtraMethods, m_ppExtraMethods);
return FALSE;
}
m_bCoredllHooked = TRUE;
//Now create our own private API. We will use it to wrap a
//pointer to some interceptor routines in an API trap.
m_iNumOurApiMethods = NUM_OUR_API_METHODS;
int l_iSize = (sizeof(PFNVOID) + sizeof(DWORD)) *
m_iNumOurApiMethods;
//Allocate a table of pointers to methods and signatures.
m_ppOurApiMethods = (PFNVOID *)malloc(l_iSize);
if(!m_ppOurApiMethods)
{
HTRACE(TG_Error,
_T("ERROR: failed to allocate %d bytes for our API table"),
l_iSize);
return FALSE;
}
m_pdwOurApiSignatures = (DWORD*)
(LPBYTE(m_ppOurApiMethods) +
sizeof(PFNVOID)*m_iNumOurApiMethods);
//Initially fill all entries with a pointer to DummyRoutine,
//which does nothing. Later this pointer will be replaced by
//an actual interceptor routine.
for(int i = 0; i < m_iNumOurApiMethods; i++)
{
m_ppOurApiMethods[i] = DummyRoutine;
m_pdwOurApiSignatures[i] = FNSIG0();
}
//Finally, register our API
m_iHookAPISetID = CreateAndRegisterApi("Hook",
m_iNumOurApiMethods,
m_ppOurApiMethods,
m_pdwOurApiSignatures,
&m_hOurApiHandle);
if(m_iHookAPISetID < 0)
{
free(m_ppOurApiMethods);
m_ppOurApiMethods = NULL;
return FALSE;
}
//Get a pointer to our private API stored in the system table.
m_pHookAPISet = m_pSystemAPISets[m_iHookAPISetID];
//GetRomFileInfo must always be hooked to substitute pointers to
//system method tables retrieved by coredll when a new process
//starts.
PFNVOID l_pTrapToHookGetRomFileInfo =
SetPrivateApiMethod((PFNVOID)HookGetRomFileInfo);
g_pOrigGetRomFileInfo = HookMethod
(SH_WIN32, W32_GetRomFileInfo,
l_pTrapToHookGetRomFileInfo);
//Install custom interceptors.
InstallInterceptors();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -