|
|
gcc常用的编译选项对代码的影响 |
|
|
作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站 |
gcc常用的编译选项对代码的影响 |
本文出自:http://xfocus.org 作者:alert7 |
测试环境?redhat?6.2
★?前言
本文讨论gcc的一些常用编译选项对代码的影响。当然代码变了, 它的内存布局也就会变了,随之exploit也就要做相应的变动。 gcc的编译选项实在太多,本文检了几个最常用的选项。
★?演示程序
[alert7@redhat62?alert7]$?cat?>?test.c #include? void?hi(void) { printf("hi"); }
int?main(int?argc,?char?*argv[]) { ????????hi(); ????????return?0; }
★?一般情况
[alert7@redhat62?alert7]$?gcc?-o?test?test.c [alert7@redhat62?alert7]$?wc?-c?test ??11773?test [alert7@redhat62?alert7]$?gdb?-q?test (gdb)?disass?main Dump?of?assembler?code?for?function?main: 0x80483e4?:???????push???%ebp 0x80483e5?:?????mov????%esp,%ebp 0x80483e7?:?????call???0x80483d0? 0x80483ec?:?????xor????%eax,%eax 0x80483ee?:????jmp????0x80483f0? 0x80483f0?:????leave 0x80483f1?:????ret .... End?of?assembler?dump. (gdb)?disass?hi Dump?of?assembler?code?for?function?hi: 0x80483d0?:????????push???%ebp 0x80483d1?:???????mov????%esp,%ebp 0x80483d3?:???????push???$0x8048450 0x80483d8?:???????call???0x8048308? 0x80483dd?:??????add????$0x4,%esp 0x80483e0?:??????leave 0x80483e1?:??????ret 0x80483e2?:??????mov????%esi,%esi End?of?assembler?dump.
来看看部分的内存映象 ???????????????????(内存高址) ??????????????????????????????+--------+ ??????????????????????????????|bffffbc4|?argv的地址(即argv[0]的地址) ???????????????????0xbffffb84?+--------+ ??????????????????????????????|00000001|?argc的值 ???????????????????0xbffffb80?+--------+ ??????????????????????????????|400309cb|main的返回地址 ???????????????????0xbffffb7c?+--------+?<--?调用main函数前的esp ??????????????????????????????|bffffb98|?调用main函数前的ebp ???????????????????0xbffffb78?+--------+?<--?main函数的ebp ??????????????????????????????|080483ec|?hi()的返回地址 ???????????????????0xbffffb74?+--------+ ??????????????????????????????|bffffb78|?调用hi()前的esp ???????????????????0xbffffb70?+--------+? ??????????????????????????????|08048450|?"hi"的地址 ???????????????????0xbffffb6c?+--------+? ??????????????????????????????|?......?| ???????????????????(内存低址)
leave????指令所做的操作相当于MOV?ESP,EBP?然后?POP?EBP? ret????指令所做的操作相当于POP?EIP
★?-O?编译选项
With?`-O',?the?compiler?tries?to?reduce?code?size?and?execution?time. When?you?specify?`-O',?the?two?options?`-fthread-jumps'?and? `-fdefer-pop'?are?turned??on 优化,减少代码大小和执行的时间
[alert7@redhat62?alert7]$?gcc?-O?-o?test?test.c [alert7@redhat62?alert7]$?wc?-c?test ??11757?test [alert7@redhat62?alert7]$?gdb?-q?test (gdb)?disass?main Dump?of?assembler?code?for?function?main: 0x80483d8?:???????push???%ebp 0x80483d9?:?????mov????%esp,%ebp 0x80483db?:?????call???0x80483c8? 0x80483e0?:?????xor????%eax,%eax 0x80483e2?:????leave 0x80483e3?:????ret 0x80483e4?:????nop ... End?of?assembler?dump. (gdb)?disass?hi Dump?of?assembler?code?for?function?hi: 0x80483c8?:????????push???%ebp 0x80483c9?:???????mov????%esp,%ebp 0x80483cb?:???????push???$0x8048440 0x80483d0?:???????call???0x8048308? 0x80483d5?:??????leave 0x80483d6?:??????ret 0x80483d7?:??????nop End?of?assembler?dump.
在main()中,把一条jmp指令优化掉了,很显然,这条指令是可以不需要的。 在hi()中,把add????$0x4,%esp优化掉了,这会不会使stack不平衡呢? 来看看部分的内存映象 ???????????????????(内存高址) ??????????????????????????????+--------+ ??????????????????????????????|bffffbc4|?argv的地址(即argv[0]的地址) ???????????????????0xbffffb84?+--------+ ??????????????????????????????|00000001|?argc的值 ???????????????????0xbffffb80?+--------+ ??????????????????????????????|400309cb|main的返回地址 ???????????????????0xbffffb7c?+--------+?<--?调用main函数前的esp ??????????????????????????????|bffffb98|?调用main函数前的ebp ???????????????????0xbffffb78?+--------+?<--?main函数的ebp ??????????????????????????????|080483e0|?hi()的返回地址 ???????????????????0xbffffb74?+--------+ ??????????????????????????????|bffffb78|?调用hi()前的esp ???????????????????0xbffffb70?+--------+? ??????????????????????????????|08048440|?"hi"的地址 ???????????????????0xbffffb6c?+--------+? ??????????????????????????????|?......?| ???????????????????(内存低址)
leave????指令所做的操作相当于把MOV?ESP,EBP?然后?POP?EBP?? 看到leave指令操作了没有,先把ebp-->esp,再pop?ebp,这样即使 在过程内堆栈的esp,ebp是不平衡的,但只要返回时候碰到leave指令 就会平衡了,所以把add????$0x4,%esp优化掉也是没有问题的。
★?-O2?编译选项
-O2????Optimize??even?more.??Nearly?all?supported?optimizations?that?do? ????not?involve?a?space-speed?tradeoff?are?performed.??Loop?unrolling ????and?function?inlining?are?not?done,?for?example.??As?compared?to?-O, ????????this?option?increases?both?compilation?time?and?the?performance?of ????the?generated?code.
[alert7@redhat62?alert7]$?gcc?-O2?-o?test?test.c [alert7@redhat62?alert7]$?wc?-c?test ??11757?test [alert7@redhat62?alert7]$?gdb?-q?test (gdb)?disass?main Dump?of?assembler?code?for?function?main: 0x80483d8?:???????push???%ebp 0x80483d9?:?????mov????%esp,%ebp 0x80483db?:?????call???0x80483c8? 0x80483e0?:?????xor????%eax,%eax 0x80483e2?:????leave 0x80483e3?:????ret ... 0x80483ef?:????nop End?of?assembler?dump. (gdb)?disass?hi Dump?of?assembler?code?for?function?hi: 0x80483c8?:????????push???%ebp 0x80483c9?:???????mov????%esp,%ebp 0x80483cb?:???????push???$0x8048440 0x80483d0?:???????call???0x8048308? 0x80483d5?:??????leave 0x80483d6?:??????ret 0x80483d7?:??????nop End?of?assembler?dump.
由于程序比较简单,再优化也没有好优化的了,所以跟-O出来的一样。
★?-fomit-frame-pointer?编译选项
-fomit-frame-pointer ??????????????Don't?keep?the?frame?pointer?in?a?register?for?functions? ??????????that?don't?need?one.??This?avoids?the??instructions?to?save,? ??????????set?up?and?restore?frame?pointers;?it?also?makes?an?extra? ??????????register?available?in?many?functions.??It?also?makes? ??????????debugging?impossible?on?most?machines.
忽略帧指针。这样在程序就不需要保存,安装,和恢复ebp了。这样ebp也就是一个 free的register了,在函数中就可以随便使用了。
[alert7@redhat62?alert7]$?gcc?-fomit-frame-pointer?-o?test?test.c [alert7@redhat62?alert7]$?wc?-c?test ??11773?test [alert7@redhat62?alert7]$?gdb?-q?test (gdb)?disass?main Dump?of?assembler?code?for?function?main: 0x80483e0?:???????call???0x80483d0? 0x80483e5?:?????xor????%eax,%eax 0x80483e7?:?????jmp????0x80483f0? 0x80483e9?:?????lea????0x0(%esi,1),%esi 0x80483f0?:????ret .... End?of?assembler?dump. (gdb)?disass?hi Dump?of?assembler?code?for?function?hi: 0x80483d0?:????????push???$0x8048450 0x80483d5?:???????call???0x8048308? 0x80483da?:??????add????$0x4,%esp 0x80483dd?:??????ret 0x80483de?:??????mov????%esi,%esi End?of?assembler?dump.
在main()和hi()中都去掉了以下指令 push???%ebp mov????%esp,%ebp//这两条指令安装 leave//这条指令恢复 来看看部分的内存映象 ???????????????????(内存高址) ??????????????????????????????+--------+ ??????????????????????????????|bffffbc4|?argv的地址(即argv[0]的地址) ???????????????????0xbffffb84?+--------+ ??????????????????????????????|00000001|?argc的值 ???????????????????0xbffffb80?+--------+ ??????????????????????????????|400309cb|main的返回地址 ???????????????????0xbffffb7c?+--------+? ??????????????????????????????|080483e5|?hi()的返回地址 ???????????????????0xbffffb78?+--------+ ??????????????????????????????|08048450|??"hi"字符串的地址 ???????????????????0xbffffb74?+--------+? ??????????????????????????????|?......?| ???????????????????(内存低址) 没有保存上层执行环境的ebp.
★?-fomit-frame-pointer?&&?-O2?
-fomit-frame-pointer编译选项去掉了 push???%ebp mov????%esp,%ebp//这两条指令安装 leave//这条指令恢复 -O2编译选项去掉了 add????$0x4,%esp
两个加起来会不会这四条指令一起去掉,从而使stack不平衡呢?
[alert7@redhat62?alert7]$?gcc?-fomit-frame-pointer?-O2?-o?test?test.c [alert7@redhat62?alert7]$?wc?-c?test ??11741?test [alert7@redhat62?alert7]$?gdb?-q?test (gdb)?disass?main Dump?of?assembler?code?for?function?main: 0x80483d8?:???????call???0x80483c8? 0x80483dd?:?????xor????%eax,%eax 0x80483df?:?????ret End?of?assembler?dump. (gdb)?disass?hi Dump?of?assembler?code?for?function?hi: 0x80483c8?:????????push???$0x8048430 0x80483cd?:???????call???0x8048308? 0x80483d2?:??????add????$0x4,%esp 0x80483d5?:??????ret 0x80483d6?:??????mov????%esi,%esi End?of?assembler?dump. 来看看部分的内存映象 ???????????????????(内存高址) ??????????????????????????????+--------+ ??????????????????????????????|bffffbc4|?argv的地址(即argv[0]的地址) ???????????????????0xbffffb84?+--------+ ??????????????????????????????|00000001|?argc的值 ???????????????????0xbffffb80?+--------+ ??????????????????????????????|400309cb|main的返回地址 ???????????????????0xbffffb7c?+--------+? ??????????????????????????????|080483dd|?hi()的返回地址 ???????????????????0xbffffb78?+--------+ ??????????????????????????????|08048430|??"hi"字符串的地址 ???????????????????0xbffffb74?+--------+? ??????????????????????????????|?......?| ???????????????????(内存低址)
此时就没有把add????$0x4,%esp优化掉,如果优化掉的话,整个stack就 会变的不平衡,从而会导致程序出错。
★?-fPIC?编译选项
-fPIC????If??supported?for?the?target?machine,?emit?position-independent ????code,?suitable?for?dynamic?linking,even?if?branches?need?large? ????displacements. 产生位置无关代码(PIC),一般创建共享库时用到。 在x86上,PIC的代码的符号引用都是通过ebx进行操作的。
[alert7@redhat62?alert7]$?gcc?-fPIC?-o?test?test.c [alert7@redhat62?alert7]$?wc?-c?test ??11805?test [alert7@redhat62?alert7]$?gdb?-q?test (gdb)?disass?main Dump?of?assembler?code?for?function?main: 0x80483f8?:???????push???%ebp 0x80483f9?:?????mov????%esp,%ebp 0x80483fb?:?????push???%ebx 0x80483fc?:?????call???0x8048401? 0x8048401?:?????pop????%ebx//取得该指令的地址 0x8048402?:????add????$0x1093,%ebx//此时ebx里面存放着是GOT表的地址 0x8048408?:????call???0x80483d0? 0x804840d?:????xor????%eax,%eax 0x804840f?:????jmp????0x8048411? 0x8048411?:????mov????0xfffffffc(%ebp),%ebx 0x8048414?:????leave 0x8048415?:????ret ... End?of?assembler?dump. (gdb)?disass?hi Dump?of?assembler?code?for?function?hi: 0x80483d0?:????????push???%ebp 0x80483d1?:???????mov????%esp,%ebp 0x80483d3?:???????push???%ebx 0x80483d4?:???????call???0x80483d9? 0x80483d9?:???????pop????%ebx 0x80483da?:??????add????$0x10bb,%ebx 0x80483e0?:??????lea????0xffffefdc(%ebx),%edx 0x80483e6?:??????mov????%edx,%eax 0x80483e8?:??????push???%eax 0x80483e9?:??????call???0x8048308? 0x80483ee?:??????add????$0x4,%esp 0x80483f1?:??????mov????0xfffffffc(%ebp),%ebx 0x80483f4?:??????leave 0x80483f5?:??????ret 0x80483f6?:??????mov????%esi,%esi End?of?assembler?dump. 来看看部分的内存映象 ?? ????(内存高址) ??????????????+--------+ ??????????????|bffffbc4|?argv的地址(即argv[0]的地址) ???0xbffffb84?+--------+ ??????????????|00000001|?argc的值 ???0xbffffb80?+--------+ ??????????????|400309cb|main的返回地址 ???0xbffffb7c?+--------+?<--?调用main函数前的esp ??????????????|bffffb98|?调用main函数前的ebp ???0xbffffb78?+--------+?<--?main函数的ebp ??????????????|401081ec|?保存的ebx ???0xbffffb74?+--------+ ??????????????|0804840d|?(存放过call?0x8048401的下一条指令地址) ???0xbffffb70?+--------+? ??????????????|bffffb78|?调用hi()前的esp ???0xbffffb6c?+--------+? ??????????????|08049494|?GOT表地址 ???0xbffffb68?+--------+? ??????????????|08048470|(存放过call?0x80483d9的下一条指令地址)? ???0xbffffb64?+--------+? ??????????????|?......?| ?????(内存低址)
★?-static?编译选项
-static ????On?systems?that?support?dynamic?linking,?this?prevents? ????linking?with?the?shared?libraries.??On?other??systems,? ????this?option?has?no?effect. 把一些函数都静态的编译到程序中,而无需动态链接了。
[alert7@redhat62?alert7]$?gcc?-o?test?-static?test.c [alert7@redhat62?alert7]$?wc?-c?test 962808?test [alert7@redhat62?alert7]$?gdb?-q?test (gdb)?disass?main Dump?of?assembler?code?for?function?main: 0x80481b4?:???????push???%ebp 0x80481b5?:?????mov????%esp,%ebp 0x80481b7?:?????call???0x80481a0? 0x80481bc?:?????xor????%eax,%eax 0x80481be?:????jmp????0x80481c0? 0x80481c0?:????leave 0x80481c1?:????ret ... End?of?assembler?dump. (gdb)?disass?hi Dump?of?assembler?code?for?function?hi: 0x80481a0?:????????push???%ebp 0x80481a1?:???????mov????%esp,%ebp 0x80481a3?:???????push???$0x8071528 0x80481a8?:???????call???0x804865c? 0x80481ad?:??????add????$0x4,%esp 0x80481b0?:??????leave 0x80481b1?:??????ret 0x80481b2?:??????mov????%esi,%esi End?of?assembler?dump. [alert7@redhat62?alert7]$?ldd?test ????????not?a?dynamic?executable -static出来的代码已经没有PLT了,GOT虽然有,已经全部为0了。
| | 
|
|
相关文章:相关软件: |
|