1

私はここでバイナリ難読化を使用しているので、opコードで満たされたバッファーを取得し、Linuxを使用しているので、すべての関数呼び出しは同じ呼び出し元/呼び出し先の規則を使用し、ここでは問題ありません。

私の質問はE8オペコードについてです。このオペコードは相対アドレスを使用してニアコールを取ります。

私の質問は次のとおりです。私は電話がかかってきた住所を知っています。私は電話をかけなければならない住所を知っています。それで、E8電話に入れなければならないシフトアドレスをどのように見つけることができますか?これは:

signed long src = (signed long)buffer + shift; //get the position where E8 instruction is
signed long dst = (signed long)srand;          //get the destination position where i want to call (yes, srand(long) function in this case.)

だから私のバッファには:

buffer[] = "[....]\xE8\xFF\xFA\xFE\x54[.....]"; //example

srandへの有効なポインタに置き換える必要がありますが、持っているものから相対アドレスを取得するにはどうすればよいですか?

FF命令で直接電話できると思っていたのですが、どうしたらいいのかわかりませんでした。代わりに5を超えるオペコードを入れることができないため(たとえば)$ eaxにアドレスをコピーできません(上記のすべてのjmp呼び出しがバナナになります)。 5バイトで直接呼び出します。

したがって、誰かがE8相対シフトアドレスを置き換えるための正しい値を取得する方法を知っている場合、またはE8呼び出しと同じ機能プロパティを維持し、5バイトだけを使用して何らかの直接呼び出しを行う方法がある場合...

(質問する前に、FF XX XX XX XXを実際のアドレスであるXXとして配置しようとしましたが、機能しませんでした。x86は呼び出しのようには見えず、INC(???)およびランダムとして解釈されます。私はこの方法で交換を試みました:

inline void endian_swap(long& x) {
      x = (x>>24) |
          ((x<<8) & 0x00FF0000) |
          ((x>>8) & 0x0000FF00) |
          (x<<24);
}

endian_swap(dst);
endian_swap(src);
unsigned int p = dst - src;
endian_swap(p);

そして、私が見つけたアドレスをE8コールに入れます。とにかくうまくいきませんでした。

4

2 に答える 2

3

near calland jxx/命令の相対アドレスは、制御を転送するターゲット アドレスからor命令near jmpの直後の命令のアドレスを差し引いたものに等しくなります。相対アドレスは、制御を転送している命令ではなく、次の命令のアドレスに相対的です。IOW、アドレスオペランドが相対である場合、 or命令の長さを考慮する必要があります。calljumpcalljump

call通常、5 バイト以下のorjump命令に相当するものはありません。

+jmpとしてシミュレートできますが、任意のターゲット アドレスを使用する 32 ビット モードでは、これら 2 つの命令で少なくとも 1+4+1=6 バイトが得られます。同じ方法でシミュレートできますが、戻りアドレスをスタックに配置するために別のor命令を追加する必要があります。したがって、これらの 6 バイトにさらに 5 バイトを追加します。push target addressretcallpushcall

アドレスオペランドをターゲットオフセットとターゲットセグメントで構成される即値として受け取る「jmp」(およびIIRC「call」も)の「絶対」バージョンがあります。このような命令は、少なくとも 1+4+2=7 バイトの長さになります (オフセットに 4 バイト、セグメント セレクタに 2 バイト)。

指定したメモリ位置 (例: ) からターゲット アドレスを取得するcallorのバリアントを使用する場合、その命令は少なくとも 1+1=2 バイト (オペコード + ModR/M バイト) の長さになりますが、ターゲットアドレスを含むそのメモリ位置のアドレスをレジスタにロードすると、さらに1 + 4 = 5バイトのコストがかかり、少なくとも7バイトが得られます。レジスタでターゲット アドレスを指定できるバリアントもありますが (例: )、レジスタをロードする必要があるため、少なくとも 7 バイトになります。jmpcall [ebx]jmp ebx

call/命令を短くする唯一の方法jumpは、ターゲット アドレスがその命令のアドレスに非常に近い場合です (この場合、rel16フォーム (適切なオペランドまたはアドレスを使用) を使用できます (どちらかは覚えていません))。オーバーライド プレフィックス) またはrel8利用可能な場合はフォーム) または、ターゲット アドレスが小さい場合 (この場合push target addressは、より短いpush Ibか、またはより短いoperand size prefix + push Iw)。

于 2012-05-31T14:15:22.503 に答える
2

私はそれを次のようにして解決しました:

long dst = (long)srand;
long src = ((long)buffer) + shift + 5; //begin of buffer + actual position + this instruction size
long p = dst - src;
p = htonl(p);

バッファの呼び出しを置き換えるよりも、すべてがうまく機能します。

于 2012-05-31T13:54:40.577 に答える