概要
オープンされているオブジェクトハンドルをクローズするWin32 APIの関数です。無効なハンドルや保護されたハンドルを指定することでデバッガーを検出することが可能です。
関数のプロトタイプは以下のとおりです。
C++
BOOL CloseHandle(
[in] HANDLE hObject,
);
第一引数のhObjectに無効なハンドルを指定することで、実行中のプロセスがデバッグされている場合、STATUS_INVALID_HANDLE(0xC0000008)例外が発生します。これにより、デバッガーの存在を検出することが可能です。
このほかにも、保護されたハンドルを使用する方法も存在します。保護されたハンドルを第一引数のhObjectに指定し、実行中のプロセスがデバッグされていた場合は、EXCEPTION_HANDLE_NOT_CLOSABLE(0xC0000235)例外が発生します。
実装の例
無効なハンドルを指定し、STATUS_INVALID_HANDLE(0xC0000008)例外によりデバッガーを検出するC++/x86 Assemblyのコード例を以下に示します。
C++
DWORD dCode;
__try {
CloseHandle((HANDLE)0xDEADBEEF);
}
__except (dCode = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER) {
if (dCode == EXCEPTION_INVALID_HANDLE) {
exit(1);
}
}
Assembly(x86)
push 0FFFFFFFFh
push offset _scopetable_entry
push offset _except_handler3
mov eax, large fs:0
push eax
mov large fs:0, esp
sub esp, 16
push ebx
push esi
push edi
mov [ebp+ms_exc.old_esp], esp
mov [ebp+ms_exc.registration.TryLevel], 0
push 0DEADBEEF ; hObject
call CloseHandle
loc_debugger_not_found:
; ---------------------------------------------------------------------------
loc_except_filter:
mov eax, [ebp+ms_exc.exc_ptr]
mov eax, [eax]
mov eax, [eax] ; GetExceptionCode()
mov [ebp+var_20], eax
mov [ebp+dCode], eax
mov eax, 1
retn
; ---------------------------------------------------------------------------
loc_except:
mov esp, [ebp+ms_exc.old_esp]
cmp [ebp+dCode], EXCEPTION_INVALID_HANDLE
jnz short loc_debugger_not_found
push 1
call exit
回避手法
CloseHandleによるデバッガー検出を回避し、プログラムを解析する手法を以下に示します。一時的に検出を回避するときには1、2の手法を、恒久的に検出を回避するときには3の手法を使います。
- デバッグ中にレジスタやメモリ上の値を変更する
GetExceptionCodeの戻り値の値を変更します。 - プラグインを利用する
ScyllaHide(x64dbgなどで利用可能なプラグイン)の”NtClose”の項目にチェックを入れます。 - プログラムを書き換える
CloseHandleの処理をNOP命令に書き換え、変更を保存します。
検出手法
CloseHandleのSTATUS_INVALID_HANDLE(0xC0000008)例外によるアンチデバッグ機能を有するファイルを検出するYARAルールは以下のとおりです。
YARAルール
rule Win32API_CloseHandle
{
strings:
$str = "CloseHandle"
$hex = {81 [1-2] 08 00 00 C0}
condition:
$str and $hex
}