
通常のコードで「余分な」アセンブラコマンドを非表示にする方法について説明します。 このメソッドは、特に「非表示」コマンドの生成が自動化されている場合に、コードの逆アセンブリを複雑にするのに役立ちます。
ツールキット:OllyDbgデバッガー。
奇妙な奇妙なコード
次のコードを見てください。一見してわかるよりも多くのコマンドが隠されています。
MOV EAX,1EBC031
MOV EBX,90DB3190
CMP EAX,EBX
JNE SHORT 0000009E
NOP
(アセンブラーを使用してこのコードの断片をOllyDbgに挿入するのは難しい場合があるため、組み込みのHEXエディターを使用することをお勧めします。「B8 31 C0 EB 01 BB 90 31 DB 90 39 D8 75 F3 90」)
EAXとEBXは等しくないため、このコードは無期限に実行され、JNEチームはこれら2つのレジスタが同じになるまで最初のチームの領域に移行すると思いますか?
最後のNOPステートメントにブレークポイントを設定して実行し、結果を確認しましょう。

ブレークポイントを設定し(アドレスは赤で強調表示され、実行位置は黒です)、開始ボタンを押します。

開始後、実行プロセスは目的のポイントで停止しました。
奇妙なことに、プログラムはフリーズせず、レジスタEAXとEBXの値はゼロに等しい。 しかし、これはどうして起こるのでしょうか?
コードを詳しく見てみましょう。 最初のコマンドは値1EBC031をEAXレジスタに入れ、2番目のコマンドは値90DB3190をEBXに入れます。 CMPは2つのレジスタを比較します。 レジスタ値が一致しない場合、JNEは遷移を行います。 ここで最も興味深いのは、遷移が最初のコマンドの先頭ではなく、最初のコマンドの2番目のバイトにあることです。 1つのコマンドでコードをトレースしてみましょう。
最初の位置に置きます。

コマンドは通常どおり実行されます。

...そして、我々は移行に着きます。

短い移行が完了しましたが、何が見えますか? 2つの隠しコマンド-XOR EAX、EAXはEAXレジスタのゼロ化を実行します。

そして、別のMOV内で制御を移す短い移行。


別の場所が残った:)

2番目のレジスタをゼロにする

チェックに行きます。 現時点では、EAXおよびEBXレジスタはゼロです。

検証に成功しました。


実際には、素数ではなく、コマンドのマシンコードがEAXレジスタに書き込まれます。 このような「オーバーレイ」のため、アセンブリ言語でコードを表示することは実際上不可能です。 アセンブラーコマンドのサイズは異なります。 コマンド "MOV EAX、1EBC031"は5バイトかかりますが、コマンドとしてはXOR EAX、EAX-2バイトです。 バイナリシフトコマンドとセミレジスタALおよびAHを使用して、これらの「ジャンプ」を使用して、EAXレジスタ全体を処理および入力できます。
マシン命令をMOVパラメーターとして挿入する場合、バイトシーケンスを変更する必要があることに注意してください。たとえば、MOVコマンドに配置された31COコマンド(XOR EAX、EAX)は「MOV EAX、C031」のようになります。
この方法は多くのソフトウェア保護システムで使用されており、移行を見つけるのが困難です。 また、レジスタに入力された値は、XOR方式を使用した単純な暗号化に使用できます。 アセンブラーコードを小さなフラグメントに再コンパイルするプロセスを自動化するプログラムを作成して、リバースエンジニアリングプロセスを確実に複雑化できると思います。
32ビットレジスタに加えて、64ビットシステムには64ビットレジスタがあります。これらはRAX、RBX、RCX、RDXです。 彼らは2倍以上のチームを配置できます。
アセンブリコードをアプリケーションに挿入する
高レベルの開発環境の標準ツールを使用できます。C++の場合-このコードは次のようになります。
int someint=123; __asm { MOV EAX, someint INC EAX // ... MOV someint,EAX }
Delphiの場合:
変数someint:整数。 somelong:倍長整数;
begin
asm
mov ax,i
mov ebx,somelong
// ...
end;
end.
OllyDbgを使用して、コード用のスペースを事前に割り当てることができます。
同時に、アセンブラコードの一部を挿入するプログラム自体がいくつかのレジスタを使用することを忘れないでください。したがって、変更するまでレジスタの値を保存することを忘れないでください(PUSH)。