首页
社区
课程
招聘
[原创]必备绝技--Hook大法( 上 )
发表于: 2007-4-8 22:23 47433

[原创]必备绝技--Hook大法( 上 )

Lvg 活跃值
5
2007-4-8 22:23
47433

【文章标题】: 必备绝技--Hook大法(上)
【文章作者】: LvG
【作者邮箱】: [email]LvG2008@gmail.com[/email]
【作者声明】: 这没有什么新鲜东西,其内容全部来自于前辈,姑且当作学习笔记。文字用自己的话写出,四段代码均出自别人(知道作者的,以注明),但短小精悍,就写在一起了,便于察看。欢迎指正。
--------------------------------------------------------------------------------
【详细过程】
  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 退出
         
  当然也可以合成一个文件,但这样分开的好处是可以实现模块化,可以分别关心各自的功能,也便于以后重用。
  (三)代码实例:
                  .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 :DWORD, :DWORD, :DWORD
  HookProc PROTO         STDCALL :LPVOID
  
                  .code
  HookProc         proc         Arg1:LPVOID
                        invoke         MessageBox, NULL, addr szHooked, addr szMsgTitle, MB_OK
                        ret
  HookProc         endp
  
  IATHook         proc         pDLLName:LPVOID, 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汇编程序设计>> 罗云彬
  
--------------------------------------------------------------------------------

                                                       2007年04月08日 22:15:49


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (35)
雪    币: 707
活跃值: (1301)
能力值: ( LV9,RANK:190 )
在线值:
发帖
回帖
粉丝
2
呵呵,学习.............
2007-4-8 22:33
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
hook概念:是一种通过更改程序的数据结构或代码结构从而改变程序运行路线的一种方法。(纯属本人自己观点)

改变运行路线WriteProcessMemory就够了

我认为绝大多数的ring3级hook都是在监视并修改线程环境

应该有个注入的概念
2007-4-9 00:38
0
雪    币: 311
活跃值: (124)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
学习ing,顶一个.
2007-4-9 00:50
0
雪    币: 235
活跃值: (29)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
6
WriteProcessMemory的确可以,但想改变运行路线的方法很多

从广义角度理解,我认为注入应该属于一种hook,或是为达到hook而服务的。
2007-4-9 07:38
0
雪    币: 461
活跃值: (93)
能力值: ( LV9,RANK:1170 )
在线值:
发帖
回帖
粉丝
7
好文,留个名!
2007-4-9 12:56
0
雪    币: 154
活跃值: (80)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
很有条理,看后很清楚 期待这个:
二.内核模式Hook:ssdt-hook,idt-hook,int 2e/sysenter-hook
2007-4-9 14:01
0
雪    币: 114
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
强贴要留名!!
2007-4-13 13:40
0
雪    币: 156
活跃值: (48)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
学习学习学习
2007-4-13 15:57
0
雪    币: 295
活跃值: (461)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
11
学习,楼主人才。
2007-4-24 23:06
0
雪    币: 202
活跃值: (151)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
我要慢慢肯掉你
2007-4-26 17:07
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
好文。。。。。。。。。。
2007-4-26 22:45
0
雪    币: 103
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
讲的很有条理。
2007-4-27 11:07
0
雪    币: 360
活跃值: (77)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
15
但是不知道怎么在其他钩子之前调用自己的hook呢
2007-5-9 00:39
0
雪    币: 314
活跃值: (15)
能力值: ( LV12,RANK:410 )
在线值:
发帖
回帖
粉丝
16
好,顶。
不过,别用此法做坏事
2007-5-9 09:50
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
绝对的支持这个
2007-5-9 13:32
0
雪    币: 1505
能力值: (RANK:210 )
在线值:
发帖
回帖
粉丝
18
楼主不仅人才 而且还有高尚的情操,奉献的精神
2007-5-9 15:10
0
雪    币: 1312
活跃值: (5164)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
19
学习学习学习
2007-5-26 02:30
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
看不懂,但还是要感谢分享!
2007-5-26 02:55
0
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
这是做什么用的........
2007-5-26 13:55
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
(四)局限性:1当程序运用一种叫late-demand binding技术,函数被调用时才定位地址,这样以来就不能在IAT中定位目标函数地址了.2当目标程序用动态加载(LoadLibrary)时,这种方法也将失效.

你不可以HOOK LoadLibrary函数吗?
2007-6-1 19:48
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
好文是好文,可是头也好大了,谢谢楼主!
2007-6-1 22:17
0
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
深奥啊,菜鸟学习中。。
2007-6-4 07:49
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
25
局限性:1当程序运用一种叫late-demand binding技术,函数被调用时才定位地址,这样以来就不能在IAT中定位目标函数地址了.2当目标程序用动态加载(LoadLibrary)时,这种方法也将失效.


RING3下继续HOOK掉LoadLibraryA(W)、LoadLibraryExA(W)、GetProcAdress就可以了嘛~
2007-10-4 22:27
0
游客
登录 | 注册 方可回帖
返回
//