Nisy 发表于 2007-4-9 07:39:28

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

标 题: 【原创】必备绝技--Hook大法(一)
作 者: Lvg
时 间: 2007-04-08,22:23
链 接: http://bbs.pediy.com/showthread.php?threadid=42362

【文章标题】: 必备绝技--Hook大法(一)
【文章作者】: LvG
【作者邮箱】: [email protected]
【作者声明】: 这没有什么新鲜东西,其内容全部来自于前辈,姑且当作学习笔记。文字用自己的话写出,四段代码均出自别人(知道作者的,以注明),但短小精悍,就写在一起了,便于察看。欢迎指正。
--------------------------------------------------------------------------------
【详细过程】
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),目标函数(GetProcAddress)
    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
szMsgTitledb   "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   .e_magic != IMAGE_DOS_SIGNATURE
             ;0x4D 0x5A (MZ)
            xor   eax, eax
            ret
                ;Return 0
         .endif
      
         add   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   .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, .OptionalHeader.DataDirectory.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 .Name1 != NULL
            mov   ecx, hModule
            add   ecx, .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, .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   .u1.Function != NULL
            mov ecx, hModule
            add ecx, .u1.Function
         
            mov edx, .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, .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 , 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")

HHOOKg_hHook;
TCHARg_szPath;
TCHARg_szCurrent;
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 = 0;

      if(g_szCurrent != 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;
      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
includelibuser32.lib
include    kernel32.inc
includelibkernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      .data
hInstancedd?

      .data?
hWnd    dd?
hHook    dd?
dwMessagedd?
szAscii    db4 dup (?)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; dll 的入口函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DllEntryproc_hInstance,_dwReason,_dwReserved

      push_hInstance
      pophInstance
      moveax,TRUE
      ret

DllEntryEndp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 键盘钩子回调函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
HookProcproc_dwCode,_wParam,_lParam
      local@szKeyState:byte

      invokeCallNextHookEx,hHook,_dwCode,_wParam,_lParam
      invokeGetKeyboardState,addr @szKeyState
      invokeGetKeyState,VK_SHIFT
      mov@szKeyState + VK_SHIFT,al
      movecx,_lParam
      shrecx,16
      invokeToAscii,_wParam,ecx,addr @szKeyState,addr szAscii,0
      movbyte ptr szAscii ,0
      invokeSendMessage,hWnd,dwMessage,dword ptr szAscii,NULL
      xoreax,eax
      ret

HookProcendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 安装钩子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
InstallHookproc_hWnd,_dwMessage

      push_hWnd
      pophWnd
      push_dwMessage
      popdwMessage
      invokeSetWindowsHookEx,WH_KEYBOARD,addr HookProc,hInstance,NULL
      movhHook,eax
      ret

InstallHookendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 卸载钩子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
UninstallHookproc

      invokeUnhookWindowsHookEx,hHook
      ret

UninstallHookendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      EndDllEntry
文件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
includelibuser32.lib
include    kernel32.inc
includelibkernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      .data
hInstancedd?

      .data?
hWnd    dd?
hHook    dd?
dwMessagedd?
szAscii    db4 dup (?)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; dll 的入口函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DllEntryproc_hInstance,_dwReason,_dwReserved

      push_hInstance
      pophInstance
      moveax,TRUE
      ret

DllEntryEndp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 键盘钩子回调函数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
HookProcproc_dwCode,_wParam,_lParam
      local@szKeyState:byte

      invokeCallNextHookEx,hHook,_dwCode,_wParam,_lParam
      invokeGetKeyboardState,addr @szKeyState
      invokeGetKeyState,VK_SHIFT
      mov@szKeyState + VK_SHIFT,al
      movecx,_lParam
      shrecx,16
      invokeToAscii,_wParam,ecx,addr @szKeyState,addr szAscii,0
      movbyte ptr szAscii ,0
      invokeSendMessage,hWnd,dwMessage,dword ptr szAscii,NULL
      xoreax,eax
      ret

HookProcendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 安装钩子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
InstallHookproc_hWnd,_dwMessage

      push_hWnd
      pophWnd
      push_dwMessage
      popdwMessage
      invokeSetWindowsHookEx,WH_KEYBOARD,addr HookProc,hInstance,NULL
      movhHook,eax
      ret

InstallHookendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 卸载钩子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
UninstallHookproc

      invokeUnhookWindowsHookEx,hHook
      ret

UninstallHookendp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      EndDllEntry

4.局限性:会产生Dll体,虽然没有进程,但可以通过其他工具轻易发现
(三)通过创建远程线程
1.一般思路:远程线程,顾名思义就是在其他进程中创建一个线程,如果这个进程是系统每次启动必须加载的,那么就能每次有注入目标。这主要通过CreateRemoteThread函数完成。
2.大体框架:
文件1:可以重定位的代码,或是DLL,这个代码当然是有特定目的的
文件2:查找特定进程,如文件管理器,打开进程
          VirtualAllocEx函数在进程中申请分配空间
          WriteProcessMemory函数将远程线程中的代码拷贝到申请到的空间
          CreateRemoteThread函数创建远程线程
3.代码实例:
文件1:一段可重定位代码
REMOTE_CODE_STARTequ this byte

_lpLoadLibary    dd?;输入函数地址表
_lpGetProcAddressdd?
_lpGetModuleHandledd?

_lpMessageBox    dd?

            ;全局变量表
_hInstancedd?
_szDllUserdb'User32.dll',0
_szMessageBoxdb'MessageBox',0
_szCaptiondb'A rootkit !',0
_szText    db'Hello,im LvG,but you cant find me!',0

      .code
_RemoteThreadprocuses ebx edi esi lParam
      local@hModule
      local@hInstance
      
      call@F
      @@:
      popebx
      subebx, offset @B
      
      _invoke,NULL
      mov, eax
      
      
      leaeax,
      _invoke, eax
      mov@hModule, eax
      leaesi,
      _invoke, @hModule, esi
      mov, eax
      leaeax,
      leaecx,
   
      _invoke , NULL, ecx, eax,MB_OK
      ret
_RemoteThreadendp
REMOTE_CODE_ENDequ this byte
REMOTE_CODE_LENGTHequ offset REMOTE_CODE_END - offset REMOTE_CODE_START
文件2:
      .386
      .model flat, stdcall
      option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include    windows.inc
include    user32.inc
includelibuser32.lib
include    kernel32.inc
includelibkernel32.lib
include    Macro.inc
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      .data?
lpLoadLibrarydd?
lpGetProcAddress dd?
lpGetModuleHandle dd?
dwProcessIDdd?
dwThreadIDdd?
hProcessdd?
lpRemoteCodedd?

      .const
szErrOpen    db'无法打开远程线程!',0
szDesktopClass    db'Progman',0
szDesktopWindow    db'Program Manager',0
szDllKernel    db'Kernel32.dll',0
szLoadLibrary    db'LoadLibraryA',0
szGetProcAddressdb'GetProcAddress',0
szGetModuleHandle db'GetModuleHandleA',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include    RemoteCode.asm

start:
      invokeGetModuleHandle,addr szDllKernel
      movebx,eax
      invokeGetProcAddress,ebx,offset szLoadLibrary
      movlpLoadLibrary,eax
      invokeGetProcAddress,ebx,offset szGetProcAddress
      movlpGetProcAddress,eax
      invokeGetProcAddress,ebx,offset szGetModuleHandle
      movlpGetModuleHandle,eax
;********************************************************************
; 查找文件管理器窗口并获取进程ID,然后打开进程
;********************************************************************
      invokeFindWindow,addr szDesktopClass,addr szDesktopWindow
      invokeGetWindowThreadProcessId,eax,offset dwProcessID
      movdwThreadID,eax
      invokeOpenProcess,PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or \
      PROCESS_VM_WRITE,FALSE,dwProcessID
      .ifeax
      movhProcess,eax
;********************************************************************
; 在进程中分配空间并将执行代码拷贝过去,然后创建一个远程线程
;********************************************************************
      invokeVirtualAllocEx,hProcess,NULL,REMOTE_CODE_LENGTH,MEM_COMMIT,PAGE_EXECUTE_READWRITE
      .ifeax
          movlpRemoteCode,eax
          invokeWriteProcessMemory,hProcess,lpRemoteCode,\
            offset REMOTE_CODE_START,REMOTE_CODE_LENGTH,NULL
          invokeWriteProcessMemory,hProcess,lpRemoteCode,\
            offset lpLoadLibrary,sizeof dword * 3,NULL
          moveax,lpRemoteCode
          addeax,offset _RemoteThread - offset REMOTE_CODE_START
          invokeCreateRemoteThread,hProcess,NULL,0,eax,0,0,NULL
          invokeCloseHandle,eax
      .endif
      invokeCloseHandle,hProcess
      .else
      invokeMessageBox,NULL,addr szErrOpen,NULL,MB_OK or MB_ICONWARNING
      .endif
      invokeExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
      endstart
4.局限性:有时会遇到申请内存失败。

总结:以上的几种方法,相互配合将发挥更为强大的力量。但由于都是动作在ring3,有着先天不足的缺点,都逃不过内核模块的监测。


参考文献:<<Rootkits: Subverting the Windows Kernel>> 一本专门介绍rootkits的好书 可在网上baidu到
            <<Win32汇编程序设计>> 罗云彬

--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛,一蓑烟雨, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2007年04月08日 22:15:49

fonge 发表于 2007-4-9 15:20:36

最近发现好多东东~
学都学不过来了,不知道怎么办/:02

chsmr 发表于 2008-2-27 18:06:22

好东西,只先收藏一下,谢谢提供。

zqjian 发表于 2008-3-6 09:21:18

谢谢老大,学无止境呀,好难哦

dalangtaosha 发表于 2008-3-8 17:34:47

支持强力支持

疯言疯语 发表于 2008-3-16 19:32:51

原帖由 chsmr 于 2008-2-27 18:06 发表 https://www.chinapyg.com/images/common/back.gif
好东西,只先收藏一下,谢谢提供。
收藏是个好办法

ascgq 发表于 2008-3-18 18:28:34

虽然还不太懂,还是谢谢老大!

yayaw 发表于 2008-3-23 13:17:45

谢谢呀。。。。。。

chuangwang 发表于 2008-3-29 18:35:59

太复杂了,看不明白,慢慢学吧。

775825866 发表于 2008-4-9 13:13:39

谢谢指教 学习一下
页: [1] 2 3 4
查看完整版本: 必备绝技--Hook大法(一)