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