#include <stdio.h>
#include <windows.h>
typedef BOOL(*IS_DEBUGGER_PRESENT)(void);
int debug_flag = -12;
IS_DEBUGGER_PRESENT proc;
void proc_set(){
char name[] = "IrFffpa`m{Zyi~kad";
int i,size=strlen(name);
i = 0;
while(i < size){
name[i] ^= i;
i++;
}
proc = (IS_DEBUGGER_PRESENT)GetProcAddress(GetModuleHandle("kernel32.dll"),name);
memset(name,0,size);
}
void check(int n){
debug_flag += proc()+1;
if(n>0){
check(n-1);
}
}
main(){
BYTE a[4];
do{
proc_set();
check(8);
*(int*)&a[3+debug_flag] = 0x12345678;
}while(a[1]!=0x56);
printf("ok");
getchar();
return 0;
}
前提知識:C言語全般、win32API基礎、IsDebuggerPresentはデバッガーを検出すると1を返す関数でkernel32.dllの中に含まれている事。
まず、procとdebug_flagをグローバル領域(動的ではなく固定割り当て)にする事で、探索必要領域を広げ見つけ辛くさせる。
GetProcAddress経由でIsDebuggerPresentのアドレスを取得する事で、使用している外部関数の列挙から逃れる。
GetProcAddress関数を呼ぶ際に使う”IsDebuggerPresent”文字列は暗号化した状態で保持し、なおかつ無駄な関数呼び出しをすることでデコード後もメモリーに残らなくする。
(暗号化が適当なのは仕様、一応書きやすいようASCII文字範囲から抜けないようにという意図がある)
IsDebuggerPresentを呼び出した前後では判定を行わない、なおかつflagを直接if文で使わず配列への代入位置とし間接的な判定を行うことで、万が一場所が割れても安易にif文を変更できないようにした。
デバッガー検出した場合に終了するのではなくループさせ続ける事で、判定箇所を特定し辛くした。
(オーバーフローの危険性があるが、むしろその方が解析ミスを疑わせられるためあえてこうしてある)
ちなみに、このデバッガー検出を突破する方法は、IsDebuggerPresent側を改造して常に0を返させればいいだけ。
解析改造とは常にイタチゴッコである。