GhidraのScriptまわりについて

はじめに

先日、NSAリバースエンジニアリングツールのGhidraを公開した。 OSSであることや、Hex-rays社が高価で販売しているようなデコンパイラがついていることから注目されている。 SREを「Site Reliability Engineering」ではなく「Software Reverse Engineering」としてSRE frameworkを標榜しているのもかっこいい!!!!!

IDAでいうIDAPythonのように、GhidraでもJavaJythonとしてのPythonで解析に役立つScriptを動かすことができる。 docs/GhidraAPI_javadoc.zipAPIリファレンスがあり、それらのAPIを扱える。 この記事では、そんなGhidraのScriptまわりを見ていこうと思う。

Pythonインタプリタ

CodeBrowserのツールバーのWindow->PythonよりPythonインタプリタを起動できる。 APIの挙動を確かめたいときによさそう。

f:id:TAKEmaru:20190319195839p:plain

上では、currentProgram.getName()でバイナリのファイル名を取得し、 askString()でポップアップを出し、ユーザーからの入力を受け取っている。

Script Manager

Code Browser上の再生ボタンのような▷のボタンを押すとScript Managerが開かれる。

f:id:TAKEmaru:20190318201824p:plain

ダウンロードしてきたScriptを読み込むにはScript Directoriesのボタンを押して、Scriptがあるディレクトリを追加してあげるとよさそう。

f:id:TAKEmaru:20190318204530p:plain

Create New Scriptボタンを選択するとScript Managerの右側に簡易的なエディタが出現する。 Script Manager上でコードを書けるので便利そう。 ここで作成したScriptはデフォルトでは~/ghidra_scriptsに保存される。

f:id:TAKEmaru:20190318204951p:plain

参考になりそうなScript

Ghidra/Features/以下にJavaPythonのScriptがたくさん置かれている。

Script Mangerを開くとExamplesというディレクトリがあり、ここにあるScriptを読んでいくとチュートリアル代わりになりそう。

f:id:TAKEmaru:20190319194623p:plain

ExamplesというディレクトリがあるかのようにUI上では表示されるが、これはカテゴリのようなもののようで、実際には全然違うディレクトリにあるので注意。

$ find . -name ghidra_basics.py
./Ghidra/Features/Python/ghidra_scripts/ghidra_basics.py

便利そうなscript

ghidraninja/ghidra_scriptsというghidraのscriptがいくつか置かれたリポジトリがある。早い。

github.com

binwalkを走らせて見つけたアドレスをBookmarkに登録するbinwalk.pyや、暗号に使われる定数を見つけるyara.py、 swiftの関数名をdemangleしてくれるswift_demangler.py、stripped Go binaryにシンボルをつけ直すgolang_renamer.pyがあり便利そう。

Nginxのalias traversalについて

Nginxのalias traversalとは

Nginxではaliasディレクティブを使って locationディレクティブで指定したURIのパスをファイルシステム上のパスに対応させることができます。 以下の例のようにconfigを書くと、/var/www/app/static/以下にあるファイルに/static/ファイル名のようなパスでアクセスできます。

location /static {
    alias /var/www/app/static/;
}

しかし、このようにlocationのパスの末尾が/で終わっていない場合、..を使うことで、開発者が意図していない上位のディレクトリへのアクセスが可能になってしまいます。 このケースだと、/static../setting.pyのようにパスを指定することで、aliasで指定したディレクトリより上位のディレクトリである/var/www/app以下のsetting.pyにアクセスすることができます。これがNginxのalias traversalです。

以下のようにlocationで指定するパスの末尾に/を書いておくことで防ぐことができます。

location /static/ {
    alias /var/www/app/static/;
}

Nginxは、alias traversalを脆弱性として扱っておらず、Nginx側で修正されることはありません。

初出は2016年のHCTFの問題のようです。 HCTF2016 Web WP - 小西的博客 | Xiaoxi's Blog

ぼくはCODEBLUE 2018でorangeさんのBreaking Parser Logic - Take Your Path Normalization Off and Pop 0days Outを聞いて知りました。 ちなみに、この発表はDEFCON26やBlack Hat 2018やHack.lu 2018でも行われています。ぼくもつよいexploit手法を見つけたら海外カンファレンス巡業したい。

実例

hackeroneでは以下のようなものが見つかっていました。

やってみる

alias traversalの問題があるNginxサーバーを立てることができるDockerfileを書きました。

github.com

このリポジトリは以下のファイルから構成されています。

nginx-alias-traversal-sample$ tree .
.
├── Dockerfile
├── LICENSE.md
├── README.md
├── index.html
├── screenshots
│   ├── flag.png
│   └── top.png
└── vulnerable.conf

1 directory, 7 files
$ docker build -t nginx-traversal .
$ docker run -d -p 3000:80 nginx-traversal:latest

上のコマンドでdocker runすると、http://localhost:3000でNginxサーバーが動きます。

f:id:TAKEmaru:20190306124807p:plain

http://localhost:3000/static/がalias traversal可能なパスになっています。

f:id:TAKEmaru:20190306124826p:plain

alias traversalを利用して、aliasで指定されたディレクトリの一つ上の階層にあるflagを読み出すことができました。

f:id:TAKEmaru:20190306124902p:plain

発見するのに使えるツール

Nginxのconfigにアクセスすることができる開発者側であれば、 gixyというNginxのconfigの静的解析ツールを使って、alias traversalを検出することができます。

github.com

$ gixy vulnerable.conf 

==================== Results ===================

>> Problem: [alias_traversal] Path traversal via misconfigured alias.
Description: Using alias in a prefixed location that doesn't ends with directory separator could lead to path traversal vulnerability. 
Additional info: https://github.com/yandex/gixy/blob/master/docs/en/plugins/aliastraversal.md
Pseudo config:

server {
    server_name localhost;

    location /static {
        alias /var/www/app/static/;
    }
}

==================== Summary ===================
Total issues:
    Unspecified: 0
    Low: 0
    Medium: 0
    High: 1

また、脆弱性を発見するペンテスターはBurpの拡張を使って検出することができます。

github.com

私的Dockerメモ

Dockerは便利だけど、ぼくにとっては普段そんなに使うツールではなくて、よくコマンドを忘れてしまう。

覚えられるように、すぐ見返せるように、メモしておく。

Dockerイメージに関するコマンド

一覧

$ docker images

ビルド

直下にあるDockerFileからビルド。

$ docker build ./ -t example

削除

イメージIDを指定して削除。複数のイメージIDを指定できる。

$ docker rmi IMAGE-ID IMAGE-ID IMAGE-ID

すべてのイメージを削除

$ docker rmi -f $(docker images -q)

Dockerコンテナに関するコマンド

一覧

$ docker ps -a

ビルド

イメージからコンテナをビルド。 -tは、Dockerコンテナ内の標準出力とホスト側の出力をつなげるオプション。-iは逆にホスト側の入力とコンテナの標準入力をつなげるオプション。

$ docker run -it IMAGE-ID /bin/bash

-p外部からアクセスされるポート番号:コンテナ側のポート番号を指定し、ポートフォワーディングするオプション。 -dはデーモンとしてバックグラウンドで実行するオプション。

$ docker run -d -p 3000:80 IMAGE-ID

コンテナの中に入る

起動済みのコンテナの中に入る。ビルドする際との違いはrunがexecになって、イメージIDがコンテナIDになっている点。

$ docker exec -it CONTAINER-ID /bin/bash

停止

コンテナIDを指定して停止。

$ docker stop CONTAINER-ID

削除

コンテナIDを指定して削除。複数のコンテナIDを指定できる。

$ docker rm CONTAINER-ID CONTAINER-ID CONTAINER-ID

停止しているコンテナをすべて削除。

$ docker container prune

状態に関わらず、すべてのコンテナを削除。

$ docker rm -f $(docker ps -aq)

その他Tips

no Space Left on Deviceの対処法

空き容量不足によるエラー。単純にディスクが不足している以外に、Dockerに割り当てられている仮想ディスクの容量不足が原因のことがある。 不要なイメージやコンテナを消すか、仮想ディスクの容量を増やしてあげると解決する。

blog.kasei-san.com

ISUCONがきっかけでSinatraにコントリビュートした話

ISUCON8の予選へ向けてSinatraで作られたwebアプリケーションを高速化する方法を模索する最中、 ErubisというERBテンプレートエンジンが使われているコードを見かけました。 これがきっかけでより高速なeRubyテンプレートエンジンであるErubiをサポートするためのコードをSinatraにコミットしました。この記事ではその詳細について説明したいと思います。

ISUCONというのはお題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトルです。

isucon.net

ErubisとErubi

eRubyのテンプレートエンジンはRubyの標準ライブラリのERB以外にも存在し、ErubisとErubiといったものがあります。 ErubisはERBより高速に動作し、Rails 5.0.xまではデフォルトのeRubyテンプレートエンジンとして使われていましたが、2011年ごろからメンテされていませんでした。 ErubiはErubisより高速に動作し、現在もメンテされています。

github.com

Railsでは5.1からデフォルトのeRubyテンプレートエンジンがErubisからErubiに変更されました。 github.com

どんなコードをコミットしたのか

Erubiを動作させるためのコードをごりごり書くつもりだったのですが、 Sinatraの内部で使われているTiltという複数のeRubyテンプレートエンジンへのインターフェースを提供するライブラリが 既にErubiに対応済みでした。

github.com

これによって、 SinatraのREADMEではErubiを使えると書かれていないものの、すでにErubiを使用可能であるという状況になっていました。 というわけでテストコードとドキュメントの修正を行いました。 最終的にマージされたプルリクエストはこれです。

github.com

結果として、テストコードとドキュメントの修正しかすることがなかったですが、SinatraがErubiをサポートしていることが明確になってよかったと思います。今年のISUCON9からはErubiを使えますね!!!

IDAの便利プラグイン3選!!!

これはセキュリティツール系 Advent Calendar 2018 の25日目の記事です。

この記事では便利なIDAのプラグインを3つ紹介したいと思います。

findCrypt

findCryptは暗号に使われる定数をgrepすることで、どんな暗号が使われているか判別するIDAプラグインです。

github.com

使い方

IDAにバイナリを読み込ませた状態で、メニューバーのFile->Script file...からfindcrypt.pyを実行することで使えます。 実行すると以下のようにOutput windowにスキャンの結果が出力されます。以下の例ではRijndaelで用いられている定数が見つかっていますね。

f:id:TAKEmaru:20181224221904p:plain
Output windowに出力されたfindCryptによるスキャンの結果

また、見つけた定数に名前をつけてくれるので、ディスアセンブル結果が表示されているIDA View-A上からも定数を確認しやすいです。

f:id:TAKEmaru:20181224222028p:plain
findCryptによって発見されたRijndaelの定数

シュッと用いられている暗号がわかって便利ですね。定数を使わないようにカスタムされた暗号が用いられている場合はこのプラグインでは見つけられないので、自力でがんばる必要があります。

LazyIDA

LazyIDAはMake your IDA Lazy!を目指しているプラグインです。 いくつか機能がありますが、データをC/C++の配列やPythonのlistに変換してくれる機能が便利です。

github.com

使い方

IDAのpluginsディレクトリ以下にLazyIDA.pyを配置すると使えるようになります。 IDAの画面上で左クリックすると、Convertというメニューが追加されていると思います。ここから好きなフォーマットを選択し変換することができます。

ここでは、先ほどfindCryptで見つけたRijndaelの定数をLazyIDAでPythonのlistに変換してみます。

f:id:TAKEmaru:20181224221205p:plain
LazyIDAでデータを変換する様子

変換した結果はOutput windowに出力され、これをコピペしてPythonスクリプトから扱うことができます。

f:id:TAKEmaru:20181224221321p:plain
Output windowに出力されたLazyIDAで変換したデータ

これはエンコードされたデータをデコードするときや、暗号化を解くときのスクリプトを書くときに便利です。

KeyPatch

IDAにはx86/x64を対象にしたアセンブラが組み込まれていますが、他のアーキテクチャを対象としたものはありません。 Keypatchは軽量なmulti-platform, multi-architecture assembler frameworkである Keystone – The Ultimate Assemblerを使って、IDA上で様々なアーキテクチャへのアセンブルを実現し、x86/x64以外のバイナリへパッチを当てやすくするプラグインです。

github.com

このプラグインはHex-Raysが行っているPlug-In Contest 2016で3位になっています。

www.hex-rays.com

使い方

Keystoneをインストールし、 IDAのpluginsディレクトリ以下にkeypatch.pyを配置すると使えます。 macOS上のIDAPythonは/usr/bin/pythonを使っているため、普段macOSのデフォルトではないPython(pyenvでインストールしたPythonなど)を使っている場合は、 IDAPythonからpipでインストールしたライブラリを使えません。 その場合はpipでインストールしたライブラリをIDAのディレクトリの中にコピーする必要があります。 わたしはpyenvでインストールしたPythonを使っているので以下のようなコマンドになりました。パスは適宜変更してください。

$ sudo cp -r ~/.pyenv/versions/2.7.15/lib/python2.7/site-packages/keystone /Applications/IDA\ Pro\ 7.2/ida.app/Contents/MacOS/python/

インストールに成功していると、IDAの画面上で左クリックして出るメニューにKeypatchが追加されています。ここからPatcherを選択することでKeyPatchのWindowが出現します。

f:id:TAKEmaru:20181225143658p:plain
KeypatchのWindowを出す様子

ここではMOV R0, R3というARMのアセンブリMOV R0, 1に変更しています。

f:id:TAKEmaru:20181225022711p:plain
Keypatchでパッチを当てる様子

以下はパッチを当てたあとの様子です。コメントにパッチを当てる前のアセンブリが残されていて親切ですね。

f:id:TAKEmaru:20181225021610p:plain
パッチを当てたあと

このプラグインを使わずに、現状のIDAでx86/x64以外のバイナリに対しパッチを当てるには機械語のパッチを当てることになります。 このプラグインのおかげでARMなどのバイナリにパッチを当てる作業は楽になりました。

リアルモードでも32bitのレジスタを使うことができる

この記事は自作OS Advent Calendar 2018の21日目の記事です。

自作OSのアドカレなので、まずは作っているCPUエミュの話をしましょう。

CPUエミュを作っている話

そもそもなぜCPUエミュを作っているのかというと、 Golangで書かれたファミコンのエミュのコードを読んでめっちゃおもしろいなって思ったのが、 CPUエミュを作ってみようと思い始めたきっかけでした。

github.com

それで一番馴染みがあるアーキテクチャであるx86を対象にGolangx86のCPUエミュ「cibo」を作りはじめました。 x86/x64を対象にしたソフトウェアエミュレータは、Type1ハイパーバイザーがあるのであまり需要がない気はしますが、 はじめて作るCPUエミュは親しみのあるアーキテクチャの方がいいでしょう。 ciboという名はBLAMEの生電社の主任科学者シボさんから取っています。 「久しぶりだな頭取!」って言って霧亥を助けに来るシーン、かっこいいですよね。 github.com

ひとまずQEMUBochsで使われているBIOSである、SeaBIOSを動作させることを目標に開発しています。 今のところ、NASMでアセンブルされた簡単なバイナリを走らせることができるくらいの進捗です。早くVGAあたりをエミュレートしてカラーの画面を出したいですね

$ cibo --debug ./samples/asm/simple_call
EIP = 0x7C00, Opcode = 0xB8
EIP = 0x7C05, Opcode = 0xBB
EIP = 0x7C0A, Opcode = 0xE8
EIP = 0x7C14, Opcode = 0x89
EIP = 0x7C16, Opcode = 0xB8
EIP = 0x7C1B, Opcode = 0xC3
EIP = 0x7C0F, Opcode = 0xE9
No mapping area: 0x0
==================== registers ====================
01: EAX = 0x1011
02: ECX = 0x0
03: EDX = 0x0
04: EBX = 0xF1
05: ESP = 0x7C04
06: EBP = 0x0
07: ESI = 0x0
08: EDI = 0x0
09: EIP = 0x0
10: CS = 0x0
11: DS = 0x0
12: SS = 0x0
13: ES = 0x0
14: FS = 0x0
15: GS = 0x0
16: EFLAGS = 0x2 (00000000000000000000000000000010)
17: MM0 = 0x0
18: MM1 = 0x0
19: MM2 = 0x0
20: MM3 = 0x0
21: MM4 = 0x0
22: MM5 = 0x0
23: MM6 = 0x0
24: MM7 = 0x0

また、Unicornのようにコードからも操作できるようにしています。

package main

import (
    "github.com/tkmru/cibo/core"
)

func main() {
    beginAddress := 0x7c00
    emu := cibo.NewEmulator(32, beginAddress, 29, false, true)
    cpu := emu.CPU
    reg := &cpu.X86registers

    emu.RAM = []byte{0xb8, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x75, 0x05, 0xe9, 0xef, 0x83, 0xff, 0xff, 0xb8, 0x02, 0x00, 0x00, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x74, 0xef}
    /*
       mov eax, 0x1
       cmp eax, 0x2
       jnz not_equal

     equal:
       jmp 0

     not_equal:
       mov eax, 0x2
       cmp eax, 0x2
       jz equal
   */

    reg.Init()
    emu.Run()
}

テストはmulti-architecture assembler frameworkであるKeystoneGolangバインディングと標準パッケージのtestingを使って書いています。 Golangを使ってCPUエミュのテストを書くにはこれがいいと思います。実際のテストコードはこれです。

うっかり自作CPUエミュの話が長くなってしまいましたが、自作OSのアドカレの記事なのでまあよしとしましょう。 そろそろ本題に入ります。

BIOSとは

特に説明をせずBIOSについて言及していましたが、ここで説明していきます。 BIOSというのは、Basic Input/Output Systemの略でPCの電源を入れた直後の初期化や HDDから最初のプログラムローダをメモリに読み出す役割を持つプログラムです。

BIOSはリアルモードという16bitで動作するモードで動き、 周辺機器に関する処理を行ったあと、MBR(Master Boot Record)やPBR(PartiPartition Boot Record)といったブートセクタを読み出し、 32bit/64bitで動くOSに動作を移します。

このようなBIOSですが、16bitでしか動作しないので、32bit/64bitで動作するUEFIに取って代わられようとしています。 Intel CPUでは 2020年までに CSM (BIOS 互換機能) を撤廃して UEFI に完全移行する方針のようで、 近いうちにBIOSが搭載されたデバイスは見かけなくなってしまうようです。

neriring.hatenablog.jp

なぜ、そのうちなくなるであろうBIOSを自作CPUエミュで動かそうとしているのかというと、いきなりx64のエミュを実装するのは大変かなと思ったからです。ところで、seabiosを自作CPUエミュで動かそうと思うと、seabios内で使われている命令すべてを自作エミュ上で動作するようにしておく必要があります。そのため、どんな命令が使われているのか知るためにIDAでseabiosのバイナリをディスアセンブルしてみたところ、リアルモードでも32bitのレジスタは読み書きされていることに気づきました。

リアルモードで32bitのレジスタ???

下の画像を見ると32bitのレジスタを使っている命令は先頭に0x66というopcodeがついているのが分かると思います。 0x66というopcodeはOperand-size override prefixという役割を持っていて、オペランドのサイズを上書きできる接頭辞です。 つまり、リアルモードではopcode 0x66を使うことで32bitのレジスタを読み書きできるのです!!

f:id:TAKEmaru:20181220015606p:plain
seabiosのバイナリをIDAでディスアセンブルした結果の一部

これを知って、私の好きなopcodeは0x66になりました。 16bitで動作している環境で32bitのレジスタが使えるというのはとてもおもしろいですね。 わたしはこれを自分で発見してとても驚いたのですが、 Wikipediaに書かれていたので自明なことだったようです....

PinなどのDBIツールでトレースした結果をIDAにマッピングするプラグイン「Lighthouse」を使ってみた

Lighthouseとは

Lighthouse とは、DBIツールでトレースすることで得たコードカバレッジデータを見やすくIDA内の独自のViewに表示し、IDAのDisassembly View、Graph ViewにマッピングしてくれるIDAプラグインである。

github.com

DBI(Dynamic Binary Instrumentation)は実行時にバイナリの内容を書き換えることによって、CPU命令の単位でトレースなどを行う手法である。 Lighthouseは、PinDynamoRIOFridaの3種類のDBIツールに対応している。この記事ではPinを用いた。

インストールする

git cloneして/plugin以下にあるlighthouse_plugin.pyとlighthouseフォルダをIDAの/pluginsフォルダに入れるとインストールできる。 以下はmacOSでのコマンド例だが、OSが違ってもパスが変わるくらいでそんなに変わらないはず。

$ git clone git@github.com:gaasedelen/lighthouse.git
$ cp -R lighthouse/plugin/ /Applications/IDA\ Pro\ 7.1/ida64.app/Contents/MacOS/plugins/

また、PinのログフォーマットをLighthouseで扱える形式にするためのpintoolをビルドしておく必要がある。64bitのMacOSだと、/lighthouse/coverage/pin/obj-intel64/CodeCoverage.dylibが生成される。

$ export PIN_ROOT=~/pin # Pinのインストールパスを指定
$ export PATH=$PATH:$PIN_ROOT
$ cd ~/lighthouse/coverage/pin
$ make
mkdir -p obj-intel64
/Applications/Xcode.app/Contents/Developer/usr/bin/make objects
make[1]: Nothing to be done for `objects'.
/Applications/Xcode.app/Contents/Developer/usr/bin/make libs
make[1]: Nothing to be done for `libs'.
/Applications/Xcode.app/Contents/Developer/usr/bin/make dlls
make[1]: Nothing to be done for `dlls'.
/Applications/Xcode.app/Contents/Developer/usr/bin/make apps
make[1]: Nothing to be done for `apps'.
/Applications/Xcode.app/Contents/Developer/usr/bin/make tools
...

使ってみる

Pinを使って解析したいプログラムをトレースする。 ここでは、最近、Golangで書いているCPUエミュ cibo をPinにかけた。 実行結果はtrace.logとしてファイルに出力される。ちなみにgolangのバイナリの構造はこれがくわしい。

$ pin -t obj-intel64/CodeCoverage.dylib -- cibo hoge/samples/asm/simple_call
CodeCoverage tool by Agustin Gianni (agustingianni@gmail.com)
Logging code coverage information to: trace.log
Loaded image: 0x1000000:0x12fe707 -> cibo
Loaded image: 0x59e1000:0x5a7efff -> dyld
Loaded image: 0x7fff6a7ed000:0x7fff6a820fff -> libclosured.dylib
Loaded image: 0x7fff6acff000:0x7fff6ad00fff -> libSystem.B.dylib
Loaded image: 0x7fff6af33000:0x7fff6af89fff -> libc++.1.dylib
Loaded image: 0x7fff6af8a000:0x7fff6afaefff -> libc++abi.dylib
Loaded image: 0x7fff6c300000:0x7fff6c6eefff -> libobjc.A.dylib
Loaded image: 0x7fff6cd9b000:0x7fff6cd9ffff -> libcache.dylib
Loaded image: 0x7fff6cda0000:0x7fff6cdaafff -> libcommonCrypto.dylib
Loaded image: 0x7fff6cdab000:0x7fff6cdb2fff -> libcompiler_rt.dylib
Loaded image: 0x7fff6cdb3000:0x7fff6cdbbfff -> libcopyfile.dylib
Loaded image: 0x7fff6cdbc000:0x7fff6ce41fff -> libcorecrypto.dylib
Loaded image: 0x7fff6cec9000:0x7fff6cf02fff -> libdispatch.dylib
Loaded image: 0x7fff6cf03000:0x7fff6cf20fff -> libdyld.dylib
Loaded image: 0x7fff6cf21000:0x7fff6cf21fff -> libkeymgr.dylib
Loaded image: 0x7fff6cf2f000:0x7fff6cf2ffff -> liblaunch.dylib
Loaded image: 0x7fff6cf30000:0x7fff6cf34fff -> libmacho.dylib
Loaded image: 0x7fff6cf35000:0x7fff6cf37fff -> libquarantine.dylib
Loaded image: 0x7fff6cf38000:0x7fff6cf39fff -> libremovefile.dylib
Loaded image: 0x7fff6cf3a000:0x7fff6cf51fff -> libsystem_asl.dylib
Loaded image: 0x7fff6cf52000:0x7fff6cf52fff -> libsystem_blocks.dylib
Loaded image: 0x7fff6cf53000:0x7fff6cfdcfff -> libsystem_c.dylib
Loaded image: 0x7fff6cfdd000:0x7fff6cfe0fff -> libsystem_configuration.dylib
Loaded image: 0x7fff6cfe1000:0x7fff6cfe4fff -> libsystem_coreservices.dylib
Loaded image: 0x7fff6cfe5000:0x7fff6cfe6fff -> libsystem_darwin.dylib
Loaded image: 0x7fff6cfe7000:0x7fff6cfedfff -> libsystem_dnssd.dylib
Loaded image: 0x7fff6cfee000:0x7fff6d037fff -> libsystem_info.dylib
Loaded image: 0x7fff6d038000:0x7fff6d05dfff -> libsystem_kernel.dylib
Loaded image: 0x7fff6d05e000:0x7fff6d0a9fff -> libsystem_m.dylib
Loaded image: 0x7fff6d0aa000:0x7fff6d0c9fff -> libsystem_malloc.dylib
Loaded image: 0x7fff6d0ca000:0x7fff6d16efff -> libsystem_network.dylib
Loaded image: 0x7fff6d16f000:0x7fff6d179fff -> libsystem_networkextension.dylib
Loaded image: 0x7fff6d17a000:0x7fff6d183fff -> libsystem_notify.dylib
Loaded image: 0x7fff6d184000:0x7fff6d18bfff -> libsystem_platform.dylib
Loaded image: 0x7fff6d18c000:0x7fff6d197fff -> libsystem_pthread.dylib
Loaded image: 0x7fff6d198000:0x7fff6d19bfff -> libsystem_sandbox.dylib
Loaded image: 0x7fff6d19c000:0x7fff6d19dfff -> libsystem_secinit.dylib
Loaded image: 0x7fff6d19e000:0x7fff6d1a5fff -> libsystem_symptoms.dylib
Loaded image: 0x7fff6d1a6000:0x7fff6d1b9fff -> libsystem_trace.dylib
Loaded image: 0x7fff6d1bb000:0x7fff6d1c0fff -> libunwind.dylib
Loaded image: 0x7fff6d1c1000:0x7fff6d1edfff -> libxpc.dylib

生成されたtrace.logをIDAのメニューバーFile -> Load file -> Code coverage fileより読み込む。 f:id:TAKEmaru:20181011233401p:plain

Coverage OverviewというカスタムViewが表示される。Golang製のバイナリで試したため、Coverage率の上位はruntime系の関数が大部分を占めている。シンボルがないバイナリでは、Coverage率が上位の関数をザッと見るのは処理系によっては効率悪いかも。

f:id:TAKEmaru:20181011183102p:plain

フィルタすることもできる。パッケージ名になっているコマンド名でフィルタすると本質っぽい関数だけが表示されていいかんじだった。

f:id:TAKEmaru:20181011183127p:plain

Disassembly View、Graph Viewの中で実際に実行された部分に色をつけてくれる。これは本質ではないアセンブリを読み飛ばすことができるので、すごく便利そう。 f:id:TAKEmaru:20181011183140p:plain

f:id:TAKEmaru:20181011194339p:plain

感想

DBIツールによる動的解析結果を、IDAでの静的解析時に効果的に利用できる点がすばらしいと感じた。 Disassembly View、Graph Viewの中で実際に実行された部分に色をつけてくれるので、読まなくていいアセンブリを無駄に読むことがなくなり解析の効率をあげられそうであった。

また、今回は試してないが複数のトレースログの差分を表示することもできるようで、これによってシンボルがないバイナリでも、Coverage Overviewに本質のルーチンだけをフィルタして表示できそうである。そのうち試してみたい。