Win 7 中 Process explorer 中 IE 浏览器所加载的 DLL 文件:
如何查看库文件的导出函数:
下载 VS 后直接在搜索栏输入 VS (第一个和第三个都可以),打开命令窗口,输入 命令 " dumpbin /exports 库文件绝对路径 " 就可以看到函数. 若后面再加上" > C:Users123456Desktop1.txt " ,
就可以将导出函数保存到文件中.
wininet.dll 中有一个导出函数 InternetConnect() ,可能与网络连接有关.
在Win 7 64位操作系统上,对 InternetConnectW() 下断点.
修改字符串后,禁止断点后继续运行,成功跳转到修改后的网站.
目前的浏览器将每个选项卡都对应为一个进程,因此要钩取整个 IE 需要采用全局钩取.
但是,同样需要注意的是,此处注入 DLL 成功后, 已加载的进程不受影响,未来加载的程序才会受影响.
运行配套的进程,确实如书上所说,运行完 ZwCreateUserProcess() ,程序就被挂起( Suspended ) , EP 代码未运行:
而 NtResumeThread() 从名字可知就是恢复线程运行的.
在用户模式下, Zw 和 Nt 系列的函数调用并无不同.在内核模式下,有不同:
Nt 系列 API 将直接调用对应的函数代码,而 Zw 系列 API 则通过 KiSystemService,最终跳转到对应的函数代码.
ZW开头的函数是通过eax中系统服务号去SSDT中查找相应的系统服务,然后调用之,若在驱动中直接调用NT开头的函数是不会经过SSDT的 也不会被SSDT HOOK拦截的
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { char szCurProc[MAX_PATH] = {0,}; char *p = NULL; switch( fdwReason ) { case DLL_PROCESS_ATTACH : DebugLog("DllMain() : DLL_PROCESS_ATTACH "); GetModuleFileNameA(NULL, szCurProc, MAX_PATH); p = strrchr(szCurProc, '\'); if( (p != NULL) && !_stricmp(p+1, "iexplore.exe") ) { DebugLog("DllMain() : current process is [iexplore.exe] "); // 钩取 wininet!InternetConnectW() API 之前 // 预先加载 wininet.dll if( NULL == LoadLibrary(L"wininet.dll") ) { DebugLog("DllMain() : LoadLibrary() failed!!! [%d] ", GetLastError()); } } // hook hook_by_code("ntdll.dll", "ZwResumeThread", (PROC)NewZwResumeThread, g_pZWRT); // NewZwResumeThread、NewInternetConnectW 是本 DLL 中的函数 hook_by_code("wininet.dll", "InternetConnectW", // 因此会直接表示为地址传入函数 (PROC)NewInternetConnectW, g_pICW); break; case DLL_PROCESS_DETACH : DebugLog("DllMain() : DLL_PROCESS_DETACH "); // unhook unhook_by_code("ntdll.dll", "ZwResumeThread", g_pZWRT); unhook_by_code("wininet.dll", "InternetConnectW", g_pICW); break; } return TRUE; }
BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes) { FARPROC pFunc = NULL; DWORD dwOldProtect = 0, dwAddress = 0; BYTE pBuf[5] = {0xE9, 0, }; PBYTE pByte = NULL; HMODULE hMod = NULL; hMod = GetModuleHandleA(szDllName); if( hMod == NULL ) { DebugLog("hook_by_code() : GetModuleHandle("%s") failed!!! [%d] ", szDllName, GetLastError()); return FALSE; } pFunc = (FARPROC)GetProcAddress(hMod, szFuncName); if( pFunc == NULL ) { DebugLog("hook_by_code() : GetProcAddress("%s") failed!!! [%d] ", szFuncName, GetLastError()); return FALSE; } pByte = (PBYTE)pFunc; if( pByte[0] == 0xE9 ) { DebugLog("hook_by_code() : The API is hooked already!!! "); return FALSE; } if( !VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect) ) { DebugLog("hook_by_code() : VirtualProtect(#1) failed!!! [%d] ", GetLastError()); return FALSE; } memcpy(pOrgBytes, pFunc, 5); //修改5字节的属性 dwAddress = (DWORD)pfnNew - (DWORD)pFunc - 5; // 计算相对地址 memcpy(&pBuf[1], &dwAddress, 4); // 保存原地址 memcpy(pFunc, pBuf, 5); // 覆写函数首地址 if( !VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect) ) { DebugLog("hook_by_code() : VirtualProtect(#2) failed!!! [%d] ", GetLastError()); return FALSE; } return TRUE; }
#define STR_MODULE_NAME (L"redirect.dll")
#define STATUS_SUCCESS (0x00000000L)
NTSTATUS WINAPI NewZwResumeThread(HANDLE ThreadHandle, PULONG SuspendCount) // 对 ZwResumeThread API 进行全局钩取 { // 每次创建新进程,都会调用CreateProcess 里面的 ZwResumeThread 函数来唤醒进程 NTSTATUS status, statusThread; // 钩取此函数,可以在每次唤醒线程前,将 DLL 注入子进程中. FARPROC pFunc = NULL, pFuncThread = NULL; DWORD dwPID = 0; static DWORD dwPrevPID = 0; THREAD_BASIC_INFORMATION tbi; HMODULE hMod = NULL; TCHAR szModPath[MAX_PATH] = {0,}; DebugLog("NewZwResumeThread() : start!!! "); hMod = GetModuleHandle(L"ntdll.dll"); if( hMod == NULL ) { DebugLog("NewZwResumeThread() : GetModuleHandle() failed!!! [%d] ", GetLastError()); return NULL; } // call ntdll!ZwQueryInformationThread() pFuncThread = GetProcAddress(hMod, "ZwQueryInformationThread"); if( pFuncThread == NULL ) { DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d] ", GetLastError()); return NULL; } statusThread = ((PFZWQUERYINFORMATIONTHREAD)pFuncThread) // 调用 ZwQueryInformationThread API, 获取当前线程的 PID 值 (ThreadHandle, 0, &tbi, sizeof(tbi), NULL); if( statusThread != STATUS_SUCCESS ) { DebugLog("NewZwResumeThread() : pFuncThread() failed!!! [%d] ", GetLastError()); return NULL; } dwPID = (DWORD)tbi.ClientId.UniqueProcess; // 获取到 PID 值 if ( (dwPID != GetCurrentProcessId()) && (dwPID != dwPrevPID) ) // 第一次调用时 PID 值不能为 0,后面再次调用时不能注入上次注入过的进程. { DebugLog("NewZwResumeThread() => call InjectDll() "); dwPrevPID = dwPID; // change privilege if( !SetPrivilege(SE_DEBUG_NAME, TRUE) ) DebugLog("NewZwResumeThread() : SetPrivilege() failed!!! "); // get injection dll path GetModuleFileName(GetModuleHandle(STR_MODULE_NAME), // 获取要注入的 DLL 的路径 szModPath, MAX_PATH); if( !InjectDll(dwPID, szModPath) ) DebugLog("NewZwResumeThread() : InjectDll(%d) failed!!! ", dwPID); //注入进程 } // call ntdll!ZwResumeThread() if( !unhook_by_code("ntdll.dll", "ZwResumeThread", g_pZWRT) ) //脱钩 { DebugLog("NewZwResumeThread() : unhook_by_code() failed!!! "); return NULL; } pFunc = GetProcAddress(hMod, "ZwResumeThread"); //获取原 API 地址 if( pFunc == NULL ) { DebugLog("NewZwResumeThread() : GetProcAddress() failed!!! [%d] ", GetLastError()); goto __NTRESUMETHREAD_END; } status = ((PFZWRESUMETHREAD)pFunc)(ThreadHandle, SuspendCount); // 调用原 API ,运行挂起的线程 if( status != STATUS_SUCCESS ) { DebugLog("NewZwResumeThread() : pFunc() failed!!! [%d] ", GetLastError()); goto __NTRESUMETHREAD_END; } __NTRESUMETHREAD_END: if( !hook_by_code("ntdll.dll", "ZwResumeThread", // 执行完函数之后,继续钩取函数 (PROC)NewZwResumeThread, g_pZWRT) ) { DebugLog("NewZwResumeThread() : hook_by_code() failed!!! "); } DebugLog("NewZwResumeThread() : end!!! "); return status; }
HINTERNET WINAPI NewInternetConnectW ( HINTERNET hInternet, LPCWSTR lpszServerName, INTERNET_PORT nServerPort, LPCTSTR lpszUsername, LPCTSTR lpszPassword, DWORD dwService, DWORD dwFlags, DWORD_PTR dwContext ) { HINTERNET hInt = NULL; FARPROC pFunc = NULL; HMODULE hMod = NULL; // 先 unhook if( !unhook_by_code("wininet.dll", "InternetConnectW", g_pICW) ) // 脱钩 { DebugLog("NewInternetConnectW() : unhook_by_code() failed!!! "); return NULL; } // call original API hMod = GetModuleHandle(L"wininet.dll"); if( hMod == NULL ) { DebugLog("NewInternetConnectW() : GetModuleHandle() failed!!! [%d] ", GetLastError()); goto __INTERNETCONNECT_EXIT; } pFunc = GetProcAddress(hMod, "InternetConnectW"); // 获取原 API 地址 if( pFunc == NULL ) { DebugLog("NewInternetConnectW() : GetProcAddress() failed!!! [%d] ", GetLastError()); goto __INTERNETCONNECT_EXIT; } if( !_tcsicmp(lpszServerName, L"www.naver.com") || // 对指定网址进行替换 !_tcsicmp(lpszServerName, L"www.daum.net") || !_tcsicmp(lpszServerName, L"www.nate.com") || !_tcsicmp(lpszServerName, L"www.yahoo.com") ) { DebugLog("[redirect] naver, daum, nate, yahoo => reversecore "); hInt = ((PFINTERNETCONNECTW)pFunc)(hInternet, L"www.reversecore.com", nServerPort, lpszUsername, lpszPassword, dwService, dwFlags, dwContext); } else { DebugLog("[no redirect] "); hInt = ((PFINTERNETCONNECTW)pFunc)(hInternet, lpszServerName, nServerPort, lpszUsername, lpszPassword, dwService, dwFlags, dwContext); } __INTERNETCONNECT_EXIT: //函数执行完之后重新钩取原 API. // hook if( !hook_by_code("wininet.dll", "InternetConnectW", (PROC)NewInternetConnectW, g_pICW) ) { DebugLog("NewInternetConnectW() : hook_by_code() failed!!! "); } return hInt; }
CreateProcess 里面封装了 CreateProcessInternal , 实际测试中,钩取 CreateProcess ,并在其中调用 CreateProcessInternal 是没有问题的.
在 XP 系统中能正常 hide 进程,只是在 show 时完成程序后会退出.
另外,在 VS 中编译以前的代码时,需要在 工程 - 属性 - C/C++ - 常规中,把 SDL 检查关闭,
并且,如果运行的系统中没有相应的 DLL ,可以在 VS 中选择 代码生成 -> 运行库,将模式改为多线程调试.即设置为静态库.VS默认是动态库.