0x080485d2<_Z7absdiffii+46>: ret cmp0xc(?p),êx
jge0x80485c1<_Z7absdiffii+29> mov0x8(?p),íx mov-0x4(?p),êx
从上面的三句我们能够看出那个地方确实是执行if条件语句了。也能够看出if条件语句反汇编后的一些特征,我们一般能够认为cmp+条件跳转指令+jmp跳转,确实是if条件语句反汇编的代码。这关于我们在实际中分析代码需要快速识别一些特征反汇编代码很有关心。也方便我们关于代码的整体结构有更好的认识,记住一些常用的特征代码结构是必要的,这些也能够从正面入手,再反面进行分析,从而能够提高快速分析汇编代码的能力。 mov0x8(?p),íx取得x mov0xc(?p),êx取得y
movêx,ìx把y放入寄存器ìx中 subíx,ìx得到x–y movìx,-0x4(?p)
mov-0x4(?p),êx将结果放入êx中返回
由于上面的跳转指令是jge即表示大于等于跳转,而if条件语句本身的比较是用<进行的,因此上面这段汇编代码是先进行else后面的语句体进行执行的。对代码进行分析即能够明白。另外一般函数的返回值基本上用êx寄存器返回的,看最后一句就能够明白了。
C语言提供了好几种循环结构,即while、for和do-while。汇编语言中并没有相应的指令存在,作为替代,将条件测试和跳转组合起来实现循环的效果。比较有趣的是,大多数汇编器依照一个循环的do-while形式来产生循环代码。 do-while循环
其通用形式是如此的: do
body-statement while(test-expr);
循环的效果确实是重复执行body-statement,对test-expr求值,假如求值的结果为非零,就接着循环。注意,body-statement至少执行一次。 看看下面举的例子来进行分析。 #include
inti=0; intval=0; intnval=1; do{
intt=val+nval; val=nval; nval=t;
i++;
}while(i intmain() { intm=5; intans=0; ans=fib_dw(m); printf(“%d\\n”,ans); return0; } 0x080485a4<_Z6fib_dwi+0>: push?p 0x080485a5<_Z6fib_dwi+1>: mov%esp,?p 0x080485a7<_Z6fib_dwi+3>: sub$0x10,%esp 0x080485aa<_Z6fib_dwi+6>: movl$0x0,-0x4(?p) 0x080485b1<_Z6fib_dwi+13>: movl$0x0,-0x8(?p) 0x080485b8<_Z6fib_dwi+20>: movl$0x1,-0xc(?p) 0x080485bf<_Z6fib_dwi+27>: mov-0xc(?p),íx 0x080485c2<_Z6fib_dwi+30>: mov-0x8(?p),êx 0x080485c5<_Z6fib_dwi+33>: addíx,êx 0x080485c7<_Z6fib_dwi+35>: movêx,-0x10(?p) 0x080485ca<_Z6fib_dwi+38>: mov-0xc(?p),êx 0x080485cd<_Z6fib_dwi+41>: movêx,-0x8(?p) 0x080485d0<_Z6fib_dwi+44>: mov-0x10(?p),êx 0x080485d3<_Z6fib_dwi+47>: movêx,-0xc(?p) 0x080485d6<_Z6fib_dwi+50>: addl$0x1,-0x4(?p) 0x080485da<_Z6fib_dwi+54>: mov-0x4(?p),êx 0x080485dd<_Z6fib_dwi+57>: cmp0x8(?p),êx 0x080485e0<_Z6fib_dwi+60>: jl0x80485bf<_Z6fib_dwi+27> 0x080485e2<_Z6fib_dwi+62>: mov-0x8(?p),êx 0x080485e5<_Z6fib_dwi+65>: leave 0x080485e6<_Z6fib_dwi+66>: ret 这段代码确实是while语句括号进行的条件比较, 0x080485da<_Z6fib_dwi+54>: mov-0x4(?p),êx 0x080485dd<_Z6fib_dwi+57>: cmp0x8(?p),êx 0x080485e0<_Z6fib_dwi+60>: jl0x80485bf<_Z6fib_dwi+27> 先将局部变量i的值放入到êx寄存器中,再与传进来的参数n进行比较,假如小于那么进行跳转,我们能够看出while条件语句的反汇编后的特征结构为cmp+条件跳转语句。这也一定程度说明了do-while这种循环结构反汇编后的代码比较少,不明白效率是否有一定的提高,对一些优化能够进行实践操作。 while循环的通用形式是如此的: while〔test-expr〕 body-statement 它与do-while的不同之处在于对test-expr求值,在第一次执行body-statement之前,循环就可能中止了。 #include intloop_while(inta,intb) { inti=0; intresult=a; while(i<256) { result+=a; a-=b; i+=b; } returnresult; } intmain() { intn=5,m=6; intans=0; ans=loop_while(n,m); printf(“%d\\n”,ans); return0; } 0x080485a4<_Z10loop_whileii+0>: push?p 0x080485a5<_Z10loop_whileii+1>: mov%esp,?p 0x080485a7<_Z10loop_whileii+3>: sub$0x10,%esp 0x080485aa<_Z10loop_whileii+6>: movl$0x0,-0x4(?p) 0x080485b1<_Z10loop_whileii+13>: mov0x8(?p),êx 0x080485b4<_Z10loop_whileii+16>: movêx,-0x8(?p) 0x080485b7<_Z10loop_whileii+19>: jmp0x80485cb<_Z10loop_whileii+39> 0x080485b9<_Z10loop_whileii+21>: mov0x8(?p),êx 0x080485bc<_Z10loop_whileii+24>: addêx,-0x8(?p) 0x080485bf<_Z10loop_whileii+27>: mov0xc(?p),êx 0x080485c2<_Z10loop_whileii+30>: subêx,0x8(?p) 0x080485c5<_Z10loop_whileii+33>: mov0xc(?p),êx 0x080485c8<_Z10loop_whileii+36>: addêx,-0x4(?p) 0x080485cb<_Z10loop_whileii+39>: cmpl$0xff,-0x4(?p) 0x080485d2<_Z10loop_whileii+46>: jle0x80485b9<_Z10loop_whileii+21> 0x080485d4<_Z10loop_whileii+48>: mov-0x8(?p),êx 0x080485d7<_Z10loop_whileii+51>: leave 0x080485d8<_Z10loop_whileii+52>: ret 上面红色的红色标记确实是while条件语句反汇编后的特征结构,从正向动身, 再从逆向来分析语言的一些机制关于我们更好的理解一些语言机制的实现编译器在背后实现了一些什么,这些大部分能够从反汇编后的代码看出。 for循环的通用形式: for(init-expr;test-expr;update-expr) body-statement C语言标准说明,如此一个循环的行为与下面这段使用while循环的代码的行为一样: init-expr while(test-expr){ body-statement update-expr; } 程序首先会对初始化表达式init-expr求值。然后进行循环,它会先对测试条件test-expr求值,假如测试结果为“假”就会退出,然后执行循环体body-statement,最后对更新表达式update-expr求值。 #include intval=1; intnval=1; for(i=1;i intt=val+nval; val=nval; nval=t; } returnval; } intmain() { inta=5; intans=0; ans=fib_for(a); printf(“%d\\n”,ans); return0; } 0x080485a4<_Z7fib_fori+0>: push?p 0x080485a5<_Z7fib_fori+1>: mov%esp,?p 0x080485a7<_Z7fib_fori+3>: sub$0x10,%esp 0x080485aa<_Z7fib_fori+6>: movl$0x1,-0x8(?p) 0x080485b1<_Z7fib_fori+13>: movl$0x1,-0xc(?p) 0x080485b8<_Z7fib_fori+20>: movl$0x1,-0x4(?p) 0x080485bf<_Z7fib_fori+27>: jmp0x80485dc<_Z7fib_fori+56> 0x080485c1<_Z7fib_fori+29>: mov-0xc(?p),íx 0x080485c4<_Z7fib_fori+32>: mov-0x8(?p),êx 0x080485c7<_Z7fib_fori+35>: addíx,êx 0x080485c9<_Z7fib_fori+37>: movêx,-0x10(?p) 0x080485cc<_Z7fib_fori+40>: mov-0xc(?p),êx 0x080485cf<_Z7fib_fori+43>: movêx,-0x8(?p) 0x080485d2<_Z7fib_fori+46>: mov-0x10(?p),êx 0x080485d5<_Z7fib_fori+49>: movêx,-0xc(?p) 0x080485d8<_Z7fib_fori+52>: addl$0x1,-0x4(?p) 0x080485dc<_Z7fib_fori+56>: mov-0x4(?p),êx 0x080485df<_Z7fib_fori+59>: cmp0x8(?p),êx 0x080485e2<_Z7fib_fori+62>: jl0x80485c1<_Z7fib_fori+29> 0x080485e4<_Z7fib_fori+64>: mov-0x8(?p),êx 0x080485e7<_Z7fib_fori+67>: leave 那个地方的反汇编代码结构与上面的while条件语句是一样的,也说明在高级语言的不同形式语句在底层的表现有可能是一样的或是以相似的方式的来实现的。 switch语句提供了依照一个整数索引值进行多重分支的能力,相比起用很长的if-else语句,使用跳转表的优点是执行开关语句的时间和开关情况的数量无关。如此不仅提高了C代码的可读性,而且通过使用一种称为跳转表的数据结构使得实现更加高效。跳转表是一个数组,表项i是一个代码段的地址,那个代码段实现的是当开关索引值等于i时程序应该采取的动作。下面给个程序来个感性的认识。 intswitch_eg(intx) { intresult=x; switch(x) { case100: result*=13; break; case102: result+=10; break; case103: result+=11; break; case104: case106: result*=result; break; default: result=0;