挂钩Windows API

    技术2022-05-11  11

    ===========================[ 挂钩Windows API ]==================

                                        SoBeIt

                           Author:  Holy_Father <holy_father@phreaker.net>                       Version: 1.1 english                       Date:    6.10.2002

    =====[ 1. 内容 ]=============================================

    1. 内容2. 介绍3. 挂钩方法  3.1 运行前挂钩  3.2 运行时挂钩    3.2.1 使用IAT挂钩本进程     3.2.2 改写入口点挂钩本进程    3.2.3 保存原始函数    3.2.4 挂钩其它进程      3.2.4.1 DLL注入      3.2.4.2 独立的代码      3.2.4.3 原始修改4. 结束语

    =====[ 2. 介绍 ]====================================================

        这篇文章是有关在OS Windows下挂钩API函数的方法。所有例子都在基于NT技术的Windows版本NT 4.0及以上有效(Windows NT 4.0, Windows 2000, Windows XP)。可能在其它Windows系统也会有效。    你应该比较熟悉Windows下的进程、汇编器、PE文件结构和一些API函数,才能明白这篇文章里的内容。    这里使用"Hooking API"这个术语表示对API的完全修改。当调用被挂钩的API时,我们的代码能立刻被执行。我将写下完全的挂钩过程。

    =====[ 3. 挂钩方法 ]==============================================

        一般来说我们的目的是用我们的代码取代一些函数里的代码。这些问题有时可以在进程运行前解决。这些大多数时候可以用我们运行的用户级进程来完成,目的可以是修改程序的行为。举个例子应用程序的破解,比方说有些程序会在启动时需要原光盘,我们想要不用光盘就启动它。如果我们修改获取驱动类型的函数我们就可以让程序从硬盘启动。    当我们挂钩系统进程时(比如说服务)这些不可能做到或者我们不打算这么做,或者在这个例子里我们不知道哪个进程才是目标。这时我们就要用到动态挂钩(在运行时挂钩)的技术。使用的例子有rootkit或者病毒里的反杀毒软件的技术。

    =====[ 3.1 运行前挂钩 ]===========================================

        这里修改我们想要修改函数来自的物理模块(大多数时候是.exe或.dll)。在这里我们至少有3种可能的做法。    第一种可能是找到函数的入口点然后重写它的代码。这会因为函数的大小而受限制,但我们能动态加载其它一些模块(API LoadLibrary),所以应该足够了。    内核函数(kernel32.dll)是通用的因为Windows中每个进程都有这个模块的拷贝。另一个好处是如果我们知道哪些模块在某版本中会修改,我们可以在一些API如LoadLibraryA中使用直接的指针。这是因为kernel模块在内存中地址在相同Windows版本中是固定的。我们同样也能用动态加载的模块的作用。在这里它的初始化部分在加载进内存后立刻就运行。在新模块的初始化部分我们不受限制。    第二种可能是在模块中被代替的函数只是原函数的扩展。然后我们选择要么修改开始的5个字节为跳转指令或者改写IAT。如果改为跳转指令,那么将会改变指令执行流程转为执行我们的代码。如果调用了IAT记录被修改的函数,我们的代码能在调用结束后被执行。但模块的扩展没那么容易,因为我们必须注意DLL首部。    下一个是修改整个模块。这意味着我们创建自己的模块版本,它能够加载原始的模块并调用原始的函数,当然我们对这个不感兴趣,但重要的函数都是被更新的。这种方法对于有的模块过大有几百个导出函数的很不方便。

    =====[ 3.2 运行时挂钩 ]==========================================

        在运行前挂钩通常都非常特殊,并且是在内部面向具体的应用程序(或模块)。如果我们更换了kernel32.dll或ntdll.dll里的函数(只在NT操作系统里),我们就能完美地做到在所有将要运行的进程中替换这个函数。但说来容易做起来却非常难,因为我们不但得考虑精确性和需要编写比较完善的新函数或新模块,但主要问题是只有将要运行的进程才能被挂钩(要挂钩所有进程只能重启电脑)。另一个问题是如何进入这些文件,因为NT操作系统保护了它们。比较好的解决方法在进程正在运行时挂钩。这需要更多的有关知识,但最后的结果相当不错。在运行中挂钩只对能够写入它们的内存的进程能成功。为了能写入它自己我们使用API函数WriteProcessMemory。现在我们开始运行中挂钩我们的进程。

    =====[ 3.2.1 使用IAT挂钩本进程 ]===================================

        这里有很多种可能性。首先介绍如何用改写IAT挂钩函数的方法。接下来这张图描述了PE文件的结构:

         +-------------------------------+     - offset 0     | MS DOS标志("MZ") 和 DOS块     |     +-------------------------------+          |      PE 标志 ("PE")           |     +-------------------------------+     |             .text             |     - 模块代码     |           程序代码            |     |                               |     +-------------------------------+     |             .data             |     - 已初始化的(全局静态)数据     |          已初始化的数据       |     |                               |     +-------------------------------+     |            .idata             |     - 导入函数的信息和数据     |            导入表             |            |                               |     +-------------------------------+     |            .edata             |     - 导出函数的信息和数据     |            导出表             |            |                               |     +-------------------------------+     |           调试符号            |     +-------------------------------+

        这里对我们比较重要的是.idata部分的导入地址表(IAT)。这个部分包含了导入的相关信息和导入函数的地址。有一点很重要的是我们必须知道PE文件是如何创建的。当在编程语言里间接调用任意API(这意味着我们是用函数的名字来调用它,而不是用它的地址),编译器并不直接把调用连接到模块,而是用jmp指令连接调用到IAT,IAT在系统把进程调入内存时时会由进程载入器填满。这就是我们可以在两个不同版本的Windows里使用相同的二进制代码的原因,虽然模块可能会加载到不同的地址。进程载入器会在程序代码里调用所使用的IAT里填入直接跳转的jmp指令。所以我们能在IAT里找到我们想要挂钩的指定函数,我们就能很容易改变那里的jmp指令并重定向代码到我们的地址。完成之后每次调用都会执行我们的代码了。这种方法的缺点是经常有很多函数要被挂钩(比方说如果我们要在搜索文件的API中改变程序的行为我们就得修改函数FindFirstFile和FindNextFile,但我们要知道这些函数都有ANSI和WIDE版本,所以我们不得不修改FindFirstFileA、FindFirstFileW、FindNextFileA和FileNextFileW的IAT地址。但还有其它类似的函数如FindFirstFileExA和它的WIDE版本FindFirstFileExW,也都是由前面提到的函数调用的。我们知道FindFirstFileW调用FindFirstFileExW,但这是直接调用,而不是使用IAT。再比如说ShellAPI的函数SHGetDesktopFolder也会直接调用FindFirstFilwW或FindFirstFileExW)。如果我们能获得它们所有,结果就会很完美。    我们通过使用imagehlp.dll里的ImageDirectoryEntryToData来很容易地找到IAT。

        PVOID ImageDirectoryEntryToData(        IN LPVOID Base,            IN BOOLEAN MappedAsImage,            IN USHORT DirectoryEntry,            OUT PULONG Size        );

    在这里Base参数可以用我们程序的Instance(Instance通过调用GetModuleHandle获得):

        hInstance = GetModuleHandleA(NULL);

    DirectoryEntry我们可以使用恒量IMAGE_DIRECTORY_ENTRY_IMPORT。

        #define IMAGE_DIRECTORY_ENTRY_IMPORT 1

        函数的结果是指向第一个IAT记录指针。IAT的所有记录是由IMAGE_IMPORT_DESCRIPTOR定义的结构。所以函数结果是指向IMAGE_IMPORT_DESCRIPTOR的指针。

        typedef struct _IMAGE_THUNK_DATA {        union {            PBYTE ForwarderString;            PDWORD Function;            DWORD Ordinal;            PIMAGE_IMPORT_BY_NAME AddressOfData;        } ;    } IMAGE_THUNK_DATA,*PIMAGE_THUNK_DATA;

        typedef struct _IMAGE_IMPORT_DESCRIPTOR {        union {            DWORD Characteristics;            PIMAGE_THUNK_DATA OriginalFirstThunk;        } ;        DWORD TimeDateStamp;        DWORD ForwarderChain;        DWORD Name;        PIMAGE_THUNK_DATA FirstThunk;    } IMAGE_IMPORT_DESCRIPTOR,*PIMAGE_IMPORT_DESCRIPTOR;

        IMAGE_IMPORT_DESCRIPTOR里的Name成员变量是模块名字的指针。如果我们想要挂钩某个函数比如是来自kernel32.dll我们就在导入表里找属于名字kernel32.dll的描述符号。我们先调用ImageDirectoryEntryToData然后找到名字是"kernel32.dll"的描述符号(可能不只一个描述符号是这个名字),最后我们在这个模块的记录里所有函数的列表里找到我们想要的函数(函数地址通过GetProcAddress函数获得)。如果我们找到了就必须用VirtualProtect函数来改变内存页面的保护属性,然后就可以在内存中的这些部分写入代码了。在改写了地址之后我们要把保护属性改回来。在调用VirtualProtect之前我们还要先知道有关页面的信息,这通过VirtualQuery来实现。我们可以加入一些测试以防某些函数会失败(比方说如果第一次调用VirtualProctect就失败了,我们就没办法继续)。

        PCSTR pszHookModName = "kernel32.dll",pszSleepName = "Sleep";    HMODULE hKernel = GetModuleHandle(pszHookModName);    PROC pfnNew = (PROC)0x12345678,       //这里存放新地址        pfnHookAPIAddr = GetProcAddress(hKernel,pszSleepName);

        ULONG ulSize;    PIMAGE_IMPORT_DESCRIPTOR pImportDesc =         (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(            hKernel,            TRUE,            IMAGE_DIRECTORY_ENTRY_IMPORT,            &ulSize        );

        while (pImportDesc->Name)    {        PSTR pszModName = (PSTR)((PBYTE) hKernel + pImportDesc->Name);        if (stricmp(pszModName, pszHookModName) == 0)         break;           pImportDesc++;    }

        PIMAGE_THUNK_DATA pThunk =     (PIMAGE_THUNK_DATA)((PBYTE) hKernel + pImportDesc->FirstThunk);

        while (pThunk->u1.Function)    {        PROC* ppfn = (PROC*) &pThunk->u1.Function;        BOOL bFound = (*ppfn == pfnHookAPIAddr);

            if (bFound)         {            MEMORY_BASIC_INFORMATION mbi;            VirtualQuery(                ppfn,                &mbi,                sizeof(MEMORY_BASIC_INFORMATION)            );            VirtualProtect(                mbi.BaseAddress,                mbi.RegionSize,                PAGE_READWRITE,                &mbi.Protect)            )

                *ppfn = *pfnNew;

                DWORD dwOldProtect;            VirtualProtect(                mbi.BaseAddress,                mbi.RegionSize,                mbi.Protect,                &dwOldProtect            );            break;        }        pThunk++;    }

    调用Sleep(1000)的结果如例子所示:

        00407BD8: 68E8030000    push 0000003E8h    00407BDD: E812FAFFFF    call Sleep

        Sleep:     ;这是跳转到IAT里的地址    004075F4: FF25BCA14000    jmp dword ptr [00040A1BCh]

        原始表:    0040A1BC: 79 67 E8 77 00 00 00 00          新表:    0040A1BC: 78 56 34 12 00 00 00 00

    所以最后会跳转到0x12345678。         

    =====[ 3.2.2 改写入口点挂钩本进程 ]==================

        改写函数入口点开始的一些字节这种方法相当简单。就象改变IAT里的地址一样,我们也要先修改页面属性。在这里对我们想要挂钩的函数是一开始的5个字节。为了之后的使用我们用动态分配MEMORY_BASIC_INFORMATION结构。函数的起始地址也是用GetProcAddress来获得。我们在这个地址里插入指向我们代码的跳转指令。接下来程序调用Sleep(5000)(所以它会等待5秒钟),然后Sleep函数被挂钩并重定向到new_sleep,最后它再次调用Sleep(5000)。因为新的函数new_sleep什么都不做并直接返回,所以整个程序只需要5秒钟而不是10秒种。

    .386p.model flat, stdcall

    includelib lib/kernel32.libSleep            PROTO :DWORDGetModuleHandleA    PROTO :DWORDGetProcAddress        PROTO :DWORD,:DWORDVirtualQuery        PROTO :DWORD,:DWORD,:DWORDVirtualProtect        PROTO :DWORD,:DWORD,:DWORD,:DWORDVirtualAlloc        PROTO :DWORD,:DWORD,:DWORD,:DWORDVirtualFree        PROTO :DWORD,:DWORD,:DWORDFlushInstructionCache    PROTO :DWORD,:DWORD,:DWORDGetCurrentProcess    PROTOExitProcess         PROTO :DWORD

    .data

    kernel_name         db "kernel32.dll",0sleep_name        db "Sleep",0old_protect        dd ?

    MEMORY_BASIC_INFORMATION_SIZE    equ 28

    PAGE_READWRITE        dd 000000004hPAGE_EXECUTE_READWRITE dd 000000040hMEM_COMMIT        dd 000001000hMEM_RELEASE        dd 000008000h

    .codestart:    push    5000    call    Sleep

    do_hook:    push    offset kernel_name    call    GetModuleHandleA    push    offset sleep_name    push    eax    call    GetProcAddress    mov    edi,eax            ;最后获得Sleep地址

        push    PAGE_READWRITE    push    MEM_COMMIT    push    MEMORY_BASIC_INFORMATION_SIZE    push     0    call    VirtualAlloc    test    eax,eax    jz     do_sleep    mov    esi,eax            ;为MBI结构分配内存

        push    MEMORY_BASIC_INFORMATION_SIZE    push    esi    push    edi    call    VirtualQuery        ;内存页的信息    test    eax,eax    jz    free_mem

        call    GetCurrentProcess    push    5    push    edi    push    eax    call    FlushInstructionCache    ;只是为了确定一下:)

        lea    eax,[esi+014h]    push    eax    push    PAGE_EXECUTE_READWRITE    lea    eax,[esi+00Ch]    push    [eax]    push    [esi]    call    VirtualProtect          ;我们要修改保护属性,这样才能够写入代码    test    eax,eax    jz    free_mem       

        mov    byte ptr [edi],0E9h    ;写入跳转指令    mov    eax,offset new_sleep    sub    eax,edi    sub    eax,5    inc    edi    stosd                ;这里是跳转地址

        push    offset old_protect    lea    eax,[esi+014h]    push    [eax]    lea    eax,[esi+00Ch]    push    [eax]    push    [esi]    call    VirtualProtect        ;恢复页保护属性

    free_mem:    push    MEM_RELEASE    push    0    push    esi    call    VirtualFree        ;释放内存do_sleep:    push    5000    call    Sleep    push    0    call    ExitProcessnew_sleep:                    ret    004hend start

    第二次调用Sleep的结果是这样:

        004010A4: 6888130000    push 000001388h    004010A9: E80A000000    call Sleep

        Sleep:     ;这里是跳转到IAT里的地址     004010B8: FF2514204000    jmp dword ptr [000402014h]

        tabulka:    00402014: 79 67 E8 77 6C 7D E8 77          Kernel32.Sleep:    77E86779: E937A95788    jmp 0004010B5h

        new_sleep:    004010B5: C20400    ret 004h   

    =====[ 3.2.3 保存原始函数 ]=====================================

        更多时候我们需要的不仅仅是挂钩函数。比方说也许我们并不想取代给定的函数而只是想检查一下它的结果,或者也许我们只是想在函数被使用特定的参数来调用时才取代原函数。比较好的例子有前面提过的通过取代FindXXXFile函数来完成隐藏文件。所以如果我们想要隐藏指定的文件并且不想被注意的话,就得对其它所有文件只调用没有被修改过的原始函数。这对使用修改IAT的方法时是很简单的,为调用原始函数我们可以用GetProcAddress获得它的原始地址,然后直接调用。但修改入口点的方法就会有问题,因为修改了函数入口点的5个字节,使我们破坏了原函数。所以我们必须保存开始的那些指令。这将用到以下的技术。    我们知道我们要修改开始的5个字节但不知道里面包含多少条指令以及指令的长度。我们得为开始那些指令保留足够的内存空间。16个字节应该足够了,因为函数开始时通常没有多长的指令,很可能根本就用不到16个字节。整个被保留的内存用0x90(0x90=nop)来填满。下一个5个字节预留给将在之后填入的跳转指令。

    old_hook:        db 090h,090h,090h,090h,090h,090h,090h,090h            db 090h,090h,090h,090h,090h,090h,090h,090h            db 0E9h,000h,000h,000h,000h

        现在我们已准备好拷贝开始的指令。为获得指令长度的代码相当麻烦,这就是我们得使用已完成的引擎的原因。它是由Z0MBiE写的。传入参数是我们要获得长度的指令的地址。输出参数在eax里。

    ; LDE32, Length-Disassembler Engine, 32-bit, (x) 1999-2000 Z0MBiE; special edition for REVERT tool

    ; version 1.05

    C_MEM1                  equ     0001h       ; |C_MEM2                  equ     0002h       ; |may be used simultaneouslyC_MEM4                  equ     0004h       ; |C_DATA1                 equ     0100h       ; |C_DATA2                 equ     0200h       ; |may be used simultaneouslyC_DATA4                 equ     0400h       ; |C_67                    equ     0010h       ; used with C_PREFIXC_MEM67                 equ     0020h       ; C_67 ? C_MEM2 : C_MEM4C_66                    equ     1000h       ; used with C_PREFIXC_DATA66                equ     2000h       ; C_66 ? C_DATA2 : C_DATA4C_PREFIX                equ     0008h       ; prefix. take opcode againC_MODRM                 equ     4000h       ; MODxxxR/MC_DATAW0                equ     8000h       ; opc&1 ? C_DATA66 : C_DATA1

                            p386                        model   flat                        locals  @@

                            .code

    public                  disasm_mainpublic                  _disasm_mainpublic                  @disasm_mainpublic                  DISASM_MAIN

    disasm_main:_disasm_main:@disasm_main:DISASM_MAIN:

    ; __fastcall            EAX; __cdecl               [ESP+4]

    ;这是我的第一处修改,它只是这个函数的声明get_instr_len:

                            mov     ecx, [esp+4]    ; ECX = opcode ptr

                            xor     edx, edx        ; 标志                        xor     eax, eax

    @@prefix:               and     dl, not C_PREFIX

                            mov     al, [ecx]                        inc     ecx

                            or      edx, table_1[eax*4]

                            test    dl, C_PREFIX                        jnz     @@prefix

                            cmp     al, 0F6h                        je      @@test                        cmp     al, 0F7h                        je      @@test

                            cmp     al, 0CDh                        je      @@int

                            cmp     al, 0Fh                        je      @@0F@@cont:                        test    dh, C_DATAW0 shr 8                        jnz     @@dataw0@@dataw0done:                        test    dh, C_MODRM shr 8                        jnz     @@modrm@@exitmodrm:                        test    dl, C_MEM67                        jnz     @@mem67@@mem67done:                        test    dh, C_DATA66 shr 8                        jnz     @@data66@@data66done:                        mov     eax, ecx                        sub     eax, [esp+4]

                            and     edx,C_MEM1+C_MEM2+C_MEM4+C_DATA1+C_DATA2+C_DATA4                        add     al, dl                        add     al, dh

    ;这里是我的第二处修改,只有在原始版本这里是retn@@exit:                 ret     00004h  

    @@test:                 or      dh, C_MODRM shr 8                        test    byte ptr [ecx], 00111000b  ; F6/F7 -- test                        jnz     @@cont                        or      dh, C_DATAW0 shr 8                        jmp     @@cont

    @@int:                  or      dh, C_DATA1 shr 8                        cmp     byte ptr [ecx], 20h                        jne     @@cont                        or      dh, C_DATA4 shr 8                        jmp     @@cont

    @@0F:                   mov     al, [ecx]                        inc     ecx                        or      edx, table_0F[eax*4]

                            cmp     edx, -1                        jne     @@cont

    @@error:                mov     eax, edx                        jmp     @@exit

    @@dataw0:               xor     dh, C_DATA66 shr 8                        test    al, 00000001b                        jnz     @@dataw0done                        xor     dh, (C_DATA66+C_DATA1) shr 8                        jmp     @@dataw0done

    @@mem67:                xor     dl, C_MEM2                        test    dl, C_67                        jnz     @@mem67done                        xor     dl, C_MEM4+C_MEM2                        jmp     @@mem67done

    @@data66:               xor     dh, C_DATA2 shr 8                        test    dh, C_66 shr 8                        jnz     @@data66done                        xor     dh, (C_DATA4+C_DATA2) shr 8                        jmp     @@data66done

    @@modrm:                mov     al, [ecx]                        inc     ecx

                            mov     ah, al  ; ah=mod, al=rm

                            and     ax, 0C007h                        cmp     ah, 0C0h                        je      @@exitmodrm

                            test    dl, C_67                        jnz     @@modrm16

    @@modrm32:              cmp     al, 04h                        jne     @@a

                            mov     al, [ecx]       ; sib                        inc     ecx                        and     al, 07h

    @@a:                    cmp     ah, 40h                        je      @@mem1                        cmp     ah, 80h                        je      @@mem4

                            cmp     ax, 0005h                        jne     @@exitmodrm

    @@mem4:                 or      dl, C_MEM4                        jmp     @@exitmodrm

    @@mem1:                 or      dl, C_MEM1                        jmp     @@exitmodrm

    @@modrm16:              cmp     ax, 0006h                        je      @@mem2                        cmp     ah, 40h                        je      @@mem1                        cmp     ah, 80h                        jne     @@exitmodrm

    @@mem2:                 or      dl, C_MEM2                        jmp     @@exitmodrm

                            endp

                            .data

    ;0F      -- 在代码中分析,不需要标志(也就是标志(flag)必须为0);F6,F7   -- --//-- (ttt=000 -- 3 字节, 否则为2字节);CD      -- --//-- (如果为 CD 20 为6字节, 否则为2字节)

    table_1                 label   dword   ; 一般的指令

    dd C_MODRM              ; 00dd C_MODRM              ; 01dd C_MODRM              ; 02dd C_MODRM              ; 03dd C_DATAW0             ; 04dd C_DATAW0             ; 05dd 0                    ; 06dd 0                    ; 07dd C_MODRM              ; 08dd C_MODRM              ; 09dd C_MODRM              ; 0Add C_MODRM              ; 0Bdd C_DATAW0             ; 0Cdd C_DATAW0             ; 0Ddd 0                    ; 0Edd 0                    ; 0Fdd C_MODRM              ; 10dd C_MODRM              ; 11dd C_MODRM              ; 12dd C_MODRM              ; 13dd C_DATAW0             ; 14dd C_DATAW0             ; 15dd 0                    ; 16dd 0                    ; 17dd C_MODRM              ; 18dd C_MODRM              ; 19dd C_MODRM              ; 1Add C_MODRM              ; 1Bdd C_DATAW0             ; 1Cdd C_DATAW0             ; 1Ddd 0                    ; 1Edd 0                    ; 1Fdd C_MODRM              ; 20dd C_MODRM              ; 21dd C_MODRM              ; 22dd C_MODRM              ; 23dd C_DATAW0             ; 24dd C_DATAW0             ; 25dd C_PREFIX             ; 26dd 0                    ; 27dd C_MODRM              ; 28dd C_MODRM              ; 29dd C_MODRM              ; 2Add C_MODRM              ; 2Bdd C_DATAW0             ; 2Cdd C_DATAW0             ; 2Ddd C_PREFIX             ; 2Edd 0                    ; 2Fdd C_MODRM              ; 30dd C_MODRM              ; 31dd C_MODRM              ; 32dd C_MODRM              ; 33dd C_DATAW0             ; 34dd C_DATAW0             ; 35dd C_PREFIX             ; 36dd 0                    ; 37dd C_MODRM              ; 38dd C_MODRM              ; 39dd C_MODRM              ; 3Add C_MODRM              ; 3Bdd C_DATAW0             ; 3Cdd C_DATAW0             ; 3Ddd C_PREFIX             ; 3Edd 0                    ; 3Fdd 0                    ; 40dd 0                    ; 41dd 0                    ; 42dd 0                    ; 43dd 0                    ; 44dd 0                    ; 45dd 0                    ; 46dd 0                    ; 47dd 0                    ; 48dd 0                    ; 49dd 0                    ; 4Add 0                    ; 4Bdd 0                    ; 4Cdd 0                    ; 4Ddd 0                    ; 4Edd 0                    ; 4Fdd 0                    ; 50dd 0                    ; 51dd 0                    ; 52dd 0                    ; 53dd 0                    ; 54dd 0                    ; 55dd 0                    ; 56dd 0                    ; 57dd 0                    ; 58dd 0                    ; 59dd 0                    ; 5Add 0                    ; 5Bdd 0                    ; 5Cdd 0                    ; 5Ddd 0                    ; 5Edd 0                    ; 5Fdd 0                    ; 60dd 0                    ; 61dd C_MODRM              ; 62dd C_MODRM              ; 63dd C_PREFIX             ; 64dd C_PREFIX             ; 65dd C_PREFIX+C_66        ; 66dd C_PREFIX+C_67        ; 67dd C_DATA66             ; 68dd C_MODRM+C_DATA66     ; 69dd C_DATA1              ; 6Add C_MODRM+C_DATA1      ; 6Bdd 0                    ; 6Cdd 0                    ; 6Ddd 0                    ; 6Edd 0                    ; 6Fdd C_DATA1              ; 70dd C_DATA1              ; 71dd C_DATA1              ; 72dd C_DATA1              ; 73dd C_DATA1              ; 74dd C_DATA1              ; 75dd C_DATA1              ; 76dd C_DATA1              ; 77dd C_DATA1              ; 78dd C_DATA1              ; 79dd C_DATA1              ; 7Add C_DATA1              ; 7Bdd C_DATA1              ; 7Cdd C_DATA1              ; 7Ddd C_DATA1              ; 7Edd C_DATA1              ; 7Fdd C_MODRM+C_DATA1      ; 80dd C_MODRM+C_DATA66     ; 81dd C_MODRM+C_DATA1      ; 82dd C_MODRM+C_DATA1      ; 83dd C_MODRM              ; 84dd C_MODRM              ; 85dd C_MODRM              ; 86dd C_MODRM              ; 87dd C_MODRM              ; 88dd C_MODRM              ; 89dd C_MODRM              ; 8Add C_MODRM              ; 8Bdd C_MODRM              ; 8Cdd C_MODRM              ; 8Ddd C_MODRM              ; 8Edd C_MODRM              ; 8Fdd 0                    ; 90dd 0                    ; 91dd 0                    ; 92dd 0                    ; 93dd 0                    ; 94dd 0                    ; 95dd 0                    ; 96dd 0                    ; 97dd 0                    ; 98dd 0                    ; 99dd C_DATA66+C_MEM2      ; 9Add 0                    ; 9Bdd 0                    ; 9Cdd 0                    ; 9Ddd 0                    ; 9Edd 0                    ; 9Fdd C_MEM67              ; A0dd C_MEM67              ; A1dd C_MEM67              ; A2dd C_MEM67              ; A3dd 0                    ; A4dd 0                    ; A5dd 0                    ; A6dd 0                    ; A7dd C_DATA1              ; A8dd C_DATA66             ; A9dd 0                    ; AAdd 0                    ; ABdd 0                    ; ACdd 0                    ; ADdd 0                    ; AEdd 0                    ; AFdd C_DATA1              ; B0dd C_DATA1              ; B1dd C_DATA1              ; B2dd C_DATA1              ; B3dd C_DATA1              ; B4dd C_DATA1              ; B5dd C_DATA1              ; B6dd C_DATA1              ; B7dd C_DATA66             ; B8dd C_DATA66             ; B9dd C_DATA66             ; BAdd C_DATA66             ; BBdd C_DATA66             ; BCdd C_DATA66             ; BDdd C_DATA66             ; BEdd C_DATA66             ; BFdd C_MODRM+C_DATA1      ; C0dd C_MODRM+C_DATA1      ; C1dd C_DATA2              ; C2dd 0                    ; C3dd C_MODRM              ; C4dd C_MODRM              ; C5dd C_MODRM+C_DATA1      ; C6dd C_MODRM+C_DATA66     ; C7dd C_DATA2+C_DATA1      ; C8dd 0                    ; C9dd C_DATA2              ; CAdd 0                    ; CBdd 0                    ; CCdd 0                    ; CDdd 0                    ; CEdd 0                    ; CFdd C_MODRM              ; D0dd C_MODRM              ; D1dd C_MODRM              ; D2dd C_MODRM              ; D3dd C_DATA1              ; D4dd C_DATA1              ; D5dd 0                    ; D6dd 0                    ; D7dd C_MODRM              ; D8dd C_MODRM              ; D9dd C_MODRM              ; DAdd C_MODRM              ; DBdd C_MODRM              ; DCdd C_MODRM              ; DDdd C_MODRM              ; DEdd C_MODRM              ; DFdd C_DATA1              ; E0dd C_DATA1              ; E1dd C_DATA1              ; E2dd C_DATA1              ; E3dd C_DATA1              ; E4dd C_DATA1              ; E5dd C_DATA1              ; E6dd C_DATA1              ; E7dd C_DATA66             ; E8dd C_DATA66             ; E9dd C_DATA66+C_MEM2      ; EAdd C_DATA1              ; EBdd 0                    ; ECdd 0                    ; EDdd 0                    ; EEdd 0                    ; EFdd C_PREFIX             ; F0dd 0                    ; F1dd C_PREFIX             ; F2dd C_PREFIX             ; F3dd 0                    ; F4dd 0                    ; F5dd 0                    ; F6dd 0                    ; F7dd 0                    ; F8dd 0                    ; F9dd 0                    ; FAdd 0                    ; FBdd 0                    ; FCdd 0                    ; FDdd C_MODRM              ; FEdd C_MODRM              ; FF

    table_0F                label   dword   ; 0F为前缀的指令

    dd C_MODRM              ; 00dd C_MODRM              ; 01dd C_MODRM              ; 02dd C_MODRM              ; 03dd -1                   ; 04dd -1                   ; 05dd 0                    ; 06dd -1                   ; 07dd 0                    ; 08dd 0                    ; 09dd 0                    ; 0Add 0                    ; 0Bdd -1                   ; 0Cdd -1                   ; 0Ddd -1                   ; 0Edd -1                   ; 0Fdd -1                   ; 10dd -1                   ; 11dd -1                   ; 12dd -1                   ; 13dd -1                   ; 14dd -1                   ; 15dd -1                   ; 16dd -1                   ; 17dd -1                   ; 18dd -1                   ; 19dd -1                   ; 1Add -1                   ; 1Bdd -1                   ; 1Cdd -1                   ; 1Ddd -1                   ; 1Edd -1                   ; 1Fdd -1                   ; 20dd -1                   ; 21dd -1                   ; 22dd -1                   ; 23dd -1                   ; 24dd -1                   ; 25dd -1                   ; 26dd -1                   ; 27dd -1                   ; 28dd -1                   ; 29dd -1                   ; 2Add -1                   ; 2Bdd -1                   ; 2Cdd -1                   ; 2Ddd -1                   ; 2Edd -1                   ; 2Fdd -1                   ; 30dd -1                   ; 31dd -1                   ; 32dd -1                   ; 33dd -1                   ; 34dd -1                   ; 35dd -1                   ; 36dd -1                   ; 37dd -1                   ; 38dd -1                   ; 39dd -1                   ; 3Add -1                   ; 3Bdd -1                   ; 3Cdd -1                   ; 3Ddd -1                   ; 3Edd -1                   ; 3Fdd -1                   ; 40dd -1                   ; 41dd -1                   ; 42dd -1                   ; 43dd -1                   ; 44dd -1                   ; 45dd -1                   ; 46dd -1                   ; 47dd -1                   ; 48dd -1                   ; 49dd -1                   ; 4Add -1                   ; 4Bdd -1                   ; 4Cdd -1                   ; 4Ddd -1                   ; 4Edd -1                   ; 4Fdd -1                   ; 50dd -1                   ; 51dd -1                   ; 52dd -1                   ; 53dd -1                   ; 54dd -1                   ; 55dd -1                   ; 56dd -1                   ; 57dd -1                   ; 58dd -1                   ; 59dd -1                   ; 5Add -1                   ; 5Bdd -1                   ; 5Cdd -1                   ; 5Ddd -1                   ; 5Edd -1                   ; 5Fdd -1                   ; 60dd -1                   ; 61dd -1                   ; 62dd -1                   ; 63dd -1                   ; 64dd -1                   ; 65dd -1                   ; 66dd -1                   ; 67dd -1                   ; 68dd -1                   ; 69dd -1                   ; 6Add -1                   ; 6Bdd -1                   ; 6Cdd -1                   ; 6Ddd -1                   ; 6Edd -1                   ; 6Fdd -1                   ; 70dd -1                   ; 71dd -1                   ; 72dd -1                   ; 73dd -1                   ; 74dd -1                   ; 75dd -1                   ; 76dd -1                   ; 77dd -1                   ; 78dd -1                   ; 79dd -1                   ; 7Add -1                   ; 7Bdd -1                   ; 7Cdd -1                   ; 7Ddd -1                   ; 7Edd -1                   ; 7Fdd C_DATA66             ; 80dd C_DATA66             ; 81dd C_DATA66             ; 82dd C_DATA66             ; 83dd C_DATA66             ; 84dd C_DATA66             ; 85dd C_DATA66             ; 86dd C_DATA66             ; 87dd C_DATA66             ; 88dd C_DATA66             ; 89dd C_DATA66             ; 8Add C_DATA66             ; 8Bdd C_DATA66             ; 8Cdd C_DATA66             ; 8Ddd C_DATA66             ; 8Edd C_DATA66             ; 8Fdd C_MODRM              ; 90dd C_MODRM              ; 91dd C_MODRM              ; 92dd C_MODRM              ; 93dd C_MODRM              ; 94dd C_MODRM              ; 95dd C_MODRM              ; 96dd C_MODRM              ; 97dd C_MODRM              ; 98dd C_MODRM              ; 99dd C_MODRM              ; 9Add C_MODRM              ; 9Bdd C_MODRM              ; 9Cdd C_MODRM              ; 9Ddd C_MODRM              ; 9Edd C_MODRM              ; 9Fdd 0                    ; A0dd 0                    ; A1dd 0                    ; A2dd C_MODRM              ; A3dd C_MODRM+C_DATA1      ; A4dd C_MODRM              ; A5dd -1                   ; A6dd -1                   ; A7dd 0                    ; A8dd 0                    ; A9dd 0                    ; AAdd C_MODRM              ; ABdd C_MODRM+C_DATA1      ; ACdd C_MODRM              ; ADdd -1                   ; AEdd C_MODRM              ; AFdd C_MODRM              ; B0dd C_MODRM              ; B1dd C_MODRM              ; B2dd C_MODRM              ; B3dd C_MODRM              ; B4dd C_MODRM              ; B5dd C_MODRM              ; B6dd C_MODRM              ; B7dd -1                   ; B8dd -1                   ; B9dd C_MODRM+C_DATA1      ; BAdd C_MODRM              ; BBdd C_MODRM              ; BCdd C_MODRM              ; BDdd C_MODRM              ; BEdd C_MODRM              ; BFdd C_MODRM              ; C0dd C_MODRM              ; C1dd -1                   ; C2dd -1                   ; C3dd -1                   ; C4dd -1                   ; C5dd -1                   ; C6dd -1                   ; C7dd 0                    ; C8dd 0                    ; C9dd 0                    ; CAdd 0                    ; CBdd 0                    ; CCdd 0                    ; CDdd 0                    ; CEdd 0                    ; CFdd -1                   ; D0dd -1                   ; D1dd -1                   ; D2dd -1                   ; D3dd -1                   ; D4dd -1                   ; D5dd -1                   ; D6dd -1                   ; D7dd -1                   ; D8dd -1                   ; D9dd -1                   ; DAdd -1                   ; DBdd -1                   ; DCdd -1                   ; DDdd -1                   ; DEdd -1                   ; DFdd -1                   ; E0dd -1                   ; E1dd -1                   ; E2dd -1                   ; E3dd -1                   ; E4dd -1                   ; E5dd -1                   ; E6dd -1                   ; E7dd -1                   ; E8dd -1                   ; E9dd -1                   ; EAdd -1                   ; EBdd -1                   ; ECdd -1                   ; EDdd -1                   ; EEdd -1                   ; EFdd -1                   ; F0dd -1                   ; F1dd -1                   ; F2dd -1                   ; F3dd -1                   ; F4dd -1                   ; F5dd -1                   ; F6dd -1                   ; F7dd -1                   ; F8dd -1                   ; F9dd -1                   ; FAdd -1                   ; FBdd -1                   ; FCdd -1                   ; FDdd -1                   ; FEdd -1                   ; FF

                            end

        现在我们可以获取任意地址的指令长度。我们重复调用这个函数直到读取了5个字节。完成后把这些字节拷贝到old_hook。我们知道了开始这些指令的长度,所以我们可以在原始函数的下条指令填入跳转地址。

    .386p.model flat, stdcall

    ...

    .data

    kernel_name         db "kernel32.dll",0sleep_name        db "Sleep",0

    ...

    MEM_RELEASE        dd 000008000h

    ;16 nops + 一个跳转指令old_sleep        db 090h,090h,090h,090h,090h,090h,090h,090h,               090h,090h,090h,090h,090h,090h,090h,090h,               0E9h,000h,000h,000h,000h

     


    最新回复(0)