一个月前开始使用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,不通过则不允许登录。
默默点赞
排队点赞