インターセプトラッピングライブラリ

すべての人に良い一日を!

最近、インターセプターの実装をレイアウトしました( こちら )。

正直、面倒で不器用な作業であることが判明しました。 コメントの1つでは、尊敬されているk_dがサブスクライブされてお​​らず、mhookのラッパー( MHook vs Zuma )について言及しています。

もちろん、__ cdeclのインターセプトだけでなく、さらにコードのほぼどこにでもインターセプトを配置できる代替機能に興味がありました。

私はこの解決策が気に入ったため、ライブラリを書き直すことにしました。これは、さまざまな種類のインターセプトに使用し、 k_dの素材を使用してきれいに作成します。 現在のバージョンは、プログラマーのグラバーの実験的な手が到達するすべてをインターセプトし、スタックからの引数を解析できます(少なくとも、潜在的に、アイデアはこれを行うことができます。おそらく)。

何が起こったのか、あなたの注目を集めます。





作業ライブラリをコンパイルするには、MHook、k_dのラッパー、中程度のストレートアーム、テーブルの下から引き出されたヘッド、および相談するためのアヒルが必要です: duck



さあ、行こう!



I)機能:



1)ファイルへのログ出力:



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); }
      
      







使用法:



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







funcName = "Hello、world、you you何度もこのメッセージを読む"とすると、次の内容のファイルC:\ VariadicDump \ Advanced.txtが取得されます。



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









2)pars lua_State(この関数の初期化済みおよびプライベート用のみ!たとえば、MMO Runes of Magicでチャットをインターセプトするのに役立ちます。他の場合は使用しませんでした):



 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()); }
      
      







使用法:



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







たとえば、* Lには2つの引数がありました—チャットとテキストのタイプ(1と「こんにちは、世界、あなたはそれをもう一度聞きたくないですか?」)。 この関数は、「C:\ VariadicDump \ Lua.txt」に次を書き込みます。



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









3)スタックからの引数の解析:



 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"); }
      
      







使用法:



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







結果として、引数は計算esp + index * 4 name ## _ arg_amount / 4回から導出されます。

良い方法では、そこに引数の数を渡す方がより正確で美しいですが、必要に応じて自分で行うことは難しくありません。



4)インターセプトされたアプリケーションのメインモジュールのアドレス:



 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; }
      
      







特別なものは何も必要ありません。たとえば、Riftでは、仮想アドレスは次のように計算されます。



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







name ## _ Detourはフックされた関数です。



5)機能のアタッチ/デタッチ:



スプリングボードをインストール/削除するためのシンプルなラッパー。 DllMainを探してコードを登らないようにするためだけに必要です:)



リストの最後にありますが、私たちの心の最後ではなく、機能の有用性もあります。



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







スプリングボードが立っていたコードを簡単かつ上品に復元します。



II)マクロ



マクロは、このプロジェクトの主な機能であり、実際には、作業部分を非常に小さいサイズに削減することができました。



1)再計算:

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







上記のとおり、アドレス変換に必要です。



2)取り外し:

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







リバウンドのラッパー...スプリングボードからコードを解放します。



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)
      
      







踏み台の設置のための2人の双子の兄弟。 RegHook-Mhookのラッパー関数。説明はソースまたはソースで読み取ることができます。 同じ記事では、プロムナードに沿って裸で走ったり、霧からハリネズミを呼び出したりしないように、コンテキストと食事があります(冗談です、誰もあなたに教えないでしょう)。



attach()関数で使用されます。



4)DTR:

 #define DTR(name)\ DETACH(name)
      
      







ラップオーバーラップ。

物議をかもす必要がありますが、ATRの隣により美しく表示されます^^(DETACHは時代の遺物であり、削除するのは残念です)。



detach()関数で使用されます。



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;\ /*  ,   (. )*/
      
      







この村で最もcなマクロ。 実際、彼はインターセプターとインターセプトされた関数の宣言、スプリングボードからソースコードを保存する変数の宣言などに従事しています。



例:



 RF_O_UP_FUNC_CONTEXT(con, 0x60D710, 0x8);
      
      







con_Detourとcon_hookの2つの関数を宣言し、インターセプトされた関数をアドレス0x60D710にバインドし、引数を分析する必要がある場合、出力に2つの要素が含まれることを示します。



III)ケーススタディ



 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   -   .. }
      
      







dllが機能するためには、mhook + k_dのラッパーだけでなく、luaの一部が必要になる場合があります。



ここからライブラリソースをダウンロードできます。



また、優れた作業とアイデアを提供してくれたk_dにも感謝します!



みなさん、ありがとうございました! そして、はい、アヒルが勝利します! いたずら!



All Articles