Introducing 

Prezi AI.

Your new presentation assistant.

Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.

Loading content…
Loading…
Transcript

えんいー

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,&reg,&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

Learn more about creating dynamic, engaging presentations with Prezi