Introducing
Your new presentation assistant.
Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.
Trending searches
えんいー
3/7
6/7
7/7
5/7
4/7
2/7
1/7
未来の部屋
Regexp Assemble for PHP
VCの支援受けて会社作ります。
自己紹介
世界一わかりやすいポインタ
萌え萌えCSS
音声認識の
誤認識フィルタとしての機械学習
なのは完売
新潟アクセス修飾子
とある関数の電脳戦
(バトルプログラミング)
世界で2番目に
SEXYHOOK3
perlの魔術的ライブラリ
Regexp AssembleをPHPに移植。
正規表現を機械的に作成する。
ポインタを
超わかりやすく説明
音声認識を利用して
家電制御を制御する
未来の部屋
自己紹介
こんちにはー
jQueryを
萌え化する
プロセスの乗っ取りを防ぐ
アンチフックの話
そして、攻性防壁の構築。
一部アセンブラ
by rti
名前: rti
仕事: もうすぐ会社作ってニート脱却?
肩書き: シーランド公国伯爵
特技: イオナズンが使えます。
最近のトレンド: 音声認識
public
protected
private
そして niigata
http://d.hatena.ne.jp/rti7743/
音声認識による
ホームコントロール作ってます。
うまくいくかわかんないけど、
応援してください。 (ステマ)
手伝ってくれる人募集中。
http://rtilabs.net/
音声認識の誤認識フィルタにSVMを応用するお話です。
https://twitter.com/#!/super_rti
http://prezi.com/9t_u8vkfbukc/
http://d.hatena.ne.jp/rti7743/20111220/1324389840
http://prezi.com/jwn5gq36td7y/presentation/
http://rtilabs.net/files/2011_11_02/
http://prezi.com/2r6wmrriyeqb/niigata/
http://d.hatena.ne.jp/rti7743/20120104/1325668680
http://rtilabs.net/files/2010_12_24/moemoe_css/
動作環境
SEXYHOOKでtime関数を乗っ取る
基本はデバッグビルド
強引に接合部を作り出す。
sexyhookならね。
time関数のハードコーディング
sexyhookは、
x86 x64
CPU
A
だけど、APIフックとかはふつーにリリースでもできるよ。
関数の乗っ取り
//2000年以上か?
bool isOver2000year()
{
//現在動かしたら、絶対 TRUE にしかならない
return time(NULL) >= 946652400; //2000-01-01 00:00:00
}
VC++6 ~
gcc4 ~
SEXYHOOK3
コンパイラ
sexyhookって
何?
APIの乗っ取り
{
//現在は2012年なので結果はTRUE
bool r = isOver2000year();
printf("%d" , (int)r); //1
}
{
//time関数を乗っ取る all your function are belong to us
SEXYHOOK_FUNC_HOOK_1_BEGIN(time_t,__cdecl,time,time_t * a)
{
//昔の時刻を返すようにする
return 915116400;//1999-01-01 00:00:00
}
SEXYHOOK_FUNC_END();
//現在は2012年なので、結果は TRUE になりそうだが、
//上で関数をフックしているので、結果は FALSE
bool r = isOver2000year();
printf("%d" , (int)r); //0
}
後付けで
テスト用の接合部を
作り出せるツール
B
inline int hogehoge()
{
return 12345;
}
include "sexyhook.h"だけで使える。
メソッドの乗っ取り
最適化入っちゃうと展開される
可能性があるし・・・
対応するする詐欺: Arm clang
なんでも乗っとるよ!!
C
フック、アンフックのタイミングを遅延させたい
もっとサンプルが見たい!!
API
thisも使える
クラス
関数
関数のアドレス
引数
呼び出し規約
戻り値
SEXYHOOK_BEGIN(int,SEXYHOOK_STDCALL,&HeapCreate,(HANDLE a1,DWORD a2,SIZE_T a3))
{
return NULL;
}
SEXYHOOK_END();
SEXYHOOK_BEGIN(int,SEXYHOOK_CLASS,&classMethodCallTest::Add,(int a))
{
return SEXYHOOK_THIS(classMethodCallTest*)->Value;
}
SEXYHOOK_END();
SEXYHOOK_BEGIN(int,SEXYHOOK_CLASS,&classMethodCallTest::Add,(int a))
{
return 10;
}
SEXYHOOK_END();
SEXYHOOK_BEGIN(time_t,SEXYHOOK_CDECL,&time,(time_t * a))
{
return 915116400;//1999-01-01 00:00:00
}
SEXYHOOK_END();
publicだけしか呼べない制約あり
sexyhookのサンプルとテストが
main.cpp に書いてあるよ!!
使い方
_AS を使うと、変数に代入できる。
1.
sexyhook.h をコピーする。
2.
#include "sexyhook.h"
3.
後はフックしたい関数の定義を書く
おしまい
SEXYHOOK_BEGIN(time_t,SEXYHOOK_CDECL,&time,(time_t * a))
{
return 915116400;//1999-01-01 00:00:00
}
SEXYHOOK_END_AS() g_timehook;
void main()
{
//フックする
g_timehook.Hook();
//何か処理をする
//フック解除
g_timehook.UnHook();
}
dll内の関数
仮想メソッド
フック元の呼び出し
SEXYHOOK_BEGIN(int,SEXYHOOK_STDCALL
,SEXYHOOK_DYNAMICLOAD("dlltest.dll","DllAdd"),(int a , int b))
{
return a - b;
}
SEXYHOOK_END();
SEXYHOOK_BEGIN(int,SEXYHOOK_CLASS,&Child::g,())
{
return 103;//Child::g
}
SEXYHOOK_END(&child);
SEXYHOOK_BEGIN(int,SEXYHOOK_CLASS,&classMethodCallTest::Add,(int a))
{
return CallOriginalFunction(a);
}
SEXYHOOK_END();
SEXYHOOK_BEGIN(time_t,SEXYHOOK_CDECL,&time,(time_t * a))
{
return CallOriginalFunction(a);
}
SEXYHOOK_END();
DLL名と関数名を指定
クラスインスタンスを渡す。
仮想メソッドなので、クラスインスタンスにより、
呼び出すメソッドが決定される。
time
000977C0 push ebp
000977C1 mov ebp,esp
000977C3 sub esp,0D3Ch
000977C9 push esi
000977CA push edi
jmp テストコード
ただし、このやり方には、
一つ問題がある。
元のルーチンを呼び出すのが大変。
元のコード
一度復旧して実行する
これが SEXYHOOK2 での方法、
問題点
スレッドセーフではない。
毎回復旧とフックするので非効率
アルゴリズム
トランポリンフック
復旧
偽time関数
偽物に飛ばす
jmpコードを差し込みます。
5バイトから12バイト程度の命令です。
実行後にもう一度フックする。
(デストラクタで)
元のルーチンが破壊されている。
実行する
一度、バックアップで復旧
time
SECCONハッカソン(つくば)に誘われたので、
そこで 夜なべして作った。
x86の命令は可変長
time
レッドブルと栄養ドリンクを調合した
謎ドリンク(ユンブル)を飲みながら作った。
筑波はおかしい。
time
x86とx64の命令調を求めるコードを作った。
中途半端にやると、命令を壊してしまう。
バックアップ
000977C0 push ebp
000977C1 mov ebp,esp
000977C3 sub esp,0D3Ch
000977C9 push esi
000977CA push edi
バックアップ
000977C0 push ebp
000977C1 mov ebp,esp
000977C3 sub esp,0D3Ch
000977C9 push esi
000977CA push edi
jmp直後
効率的な
フックルーチン
jmp直後
Debugは、 オープンソースのソフトウェアを
objdump したものを食べさせてみて、
正しくパースできるか?を確認した。
x86とx64対応。
一応動いている。
ただし、マイナーな命令には、
対応できていないかもしれない。
壊す命令サイズを考えながらフックする。
何倍と壊してもいいのか?を把握する。
そのためには、
x86 x64のオペコード長を求める
ルーチンが必要になった。
9: //関数のテスト
10: int add(int a,int b)
11: {
//強引に書き換えてフックルーチンへ飛ばす
00401470 jmp `main'::`83'
::SEXYHOOKFunc388::HookFunction (00402a5e)
...
00401477 inc ebp
00401478 or al,5Dh
0040147A ret
12 }
//マシン語の長さを求めます。
//http://www2.odn.ne.jp/~hab81760/modrm_sib.htm
//http://dl.dropbox.com/u/2476414/TechResources/x86_opcodemap_1_b4.pdf
//http://download.intel.com/jp/developer/jpdoc/IA32_Arh_Dev_Man_Vol2B_i.pdf
//http://www.logix.cz/michal/doc/i386/app-a.htm
//http://www.wdic.org/w/SCI/REX%E3%83%97%E3%83%AA%E3%83%95%E3%82%A3%E3%83%83%E3%82%AF%E3%82%B9
//http://www.wdic.org/w/SCI/%E3%82%AA%E3%83%9A%E3%82%B3%E3%83%BC%E3%83%89%20(IA-32)
//http://iwaohanma.web.fc2.com/
static int OperandLength(const unsigned char* code,SEXYHOOK_CPU_ARCHITECTURE cputype)
{
//1バイト命令
//0x00 仕様がよくわからない命令
//0x01 1バイトの命令
//0x02 2バイトの命令
//...
//0xffmodrm
//0xfdmodrm + 4
//0xfcmodrm + 1
//0xfb modrm + 4 or modrm + 1 or 2
//0xfa modrm + 1 or 2
//0xf566 の影響を受ける 5バイト長の命令
//0xe566 の影響を受ける 5バイト長の命令 64bitで48をつけると 64bitになる命令
static unsigned char codeTable[] = {
//0123456789abcdef
/*0*/0xff,0xff,0xff,0xff,0x02,0xf5,0x01,0x01,0xff,0xff,0xff,0xff,0x02,0xf5,0x01,0x00,//0
/*1*/0xff,0xff,0xff,0xff,0x02,0xf5,0x01,0x01,0xff,0xff,0xff,0xff,0x02,0xf5,0x01,0x01,//1
/*2*/0xff,0xff,0xff,0xff,0x02,0xf5,0x01,0x01,0xff,0xff,0xff,0xff,0x02,0xf5,0x01,0x01,//2
/*3*/0xff,0xff,0xff,0xff,0x02,0xf5,0x01,0x01,0xff,0xff,0xff,0xff,0x02,0xf5,0x01,0x01,//3
/*4*/0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//4
/*5*/0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//5
/*6*/0x01,0x01,0xff,0xff,0x00,0x00,0x00,0x00,0x05,0xfd,0x02,0xfc,0x01,0x01,0x00,0x00,//6
/*7*/0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,//7
/*8*/0xfc,0xfd,0xfd,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//8
/*9*/0x01,0x01,0x05,0x05,0x01,0x05,0x05,0x05,0x01,0x01,0x00,0x01,0x01,0x01,0x01,0x01,//9
/*a*/0x05,0x05,0x05,0x05,0x01,0x01,0x01,0x01,0x02,0xf5,0x01,0x01,0x01,0x01,0x01,0x01,//a
/*b*/0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,//b
/*c*/0xfc,0xfc,0x03,0x01,0xff,0xff,0xfc,0xfd,0x01,0x01,0x01,0x03,0x01,0x02,0x01,0x01,//c
/*d*/0xff,0xff,0xff,0xff,0x02,0x02,0x01,0x01,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//d
/*e*/0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x02,0x05,0x05,0xf5,0x02,0xff,0xff,0xff,0xff,//e
/*f*/0x01,0x00,0x01,0x00,0x01,0x00,0xfa,0xfb,0x01,0x01,0x01,0x01,0x01,0x01,0xff,0xff //f
};
//f0から始まる 2バイト命令
static unsigned char codeTableF0[] = {
//0123456789abcdef
/*0*/0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,//0
/*1*/0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0xff,//1
/*2*/0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,//2
/*3*/0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//3
/*4*/0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//4
/*5*/0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//5
/*6*/0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0xff,//6
/*7*/0xfc,0xfc,0xfc,0xfc,0xff,0xff,0xff,0x01,0xff,0xff,0x00,0x00,0x00,0x00,0xff,0xff,//7
/*8*/0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,0x05,//8
/*9*/0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x02,0x02,0x02,0x02,0xff,0xff,0xff,0xff,//9
/*a*/0x00,0x00,0x01,0xff,0xfc,0xff,0x00,0x00,0x00,0x00,0x00,0xff,0xfc,0xff,0xff,0xff,//a
/*b*/0x02,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0xfc,0xff,0xff,0xff,0xff,0xff,//b
/*c*/0x00,0xff,0xfc,0x00,0x00,0x00,0x00,0xff,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//c
/*d*/0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//d
/*e*/0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,//e
/*f*/0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00 //f
};
unsigned char len = codeTable[*code];
unsigned char ex = 0;
unsigned char registersize = 0;
unsigned char registersize64 = 0;
if (cputype == SEXYHOOK_CPU_ARCHITECTURE_X64)
{//64bit対応 その1
if (*code == 0xf2 || *code == 0xf3)
{
code =code + 1;
ex += 1;
len = codeTable[*code];
}
}
//prefix ぷよぷよだとダイアキュートみたいな
if (*code >= 0x64 && *code <= 0x67 )
{
registersize = *code;
code =code + 1;
ex += 1;
len = codeTable[*code];
}
if (cputype == SEXYHOOK_CPU_ARCHITECTURE_X64)
{//64bit対応 その2
if ( registersize == 0x66 && *code == 0x2e)
{//66 2e 0f 1f 84 00 00 00 00 00 長いnot のように、 66 2e と入るときがあるらしい。
code =code + 1;
ex += 1;
}
if (*code >= 0x40 && *code <= 0x4f )
{
registersize64 = *code;
code =code + 1;
ex += 1;
len = codeTable[*code];
}
}
//lock prefix
if (*code == 0xf0)
{
code = code + 1;
ex += 1;
len = codeTable[*code];
}
//9b は謎w
if (*code == 0x9b)
{
if (*(code+1) == 0xdd)
{// 9b dd b4 24 50 02 00 00 fsave 0x250(%rsp)
return ex + 2 + 2 + 4;
}
else if (*(code+1) == 0x97)
{//9b 97 66 00 ???
return ex + 1 + 3;
}
else if (*(code+1) == 0x3f)
{//9b 3f 08 ???
return ex + 1 + 2;
}
else if (*(code+1) == 0xc4)
{//9b c4 20 ???
return ex + 1 + 2;
}
else
{
return ex + 1;
}
}
//2バイトの長いオペコードの処理
if (*code == 0x0f)
{
code = code + 1;
ex += 1;
len = codeTableF0[*code];
}
//repne / reps は 次のコードを見ないとわからない
if (*code == 0xf2 || *code == 0xf3)
{
if ( (*(code + 1) & 0xf0) == 0xa0)
{
return ex + 2;
}
return ex + 1;
}
if (len == 0)
{
}
else if ( len <= 0x10)
{
return len + ex;
}
else if ( len == 0xf5 || len == 0xe5)
{
if (registersize == 0x66)
{//66 bf と来ると word 単位でアクセスするらしい
return 3 + ex;
}
else
{
if (len == 0xe5 && (registersize64 >= 0x48 && registersize64 <= 0x4f) )
{//64bit拡張で 8バイトでアクセスできる命令
return 9 + ex;
}
return 5 + ex;
}
}
else
{
unsigned char mod = 0;
unsigned char reg = 0;
unsigned char rw = 0;
int modlen = modrmLen( *(code + 1) ,*(code + 2) ,&mod,®,&rw);
if ( len == 0xff)
{
return 1 + 1 + modlen + ex;
}
if ( len == 0xfd)
{//c7 85 00 fc ff ff 00 00 00 00
//mov dword ptr [ebp-400h],0
if (registersize == 0x66)
{//66 c7 と来ると word 単位でアクセスするらしい
return 1 + 1 + modlen + 2 + ex;
}
else
{
return 1 + 1 + modlen + 4 + ex;
}
}
if ( len == 0xfc)
{//c1 f8 0a
//sareax,0x0a
return 1 + 1 + modlen + 1 + ex;
}
if ( len == 0xfb)
{//modrm によって長さが変わる
if (reg == 0)
{
if (registersize == 0x66)
{
return 1 + 1 + 2 + modlen + ex;
}
else
{
return 1 + 1 + 4 + modlen + ex;
}
}
else if (reg >= 2) return 1 + 1 + modlen + ex;
else return 1 + 1 + ex;
}
if ( len == 0xfa)
{//modrm によって長さが変わる
if (reg == 0) return 1 + 1 + 1 + modlen + ex;
else if (reg >= 2) return 1 + 1 + modlen + ex;
else return 1 + 1 + ex;
}
}
DebugBreak();
return 0;
}
static int modrmLen(unsigned char modrm,unsigned char sib,unsigned char *mod,unsigned char *reg,unsigned char *rw)
{
*mod = (modrm & 0xc0) >> 6;
*reg = (modrm & 0x38) >> 3;
*rw = (modrm & 0x07);
switch (*mod)
{
case 0:
switch(*rw)
{
case 0:return 0;//eax
case 1:return 0;//ecx
case 2:return 0;//edx
case 3:return 0;//ebx
case 4:
{//SIB sibのbaseビットによって長さが違う
unsigned char base = (sib & 0x07);
if (base == 5)return 1 + 4;
elsereturn 1;
}
case 5:return 4;//disp32
case 6:return 0;//esi
case 7:return 0;//edi
}
break;
case 1:
switch(*rw)
{
case 0:return 1;//eax + disp8
case 1:return 1;//ecx + disp8
case 2:return 1;//edx + disp8
case 3:return 1;//ebx + disp8
case 4:return 1 + 1;//SIB
case 5:return 1;//ebp + disp8
case 6:return 1;//esi + disp8
case 7:return 1;//edi + disp8
}
case 2:
switch(*rw)
{
case 0:return 4;//eax + disp32
case 1:return 4;//ecx + disp32
case 2:return 4;//edx + disp32
case 3:return 4;//ebx + disp32
case 4:return 1 + 4;//SIB
case 5:return 4;//ebp + disp32
case 6:return 4;//esi + disp32
case 7:return 4;//edi + disp32
}
case 3:
switch(*rw)
{
case 0:return 0;//al/ax/eax/mm0/xmm0
case 1:return 0;//cl/cx/ecx/mm1/xmm1
case 2:return 0;//dl/dx/edx/mm2/xmm2
case 3:return 0;//bl/bx/ebx/mm3/xmm3
case 4:return 0;//ah/sp/esp/mm4/xmm4
case 5:return 0;//ch/bp/ebp/mm5/xmm5
case 6:return 0;//dh/si/esi/mm6/xmm6
case 7:return 0;//bh/di/edi/mm7/xmm7
}
}
DebugBreak();
return 0;
}
問題点
SEXYHOOK3
壊すバイトサイズを
コントロールできるようになったので、
メモリ空間をつなぎ合わせることができた!
JMPコードの部分をバックアップに入れる。
バックアップの最後には、
JMPコードの直後の命令に飛ぶ命令を入れる。
命令空間を手動でつなぐ感じ。
x86命令は可変長。
命令が何バイトあるのか
調べないといけない。
常に5バイトの
jmpコードを使うなどすると、
命令が壊れてしまう。
SEXYHOOKを使うと、いろいろなフックできます。
後付けで接合部が作れます。
APIフックもできます。
ver3から効率的なフックができるようになりました。
まとめ
rti技研もよろしくー (ステマ)
SEXYHOOK 3