Successfully reported this slideshow.
Your SlideShare is downloading. ×

how to port * to BitVisor

Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Ad
Loading in …3
×

Check these out next

1 of 23 Ad

More Related Content

Similar to how to port * to BitVisor (20)

Recently uploaded (20)

Advertisement

how to port * to BitVisor

  1. 1. BitVisorに「移植」する 東京農工大学 市川 遼 2017/12/05 BitVisor Summit 6
  2. 2. 自己紹介 ● 東京農工大学 工学府情報工学専攻1年 ● twitter: @icchyr ● CTF: TokyoWesterns ● 研究: OS, セキュリティ
  3. 3. 本日お話しすること ● LVisorについて ● LVisorの実装上の課題 ○ BitVisorのどの部分で動かすのか ○ どうやって呼び出すのか ○ エラーが起きたらどうするのか ○ 依存ライブラリはどうするのか ○ etc. ● これらを解決する方法を検討 ○ BitVisorに外部のプログラムを移植した例は多くあるが, ソースコードが公開されているものは少ない ○ 初期実装ではひたすらアドホックに試した → 後に限界が見えてきた ■ なるべくソースコードを改変する必要がない方法を模索 ○ 実装する上での具体的な手順について共有
  4. 4. LVisorの背景 ● VMMに汎用スクリプト言語を組み込むモチベーション ○ 比較的簡単に複雑な処理を記述可能 ○ eval相当の機能がある場合は動的にプログラムを追加可能 ○ 通常VMMに動的に機能を追加するのは難しい ● BitVisorにVMI (Virtual Machine Introspection) があるとうれしい ○ ゲストOSから不可視 ■ マルウェア解析環境として適している ○ 他のVMMに比べてパフォーマンスが優れている ■ 解析効率の向上 ● BitVisorにLuaとLibVMIを組み込んだ ○ 普通のBitVisorでは処理を追加するために Cで直接VMMを書き換える必要がある ○ スクリプト言語でBitVisorを使いたい ○ LibVMI+シンボル情報でゲスト OS解析の補助 ○ Luaのプログラムをルールとしてプロセスやネットワークを監視
  5. 5. Luaを選んだ理由 ● Luaの特徴 ○ (比較的) 早い ○ バイナリが小さい,依存ライブラリが少ない (最低限libc, libmのみ) ○ 記述方法が多様 ■ 手続き型 ■ プロトタイプベース ■ など ○ インターフェースとして有用 ● BitVisorの特徴 ○ 早い ○ VMMが小さい ○ 拡張のハードルが高い ■ processなどを書いてビルドし直す必要がある ● BitVisorに組み込む上でLuaは比較的相性が良い
  6. 6. インターフェースとしてのLua ● LuaをインターフェースとするAPIを提供 ○ システムコールフック ○ 仮想メモリアクセス ○ ネットワークパケットフィルタ ● オブジェクト指向でデータにアクセス ○ フックするイベントに対して処理を登録 ○ イベントハンドラにフック対象に関わるオブジェクトが渡される ● Luaはプロトタイプベースなので記述しやすい ○ メソッドに対して動的に処理を追加できる ○ 関数の動作を上書きすることが可能なため用途に合わせてフレームワーク的に扱える
  7. 7. LVisorの例 ● 使用例 ○ /tmp/ で始まるバイナリが起動 (execve) された時に全てのネットワーク通信を遮断 ○ 現状プロセス単位の通信は制御できない denyall = function(eth) return DROP end execve_hook = function(args) filename = args[0] -- execveの第一引数 (filename) へのポインタを取得 filename_s = pmem.read(filename, 0x100) -- filenameを文字列で取得 -- /tmp/で始まるバイナリの場合全てのネットワーク通信を遮断 if string.match(filename_s, “^/tmp/”) ~= nil then net.eth.hooks.add(“*”, “*”, “denyall”, denyall) end end syscall.hooks.add(“netproc”, execve_hook)
  8. 8. LVisorの実装方法
  9. 9. BitVisorに機能を追加する方法 ● BitVisorで処理を走らせる手段 ○ 一回のみ ■ INITFUNC ○ 定期的 ■ thread ○ dbgshから任意のタイミング ■ process ○ ゲストOSから任意のタイミング ■ vmmcall ● BitVisorの実装 (vpn, storageなど) ○ BitVisorの機能が必要な部分のみ msgbufで呼び出し,それ以外は保護ドメインで処理 ○ 必要な時のみしかRing 0で動作させない方針
  10. 10. LVisorの実装方針 ● Ring 0で動かすのは得策ではない ○ 移植するプログラムが巨大であるため ● 基本的にvpnやstorage等と同じ方針をとる ○ 必要な部分だけmsgbufでやりとりする ○ Lua,LibVMIは保護ドメインで動作させる ● まずLuaのインタプリタを組み込み,次にLibVMIを移植 ● 環境 ○ Lua: 5.3.3 ○ LibVMI: 2016年9月時点でのGitHubの版
  11. 11. BitVisorのビルドシステムおさらい ● makeをベースとしたビルドシステム ○ 下の階層をビルドした結果を上の階層にリンク ○ オブジェクト (.o) を作る場合は subdirs-1 に追加 ○ 静的ライブラリ (.a) を作る場合は asubdirs-1 に追加 ○ objs-1 にオブジェクトファイルを追加することでビルド対象を決定 ○ CFLAGSを書き換えることでコンパイルオプションを調節 ○ 基本的にカレントディレクトリは一番上 (bitvisor/) になることに注意 ● processのビルド ○ $(name)-objs にオブジェクトファイルを追加 ○ $(name)-libs に依存ライブラリ (.a) を追加 ○ bins-1 にprocessとして登録する名前を追加
  12. 12. リンクについて ● BitVisorは基本的にstatic link ○ dynamic linkがサポートされていない ○ そもそもサポートする必要がない (再利用されるコードが極めて小さいため ) ○ バイナリのローダは存在するがライブラリのローダは存在しない ● Ring 0の部分は最終的に全て同じ階層でリンクされる ○ どこかにシンボルが存在していればよい ○ processからリンクしたい場合は process-dependsに加える必要がある
  13. 13. ソースコードの配置場所 ● 全てprocess配下に置くのが正しいか? ○ vpnやstorageはそうではない ■ dbgshから呼び出すことを想定していない ● 例: vpn ○ vpn/lib/user.c に処理を書き,process/vpn.c ではexternのようにして呼び出す ○ この構成のメリット ■ process/Makefileを汚さない ■ process/ 以外からもリンクすることができる ● musl, LibVMIは一番上の階層に置く
  14. 14. 移植に必要な手順 ● 静的ライブラリまたはオブジェクトを作成する ○ BitVisorのビルドシステムに組み込む ■ findコマンドなどである程度自動化 , コンパイルオプションに注意 ○ プロジェクトのMakefileを直接叩く ■ カレントディレクトリに注意 ● 必要なプログラムの依存関係に加える ○ processであれば$(name)-libs ○ それ以外であればasubdirs-1 (or subdirs-1) ● 標準的なOSの機能を使う部分は修正する必要がある ○ 標準入出力, メモリ管理は特にBitVisorに合わせる必要がある
  15. 15. Luaの組み込み方法 ● Luaは比較的移植がしやすい ○ 依存ライブラリが少ない ○ 全てのソースコードが同じ階層に存在し,コンパイルしたオブジェクトをリンクするだけ ■ ビルドシステムへの負担が少ない ○ 静的ライブラリ (.a) を作成できればよい ● BitVisorのビルドシステムに組み込む ○ BitVisorのビルドシステムを理解する ○ process/ 以下にluaのソースコードを丸ごとコピー ○ LuaのMakefileをBitVisor向けに編集 (objs-1にLuaのプログラムを追加していくだけ ) ○ process/MakefileにLuaに関わる部分を追記 ● これだけでは動かない ○ libcが必要 ○ BitVisorは部分的にしかlibcの関数をサポートしていない
  16. 16. libcの組み込み方法 ● 必要なlibcを移植するのは大変 → 既存のlibcを移植する ● どのlibcを使うか? ○ eglibc ○ uClibc ○ newlib ○ musl libc ○ etc. ○ 比較的サイズが小さくビルドも簡単な musl libcを採用 ● BitVisorに合わせた変更が必要 ○ ファイルシステムおよび fdの概念が存在しない ○ BitVisorのprocess/libでサポートしている関数に注目 ■ 標準出力 (printf) ■ 標準入力 (lineinput) ■ メモリ管理 (alloc/free) ○ 最低限これらの機能と接続しないと動作しない
  17. 17. libcの組み込み方法 ● muslの関数を編集 ○ 標準出力 ■ __fwritexでputcharを使う (process/lib/lib_putchar.c) ■ muslのprintfを使えるようにするため ● BitVisorのprintfは浮動小数点系のフォーマット指定子に対応していない ○ 標準入力 ■ libc側で対応せずにprocessの入力を受け取るところで対処 ○ メモリ管理 ■ malloc ● process/lib/lib_mm.c:alloc を使うように修正 ■ free ● process/lib/lib_mm.c:free を使うように修正 ■ realloc ● size == 0の時のバグを修正 ■ 確保可能な領域は各 processでheap, heaplenを定義して調整
  18. 18. libcの組み込み方法 ● ビルドシステムの修正 ○ muslのMakefileをBitVisorに対応させるのは困難 ○ BitVisorのmake中にmuslのmakeを走らせるようにする ■ cleanを回避する場合は ifndef clean_p の中に書く (clean時に定義される変数の一つ ) ● リンク方法の検討 ○ プロジェクトの.aを直接リンクする (ビルド時に生成された .aを指定) ○ BitVisorのビルドシステムで.aを作る (ビルド時に生成された .oを集める) ← こちらを採用 ● 例: include makefiles/musl.mak ifndef clean_p $(info building musl...) $(info $(shell cd $(musl_dir) && make -j4 && cd - >/dev/null)) objs-1 += $(musl_o) endif
  19. 19. Luaの組み込み方法 (続き) ● Luaのインタプリタを用意する ○ lua.cをprocess向けに編集 ○ lua_writelineマクロとlua_readlineマクロをそれぞれ編集 ■ printfとlineinputを使うように修正 ○ main関数を修正 ■ setlimitを呼び出して大きくスタックを確保するように修正 ● 標準ではスタックが足りなくてクラッシュする ■ pushcfunction~reportまで削除し,代わりに doREPLを呼び出す ● argc, argvが存在しないためpushcfunctionが使えない ■ exitprocessで終了 ● 浮動小数点レジスタのサポート ○ VMM起動時にCR0を操作して有効化しておく (一時的な措置) ● debugshのprocessからLuaインタプリタが使用可能に
  20. 20. LibVMIの組み込み方法 ● LibVMIはlibcの他にGlib, json-cに依存 ○ libcと同様の方法でビルドシステムに組み込む ● LibVMIのBitVisor対応 ○ XenをベースにBitVisor用のdriverを作成 ■ ゲストOSのCPUの読み書き ■ ゲストOSの物理メモリの読み書き ■ ゲストOSの電源操作 (pause, resume, halt) ■ メモリサイズの取得 ○ CPUレジスタ操作,メモリ操作があれば理論上は動作する ○ rekallのprofileを用意 ■ 現状はファイルシステムが無いのでバイナリの dataセクションに埋め込む ■ objcopyでJSONを変換 ■ サイズが非常に大きい (Linuxで約3.3M) ため改善の必要あり
  21. 21. LibVMIの組み込み方法 ● ビルドシステムの修正 ○ LibVMIのビルドシステムはKVM, Xenなどの本来対応する VMM用のライブラリに深く依存 ○ BitVisor用のdriverをビルドするようにMakefileを作成 ■ libvmi/およびその下のarch, driver, os以下 ● 例: include makefiles/libvmi.mak CFLAGS += $(libvmi_INCLUDE) curdir = $(libvmi_dir)/driver subdirs-1 += bitvisor obj = $(subst .c,.o,$(shell find $(curdir) -maxdepth 1 -name "*.c")) objs-1 += $(obj:$(curdir)/%=%)
  22. 22. 近況 ● Luaはほぼ完全に動作 ○ muslのprint系が壊れていて変な出力が出るものの特に影響はない ● LibVMIが完全に動いていない ○ 動きはするがオフセットがずれている ● ネットワーク監視が完全に動いていない ○ netapiの使い方が把握しきれていない ● 全てのAPIに対応できていない
  23. 23. まとめ ● BitVisorへの移植は比較的容易な手順で実現可能 ○ 一番上の階層にプロジェクト用のディレクトリを切り分ける ○ プロジェクトをそのままコピーする ○ Makefile内でプロジェクトのビルドを行う ○ 生成された.oファイルを検索してobjs-1に追加 ● libc, GLibcが移植できたため大抵のプログラムは移植可能 ○ OSの機能を必要とするものは移植できない ○ BitVisorを拡張するのが容易に

×