関数ポインタとmprotectを使って関数の領域を上書き2

http://d.hatena.ne.jp/kanbayashi/20081005/p1
とかやってみたついでに遊んでみる。


#include

void hoge(){
printf("hoge\n");
}

void bar(){
printf("bar\n");
}

void main(){
bar();
}

こうすると当然


bar
と出力されるわけだけど、ここでbar関数にhoge関数の中身をコピーして、出力される文字列を入れ替えちゃおう。

下調べ

とりあえず、hoge関数とbar関数の中身をobdumpで調べる

objdump -d hoge_bar.out


08048414 :
8048414: 55 push %ebp
8048415: 89 e5 mov %esp,%ebp
8048417: 83 ec 08 sub $0x8,%esp
=============================ココ==================================
804841a: c7 04 24 00 86 04 08 movl $0x8048600,(%esp)
===================================================================
8048421: e8 52 ff ff ff call 8048378
8048426: c9 leave
8048427: c3 ret

08048428 :
8048428: 55 push %ebp
8048429: 89 e5 mov %esp,%ebp
804842b: 83 ec 08 sub $0x8,%esp
=============================ココ==================================
804842e: c7 04 24 05 86 04 08 movl $0x8048605,(%esp)
===================================================================
8048435: e8 3e ff ff ff call 8048378
804843a: c9 leave
804843b: c3 ret

ヒープにある文字列を取り出すコードは、
関数の先頭+6バイト目から始まる7バイトにあるみたいだから、そこをコピーしてあげればよさそう。

書いてみる


#include
#include
#include

void hoge(){
printf("hoge\n");
}

void bar(){
printf("bar\n");
}

void main(){
void (*hoge_p)();
void (*bar_p)();
int *p;
unsigned int p_i;
int i;

hoge_p = hoge;
bar_p = bar;

p = bar;
p_i = p;
/* mprotectに渡すアドレスはページ境界(4K)に合わせる */
p = p_i & 0xFFFFF000;
/* bar関数のマップされている領域を書き込み可能にする */
if(mprotect(p,0x1000,PROT_WRITE | PROT_EXEC) < 0){
perror("mprotect");
}

/* 文字列のデータを持ってくるところのみコピー */
memcpy(bar_p+6,hoge_p+6,7);
printf("write succeeded\n");

/* さてどうなるかな */
bar();
}

出力

$./hoge_bar.out
write succeeded
hoge

やったー、書き換え成功。