Hook功能已经实现,现在有个问题,当我修改玩系统的loadlibraryexw的地址的为我要改的地址的时候,一打开ie就崩了,补充,我hook的原理就是修改loadlibraryexw的地址 然后替换,如果不需要的时候再改回来
调用IE的时候DebugView会打出
[3284] ERROR: Not all DirectUser Contexts were destroyed before EndProcess().
的错误
请问怎么解决情况啊
调用IE的时候DebugView会打出
[3284] ERROR: Not all DirectUser Contexts were destroyed before EndProcess().
的错误
请问怎么解决情况啊
BOOL ret=FALSE;
if (Status) {
ret = WriteProcessMemory(hProcess, (void *)FunAddr, NewCode, 5, 0);
if (ret) return TRUE;}
else {
ret = WriteProcessMemory(hProcess, (void *)FunAddr, OldCode, 5, 0);
if (ret) return TRUE;}
return FALSE;
}BOOL loadHookStatus(BOOL Status){
BOOL ret=FALSE;
if (Status) {
ret = WriteProcessMemory(loadhProcess, (void *)loadFunAddr, loadNewCode, 5, 0);
if (ret) return TRUE;}
else {
ret = WriteProcessMemory(loadhProcess, (void *)loadFunAddr, loadOldCode, 5, 0);
if (ret) return TRUE;}
return FALSE;
}//Char转WChar
WCHAR* ToWChar(char * str)
{
//在GDI+中,有关字符的参数类型全部都是WCHAR类型的
//该函数是将传统字符串进行转换 static WCHAR buffer[1024];
wcsset(buffer,0);
MultiByteToWideChar(CP_ACP,0,str,strlen(str),buffer,1024);
return buffer;
}//CreateProcess的替代函数
BOOL WINAPI CreateProcessWCallBack(LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation){
return CreateProcessW(lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,
dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation);
}VOID OutputDebugStringExW(const wchar_t* szFormat, ...)
{
WCHAR Buffer[2048] = {0}; va_list argList;
va_start(argList, szFormat);
vswprintf(Buffer, sizeof(Buffer), szFormat, argList);
va_end(argList); OutputDebugStringW(Buffer);
} HMODULE WINAPI LoadLibraryExWCallBack(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags){
OutputDebugStringW(ToWChar ("1"));
loadHookStatus(FALSE);
loadBool = FALSE;
OutputDebugStringW(ToWChar ("2"));
OutputDebugStringW(lpLibFileName);
return LoadLibraryExW(lpLibFileName,hFile,dwFlags);
}//修改原始CreateProcess为我们的替换函数
BOOL HookCreateProcess(){
ULONG JmpAddr=0;
char msg[255]={0}; FunAddr = (ULONG)GetProcAddress(LoadLibrary("Kernel32.dll"), "CreateProcessW");//得到CreateProcessW函数的地址
memcpy(OldCode, (void *)FunAddr, 5);//保存函数地址的5字节
//修改CreateProcess地址
NewCode[0] = 0xe9;
JmpAddr = (ULONG)CreateProcessWCallBack - FunAddr - 5;
memcpy(&NewCode[1], &JmpAddr, 4);
//更改CreateProcess地址
HookStatus(TRUE);
return TRUE;
}BOOL HookLoadLibraryExW(){
ULONG JmpAddr=0;
char msg[255]={0}; loadFunAddr = (ULONG)GetProcAddress(LoadLibrary("Kernel32.dll"), "LoadLibraryExW");//得到CreateProcessW函数的地址
memcpy(loadOldCode, (void *)loadFunAddr, 5);//保存函数地址的5字节
loadNewCode[0] = 0xe9;
JmpAddr = (ULONG)LoadLibraryExWCallBack- loadFunAddr - 5;
memcpy(&loadNewCode[1], &JmpAddr, 4);
loadHookStatus(TRUE);
return TRUE;
}BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
hMod = (HINSTANCE)hModule;
if (ul_reason_for_call==DLL_PROCESS_ATTACH){//dll被映射时
//CreateProcess
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
hExe = FindWindow(NULL, "Hook CreateProcessW");
HookCreateProcess();
CreateBool = FALSE;
loadhMod = (HINSTANCE)hModule;
//LoadLibraryExW
loadhProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, GetCurrentProcessId());
loadhExe = FindWindow(NULL, "Hook LoadLibraryExW");
HookLoadLibraryExW();
loadBool = FALSE;
}
if (ul_reason_for_call==DLL_PROCESS_DETACH) //dll被解除映射时
{
HookStatus(FALSE);
loadHookStatus(FALSE);
}
return TRUE;
}
loadFunAddr = (ULONG)GetProcAddress(LoadLibrary("Kernel32.dll"), "LoadLibraryExW");//得到CreateProcessW函数的地址
VirtualProtect(loadFunAddr,5, PAGE_EXECUTE_READWRITE, &dwOldProtect); //试下更改页面保护属性
memcpy(loadOldCode, (void *)loadFunAddr, 5);//保存函数地址的5字节
每次调用原函数都要重新恢复前面5个字节,
很烦琐不说,多线程下也不安全.
而且有些函数头前面5个字节并不一定是完全的汇编指令,
恰好 LoadLibraryExW是这样,
你不管三七二十一,直接就把前面5个字节改成JMP跳转指令,
连后面的指令也破坏了.
原始的LoadLibraryExW函数是这样的.kernel32!LoadLibraryExW:
7c801af5 6a34 push 34h
7c801af7 68f8e0807c push offset kernel32!DuplicateHandle+0x25a (7c80e0f8)
7c801afc e8d5090000 call kernel32!ReleaseMutex+0x1f (7c8024d6)
7c801b01 33ff xor edi,edi
7c801b03 897dd8 mov dword ptr [ebp-28h],edi
7c801b06 897dd4 mov dword ptr [ebp-2Ch],edi
7c801b09 897de0 mov dword ptr [ebp-20h],edi
7c801b0c 897de4 mov dword ptr [ebp-1Ch],edi强行更改前面5字节后,就变这样的,
原本第3条是CALL指令,现在变成add了.
第3条指令也一起被破坏了.kernel32!LoadLibraryExW:
7c801af5 e9e6f6c083 jmp 004111e0
7c801afa 807ce8d509 cmp byte ptr [eax+ebp*8-2Bh],9
7c801aff 0000 add byte ptr [eax],al
7c801b01 33ff xor edi,edi
7c801b03 897dd8 mov dword ptr [ebp-28h],edi
7c801b06 897dd4 mov dword ptr [ebp-2Ch],edi
7c801b09 897de0 mov dword ptr [ebp-20h],edi
7c801b0c 897de4 mov dword ptr [ebp-1Ch],edi比较好的方法是这样LPVOID pfnLoadLibraryExW = 0;
typedef HMODULE (WINAPI *LOADLIBRARYEX)(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags);HMODULE WINAPI LoadLibraryExWCallBack(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags)
{
if (_tcscmp(lpLibFileName, TEXT("123.dll")) == 0)
{
return 0;
} return ((LOADLIBRARYEX)pfnLoadLibraryExW)(lpLibFileName,hFile,dwFlags);
}
BOOL HookLoadLibraryExW()
{
/*HOOK前面7个字节,不是5个字节,
因为前面push 34h只有2个字节,不能容纳一条JMP指令,
*/
CONST int CODELEN = 7;
BYTE OldCode[CODELEN];
DWORD dwOldProtect; pfnLoadLibraryExW = GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")), "LoadLibraryExW");
//更改页面保护属性
VirtualProtect(pfnLoadLibraryExW, CODELEN, PAGE_EXECUTE_READWRITE, &dwOldProtect);
//保存函数地址的7字节
memcpy(OldCode, pfnLoadLibraryExW, CODELEN);
//先用NOP指令填充
memset(pfnLoadLibraryExW, 0x90, CODELEN);
//开始写入跳转指令
*(LPBYTE)pfnLoadLibraryExW = 0xe9;
*(LPINT)((int)pfnLoadLibraryExW+1) = (int)LoadLibraryExWCallBack - (int)pfnLoadLibraryExW - 5;
//刷新进程缓冲,恢复原始页面保护属性
FlushInstructionCache((HANDLE)-1, pfnLoadLibraryExW, CODELEN);
VirtualProtect(pfnLoadLibraryExW, CODELEN, dwOldProtect, NULL);
//申请一段大小为之前破坏掉的代码大小+JMP指令大小的内存
pfnLoadLibraryExW = VirtualAlloc(NULL, CODELEN+5, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
//再把之前备份的指令复制到刚刚申请的内存中
memcpy(pfnLoadLibraryExW, OldCode, sizeof(OldCode));
//然后再构建一段跳转指令跳回到LoadLibraryExW函数.
*(LPBYTE)((int)pfnLoadLibraryExW+CODELEN) = 0xe9;
*(LPINT)((int)pfnLoadLibraryExW+CODELEN+1) = (int)LoadLibraryExW - (int)pfnLoadLibraryExW - 7;//((int)LoadLibraryExW+CODELEN) - ((int)pfnLoadLibraryExW+CODELEN) - 5; return TRUE;
}再反汇编看下,第6-7个字节被2个NOP指令代替了.
没有破坏第三条CALL指令.
调用原函数也不用重新恢复前面5个字节.kernel32!LoadLibraryExW:
7c801af5 e9e6f6c083 jmp 004111e0
7c801afa 90 nop
7c801afb 90 nop
7c801afc e8d5090000 call kernel32!ReleaseMutex+0x1f (7c8024d6)
7c801b01 33ff xor edi,edi
7c801b03 897dd8 mov dword ptr [ebp-28h],edi
7c801b06 897dd4 mov dword ptr [ebp-2Ch],edi
7c801b09 897de0 mov dword ptr [ebp-20h],edi