Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
eBPFを用いたAndroid向けデバッガ「eDBG」のx86_64 Linuxへの移植
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Arata
January 31, 2026
19
0
Share
eBPFを用いたAndroid向けデバッガ「eDBG」のx86_64 Linuxへの移植
Arata
January 31, 2026
More Decks by Arata
See All by Arata
デコンパイラ研究調査
arata_nvm
1
5
コンパイラ基盤を支える言語たち
arata_nvm
1
64
LLVMのDSL”TableGen”向け言語サーバーの開発
arata_nvm
0
16
5分でわかるPage-Fault Weird Machine
arata_nvm
2
160
Pythonのcopy-and-patch JITの実装を読む
arata_nvm
0
130
eBPFを使った動的解析手法
arata_nvm
1
780
カーネルハック実験の振り返り
arata_nvm
1
57
Improving LLVM Backend Development with a New TableGen Language Server
arata_nvm
0
51
コードエディターのシンタックスハイライトの話
arata_nvm
0
240
Featured
See All Featured
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
380
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
930
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.1k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.7k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
210
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
1.1k
The agentic SEO stack - context over prompts
schlessera
0
790
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
520
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Building an army of robots
kneath
306
46k
How GitHub (no longer) Works
holman
316
150k
Abbi's Birthday
coloredviolet
2
7.8k
Transcript
eBPFを用いたAndroid向けデバッガ「eDBG」の x86_64 Linuxへの移植 2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 安藤慎
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 eDBG: https://github.com/ShinoLeah/eDBG • ARM64 Android向けデバッガ
• ptraceを使わずeBPFでデバッガのコア機能を実装 背景: eDBGとは #2
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 ptraceに依存しない、検知されにくいデバッガが欲しい • 一般的なデバッガはptraceシステムコールに依存している • ptraceに対するanti-debug手法は一般に知られており、検知が容易
◦ ptrace(PTRACE_TRACEME)の戻り値をチェック ◦ /proc/self/statusのTracerPidの値をチェック 背景: eDBGのモチベーション #3
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 以下の2点を大課題のゴールとして設定した • eDBGをx86_64 Linux向けに移植する •
GDBのRemote Protocolを話せるようにする 大課題のゴール #4
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 GDBでリモートデバッグするためのプロトコル QEMU, BitVisor, cloud-hypervisorなどが対応している 補足1:
GDB Remote Protocolとは #5 GDB Remote Protocol Host B eDBG デバッグ対象の プログラム 制御 Host A GDB 命令の例: • レジスタの値取得 • メモリの値取得 • BPを設定 • 継続実行 ※BP: BreakPoint
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 「フックポイント」通過時にユーザーコードを実行できるLinuxの機能 フックポイントの例: • syscalls ◦
システムコール • kprobe / kretprobe ◦ カーネル空間のコード • uprobe / uretprobe ◦ ユーザー空間のコード 補足2: eBPFとは #6 https://ebpf.io/ja/what-is-ebpf/
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 openatシステムコールが呼ばれた時に、 どのコマンドが何をopenしたのか表示するeBPFプログラムを実行 補足2: eBPFの使用例 #7
# bpftrace -e ' tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args.filename)); }' Attaching 1 probe... node /proc/1062521/cmdline cpuUsage.sh /etc/ld.so.cache [...]
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 「helper関数」を呼び出すことでOSの情報を取得・変更できる • bpf_probe_{read, write}_user() ◦
ユーザー空間のメモリ読み書き • bpf_probe_read_kernel() ◦ カーネル空間のメモリ読み込み • bpf_send_signal() ◦ プロセスにシグナルを送信 • bpf_current_task(), bpf_task_pt_regs() ◦ プロセスのstruct task_struct, struct pt_regsを取得 ◦ 汎用レジスタの値の取得に使える 補足2: eBPFで実行できる機能 #8
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 以下の2つが実現できればデバッガはおおむね実装できる • プロセスを特定の場所で停止・再開させる ◦ 「特定の場所で」:
フックポイントで場所を指定 ◦ 「停止・再開させる」: SIGSTOP, SIGCONTをプロセスに送信 • 停止した時点でのプロセスの状態を調べる ◦ レジスタ: eBPFでstruct pt_regsを取得 ◦ メモリ: process_vm_{read, write}v()システムコールを利用 ◦ その他: /proc/{pid}/ 以下を利用 実装: 基本的な実装方針 #9
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 実装: 実装した機能 #10 機能 GDB
eDBG エントリポイントでのブレーク ptrace(PTRACE_TRACEME) eBPF + tracepoint ソフトウェアブレークポイント ptrace(PTRACE_POKETEXT) eBPF + uprobe ハードウェアブレークポイント ptrace(PTRACE_POKEUSER) eBPF + perf_event システムコールキャッチ ptrace(PTRACE_SYSCALL) eBPF + tracepoint シングルステップ実行 ptrace(PTRACE_SINGLESTEP) eBPF + uprobe 継続実行 ptrace(PTRACE_CONT) eBPF + uprobe
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 実装: 実装した機能 (cont’d) #11 機能
GDB eDBG レジスタの読み込み ptrace(PTRACE_GETREGSET) eBPF レジスタの書き込み ptrace(PTRACE_SETREGSET) 未実装 メモリの読み込み process_vm_readv() メモリの書き込み process_vm_writev()
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 使用するフックポイント: sys_exit_execve execve()システムコール実行直後でフック 実行するeBPFプログラム: 1.
bpf_send_signal(SIGSTOP)でプロセスを止める 2. レジスタ等の状態を親プロセスに送る 実装: エントリポイントでのブレーク #12
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 使用するフックポイント: sys_exit_execve execve()システムコール実行直後でフック 実行するeBPFプログラム: 1.
bpf_send_signal(SIGSTOP)でプロセスを止める 2. レジスタ等の状態を親プロセスに送る 実装: エントリポイントでのブレーク #13
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 使用するフックポイント: uprobe プログラムの特定のアドレスでフック 実行するeBPFプログラム: 1.
bpf_send_signal(SIGSTOP)でプロセスを止める 2. レジスタ等の状態を親プロセスに送る 実装: ソフトウェアブレークポイント #14
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 使用するフックポイント: perf_event 特定のアドレスを実行、もしくはアクセスした場合にフック 実行するeBPFプログラム: 1.
bpf_send_signal(SIGSTOP)でプロセスを止める 2. レジスタ等の状態を親プロセスに送る 実装: ハードウェアブレークポイント #15
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 使用するフックポイント: sys_enter, sys_exit システムコールが呼ばれる直前、直後をフック 実行するeBPFプログラム:
1. bpf_send_signal(SIGSTOP)でプロセスを止める 2. レジスタ等の状態を親プロセスに送る 注意: sys_enterでシステムコールの引数等は取得できるが、 ブレークはできない 実装: システムコールキャッチ #16
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 1. 現在停止しているアドレスの命令を取得 ◦ ディスアセンブルにはcapstoneを使用 2.
命令と現在の状態から1命令実行後のアドレスを予測 3. 予測したアドレスにブレークポイントを仕掛けて継続実行 予測ロジック: • RET: スタック上のリターンアドレスでブレーク • CALL: 呼び出し先でブレーク • JUMP/条件付きJUMP: 分岐条件をチェック、分岐先でブレーク 実装: シングルステップ実行 #17
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 1. 子プロセスにSIGCONTを送信 2. waitpid()システムコールで子プロセスが再び停止するまで待機 実装:
継続実行 #18
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 各eBPFプログラムで以下の処理を行う 1. bpf_get_current_task()でプロセスのstruct task_structを取得 ◦
セグメントレジスタ、浮動小数点レジスタが見える 2. bpf_task_pt_regs()でプロセスのstruct pt_regsを取得 ◦ 汎用レジスタが見える 3. 取得した値をeBPF Mapでデバッガに送る 実装: レジスタの読み込み #19
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 • おそらく実装できない • struct pt_regsを書き換えれば良いように思えるが、eBPFプログラム
からカーネル空間へのメモリ書き込みは許可されていない 実装: レジスタの書き込み #20
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 • 補助ベクタの取得 ◦ /proc/{pid}/auxvの内容を返す ◦
エントリポイント、ベースアドレスなどの情報が含まれる • ホストでのfile操作(open, readlink, pread, close) ◦ /proc/{pid}/cwdやライブラリ等を読む • デバッグ対象プログラムのファイルパスの取得 • デバッグ対象プロセスのpidの取得 • 各セクションのオフセットの取得 実装: その他実装したRemote Protocolの機能 #21
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 以下の2点に関してeDBGを評価した • ptraceに対するanti-debugの回避 • GDBとのパフォーマンス比較
環境: • OS: Ubuntu 24.04.3 LTS (x86_64) • CPU: AMD Ryzen 5 5600H • Memory: 12GB • GDB: 15.0.50.20240403-0ubuntu1 評価 #22
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 以下の手法でptraceを検出するプログラムanti-ptraceを作成し、 GDBとeDBGで検知結果を確認した • /proc/self/statusのTracerPidの値をチェック ◦
0以外の値 → デバッグされている可能性がある • ptrace(PTRACE_TRACEME)の戻り値をチェック ◦ EPERMエラーが返る → デバッグされている可能性がある 評価: ptraceに対するanti-debugの回避 #23
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 $ ./anti-ptrace pid = 340401
[check_tracerpid] /proc/self/status ... OK [check_ptrace_traceme] ptrace(PTRACE_TRACEME) ... OK 評価: ptraceに対するanti-debugの回避(結果) #24 そのまま実行 → 検知されなかった ⭕
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 評価: ptraceに対するanti-debugの回避(結果) #25 $ gdb
-nx -q ./anti-ptrace (gdb) r [...] pid = 341440 [check_tracerpid] /proc/self/status ... TRACED (TracerPid: 341379) [check_ptrace_traceme] ptrace(PTRACE_TRACEME) ... TRACED GDBでデバッグ → 検知された ❌
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 評価: ptraceに対するanti-debugの回避(結果) #26 $ cargo
run -- ./testdata/anti-ptrace (別ウィンドウのgdbからアタッチ、継続実行) [...] pid = 342918 [check_tracerpid] /proc/self/status ... OK [check_ptrace_traceme] ptrace(PTRACE_TRACEME) ... OK eDBGでデバッグ → 検知されなかった ⭕
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 以下にブレークポイントを設定し、継続実行を繰り返したときの実行時間 をそれぞれ比較した • 関数呼び出し (loop_func)
• システムコール呼び出し (loop_syscall) 評価: GDBとのパフォーマンス比較 #27
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 関数do_something()を10000回呼び出すプログラム 評価: GDBとのパフォーマンス比較 (loop_func) #28
#define N 10000 void do_something() {} int main(void) { for (uint64_t i = 0; i < N; i++) { do_something(); } }
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 システムコールgetpid()を10000回呼び出すプログラム 評価: GDBとのパフォーマンス比較 (loop_syscall) #29
#define N 10000 int main(void) { for (uint64_t i = 0; i < N; i++) { getpid(); } }
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 それぞれ3回計測を行い、その平均を算出した 評価: GDBとのパフォーマンス比較(結果) #30 実行時間
[秒] BPなし GDBserver eDBG loop_func 0.070 12.4 11.0 loop_syscall 0.071 17.3 8.76 GDBと比較して高速化を達成した • loop_func: 約1.13x 高速化 • loop_syscall: 約1.97x 高速化
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 明確な理由は不明 • int3を使う点はGDB, eDBG (uprobe)ともに同じ
◦ この点では大きな差異は生じないはず • 継続実行でシステムコールの発行回数が違う可能性 ◦ GDB: ptrace(POKETEXT → SINGLESTEP → POKETEXT → CONT) ◦ eDBG: kill(SIGCONT) • eDBGはBPを削除してもint3にパッチしたままで、i-cacheが効いてい る可能性 考察: loop_funcで高速化を達成した要因 #31
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 eBPFでは特定のシステムコール呼び出しに限ってSIGSTOPを送ることが 可能なためと思われる • ptrace(PTRACE_SYSCALL)はすべてのシステムコールでブレークする ◦
ブレークさせるかの判定はユーザー空間で行われる • eBPFでは特定のシステムコールでのみブレークさせられる ◦ ブレークさせたいシステムコール番号をeBPF Mapで共有している ◦ sys_exitでこのeBPF Mapを見て必要な場合にのみSIGSTOPを送る ◦ ブレークさせるかの判定はカーネル空間で行われる プログラムの特性によってはさらに高速化の恩恵を得られる可能性がある 例: キャッチしたいシステムコールの呼び出し頻度が少ないプログラム 考察: loop_syscallで高速化を達成した要因 #32
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 • システムコールの呼び出し直前でブレークできない • レジスタの値の変更ができない •
マルチプロセス・マルチスレッドへの対応が難しい ◦ 任意の時点でプロセス・スレッドにアタッチして即座に状態を 取得できる必要がある ◦ eBPFは受動的に情報を取得するので、原理的に難しい ◦ 例: スレッド1でブレーク→スレッド2も一緒に停止するため、 発火させられるフックポイントがない=状態を取得できない • 実行のために強い権限が必要 課題: eBPF由来の制約が大きい #33
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 • eBPFベースのデバッガ「eDBG」をx86_64 Linuxへ移植した ◦ GDB
Remote Protocolへの対応を新規に追加した ◦ ブレークポイントの追加・削除のオーバーヘッドを削減した • GDBと比較して検知されにくく、低オーバーヘッドである ◦ ptraceを使用しないため、一部のanti-debugを回避できる ◦ eBPFを使用して、ブレークポイントのオーバーヘッドを抑えられる • インタラクティブにデバッグを行うための機能は一部実装が難しい ◦ eBPFがトレース目的の機能であるため リポジトリ: https://github.com/arata-nvm/eDBG-x64 まとめ #34
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 • 実はあまりない ◦ eBPFのポータブル性やGDBのマルチアーキ対応のおかげ •
レジスタセットの違いの対応は必要 ◦ x86_64とARM64ではレジスタセットが異なる ◦ struct pt_regsの構造も異なる ◦ アーキごとに適切な場所を読む 付録: x86_64 Linux移植にあたっての課題 #35
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 • GDBはブレークポイントの追加・削除を頻繁に行う ◦ プログラムが実行中の間のみブレークポイントを設定する ◦
そのために毎回実行前にBP追加、実行後にBP削除を行う • eBPFプログラムのアタッチ・デタッチ操作は重い ◦ GDBからの指示そのままに操作を行うと非常に動作が遅くなる ◦ 対処として、基本デタッチを行わず、eBPF MapでBPの有効/無効 を制御することで高速化した ◦ 一時的にBPを追加するシングルステップ実行は依然として遅い 付録: GDBとeBPFの相性が悪い点 #36
2026/01/30 情報システム実験B「バイナリプログラムの解析」 最終発表会 | 安藤慎 • GDB Remote Protocolのサポートのためgdbstubクレートを利用した ◦
多数のコマンドへの対応、アーキテクチャの定義など手厚い • サーバーとの通信を1文字づつ行うよう実装されている ◦ この点がパフォーマンス上のネックとなっていた ◦ Buffered IOを実装したところ、実行時間が大幅に改善された ◦ 例: loop_syscall ▪ 改善前: 49.8 秒 ▪ 改善後: 8.76 秒 付録: gdbstubクレートにおける改良 #37