|
![]() | 作者: yongmin [yongmin]
![]() |
登录 |
作者:Lvg 转贴自:一蓑烟雨 【文章标题】: 必备绝技--Hook大法(上) 【文章作者】: LvG 【作者邮箱】: LvG2008@gmail.com 【作者声明】: 这没有什么新鲜东西,其内容全部来自于前辈,姑且当作学习笔记。文字用自己的话写出,四段代码均出自别人(知道作者的,以注明),但短小精悍,就写在一起了,便于察看。欢迎指正。 -------------------------------------------------------------------------------- 【详细过程】 hook概念:是一种通过更改程序的数据结构或代码结构从而改变程序运行路线的一种方法。(纯属本人自己观点) 分类:从上面的概念来看,一种是改变程序的数据结构,如:IAT-hook,Dll-inject及Direct Kernel Object Manipulation(DKOM)。一种是Inline Function Hooking。 用途:现在这种方法普遍运用于各类程序中,如加壳,杀软,病毒,Rootkits等等。 本文从难以程度上主要分三块详细介绍:一.用户模式Hook:IAT-hook,Dll-inject二.内核模式Hook:ssdt-hook,idt-hook,int 2e/sysenter-hook三.Inline Function Hook; 这次先来看第一部分 Ⅰ.用户模式Hook 一.IAT-hooking (一)一般原理:IAT是Import Address Table(输入地址表)的简写,这需要你知道关于win PE格式的了解。现在应用程序中的大多数函数都是windows api,而这些函数一般都由几个系统dll导出,如user32.dll,kernel32.dll,advapi32.dll等。如果程序要运用这些函数,就的从这些dll文件中导入,程序会把导入的函数放到一个叫IAT的数据结构中。我们可以先找到自己需要hook的函数,然后把目标函数的地址改成我们自己的hook函数,最后在恢复到目标函数的地址。这样一来,目标函数被调用时,我们的hook函数也就别调用了。如果这个hook函数是病毒,是后门,是。。。。。。。。由于是在目标函数进程的空间内,所以这个hook函数也就不会被发现。 关于WIN PE格式的详细知识可参见:http://bbs.pediy.com/showthread.php?t=31840及<<加密与解密>>。 (二)大体框架:这里用伪码给个一般框架,以便有个大体印象。 文件1:myhookfun() { 可以创建一个新的线程,去执行木马或后门等功能 } 文件2: include <文件1> 寻找目标模块(GetModuleHandle) if(目标模块找到) 根据pe结构,在目标模块中定位目标函数的IAT地址(这个地址在加载时就确定了) if (目标函数在IAT中的地址找到) 用我们的myhookfun()地址取代 esle 退出 esle 退出 当然也可以合成一个文件,但这样分开的好处是可以实现模块化,可以分别关心各自的功能,也便于以后重用。 (三)代码实例:这仅仅是个示例,用自己dll中的一个函数去替换另一个函数 .486 .model flat, stdcall option casemap:none include windows.inc include kernel32.inc includelib kernel32.lib include user32.inc includelib user32.lib .data szMsgTitle db "IAT Hook", 0 szModule db "user32.dll", 0 szTargetFunc db "GetForegroundWindow", 0 szHooked db "This is in the hooked function - Seems to have worked.", 0 szFail db "Failed.", 0 .data? IATHook PROTO STDCALL WORD, WORD, WORD HookProc PROTO STDCALL PVOID .code HookProc proc Arg1PVOID invoke MessageBox, NULL, addr szHooked, addr szMsgTitle, MB_OK ret HookProc endp IATHook proc pDLLNamePVOID, pOldAddr:LPVOID, pNewAddr:LPVOID LOCAL hModule:HANDLE LOCAL dwVirtualAddr:DWORD LOCAL dwOrigProtect:DWORD LOCAL dwDllFound:DWORD LOCAL dwFunctionFound:DWORD ;Local variables .if pDLLName == NULL ;Check for NULL pointer xor eax, eax ret .endif .if pOldAddr == NULL ;Check for NULL pointer xor eax, eax ret .endif .if pOldAddr == NULL ;Check for NULL pointer xor eax, eax ret .endif mov dwDllFound, 0 mov dwFunctionFound, 0 ;Initialize invoke GetModuleHandle, NULL ;Get the main module's base address mov hModule, eax ;Copy it into hModule mov edi, hModule assume edi:ptr IMAGE_DOS_HEADER ;Make edi act as IMAGE_DOS_HEADER struct .if edi == NULL ;Check for NULL pointer xor eax, eax ret ;Return 0 .endif .if [edi].e_magic != IMAGE_DOS_SIGNATURE ;0x4D 0x5A (MZ) xor eax, eax ret ;Return 0 .endif add edi, [edi].e_lfanew ;pNtHeader = (IMAGE_NT_HEADERS*)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew); assume edi:ptr IMAGE_NT_HEADERS ;Make edi act as IMAGE_NT_HEADERS struct .if edi == NULL ;Check for NULL pointer xor eax, eax ret ;Return 0 .endif .if [edi].Signature != IMAGE_NT_SIGNATURE ;If it's an invalid NT header ;0x50 0x45 0x00 0x00 (PE\0\0) xor eax, eax ret ;Return 0 .endif mov edx, [edi].OptionalHeader.DataDirectory[sizeof IMAGE_DATA_DIRECTORY].VirtualAddress mov dwVirtualAddr, edx ;Copy the VirtualAddress into dwVirtualAddr .if dwVirtualAddr == 0 ;Invalid virtual address xor eax, eax ret ;Return 0 .endif mov edi, hModule add edi, dwVirtualAddr ;pImportHeader = (IMAGE_IMPORT_DESCRIPTOR*)((DWORD)pDosHeader + dwVirtualAddr); assume edi:ptr IMAGE_IMPORT_DESCRIPTOR ;Make edi act as IMAGE_IMPORT_DESCRIPTOR struct .if edi == NULL ;Check for NULL pointer xor eax, eax ret ;Return 0 .endif .while [edi].Name1 != NULL mov ecx, hModule add ecx, [edi].Name1 ;pModuleLabel = (char*)((DWORD)pDosHeader + (DWORD)pImportHeader->Name); mov edx, pDLLName invoke lstrcmpi, ecx, edx ;Check if this is the DLL we are looking for .if eax == 0 ;This is the DLL we are looking for mov dwDllFound, 1 ;Set ecx to 0, so we know later if the DLL was found .break .endif add edi, sizeof IMAGE_IMPORT_DESCRIPTOR ;Next DLL .endw .if dwDllFound != 1 ;If the DLL wasn't found xor eax, eax ret ;Return 0 .endif mov edi, [edi].FirstThunk add edi, hModule ;pThunkData = (IMAGE_THUNK_DATA*)((DWORD)pDosHeader + (DWORD)pImportHeader->FirstThunk); assume edi:ptr IMAGE_THUNK_DATA ;Make edi act as IMAGE_THUNK_DATA struct .while [edi].u1.Function != NULL mov ecx, hModule add ecx, [edi].u1.Function mov edx, [edi].u1.Function ;Copies the current functions address (in the IAT table) into edx .if pOldAddr == edx ;If this is the function we are going to hook lea ebx, [edi].u1.Function ;Copy the address in the table that the function is stored in, into ebx invoke VirtualProtect, ebx, 4, PAGE_WRITECOPY, addr dwOrigProtect ;Unprotect the memory where we are going to overwrite (We need 4 bytes --- DWORD = 4 bytes) mov eax, pNewAddr ;Copy the address we are going to replace it with into eax mov [ebx], eax ;Patch the address invoke VirtualProtect, ebx, 4, addr dwOrigProtect, NULL ;Restore the original protection level mov dwFunctionFound, 1 ;Set the value, for later .break .endif add edi, sizeof IMAGE_THUNK_DATA ;Next thunk .endw .if dwFunctionFound != 1 ;If the function wasn't found xor eax, eax ret ;Return 0 .endif mov eax, 1 ret ;Return 1 ;Success IATHook endp start: invoke GetModuleHandle, addr szModule invoke GetProcAddress, eax, addr szTargetFunc mov ebx, HookProc invoke IATHook, addr szModule, eax, ebx ;Redirect GetForegroundWindow (eax) to HookProc (ebx) .if eax == 0 invoke MessageBox, NULL, addr szFail, addr szMsgTitle, MB_OK invoke ExitProcess, 0 .endif ;Is now hooked, hopefully.. so lets call it invoke GetForegroundWindow invoke ExitProcess, 0 end start (四)局限性:1当程序运用一种叫late-demand binding技术,函数被调用时才定位地址,这样以来就不能在IAT中定位目标函数地址了.2当目标程序用动态加载(LoadLibrary)时,这种方法也将失效. 二.Dll-Injecting (一)通过注册表注入Dll 1.一般原理:Windows的注册表中有这样一个键值, HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_Dlls。在这个键下的值都会被系统的任何一个GUI程序所加载,其实就是只要程序调用了User32.dll,则User32.dll的DllMain函数在初始化时,会把这个键下的Dll自动加载,除非是命令行程序。记得求职信病毒用的就是这一招。 2.大体框架:这个方法要操作注册表,简要介绍一下几个主要的操作注册表的函数 RegCreateKeyEx: 创建一个子键 RegOpenKeyEx: 打开子键 RegQuetyValueEx:获取一个项的值 RegSetValueEx: 设置指定项的值 文件1: myHookDll { 特定目的的Dll } 文件2: myHookDll.dll拷贝到系统目录 RegCreateKeyEx 创建AppInit_Dlls键 RegQuetyValueEx 获取这个项 找到myHookDll.dll路径 RegSetValueEx 把myHookDll.Dll设置成AppInit_Dlls 3.代码实例: #include <windows.h> #include <commctrl.h> #include <tchar.h> #pragma comment(linker, "/opt:nowin98" #pragma comment(linker, "/merge:.text=.data" #pragma comment(linker, "/merge:.rdata=.data" #define REGLOC _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows") HHOOK g_hHook; TCHAR g_szPath[MAX_PATH]; TCHAR g_szCurrent[0x1000]; HMODULE g_hInstance; HKEY GetRegLoc() { HKEY hKey = 0; RegCreateKeyEx(HKEY_LOCAL_MACHINE, REGLOC, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0); return hKey; } #pragma comment(linker, "/export:DllRegisterServer=_DllRegisterServer@0,PRIVATE") #pragma comment(linker, "/export:DllUnregisterServer=_DllUnregisterServer@0,PRIVATE") char *stristr(const char *String, const char *Pattern) { char *pptr, *sptr, *start; for (start = (char *)String; *start != 0; start++) { // find start of pattern in string for( ; ((*start!=0) && (toupper(*start) != toupper(*Pattern))); start++) ; if(0 == *start) return NULL; pptr = (char *)Pattern; sptr = (char *)start; while(toupper(*sptr) == toupper(*pptr)) { sptr++; pptr++; // if end of pattern then pattern was found if(0 == *pptr) return start; } } return NULL; } // // DllRegisterServer. // STDAPI DllRegisterServer() { HKEY hKey; DWORD type; DWORD len; DWORD ret = E_UNEXPECTED; if((hKey = GetRegLoc()) == 0) return E_UNEXPECTED; // Get current AppInit_Dlls string if(ERROR_SUCCESS == RegQueryValueEx(hKey, _T("AppInit_Dlls"), 0, &type, g_szCurrent, &len)) { // Make sure aren't already registered char *ptr = stristr(g_szCurrent, g_szPath); g_szCurrent[len] = 0; if(g_szCurrent[0] != 0) lstrcat(g_szCurrent, _T(",")); ret = S_OK; // append our DLL path to the AppInit_Dlls path if(ptr == 0) { lstrcat(g_szCurrent, g_szPath); len = lstrlen(g_szCurrent); RegSetValueEx(hKey, _T("AppInit_Dlls"), 0, REG_SZ, g_szCurrent, len); } } RegCloseKey(hKey); return ret; } STDAPI DllUnregisterServer() { HKEY hKey; DWORD type; DWORD len; DWORD ret = E_UNEXPECTED; if((hKey = GetRegLoc()) == 0) return E_UNEXPECTED; // Get current AppInit_Dlls string if(ERROR_SUCCESS == RegQueryValueEx(hKey, _T("AppInit_Dlls"), 0, &type, g_szCurrent, &len)) { // Find where our DLL path is stored char *ptr = stristr(g_szCurrent, g_szPath); ret = S_OK; if(ptr != 0) { len = lstrlen(g_szPath); if(ptr > 0 && ptr[-1] == ',') { ptr--; len++; } memmove(ptr, ptr + len, lstrlen(g_szCurrent) - len + 1); RegSetValueEx(hKey, _T("AppInit_Dlls"), 0, REG_SZ, g_szCurrent, len); } } RegCloseKey(hKey); return S_OK; } // // Computer-based training hook. Used to trap window creation // of a common dialog (Open/Save), so that the ListView contained // in these dialogs can be changed to report-view before it is displayed. // static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) { if(nCode == HCBT_CREATEWND) { HWND hwnd = (HWND)wParam; HWND hwndParent; CBT_CREATEWND *cw = (CBT_CREATEWND *)lParam; TCHAR szClass[32]; GetClassName(hwnd, szClass, 32); // Is this a ListView being created? if(lstrcmpi(szClass, _T("SysListView32")) == 0) { HMODULE hModule = GetModuleHandle(_T("comdlg32.dll")); hwndParent = cw->lpcs->hwndParent; if(hModule != (HMODULE)GetWindowLong(hwndParent, GWL_HINSTANCE)) hwndParent = GetParent(hwndParent); // Make sure the parent window (the dialog) was created by // the common-dialog library if(hModule == (HMODULE)GetWindowLong(hwndParent, GWL_HINSTANCE)) { PostMessage(cw->lpcs->hwndParent, WM_COMMAND, MAKEWPARAM(28716, 0), 0); } /*else { GetClassName(cw->lpcs->hwndParent, szClass, 32); if(lstrcmpi(szClass, _T("SHELLDLL_DefView")) == 0) { PostMessage(cw->lpcs->hwndParent, WM_COMMAND, MAKEWPARAM(28716, 0), 0); } }*/ } } return CallNextHookEx(g_hHook, nCode, wParam, lParam); } void InstallHook(DWORD dwThreadId) { g_hHook = SetWindowsHookEx(WH_CBT, CBTProc, 0, dwThreadId); } void RemoveHook(DWORD dwThreadId) { UnhookWindowsHookEx(g_hHook); g_hHook = 0; } BOOL WINAPI DllMain(HMODULE hInstance, DWORD dwReason, PVOID lpReserved) { switch(dwReason) { case DLL_PROCESS_ATTACH: g_hInstance = hInstance; GetModuleFileName(hInstance, g_szPath, MAX_PATH); DisableThreadLibraryCalls(hInstance); InstallHook(GetCurrentThreadId()); return TRUE; case DLL_PROCESS_DETACH: RemoveHook(GetCurrentThreadId()); break; } return TRUE; } #ifdef _DEBUG int main() { return 0; } #endif BOOL WINAPI _DllMainCRTStartup(HMODULE hInstance, DWORD dwReason, PVOID lpReserved) { return DllMain(hInstance, dwReason, lpReserved); } 4.局限性:由于这种方法太显而易见,所以很容易被发现。 (二)通过消息钩子 1.基本原理:微软自己定义了一个钩子函数,这个钩子可以钩住系统的任何一类消息,并产生相关的回调函数。比如我们设置的是键盘钩子,如果用户按下键盘的键,就可以触发一个我们自定义功能的回调函数。 2.大体框架: 文件1:产生特定功能的Dll,并设置钩子 SetWindowsHookEx(WH_KEYBOARD, myKeyBrdFuncAd, myDllHandle, 0), 文件2:将Dll设置到特定目录,隐藏等 安装钩子函数,只要另一个进程按下了键,则钩子启动,加载Dll 卸载钩子 3.代码实例: 文件1: ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Sample code for < Win32ASM Programming 2nd Edition> ; by 罗云彬, http://asm.yeah.net ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Hookdll.asm ; 键盘钩子使用的 dll 程序 ; 用来方置钩子过程 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 使用 nmake 或下列命令进行编译和链接: ; ml /c /coff Hookdll.asm ; Link /subsystem:windows /section:.bss,S /Def:Hookdll.def /Dll Hookdll.obj ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .386 .model flat, stdcall option casemap :none ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Include 文件定义 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .data hInstance dd ? .data? hWnd dd ? hHook dd ? dwMessage dd ? szAscii db 4 dup (?) ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .code ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; dll 的入口函数 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DllEntry proc _hInstance,_dwReason,_dwReserved push _hInstance pop hInstance mov eax,TRUE ret DllEntry Endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 键盘钩子回调函数 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> HookProc proc _dwCode,_wParam,_lParam local @szKeyState[256]:byte invoke CallNextHookEx,hHook,_dwCode,_wParam,_lParam invoke GetKeyboardState,addr @szKeyState invoke GetKeyState,VK_SHIFT mov @szKeyState + VK_SHIFT,al mov ecx,_lParam shr ecx,16 invoke ToAscii,_wParam,ecx,addr @szKeyState,addr szAscii,0 mov byte ptr szAscii [eax],0 invoke SendMessage,hWnd,dwMessage,dword ptr szAscii,NULL xor eax,eax ret HookProc endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 安装钩子 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> InstallHook proc _hWnd,_dwMessage push _hWnd pop hWnd push _dwMessage pop dwMessage invoke SetWindowsHookEx,WH_KEYBOARD,addr HookProc,hInstance,NULL mov hHook,eax ret InstallHook endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 卸载钩子 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> UninstallHook proc invoke UnhookWindowsHookEx,hHook ret UninstallHook endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> End DllEntry 文件2: ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Sample code for < Win32ASM Programming 2nd Edition> ; by 罗云彬, http://asm.yeah.net ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Hookdll.asm ; 键盘钩子使用的 dll 程序 ; 用来方置钩子过程 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 使用 nmake 或下列命令进行编译和链接: ; ml /c /coff Hookdll.asm ; Link /subsystem:windows /section:.bss,S /Def:Hookdll.def /Dll Hookdll.obj ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .386 .model flat, stdcall option casemap :none ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Include 文件定义 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .data hInstance dd ? .data? hWnd dd ? hHook dd ? dwMessage dd ? szAscii db 4 dup (?) ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .code ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; dll 的入口函数 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> DllEntry proc _hInstance,_dwReason,_dwReserved push _hInstance pop hInstance mov eax,TRUE ret DllEntry Endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 键盘钩子回调函数 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> HookProc proc _dwCode,_wParam,_lParam local @szKeyState[256]:byte invoke CallNextHookEx,hHook,_dwCode,_wParam,_lParam invoke GetKeyboardState,addr @szKeyState invoke GetKeyState,VK_SHIFT mov @szKeyState + VK_SHIFT,al mov ecx,_lParam shr ecx,16 invoke ToAscii,_wParam,ecx,addr @szKeyState,addr szAscii,0 mov byte ptr szAscii [eax],0 invoke SendMessage,hWnd,dwMessage,dword ptr szAscii,NULL xor eax,eax ret HookProc endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 安装钩子 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> InstallHook proc _hWnd,_dwMessage push _hWnd pop hWnd push _dwMessage pop dwMessage invoke SetWindowsHookEx,WH_KEYBOARD,addr HookProc,hInstance,NULL mov hHook,eax ret InstallHook endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 卸载钩子 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> UninstallHook proc invoke UnhookWindowsHookEx,hHook ret UninstallHook endp ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> End DllEntry 4.局限性:会产生Dll体,虽然没有进程,但可以通过其他工具轻易发现 (三)通过创建远程线程 1.一般思路:远程线程,顾名思义就是在其他进程中创建一个线程,如果这个进程是系统每次启动必须加载的,那么就能每次有注入目标。这主要通过CreateRemoteThread函数完成。 2.大体框架: 文件1:可以重定位的代码,或是DLL,这个代码当然是有特定目的的 文件2:查找特定进程,如文件管理器,打开进程 VirtualAllocEx函数在进程中申请分配空间 WriteProcessMemory函数将远程线程中的代码拷贝到申请到的空间 CreateRemoteThread函数创建远程线程 3.代码实例: 文件1:一段可重定位代码 REMOTE_CODE_START equ this byte _lpLoadLibary dd ? ;输入函数地址表 _lpGetProcAddress dd ? _lpGetModuleHandle dd ? _lpMessageBox dd ? ;全局变量表 _hInstance dd ? _szDllUser db 'User32.dll',0 _szMessageBox db 'MessageBox',0 _szCaption db 'A rootkit !',0 _szText db 'Hello,im LvG,but you cant find me!',0 .code _RemoteThread proc uses ebx edi esi lParam local @hModule local @hInstance call @F @@: pop ebx sub ebx, offset @B _invoke [ebx, _lpGetModuleHandle],NULL mov [ebx, _hInstance], eax lea eax, [ebx + offset _szDllUser] _invoke [ebx + _lpGetModuleHandle], eax mov @hModule, eax lea esi, [ebx + offset _szMessageBox] _invoke [ebx + _lpGetProcAddress], @hModule, esi mov [ebx + offset _lpMessageBox], eax lea eax, [ebx + offset _szCaption] lea ecx, [ebx + offset _szText] _invoke [ebx + _lpMessageBox], NULL, ecx, eax,MB_OK ret _RemoteThread endp REMOTE_CODE_END equ this byte REMOTE_CODE_LENGTH equ offset REMOTE_CODE_END - offset REMOTE_CODE_START 文件2: .386 .model flat, stdcall option casemap :none ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; Include 文件定义 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib include Macro.inc ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ; 数据段 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .data? lpLoadLibrary dd ? lpGetProcAddress dd ? lpGetModuleHandle dd ? dwProcessID dd ? dwThreadID dd ? hProcess dd ? lpRemoteCode dd ? .const szErrOpen db '无法打开远程线程!',0 szDesktopClass db 'Progman',0 szDesktopWindow db 'Program Manager',0 szDllKernel db 'Kernel32.dll',0 szLoadLibrary db 'LoadLibraryA',0 szGetProcAddress db 'GetProcAddress',0 szGetModuleHandle db 'GetModuleHandleA',0 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> .code ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> include RemoteCode.asm start: invoke GetModuleHandle,addr szDllKernel mov ebx,eax invoke GetProcAddress,ebx,offset szLoadLibrary mov lpLoadLibrary,eax invoke GetProcAddress,ebx,offset szGetProcAddress mov lpGetProcAddress,eax invoke GetProcAddress,ebx,offset szGetModuleHandle mov lpGetModuleHandle,eax ;******************************************************************** ; 查找文件管理器窗口并获取进程ID,然后打开进程 ;******************************************************************** invoke FindWindow,addr szDesktopClass,addr szDesktopWindow invoke GetWindowThreadProcessId,eax,offset dwProcessID mov dwThreadID,eax invoke OpenProcess,PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or \ PROCESS_VM_WRITE,FALSE,dwProcessID .if eax mov hProcess,eax ;******************************************************************** ; 在进程中分配空间并将执行代码拷贝过去,然后创建一个远程线程 ;******************************************************************** invoke VirtualAllocEx,hProcess,NULL,REMOTE_CODE_LENGTH,MEM_COMMIT,PAGE_EXECUTE_READWRITE .if eax mov lpRemoteCode,eax invoke WriteProcessMemory,hProcess,lpRemoteCode,\ offset REMOTE_CODE_START,REMOTE_CODE_LENGTH,NULL invoke WriteProcessMemory,hProcess,lpRemoteCode,\ offset lpLoadLibrary,sizeof dword * 3,NULL mov eax,lpRemoteCode add eax,offset _RemoteThread - offset REMOTE_CODE_START invoke CreateRemoteThread,hProcess,NULL,0,eax,0,0,NULL invoke CloseHandle,eax .endif invoke CloseHandle,hProcess .else invoke MessageBox,NULL,addr szErrOpen,NULL,MB_OK or MB_ICONWARNING .endif invoke ExitProcess,NULL ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> end start 4.局限性:有时会遇到申请内存失败。 总结:以上的几种方法,相互配合将发挥更为强大的力量。但由于都是动作在ring3,有着先天不足的缺点,都逃不过内核模块的监测。 参考文献:<<Rootkits: Subverting the Windows Kernel>> 一本专门介绍rootkits的好书 可在网上baidu到 <<Win32汇编程序设计>> 罗云彬 -------------------------------------------------------------------------------- 【版权声明】: 本文原创于看雪技术论坛,一蓑烟雨, 转载请注明作者并保持文章的完整, 谢谢! |
地主 发表时间: 07-04-17 09:09 |
|
20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon
粤ICP备05087286号