[開発]引数が不明な関数インターセプター

たまにたまたま、MMOゲームのクライアントをさまざまな種類のユーティリティのトピックで分析したり、特定のゲームの側面のアクションに関する情報を取得したりするのが楽しいことがあります。 情報のほとんどは、IDA ProまたはOllyDbgでのクライアント解析から取得されます。



私はこのアクションの経験があまりないので、通常は関数をささいな方法で取り、dllインターセプターを作成し、インターセプト中に受け取った関数の引数を分析します。



残念ながら、IDAでさえ理想的ではありません。trueの関数引数を取得することはしばしば問題です(最も単純な例はlua関数で、lua_stateはintとしてIdaによって定義されます)。 そして、クライアントがそれを分析すると、dllは、無作法な量の関数、それらの宣言と説明、およびその他の良いものだけで成長することがあります。 その結果、数キロメートルのコードが得られます。



しかし、私たちのほとんどの美しい生活への欲求-したがって、このコードを何らかの方法で「タンピング」して、より読みやすくしたいという欲求があります。 たとえば、dllを作成するときは、マクロ、リージョンを使用するのが好きで、同じタイプの関数の数を減らすなどの可能性があります。



そして、少し前に、関数、変数、その他の良さの宣言と説明を1つのマクロに圧縮することで、コードをさらに圧縮するというアイデアを得ました。 理想的には、インターセプトされた関数の引数リストをファイルにドロップします。 現時点では、__ cdecl関数用の比較的普遍的なインターセプターを作成しました(この分野の知識レベルは私にとってあまり高くないため、Windows x86でのみ適切に機能すると想定できますが、他にもいくつかの制限があります)。 傍受のために、私は通常Detours x86、時には単純なアナログを使用します。



実際には、コード:



#define cdecl_hook(name1)\ /*Macro definition*/ void name1##_hook(int a1, ...)\ /*Declare hooker*/ {\ int check_s = 0;\ __asm{mov check_s, esp}\ /*Save esp state*/ int *ptr = &a1;\ /*Get pointer to 1st arg, equialent of va_list*/ debug_msg("Advanced",true,"--%s arg list started--", __FUNCTION__);\ /*debug_msg() - vfprintf wrapper*/ for(int i=0; i*4<name1##_arg_amount; i++)\ {\ debug_msg("Advanced",true," |---Element %d: %d", i, ptr[i]);\ }\ /*Arg list -> file(Advanced.txt)*/ debug_msg("Advanced",true,"--arg list finished--\n");\ __asm{lea ecx, a1}\ /*Move addr of a1 to ecx*/ __asm{mov eax, name1##_arg_amount}\ /*move size of args in stack(can get from IDA, for ex.) to eax*/ __asm{label_loop: }\ /*Start loop*/ __asm{mov ebx, dword ptr[ecx+eax-4]}\ /*Move args from stack to ebx in loop and push ebx*/ __asm{push ebx}\ __asm{sub eax,4}\ __asm{cmp eax,0}\ __asm{jg label_loop}\ __asm{call dword ptr[name1##_Detour]}\ /*Call original function*/ __asm{mov esp, check_s}\ /*Restore stack, same as __asm{add esp, name1##_arg_amount}*/ }\
      
      







 #define RF_O_UP_FUNC(name1, address, args)\ /*Define needed functions and variables*/ typedef void (* t##name1 ) ();\ /*__declspec(dllexport) */t##name1 name1##_Detour = ( t##name1 ) ( address );\ /*Define original function and bind to addr*/ void name1##_hook(int a1, ...);\ /*Define hooker*/ int name1##_arg_amount = args;\ /*Summary size of args in stack, can get from IDA*/ cdecl_hook(name1); /*Call hooker definition*/
      
      







さて、実際には、これらすべてを宣言する例:



 RF_O_UP_FUNC(resources, 0x687054, 0x4C); RF_O_UP_FUNC(hooker, 0x17E4D18, 7); RF_O_UP_FUNC(begin, 0x689BA0, 5);
      
      







そのため、1行でインターセプター関数を宣言し、インターセプトする関数とアドレスを指定し、インターセプトするときに引数のリストを取得します(この例では、すべての引数はintとしてファイルに書き込まれ、マクロに形式を追加できます)。



その後、すべてが簡単です-Detoursを使用すると、添付ファイルは次のようになります。

DetourAttach(&(PVOID&)resources_Detour, resources_hook).







残りは、原則として、説明を必要としません。



引数の出力例:



 --resources_hook arg list started-- |---Element 0: 204181 |---Element 1: 204181 |---Element 2: 1277574 |---Element 3: 1363294854 |---Element 4: 1 |---Element 5: 0 |---Element 6: 0 |---Element 7: 0 |---Element 8: 0 |---Element 9: 0 |---Element 10: 0 |---Element 11: 0 |---Element 12: 0 |---Element 13: 0 |---Element 14: 0 |---Element 15: 0 |---Element 16: 1 |---Element 17: 100 |---Element 18: 1 --arg list finished--
      
      







全体として、いくつかの小さなマクロの助けを借りて、コードをうまく取得する機会を得ました。

短所:

1)現在、__ stdcall、__ thiscallおよびその他の呼び出し規則では機能しません。 この問題に関するヘルプやアドバイスを拒否しません。

2)すでに述べたように、この問題の経験は非常に小さいため、考慮していない妨害が存在する可能性があるため、あまり荒らさないでください。

3)アナログが見つかりませんでしたが、これは適切な方法がないことを意味するものではなく、現在の方法を最適化することは不可能です。 このテーマに関するコメントも歓迎します。



ご清聴ありがとうございました!



All Articles