動作を解析されないようにするには

参考書籍 : たのしいバイナリの歩き方



・アンチデバッギングの手法
初歩的なデバッガ対策として、IsDebuggerPresent()やCheckRemoteDebuggerPresent()がある。
これらの関数で、デバッガを検知できる。
popfを使いTF(Trap Flag)を1にし、デバッガに次の1命令を実行してSINGLE_STEP例外を発生させる方法がある。
デバッガはSINGLE_STEP例外をキャッチするため、SINGLE_STEP例外がキャッチされなかった場合に(プログラムがキャッチした場合に)検知されたくない処理を行う

bool bNoDebugger = FALSE;
	__try{
		_asm
		{
			pushfd
			or dword ptr[esp], 0x100
			popfd // Trap Fragをセット
			nop
		}
	}	
	__except (EXCEPTION_EXECUTE_HANDLER) {
		// 例外がデバッガにキャッチされない→デバッグされていない
		bNoDebugger = TRUE;
	}

	printf(bNoDebugger ? "No Debugger\n": "In Debugger\n");

	return 0;

参考 : Anti-Debugging: Detecting System Debugger

また、int 2dhで割り込みを発生させると、デバッギングされていなければEIPがインクリメントされ、1バイト命令がスキップされる。
デバッギングされていると例外をデバッガがキャッチするため、命令のスキップは起こらない

__asm {
		xor eax, eax // set Z flag
		int  2dh
		inc  eax // debugger might skip
		je   being_debugged
being_debugged:
		// ...
}

参考 :
windows - INT 2D Anti-Forensic Method - Reverse Engineering Stack Exchange
Dr. Fu's Security Blog: Malware Analysis Tutorial 4: Int2dh Anti-Debugging (Part II)



・コードを難読化して解析されるのを防ぐ
IsDebuggerPresent呼び出し部分を難読化する。
f:id:kamishiroHW:20200614114106p:plain
f:id:kamishiroHW:20200614114117p:plain
呼び出し分のマシン語は、ff 15 00 20 40なので、先頭にebを付けeb ff 15 00 20 40とする。
f:id:kamishiroHW:20200614114235p:plain
eb ffがjmp short near ptr _main+1に置き換わるが、eb ffは1バイト先にジャンプするという命令なので、問題なくcallされる。



・実行ファイルを実行できる状態のまま圧縮する
圧縮するためのソフトをパッカーと言い、有名なパッカーとしてUPXがある。
また、アンチデバッギングを目的としたパッカーもあり、ASPackなどがある。
パッキングをすると、IDAなどで解析しづらくなる。
例えば、パックする前は処理の流れを簡単に追うことができるが、
f:id:kamishiroHW:20200614120839p:plain
パック後は処理を追うのがとても難しくなる。
f:id:kamishiroHW:20200614120905p:plain



・UPXを手動でアンパックして仕組みを理解する
ASLRなしでコンパイルした.exeファイルをUPXでパックし、OllyDbgで開く
f:id:kamishiroHW:20200614131543p:plain
最初にpushad命令でスタックに全レジスタの値をコピーしている
処理をすすめると、popad命令が見つかる。
f:id:kamishiroHW:20200614131728p:plain
その次のジャンプ命令を飛んだ先で、OllyDumpを呼び出す
f:id:kamishiroHW:20200614131826p:plain
ダンプされたファイルをIDAで開くと、ソースコードそのままの処理がされていることがわかる
f:id:kamishiroHW:20200614131959p:plain
処理を眺めると、pushadとpopadの間で展開処理を行い、popadでレジスタを復元し本処理を行っていると分かる。



・ハードウェアブレイクポイントを使ってASPackをアンパックする
ASPackでパックされたコードも、基本的にはpushadとpopadを探せば良い
今まではソフトウェアブレイクポイント(該当アドレスの命令をccに書き換え)を使ってきたが、今回はハードウェアブレイクポイントを使う。
ハードウェアブレイクポイントは、処理を停止する場所をDRレジスタに書き込むという仕組みで、
このアドレスに書き込み/読み込みが起きたら停止させるなど、ソフトウェアブレイクポイントよりも柔軟な使い方ができる。
DRレジスタには限りがあるので、ハードウェアブレイクポイントは4つまでしかセットできない点に注意する。
ASPackでパックされた.exeファイルを開くと、最初にpushadが見つかる。
今回はpopadの探索を省略し、00401000にハードウェアブレイクポイントをセットする。
f:id:kamishiroHW:20200614134208p:plain
セットしたら実行する。00401000で処理が止まるので、Ctrl+A(コードの再解析)を押して表示されたコードを確認する。
f:id:kamishiroHW:20200614134348p:plain