ダメ関数潰し
個人的にはシンボルがそのままな限り動くLD_PRELOADで対応したいところだが、
ローカル関数やアドレス指定で直接呼び出されている関数にはPLT経由で制御を奪う方法は
使えない。
本番用の弄るのはアレなので、適当にサンプルをでっち上げて練習してみるテスト。
(ソースあればこんな事しなくても済むというのは以下略)
てきとーなダメサンプル。無駄な物色々入っているけど気にしない。
int main(int argc,char ** argv){ int a=1, b=2; int ret; char buff[128]; ret = func1(a,1,a); ret = func2(a,NULL,b); printf("%d\n",ret); return 0; } int func1(int a,int b,int c){ char buff[256]; int ret; ret = a * 2 + c; return ret; } int func2(int a,char *b,int c){ sprintf(b,"%d %d",a,c); return 0; }
対象のdisassemble結果はこんなの。sprintfがNULL書き込みで死亡する。
08048587 <func2>: 8048587: 55 push %ebp 8048588: 89 e5 mov %esp,%ebp 804858a: 53 push %ebx 804858b: 83 ec 14 sub $0x14,%esp 804858e: e8 34 00 00 00 call 80485c7 <__i686.get_pc_thunk.bx> 8048593: 81 c3 85 12 00 00 add $0x1285,%ebx 8048599: 8b 45 10 mov 0x10(%ebp),%eax 804859c: 89 44 24 0c mov %eax,0xc(%esp) 80485a0: 8b 45 08 mov 0x8(%ebp),%eax 80485a3: 89 44 24 08 mov %eax,0x8(%esp) 80485a7: 8d 83 0c ef ff ff lea 0xffffef0c(%ebx),%eax 80485ad: 89 44 24 04 mov %eax,0x4(%esp) 80485b1: 8b 45 0c mov 0xc(%ebp),%eax 80485b4: 89 04 24 mov %eax,(%esp) 80485b7: e8 c4 fd ff ff call 8048380 <sprintf@plt> 80485bc: b8 00 00 00 00 mov $0x0,%eax 80485c1: 83 c4 14 add $0x14,%esp 80485c4: 5b pop %ebx 80485c5: 5d pop %ebp 80485c6: c3 ret
1. 該当箇所をnopでつぶす
ある意味常套手段。そのまま滑っていく。
- 80485b7: e8 c4 fd ff ff call 8048380 <sprintf@plt> + 80485b7: 90 nop + 80485b8: 90 nop + 80485b9: 90 nop + 80485ba: 90 nop + 80485bb: 90 nop
2. 無理矢理returnする
nopで滑っていってその後の処理に当たるのが嫌な場合はこっち。
スタック弄ってる場合はretする前に戻す必要あるので注意。(この場合は%ebxと%ebp)
戻り値書きたい場合は数バイト確保して%eaxとかにmovして積む。
- 804858e: e8 34 00 00 00 call 80485c7 <__i686.get_pc_thunk.bx> - 8048593: 81 c3 85 12 00 00 add $0x1285,%ebx + 804858e: b8 01 00 00 00 mov $0x1,%eax + 8048593: 83 c4 14 add $0x14,%esp + 8048596: 5b pop %ebx + 8048597: 5d pop %ebp + 8048598: c3 ret
全く呼び出される必要がない場合は呼び出しもとを潰せばOK。
callは5byteなので、ちょうど%eaxにmovできる為リターンコードも制御可能。