📄 29a-7.019
字号:
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
Now we are able to get instruction length on arbitrary address. We will
repeat this call until 5 bytes are read. After this we will copy these bytes
to old_hook. We know how long are first instructions, so we can fill out the
relative jump address on the next instruction in 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
As you can see we copied first and second instruction (it was 6 bytes
here) and the relative jump pointed on the next instruction and that is how
it should be. We have to supposed here that relative jumps are not placed
as the first bytes of functions. If there would be we've got a problem. Next
problem is with APIs like ntdll.DbgBreakPoint. These are too short for this
method of hooking. And forasmuch as it is called by Kernel32.DebugBreak, it is
not hookable by changing IAT. But who want to hook function which does only
the int 3 call? But nothing is impossible. You can think about it and you can
find how to solve this. As I was thinking about this you can hook the following
function after this one (it would be damaged by rewritng first 5 bytes of the
previous function). Function DbgBreakPoint is 2 bytes long, so we can set some
flags here and try to write conditional jump on the begining of the second
function ... But this is not our problem now.
With the problem of saving original function relates then unhooking.
Unhooking is changing replaces bytes back to the original state. When rewriting
IAT you will have to return original address to the table if you want to do
unhooking. When using the five byte patch you will have to copy first original
instructions back. Both ways are realy simple and no need to write more about
this.
=====[ 3.2.4 Other process hooking ]============================================
Now we will do something practical with hooking during running. Who
want to deal with hooking own process? That is good only for learning basics
but it is not much practical.
I'll show you three methods of other process hooking. Two of them use
API CreateRemoteThread which is only in Windows with NT technology. The problem
of hooking is not so interesing for older windows version for me. After all
I will try to explain third method which I didn't practise, so it could be
unfunctional.
At first few about CreateRemoteThread. As the help says this function
creates new thread in any process and runs its code.
HANDLE CreateRemoteThread(
HANDLE hProcess,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
The handle hProcess can be get by OpenProcess. Here we have to have
necessary rights. The pointer lpStartAddress points on memory place in TARGET
process where the first instruction for new thread is. Because new thread is
created in target process it is in memory of target process. The pointer
lpParameter points on argument which will be refered to the new thread.
=====[ 3.2.4.1 DLL Injection ]==================================================
We are able to run new thread from any place in target process memory.
This is useless unless we have own code in it. The first method cheats on this.
It uses GetProcAddress to get actual address for LoadLibrary. Then routes
lpStartAddress to the address of LoadLibrary. Function LoadLibary has only one
parameter like the function for new thread in target process.
HINSTANCE LoadLibrary(
LPCTSTR lpLibFileName
);
We will use this similarity and we will refer the name of our DLL
library as lpParameter. After running new thread lpParameter will be on a place
of lpLibFileName. The most important thing here is behavior decribed above.
After loading new module into target process memory the initialization part is
executed. If we place specific functions which will hook functions we want to
we will win this stuff. After execution of initialization part, the thread will
have nothing to do and close but our module is still in memory. This method is
realy nice and easy to implement. This is called DLL Injection. But if you are
like I am, you don't like must of having DLL library. But if one doesn't care
about having this library it is the easiest and the fastest method (from the
programmers sight).
=====[ 3.2.4.2 Independent code ]===============================================
Going on the way of independent code is very difficult but also very
impressive thing. Independent code is the code without any statical addresses.
Everything is relative in it towards some specific place in itself. This code
is mostly done if we don't know the address where this code will be executed.
Sure, it is possible to get this address and then to relink our code so as it
will behave on the new address without errors but this is even harder than
coding independent code. Example of this kind of code can be the virus code.
The virus which infects executables in the way it adds itself somewhere into
this executable. In different executables will be the virus code on different
places depended e.g. on file structure on length.
At first we have to insert our code into target process. Then function
CreateRemoteThread will take care of running our code. So, at first we have to
get some information about target process and get handle with OpenProcess.
Then VirtualAllocEx will alloc some space in remote process memory for our
code. Finally we will use WriteProcessMemory to write our code on allocated
memory and run it. In CreateRemoteThread lpStartAddress will refer to allocated
memory and lpParameter can be whatever we want. Because I realy don't like any
unnecesarry files I use this method.
=====[ 3.2.4.3 Raw change ]=====================================================
There is not CreateRemoteThread in older windows version (without NT).
So we can't use this for hooking. There are probably other and better methods
how to hook than the method I will talk about now. In fact I don't know if this
will work in practice (one never know when use Windows) but theoretically is
everything ok.
We don't need to have our code in target process to hook its functions
at all. We have function WriteProcessMemory (this should be in all Windows
version) and we have OpenProcess, too. Last thing we need is VirtualProtectEx
which can change access to memory pages in target process. I can't see any
reason why not to hook target process functions directly from our process...
=====[ 4. Ending ]==============================================================
This small document ends. I will greet any extension which will
describe unmentionde methods of hook, I am sure there are a lot of them. I will
also greet any extensions in the parts which were not described so intimately.
You can also send me some source codes if they are fecund 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 deatails 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 ]======================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -