- 本書に寄せて
- クレジット
- はじめに
- 1章 イントロダクション
- #1 未知のバイナリの読み方
- fileコマンド:ファイル形式を特定する
- 人力fileコマンドのやり方
- まとめ
- #2 アセンブリ入門
- まとめ
- #3 Hello, World!再訪
- libcのシステムコールのラッパを使ったHello, World!
- アセンブリ言語でのHello, World!
- ELF HackのためのHello, World!
- 動的命令生成を使ったHello, World!
- まとめ
- #1 未知のバイナリの読み方
- 2章 ELF Hack
- #4 ELFファイルのセグメント
- PT_INTERP
- PT_LOAD
- PT_DYNAMIC
- PT_NOTEとPT_GNU_PROPERTY
- PT_TLS
- PT_GNU_EH_FRAME
- PT_GNU_STACK
- PT_GNU_RELRO
- まとめ
- #5 ld-linux.soの環境変数を利用する
- LD_PRELOAD
- LD_DEBUG
- LD_AUDIT
- まとめ
- #6 共有ライブラリを検索するディレクトリ
- 共有ライブラリの検索の実例
- ダイナミックリンカが共有ライブラリを検索するディレクトリ
- セキュリティ実行モード
- DT_RUNPATH
- まとめ
- #7 dlopenによるライブラリの実行時ロードとその応用テクニック
- dlopenとdlsym
- dlopen、dlsymを使ってみる
- 応用:既存のライブラリ関数をラップする
- まとめ
- #8 IFUNCを使って実行時に実装を切り替える
- IFUNCの使用例
- IFUNCのresolver functionが呼ばれるタイミング
- まとめ
- #9 ELFのハッシュテーブルのしくみ
- DT_HASH
- DT_GNU_HASH
- 2つのハッシュテーブルの比較
- まとめ
- #10 TLSのしくみを理解する
- TLSアクセスモデル
- 各アクセスモデルの実際の動作
- まとめ
- #11 コアファイルを読む
- コアファイルの構造
- コアファイルの解析
- まとめ
- #12 補助ベクトルを使ってプロセスに情報を渡す
- 補助ベクトルの利用
- 補助ベクトルがプロセスに渡されるしくみ
- 参考文献
- まとめ
- #13 静的リンクとASLRの関係
- 静的リンクされたアプリケーションの作り方
- 静的リンクとASLR
- まとめ
- #14 soldを使って依存する共有ライブラリを後からリンクする
- soldの使い方
- soldのしくみ
- まとめ
- #15 glibcをHackする
- glibcのソースコードを読む
- glibcにパッチを当てる
- まとめ
- #16 patchelfでELFバイナリのフィールドを書き換える
- PT_INTERPの編集
- DT_RUNPATHの編集
- 参考文献
- まとめ
- #17 LIEFを使ってELFバイナリを書き換える
- シンボルのリネーム
- 関数の差し替え
- まとめ
- #18 PT_NOTEを利用したバイナリパッチ
- PT_NOTEタイプのプログラムヘッダの書き換え
- 参考文献
- まとめ
- #19 DWARF Expressionを実行する:DWARFⅠ
- DWARFについて
- 四則演算用のひな型の準備
- DWARF Expressionが実行できることの確認
- まとめ
- #20 DWARFで数式を評価する:DWARFⅡ
- 入力された数式の参照
- 与えられた数式の評価
- まとめ
- #21 DWARFで標準出力に出力する:DWARFⅢ
- 評価結果の出力
- 実世界における意義
- 参考文献
- まとめ
- #4 ELFファイルのセグメント
- 3章 OS Hack
- #22 実行可能ファイルとその起動方法
- shebang
- binfmt_misc
- まとめ
- #23 LinuxでHuge Pageを使う
- Transparent Huge Page
- 明示的なHuge Pageの確保
- まとめ
- #24 CRIUを使ってプロセスを保存、再開する
- CRIUの使い方
- CRIUのしくみ
- まとめ
- #25 procfs / sysfsの基本を把握する
- procfs
- システム全体の情報に関するファイル
- sysfs
- まとめ
- #26 用途に合わせたファイルシステムを選ぶ
- Overlay Filesystem(OverlayFS)
- Btrfs:Copy-On-Writeファイルシステム
- EROFS:圧縮ファイルシステム
- まとめ
- #27 特定のプロセスに見せるファイルを差し替える
- バインドマウントでファイルやディレクトリを一時的に置き換える
- マウントネームスペースとバインドマウントで特定のプロセスにのみ置き換えを行う
- OverlayFSを用いて、ファイルへの書き込みだけ別の場所へと置き換える
- まとめ
- #28 FUSEを使ってファイルシステムを自作する
- FUSEとは?
- FUSEのしくみ
- ファイルシステムを自作してみる
- パフォーマンス向上のコツ
- まとめ
- #29 特殊なメモリ領域vsyscallとvDSO
- vsyscallの当初の用途
- vsyscallのほかの用途
- vDSO
- まとめ
- #30 KVMを使ってハイパーバイザを作成する
- ハイパーバイザとは
- KVMの概要
- ゲストプログラムの準備
- KVMのAPI
- VMを実行する
- 実用的なハイパーバイザへの道
- まとめ
- #31 LinuxカーネルHack入門
- Linuxカーネルを読む
- Linuxカーネルをビルドする
- ルートディスクイメージの作成
- QEMUでLinuxシステムをブートする
- まとめ
- #32 Unikernel:アプリケーションをOSとして動かす
- Unikernel/ライブラリOSとは
- UnikraftでアプリケーションをUnikernelにする
- まとめ
- #33 UEFIとSecure Boot
- Secure Boot
- Secure Boot変数
- まとめ
- #34 GNUツールチェインで機械語ファイルを出力する
- リンカスクリプトを使ってバイナリファイルを出力する
- C言語に対応したリンカスクリプト
- まとめ
- #35 QEMU上で動くファームウェアを作る
- PCのブート
- QEMUを使ったファームウェアプログラミング
- まとめ
- #36 Chromebook上で自作のファームウェアを動かす
- ChromebookのCCD
- CCDを使ったファームウェア書き換え
- Apollo Lakeを搭載したChromebook上でのファームウェアプログラミング
- まとめ
- #22 実行可能ファイルとその起動方法
- 4章 コンテナHack
- #37 Linuxネームスペースでプロセスを分離する
- Linuxネームスペース
- PID/マウントネームスペースを作ってみる
- まとめ
- #38 cgroupでプロセスのリソースを管理する
- cgroupの概要
- cgroupの基本操作
- メモリのコントロール
- PIDのコントロール
- I/Oのコントロール
- まとめ
- #39 chroot/pivot_rootでルートディレクトリを切り替える
- chrootによるルートディレクトリの切り替え
- pivot_rootによるルートファイルシステムの差し替え
- まとめ
- #40 一般ユーザーがrootのように振る舞う方法3選
- setuidを設定する
- 必要なケーパビリティだけを付与する
- ユーザーネームスペースの中でrootになる
- まとめ
- #41 rootlessコンテナの使い方とそのしくみ
- rootlessコンテナとは
- Podmanを使ってみる
- rootlessコンテナのしくみ
- まとめ
- #42 ユーザーネームスペース内で各種のネームスペースを作成する
- ユーザーネームスペースの制限
- マウントネームスペースの制限
- ネットワークネームスペースの制限
- cgroupネームスペースの制限
- まとめ
- #43 /proc/PID/rootからコンテナ内のファイルに直接アクセスする
- /proc/<PID>/rootを使ってみる
- まとめ
- #37 Linuxネームスペースでプロセスを分離する
- 5章 デバッガ・トレーサHack
- #44 gdb Tips
- コマンドを省略する
- 特定の状況でブレークする
- ブレーク時に自動で処理する
- さまざまな情報を取得する
- 環境設定
- メモリの検索・操作
- レコード
- チェックポイント
- 便利に表示する
- Python連携
- プラグイン(.gdbinit)
- gdbserver
- まとめ
- #45 rrを使ってRecord and Replayデバッグを行う
- rrとは
- rrを使ってみる
- rrの原理としくみ
- まとめ
- #46 サニタイザで低レイヤのバグを見つける:サニタイザⅠ
- サニタイザとは
- サニタイザの種類
- サニタイザを使ってみる
- ほかのバグ検出方法との関係
- まとめ
- #47 Address Sanitizerのしくみ:サニタイザⅡ
- Address Sanitizerが追加するコード
- アセンブリを見てみる
- まとめ
- #48 Linuxパフォーマンス解析ことはじめ
- 可観測性ツールの分類
- perfコマンド
- まとめ
- #49 ftraceを使ってカーネル内で起こっていることをトレースする
- 準備
- 関数コールグラフのトレース
- 関数トレーシングのしくみ
- イベントトレーシング
- ユーザースペースのイベントも記録する
- trace-cmdを通じたトレーシング
- まとめ
- #50 eBPFを使ったトレーシング入門
- eBPFとは
- eBPFプログラミングのためのライブラリ
- bpftraceを使ってみる
- bpftraceの基本的な文法
- まとめ
- #51 DBIで実行命令をトレース・改変する
- 代表的なDBIツール
- Fridaでトレースと改変を行う
- まとめ
- #52 Intel PTで高速にトレースを取得する
- Intel PTのパケット
- Intel PTで実行命令数を取得する
- まとめ
- #44 gdb Tips
- 6章 セキュリティHack
- #53 seccompでプロセスの使えるシステムコールを制限する
- seccompとは
- seccompを使ったプログラムを書く
- 実アプリケーションでの使用例
- まとめ
- #54 Landlockで非特権プロセスサンドボックスを作る
- Landlock
- Landlockを使ったプログラムを書く
- Landlockプログラムの動作を確認する
- 注意点:Landlockの制限
- まとめ
- #55 ASLR:不正なメモリアクセスに対するセキュリティ機構
- Linuxユーザーランドプロセスに対するASLRの動作
- Linuxユーザーランドプロセスに対するASLRの実装
- ASLRを回避する攻撃手法
- まとめ
- #56 ROP:メモリ破壊を悪用するスタンダードな攻撃手法
- Linuxユーザーランドでの一例
- ROPの重要性
- ROPへの対策
- まとめ
- #57 Intel CET:ROPに対するセキュリティ機構
- Shadow Stackの詳細
- Intel SDEでIntel CETを試す
- まとめ
- #58 Clang CFIによって不正な制御フローを検知する
- 関数ポインタの検査
- クラスオブジェクトのポインタの検査
- 共有ライブラリを考慮したバージョン
- まとめ
- #59 スタックフレームの変化を観察する
- 素朴なスタックフレーム
- フレームポインタの省略
- Stack Smashing Protector(SSP)
- Red zoneの利用
- まとめ
- #60 ファジングの概要と分類
- ファザー(ファジングツール)の種別
- 代表的なファジングツール
- まとめ
- #61 グレイボックスファジングでバグや脆弱性を探す
- プログラムをビルドしてAFL++でファジングする
- グレイボックスファザーのしくみ
- AFL++におけるプロセス間通信のしくみ
- まとめ
- #62 LibAFLでファザーを実装する
- 対象プログラムのビルド
- 愚直なファザーを実装する
- まとめ
- #63 LibAFLで実装したファザーを改良する
- シードスケジューリングの改良
- 実行速度の改善
- そのほかの改善
- まとめ
- #64 angrでシンボリック実行する
- 代表的なシンボリック実行ツール
- angrでシンボリック実行する
- シンボリック実行の難しさ
- 技術的な問題への対処
- まとめ
- #65 BadUSB:使用者を騙すUSBデバイス
- 実験
- 対策
- まとめ
- #66 Row Hammer:DRAMの脆弱性に対する攻撃手法
- 原理
- コードの例
- 緩和策と発展形の攻撃
- まとめ
- #67 MeltdownとSpectre:CPUの脆弱性に対する攻撃手法
- CPUの最適化技法
- Meltdown
- Spectre
- 影響を受けたCPUと対応
- まとめ
- #53 seccompでプロセスの使えるシステムコールを制限する
- 7章 数値表現とデータ処理Hack
- #68 整数表現の基礎知識
- 符号なし整数と2の補数による符号付き整数
- レジスタと演算器のビット幅
- エンディアン
- まとめ
- #69 さまざまな整数表現
- 任意精度数値型と多倍長表現
- 固定小数点数
- 可変長表現
- まとめ
- #70 浮動小数点数のビット列表現を理解する
- 浮動小数点数の基本(IEEE 754の基本)
- 浮動小数点数のビット列表現(2進)
- 浮動小数点数のビット列表現(10進)
- まとめ
- #71 浮動小数点例外
- 浮動小数点例外の種類
- 例外の状態フラグ
- デフォルト以外の処理方法
- まとめ
- #72 浮動小数点数の丸め方を変える
- 5通りの丸め方
- 動的な指定
- 静的な指定
- まとめ
- #73 浮動小数点環境を触るコードに対するコンパイラの最適化と戦う
- コンパイラの最適化によって意図通りに動かなくなる例
- C標準のプラグマ
- volatileの利用
- インラインアセンブリの利用
- まとめ
- #74 NaNを深掘りする
- signaling NaN
- NaNのペイロードと伝播
- RISC-Vの浮動小数点レジスタとNaN
- まとめ
- #75 浮動小数点数のアーキテクチャごとの差異に触れる
- アンダーフローの判定のタイミング
- FMAとinvalid operation例外
- 浮動小数点数から整数への変換
- Armの代替動作(FEAT_AFP)
- まとめ
- #76 SIMD命令セットの基礎知識
- x86/x86-64のSIMD命令
- ARMのSIMD命令
- コンパイラにSIMD命令を出力させる
- サポートされる拡張命令セットを検出する
- まとめ
- #77 SIMD並列化したコードを書く
- 並列化コードを書く前に
- コンパイラの自動並列化を利用する
- OpenMP SIMDプラグマを使う
- コンパイラのintrinsic関数を使う
- SIMDラッパライブラリを使う
- アセンブリを手書きする
- JITライブラリを使う
- まとめ
- #78 SIMD命令を使ったさまざまなテクニック
- SIMD命令を使ってstrlen関数を高速化する
- SIMD命令を使ってVByteの展開を高速化する
- まとめ
- #68 整数表現の基礎知識
- 8章 言語処理系Hack
- #79 NaNを活用して64ビット値にタグ付きの値を格納する
- 動的型付き言語での値の表現
- NaN boxingの例
- 採用例
- まとめ
- #80 ucontext.hでコルーチンを実装する
- ucontext.h
- コルーチンを実装する
- ucontext.hの問題点
- スタックを持たないコルーチン
- まとめ
- #81 Profile Guided Optimization
- PGOを使う一般的な手順
- PGOを使う具体例
- 参考文献
- まとめ
- #82 LD_PRELOADを使ってメモリアロケータを入れ替える
- さまざまなメモリアロケータ
- LD_PRELOADを使ったメモリアロケータの入れ替え
- メモリアロケータの自作
- まとめ
- #83 ABIと呼び出し規約を理解する
- ABIがそろっていない場合に起こる現象の例
- C言語のABI
- C言語以外のABI
- まとめ
- #84 libffiで実行時までシグネチャがわからない関数を呼び出す
- PythonのFFIを使ってみる
- dlopen/dlsymを使った共有ライブラリのロード
- アセンブリ言語による呼び出し規約の実装
- libffiを使う
- C++/Rustでライブラリを提供する
- まとめ
- #85 実行時に機械語を生成する
- 例:関数を部分適用する
- メモリの実行許可
- 実行時生成された関数をperfで見えるようにする
- 発展
- まとめ
- #86 GCC/Clangの組み込み関数を利用する
- ビット操作
- コードが実行されないことをコンパイラに伝える
- 標準化された組み込み関数やマクロ
- まとめ
- 組み込み関数のリファレンス
- #79 NaNを活用して64ビット値にタグ付きの値を格納する
- 9章 そのほかのHack
- #87 用語集
- #88 Binary Hacksに必要なツール
- コンパイラ・デバッガ
- バイナリファイル関連のツール
- OS関連のコマンド
- そのほかのコマンド
- #89 文献案内
- 書籍
- インターネット