6

いくつかのアセンブリ コードがあり、C++ コードからすべての関数を実行できるように、呼び出し関数のプロトタイプを見つけたいと考えています。

私が実際にやろうとしているのは、実行中のプロセスに dll を挿入し、実行中のプロセスの関数を dll から呼び出すことです。現在、dll の注入に成功しましたが、「呼び出し」を行う方法がわかりません。

私は初心者で、アセンブリ コードについて少ししか知りません。私のdllはVisual C++ 2012で書かれています。

実行中のプロセスのコードは次のとおりです。

CPU Disasm
Address   Hex dump          Command                                  Comments
6013BE24  /$  53            PUSH EBX
6013BE25  |.  8B1D 10461860 MOV EBX,DWORD PTR DS:[60184610]
6013BE2B  |.  8B1B          MOV EBX,DWORD PTR DS:[EBX]
6013BE2D  |.  8B40 04       MOV EAX,DWORD PTR DS:[EAX+4]
6013BE30  |.  FFD3          CALL EBX
6013BE32  |.  5B            POP EBX
6013BE33  \.  C3            RETN

関数を6013BE30呼び出しており、関数 (EBX) が004BAFAC

CPU Disasm
Address   Hex dump          Command                                  Comments
004BAFAC  /$  55            PUSH EBP                                 ; Test.004BAFAC(guessed void)
004BAFAD  |.  8BEC          MOV EBP,ESP
004BAFAF  |.  53            PUSH EBX
004BAFB0  |.  8BD8          MOV EBX,EAX
004BAFB2  |.  8B43 08       MOV EAX,DWORD PTR DS:[EBX+8]
004BAFB5  |.  E8 3EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFBA  |.  8B43 0C       MOV EAX,DWORD PTR DS:[EBX+0C]
004BAFBD  |.  E8 36F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFC2  |.  8B43 14       MOV EAX,DWORD PTR DS:[EBX+14]
004BAFC5  |.  E8 2EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFCA  |.  8B43 18       MOV EAX,DWORD PTR DS:[EBX+18]
004BAFCD  |.  E8 26F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFD2  |.  8B43 1C       MOV EAX,DWORD PTR DS:[EBX+1C]
004BAFD5  |.  E8 1EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFDA  |.  8B43 10       MOV EAX,DWORD PTR DS:[EBX+10]
004BAFDD  |.  E8 16F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFE2  |.  8B43 20       MOV EAX,DWORD PTR DS:[EBX+20]
004BAFE5  |.  E8 0EF40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFEA  |.  8B43 44       MOV EAX,DWORD PTR DS:[EBX+44]
004BAFED  |.  E8 06F40B00   CALL 0057A3F8                            ; [Test.0057A3F8
004BAFF2  |.  8B43 44       MOV EAX,DWORD PTR DS:[EBX+44]

004BAFACでは、Visual C++ からat 関数を呼び出す方法は?

4

2 に答える 2

2

アセンブリ関数では、引数は最後の引数から始めてスタックからポップされます。したがって、引数を関数に渡すには、最初に引数をスタックにプッシュしてから、関数を呼び出します。MASMでは、これはメッセージボックスを表示するために次のようになります。

.data 
MsgBoxCaption  db "Attention",0 
MsgBoxText     db "Hello Message Box!",0 

.code
start:
push 0
mov eax, offset MsgBoxCaption
push eax
push offset MsgBoxText
push 0
call MessageBoxA
call ExitProcess
end start

C ++では、次のようになります。

int retval = MessageBox(NULL, "Hello Message Box!", "Attention", 0);

OllyDbgで分解すると、次のようになります。

CPU Disasm
Address   Hex dump          Command                                  Comments
011D13C0  |.  6A 00         PUSH 0                                   ; /Type = MB_OK|MB_DEFBUTTON1|MB_APPLMODAL
011D13C2  |.  68 54571D01   PUSH OFFSET 011D5754                     ; |Caption = "Attention"
011D13C7  |.  68 3C571D01   PUSH OFFSET 011D573C                     ; |Text = "Hello Message Box!"
011D13CC  |.  6A 00         PUSH 0                                   ; |hOwner = NULL
011D13CE  |.  FF15 40831D01 CALL DWORD PTR DS:[<&USER32.MessageBoxA> ; \USER32.MessageBoxA

戻り値はeaxに格納されます。DWORD(4バイト)より大きいデータ型の場合、実際には値ではなく参照を渡していることがわかります。各引数は実際には単なるDWORDです。これは、スタックが32ビットシステムで32ビット整列されているため、32ビット値しか保持できないためです。レジスタの場合も同様です。32ビットシステムでは、レジスタは32ビット幅です。文字列を渡す場合は、文字列や文字/バイトの可変幅配列ではなく、文字列への参照を渡します。整数の場合、参照ではなく値として渡される可能性があります。MASMでプロトタイピング機能を使用する場合、すべてのパラメーターをDWORDとしてプロトタイピングします(C ++では機能しません)。

したがって、上記の例では、スタックに渡されるパラメーターが1つあるようです(プッシュebx)。後で取得するためにebxがプッシュされて保存されている可能性があるためです(つまり、呼び出しebxが再度ポップされた後、ebxに保存されている値を保持する必要がある可能性があります)。実際にライブデバッグセッションを実行し、スタック/レジスタを監視している場合にのみ、確実に判断できます。呼び出しをステップオーバーし、前後のスタックポインター(esp)をチェックして、関数に渡される引数の数を確認します(ここでも、1つの引数= 1 DWORD = 4バイト)。

C ++で関数のプロトタイプを作成するには、引数がどのデータ型であるかを理解する必要があります。おそらく、アセンブリコードをシングルステップで実行し、問題の関数の周りのコードをトラバースしながらレジスタやスタックをチェックします。eaxの戻り値についても同じことが言えます。したがって、eaxは文字列を保持することはなく、文字列への参照を保持する可能性がありますが、32ビット以下の整数を保持する可能性があります。周囲のコードも逆にして、eaxがどのような種類のデータを指しているのかを知る必要があります。

編集:実際、私が書いたものの半分は間違っていました。特にパラメーターは常に参照であるため、私が書いたものをもう一度読んでください。ご不便をおかけして申し訳ありません-疲れている質問に答えるべきではありません:)

于 2013-03-10T15:16:06.240 に答える
2

詳細がなければ、何が起こっているのかを判断するのは非常に困難です。異常なコードのため、アプリが難読化されていると思われます。あなたはIDAでもっとうまくいくかもしれません。

簡単な答えは、すべての関数が何かへのポインターを取るように見えるということですeax(0057A3F8代わりに 4 バイトの整数を取る場合があります)。これらが何へのポインタであるかを判断するのは困難です。C++ からこれらを呼び出すには、おそらくアセンブリ ヘルパーが必要になるでしょう。


最初に、呼び出し規約を解決する必要があります。 と の両方が単一の引数を取るように見えます6013BE24ウィキペディアのこのリストによると、これは Borland (fastcall)、Watcom (デフォルト)、または Embarcadero Delphi でのみ使用されます。リバース エンジニアリングしているアプリが C++ で記述されているかどうかはわかりませんが、C++ で記述されている場合でも、少し組み立てないと呼び出すのは難しいと思います。004BAFACeax

6013BE24関数テーブル内の関数を次のように検索しているように見えますebx=**(void***)0x60184610(ポインタからポインタへのポインタから関数へのポインタがどのように見えるかは忘れました)。これがどこかの再配置テーブルを指しているかどうかを確認します。また、eax(のようなものstruct Foo { void * dummy; Bar * bar; ... }) の構造体へのポインターを取り、大まかにreturn ebx(eax->bar). 実際に何かを返すかどうかはわかりませんが、レジスタに返されたものは何でも返します。ebx保存する必要のないレジスタの代わりに使用する理由がわかりません。

004BAFACスタック フレームを設定し、 を保持してから、 (eax などの)内のものを使用して をebxいくつか呼び出します。が の場合、次のようになり、再度ロードされます(そして、分解が終了します)。実際にはある種の構造体だと思います。0057A3F8barbarvoid**f(bar[2]); f(bar[3]); f(bar[5]); f(bar[6]); f(bar[7]); f(bar[4]); f(bar[8]); f(bar[17]);bar[17]bar

0057A3F8では単一の引数を取るようeaxです。

于 2013-03-10T17:14:49.160 に答える