Upgrade to Pro — share decks privately, control downloads, hide ads and more …

eBPFを使った動的解析手法

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Arata Arata
September 23, 2025
660

 eBPFを使った動的解析手法

Avatar for Arata

Arata

September 23, 2025
Tweet

More Decks by Arata

Transcript

  1. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata 導入: rev問題における動的解析 • 動的解析: バイナリを実際に動かして解析する手法

    • 問題によって異なるアプローチが求められる ◦ 例: gdb, strace, バイナリパッチ, VM改変 など • 様々な動的解析の手法を知り、使い分けることが重要 → 本発表ではeBPFを使った動的解析手法について紹介 2
  2. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata 用意された「フックポイント」通過時にコードを実行できる フックポイントの例: • syscalls ◦

    システムコール • kprobe / kretprobe ◦ カーネル空間のコード • uprobe / uretprobe ◦ ユーザー空間のコード ◦ 今回特に重要 eBPFがトレースできるもの 6 https://github.com/bpftrace/bpftrace
  3. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata Delve: https://github.com/go-delve/delve • Golang向けデバッガー •

    関数呼び出し時の引数と戻り値をトレースする機能で試験的にeBPF を利用 • ptraceと比較して高速な点がeBPF利用の主な動機 ◦ ptrace: ブレーク毎にユーザー空間にスイッチする ◦ eBPF: カーネル空間でブレークを処理、一定単位でデータを取得 デバッガーにおけるeBPFの利用 #1 7 https://developers.redhat.com/articles/2023/02/13/how-debugging-go-programs-delve-and-ebpf-faster
  4. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata eDBG: https://github.com/ShinoLeah/eDBG • Android向けデバッガー •

    ptraceを使わずeBPFでデバッガーのコア機能を実装 • 本来eBPFはトレース対象のプログラムを停止しない ◦ トレース対象のプログラムにSIGSTOP/SIGCONTを送信 ◦ これによってインタラクティブな操作を実現 • anti-debugの回避がeBPF利用の主な動機 デバッガーにおけるeBPFの利用 #2 8
  5. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata 問題概要 • よくあるcrackme問題 • 実行するとフラグの入力を求め、正しいか判定する

    実例 #1: gomen (SatokiCTF 2024) 12 https://tan.hatenadiary.jp/entry/2024/08/28/021429#Rev-easy-gomen-2-teams-solves-200-points
  6. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata デバッガーの検知方法 • /proc/self/statusのTracerPidを監視する ◦ TracerPidはptraceでアタッチしているプロセスのPID

    ◦ TracerPid = 0: プロセスはアタッチされていない ◦ TracerPid ≠ 0: プロセスはアタッチされている • gdb, strace, ltrace等でアタッチすると検知されてしまう 実例 #1: gomen (SatokiCTF 2024) 14
  7. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata 方針 • 天啓: 復号した正解フラグを引数にstrlen,memcpy関数が呼ばれる •

    ltraceで関数呼び出しをトレースしたいが、今回は難しい • eBPFでltraceっぽいことをしてみる 実例 #1: gomen (SatokiCTF 2024) 15
  8. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata eBPFを用いた解法 • bpftraceを使用 ◦ DSLを用いてeBPFによるトレースを行えるツール

    • libcの関数が呼ばれたら、その第一引数を表示したい • DSLでの記法 ◦ libcの関数が呼ばれたら: uprobe:libc:* ◦ その第一引数を表示する: print(str(arg0)) • 実行するとフラグが得られた 実例 #1: gomen (SatokiCTF 2024) 16
  9. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata 問題概要 • よくあるcrackme問題 • 実行するとフラグの入力を求め、正しいか判定する

    • 0 solves 実例 #2: AVX-512 (IERAE CTF 2025) 17 https://gmo-cybersecurity.com/blog/ierae-ctf-2025-writeup-reversing/
  10. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata 問題の特徴 • 命令の実行フローを動的制御して難読化 ◦ EFLAGSのTrap

    flagを立てて、1命令実行毎にSIGTRAPを送信 ◦ シグナルハンドラでRIPを操作して実行フローを動的制御 ◦ 様々な命令が乱雑に置かれていて、それらを適切な順番でピック して実行していくイメージ • フラグの判定ロジックがAVX-512を使用 実例 #2: AVX-512 (IERAE CTF 2025) 18
  11. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata 難読化手法とGDBの相性の悪さ • 実行された命令をGDBでトレースしたい • しかしGDBは以下の機能のためにSIGTRAPを使う

    ◦ ブレークポイント ◦ ステップ実行 • 1命令実行毎にSIGTRAPが送信されるプログラムでは GDBがまともに使えない 実例 #2: AVX-512 (IERAE CTF 2025) 19
  12. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata 公式Writeupの方針 • 実行フローの制御ロジックを静的解析 • 実行される命令をシミュレートして難読化解除

    シミュレート実装における様々な落とし穴 • syscall命令でのTrap flagのクリア • sub命令によるループ • add命令による条件分岐 実例 #2: AVX-512 (IERAE CTF 2025) 20
  13. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata eBPFを用いた解法の問題点 • フラグの判定ロジックは複数パートに分かれており、不正解だと分 かった時点で早期returnする •

    つまり実行された判定ロジックしかわからない • 正解した扱いにするにはレジスタの書き換えが必要だが、eBPFでは 不可能 ◦ 一方でメモリの書き換えは可能 実例 #2: AVX-512 (IERAE CTF 2025) 23 https://devblog.lac.co.jp/entry/20220620
  14. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata • 既存のツールでトレースを取れない場合に、代替ツールとしてeBPF が使える可能性がある ◦ 特にstraceやltraceの代替として

    • プログラムの状態を書き換えつつトレースを取りたい場合には不向き ◦ 使えるなら素直にgdb scriptを使った方が早い ここまでのまとめ 24
  15. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata eBPF(特にuprobe)によるトレースを防ぐことは可能か? トレースの検知 • int3命令の存在確認 •

    リターンアドレスの検証 • [uprobes]領域の存在確認 トレースの回避 • コード領域をwrite可能にする anti-eBPF 26
  16. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata eBPF(特にuprobe)によるトレースを防ぐことは可能か? トレースの検知 • int3命令の存在確認 •

    リターンアドレスの検証 • [uprobes]領域の存在確認 トレースの回避 • コード領域をwrite可能にする anti-eBPF 27
  17. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata • uretprobeはトレース対象のリターンアドレスを変更する • リターンアドレスが変化していればトレースされている可能性がある •

    この挙動が原因でGo言語のバイナリでは使えない anti-eBPF: リターンアドレスの検証 29 https://mechpen.github.io/posts/2022-10-30-golang-bpf/ リターンアドレスが[uprobes]領域に向いている様子:
  18. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata • 置換した命令を配置・実行するために[uprobes]領域が確保される a. int3命令でトラップ b.

    [uprobes]領域にコードを生成、RIPを向ける c. コードをシングルステップ実行 d. 元のコードの次の命令にRIPを戻す • /proc/self/mapsに[uprobes]領域があればトレースされている可能 性がある • (推測)この方式はマルチスレッド対応のため? anti-eBPF: [uprobes]領域の存在確認 30 https://blog.quarkslab.com/defeating-ebpf-uprobe-monitoring.html
  19. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata • 命令をエミュレートできる時[uprobes]領域を使用しない • そのような命令はarch_uprobe_analyze_insn関数を読むとわかる ◦

    https://elixir.bootlin.com/linux/v6.16.8/source/arch/x86/ker nel/uprobes.c#L980 ◦ コメントによればpush, nop, jmp, cond jmp命令など • トレース対象の命令が上記になるよう調整すれば回避できる • オフセットでトレース対象を指定するにはbpftraceをbfd有効でビル ドするか、バイナリをstripする anti-eBPF: [uprobes]領域の存在確認(回避) 31 https://www.sh1no.icu/posts/28348c4/
  20. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata eBPF(特にuprobe)によるトレースを防ぐことは可能か? トレースの検知 • int3命令の存在確認 •

    リターンアドレスの検証 • [uprobes]領域の存在確認 トレースの回避 • コード領域をwrite可能にする anti-eBPF 32
  21. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata • uprobeの対象アドレスはvalid_vma関数でチェックされる ◦ https://elixir.bootlin.com/linux/v6.16.8/source/kernel/event s/uprobes.c#L1295

    • アドレスの指す領域がwrite可能だとこのチェックで弾かれる • つまりwrite可能なコード領域にはuprobeを設定できない • チェックされるタイミング ◦ uprobe設定時: eBPFでアタッチしたとき ◦ mmap時: ライブラリがロードされたとき anti-eBPF: コード領域をwrite可能にする 33 https://blog.quarkslab.com/defeating-ebpf-uprobe-monitoring.html
  22. 2025/09/23 魔女のお茶会 #8(2025 夏) @Arata eBPFについて • 『Binary Hacks Rebooted』

    #50 • 『入門 eBPF』 • https://zenn.dev/hidenori3/articles/e1352e8cfeb2af bpftraceについて • https://github.com/bpftrace/bpftrace?tab=readme-ov-file#exa mple-one-liners • https://www.brendangregg.com/BPF/bpftrace-cheat-sheet.html eBPF, bpftraceの資料 35