Trao đổi với tôi

http://www.buidao.com

5/24/16

[Hooking], Hooking Windows API



[ Hooking Windows API ]

                 Technics of hooking API functions on Windows
                 --------------------------------------------

                       Author:  Holy_Father
                       Version: 1.1 english
                       Date:    6.10.2002


=====[ 1. Contents ]============================================================

1. Contents
2. Introduction
3. Hooking methods
  3.1 Hooking before running
  3.2 Hooking during running
    3.2.1 Own process hooking using IAT
    3.2.2 Own process hooking using entry point rewriting
    3.2.3 Original function saving
    3.2.4 Other process hooking
      3.2.4.1 DLL Injection
      3.2.4.2 Independent code
      3.2.4.3 Raw change
4. Ending


=====[ 2. Introduction ]========================================================

        Đây là bài viết về hooking API functions trên OS Windows. Tất cả các ví dụ
ở đây làm việc hòan tòan trên Windows systems based on NT technology version NT 4.0
and higher (Windows NT 4.0, Windows 2000, Windows XP). Có lẽ cũng sẽ làm việc trên
các Windows systems khác.
        Bạn đã rất thân thuộc với các processes trên Windows, assembler, PE files
structure và vài API functions để hiểu tòan bộ bài viết này.
        Khi sử dụng điều khỏan "Hooking API" ở đây, tôi chỉ có ý là thay đổi đầy đủ API.
Vì vậy, khi calling hooked API, code của chúng ta được chạy ngay lập tức. Tôi ko đề cập đến các
cases of chỉ giám sát API. Tôi sẽ viết về hooking hòa tòan.


=====[ 3. Hooking methods ]=====================================================

        Đích của chúng ta nói chung là thay thế code of vài function với code của
chúng ta. Vấn đề này có thể đôi khi được giải quyết trước khi running process. Điều này
có thể được thực hiện hầu hết với các process lớp user mà chúng được run bởi chúng ta và đích cuối nghĩa là
thay đổi hành vi của chương trình. Ví dụ điều này là có thể ứng dụng trong crack.
Nghĩa là chương trình mà nó muốn đĩa CD-ROM gốc trong suốt quá trình startup (điều này trong game
Atlantis) và chúng ta muốn run nó mà ko cần CDs. Nếu chúng ta thay đổi function cho
việc lấy một drive type chúng ta sẽ có thể run chương trình này từ hard drive.
        Điều này ko thể làm được hay chúng ta ko muốn làm điều này khi muốn hook
system process (e.g. services) hay trong cas chúng ta ko biết process nào sẽ  
là target. Thì chúng ta sẽ sử dụng kỹ thuật hooking suốt quá trình running . Ví dụ sử dụng
điều này có thể là rootkit hay virus với các kỹ thuật anti-antivirus.


=====[ 3.1 Hooking before running ]=============================================

        Đây là về thay đổi physical module (hầu hét là .exe hay .dll) khi
function, mà chúng ta muốn thay đổi. Chúng ta phải có ít nhất 3 khả năng ở đây
đề làm được điều này.
        Trước tiên là tìm entry point of function đó và về cơ bản là
rewrite code của nó. Điều này bị giới hạn bởi function size nhưng chúng ta có thể load vài
modules khác một cách động dynamically (API LoadLibrary), vì vậy nó có thể đủ.
        Kernel functions (kernel32.dll) có thể được sử dụng trong tất cả các cas vì
mỗi process trong windows có chính bản copy module này của nó. Thuận lợi khác
là nếu chúng ta biết OS nào sẽ bị thay đổi module run. Chúng ta có thể sử dụng các con trỏ
trực tiếp trong cas này có nghĩa là API LoadLibraryA. Điều này như thế vì address
of kernel module trong memory là tỉnh trong phạm vi một OS Windows version.
Chúng ta cũng có thể sử dụng hành vi của module được load động. Trong cas này phần khởi trị đầu
của nó được run ngay lập tức sau khi loading vào memory. Chúng ta ko bị giới hạn
trong phần khởi trị đầu của module mới.
        Khả năng thứ hai của việc thay thế hàm trong module là phần mở rộng của nó.
Thì chúng ta phải chọn giữa 5 bytes đầu tiên bởi relative jump
hay rewriting IAT. Trong trường hợp relative jump, điều này sẽ redirect (chuyển tiếp) code
thực thi đến code của chúng ta. Khi calling function mà IAT record của chúng bị thay đổi,
code của chúng ta sẽ bị thực thi một cách trực tiếp sau call này. Nhưng phần mở rộng của module
vì vậy ko dễ dàng vì chúng ta phải bảo quản DLL header.
        Khả năng kế tiếp là thay thế tòan module. Đìều đó có nghĩa là chúng ta cài đặt
version of của chính module mà chúng có thể load cái module gốc và call các original
functions mà chúng ta ko quan tâm đến. Nhưng các hàm quan trọng sẽ hòan tòan mới
Phương pháp này ko tốt lắm vì các modules lớn mà chúng có thể chứa hàm trăm
các exports.


=====[ 3.2 Hooking during running ]=============================================

        Hooking before running hầu như rất đặc biệt và định hướng một cách thân thiện
cho các khối ứng dụng (hay module). Nếu chúng ta thay thế hàm trong kernel32.dll
hay trong ntdll.dll (chỉ trên NT OS) thì chúng ta sẽ có được sự thay thế hòan hảo hàm này
trong tất cả các processes mà chúng được run sau đó, nhưng nó cũng khó để làm được nó
vì chúng ta phải lấy cẩn thận về độ chính xác và code chính of các
functions mới hay cả modules mới, nhưng vấn đề chính chỉ process
mà nó được run sau sẽ bị hooked (vậy với tất cả các process thì chúng ta phải reboot
system). Vấn đề kế tiếp là có thể truy xuất các files này bởi vì NT OS cố bảo vệ chúng.
Quá nhiều cách giải quyết tuyệt vời cho việc hook process suốt quá trịnh running. PP này  
yêu cầu nhiều kiến thức nhưng kết quả thì rất hòan hảo. Hooking during running
có thể chỉ được thực hiện trên process mà với chúng chúng ta viết truy xuất đến memory của chúng.
Đối với việc viết vào chính nó chúng ta sẽ sử dụng API function WriteProcessMemory. Chúng ta sẽ
bắt đầu từ việc hooking process của chính chúng ta trong suốt quá trình running.


=====[ 3.2.1 Own process hooking using IAT ]====================================

        Có nhiều khả năng ở đây. Trước tiên tôi sẽ chỉ cho bạn như thế nào để hook
function bằng cách rewriting IAT (viết lại IAT). Following picture shows structure of PE file:

     +-------------------------------+     - offset 0
     | MS DOS Header ("MZ") and stub |
     +-------------------------------+    
     |      PE signature ("PE")      |
     +-------------------------------+
     |             .text             |     - module code
     |         Program Code          |
     |                               |
     +-------------------------------+
     |             .data             |     - initialized (global static) data
     |        Initialized Data       |
     |                               |
     +-------------------------------+
     |            .idata             |     - information for imported functions
     |         Import Table          |       and data
     |                               |
     +-------------------------------+
     |            .edata             |     - information for exported functions
     |         Export Table          |       and data
     |                               |
     +-------------------------------+
     |         Debug symbols         |
     +-------------------------------+

        Phần quan trọng đối với chúng ta ở đây là Import Address Table (IAT) trong .idata
part. Phần này chứa các mô tả của các imports và phần lớn các imported functions
addresses. Bây giờ quan trọng để biết các PE files created như thế nào. Khi calling
bất kỳ API một cách gián tiếp trong programming language (điều đó có ý nghĩa là chúng ta call nó sử dụng  
tên của nó, ko phải sử dụng địa chỉ riêng OS của nó) thì compiler ko link trực tiếp các
calls đến module nhưng nó links call đến IAT trên chỉ thị jmp mà chúng sẽ được
filled bởi process loader khi OS được loading process vào memory. Điều này là tại sao
chúng ta có thể sử dụng binary giống như vậy trên 2 version khác nhau của Windows mà ở đó các modules
có thể được loaded vào các addresses khác nhau. Process loader sẽ lấp ra fill out chỉ thị direct jmp
trong IAT mà chúng được sử dụng bởi các calls của chúng ta từ program code. Vì vậy,
nếu chúng ta có thể tìm ra function đặc trưng trong IAT mà chúng a muốn hook chúng,
chúng ta có thể dễ dàng thay đổi chỉ thị jmp ở đó và redirect (chuyển tiếp) code đến address của chúng ta.
Mọi call sau đó thực thi hàm này sẽ thực thi code của chúng ta. Tiện ích của pp này
là sự hòan chỉnh của nó. Bát tiện là thông thường phần lớn các functions mà nó được
hooked (e.g. nếu chúng ta muốn thay đổ hành vi chương trình trong file searching APIs
thì chúng ta sẽ phải thay đổi các functions FindFirstFile và FindNextFile, nhưng chúng ta phải
biết rằng các functions này có ANSI và WIDE version của nó, vì vậy chúng ta phải thay đổi  
IAT address cho FindFirstFileA, FindFirstFileW, FindNextFileA và cũng như  
FileNextFileW. Nhưng vẫn có vài hàm khác giống như FindFirstFileExA và WIDE
version của nó FindFirstFileExW mà chúng được gọi bởi các hàm đã nói đến trước đó.
Chúng ta biết rằng FindFirstFileW calls FindFirstFileExW nhưng điều này được thực hiện một cách trực tíep
- ko sử dụng IAT. Và vẫn vài cách khác để thực hiện. Đó là e.g. ShellAPI
functions giống như SHGetDesktopFolder mà chúng cũng calls FindFirstFileW một cách trực tiếp hay  
FindFirstFileExW). Nhưng nếu chúng ta có tất cả chúng, result sẽ rất hòan hảo.
        Chúng ta có thể sử dụng ImageDirectoryEntryToData từ imagehlp.dll để tìm ra IAT
một cách dễ dàng.

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

Chúng ta sẽ sử dụng Instance of ứng dụng của chúng ta như là Base (Instance có thể có được bằng cách calling
GetModuleHandle:

        hInstance = GetModuleHandleA(NULL);

), và như DirectoryEntry chúng at sẽ sử dụng hằng số IMAGE_DIRECTORY_ENTRY_IMPORT.

        #define IMAGE_DIRECTORY_ENTRY_IMPORT 1

Result của hàm này là pointer trỏ đến IAT record đầu tiên. IAT records là cấu trúc
structures mà nó được định nghĩa bởi I IMAGE_IMPORT_DESCRIPTOR. Vậy, result
là một pointer trên 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;

        Giá trị Name trong IMAGE_IMPORT_DESCRIPTOR là một tham chiếu tương ứng với
name of module. Nếu chúng ta muốn hook một function e.g. từ kernel32.dll
chúng ta phải tìm ra trong imports mà nó phụ thuộc vào descriptor với name là
kernel32.dll. Chúng ta sẽ call ImageDirectoryEntryToData tại lúc bắt đầu và rồi chúng ta sẽ thử
tìm descriptor với name "kernel32.dll" (ở đó có thể nhiều hơn 1
descriptor với name này). Cuối cùng chúng ta sẽ phải tìm ra function của chúng ta trong  
danh sách tất cả các functions trong record (address of function của chúng ta có thể có được
bởi hàm GetProcAddress function). Nếu chúng ta tìm nó chúng ta phải sử dụng VirtualProtect để thay đổi
memory page protection và sau đó thì chúng ta có thể write phần này của memory.
Sau khi rewriting address chúng ta phải thay đổi protection trở lại. Trước khi
calling VirtualProtect chúng ta phải biết vài thông tin về memory page này.
Điều này được làm nởi VirtualQuery. Chúng ta có thể thêm vài tests trong cas vài calls sẽ bị
fail (e.g. chúng ta ko tiếp tục nếu VirtualProtect call đầu tiên bị failed, etc)>

        PCSTR pszHookModName = "kernel32.dll",pszSleepName = "Sleep";
        HMODULE hKernel = GetModuleHandle(pszHookModName);
        PROC pfnNew = (PROC)0x12345678,       //new address will be here
               pfnHookAPIAddr = GetProcAddress(hKernel,pszSleepName);

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

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

        PIMAGE_THUNK_DATA pThunk =
        (PIMAGE_THUNK_DATA)((PBYTE) hInstance + 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++;
        }

Result of calling Sleep(1000) có thể cho ví dụ này:

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

        Sleep:     ;this is jump on address in IAT
        004075F4: FF25BCA14000 jmp dword ptr [00040A1BCh]

        original table:
        0040A1BC: 79 67 E8 77 00 00 00 00
     
        new table:
        0040A1BC: 78 56 34 12 00 00 00 00

Vì vậy jump cuối cùng là 0x12345678.
         

=====[ 3.2.2 Own process hooking using entry point rewriting ]==================

        PP rewriting vài chỉ thị đầu tiên trên function entry
point rất đơn giản. Như trong cas rewritng address trong IAT mà chúng ta phải
thay đổi page protection lúc đầu tiên. Ở đây nó sẽ là 5 bytes đầu tiên of hàm đã cho
mà chúng ta muốn hook chúng. Để tiền dùng sau này chúng ta sẽ sử dụng cấp phát động
cấu trúc MEMORY_BASIC_INFORMATION structure. Điểm bắt đầu hàm có được bởi gọi hàm  
GetProcAddress một lần nữa. Trên addr này chúng ta sẽ insert relative jump đến  
code của chúng ta. Chương trình sau đây calls Sleep(5000) (vì vậy nó sẽ chờ 5 seconds), rồi
Sleep functions bị hooked và redirected chuyển tiếp đến new_sleep, cuối cùng nó call
Sleep(5000) một lần nữa. Bởi vì new function new_sleep ko làm gì và trả về returns
ngay lập tức nguyên chương trình sẽ mất chỉ 5 trong 10 seconds.


.386p
.model flat, stdcall

includelib lib\kernel32.lib
Sleep                  PROTO :DWORD
GetModuleHandleA       PROTO :DWORD
GetProcAddress         PROTO :DWORD,:DWORD
VirtualQuery           PROTO :DWORD,:DWORD,:DWORD
VirtualProtect         PROTO :DWORD,:DWORD,:DWORD,:DWORD
VirtualAlloc           PROTO :DWORD,:DWORD,:DWORD,:DWORD
VirtualFree            PROTO :DWORD,:DWORD,:DWORD
FlushInstructionCache  PROTO :DWORD,:DWORD,:DWORD
GetCurrentProcess      PROTO
ExitProcess            PROTO :DWORD


.data

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

 MEMORY_BASIC_INFORMATION_SIZE equ 28

 PAGE_READWRITE        dd 000000004h
 PAGE_EXECUTE_READWRITE dd 000000040h
 MEM_COMMIT            dd 000001000h
 MEM_RELEASE           dd 000008000h


.code
start:
        push    5000
        call    Sleep

 do_hook:
        push    offset kernel_name
        call    GetModuleHandleA
        push    offset sleep_name
        push    eax
        call    GetProcAddress
        mov     edi,eax                ;finally got Sleep address

        push    PAGE_READWRITE
        push    MEM_COMMIT
        push    MEMORY_BASIC_INFORMATION_SIZE
        push    0
        call    VirtualAlloc
        test    eax,eax
        jz      do_sleep
        mov     esi,eax                ;alocation for MBI

        push    MEMORY_BASIC_INFORMATION_SIZE
        push    esi
        push    edi
        call    VirtualQuery           ;inforamtion about the memory page
        test    eax,eax
        jz      free_mem

        call    GetCurrentProcess
        push    5
        push    edi
        push    eax
        call    FlushInstructionCache  ;just to be sure :)

        lea     eax,[esi+014h]
        push    eax
        push    PAGE_EXECUTE_READWRITE
        lea     eax,[esi+00Ch]
        push    [eax]
        push    [esi]
        call    VirtualProtect          ;we will change protection for a moment
                                      ;so we will be able to write there
        test    eax,eax
        jz      free_mem              

        mov     byte ptr [edi],0E9h    ;to write relative jump
        mov     eax,offset new_sleep
        sub     eax,edi
        sub     eax,5
        inc     edi
        stosd                          ;this is relative address for jump

        push    offset old_protect
        lea     eax,[esi+014h]
        push    [eax]
        lea     eax,[esi+00Ch]
        push    [eax]
        push    [esi]
        call    VirtualProtect         ;return back the protection of page

 free_mem:
        push    MEM_RELEASE
        push    0
        push    esi
        call    VirtualFree            ;free memory
 do_sleep:
        push    5000
        call    Sleep
        push    0
        call    ExitProcess
 new_sleep:                          
        ret     004h
end start


Result of call Sleep thứ hai là như vầy:

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


        Sleep:     ;toto je jump na adresu v 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 Original function saving ]=========================================

        Hầu như chúng ta cần hơn hook một hàm. Cho ví dụ, trong cas khi chúng ta
ko muốn replace hàm đã cho nhưng chỉ check result của nó, hay trong cas khi
chúng ta chỉ muốn đôi khi replace function e.g. khi nó được called với các đối số
đặc biệt. Ví dụ good về điều này là các files thật sự đã nói trước đó hiding
được làm bởi replacing FindXXXFile functions. Vì vậy nếu chúng ta muốn hide các file đặc trưng
và ko muốn thông báo thì chúng ta phải bỏ original function cho tất cả các file
khác mà ko cần thay đổi hành vi của các hàm. Điều này đon giản khi sử dụng pp
rewriting IAT. Đói với việc calling original function chúng ta có thể có original
address của nó với việc gọi hàm GetProcAddress và rồi gọi nó một cách trực tiếp. Nhưng vấn đề xảy ra  
khi sử dụng rewriting entry point method. Bởi rewriting 5 bytes này tại
functions entry point chúng ta mất original function mà ko thể thu hồi được. Vì vậy chúng ta cần
save các instructions đầu tiên. Chúng ta có thể sử dụng kỹ thuật sau.
        Chúng ta biết rằng chúng ta sẽ chỉ rewrite 5 bytes đầu tiên nhưng ko biết bao nhiêu
chỉ thị ở đó hay chúng dài bao nhiêu bytes. Chúng ta phải để dành đủ memory
cho các chỉ thị đầu tien. 16 bytes có thể là đủ bởi vì thường ko có
các chỉ thị dài tại lúc bắt đầu hà. Có lẽ chúng ta sử dụng ít hơn 16.
Tòan bộ vùng memory để dành được lấp với giá trị 0x90 (0x90 = nop) trong case có các
chỉ thị ngắn hơn.Kế đến 5bytes sẽ là relative jump mà nó sẽ được láp sau.

 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


        Bây giờ chúng ta sẳn sàng copy các chỉ thị đầu tiên. Nó là một stuff dài để có
chiều dài của instruction, điều này là tại sao chúng ta sẽ làm việc với một engine hòan chỉnh. Engine này
được làm bởi Z0MBiE. Nhập Input đói số vào là instruction address mà chúng ta muốn lấy chiều dài
của chúng. Output thông thường trong 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 simultaneously
C_MEM4                  equ     0004h       ; |
C_DATA1                 equ     0100h       ; |
C_DATA2                 equ     0200h       ; |may be used simultaneously
C_DATA4                 equ     0400h       ; |
C_67                    equ     0010h       ; used with C_PREFIX
C_MEM67                 equ     0020h       ; C_67 ? C_MEM2 : C_MEM4
C_66                    equ     1000h       ; used with C_PREFIX
C_DATA66                equ     2000h       ; C_66 ? C_DATA2 : C_DATA4
C_PREFIX                equ     0008h       ; prefix. take opcode again
C_MODRM                 equ     4000h       ; MODxxxR/M
C_DATAW0                equ     8000h       ; opc&1 ? C_DATA66 : C_DATA1

                        p386
                        model   flat
                        locals  @@

                        .code

public                  disasm_main
public                  _disasm_main
public                  @disasm_main
public                  DISASM_MAIN

disasm_main:
_disasm_main:
@disasm_main:
DISASM_MAIN:

; returns opcode length in EAX or -1 if error

; input: pointer to opcode

; __fastcall            EAX
; __cdecl               [ESP+4]

;this is my first change here, it's the label only for calling this function
get_instr_len:

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

                        xor     edx, edx        ; flags
                        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

;my second change heer, there was retn only in original version
@@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      -- analyzed in code, no flags (i.e.flags must be 0)
;F6,F7   -- --//-- (ttt=000 -- 3 bytes, otherwise 2 bytes)
;CD      -- --//-- (6 bytes if CD 20, 2 bytes otherwise)

table_1                 label   dword   ; normal instructions

dd C_MODRM              ; 00
dd C_MODRM              ; 01
dd C_MODRM              ; 02
dd C_MODRM              ; 03
dd C_DATAW0             ; 04
dd C_DATAW0             ; 05
dd 0                    ; 06
dd 0                    ; 07
dd C_MODRM              ; 08
dd C_MODRM              ; 09
dd C_MODRM              ; 0A
dd C_MODRM              ; 0B
dd C_DATAW0             ; 0C
dd C_DATAW0             ; 0D
dd 0                    ; 0E
dd 0                    ; 0F
dd C_MODRM              ; 10
dd C_MODRM              ; 11
dd C_MODRM              ; 12
dd C_MODRM              ; 13
dd C_DATAW0             ; 14
dd C_DATAW0             ; 15
dd 0                    ; 16
dd 0                    ; 17
dd C_MODRM              ; 18
dd C_MODRM              ; 19
dd C_MODRM              ; 1A
dd C_MODRM              ; 1B
dd C_DATAW0             ; 1C
dd C_DATAW0             ; 1D
dd 0                    ; 1E
dd 0                    ; 1F
dd C_MODRM              ; 20
dd C_MODRM              ; 21
dd C_MODRM              ; 22
dd C_MODRM              ; 23
dd C_DATAW0             ; 24
dd C_DATAW0             ; 25
dd C_PREFIX             ; 26
dd 0                    ; 27
dd C_MODRM              ; 28
dd C_MODRM              ; 29
dd C_MODRM              ; 2A
dd C_MODRM              ; 2B
dd C_DATAW0             ; 2C
dd C_DATAW0             ; 2D
dd C_PREFIX             ; 2E
dd 0                    ; 2F
dd C_MODRM              ; 30
dd C_MODRM              ; 31
dd C_MODRM              ; 32
dd C_MODRM              ; 33
dd C_DATAW0             ; 34
dd C_DATAW0             ; 35
dd C_PREFIX             ; 36
dd 0                    ; 37
dd C_MODRM              ; 38
dd C_MODRM              ; 39
dd C_MODRM              ; 3A
dd C_MODRM              ; 3B
dd C_DATAW0             ; 3C
dd C_DATAW0             ; 3D
dd C_PREFIX             ; 3E
dd 0                    ; 3F
dd 0                    ; 40
dd 0                    ; 41
dd 0                    ; 42
dd 0                    ; 43
dd 0                    ; 44
dd 0                    ; 45
dd 0                    ; 46
dd 0                    ; 47
dd 0                    ; 48
dd 0                    ; 49
dd 0                    ; 4A
dd 0                    ; 4B
dd 0                    ; 4C
dd 0                    ; 4D
dd 0                    ; 4E
dd 0                    ; 4F
dd 0                    ; 50
dd 0                    ; 51
dd 0                    ; 52
dd 0                    ; 53
dd 0                    ; 54
dd 0                    ; 55
dd 0                    ; 56
dd 0                    ; 57
dd 0                    ; 58
dd 0                    ; 59
dd 0                    ; 5A
dd 0                    ; 5B
dd 0                    ; 5C
dd 0                    ; 5D
dd 0                    ; 5E
dd 0                    ; 5F
dd 0                    ; 60
dd 0                    ; 61
dd C_MODRM              ; 62
dd C_MODRM              ; 63
dd C_PREFIX             ; 64
dd C_PREFIX             ; 65
dd C_PREFIX+C_66        ; 66
dd C_PREFIX+C_67        ; 67
dd C_DATA66             ; 68
dd C_MODRM+C_DATA66     ; 69
dd C_DATA1              ; 6A
dd C_MODRM+C_DATA1      ; 6B
dd 0                    ; 6C
dd 0                    ; 6D
dd 0                    ; 6E
dd 0                    ; 6F
dd C_DATA1              ; 70
dd C_DATA1              ; 71
dd C_DATA1              ; 72
dd C_DATA1              ; 73
dd C_DATA1              ; 74
dd C_DATA1              ; 75
dd C_DATA1              ; 76
dd C_DATA1              ; 77
dd C_DATA1              ; 78
dd C_DATA1              ; 79
dd C_DATA1              ; 7A
dd C_DATA1              ; 7B
dd C_DATA1              ; 7C
dd C_DATA1              ; 7D
dd C_DATA1              ; 7E
dd C_DATA1              ; 7F
dd C_MODRM+C_DATA1      ; 80
dd C_MODRM+C_DATA66     ; 81
dd C_MODRM+C_DATA1      ; 82
dd C_MODRM+C_DATA1      ; 83
dd C_MODRM              ; 84
dd C_MODRM              ; 85
dd C_MODRM              ; 86
dd C_MODRM              ; 87
dd C_MODRM              ; 88
dd C_MODRM              ; 89
dd C_MODRM              ; 8A
dd C_MODRM              ; 8B
dd C_MODRM              ; 8C
dd C_MODRM              ; 8D
dd C_MODRM              ; 8E
dd C_MODRM              ; 8F
dd 0                    ; 90
dd 0                    ; 91
dd 0                    ; 92
dd 0                    ; 93
dd 0                    ; 94
dd 0                    ; 95
dd 0                    ; 96
dd 0                    ; 97
dd 0                    ; 98
dd 0                    ; 99
dd C_DATA66+C_MEM2      ; 9A
dd 0                    ; 9B
dd 0                    ; 9C
dd 0                    ; 9D
dd 0                    ; 9E
dd 0                    ; 9F
dd C_MEM67              ; A0
dd C_MEM67              ; A1
dd C_MEM67              ; A2
dd C_MEM67              ; A3
dd 0                    ; A4
dd 0                    ; A5
dd 0                    ; A6
dd 0                    ; A7
dd C_DATA1              ; A8
dd C_DATA66             ; A9
dd 0                    ; AA
dd 0                    ; AB
dd 0                    ; AC
dd 0                    ; AD
dd 0                    ; AE
dd 0                    ; AF
dd C_DATA1              ; B0
dd C_DATA1              ; B1
dd C_DATA1              ; B2
dd C_DATA1              ; B3
dd C_DATA1              ; B4
dd C_DATA1              ; B5
dd C_DATA1              ; B6
dd C_DATA1              ; B7
dd C_DATA66             ; B8
dd C_DATA66             ; B9
dd C_DATA66             ; BA
dd C_DATA66             ; BB
dd C_DATA66             ; BC
dd C_DATA66             ; BD
dd C_DATA66             ; BE
dd C_DATA66             ; BF
dd C_MODRM+C_DATA1      ; C0
dd C_MODRM+C_DATA1      ; C1
dd C_DATA2              ; C2
dd 0                    ; C3
dd C_MODRM              ; C4
dd C_MODRM              ; C5
dd C_MODRM+C_DATA1      ; C6
dd C_MODRM+C_DATA66     ; C7
dd C_DATA2+C_DATA1      ; C8
dd 0                    ; C9
dd C_DATA2              ; CA
dd 0                    ; CB
dd 0                    ; CC
dd 0                    ; CD
dd 0                    ; CE
dd 0                    ; CF
dd C_MODRM              ; D0
dd C_MODRM              ; D1
dd C_MODRM              ; D2
dd C_MODRM              ; D3
dd C_DATA1              ; D4
dd C_DATA1              ; D5
dd 0                    ; D6
dd 0                    ; D7
dd C_MODRM              ; D8
dd C_MODRM              ; D9
dd C_MODRM              ; DA
dd C_MODRM              ; DB
dd C_MODRM              ; DC
dd C_MODRM              ; DD
dd C_MODRM              ; DE
dd C_MODRM              ; DF
dd C_DATA1              ; E0
dd C_DATA1              ; E1
dd C_DATA1              ; E2
dd C_DATA1              ; E3
dd C_DATA1              ; E4
dd C_DATA1              ; E5
dd C_DATA1              ; E6
dd C_DATA1              ; E7
dd C_DATA66             ; E8
dd C_DATA66             ; E9
dd C_DATA66+C_MEM2      ; EA
dd C_DATA1              ; EB
dd 0                    ; EC
dd 0                    ; ED
dd 0                    ; EE
dd 0                    ; EF
dd C_PREFIX             ; F0
dd 0                    ; F1
dd C_PREFIX             ; F2
dd C_PREFIX             ; F3
dd 0                    ; F4
dd 0                    ; F5
dd 0                    ; F6
dd 0                    ; F7
dd 0                    ; F8
dd 0                    ; F9
dd 0                    ; FA
dd 0                    ; FB
dd 0                    ; FC
dd 0                    ; FD
dd C_MODRM              ; FE
dd C_MODRM              ; FF

table_0F                label   dword   ; 0F-prefixed instructions

dd C_MODRM              ; 00
dd C_MODRM              ; 01
dd C_MODRM              ; 02
dd C_MODRM              ; 03
dd -1                   ; 04
dd -1                   ; 05
dd 0                    ; 06
dd -1                   ; 07
dd 0                    ; 08
dd 0                    ; 09
dd 0                    ; 0A
dd 0                    ; 0B
dd -1                   ; 0C
dd -1                   ; 0D
dd -1                   ; 0E
dd -1                   ; 0F
dd -1                   ; 10
dd -1                   ; 11
dd -1                   ; 12
dd -1                   ; 13
dd -1                   ; 14
dd -1                   ; 15
dd -1                   ; 16
dd -1                   ; 17
dd -1                   ; 18
dd -1                   ; 19
dd -1                   ; 1A
dd -1                   ; 1B
dd -1                   ; 1C
dd -1                   ; 1D
dd -1                   ; 1E
dd -1                   ; 1F
dd -1                   ; 20
dd -1                   ; 21
dd -1                   ; 22
dd -1                   ; 23
dd -1                   ; 24
dd -1                   ; 25
dd -1                   ; 26
dd -1                   ; 27
dd -1                   ; 28
dd -1                   ; 29
dd -1                   ; 2A
dd -1                   ; 2B
dd -1                   ; 2C
dd -1                   ; 2D
dd -1                   ; 2E
dd -1                   ; 2F
dd -1                   ; 30
dd -1                   ; 31
dd -1                   ; 32
dd -1                   ; 33
dd -1                   ; 34
dd -1                   ; 35
dd -1                   ; 36
dd -1                   ; 37
dd -1                   ; 38
dd -1                   ; 39
dd -1                   ; 3A
dd -1                   ; 3B
dd -1                   ; 3C
dd -1                   ; 3D
dd -1                   ; 3E
dd -1                   ; 3F
dd -1                   ; 40
dd -1                   ; 41
dd -1                   ; 42
dd -1                   ; 43
dd -1                   ; 44
dd -1                   ; 45
dd -1                   ; 46
dd -1                   ; 47
dd -1                   ; 48
dd -1                   ; 49
dd -1                   ; 4A
dd -1                   ; 4B
dd -1                   ; 4C
dd -1                   ; 4D
dd -1                   ; 4E
dd -1                   ; 4F
dd -1                   ; 50
dd -1                   ; 51
dd -1                   ; 52
dd -1                   ; 53
dd -1                   ; 54
dd -1                   ; 55
dd -1                   ; 56
dd -1                   ; 57
dd -1                   ; 58
dd -1                   ; 59
dd -1                   ; 5A
dd -1                   ; 5B
dd -1                   ; 5C
dd -1                   ; 5D
dd -1                   ; 5E
dd -1                   ; 5F
dd -1                   ; 60
dd -1                   ; 61
dd -1                   ; 62
dd -1                   ; 63
dd -1                   ; 64
dd -1                   ; 65
dd -1                   ; 66
dd -1                   ; 67
dd -1                   ; 68
dd -1                   ; 69
dd -1                   ; 6A
dd -1                   ; 6B
dd -1                   ; 6C
dd -1                   ; 6D
dd -1                   ; 6E
dd -1                   ; 6F
dd -1                   ; 70
dd -1                   ; 71
dd -1                   ; 72
dd -1                   ; 73
dd -1                   ; 74
dd -1                   ; 75
dd -1                   ; 76
dd -1                   ; 77
dd -1                   ; 78
dd -1                   ; 79
dd -1                   ; 7A
dd -1                   ; 7B
dd -1                   ; 7C
dd -1                   ; 7D
dd -1                   ; 7E
dd -1                   ; 7F
dd C_DATA66             ; 80
dd C_DATA66             ; 81
dd C_DATA66             ; 82
dd C_DATA66             ; 83
dd C_DATA66             ; 84
dd C_DATA66             ; 85
dd C_DATA66             ; 86
dd C_DATA66             ; 87
dd C_DATA66             ; 88
dd C_DATA66             ; 89
dd C_DATA66             ; 8A
dd C_DATA66             ; 8B
dd C_DATA66             ; 8C
dd C_DATA66             ; 8D
dd C_DATA66             ; 8E
dd C_DATA66             ; 8F
dd C_MODRM              ; 90
dd C_MODRM              ; 91
dd C_MODRM              ; 92
dd C_MODRM              ; 93
dd C_MODRM              ; 94
dd C_MODRM              ; 95
dd C_MODRM              ; 96
dd C_MODRM              ; 97
dd C_MODRM              ; 98
dd C_MODRM              ; 99
dd C_MODRM              ; 9A
dd C_MODRM              ; 9B
dd C_MODRM              ; 9C
dd C_MODRM              ; 9D
dd C_MODRM              ; 9E
dd C_MODRM              ; 9F
dd 0                    ; A0
dd 0                    ; A1
dd 0                    ; A2
dd C_MODRM              ; A3
dd C_MODRM+C_DATA1      ; A4
dd C_MODRM              ; A5
dd -1                   ; A6
dd -1                   ; A7
dd 0                    ; A8
dd 0                    ; A9
dd 0                    ; AA
dd C_MODRM              ; AB
dd C_MODRM+C_DATA1      ; AC
dd C_MODRM              ; AD
dd -1                   ; AE
dd C_MODRM              ; AF
dd C_MODRM              ; B0
dd C_MODRM              ; B1
dd C_MODRM              ; B2
dd C_MODRM              ; B3
dd C_MODRM              ; B4
dd C_MODRM              ; B5
dd C_MODRM              ; B6
dd C_MODRM              ; B7
dd -1                   ; B8
dd -1                   ; B9
dd C_MODRM+C_DATA1      ; BA
dd C_MODRM              ; BB
dd C_MODRM              ; BC
dd C_MODRM              ; BD
dd C_MODRM              ; BE
dd C_MODRM              ; BF
dd C_MODRM              ; C0
dd C_MODRM              ; C1
dd -1                   ; C2
dd -1                   ; C3
dd -1                   ; C4
dd -1                   ; C5
dd -1                   ; C6
dd -1                   ; C7
dd 0                    ; C8
dd 0                    ; C9
dd 0                    ; CA
dd 0                    ; CB
dd 0                    ; CC
dd 0                    ; CD
dd 0                    ; CE
dd 0                    ; CF
dd -1                   ; D0
dd -1                   ; D1
dd -1                   ; D2
dd -1                   ; D3
dd -1                   ; D4
dd -1                   ; D5
dd -1                   ; D6
dd -1                   ; D7
dd -1                   ; D8
dd -1                   ; D9
dd -1                   ; DA
dd -1                   ; DB
dd -1                   ; DC
dd -1                   ; DD
dd -1                   ; DE
dd -1                   ; DF
dd -1                   ; E0
dd -1                   ; E1
dd -1                   ; E2
dd -1                   ; E3
dd -1                   ; E4
dd -1                   ; E5
dd -1                   ; E6
dd -1                   ; E7
dd -1                   ; E8
dd -1                   ; E9
dd -1                   ; EA
dd -1                   ; EB
dd -1                   ; EC
dd -1                   ; ED
dd -1                   ; EE
dd -1                   ; EF
dd -1                   ; F0
dd -1                   ; F1
dd -1                   ; F2
dd -1                   ; F3
dd -1                   ; F4
dd -1                   ; F5
dd -1                   ; F6
dd -1                   ; F7
dd -1                   ; F8
dd -1                   ; F9
dd -1                   ; FA
dd -1                   ; FB
dd -1                   ; FC
dd -1                   ; FD
dd -1                   ; FE
dd -1                   ; FF

                        end


        Bây giờ chúng ta có thể lấy được chiều dài của chỉ thị trên address bất kỳ. chúng ta sẽ
repeat call này cho đến 5 bytes được read. Sau đó chúng ta sẽ copy các bytes này đến
old_hook. Chúng ta biết bao nhiêu bytes các chỉ thị đều tiên. vì vậy chúng ta có thể fill out the
relative (tương đối) jump address trên next instruction trong original function.

.386p
.model flat, stdcall

...

.data

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

 ...

 MEM_RELEASE           dd 000008000h

;16 nops + one relative jump
 old_sleep             db 090h,090h,090h,090h,090h,090h,090h,090h,
                          090h,090h,090h,090h,090h,090h,090h,090h,
                          0E9h,000h,000h,000h,000h


.code
start:
        push    5000
        call    Sleep

 do_hook:
        push    offset kernel_name
        call    GetModuleHandleA
        push    offset sleep_name
               push    eax
        call    GetProcAddress
        push   eax
        mov     esi,eax

        xor     ecx,ecx
        mov     ebx,esi
 get_five_bytes:
        push    ecx
        push    ebx
        call    get_instr_len          ;calling LDE32
        pop     ecx
        add     ecx,eax
        add     ebx,eax
        cmp     ecx,5
        jb      get_five_bytes
        mov     edi,offset old_sleep   ;counting relative jump address
        mov     [edi+011h],ebx
        sub     [edi+011h],edi
        sub     dword ptr [edi+011h],015h
        rep     movsb
        pop     edi

;following code was above, so without comments

        push    PAGE_READWRITE
        push    MEM_COMMIT
        push    MEMORY_BASIC_INFORMATION_SIZE
        push    0
        call    VirtualAlloc
        test    eax,eax
        jz      do_sleep
        mov     esi,eax

        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    ExitProcess
 new_sleep:
        mov     eax,dword ptr [esp+004h]             
        add     eax,eax                        ;doubling timeout
        push    eax
        mov     eax,offset old_sleep            ;calling old function
        call    eax
        ret     004h



After the hook it will look like this:

        004010CC: 6888130000   push 000001388h
        004010D1: E818090000   call Sleep


        Sleep:     ;this is jump on address in IAT
        004019EE: FF2514204000 jmp dword ptr [000402014h]

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

        new_sleep:
        004010DD: 8B442404     mov eax,dword ptr [esp+4]
        004010E1: 03C0         add eax,eax
        004010E3: 50           push eax
        004010E4: B827304000   mov eax,000403027h
        004010E9: FFD0         call eax

        old_sleep:
        00403027: 6A00         push 0
        00403029: FF742408     push dword ptr [esp+8]
        0040302D: 90           nop
        0040302E: 90           nop
        0040302F: 90           nop
        00403030: 90           nop
        00403031: 90           nop
        00403032: 90           nop
        00403033: 90           nop
        00403034: 90           nop
        00403035: 90           nop
        00403036: 90           nop
        00403037: E94337A877   jmp Kernel32.77E8677F

;this instruction is placed 1 byte after first instruction at Kernel32.Sleep
(77E86779)

        Kernel32.77E8677F:    
        77E8677F: E803000000   call Kernel32.SleepEx
        ...                    ;following is unimportant

To make this clearer, this is how the original version of Kernel32.Sleep looks:

        Kernel32.Sleep:
        77E86779: 6A00         push 0
        77E8677B: FF742408     push dword ptr [esp+8]
        77E8677F: E803000000   call Kernel32.SleepEx
        77E86784: C20400       ret 00004h


        Như bạn có thể thấy chúng ta đã copied chỉ thị đầu tiên và thứ hai (nó là 6 bytes
ở đây) và relative jump được trỏ đến trên next instruction và đó là nó sẽ như thế nào
Chúng ta phải tưởng tượng ở đây các relative jumps ko được đặt như
các bytes đầu tiên của các hàm functions. Nếu là thế chúng ta có một vấn đề. Vấn đề
kết tíep là với các hàm APIs giống như ntdll.DbgBreakPoint. Chúng quá ngắn cho pp này
để hooking. Và thấy rằng khi nó được gọi bởi Kernel32.DebugBreak, nó ko thể hook bởi
thay đổi IAT. Nhưng ai muốn hook function mà nó chỉ gọi  
int 3? Nhưng ko có gì là ko thể. Bạn có thể nghĩ về nó và bạn có thể
tìm cách như thế nào để giải quyết vấn đề này . Khi bạn nghĩ về điều này bạn có thể hook hàm
sau đây sau hàm này (nó sẽ bị damaged bởi rewritng first 5 bytes of hàm trước đó).
Hàm DbgBreakPoint là 2 bytes chiều dài, vì vậy chúng ta có thể set vài
flags ở đây và thữ write conditional jump trên begining of the second
function ... Nhưng bây giờ điều ày ko phải là vấn đề của chúng ta.
Với vấn đề saving original function rồi thuật lại unhooking.
Unhooking thay đổi thay thế các bytes trở lại trạng thái gốc original state. Khi rewriting
IAT bạn sẽ phải return original address đến table nếu bạn muốn làm
unhooking. Khi sử dụng 5 byte patch bạn sẽ phải copy các chỉ thị gốc đàu tiên trở lại.  
Cảc hai cách thật sự đơn giản và ko cần viết nhềiu về điều này.


=====[ 3.2.4 Other process hooking ]============================================
   
        Bây giờ chúng ta sẽ làm vài thứ thực tế với việc hooking trong suốt quá trình running. Ai múôn
đề cập đến hooking cho chính process của nó? Đó chỉ tốt cho việc học căn bản
nhưng nó ko thực tế.
        Tôi sẽ chỉ cho bạn 3 pp để hooking process khác. Hai trong chúng sử dụng
API CreateRemoteThread mà chúng chỉ có trong Windows với NT technology. Vấn đề
of hooking ko đáng quan tâm cho các older windows version đối với tôi. Sau tất cả
tôi sẽ thử giải thích pp thứ ba mà tôi ko thực hành. vì vậy nó có thể ko
họat động.
        Dầu tiên nói vài diều về CreateRemoteThread. Như phần help nói rằng hàm này
creates new thread trong bất kỳ process nào và runs code của nó.

        HANDLE CreateRemoteThread(
               HANDLE hProcess,
               LPSECURITY_ATTRIBUTES lpThreadAttributes,
               DWORD dwStackSize,
               LPTHREAD_START_ROUTINE lpStartAddress,
               LPVOID lpParameter,
               DWORD dwCreationFlags,
               LPDWORD lpThreadId
        );

        Handle hProcess có thể có bởi OpenProcess. Ở đây ch1ng ta phải có quyền
cần thiết. Pointer lpStartAddress trỏ đến memory place trong TARGET
process mà ở đó chỉ thị đầu tiên cho new thread . Bởi vì new thread được  
created trong target process nó ở trong memory of target process. Con trỏ  
lpParameter trỏ đến trên đối số mà nó sẽ được tham chiếu đén new thread.


=====[ 3.2.4.1 DLL Injection ]==================================================

        Chúng ta có thể run new thread từ bất kỳ nơi nào trong target process memory.
Ở đây trừ phi chúng ta có chính code trong nó. PP đầu tiên cheats cho điều này.
Nó sử dụng GetProcAddress để có addr thực cho hàm LoadLibrary. Rồi định tuyến  
lpStartAddress đến address of LoadLibrary. Function LoadLibary chỉ có một
parameter giống như hàm cho new thread trong target process.

        HINSTANCE LoadLibrary(
               LPCTSTR lpLibFileName
        );

        Chúng ta sẽ sử dụng sự đồng dạng này và chúng ta sẽ tham chiếu đến name of our DLL
library như là lpParameter. Sau đó running new thread lpParameter sẽ trên vị trí của
of lpLibFileName. Điều quan trọng nhất ở đây là hành vi được mô tả trước đó.
Sau khi loading new module vào trong target process memory phần khởi trị đầu đã được
thực thi. Nếu chúng ta đặt các hàm functions đặc biệt mà chúng sẽ hook các functions mà chúng ta muốn
chúng ta sẽ chiến thắng trong stuff này. Sau khi thực thi phần khởi trị đầu, thread sẽ ko có gì  
dể làm và close nhưng module của chúng ta sẽ vẫn trong memory. PP này thật sự  
rất đẹp và dễ thực hiện. Đây được gọi là DLL Injection. Nhưng nếu bạn thích như tôi
bạn bạn ko thích phải có nhiều DLL library. Nhưng nếu ai đó ko quan tâm
về việc có nhiều library này thì nó là pp dễ nhất và nhanh nhất (từ gốc độ  
lập trình viên).


=====[ 3.2.4.2 Independent code ]===============================================

        Tiếp tục với cách independent code là rất khó nhưng cũng rất ấn
tượng. Independent code là code mà ko có các addresses tỉnh nào.
Mọi thứ đều là tương đối trong  nó theo hướng một nơi mốc nào đó trong nó. Code này
hầu hết được làm nếu chúng ta ko biết address mà ở đó code này sẽ được thực thi.
Chắc chắn, nó có thể có addr này và rồi relink code của chúng ta như là nó xử lý
trên new address mà ko có lỗi nào nhưng điều này ngay cả khó hơn là
coding independent code. Ví dụ về lọai code này có thể là virus code.
Virus mà chúng lây nhiễm vào các file thực thi trong cách mà nó add chính nó vào một nơi nào đó
trong file thực thi này Các file thực thi khác sẽ là virus code trên các nơi khác
mà nó phụ thuộc. e.g. on file structure on length.
        Đầu tiên chúng ta phải insert  code của chúng ta trong target process. Rồi function
CreateRemoteThread sẽ săn sóc running code của chúng ta. Vì vậy, đầu tiên chúng ta phải
lấy vài thông tin về target process và lấy handle với OpenProcess.
Rồi dùng VirtualAllocEx sẽ cách phát vài space trong remote process memory cho
code của chúng ta.Cuối cùng chúng ta sẽ sử dụng WriteProcessMemory để write code của chúng ta trên  
memory được cấp phát và run nó. Trong CreateRemoteThread lpStartAddress sẽ tham chiếu đến
memory được cấp phát và lpParameter có thể là bất cứ gì chúng ta muốn. Bởi vì Tôi thật sự ko thích các  
files ko cần thíết nào nên tôi sử dụng pp này.


=====[ 3.2.4.3 Raw change ]=====================================================

        Ko có hàm CreateRemoteThread trong older windows version (ngọai trừ NT).
Vì vậy cúng ta ko thể sử dụng hàm này để hooking. Có lẽ có pp khác và tốt hơn các pp  
hook tôi sẽ nói về một pp khác ngay bây giờ. Trong thực tế tôi ko biết nếu pp này
làm việc trong thực tiển (chưa có ai biết khi sử dụng Windows) nhưng về mặt lý thuyết thì mọi thứ
đều OK .
        Chúng ta ko cần phải có code của chúng ta trong target process để hook các hàm functions
của nó hòan tòan. Chúng ta có hàm WriteProcessMemory (hàm này có trong all các Windows
version) và chúng ta củng có hàm OpenProcess. Sau cùng chúng ta cần là VirtualProtectEx
mà chúng có thể thay đổi truy xấut memory pages trong target process. Tôi ko thể thấy bất cứ
lý do gì mà ko hook được target process functions một cách trực tiếp từ process của chúng ta...


=====[ 4. Ending ]==============================================================

        This small document ends. I will greet (đón chào) any extension which will
describe unmentionde (ko được nhắc đến ) methods of hook, I am sure there are a lot of them. I will
also greet (chào đón) any extensions in the parts which were not described so intimately (sâu sắc).
You can also send me some source codes if they are fecund (đẻ nhiều) for the problem of
hooking e.g. for parts where I was lazy to write the code. The goal of this
document is to show details of every technics of hooking. I hope I've done
the part of this.
        Special thanks to Z0MBiE for his work, so I haven't to code it myself
and spend ages by studying tables for getting instruction length.

===================================[ End ]======================================