# bata24/gefの機能紹介とか 2025
###### tags: `gef` `gdb` `ctf`
# はじめに
この記事は[CTF Advent Calendar 2025](https://adventar.org/calendars/12609) の2日目の記事です.
1日目は[@sters9](https://x.com/sters9)さんの「[数億年ぶりにCTFやってる,あるいはDaily AlpacaHackの紹介 | ごみばこいん](https://gomiba.co/archives/2025/12/7309a707-5447-42d5-a648-da1cf911faf2/)」でした.
もともと書く予定はなかったのですが,枠が空いていたので参戦します.
CTF Advent Calendar向けの記事なのか?という疑問はあるかと思いますが,CTFer向けのツールということでご容赦ください.
# タイトルのbata24/gefって何?
gdb拡張スクリプト[GEF](https://github.com/hugsy/gef)のfork版で,https://github.com/bata24/gef のことです.
主にCTFerとカーネル解析者向けに機能拡張しています.
詳しく知りたい方は,過去のCTF Advent Calendarにも記事を投稿しているので,参照してみてください.
- CTF Advent Calendar 2020: [gefを改造した話](https://hackmd.io/@bata24/rJVtBJsrP)
- CTF Advent Calendar 2022: [bata24/gefの機能紹介とか](https://hackmd.io/@bata24/SycIO4qPi)
- CTF Advent Calendar 2024: [bata24/gefの機能紹介とか 2024](https://hackmd.io/@bata24/SJOzjzqQ1e)
----
# 追加したコマンドの数
以下は2025/12/22時点でのGEFのロード画面です.

素のgdbにないコマンドが394コマンドです.
去年の12月時点では342コマンドでしたので,52個のコマンドが増えたことになります.
- 既存コマンドを複数コマンドに分割したケース(=実際には新機能でない)
- 既存コマンドにオプションを追加したケース(=新機能だがコマンド数に変化はない)
- 既存コマンドの内部動作を変更したケース(=新機能だがコマンド数に変化はない)
- bata24/gefの仕様上,コマンドがサブコマンドを持つ場合はそれぞれを1つとしてカウントする(=親コマンドは機能を持たない,グルーピング用途でしかない)
などがあるため,コマンド数=新機能の数 ではないですが,この記事ではここ1年で作った新しい機能を中心に紹介していこうと思います.バグフィックスや,あまり重要ではない機能追加については触れません.
# ユーザランド関連
## `tls`コマンド (機能追加)
TLS(Thread Local Storage)付近のメモリをダンプする機能です.
glibcのデバッグ情報がある場合,`-s`オプションで,TLS付近の構造体メンバを表示するようになります.

## `avx512`コマンド (新規作成)
`AVX512`関連のレジスタをダンプする機能です.

AVX512(`zmm`レジスタ関連)は,業務サーバ用CPU(Xeonなど)で使える命令セットです.普通の家庭用マシン向けのCPU(Core i7など)ではサポートされないので,通常利用では使うことはないでしょう.
ただCTFではAVX512関連の問題が出るかもしれません.
IntelSDEを使ってエミュレーションしながらデバッグすることになると思われ,そういった時に使えると思います.
なお,`zmm`レジスタへの書き込みは`xmmset`コマンドが対応しています.
## `find-syscall`コマンド (新規作成)
ユーザランドのメモリ中で,`syscall`呼び出しの箇所を特定する機能です.
[scwuaptx/Pwngdb](https://github.com/scwuaptx/Pwngdb)の機能を輸入しました.

## `fpchain`コマンド (新規作成)
`__IO_list_all`を辿ってダンプする機能です.
[scwuaptx/Pwngdb](https://github.com/scwuaptx/Pwngdb)の機能を輸入しました.

似たような機能で`stdio-dump`コマンド(`stdin`/`stdout`/`stderr`のメンバをまとめてダンプする機能)がありますが,`__IO_list_all`を辿るかどうかが違いです.
## `load-file`/`load-file-mmap`コマンド (新規作成)
ホスト環境上の指定ファイルを,ユーザランドのメモリにマップする機能です.

- `load-file`コマンド: すでに存在するメモリに書き込む
- `load-file-mmap`コマンド: 新しくメモリを確保して書き込む

## `munmap`コマンド (新規作成)
`munmap`システムコールを簡単に呼び出すラッパーです.
`mmap`コマンドはあったのに,`munmap`はなかったので作りました.
## `unicorn-emulate`コマンド (機能追加)
`unicorn`を使って,アセンブリ命令の実行結果をエミュレーションする機能です.
このコマンド自体はオリジナルの[hugsy/gef](https://github.com/hugsy/gef)にもあったものです.

ただ`unicorn`がサポートしていない命令はエミュレーションできないなど,一部使い勝手が悪いところがありました.
そのため以下の機能を追加しています.
- AVXやNeonによる最適化された`memcpy`などを使わないように,GOTにパッチを当ててから実行する機能(`-A`オプション)
- `mmap`, `munmap`, `brk`をなるべくエミュレーションする機能(`-E`オプション)
- ARM64の命令の一部をエミュレーション(`-I`オプション)

`unicorn-emulate`コマンドは,後述の`heap try-free`コマンドなどから内部的に呼び出されるのですが,上記改善を導入したことによって,エミュレーションの成功率が上がり,かなり実用的になりました.
## `angr`コマンド (機能追加)
`angr`を使って,制約条件を解決するコマンドです.
よくあるrev問向けに,`find`アドレス群(`-f`)と`avoid`アドレス群(`-a`),そしてシンボリックに計算を進めたいメモリのアドレスと長さ(`-s`)を指定するだけで使える,非常に便利なものです(必要に応じて文字種を指定することもできます(`-t`).

ただし`angr`は,カナリアチェックを行う関数を通過するとき,必ず失敗します.
おそらくシンボリック実行する際に,カナリア値の一致性チェックができないからでしょう(bata24/gefが,メモリダンプした値を元に`angr`を走らせるという,特殊な使い方をしているからかもしれませんが).
そこで`__stack_chk_fail`のPLTにパッチを当て,何もせずリターンするような`-H`オプションを追加しました.
関数末尾が以下のようなコードだと,うまく動くはずです.
```
sub rdx, fs:28h
jz loc_XXX
call __stack_chk_fail@plt ; パッチによってすぐ戻って来る(本来はそのままabortする)
loc_XXX:
xor rax, rax
ret ; 正常リターンする経路
```
あまり無いとは思いますが,以下のようなケースのコードだと誤動作しますので,ご注意ください.
```
sub rdx, fs:28h
jnz loc_XXX
xor rax, rax
ret ; 正常リターンする経路
loc_XXX:
call __stack_chk_fail@plt ; PLTへ行くが,パッチによってすぐ戻って来る(本来はそのままabortする)
; <-- ここを実行しようとするが,retがないのでおかしくなる
```
# ユーティリティ関連
## `tmux-setup`コマンド (新規作成)
`tmux`を使って画面を分割する機能です.`tmux`セッション下で`gdb`を起動する必要があります.

デフォルトでは左右に分割するだけですが,付属のスクリプト[tmux_setup.py](https://github.com/bata24/gef/blob/dev/dev/tmux/tmux_setup.py)をカスタマイズして使えば,任意の画面配置が実現できます.

## `telescope`コマンド (機能追加)
言わずとしれた,メモリの中身を表示するコマンドです.有効なポインタ値であればその参照先まで表示します.
`-f`オプションで,スタックフレーム単位で水平線を入れる機能を追加しました.スタックを表示するときに便利です.

## `symbols`コマンド (機能追加)
GDBが認識している,シンボルの一覧を出力する機能です.

`maintenance print msymbols`のショートカットとして非常に便利なのですが,一覧の生成にとても時間がかかるという問題がありました.
そこで何度もこのコマンドを実行することを想定し,前回の結果(キャッシュ)を再表示することで高速にする,`-c`オプションを追加しています.
また`maintenance print msymbols`の出力に含まれる`*.debug`ファイルのパスはハッシュのような文字列であり,具体的にどのファイルに関するものであるのか分かり辛いという問題があるので,それを特定し併せて表示するようにしています.
## `types`コマンド (機能追加)
GDBが認識している,型情報の一覧を出力する機能です.

`symbols`コマンドと同じく,一覧の生成にとても時間がかかるという問題があったため,同様に`-c`オプションを追加しています.
## `multi-break`コマンド (新規作成)
複数のアドレスに一括でブレークポイントを仕掛ける機能です.

似たような構造を持つ複数の関数に,ベースアドレス+オフセット,のような形でブレークポイントを仕掛ける場合に便利かもしれません.
## `multi-line`コマンド (機能追加)
複数のコマンドを一行で指定する機能です.
`-t <TAG>;`, `--t <TAG>;`, `---t <TAG>;`という,3種のタグ表示を実装しました.

これが意外と便利でして,`command-break`コマンドと組み合わせるととても良かったです.

## `patch range-replace`コマンド (新規作成)
指定範囲のメモリに対し,特定のバイト列を別のバイト列に置換する機能です.

## `call-trace`コマンド (新規作成)
`call`系命令による関数呼び出しのみをピックアップして表示する機能です.
`jmp`系命令は表示しません.

## `exec-until region-change`コマンド (新規作成)
バイナリ本体からglibcに飛ぶ,またはその逆など,メモリマップ基準で実行する領域が変わったタイミングで停止する機能です.
## `history`コマンド (新規作成)
gdbのコマンド履歴を最も古いものから全て表示します.

## `print-format`コマンド (機能追加)
16進数バイト列を整形表示する機能です.
このコマンド自体はオリジナルの[hugsy/gef](https://github.com/hugsy/gef)にもあったものです.

出力フォーマットに`hex`, `hexs`, `hexn`, `hexsn`を追加しています.
- `hex`: HEX出力
- `hexs`: HEX+空白(splitted) 出力
- `hexn`: HEX+改行(newline) 出力
- `hexsn`: HEX+空白+改行 出力
## `json`コマンド (新規作成)
メモリ中,もしくは引数で与えたJSONを,きれいに表示する機能です.

## `crc32rev`コマンド (新規作成)
様々な亜種を含むCRC32の,ASCII範囲での逆算を行う機能です.

プリセットが用意してあるので,細かな値を知らなくても使えます.

もちろん,`poly`や`init_value`などを直接指定することもできます.
## `vdump`コマンド (新規作成)
メモリ内の値を白と黒の濃淡で可視化する機能です.

横幅は,結果がなるべく正方形に近づくように自動的に割り出します.
自分で指定したり,少しずつ変更しながら全パターン出力することもできます.
## `freq-analysis`コマンド (新規作成)
指定範囲のメモリにおいて,各バイト値の出現頻度を可視化する機能です.
外れ値などを除外することもできます(図では0xFFを除外しています).


# ヒープ関連
## `heap tracer`コマンド (機能追加)
`malloc`や`free`をトレースする機能です.
オリジナルの[hugsy/gef](https://github.com/hugsy/gef)にも,`heap-analysis-helper`というコマンドが存在していました.
ただしbata24/gefでは,[Arinerron/heaptrace](https://github.com/Arinerron/heaptrace)のように番号での追跡(図中の`#1`や`#2`など)も実装したかったため,全面的に刷新しています.

これまでは`malloc`と`free`くらいしか追跡していなかったのですが,実は`malloc`以外にも`ptmalloc2`のバックエンドを使ってメモリを確保する経路があります(`realloc`など一部は有名かもしれませんが).
これらは`malloc`を呼び出さないので,`malloc`にブレークポイントを仕掛けても意味がありません.
Glibcのソースコードとにらめっこして洗い出したところ,以下の経路が見つかったので,全部対応しました.
- `realloc`
- `reallocarray`
- `calloc`
- `aligned_alloc`
- `memalign`
- `posix_memalign`
- `valloc`
また,複数スレッドが動くバイナリにも対応しています.
## `heap tcache-index-helper`コマンド (新規作成)
`tcache_perthread_struct`のアドレス計算を手助けする機能です.
bata24/gefからフォークされた[S1uM4i/gef-extra](https://github.com/S1uM4i/gef-extra)で,このような機能を見つけたので,アイデアを拝借して実装しました.

- `-i INDEX`: `&tcache.counts[INDEX]`と`&tcache.entries[INDEX]`のアドレスを表示
- `-c COUNT_ADDR`: `&tcache.counts[i]`のアドレスに対応する`&tcache.entries[i]`のアドレスを表示
- `-e ENTRY_ADDR`: `&tcache.entries[i]`のアドレスに対応する`&tcache.counts[i]`のアドレスを表示
## `heap try-{free,malloc,realloc,calloc}`コマンド (新規作成)
`free()`や`malloc()`などをエミュレーションする機能です.


`heap try-free`コマンド自体は2024年に作ったのですが,それ以外は2025年に作りました.
内部的には,以下のような挙動をしています.
- レジスタを一時的に書き換える (`rax = &malloc`など)
- `call rax`のようなパッチを一時的に当てる
- `unicorn-emulate`コマンドを呼び出し,処理をエミュレーション
- 呼び出し元に返ってくるか,途中でエラーが起きるかによって成否を判定
- 書き換えたレジスタやメモリをすべて元に戻す
pwndbgにも同様のコマンドはありますが,あちらはpython側で`malloc`や`free`の内部ロジックを代わりに評価しているだけです.glibcのバージョンが新しすぎたり古すぎたりすると正しくエミュレーションできないケースがありそうですし,そもそも非glibcの場合には使えません.bata24/gefの`try-XXX`コマンドは,このあたりを考慮した実装になっています(そもそもglibcであること自体に依存しません).
また,`try-free 0x5555555fa9980 -c "visual-heap"`のように,エミュレートしたあとのメモリ状態に対して,任意のコマンドを実行する機能も追加しました.(ダブルクォーテーションのエスケープが必要となり)ちょっと使い辛さはありますが,`try-free 0x5555555fa9980 -c "try-free 0x5555555ab0010 -c \"visual-heap\""`のようにネストすることもできます.
## `heap parse`コマンド (新規作成)
Pwngdbの`parseheap`コマンドっぽく,ヒープを表示する機能です.

## glibc 2.42対応
glibc 2.42では,`tcache_perthread_struct`の構造が変わっています.
bata24/gefの主要なコードでは対応済みです.
## `scalloc-heap-dump`コマンド (新規作成)
[cksystemsgroup/scalloc](https://github.com/cksystemsgroup/scalloc)のフリーリストをダンプする機能です.

## `snmalloc-heap-dump`コマンド (新規作成)
[microsoft/snmalloc](https://github.com/microsoft/snmalloc)のフリーリストをダンプする機能です.

# カーネル関連
## `pagewalk`コマンド (機能追加)
ページテーブルをダンプする機能です.
パーミッションによるカラーリングを導入しました.

## `kvmmap`コマンド (作り直し)
カーネルデバッグ中に,`vmmap`ライクにメモリマップを出力する機能です.

もともとは`pagewalk-with-hints`コマンドとして実装されていましたが,大幅なリファクタリングを行い,コマンド名が変わりました(旧コマンド名でも呼び出せます).時間のかかる処理はデフォルトで無効化することで(必要に応じて`-v`, `-vv`などで有効にできます),実用に耐える速度で表示できるようになりました.
## `ktypes`コマンド (新規作成)
カーネルが`CONFIG_DEBUG_INFO_BTF=y`でビルドされている場合に,メモリ中から型情報を取り出し表示する機能です.

## `ktypes-load`コマンド (新規作成)
カーネルが`CONFIG_DEBUG_INFO_BTF=y`でビルドされている場合に,メモリ中から型情報を取り出し,GDBに取り込む機能です.

## `ksymaddr-remote`コマンド (機能追加)
メモリ中のカーネルの`.rodata`にある`kallsyms`関連の情報から,カーネルの「シンボル-アドレスのペア」を入手する機能です.

ただ手元に`vmlinux`ファイルがある場合,そちらを優先して使いたい方がいるかも知れません.
こういった要望のために,`--vmlinux-file`オプションを追加しました.
`ksymaddr-remote`コマンドが内部的に持つキャッシュを,`vmlinux`ファイル由来の「シンボル-アドレスペア(`kbase`考慮/調整済み)」情報を元に生成します.
### 補足
カーネルの`vmlinux`周りと,GDB,GEFの関係は少し分かりづらいかもしれませんので,整理しておきましょう.それぞれ以下コマンドを叩くと良いでしょう.
- **シンボルやデバッグ情報のついたカーネル(`vmlinux`)がない場合**
1. `ksymaddr-remote-apply`
- GEFが`ksymaddr-remote`コマンドで「シンボル-アドレスペア」を求め,それをGDBに取り込む
2. `ktypes-load`
- カーネルが`CONFIG_DEBUG_INFO_BTF=y`でビルドされている場合に,メモリ中から型情報を取り出しGDBに取り込む
- **シンボルやデバッグ情報のついたカーネル(`vmlinux`)がある場合**
1. `kload <vmlinux_path>`
- `kbase`を考慮しつつ`add-symbol-file`して,シンボル情報とデバッグ情報(型情報など)をGDBに取り込む
2. `ksymaddr-remote --vmlinux-file <vmlinux_path>`
- GEFの`ksymaddr-remote`コマンド内部のキャッシュを,`vmlinux`由来の情報で更新
- GEFの様々なコマンドが参照するため
- `kload`で既にシンボルがGDBに取り込まれているため,`ksymaddr-remote-apply`は不要
## `kipcs`コマンド (機能追加)
System-VのIPC(セマフォ,メッセージキュー,共有メモリ)の内容をダンプする機能です.
`msg_msg`のアドレスを自動で求めて表示する`-v`オプションを追加しています.

## `kchecksec`コマンド (機能追加)
Exploitで重要なカーネル関連の設定を検出・表示する機能です.
`CONFIG_FUSE_FS`, `CONFIG_SLAB_VIRTUAL`, `CONFIG_DEBUG_INFO_BTF`の検出を追加しています.

## `slub-dump`コマンド (機能追加)
SLUBの`kmem_cache`やそのフリーリストをダンプする機能です.

GoogleのKernel CTFで提供されるインスタンスでは,`CONFIG_SLAB_VIRTUAL`と呼ばれる緩和策(Linuxカーネルのメインラインにはない)が導入されたカーネルが使われています.
`kmem_cache`構造体,`slub`構造体のメンバが変わっていたり,仮想アドレスの紐づけ方が変わっています.
こちら対応済みです(6.1ベース, 6.6ベース, 6.12ベースいずれも対応).1u991yu24k1さんからのPRによるものです.
## `slab-virtual`コマンド (新規作成)
`CONFIG_SLAB_VIRTUAL`が有効なカーネルでは,SLUB機構で管理されるページにおいて,`page`構造体と仮想アドレスが紐付くのではなく,`slab`構造体と仮想アドレスが紐付きます.後者を相互変換する機能です.1u991yu24k1さんからのPRによるものです.

## `page`コマンド (機能追加)
`page`と仮想アドレス,物理アドレスを相互変換する機能です.
32ビットカーネルにおける,fixmapやHighMem領域として管理される`page`の変換をサポートしました.
## `cet`コマンド (新規作成)
Intel CETが有効なカーネルが出てくることを見越した,CETの設定状態をダンプする機能です.

## `vbar`コマンド (新規作成)
ARM32やARM64の`VBAR`領域(割り込みベクタ)の各エントリの,先頭命令をダンプする機能です.

## `highmem-dump`コマンド (新規作成)
x86やARM32のHighMem領域に関する,`page`と仮想アドレスの紐づけ情報をダンプする機能です.

## `kmem-cache-alias`コマンド (新規作成)
`kmem_cache`は,エイリアスを持つことがあります.その一覧をダンプする機能です.
リスト表示と,グループ表示の2種類が選べます.グループ表示はfederico-zancaさんのPRによるものです.


## OP-TEE関連
## `pagewalk --optee`コマンド (機能追加)
ARM64のカーネルをデバッグしているとき,ノーマルワールドにいながらセキュアワールドのメモリマップを擬似的に表示する機能です.
ヒントが表示されるようになり,より分かりやすくなりました.

正確なメモリマップは,セキュアワールドで停止してから`pagewalk`コマンドを叩く必要があります.

## `optee-break-ta`コマンド (機能追加)
OP-TEEの,TA(Trusted App; TrustZoneのS-EL0で動くアプリ)にブレークポイントを仕掛ける機能です.

ノーマルワールドにいる状態では,TAはメモリ中に存在しないので,TAがロードされるタイミングまでブレークポイントは仕掛けられません.TEE-OS内の関数である`__thread_enter_user_mode`が呼ばれるとTAがロードされたことが保証されるので(公式ドキュメントより),そこで一度停止する必要があります.
これまでは`__thread_enter_user_mode`のアドレスを求める術がなく,ユーザが事前に求めてコマンドの引数で指定する必要がありました.しかし`__thread_enter_user_mode`はアセンブリで書かれており,バイトパターンが一意なことから,GEF側で探すようにしたため指定不要となりました.
またTA-ELFを`-f`オプションで与える機能が増えました.
ELFをパースしてエントリポイントのオフセットを特定するので,単に先頭アドレスで停止させたければ,TA-ELFを事前に解析することすら不要になりました.もちろん,これまで通りオフセットを指定することもできます.

## `optee-smc-service-dump`コマンド (新規作成)
OP-TEEの,セキュアモニタ領域で動作するサービスをダンプする機能です.

## `optee-shm-list`コマンド (新規作成)
OP-TEEの,ノーマルワールド~セキュアワールド間向け共有メモリの情報をダンプする機能です.

## `optee-ta-dump memory`コマンド (新規作成)
OP-TEEの,メモリ中のTAに関する情報をダンプする機能です.

## `optee-ta-dump dir`コマンド (新規作成)
OP-TEEで動く,ホスト上のディレクトリにあるTA-ELFに関する情報をダンプする機能です.

TA-ELFは,事前にゲスト用ファイルシステムから抽出しておく必要があります.
# Qemu関連
## `qemu-system-memory-region-dump`コマンド (新規作成)
`qemu-system`プロセスそのものをデバッグしている時に,`MemoryRegion`構造体をダンプする機能です.

Qemuエスケープなどでは,MMIOハンドラを調査することが多く,そのアドレスを特定する用途で使えるかもしれません.
# d8関連
## `cage`コマンド (新規作成)
`d8`における,ubercageの各領域を可視化する機能です.

## `v8-list-maps`コマンド (新規作成)
`d8`における,ビルトインなmapのアドレスと内容をダンプする機能です.

## `v8-dump-space`コマンド (新規作成)
`d8`における,特定のスペース(`old_space`, `trusted_space`など)内のオブジェクトをダンプする機能です.

# アーキテクチャ関連
## ARM Cortex-M対応
ARM Cortex-Mのマシンを,リモートからデバッグしたかったので,対応しておきました.
一般的にARM Cortex-Mをデバッグするときは,Linuxの上で動くELFではなく,ベアメタルなファームウェアをデバッグしているはずです.メモリマップが入手できないので,そのあたりの処理をすっ飛ばす作りになっています.
ただし,対象のファームウェアに対応するELF(シンボルやデバッグ情報のために別途提供されることがあります)などをロードしているケースでは,ELFのセクション情報からメモリマップを構築するようにしています.
## RISC-Vカーネル対応
`qemu-system`上で動くRISC-Vカーネルをデバッグしたい状況がありました.
多くのカーネル関連コマンドは未対応であるものの,最低限`pagewalk`と`ksymaddr-remote`コマンドだけは動くようにしてあります.
# 終わりに
過去の記事に続き,bata24/gefで実装した機能を色々と紹介してきました.
本ツールを使っている方で,しばらく更新してないなーと思った方は,更新してみてください.
バグ報告,フィードバック,機能リクエストなどもお待ちしています.