必备绝技——Hook大法(上)

【游戏逆向】HOOK原理以及在游戏逆向中的应用 ②在某条代码处加入我们想处理的内容,例如某些变态功能 ,例如DXF扣血CALL ,判断是怪物对象直接赋值0将血量扣为0实现秒怪,而判断是人物对象直接不扣血,实现无敌的效果。我们想知道EAX的值,我们可以不hook push eax ,可以去HOOK上一句,因为2句的EAX值是相同的,也可以HOOK mov eax,[edx+c]WriteProcessMemory(hProcess,(LPDWORD)(Hook地址 + 0x00),&Temp,1,&WriteSize); 阅读详情
 
【文章标题】 :  必备绝技—— 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  退出
    
   当然也可以合成一个文件,但这样分开的好处是可以实现模块化,可以分别关心各自的功能,也便于以后重用。
   (三)代码实例:
      .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
 
 
短视频ks(某手)高版本最新抓包方案,教你用hook大法绕过QUIC协议 一般大多数网站、APP最常用的是http、https协议,而某两款最火的短视频dy(某音)、ks(某手)最新版使用的是quic协议(见附录1),导致fiddler和charles无法直接抓到包(某手7版本以下可以直接抓到包)。 而我给大家带来的最常用一种方案(亲测可行),主要思路是禁用或者绕过quic相关的so加载,迫使它走https协议。某手的相关so文件是libconnection**.so ,接下来看方案准备前的环节。 阅读详情

相关推荐

Ubuntu 22.04源码编译安装ROS Noetic

Ubuntu 22.04源码编译安装ROS Noetic

Drknown的博客 2万+

游戏逆向安全之HOOK变态功能实现

游戏逆向安全之HOOK变态功能实现

【DDSCAT——离散偶极近似仿真程序04】参数理解和模型设计

在这一部分,我们开始理解DDSCAT程序设计中的一些参数问题。 承接第二部分内容中的ddscat.par文件,我们来聊一聊偶极子、实际体积、有效半径等关键词。 一、偶极子点阵 手册中说,我们需要设计模型(target/目标),它是有偶极子点阵组成的。偶极子,顾名思义,是由一对电荷组成的,但我们不用设计一对,我们设计一个点就行,...

XD_Yangf的博客 7552

必备绝技--Hook大法( 上 )

【文章标题】: 必备绝技--Hook大法(上)【文章作者】: LvG【作者邮箱】: LvG2008@gmail.com【作者声明】: 这没有什么新鲜东西,其内容全部来自于前辈,姑且当作学习笔记。文字用自己的话写出,四段代码均出自别人(知道作者的,以注明),但短小精悍,就写在一起了,便于察看。欢迎指正。-------------------------------------------------

www.pingfi.com 1493

偏差平方和说明什么_共同方法偏差检验之潜在误差变量控制法的Amos操作

潜在误差变量控制法是在结构方程模型中,将共同方法偏差作为一个潜变量加入模型,如果在包含方法偏差潜变量情况下模型的显著拟合度优于不包含共同方法偏差潜变量的情况,那么共同方法偏差效应就得到了检验,包含共同方法偏差潜在变量的模型,对于预测与效标变量关系的估计则控制了共同方法偏差。具体操作如下:因为这个过程也是基于因子分析的基础上进行的,关于绘制模型以及运行等过程不再介绍,请参考前面关于“合成信度 ”的相...

weixin_28730927的博客 2363

一个测试工程师走进一家酒吧……

一个测试工程师走进一家酒吧,要了一杯啤酒;一个测试工程师走进一家酒吧,要了一杯咖啡;一个测试工程师走进一家酒吧,要了 0.7 杯啤酒;一个测试工程师走进一家酒吧,要了-1 杯啤酒;一个测试...

字节跳动技术团队官方博客 4884

HOOK大法实现不修改程序代码给程序添加功能

【文章标题】: HOOK大法实现不修改程序代码给程序添加功能 【文章作者】: 0x18c0 【软件名称】: Scylla 【使用工具】: OD、Stub_PE、ResHacker 【版权声明】: 本文原创于0x18c0, 转载请注明作者并保持文章的完整, 谢谢! 菜鸟第一次发帖,写的不好的地方请各位多多包含 本来是第三次培训的作业,要给Scylla加上弹窗 @Kido 老师在

hemeinvyiqiluoben的专栏 7469

0009 用VisualStudio设计Max工具

这次分享个独家专利^)^:在Visual Studio中设计3dsMax脚本工具界面。 某次做原型设计时,需求改来改去,实在懒得搞GUI;虽然也尝试在Axure RP里画原型,但还是Visual Studio更顺手,也更容易测试一些交互,就直接在VS里做了。后来突发奇想,想实验一把能否直接用到Max里去,结果没想到成功了,效果还挺好。发现了新大陆,记录一下。   开始: 在VS里新建W...

whwst的专栏 769

必备绝技——hook大法(中)

 【文章标题】: 必备绝技——hook大法( 中 )【文章作者】: LvG【作者邮箱】: LvG2008@gmail.com【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!--------------------------------------------------------------------------------【详细过程】  这次主要说说核心层的hook。包

1678

Qt6安装保姆级教程:从国内镜像下载到配置避坑指南(附清华/中科大源)

本文提供详细的Qt6安装与配置指南,重点介绍如何利用清华大学、中国科学技术大学等国内镜像源解决下载速度慢的问题。内容涵盖在线安装器获取、组件选择策略、环境变量配置以及常见编译与部署问题的排查方法,旨在帮助国内开发者高效、顺畅地完成Qt6开发环境搭建。

weixin_29281915的博客 633

RT-Thread必考面试题及参考答案

RT-Thread的设备驱动模型遵循层次化的结构,设计简洁且易于扩展。它主要由设备注册、设备操作和设备控制三部分组成。设备驱动模型允许开发者为不同的硬件设备编写驱动程序,这些驱动程序可以被RT-Thread内核统一管理和调度。在RT-Thread中,设备被抽象成一系列标准的接口,包括打开、关闭、读取、写入、控制等操作,这些操作封装在结构体中。设备驱动程序需要实现这些接口,然后通过调用函数注册设备,使其对系统可见。这种模型不仅简化了驱动开发,还提高了代码的可移植性和可维护性。

大模型大数据攻城狮的专栏 1823

必备绝技——hook大法( 中 )

【文章标题】: 必备绝技——hook大法( 中 )【文章作者】: LvG【作者邮箱】: LvG2008@gmail.com【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!--------------------------------------------------------------------------------【详细过程】  这次主要说说核心层的hook。包括

sxjswift的专栏 1933

OpenHarmony开发一个App,安装到BearPi-HM Micro开发板

建议先阅读我们这篇,这里面详细介绍了,以及hap包安装的全过程。本篇是介绍如何开发一个App,然后安装到开发板上,比如hap包,无法安装等问题。

Halifax 1030

必备绝技--Hook大法(上)

必备绝技--Hook大法标 题: 【原创】必备绝技--Hook大法( 上 )作 者: Lvg时 间: 2007-04-08,22:23链 接: http://bbs.pediy.com/showthread.php?t=42362【文章标题】: 必备绝技--Hook大法(上)【文章作者】: LvG【作者邮箱】: LvG2008@gmail.com【作者声明】:

rgbsky_nudt的专栏 2664

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

ctf python大法好_[原创]必备绝技——hook大法( 中 )

[原创]必备绝技——hook大法( 中 )2007-4-9 23:37190402[原创]必备绝技——hook大法( 中 )2007-4-9 23:37190402【文章标题】: 必备绝技——hook大法( 中 )【文章作者】: LvG【作者邮箱】: [email]LvG2008@gmail.com[/email]【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!--------...

weixin_39784774的博客 381

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

备绝技——hook大法( 中 )

必备绝技——hook大法( 中 ) 标 题: 【原创】必备绝技—

www.pingfi.com 1306

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

SSDT HOOK

文章标题】: 必备绝技——hook大法( 中 ) 【文章作者】: LvG 【作者邮箱】: LvG2008@gmail.com 【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教! --------------------------------------

whispermemory的专栏 4073

Hook使用实例

【文章标题】: 必备绝技--Hook大法(上)【文章作者】: LvG【作者邮箱】: LvG2008@gmail.com【作者声明】: 这没有什么新鲜东西,其内容全部来自于前辈,姑且当作学习笔记。文字用自己的话写出,四段代码均出自别人(知道作者的,以注明),但短小精悍,就写在一起了,便于察看。欢迎指正。-------------------------------------------------

861

SSDT hook学习资料以及总结问题

很想把调试后的代码发出来,但是由于是在公司写的,在此就不贴出来了,不过根据下边的这些资料,聪明的你一定可以把原理弄懂并且整出来的。 SSDT hook 的一点 疑问->获取服务地址用一句话就搞定 了,还用写个函数用内联汇编?KeServiceDescriptorTable.ServiceTableBase[122]   http://www.mengwuji.net/forum

duhaomin的专栏 1571
上一篇: NT下模拟Ctrl+Alt+Del
下一篇: Anskya说的
RemoteHacker
博客等级 码龄19年 0粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值