一个月前开始使用Server 2008 R2作为工作站系统,发现QQIntl经常出现卡死,根本无法使用,从1.5到2.1版本问题均存在。似乎在Win8.1上也有同样的问题。
卡死是线程死锁导致的,锁死发生在NTDLL中加载DLL文件的系统加载锁上,且锁死发生后占有锁的线程已经结束(而不是等待另一个锁这种互相等待的死锁),给排查带来了很大的难度。锁死发生后OD、VS不能挂入调试,否则OD等也会卡死。OD亦不能在启动QQ时就挂入,因为QQ本身有防调试机制。只能用WinDbg挂入。也就是说,根本无从下手,只能HackFix。
经过N天的实验,来回更换了五六个方案,最终采用了以下方案的HackFix,至今运行基本稳定。
#include <windows.h> #include <winnt.h> #include <process.h> HANDLE hHookHeap = NULL; PVOID InstallHook(PVOID CodeAddr, LONG CodeLen, PVOID HookProc) //ret: StubProc { if (hHookHeap == NULL) hHookHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0); DWORD oldProtect; VirtualProtect(CodeAddr, CodeLen, PAGE_EXECUTE_READWRITE, &oldProtect); PVOID StubProc = HeapAlloc(hHookHeap, 0, CodeLen + 5); memcpy(StubProc, (PVOID)CodeAddr, CodeLen); *((PBYTE)StubProc + CodeLen) = '\xE9'; *(PDWORD)((PBYTE)StubProc + CodeLen + 1) = (DWORD)CodeAddr + CodeLen - ((DWORD)StubProc + CodeLen + 5); *((PBYTE)CodeAddr) = '\xE9'; *(PDWORD)((PBYTE)CodeAddr + 1) = (DWORD)HookProc - ((DWORD)CodeAddr + 5); VirtualProtect(CodeAddr, CodeLen, oldProtect, &oldProtect); return StubProc; } DWORD lpLoaderLock = 0x1020c0; void* lpStub; void __stdcall hook_RtlEnterCriticalSection(CRITICAL_SECTION* lpCriticalSection) { if ((DWORD)lpCriticalSection == lpLoaderLock) { int count; for (count = 0; count < 10; ++count) { DWORD dwLockThread = (DWORD)lpCriticalSection->OwningThread; if (dwLockThread == 0 || dwLockThread == GetCurrentThreadId()) { break; } Sleep(10); } if (count == 10) { InitializeCriticalSectionEx(lpCriticalSection, 0, 0x2000000); } } ((void(__stdcall*)(CRITICAL_SECTION*))lpStub)(lpCriticalSection); } void do_hook() { DWORD hNTDLL = (DWORD)GetModuleHandleA("ntdll"); lpLoaderLock += hNTDLL; lpStub = InstallHook((void*)(hNTDLL + 0x222b0), 5, &hook_RtlEnterCriticalSection); } BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: if (GetModuleHandleA("QQ.exe") == NULL) return FALSE; do_hook(); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
代码中的两个地址常数一个是加载锁的RVA,一个是RtlEnterCriticalSection的地址。
注入采用的是修改了QQ目录下的一个DLL使之LoadLibrary这个DLL(我选的是zlib,大部分TX签名的DLL在QQ登陆时会有hash校验而不能修改)。
求解答 :
HackFix 是一款调试器?
《大部分TX签名的DLL》,如果修改这些做劫持 QQ 会崩溃还是会给检测出来???
hackfix指解决不了bug之根本的fix。qq登陆时会hash大多数dll,不通过则不允许登录。
默默点赞
排队点赞