Делаю для антивирусной системы модуль эвристического анализа. Для этого из сервиса, работающего под системой, запускается специальный процесс и инжектируется в открывающиеся процессы с целью перенаправить определенные апишные функции на свой обработчик. Принцип инжекта простой - запускаемый процесс инжекта сам себя копирует в инжектируемый процесс, корректируя там релоки и вставляя код в памяти инжектируемого процесса для перенаправления на свои обработчики. Тестировал в системах Win7,8, Windows2008 server x86-x64. Вот код в котором происходит проблема:
BOOL Gl::HookProcess(DWORD idProcess, PVOID entryPoint, PWCHAR dllName, DWORD_PTR dllBaseAddress, Gl::PgFunclist funcList, WORD listCount)
{
HMODULE hlib = NULL;
HANDLE hpr = NULL;
DWORD_PTR adr, BaseAddress = NULL, RemoteAddress = NULL, OldProc = NULL;
PDWORD_PTR pRemoteAddress = NULL, pBaseAddress = NULL;
BOOL result = FALSE;
DWORD deltaf, oldprotect, nb;
PVOID buf = NULL, p;
#ifdef DBG
PWCHAR tmp;
tmp = (PWCHAR)VirtualAlloc(NULL, 1000 * sizeof(WCHAR), MEM_COMMIT, PAGE_READWRITE);
#endif
hlib = LoadLibrary(dllName);
if(!hlib)
return FALSE;
while(1)
{
pBaseAddress = (PDWORD_PTR)VirtualAlloc(NULL, sizeof(DWORD_PTR), MEM_COMMIT, PAGE_READWRITE);
if(!pBaseAddress)
break;
pRemoteAddress = (PDWORD_PTR)VirtualAlloc(NULL, sizeof(DWORD_PTR), MEM_COMMIT, PAGE_READWRITE);
if(!pRemoteAddress)
break;
if(!Gl::HookCode(idProcess, entryPoint, &hpr, &BaseAddress, &RemoteAddress))
break;
*pRemoteAddress = RemoteAddress;
*pBaseAddress = BaseAddress;
#ifdef DBG
wsprintf(tmp, L"GHookCode %x %x\n", BaseAddress, RemoteAddress);
OutputDebugString(tmp);
#endif
buf = VirtualAlloc(NULL, 100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
for(int i = 0; i < listCount; i++)
{
deltaf = Gl::GetDeltaFunction(hlib, funcList[i].funcName);
if(!Gl::SaveOldFunction(hpr, dllBaseAddress, deltaf, &OldProc))
continue;
adr = RemoteAddress + ((DWORD_PTR)(funcList[i].oldFunc) - BaseAddress);
WriteProcessMemory(hpr, (PVOID)adr, &OldProc, sizeof(DWORD_PTR), (SIZE_T*)&nb);
RemoteAddress = *pRemoteAddress;
BaseAddress = *pBaseAddress;
#ifdef DBG
wsprintf(tmp, L"GHookCode %x %x\n", BaseAddress, RemoteAddress);
OutputDebugString(tmp);
#endif
adr = RemoteAddress + ((DWORD_PTR)(funcList[i].newFunc) - BaseAddress);
p = buf;
*((BYTE*)p) = 0xE9;
p = (PVOID)((DWORD_PTR)p + 1);
*((DWORD*)p) = (DWORD)((LONG_PTR)adr - (LONG_PTR)(dllBaseAddress + deltaf + 5));
#ifdef DBG
wsprintf(tmp, L"delta %x\n", (DWORD)((LONG_PTR)adr - (LONG_PTR)(dllBaseAddress + deltaf + 5)));
OutputDebugString(tmp);
#endif
adr = dllBaseAddress + deltaf;
VirtualProtectEx(hpr, (PVOID)adr, 10, PAGE_READWRITE, &oldprotect);
WriteProcessMemory(hpr, (PVOID)adr, buf, 5, (SIZE_T*)&nb);
VirtualProtectEx(hpr, (PVOID)adr, 10, oldprotect, &oldprotect);
RemoteAddress = *pRemoteAddress;
BaseAddress = *pBaseAddress;
}
result = TRUE;
break;
}
CWA(kernel32, FreeLibrary)(hlib);
if(pBaseAddress)
VirtualFree(pBaseAddress, 0, MEM_RELEASE);
if(pRemoteAddress)
VirtualFree(pRemoteAddress, 0, MEM_RELEASE);
if(buf)
VirtualFree(buf, 0, MEM_RELEASE);
if(hpr)
CloseHandle(hpr);
#ifdef DBG
if(tmp)
VirtualFree(tmp, 0, MEM_RELEASE);
#endif
return result;
}
В 32-битных системах все нормально работает, в 64-битных выявилась следующая бяка:
После вызова WriteProcessMemory в x64 почему то переменные RemoteAddress и BaseAddress сбрасываются в 0. Поэтому пришлось ввести дополнительные переменные pRemoteAddress и pBaseAddress, в которых сохранять значения RemoteAddress и BaseAddress до вызова WriteProcessMemory и восстанавливать эти значения после вызова WriteProcessMemory. Причем пришлось создавать переменные из памяти процесса, а не из стека, иначе вообще код падает. Правда в процессе отключен RTL и проверка переполнения стека. Но все равно непонятно почему именно после вызова WriteProcessMemory происходит подобное.