[ 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 ]======================================
0 nhận xét:
Đăng nhận xét