《逆向工程核心原理》<04-33> 通过DLL注入修改API代码实现API钩取的技术
来源:互联网 发布:淘宝给了好评能删除吗 编辑:程序博客网 时间:2024/05/19 23:11
原理:
原理(通过DLL注入修改API代码实现API钩取的技术):
(技术流程: 代码-DLL注入-CreatRemoteThread.etc)
库文件被加载到内存后, 在其目录映像中直接修改要钩取的API代码本身
Detail:先向目标进程注入用户DLL,将API代码的前5个字节修改为JMP xxxxxxxx指令来钩取API, 调用执行被钩取的API时, 修改后的JMP xxxxxxxx指令就会被执行, 转而控制hooking函数
原理(进程隐藏):
为了隐藏某个特定进程, 要潜入其他所有进程内存, 钩取相关API
实现进程隐藏的关键不是程序自身, 而是其他进程
Detail:ZwQuerySystemInformation()
NTSTATUS ZwQuerySystemInformation( SYSTEM_INFORMATION_CLASS SystemInformationClass; PVOID SysINfomation; ULONG SystemInformationlength; PULONG ReturnLength;);
隐藏进程时需要钩取系统中运行的所有进程的 ZwQuerySystemInformation()API,
并且对后面将要启动运行的所有进程也要做相同的钩取操作, 这便是全局钩取
原理(全局API钩取):
向当前运行的所有进程注入DLL后, 如果在该DLL中将CreateProcess()API也一起钩取, 那么以后运行的进程也会自动注入该DLL文件
Detial:
所有进程都是由父进程(使用CreateProcess())创建的, 所以钩取父进程的CreateProcess()API就可以将DLL文件注入所有子进程(父进程通常都是explorer.exe)
考虑到钩取比kernel32.CreateProcess()更低级的API, 选择钩取ntdll.ZwResumeThread()API
原理(7字节代码修改技术_Hot Patch):
API起码代码的MOV指令(2个字节)与其上方的5个NOP指令(5个字节)合起来共7个字节的指令没有任何意义
原因是为了方便”打热补丁”. “热补丁”由API钩取组成, 在进程处于运行状态时临时更改进程内存中的库文件(重启系统时, 修改的目标库文件会被完全取代)
Detail:A. 二次跳转 API起始代码之前的5个字节修改为FAR JMP指令(E9 xxxxxxxx) API起始代码的2个字节修改为SHORT JMP指令(E8 F9)B. 不需要在钩取函数内部进行"脱钩"/挂钩操作 在"5个字节代码修改技术"中"脱钩"/挂钩是为了"调用原函数" 在"热补丁"技术钩取API时, API代码在遭到修改的状态下也能正常调用原API 这是因为, 从API角度看只是修改了其起始代码的MOV EDI,EDI指令(无意义的两个字节), 从[API起始地址+2]地址开始, 仍然能正常调用原API, 且执行的动作完全一样
代码:
代码(HideProc.cpp):
01- InjectAllProcess()
BOOL InjectAllProcess(int nMode, LPCTSTR szDllPath){ DWORD dwPID = 0; HANDLE hSnapShot = INVALID_HANDLE_VALUE; PROCESSENTRY32 pe; // Get the snapshot of the system 获取系统快照 pe.dwSize = sizeof( PROCESSENTRY32 ); hSnapShot = CreateToolhelp32Snapshot( TH32CS_SNAPALL, NULL ); // CreateToolhelp32Snapshot()获取系统中运行的所有进程列表 // find process 查找进程 Process32First(hSnapShot, &pe); // Process32First() && Process32Next() 将获得的进程信息存放到PROCESSENTRY32结构体变量 do { dwPID = pe.th32ProcessID; // 鉴于系统安全性的考虑 // 对于PID小于100的系统进程 // 不执行DLL注入操作 if( dwPID < 100 ) continue; if( nMode == INJECTION_MODE ) InjectDll(dwPID, szDllPath); else EjectDll(dwPID, szDllPath); } while( Process32Next(hSnapShot, &pe) ); CloseHandle(hSnapShot); return TRUE;}
代码(Stealth.cpp):
01- SetProcName()
// global variable (in sharing memory)#pragma comment(linker, "/SECTION:.SHARE,RWS")#pragma data_seg(".SHARE") TCHAR g_szProcName[MAX_PATH] = {0,};#pragma data_seg()// export function#ifdef __cplusplusextern "C" {#endif__declspec(dllexport) void SetProcName(LPCTSTR szProcName){ _tcscpy_s(g_szProcName, szProcName);}#ifdef __cplusplus}#endif
02- DllMain()
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ char szCurProc[MAX_PATH] = {0,}; char *p = NULL; // #1. 异常处理 // 若当前进程为HideProc.exe, 则终止, 不进行钩取操作 GetModuleFileNameA(NULL, szCurProc, MAX_PATH); p = strrchr(szCurProc, '\\'); if( (p != NULL) && !_stricmp(p+1, "HideProc.exe") ) return TRUE; switch( fdwReason ) { // #2. API Hooking case DLL_PROCESS_ATTACH : hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, (PROC)NewZwQuerySystemInformation, g_pOrgBytes); break; // #3. API Unhooking case DLL_PROCESS_DETACH : unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, g_pOrgBytes); break; } return TRUE;}
03- hook_by_code()
BOOL hook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew, PBYTE pOrgBytes){ // hook_by_code() param: // LPCSTR szDllName: [IN]包含要钩取的API的DLL文件名称 // LPCSTR szFuncName: [IN]要钩取的API名称 // PROC pfnNew: [IN]用户提供的钩取函数地址 // PBYTE pOrgBytes: [OUT]存储原来5个字节的缓冲区, 后面"脱钩"时使用 FARPROC pfnOrg; DWORD dwOldProtect, dwAddress; BYTE pBuf[5] = {0xE9, 0, }; PBYTE pByte; // 获取要钩取的API地址 pfnOrg = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pfnOrg; // 若已经被钩取, 则返回FALSE if( pByte[0] == 0xE9 ) return FALSE; // 为了修改5个字节, 先向内存添加"写"属性 VirtualProtect((LPVOID)pfnOrg, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 备份原有代码(5字节) memcpy(pOrgBytes, pfnOrg, 5); // 计算JMP地址(E9 xxxxxxxx) // => XXXX = pfnNew - pfnOrg - 5 dwAddress = (DWORD)pfnNew - (DWORD)pfnOrg - 5; memcpy(&pBuf[1], &dwAddress, 4); // "钩子": 修改5个字节(JMP xxxxxxxx) memcpy(pfnOrg, pBuf, 5); // 恢复内存属性 VirtualProtect((LPVOID)pfnOrg, 5, dwOldProtect, &dwOldProtect); return TRUE;}
04- unhook_by_code()
BOOL unhook_by_code(LPCSTR szDllName, LPCSTR szFuncName, PBYTE pOrgBytes){ FARPROC pFunc; DWORD dwOldProtect; PBYTE pByte; // 获取API地址 pFunc = GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; // 若已经"脱钩", 贼返回FALSE if( pByte[0] != 0xE9 ) return FALSE; // 向内存添加"写"属性, 为恢复原代码(5个字节)准备 VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); // Unhook memcpy(pFunc, pOrgBytes, 5); // 恢复内存属性 VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect); return TRUE;}
05- NewZwQuerySystemInformation()
typedef NTSTATUS (WINAPI *PFZWQUERYSYSTEMINFORMATION) (SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);// SystemInformationClass 参数设置为SystemProcessInformation(5)后调用ZwQuerySystemInformation()API// SystemInformation [in/out]参数中存储的是SYSTEM_PROCESS_INFORMATION结构体单向链表的起始地址, 该结构体链表中存储着运行中的所有进程信息// 所以, 隐藏某进程前, 先要查找与之对应的链表成员, 然后断开其与链表的链接typedef struct _SYSTEM_PROCESS_INFORMATION { ULONG NextEntryOffset; ULONG NumberOfThreads; BYTE Reserved1[48]; PVOID Reserved2[3]; HANDLE UniqueProcessId; PVOID Reserved3; ULONG HandleCount; BYTE Reserved4[4]; PVOID Reserved5[11]; SIZE_T PeakPagefileUsage; SIZE_T PrivatePageCount; LARGE_INTEGER Reserved6[6];} SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION;
NTSTATUS WINAPI NewZwQuerySystemInformation( SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength){ NTSTATUS status; FARPROC pFunc; PSYSTEM_PROCESS_INFORMATION pCur, pPrev; char szProcName[MAX_PATH] = {0,}; // 开始前先"脱钩" unhook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, g_pOrgBytes); // 调用原始API pFunc = GetProcAddress(GetModuleHandleA(DEF_NTDLL), DEF_ZWQUERYSYSTEMINFORMATION); status = ((PFZWQUERYSYSTEMINFORMATION)pFunc) (SystemInformationClass, SystemInformation, SystemInformationLength, ReturnLength); if( status != STATUS_SUCCESS ) goto __NTQUERYSYSTEMINFORMATION_END; // 仅针对SystemProcessInformation类型操作 if( SystemInformationClass == SystemProcessInformation ) { // SYSTEM_PROCESS_INFORMATION类型转换 // pCur是单向链表的头 pCur = (PSYSTEM_PROCESS_INFORMATION)SystemInformation; while(TRUE) { // 比较进程名称 // g_szProcName为要隐藏的进程名称 // (= 在SetProcName()设置) if(pCur->Reserved2[1] != NULL) { if(!_tcsicmp((PWSTR)pCur->Reserved2[1], g_szProcName)) { // 从链表中删除隐藏进程的节点 if(pCur->NextEntryOffset == 0) pPrev->NextEntryOffset = 0; else pPrev->NextEntryOffset += pCur->NextEntryOffset; } else pPrev = pCur; } if(pCur->NextEntryOffset == 0) break; // 链表的下一项 pCur = (PSYSTEM_PROCESS_INFORMATION) ((ULONG)pCur + pCur->NextEntryOffset); } }__NTQUERYSYSTEMINFORMATION_END: // hook_by_code(DEF_NTDLL, DEF_ZWQUERYSYSTEMINFORMATION, (PROC)NewZwQuerySystemInformation, g_pOrgBytes); return status;}
代码(stealth2.cpp):
01- Dllmain()
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved){ char szCurProc[MAX_PATH] = {0,}; char *p = NULL; // 异常处理使注入不会发生在HideProc2.exe进程 GetModuleFileNameA(NULL, szCurProc, MAX_PATH); p = strrchr(szCurProc, '\\'); if( (p != NULL) && !_stricmp(p+1, "HideProc2.exe") ) return TRUE; // 改变 privilege SetPrivilege(SE_DEBUG_NAME, TRUE); switch( fdwReason ) { case DLL_PROCESS_ATTACH : // hook hook_by_code("kernel32.dll", "CreateProcessA", (PROC)NewCreateProcessA, g_pOrgCPA); hook_by_code("kernel32.dll", "CreateProcessW", (PROC)NewCreateProcessW, g_pOrgCPW); hook_by_code("ntdll.dll", "ZwQuerySystemInformation", (PROC)NewZwQuerySystemInformation, g_pOrgZwQSI); break; case DLL_PROCESS_DETACH : // unhook unhook_by_code("kernel32.dll", "CreateProcessA", g_pOrgCPA); unhook_by_code("kernel32.dll", "CreateProcessW", g_pOrgCPW); unhook_by_code("ntdll.dll", "ZwQuerySystemInformation", g_pOrgZwQSI); break; } return TRUE;}
02- NewCreateProcessA()
BOOL WINAPI NewCreateProcessA( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation){ BOOL bRet; FARPROC pFunc; // unhook unhook_by_code("kernel32.dll", "CreateProcessA", g_pOrgCPA); // 调用初始API pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessA"); bRet = ((PFCREATEPROCESSA)pFunc)(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); // 向生成的子进程注入stealth2.dll if( bRet ) InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME); // hook hook_by_code("kernel32.dll", "CreateProcessA", (PROC)NewCreateProcessA, g_pOrgCPA); return bRet;}
代码(stealth3.cpp)
01- hook_by_hotpatch()
BOOL hook_by_hotpatch(LPCSTR szDllName, LPCSTR szFuncName, PROC pfnNew){ FARPROC pFunc; DWORD dwOldProtect, dwAddress; BYTE pBuf[5] = { 0xE9, 0, }; BYTE pBuf2[2] = { 0xEB, 0xF9 }; PBYTE pByte; pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; if( pByte[0] == 0xEB ) return FALSE; VirtualProtect((LPVOID)((DWORD)pFunc - 5), 7, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 1. NOP (0x90) dwAddress = (DWORD)pfnNew - (DWORD)pFunc; memcpy(&pBuf[1], &dwAddress, 4); memcpy((LPVOID)((DWORD)pFunc - 5), pBuf, 5); // 2. MOV EDI, EDI (0x8BFF) memcpy(pFunc, pBuf2, 2); VirtualProtect((LPVOID)((DWORD)pFunc - 5), 7, dwOldProtect, &dwOldProtect); return TRUE;}
02- unhook_by_hotpatch()
BOOL unhook_by_hotpatch(LPCSTR szDllName, LPCSTR szFuncName){ FARPROC pFunc; DWORD dwOldProtect; PBYTE pByte; BYTE pBuf[5] = { 0x90, 0x90, 0x90, 0x90, 0x90 }; BYTE pBuf2[2] = { 0x8B, 0xFF }; pFunc = (FARPROC)GetProcAddress(GetModuleHandleA(szDllName), szFuncName); pByte = (PBYTE)pFunc; if( pByte[0] != 0xEB ) return FALSE; VirtualProtect((LPVOID)pFunc, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect); // 1. NOP (0x90) memcpy((LPVOID)((DWORD)pFunc - 5), pBuf, 5); // 2. MOV EDI, EDI (0x8BFF) memcpy(pFunc, pBuf2, 2); VirtualProtect((LPVOID)pFunc, 5, dwOldProtect, &dwOldProtect); return TRUE;}
03- NewCreateProcessA()
BOOL WINAPI NewCreateProcessA( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation){ BOOL bRet; FARPROC pFunc; // 调用原始API pFunc = GetProcAddress(GetModuleHandleA("kernel32.dll"), "CreateProcessA"); pFunc = (FARPROC)((DWORD)pFunc + 2); bRet = ((PFCREATEPROCESSA)pFunc)(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation); // 向生成的子进程注入stealth3.dll if( bRet ) InjectDll2(lpProcessInformation->hProcess, STR_MODULE_NAME); return bRet;}
0 0
- 《逆向工程核心原理》<04-33> 通过DLL注入修改API代码实现API钩取的技术
- 《逆向工程核心原理》<04-30> 通过Debug修改代码实现API钩取的技术
- 《逆向工程核心原理》<04-32> 通过DLL注入实现IAT钩取的技术
- 《逆向工程核心原理》<04-34> 高级全局API钩取
- 逆向工程核心原理读书笔记-API钩取之记事本小写转大写
- 逆向工程核心原理读书笔记-API钩取之计算器显示中文数字
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(一)
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(二)
- 逆向工程核心原理读书笔记-API钩取之IE浏览器连接控制
- 逆向工程核心原理读书笔记-API钩取之记事本小写转大写
- 逆向工程核心原理读书笔记-API钩取之计算器显示中文数字
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(一)
- 逆向工程核心原理读书笔记-API钩取之隐藏进程(二)
- 逆向工程核心原理读书笔记-API钩取之IE浏览器连接控制
- 逆向工程核心原理读书笔记-代码注入
- 逆向工程核心原理读书笔记-代码注入
- 《逆向工程核心原理》<03-25> 通过修改PE加载DLL
- 《逆向工程核心原理》<03> DLL注入的3种姿势
- fseek与ftell做c文件的移动
- C# 入门(8) using语句,using命名空间指令,using别名指令,嵌套命名空间
- Angular2开发拙见
- 412. Fizz Buzz
- java编写针对Redis数据库操作的DBHelper类
- 《逆向工程核心原理》<04-33> 通过DLL注入修改API代码实现API钩取的技术
- 明天,你想要什么?
- String to Integer (atoi)
- N皇后问题的两个最高效算法
- JAVA中的正则 与 JS中的正则
- 【剑指offer】二维数组中的查找
- Angular2响应式表单
- explicit用法
- HDOJ 1517 A Multiplication Game