2001/3/22

「コードを偽装してみる」

逆アセンブラをかけた時のコードと実際に実行されるコードが 違うというのもパスワード・クラッカーへの良い嫌がらせに なりそうです。例えば下のようなプログラムを考えてみます。

// コード偽装サンプル
// (c) tokai@fides.dti.ne.jp 2001/3/22
#include < windows.h >
#include < stdio.h >

__declspec(naked) void testfunc(){

	_asm{
		add eax,ebx  // 実際は sub eax,ebx が実行される
		ret
	}

}

int main(){

	int result;
	DWORD dwStat;

	VirtualProtect((LPVOID)testfunc,1,PAGE_EXECUTE_READWRITE,&dwStat);
	((UCHAR*)testfunc)[0] = 0x2B;
	VirtualProtect((LPVOID)testfunc,1,PAGE_EXECUTE_READ,&dwStat);

	_asm{
		mov eax,5
		mov ebx,4
		call testfunc
		mov result,eax
	}

	printf("%d\n",result);

	return 0;
}

ぱっと見た感じでは testfunc() の中で 5+4 が計算されて 9 が表示されそう ですが、実際には 5-4 で 1 が表示されます。これは ((UCHAR*)testfunc)[0] = 0x2B; の部分で add eax,ebx が sub eax,ebx に変わるからです。 単に逆アセンブラをかけて メモ帳か何かでコードを見ても add eax,ebx と表示されますので偽装されていることが 分かります。

更に前回の様に data セクションの中からプログラムを 開始してその中でコードを書き換えてみます。

// コード偽装サンプル その 2
// (c) tokai@fides.dti.ne.jp 2001/3/22
#include < windows.h >
#include < stdio.h >

void mainCRTStartup();
void testfunc();

struct ENTRYCODE
{
	unsigned char code[20];
	unsigned long dat[2];
}
entry_code = {
	{	0xE8, 0, 0, 0, 0,   // call [epi+0]
		0x58,               // pop eax
		0x8B, 0x58, 15,     // mov ebx,dword ptr [eax+15]  ebx <- mainCRTStartup
		0x53,               // push ebx
		0x8B, 0x48, 19,     // mov ecx,dword ptr [eax+19]  ecx <- testfunc
		0xC6, 0x41, 0, 0x2B,// mov  byte ptr [ecx+0],2Bh 
		// ↑ add eax,ebx を sub eax,ebx に変更
		0xc3, 0 , 0},		// ret
	{(unsigned long)mainCRTStartup,
	(unsigned long)testfunc}
};   



__declspec(naked) void testfunc(){

	_asm{
		add eax,ebx  // 実際は sub eax,ebx が実行される
		ret
	}

}



int main(){

	int result;

	_asm{
		mov eax,5
		mov ebx,4
		call testfunc
		mov result,eax
	}

	printf("%d\n",result);

	return 0;
}

この時、リンクの設定でエントリポイントシンボルに entry_code を指定し、 更に /section:.text,ewr をオプションとして追加してください (ただし、code セクション全体に write 属性がついてしまうので、 本当は手を抜かずに VirtualProtect API を使うべきです)。 これを実行すると 5-4 が計算されて 1 が表示されます。

とまあ、こういう風にコードを実行中に展開 & 変更したり、data セクションに エントリポイントを作ったり、更にリソースの隠匿や暗号化をしたり 意味のないジャンプやコールを繰り返して eip を飛ばしまくったり、等などを すれば「なんちゃってクラッカー」相手なら十分なクラッキング対策になるのでは ないのでしょうか。もっとも、ここまでやって人間不信っぷりを露呈するよりも 素直にオープンソース化 & サポート有料とした方が健康的な気がしますね。