記事について
今回は、マルウェア解析で欠かせない動的解析を行うときに使用するツールについて、動作の確認も含めながら、まとめていく。
ツール
ネットワーク系
【 tcpdump 】
検体を実行する前に起動して、検体が行う通信内容について記録する。
- 【起動コマンド】
sudo tcpdump -i any -w capture.pcap -s 0
-i any 全インターフェースを監視
-w capture.pcap 書き出しファイル
-s 0 パケット全体をキャプチャ(デフォルトだと一部が切り詰められることがある)
WireSharkでも可能!
ただ、検体の実行中は複数のツールを実行するので、tcpdumpの様なCUIツールのほうがごちゃごちゃしない気がする。
解析に関しては、もちろんwiresharkのほうがやりやすいと思う。
【 fakenet 】
名前の通り、擬似的なネットワークを提供するツール。
- 【起動コマンド】
sudo fakenet
- 【設定】(defaultからの変更点)
| 項目 | 初期値 | 変更後 |
|---|---|---|
| NetworkMode | Auto | SingleHost |
| LinuxFlushDNSCommand | service dns-clean restart | true |
| ResponseA | 192.0.2.123 | 127.0.0.1 |
| LinuxRestrictInterface | off | ens33 |
実際に動作の確認
fakenetを起動した状態で、別のターミナルからnc接続を試みてみる。
- nc
remnux@remnux:~$ nc example.com 1337
test
test
^C
- fakenet側
09/17/26 11:54:16 AM [ Diverter] nc (4320) requested UDP 172.16.95.128:53
09/17/26 11:54:16 AM [ DNS Server] Received A request for domain 'example.com' from nc (4320)
09/17/26 11:54:16 AM [ Diverter] nc (4320) requested TCP 127.0.0.1:1337
09/17/26 11:54:24 AM [ RawTCPListener] 0000: 74 65 73 74 0A test.
DNSでの名前解決、更にNCのrawデータの受け取りに成功している。
システムコール・プロセス系
【 strace 】
プログラムを実行時に、システムコールの詳細をを時系列順にログを残してくれる。
- 【起動コマンド】
strace -f -o trace.log ./a.out
-f follow forksの略。子プロセスも追跡する。
-o trace.log 出力ファイル
./a.out 記録したい対象ファイル
このコマンドは実際にプログラムを実行して記録する。
実際に動作の確認
【検体コード】
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(void) {
int fd = open("/etc/hostname", O_RDONLY);
char buf[128];
ssize_t n = read(fd, buf, sizeof(buf));
write(1, buf, n);
close(fd);
return 0;
}
- 実行してみる
gcc test.c
strace -f -o trace.log ./a.out
- ログを見てみる
#ライブラリのロードなども出ている
##### 略 #######
4484 openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
4484 read(3, "remnux\n", 128) = 7
4484 write(1, "remnux\n", 7) = 7
4484 close(3) = 0
4484 exit_group(0) = ?
4484 +++ exited with 0 +++
【 sysdig 】
システムコール、ファイル操作、ネットワーク通信、プロセスの生成・終了を丸ごと録画・分析できるツール
- 【起動コマンド】
sudo sysdig -w capture.scap
-w capture.scap 出力ファイル
実際に動作の確認
-
記録方法
起動しながら、別のターミナルでa.outを実行した
実行後はCtrl+Cで止める -
読み込み
# そのまま出力
sysdig -r capture.scap
# プロセス名で絞り込み
sysdig -r capture.scap "proc.name=a.out"
# ファイルアクセスを見る
sysdig -r capture.scap "evt.type=open or evt.type=openat"
# プロセスツリーを見る
sysdig -r capture.scap -c spy_users
# ネットワーク接続の一覧を見る
sysdig -r capture.scap -c spy_ip
困ったら、以下のコマンドで使えるchisel一覧を確認できる
sysdig -cl
プロセス系
プロセスの生成・終了を追う専用ツール(ps auxf, auditd等)も検討したが、前述のSysdigがevt.type=execve等でシステムコールレベルのプロセス生成イベントを既にカバーしているため、今回は専用ツールの追加導入は見送った。
ファイル系
【 aide 】
ファイルやディレクトリの「ハッシュ値」・「権限」・「有無】等をデータベースで管理し、変化した事項を検知する。
- 設定ファイル
監視する領域等を指定できる。
/tmp VarFile
/etc VarFile
/var VarFile
/root VarFile
/home VarFile
!/proc
!/sys
!/dev
!/var/log
!/var/cache
すべてのディレクトリ・ファイル(ルート配下)をやろうとすると、めちゃめちゃ重たい。
実際に動作の確認
- 【初期DB作成コマンド】
sudo aideinit
- 変更を加えてみる
chmod 777 /tmp/test.txt #ファイルの権限変更
touch /tmp/newfile #新規ファイルの作成
- 【比較コマンド】
sudo aide --config=/etc/aide/aide.conf --check
Start timestamp: 2026-09-18 13:36:20 +0000 (AIDE 0.18.6)
AIDE found differences between database and filesystem!!
Ignored e2fs attributes: EINV
Summary:
Total number of entries: 37134
Added entries: 3
Removed entries: 0
Changed entries: 1
---------------------------------------------------
Added entries:
---------------------------------------------------
f+++++++++++++++++: /tmp/newfile
d+++++++++++++++++: /var/tmp/systemd-private-b99b1dba387f4596bc5ca6aeffcc181d-falcoctl-artifact-follow.service-GRtDaS
d+++++++++++++++++: /var/tmp/systemd-private-b99b1dba387f4596bc5ca6aeffcc181d-falcoctl-artifact-follow.service-GRtDaS/tmp
---------------------------------------------------
Changed entries:
---------------------------------------------------
f p.. . A. . : /tmp/test.txt
---------------------------------------------------
Detailed information about changes:
---------------------------------------------------
File: /tmp/test.txt
Perm : -rw-rw-r-- | -rwxrwxrwx
ACL : A: user::rw- | A: user::rwx
A: group::rw- | A: group::rwx
A: other::r-- | A: other::rwx
---------------------------------------------------
The attributes of the (uncompressed) database(s):
---------------------------------------------------
/var/lib/aide/aide.db
MD5 : cswDUIamYT9VT7VOv7EcuQ==
SHA1 : 9shOEPKs/VJ0zqgZlLuELJJINBg=
SHA256 : 4zFulLJMpEEHT6s+hFx/0o/nSy7vxfcW
dYqMNQ1B9Hw=
SHA512 : aSU4CNGOETj8p6e+tCIE8CqPiQ9tfpOi
vskr0ostBkoZFgdSzYeGE2tvOjH+WNkM
3NMW2z6RnYUPFzo4bvHVOw==
RMD160 : vGw8HueUVOsFBwpQeQ/6eMDNWA4=
TIGER : 1EpKFZ3wwYt1UOBhpqMEw/UlENWRN/KP
CRC32 : cGKkfg==
CRC32B : 5tCtcQ==
HAVAL : c7GEy8B9LNulwFL4rUaq/hlFLEw2YdjM
o2iK3HmGtlQ=
WHIRLPOOL : XJlWtOAaB4B1ee0DWqMqmiFrhDPzNM7S
7vePAariy1/uBs2409myOB7Pwn9qZXXo
eenE5QaTs+jgg2XcrlzVkA==
GOST : gf/o5jngM7+QKhR9PZnmFmD9rJBW0XMN
7oCfHxRmYtk=
End timestamp: 2026-09-18 13:36:37 +0000 (run time: 0m 17s)
メモリ系
【 gcore 】
指定したプロセスのメモリをダンプできる。
- 【起動コマンド】
sudo gcore -o dump <PID>
-o dump 出力ファイル
実際に動作の確認
- テストプログラム
#include <stdio.h>
#include <unistd.h>
unsigned char fake_ip[4] = {131, 123, 40, 104};
char fake_marker[32] = "HELLO_FROM_HEAP_OR_DATA";
int main(void) {
printf("PID: %d\n", getpid());
printf("fake_ip address: %p\n", (void *)fake_ip);
printf("fake_marker address: %p\n", (void *)fake_marker);
printf("Sleeping for 60 seconds...\n");
for (int i = 0; i < 60; i++) sleep(1);
return 0;
}
- テストプログラムを実行して、ダンプする。
./test &
sudo gcore -o dump 9701 #テストプログラムによって出力されたPIDを指定
- dumpから検索文字列を検索してみる
remnux@remnux:~$ strings dump.9701 | grep "HELLO_FROM_HEAP"
HELLO_FROM_HEAP_OR_DATA
remnux@remnux:~$ od -A x -t x1 dump.9701 | grep "83 7b 28 68"
002410 00 00 00 00 00 00 00 00 83 7b 28 68 00 00 00 00
【 LiME 】
システム全体のメモリをダンプできる
- 【導入方法】
git clone https://github.com/504ensicsLabs/LiME.git
cd LiME/src
make
lime-6.8.0-71-generic.ko
みたいなファイルができていればOK
- 【起動コマンド】
sudo insmod lime-6.8.0-71-generic.ko "path=/tmp/remnux_ram.lime format=lime"
path=/tmp/remnux_ram.lime 出力ファイル
実際に動作の確認
上記コマンドを実行後、指定した出力先にメモリのサイズ程度のファイルが生成されればOK
【 Volatility3 】
システム全体のメモリをダンプしたファイルの解析が容易にできるツール。
実際に試した結果
LiMEで取得したダンプに対しbanners.Banners(シンボル不要)を実行したところ、カーネルバナー文字列を正常に検出できた。
一方、プロセス一覧を見るlinux.pslist等は、対象カーネルバージョンに対応するシンボルテーブルが必須であり、Ubuntu(ddebs)・Parrot(独自ビルド)いずれの環境でも入手できなかったため実行できなかった。
Linux環境でのVolatility運用は、ディストリビューションによってシンボル取得の難易度が大きく異なり、特に独自ビルドのカーネルを使う環境(Parrot)では、公式配布物に頼れず、カーネル自体のリビルドという重い作業が必要になる
メモリ解析時の注意
検証のため、RemnuxのようなVM環境ではなく、ホストOS(Parrot, RAM 16GB)でも同様にLiMEを試した。結果、ダンプ取得に約20分を要し、その間GUI操作が完全にブロックされる状態になった。
デスクトップ通知を確認したところ、LiME自体のメモリ消費によりLinuxカーネルのOOM Killerが発動しFirefoxが強制終了されていたことが判明した。
「メモリを調べるツールが、メモリ不足を引き起こす」という状況であり、実機でこの種のツールを試す際は、事前に不要なアプリケーションを終了し、十分な空きメモリを確保しておく必要がある。
さらに、volatilityでbanners.Bannersプラグインでの解析中、本来のホストOS(Parrot)のカーネルバナーだけでなく、同時に起動していたRemnuxVMのカーネルバナーも検出された。これは、ハイパーバイザーがゲストOSに割り当てたメモリが実際にはホストの物理メモリ上に存在するためであり、ホストOS側でのメモリダンプ取得は、意図せず稼働中の仮想マシンの内容まで巻き込んでしまう可能性がある、という重要な注意点である。
最後に
これらを駆使して、現在行っているマルウェア解析の動的解析フェーズへ突入していく。