この記事はBitVisor Advent Calendar 12日目の記事です.(遅刻すみません
BitVisorにプラグイン機能を実装して、各イベントに対応したコールバック関数を呼べる仕組みを実装してみます。
#プラグイン機能
ここで言うプラグイン機能とは、いわゆるdlopenとかで動的にロード/アンロードできる物ではなく(type1のbitvisorでそれをやるのは少し骨が折れそうですね...) 静的にリンクしてしまう形です。
プラグイン部分のコードはC++で書けるようにしました。プラグインの実装手順としては、Pluginクラスを継承した自分のオリジナルなプラグインクラスを定義して、諸々のマクロを書いてやるだけです。後はSignal/Slotsモデル風に、connectで各種イベントにコールバック関数を追加していきます。
#プラグイン実装例(Annotationプラグイン)
実際にAnnotationという名前のプラグインを定義してみます。
#ifndef ANNOTATION_HPP
#define ANNOTATION_HPP
#include <k2e/Plugin.hpp>
#include "CorePlugin.hpp"
namespace k2e {
class Annotation : public Plugin {
K2E_PLUGIN
public:
Annotation(K2E *k2e): Plugin(k2e) {}
void initialize();
void onModuleLoad(K2ECallbackParams *params);
};
}
#endif
Pluginを継承したAnnotationクラスです。K2E_PLUGINマクロによりプラグインに必要なもろもろの内部変数が展開されますが、開発者は気にする必要はありません。
#include "Annotation.hpp"
extern "C" {
#include "core/printf.h"
}
#include <k2e/K2E.hpp>
#include <k2e/ModuleDescriptor.h>
namespace k2e {
K2E_DEFINE_PLUGIN(Annotation, "Plugin for monitoring module and bypasses functions", "Annotation");
void Annotation::initialize()
{
k2e()->getCorePlugin()->onModuleLoad.connect(
static_cast<Plugin*>(this),
static_cast<K2ECallbackFunc_t>(&Annotation::onModuleLoad));
}
void Annotation::onModuleLoad(K2ECallbackParams *params)
{
ModuleDescriptor *md = params->ml.md;
printf("k2e: driver has loaded at 0x%llx(0x%llx): size=%llu\n",
md->LoadVBase, md->LoadPBase, md->Size);
}
}
Annotation::onModuleLoadというコールバックをコアプラグインのonModuleLoadにconnectしています。
これによりカーネルモジュールがロードされた時にAnnotation::onModuleLoadが呼ばれ、情報がprintfで表示される事になります。
モジュールのロード検知自体は独自のVMCALLとエージェントモジュールによって実現しています。
[参照]
- BitVisorにVMCALLを追加してドライバを検知してみる
http://qiita.com/RKX1209/items/91e45c5f1b9b9c7211f8
#実行
実際に実行してみると、ドライバの仮想アドレス,物理アドレス,サイズが表示できている事がわかります。
k2e: driver has loaded at 0xffffffffc092b000(0x4192b000) size=16384
#C++との連携
ところでこのプラグインC++で記述していますが、BitVisorのようなカーネル空間で動作するプログラムをC++で記述するには少し工夫(と制約)が出てきます。当然ユーザープログラムのように標準ライブラリなど使えないので、最低限の機能が使えるようABIを実装してやる必要があるわけです。
[参考]
OSDev.org C++
http://wiki.osdev.org/C%2B%2B
特にoperator new/deleteは必須ですが、これらはBitVisorのmm.cにあるalloc/freeのラッパとして実装しました。
それからMakefileもC++コードをビルドできるよう変更しました。
diff --git a/Makefile.build b/../k2e/bitvisor/Makefile.build
index 5c9e4e2..c61d65c 100644
--- a/Makefile.build
+++ b/../k2e/bitvisor/Makefile.build
@@ -12,6 +12,9 @@ bits-1 = 64
CFLAGS = -m$(bits-$(CONFIG_64)) -mno-red-zone -mno-sse -nostdinc -g -O \
-ffreestanding -fno-builtin -fno-stack-protector $(backtrace) \
-fno-strict-aliasing -Wall $(CONSTANTS-1) -I$(DIR) -Iinclude
+CXXFLAGS = -m$(bits-$(CONFIG_64)) -mno-red-zone -mno-sse -nostdinc -g -O \
+-ffreestanding -fno-builtin -fno-rtti -fno-exceptions -fno-stack-protector $(backtrace) \
+-fno-strict-aliasing -Wall $(CONSTANTS-1) -I$(DIR) -Iinclude
ASFLAGS = -m$(bits-$(CONFIG_64)) -g -Wa,-I,$(DIR) -Wa,--divide
LDFLAGS = -m$(bits-$(CONFIG_64)) -g -nostdlib -Wl,--build-id=none
outo_p = $(outo)_p
@@ -47,7 +50,8 @@ bstacksize-1-b := $(bstacksize-1-name:%=$(%).)
bstacksize-1-g := $(foreach i,$(bstacksize-1-name),$($(i)).)
bstacksize-1 := $(bstacksize-1-$(m))
bobjs = $(bobjs-1:%=$(dir)%)
-objs = $(objs-1:%=$(dir)%) $(subouto) $(subouta) $(suboutp)
+k2e-objs = $(k2eobjs-1:%=$(dir)%)
+objs = $(objs-1:%=$(dir)%) $(k2e-objs) $(subouto) $(subouta) $(suboutp)
deps = $(objs-1:%.o=$(dir)%.d) $(bobjs-1:%.o=$(dir)%.d)
bins = $(bins-1:%=$(dir)%.bin)
flags-data := CFLAGS=$(CFLAGS) ASFLAGS=$(ASFLAGS) LDFLAGS=$(LDFLAGS)
@@ -135,7 +139,7 @@ $(subouto_p) $(subouta_p) $(suboutp_p) :
# Suffix rules
.SUFFIXES :
-.SUFFIXES : .c .s .o .bin
+.SUFFIXES : .c .cpp .s .o .bin
.c.o :
$(V-info) CC $@
@@ -152,5 +156,9 @@ $(SED) -n -e '1{x' -e 's=^=$@ :>=' -e x -e '}' -e 's/#.*//' \
-e '$${x' -e 's/>.</ /g' -e 's/>$$//p' -e 's/.*: *//' \
-e 's/$$/ :/p' -e '}' $< > $(@:.o=).d || { $(RM) $@; false; }
+.cpp.o :
+ $(V-info) CXX $@
+ $(CXX) $(CXXFLAGS) -c -o $@ $<
+
# include
include $(dir)$(depends)
#その他
他にもいろいろと実装しているのですが、そのうち全てのソースコードを公開しようと思います。