📄 spyengine.cpp
字号:
return l_pRemoteMem;
}//void * AllocateMemInKernelProc
/*-------------------------------------------------------------------
FUNCTION: LoadHookDllIntoProcess
PURPOSE: In order to spy for APIs served by other processes, the
Spy interceptor routines must be accessible from these processes.
This can be achieved by loading the Spy DLL into these processes.
The way to do that is by using undocumented PerformCallBack4
routine to execute LoadLibrary in other processes. We cannot
simply call LoadLibrary exported from coredll, because it can be
intercepted by us, but the interceptor will crash because the
SpyEngine is not loaded yet into the process. Therefore, use
m_pOriginalLoadLibrary, which keeps a trap to the original
W32_LoadLibraryW handler.
PARAMETERS:
HANDLE p_hProcess - handle to the process where the DLL should
be loaded.
RETURNS:
Instance handle of the loaded DLL in the target process.
-------------------------------------------------------------------*/
HINSTANCE SpyEngine::LoadHookDllIntoProcess(HANDLE p_hProcess)
{
CALLBACKINFO CallbackInfo;
CallbackInfo.m_hDestinationProcessHandle = p_hProcess;
CallbackInfo.m_pFunction = (FARPROC)m_pOriginalLoadLibrary;
CallbackInfo.m_pFirstArgument =
(LPVOID)m_pszSpyDllPathInKernelMemory;
HTRACE(TG_DebugSpyBrief,
_T("Load our DLL in proc %x using fun %x\r\n"),
p_hProcess, m_pOriginalLoadLibrary);
DWORD l_dwResult = PerformCallBack4(&CallbackInfo, 0, 0, 0);
HTRACE(TG_DebugSpyBrief, _T("Loaded %x\r\n"), l_dwResult);
return (HINSTANCE)l_dwResult;
}
/*-------------------------------------------------------------------
FUNCTION: UnloadHookDllInProcess
PURPOSE: UnloadHookDllInProcess is used to unload SpyDll
from a process, where it was loaded by LoadHookDllIntoProcess.
PARAMETERS:
HANDLE p_hProcess - handle to process where the DLL was loaded
HINSTANCE p_hInst - instance handle of the loaded DLL
RETURNS:
TRUE on success, FALSE on failure
-------------------------------------------------------------------*/
BOOL SpyEngine::UnloadHookDllInProcess
(
HANDLE p_hProcess,
HINSTANCE p_hInst
)
{
DWORD l_dwResult = 0;
if(!CallCoredllInProc(p_hProcess, _T("FreeLibrary"),
(DWORD)p_hInst, 0,0,0, &l_dwResult))
return FALSE;
HTRACE(TG_DebugSpyBrief,
_T("FreeLibrary(%x) in process %x ret %x\r\n"),
p_hInst, p_hProcess, l_dwResult);
return l_dwResult;
}
/*-------------------------------------------------------------------
FUNCTION: LoadHookDllInAllProcesses
PURPOSE: Load our Spy DLL in all running processes so that these
processes will be able to access our interceptor routines.
-------------------------------------------------------------------*/
void SpyEngine::LoadHookDllInAllProcesses()
{
HTRACE(TG_DebugSpyBrief, _T("LoadHookDllInAllProcesses()\r\n"));
//Don't load Spy DLL into NK.EXE (process #0) because NK.EXE
//already has access to all addresses and because it is difficult
//to unload from there.
for(int l_iProcID = 1; l_iProcID < countof(m_Processes);
l_iProcID++)
{
PROCESSENTRY32 * l_pProcEntry = m_Processes + l_iProcID;
if(!l_pProcEntry->dwSize)
continue;//This slot is not used
if(l_pProcEntry->th32ProcessID == GetCurrentProcessId())
continue;//This is Spy itself.
HANDLE l_hProc = OpenProcess(0, FALSE,
l_pProcEntry->th32ProcessID);
if(l_hProc == NULL)
{
HTRACE(TG_Error,
_T("ERROR: Failed to open process %x %s\r\n"),
l_pProcEntry->th32ProcessID,l_pProcEntry->szExeFile);
}
else
{
HTRACE(TG_DebugSpyBrief,
_T("Load our DLL in process %x %s\r\n"),
l_pProcEntry->th32ProcessID,l_pProcEntry->szExeFile);
m_hSpyDllLoaded[l_iProcID] =
LoadHookDllIntoProcess(l_hProc);
CloseHandle(l_hProc);
}
}//for(int l_iProcID = 0; l_iProcID < countof(m_Processes);
HTRACE(TG_DebugSpyBrief,
_T("LoadHookDllInAllProcesses() ends\r\n"));
}//void SpyEngine::LoadHookDllInAllProcesses
/*-------------------------------------------------------------------
FUNCTION: CloseAPISet
PURPOSE: CloseAPISet closes the API handle returned by
CreateAPISet. For some reason CloseAPISet routine is not
exported from coredll. So, call it using API trap.
PARAMETERS:
HANDLE p_hSet - API handle returned by CreateAPISet
-------------------------------------------------------------------*/
void CloseAPISet(HANDLE p_hSet)
{
__try
{
((void (*)(HANDLE)) IMPLICIT_CALL(HT_APISET, 0)) (p_hSet);
}
__except(1)
{
HTRACE(TG_Error, _T("ERROR: exception in CloseAPISet"));
}
}
/*-------------------------------------------------------------------
FUNCTION: CreateDuplicateMethodTable
PURPOSE: CreateDuplicateMethodTable used to allocate memory in
the kernel process space and copy the given method and signature
table to this memory.
PARAMETERS:
int p_iNumMethods - number of methods
PFNVOID * p_pMethods - method table
DWORD * p_pdwSignatures - signature table (May be NULL)
PFNVOID ** p_ppReturnHookMthds- return the allocated method table
DWORD ** p_ppdwReturnHookSignatures - return the signatures
RETURNS:
TRUE on success, FALSE on failure
-------------------------------------------------------------------*/
BOOL CreateDuplicateMethodTable
(
int p_iNumMethods,
PFNVOID * p_pMethods,
DWORD * p_pdwSignatures,//May be NULL
PFNVOID ** p_ppReturnHookMthds,
DWORD ** p_ppdwReturnHookSignatures
)
{
int l_iSize = (sizeof(PFNVOID)*p_iNumMethods +
sizeof(DWORD)*p_iNumMethods);
LPBYTE l_pRemoteMem = (LPBYTE)AllocateMemInKernelProc(l_iSize);
HTRACE(TG_DebugSpyBrief,
_T("Create method table at %x\r\n"), l_pRemoteMem);
PFNVOID * l_pHookMthds = (PFNVOID *)l_pRemoteMem;
DWORD * l_pdwHookSignatures =
(DWORD*)(l_pRemoteMem + sizeof(PFNVOID)*p_iNumMethods);
int i;
for(i = 0; i < p_iNumMethods; i++)
{
HTRACE(TG_DebugSpyDetailed,
_T("Copy meth #%x %x from %x to %x\r\n"), i,
p_pMethods[i], &p_pMethods[i], &l_pHookMthds[i]);
l_pHookMthds[i] = p_pMethods[i];
//Our replaced API will be served by our process and we
//always should provide a signature table. But the original
//signature table pointer will be NULL if the original API
//is served by the kernel (therefore no pointer mapping is
//required). In that case fill our table by FNSIG0, which
//means that no mapping is required.
l_pdwHookSignatures[i] = p_pdwSignatures?
p_pdwSignatures[i] : FNSIG0();
}
*p_ppReturnHookMthds = l_pHookMthds;
*p_ppdwReturnHookSignatures = l_pdwHookSignatures;
return TRUE;
}//CreateDuplicateMethodTable
/*-------------------------------------------------------------------
FUNCTION: CreateAndRegisterApi
PURPOSE: CreateAndRegisterApi calls undocumented methods
CreateAPISet, RegisterAPISet and QueryAPISetID to create,
register a new API and return it's ID
PARAMETERS:
char * p_pszName - API name
int p_iNumMethods - number of methods
PFNVOID * p_ppMethods - method table
DWORD * p_pdwSignatures - method signatures
HANDLE * p_phReturnApiHandle - return API handle
RETURNS:
Positive API ID (index in the system API table)
-1 on error
-------------------------------------------------------------------*/
int CreateAndRegisterApi
(
char * p_pszName,
int p_iNumMethods,
PFNVOID * p_ppMethods,
DWORD * p_pdwSignatures,
HANDLE * p_phReturnApiHandle
)
{
HANDLE l_hApiHandle = CreateAPISet(p_pszName,
p_iNumMethods, p_ppMethods, p_pdwSignatures);
if(!l_hApiHandle)
{
HTRACE(TG_Error,
_T("ERROR: CreateAPISet(%c%c%c%c, %x, %x, %x) failed.")
_T("Err %d"),
p_pszName[0], p_pszName[1], p_pszName[2], p_pszName[3],
p_iNumMethods, p_ppMethods, p_pdwSignatures,
GetLastError());
return -1;
}
if(!RegisterAPISet(l_hApiHandle, 0))
{
HTRACE(TG_Error,
_T("ERROR: RegisterAPISet(%x) for API %c%c%c%c failed.")
_T("Err %d"),
l_hApiHandle,
p_pszName[0], p_pszName[1], p_pszName[2], p_pszName[3],
GetLastError());
CloseAPISet(l_hApiHandle);
return -1;
}
int l_iAPISetID = QueryAPISetID(p_pszName);
if(l_iAPISetID < 0)
{
HTRACE(TG_Error,
_T("ERROR: QueryAPISetID(%c%c%c%c) failed. Err %d"),
p_pszName[0], p_pszName[1], p_pszName[2], p_pszName[3],
GetLastError());
CloseAPISet(l_hApiHandle);//it also unregisters the API
return -1;
}
HTRACE(TG_DebugSpyBrief,
_T("CreateAndRegisterApi(%c%c%c%c) NumM %x Mthds %x ")
_T("Sign %x ret ID %d"),
p_pszName[0], p_pszName[1], p_pszName[2], p_pszName[3],
p_iNumMethods, p_ppMethods, p_pdwSignatures, l_iAPISetID);
*p_phReturnApiHandle = l_hApiHandle;
return l_iAPISetID;
}//int CreateAndRegisterApi
/*-------------------------------------------------------------------
FUNCTION: CreateDuplicateApi
PURPOSE: CreateDuplicateApi is used to create a copy of the
system API (CINFO structure, method and signature tables).
Then replace a pointer to the original CINFO by the new one.
We keep a table m_HookedAPI of such replacement APIs,
so CreateDuplicateApi will not allocate a new API for the same
original more than once.
PARAMETERS:
int p_iAPISetId - original API set ID to replace
RETURNS:
TRUE on success, FALSE on failure
-------------------------------------------------------------------*/
BOOL SpyEngine::CreateDuplicateApi(int p_iAPISetId)
{
if(p_iAPISetId < 0 || p_iAPISetId >= countof(m_HookedAPI))
{
HTRACE(TG_Error,
_T("ERROR: CreateDuplicateApi argument %d is out of range"),
p_iAPISetId);
return FALSE;
}
HookedAPI * l_pHookedAPI = m_HookedAPI + p_iAPISetId;
if(l_pHookedAPI->m_bUsed)
return TRUE;
HANDLE l_hCurProc = GetCurrentProcess();
CINFO * l_pOrigApiSet = m_pSystemAPISets[p_iAPISetId];
PFNVOID * l_pHookMthds = NULL;
DWORD * l_pdwHookSignatures = NULL;
PFNVOID * l_pOrigMethods = (PFNVOID *)ConvertAddr
(l_pOrigApiSet->m_ppMethods,l_pOrigApiSet->m_pProcessServer);
DWORD * l_pOrigSignatures = (DWORD *)ConvertAddr
(l_pOrigApiSet->m_pdwMethodSignatures,
l_pOrigApiSet->m_pProcessServer);
CreateDuplicateMethodTable(l_pOrigApiSet->m_wNumMethods,
l_pOrigMethods, l_pOrigSignatures,
&l_pHookMthds, &l_pdwHookSignatures);
if(p_iAPISetId == SH_WIN32)
{
m_ppHookWin32Methods = l_pHookMthds;
m_pdwHookWin32Signatures = l_pdwHookSignatures;
}
CINFO * l_pOurApiSet = (CINFO *)
AllocateMemInKernelProc(sizeof(CINFO));
//Use the same name, dispatch type, API ID and server
//as the original API:
memcpy(l_pOurApiSet, l_pOrigApiSet, sizeof(CINFO));
//But replace the method and signature tables:
l_pOurApiSet->m_ppMethods = l_pHookMthds;
l_pOurApiSet->m_pdwMethodSignatures = l_pdwHookSignatures;
HTRACE(TG_DebugSpyBrief,
_T("Created duplicate CINFO at %x for API %x ")
_T("dup mthds %x %x\r\n"),
l_pOurApiSet, p_iAPISetId,
l_pHookMthds, l_pdwHookSignatures);
//Now fill our HookedAPI structure so we can undo the
//API replacement later.
l_pHookedAPI->m_bUsed = TRUE;
l_pHookedAPI->m_bSwapped = FALSE;
l_pHookedAPI->m_iOrigApiSetId = p_iAPISetId;
l_pHookedAPI->m_pOrigApiSet = l_pOrigApiSet;
l_pHookedAPI->m_pOurApiSet = l_pOurApiSet;
//And finally, replace the pointer to the original CINFO
//by the pointer to ours.
HTRACE(TG_DebugSpyBrief,
_T("Before replace original API %x (CINFO %x by %x) ")
_T("at %x\r\n"),
p_iAPISetId,
m_pSystemAPISets[p_iAPISetId], l_pOurApiSet,
&m_pSystemAPISets[p_iAPISetId]);
m_pSystemAPISets[p_iAPISetId] = l_pOurApiSet;
l_pHookedAPI->m_bSwapped = TRUE;
HTRACE(TG_DebugSpyBrief,
_T("After replace original API %x\r\n"), p_iAPISetId);
return TRUE;
}//BOOL SpyEngine::CreateDuplicateApi
void DummyRoutine()
{
//HTRACE(TG_DebugSpyBrief, _T("DummyRoutine"));
}
/*-------------------------------------------------------------------
FUNCTION: SetPrivateApiMethod
PURPOSE: SetPrivateApiMethod finds an unused slot in our private
API method table and stores the given method to it.
PARAMETERS:
PFNVOID p_pHookMethod - pointer to the new method
RETURNS:
Trap to invoke the given method in our private API
or NULL on failure
-------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -