?? 29a-7.007
字號:
HOOKLIB & SDE
~~~~~~~~~~~~~
ABSTRACT
Two engines described: HOOKLIB splicing library, allowing you to hook any
function by address, including functions in the remote processes; and
SDE, or Subroutine Displacement Engine -- an engine allowing you to
make your C/C++ subroutines program- and/or offset-independend, for example
to inject and execute them in the remote processes.
To use these engines, no special knowledge/coding is required; everything
can be understood from the examples.
CONTENTS
1. HookLib intro
2. HookLib
3. SDE intro
4. SDE
5. Conclusion
1. HOOKLIB INTRO
~~~~~~~~~~~~~~~~
I'd like to tell ya 'bout some gamez using length disassemblers. One of such
games is so called splicing, cool vx technology known and used for years.
Different stupid scriptkiddiez are so lazy so they hook iat, and other fuckin
dwords pointing to other dwords, and they think that it is cool. But real
machos never hook dwords, they deal with only the real code. I'll tell you
why. Because one day such a scriptkiddie encounter situation where there
is no dword pointing to another dword. And then he suck big red dick.
Moreover, since function is hooked indirectly, changing some reference, you
have no guarantee that it will never be called directly, so you can not hook
all target function calls. While we always know how to hook mostly any
function in any case. So i'll tell you how. Imagine, somewhere exists
subroutine you want to hook. It consists of instructions, isnt
it? And you can change these instructions. For example, since
you insert into the prolog of the target subroutine something
like JMP, it is hooked. You may think, that subroutine will not work
after such a modification. No fucking way, it will. You only need
to take original instructions and correctly place 'em into
another location. Somewhere into the place, pointed to by the
inserted jmp, where these moved instructions will be executed.
So it all looks like the following:
before modification: after modification:
target: push ebp target: jmp hook_stub \ (1)
mov ebp, esp nop /
sub esp, 8 push esi
push esi ...
... hook_stub: call hook
push ebp
mov ebp, esp
sub esp, 8
jmp target+6
hook: ...
The only question you can ask is how to find out how many original bytes
should we copy. Amount of bytes is calculated using simple algorithm: copy
instruction by instruction, until summary size of the copied bytes
is enough to insert there (instead of them) something like jmp hook_stub
(1). So this can be 5 or more original bytes, depending
on instructions forming target subroutine prolog. Copying instructions
one by one requires such thing as length disassembler: it
is just a subroutine that returns instruction length by
given instruction pointer. Once again, scriptkiddie will insert something
like push offset hook_stub & retn, instead of a relative jmp, while
real machos always know how relative arguments are calculated,
so in situation where 5 bytes is okey but 6 is not,
scriptkiddiez will suck. Moral of this story is simple: leave easy ways
for suckers, and live your own original life.
Sometimes people torment themselfs using the following algo: copy original
bytes from the target subroutine into some temp buffer, and insert jmp to
hook subroutine instead of original prolog bytes; later,
when hook is called, restore original bytes, call original
subroutine, wait until it returns, and hook it once again.
Except redundant complexity, such method is unreliable: first,
you can lose your hook if subroutine doesnt returns; second, the
more frequently you modify executable code without thread
locking, the more chances you have to fuckup your unhappy program.
2. HOOKLIB
~~~~~~~~~~
Here is a brief description of the HOOKLIB splicing library, which allows you
to hook mostly any subroutine, including subroutines in the remote processes,
any number of times (multiple hooks), including unhook operation. Note, that
if you install hooks 1, then 2, then 3 (for the same target subroutine),
an then remove hook 2, only hook 1 will be available, since hooks are not
linked into chains.
void* InstallHook(void* Target, /* subroutine to hook */
void* Hook, /* hook handler */
unsigned long flags, /* flags, HF_xxx */
unsigned long nArgs, /* used if HF_REPUSH_ARGS */
void* stubAddr, /* if NULL, do malloc/free */
unsigned long stubSize, /* unused if stubAddr is defined */
void* hProcess ); /* process handle */
Target -- is a pointer to the subroutine you want to hook.
This can be virtual address in the remote process.
Hook -- is a pointer to the hook handler subroutine.
This also can be virtual address in the remote process.
Flags -- is a bitset of the following values:
HF_REPUSH_ARGS -- if specified, arguments are re-pushed before calling
Hook(), and you must specify also nArgs parameter.
if not specified, arguments are left on the stack
unchanged.
HF_VAARG -- used only if HF_REPUSH_ARGS flag is specified;
if used, in addition to nArgs arguments there is
last argument called va_arg,
or "variable argument list"; in C/C++ it looks
like "...", like in printf.
HF_DISABLE_UNHOOK -- normally, hook stub contains information used in
unhook operation (see UninstallHook());
if this flag is specified, such information is
not generated, and standard unhook
will be not available.
HF_NOMALLOC -- if this flag is specified, stubAddr parameter
specifies virtual address of the hook stub;
possibly in the remote context.
otherwise, malloc/free alike functions will be
used to allocate/free hook stub memory.
HF_RETTOCALLER -- used only if HF_REPUSH_ARGS is NOT specified;
if this flag is specified, Hook() handler
is called using JMP command, otherwise with CALL.
In 1st case, control is returned to caller,
bypassing target subroutine;
in 2nd case, control is passed to hooked subroutine.
HF_OWN_CALL -- used only if HF_RETTOCALLER is NOT specified;
if this flag is specified, Target() is called from
Hook(), and 1st argument passed to Hook() is
pointer to copied original bytes, linked with
jmp to (Target + orig_len)
if HF_TARGET_IS_CDECL is also specified,
nArgs is ignored, otherwise nArgs should be specified
to build 'RET n' instruction after
call Hook & add esp, n
HF_TARGET_IS_CDECL -- used only if HF_OWN_CALL,
means that Target() subroutine uses __cdecl
calling convention.
HF_REGISTERS -- do PUSHAD before Hook() call &&
do POPAD on return from Hook(),
as such Hook() can modify registers,
useful in combination with HF_RETTOCALLER flag,
when instead of target address you specify
not a subroutine but some instruction address, and
wanna inspect/change register values at that point.
nArgs -- used only if HF_REPUSH_ARGS and/or (HF_OWN_CALL&&!HF_TARGET_IS_CDECL)
flags are specified;
specifies number of arguments, not counting va_arg (if present)
stubAddr -- used only if HF_NOMALLOC flag is specified;
specifies virtual address of the hook stub
(possibly in the remote process).
stubSize -- used only if stubAddr is defined (!=NULL),
specifies max size of hook stub
hProcess -- is a handle of the process we are working with;
this handle is passed into Virtual<Alloc|Free|Protect>Ex
and/or <Read/Write>ProcessMemory functions;
if you hook subroutine in the current process,
specify here GetCurrentProcess();
if you use HOOKLIB on the unix machine,
and/or using standard C functions like malloc/free/memcpy,
this parameter is completely ignored.
Return values:
InstallHook() returns "hook handle", i.e. pointer to the hook stub
(possibly in the remote process), or NULL if error.
Stub format/Hook arguments:
HF_REPUSH_ARGS = 0
HF_RETTOCALLER = 0
HF_OWN_CALL = 0
HF_TARGET_IS_CDECL = unused
target: jmp stub
stub: (if HF_DISABLE_UNHOOK==0) <unhook_data>
call hook
orig_bytes: <orig_bytes>
jmp (target + <orig_len>)
; void __cdecl hook(hkRET, arg1, arg2, argX)
hook: ...
retn
HF_REPUSH_ARGS = 0
HF_RETTOCALLER = 0
HF_OWN_CALL = 1
HF_TARGET_IS_CDECL = 0
target: jmp stub
stub: (if HF_DISABLE_UNHOOK==0) <unhook_data>
push offset orig_bytes
(HF_REGISTERS ? PUSHAD)
call hook
(HF_REGISTERS ? POPAD)
add esp, 4
retn (nArgs * 4)
orig_bytes: <orig_bytes>
jmp (target + <orig_len>)
; sometype __cdecl hook(target, hkRET, arg1, arg2, argN)
hook: ...
call target
mov eax, retcode
retn
HF_REPUSH_ARGS = 0
HF_RETTOCALLER = 0
HF_OWN_CALL = 1
HF_TARGET_IS_CDECL = 1
target: jmp stub
stub: (if HF_DISABLE_UNHOOK==0) <unhook_data>
push offset orig_bytes
call hook
add esp, 4
retn
orig_bytes: <orig_bytes>
jmp (target + <orig_len>)
; sometype __cdecl hook(target, hkRET, arg1, arg2, argX)
hook: ...
call target
add esp, (nArgs * 4)
mov eax, retcode
retn
HF_REPUSH_ARGS = 0
HF_RETTOCALLER = 1
HF_OWN_CALL = unused
HF_TARGET_IS_CDECL = unused
target: jmp stub
stub: (if HF_DISABLE_UNHOOK==0) <unhook_data>
jmp hook
orig_bytes: <orig_bytes>
jmp (target + <orig_len>)
; void __whatever hook(arg1, arg2, argX)
hook: ...
retn <whatever>
HF_REPUSH_ARGS = 1
HF_RETTOCALLER = unused
HF_OWN_CALL = 0
HF_TARGET_IS_CDECL = unused
target: jmp stub
stub: (if HF_DISABLE_UNHOOK==0) <unhook_data>
(if HF_VAARG) push esp; add dword [esp], 4+nArgs*4
push argN
push arg1
call hook
add esp, (nArgs * 4 + HF_VAARG?4:0)
orig_bytes: <orig_bytes>
jmp (target + <orig_len>)
; void __cdecl hook(arg1, arg2, argN)
hook: ...
retn
HF_REPUSH_ARGS = 1
HF_RETTOCALLER = unused
HF_OWN_CALL = 1
HF_TARGET_IS_CDECL = 0
target: jmp stub
stub: (if HF_DISABLE_UNHOOK==0) <unhook_data>
(if HF_VAARG) push esp; add dword [esp], 4+nArgs*4
push argN
push arg1
push offset orig_bytes
call hook
add esp, (nArgs * 4 + 4 + HF_VAARG?4:0)
retn (nArgs * 4)
orig_bytes: <orig_bytes>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -