?? 29a-7.007
字號:
jmp (target + <orig_len>)
; sometype __cdecl hook(target, arg1, arg2, argN)
hook: ...
call target
mov eax, retcode
retn
HF_REPUSH_ARGS = 1
HF_RETTOCALLER = unused
HF_OWN_CALL = 1
HF_TARGET_IS_CDECL = 1
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, (4 + nArgs * 4 + HF_VAARG?4:0)
retn
orig_bytes: <orig_bytes>
jmp (target + <orig_len>)
; sometype __cdecl hook(target, arg1, arg2, argN)
hook: ...
call target
add esp, (nArgs * 4)
mov eax, retcode
retn
UninstallHook() is only available if HF_DISABLE_UNHOOK flag were NOT
specified while calling InstallHook subroutine.
int UninstallHook(void* hookHandle, /* returned by InstallHook() */
void* hProcess ); /* process handle, -1=current */
hookHandle -- is a ponter to the hook stub,
returned by InstallHook subroutine.
hProcess -- same as in InstallHook()
Return values:
UninstallHook() returns 1 if hook is removed, and 0 if error.
3. SDE INTRO
~~~~~~~~~~~~
In some cases, we need to execute own code in the remote process.
There are two common ways of doing such a bad thing:
1. remotely load code from the external dll file,
by means of calling CreateRemoteThread() two times:
1st time remotely call LoadLibrary to load own dll,
2nd time remotely call own dll's function.
2. inject some special code snippet into remote process.
I'd like to tell ya how to do it in C/C++, without any problems.
Imagine, that you have some C/C++ subroutines, and you want to inject'em
into the remote context, at different virtual address.
What will happen in such case?
1st, your subroutines use text strings.
This can be solved by copying all the text strings
into single string array (char**), and copying that array into the
remote context together with the executable code;
then, each subroutine will receive pointer to that string table as an
argument, and use text strings as StringTable[n].
2nd, your subroutines use binary data structures.
This can be solved by means of collecting all these structures into
some binary array and pass that array into the remote context,
the same as string table; then subroutines will receive pointer to that
structure as well as its size, and use it as a workspace.
3rd, your subroutines use external API calls.
This can be solved by means of disassembling all the subroutines
instruction by instruction, and replacing external calls with
fixed calls, in such way that when subroutines are copied into the
remote context, all external calls will point to the same api functions,
as in original subroutines location.
This is based on assumption, that main system dll's in different
contexts are loaded at the same base addresses.
If you want to use some specific dll, which can be loaded at
variable image base addresses, you can load its api dynamically.
4th, i can miss something else, so you should know how your c/c++ source
is compiled into assembly code, how each line of code looks in both
high and low level representation.
5th, you cant use c++ classes, since method tables should then be also
copied/modified into other location; but this probably could be solved.
So, how it all looks like?
step 1 step 2 step 3
^ ^ ^
/ \ / \ / \
<functions> --> reassembled, copied --> +--------+
<string table> --> reassembled, copied --> | |
<binary data> --> unchanged, just copied --> | temp | temp buffer is
startup code, generated --> | buffer | --> injected into
call table, generated --> | | remote process
call table init code --> | | and/or executed
reloc table, generated --> +--------+
step 1
you pass pointers to
a) specially written (in c/c++) functions,
b) string table (optionally, if specified)
c) binary data (--//--)
to the SDE engine;
it reassembles all the stuff into given temp buffer,
optionally (if VA == NULL) generates relocation table and call table,
and optionally (if SDE_RELOAD_FUNCTIONS flag is specified),
builds call table initialization code.
step 2
temp buffer is (optionally) injected into the remote process,
you can do it for example using VirtualProtectEx, VirtualAllocEx
and WriteProcessMemory functions
step 3
remote thread is created using CreateRemoteThread function,
and/or some remote hook (maybe using HOOKLIB engine) is installed
4. SDE
~~~~~~
Here is a description of the SDE, or Subroutine Displacement Engine,
which allows you to do step 1 of the stuff described above with a single
function call.
int Reassemble(void* xStart, /* 1st subroutine to reassemble */
void* xEntry, /* "main" subroutine */
void* xEnd, /* last subroutine to reassemble */
char** xStrTab, /* string table */
void* binData, /* user data */
unsigned long binSize, /* user data size */
void* buf, /* buffer to reassemble into */
unsigned long maxbufsize, /* max buffer size */
unsigned long *bufsize, /* on output, used buffer size */
unsigned long VA, /* VA of new location, 0=reloc code */
unsigned long *entry, /* on output, entry point va/rva */
unsigned long flags); /* flags, SDE_xxx */
xStart -- is an empty subroutine in your code, used to define start address
of the set of "remote" subroutines.
We assume that C/C++ compiler places subroutines in memory
in exact order as if they were located in source file.
xEntry -- is an "entrypoint" subroutine, which is called in the remote
context.
void __cdecl xEntry(unsigned long VA,
unsigned long injected_size,
char** xStrTab,
unsigned char* binData,
unsigned long binSize)
xEntry is __cdecl subroutine;
xEntry arguments are:
VA, xStrTab,
binData, binSize -- pointers to the same stuff
as passed to Reassemble(),
but, for sure, relocated according
to given VA, where all this stuff
will be placed.
injected_size -- size of the injected temp_buffer
If xEntry is executed using CreateRemoteThread,
return is equal to ExitThread,
other cases depends on your fantasy.
xEnd -- is an empty subroutine, used to define end address of the
set of "remote" functions.
xStrTab -- string table, used by your functions.
can be NULL, if it is not required.
string table is in 'char* []' format,
if SDE_SKIP_LOADLIBRARY flag is NOT specified, then
1st entry of the string table is DLL list,
each dll name (including last one) ends with ';' character,
which is replaced with \0 in the remote context; these
DLL's will be LoadLibrar'ied by the generated startup code;
last string table entry is NULL;
other string table entries are use-defined text strings.
binData -- pointer to some user-defined data, can be NULL if not required
binSize -- size of the user-defined data, can be 0
buf -- temporary buffer, to place generated stuff into
maxbufsize -- max size of the temporary buffer
bufsize -- on return, is filled with size of generated stuff in the buffer
VA -- virtual address in the remote context,
at which temp buffer will be placed.
xStart address in the current context equals to VA in the
remote context.
NOTE:
We should know VA _before_ generation of the temp buffer;
this means that obtaining virtual address in the remote process
for the future temp buffer placement begins not after,
but BEFORE temp buffer generation.
if VA == NULL, base-independend code will be generated,
i.e. code including relocation table and call table;
see also SDE_RELOAD_FUNCTIONS flag
entry -- pointer to variable, which receives remote va/rva of the generated
startup code;
if VA == NULL, entry is relative;
if VA != NULL, entry is VA-based
starup code does the following:
1. if VA == NULL, initializes relocations
2. if SDE_SKIP_LOADLIBRARY flag is NOT specified,
loads DLL's specified in the StringTable[0]
3. passes control to xEntry subroutine.
flags -- bitset of the SDE_xxx values
SDE_SKIP_LOADLIBRARY -- ignore StringTable[0],
i.e. do not load libraries specified there
SDE_RELOAD_FUNCTIONS -- used only if VA == 0,
makes independend code,
i.e. each called api name will be replaced with
its checksum, to be loaded on startup
Comments:
except that all, after buffer is generated,
the following magic dword's are replaced with corresponding values:
SDE_MAGIC_VA
SDE_MAGIC_XSTRTAB
SDE_MAGIC_BINDATA
SDE_MAGIC_BINSIZE
i.e. if you write in your "remote" subroutine something like
unsigned long va = SDE_MAGIC_VA;
then in the remote context this dword will be replaced with VA value.
!!! Make sure you're not doing something like
!!! char foo = ((char*)SDE_MAGIC_BINDATA)[123];
!!! - its incorrect! Magic values should be used in such way that
!!! they appear in the assembly instructions unchanged.
Return values:
Reassemble() returns 1 if buffer is assembled, and 0 if an error occured.
5. CONCLUSION
~~~~~~~~~~~~~
Using these engines you can hook subroutines in the remote contexts
(on NT boxes) with your own C/C++ functions, in run-time,
without external files.
See examples for some things can be done using engines.
This can be (and is) used in memory residency and fw/av bypassing techniques.
However, this is not good enough, since there are drivers and ring0 api,
which can be used for such purposes much more effectively.
Supporting 9x/me systems:
since you can not do Virtual<Alloc|Free>Ex on the 9x boxes,
you should use known remote addresses there.
Such addresses can be found by means of analyzing PE structure
of the executable image file, or using known stack, heap and other
addresses where exists some unused mapped memory.
* * *
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -