耐解析機能とは?
こちらの記事を見てもらうと仕組み等はわかると思います。
今回の記事は、耐解析機能を実装してみるお話です。
そして、あわよくば、自ら耐解析機能を無効化して解析に挑戦します。
3種類に挑戦!!
アンチデバッガー
実装方法
IsDebuggerPresent()の戻り値がBOOLなので、そのままif文に渡してあげるだけですね。
#include <windows.h>
#include <stdio.h>
int main()
{
if (IsDebuggerPresent()) {
printf("debug now!!");
}
else {
printf("No debug");
}
getchar();
}
APIすら呼び出さない方法
PEBへのポインタを直接取得して、**BeingDebuggedの値を直接読む**#include <windows.h>
#include <stdio.h>
int main()
{
#ifdef _M_X64
PBYTE p = (PBYTE)__readgsqword(0x60);
#else
PBYTE p = (PBYTE)__readfsdword(0x30);
#endif
if (p[2]) {
printf("debug now!!");
} else {
printf("No debug");
}
getchar();
}
この機能の無効化は、フラグの書き換えかジャンプ命令の書き換えが有効だと思われる。
解析方法
x64dbgから実行しようとすると、もちろんデバッガーを検出する。

x64dbgで IsDebuggerPresentを呼び出しているところを探して、その1行下のtest命令で比較しているところにブレークポイントの設置

設置したブレークポイントまで進んだところで、、
今回は、APIの戻り値を書き換える。
RAXの値を 1 → 0
※変更後

実行してみるとアンチデバッガー機能を無効化できた。

アンチVM
実装方法
今回は以下のレジストリの値を基に判断する機能を作成します。
HKEY_LOCAL_MACHINEのHARDWARE\\DESCRIPTION\\System\\BIOSを開き、BIOS Vendorの値にVMwareという文字列が含まれていたら、VMと判断します。
#include <windows.h>
#include <stdio.h>
int main()
{
HKEY hKey;
LONG result;
// キーを開く
result = RegOpenKeyExA(
HKEY_LOCAL_MACHINE,
"HARDWARE\\DESCRIPTION\\System\\BIOS",
0,
KEY_READ,
&hKey
);
if (result != ERROR_SUCCESS) {
printf("Key open failed\n");
return 1;
}
char buffer[256];
DWORD bufferSize = sizeof(buffer);
DWORD type;
// 値を取得
result = RegQueryValueExA(
hKey,
"BIOSVendor",
NULL,
&type,
(LPBYTE)buffer,
&bufferSize
);
if (result == ERROR_SUCCESS) {
printf("Value: %s\n", buffer);
if (strstr(buffer, "VMware") != NULL) {
printf("This is VM!!!!");
}
else {
printf("No VM....");
}
}
else {
printf("Query failed\n");
}
RegCloseKey(hKey);
getchar();
return 0;
}
解析方法
もちろん、VM上で実行すると検出する。

ghidraで見てみると、
RegOpenKeyでHKLM¥HARDWARE¥DESCRIPTION¥System¥BIOSを開いて、
RegQueryValueでBIOSVendorの値を読み取っていることが分かる。

試しにVM上のレジストリのBIOSVendorを書き換える。(Dellっぽくしてみた。)

改めてVM上で実行してみると、、、

パッカー
実装方法
- お好みの実行ファイルを用意します。(今回は"hello world"を表示するだけのELF)
- UPXをインストールします。
- 以下のコマンドを実行
hello.c
#include <stdio.h>
int main(void){
printf("Hello world!\n");
return 0;
}
$upx hello
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2024
UPX 4.2.4 Markus Oberhumer, Laszlo Molnar & John Reiser May 9th 2024
File size Ratio Format Name
-------------------- ------ ----------- -----------
15952 -> 5812 36.43% linux/amd64 hello
Packed 1 file.
- upxのシグネチャを破壊します。
※簡単ですが、意外と多くのマルウェアで使われているらしい。。。
【書き換え前】
略
000000e0: 1000 0000 0000 0000 b4fd 70eb 5550 5821 ..........p.UPX!
略
【書き換え後】
略
000000e0: 1000 0000 0000 0000 b4fd 70eb 5858 5821 ..........p.XXX!
略
これでupxコマンドではアンパックできなくなる
解析方法
動きの確認
$./hello
Hello world!
手始めにupxコマンドの動きを確認してみる
$upx -d hello
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2024
UPX 4.2.4 Markus Oberhumer, Laszlo Molnar & John Reiser May 9th 2024
File size Ratio Format Name
-------------------- ------ ----------- -----------
upx: hello: CantUnpackException: l_info corrupted
Unpacked 1 file: 0 ok, 1 error.
シグネチャを破壊するだけでアンパックできなくなるが、実行は可能
シグネチャをもとに戻すだけでアンパック可能になる。
いつか、マニュアルアンパックができるようになったら、その記事も公開します。
ひたすら挑戦中です。