「コードを偽装してみる」
逆アセンブラをかけた時のコードと実際に実行されるコードが 違うというのもパスワード・クラッカーへの良い嫌がらせに なりそうです。例えば下のようなプログラムを考えてみます。
// コード偽装サンプル // (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 を飛ばしまくったり、等などを すれば「なんちゃってクラッカー」相手なら十分なクラッキング対策になるのでは ないのでしょうか。もっとも、ここまでやって人間不信っぷりを露呈するよりも 素直にオープンソース化 & サポート有料とした方が健康的な気がしますね。