📜 ⬆️ ⬇️

Wrapper Interceptor Library

Good day to all!
I recently laid out my implementation of the interceptor ( here ).
It turned out, which is no secret, cumbersome and sloppy working. In 1, the respected k_d wrote back from the comments and mentioned his wrapper over mhook ( MHook vs Zuma ).
Of course, I was interested in an alternative that works with interception not only of __ cdecl, but, moreover, it allows you to intercept almost anywhere in the code.
I liked the solution and I decided to rewrite my library, which I use for various kinds of interceptions, completely, using material from k_d . The current version is able to intercept everything the programmer handles the experimental handles and parse arguments from the stack (at least, potentially the idea can do it all. Probably.)
I present to you what happened.


In order to compile the working library, you need MHook, a wrapper from k_d , medium straightened arms, a head pulled out from under the table, and a duck with which to consult: duck .

So let's go!
')
I) Functional:

1) Log output to file:

void debug_msg(const char* func_name, const char* txt,...) { va_list args; FILE *file; char file_name[256]="\0"; strcpy(file_name,"C:\\VariadicDump\\"); strcat(file_name,func_name); strcat(file_name,".txt"); fopen_s(&file,file_name, "a"); va_start(args,txt); vfprintf(file,txt,args); va_end (args); fprintf(file, "\n"); fclose(file); } 


Using:

 debug_msg("Advanced", "--%s arg list started--", funcName); 


When funcName = "Hello, world, you read this message so many times" we get the file C: \ VariadicDump \ Advanced.txt with the following contents:

--Hello, world, you read this message so many times arg list started--


2) Pars lua_State (only for initialized and private for this function! Useful, for example, in MMO Runes of Magic for intercepting chat, in other cases did not use):

 void Parse_LuaState(lua_State *L, const char *func_name) { int n = lua_gettop(L); std::vector<const char*> names; for(int i = 0; i < n; i++) { size_t arg2Len = 0; names.push_back(luaL_checklstring(L, i, &arg2Len)); } string str = ""; for (unsigned int i=0; i<names.size(); i++) { str.append(names[i]); str.append("; "); } debug_named_msg(func_name, str.c_str()); } 


Using:

 void lua_hook(lua_State *L) { Parse_LuaState(L, "Lua"); } 


For example, in * L there were 2 arguments - chat type and text (1 and “hello, world, are you hate to hear it again?”). The function will write the following in C: \ VariadicDump \ Lua.txt:

1; hello, world, are you hate to hear it again?


3) Parsing arguments from the stack:

 void parseArgs(int *ptr, int size, char* funcName) { debug_msg("Advanced", "--%s arg list started--", funcName); for(int i=0; i*4<size; i++) { debug_msg("Advanced", " |---Element %d: %d", i, ptr[i]); } debug_msg("Advanced", "--arg list finished--\n"); } 


Using:

 void con_hook(Context *context) { int *ptr = (int*)(void*)(context->ESP+4); parseArgs(ptr, con_arg_amount, __FUNCTION__); } 


As a result, the arguments will be derived at the rate of esp + index * 4 name ## _ arg_amount / 4 times.
In an amicable way, there it is more correct and more beautiful to pass count of arguments, but it’s not difficult to do it yourself, if necessary.

4) The address of the main module of the intercepted application:

 int GetMainModuleAddress() { DWORD dwAddress = NULL; HANDLE hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, _getpid()); if (hthSnapshot) { MODULEENTRY32 me = { sizeof(me) }; if (Module32First(hthSnapshot, &me)) { CloseHandle(hthSnapshot); dwAddress = (DWORD)me.modBaseAddr; } } return dwAddress; } 


Nothing special is needed, for example, in the Rift - there the virtual address is calculated as follows:

 #define RECALC(name)\ name##_Detour = (t##name)((int)name##_Detour-0x400000+rift); 


where name ## _ Detour is the function being intercepted.

5) Attach / detach functions:

Simple wrapper for installing / removing the springboard. We need it purely in order not to climb the code in search of DllMain :)

The last one on the list, but not the last one in our hearts, and its usefulness in functionality — unhook'er:

 BOOL UnHookFunction(DWORD addr, unsigned char *lpBackup) { DWORD dwAddr = addr; if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, lpBackup, 6, 0)) return TRUE; return FALSE; } 


Simply and with taste restores the code in which the springboard stood.

Ii) Macros

Macros - the main feature of this project, which, in fact, allowed to roll the working part to indecently small size.

1) RECALC:
 #define RECALC(name)\ name##_Detour = (t##name)((int)name##_Detour-0x400000+rift); 


Mentioned above is needed for recalculating the address.

2) DETACH:
 #define DETACH(name1)\ UnHookFunction((DWORD)name1##_Detour,name1##_var);\ 


Wrapper over the recovery ... release of the code from the springboard.

3) ATR / ATR_R:
 #define ATR(name)\ name##_var = RegHook((long)name##_Detour, (long)(void*)name##_hook) #define ATR_R(name)\ RECALC(name)\ name##_var = RegHook((long)name##_Detour, (long)(void*)name##_hook) 


Two twin brothers to install the springboard. RegHook is a wrapper function over Mhook, a description can be found in the source code in either. In the same article, it is indicated that there is a Context and something to eat, so as not to run naked along the embankment and not to call a hedgehog out of the fog (just kidding, nobody will tell you this).

Used in the attach () function;

4) DTR:
 #define DTR(name)\ DETACH(name) 


Wrap over wrap.
A controversial need, but it reads more beautifully next to ATR ^^ (DETACH is a relic of the epoch, sorry to delete).

Used in the detach () function;

5) RF_O_UP_FUNC_CONTEXT:
 #define RF_O_UP_FUNC_CONTEXT(name1, adres, args)\ typedef void (__cdecl * t##name1 ) ();\ t##name1 name1##_Detour = ( t##name1 ) ( adres );\ /* */ void name1##_hook(Context *context);\ /*     ;   - */ BYTE *name1##_var;\ /*    */ int name1##_arg_amount = args;\ /*  ,   (. )*/ 


The most cunning macro in this village. Actually, he is engaged in declaring an interceptor and the function being intercepted, declares a variable to save the source code from the springboard, etc.

Example:

 RF_O_UP_FUNC_CONTEXT(con, 0x60D710, 0x8); 


We declare 2 functions - con_Detour and con_hook, bind the intercepted function to the address 0x60D710 and indicate that if we need to analyze the arguments, we will get 2 pieces in the output.

III) Example of use

 RF_O_UP_FUNC_CONTEXT(con, 0x60D710, 0x8); void lua_hook(Context *context) { int *ptr = (int*)(void*)(context->ESP+4); //  1      ptr parseArgs(ptr, con_arg_amount, __FUNCTION__); //    , 2  -     ! debug_msg("LuaDump", "%s", ptr[0]); // 1   -   .. } 


To work dll may be needed from lua, as well as mhook + wrapper from k_d.

Here you can download library samples.

Thanks again to k_d for a job well done and an idea!

Thank you all, all the best! And yes the duck will triumph! Quack!

Source: https://habr.com/ru/post/174647/


All Articles