一起读反汇编代码之条件表达式

不知道小白有没有这样的困惑,就是单独一条的汇编语句能读懂,但是好几条组合到一起就感觉云里雾里了
那你就适合跟我们一起来读反汇编代码了,把基础指令的反汇编代码读懂才能逆向出一些更难的算法,今天我们一起来读的就是C++里的三元运算符———条件表达式


这里将C++的条件表达式分为5种情况,别觉得1种C++指令分为5种情况就觉得很难,不想看了,静下心来慢慢看,你一定能发现其中的规律
用的IDE是VC++6.0,程序是debug版的,release版的反汇编代码差别不大,调试器就是论坛的OD

1.简单比较并且最后两种结果的差为1,例如printf("%d\n",num==5?5:6);
此时反汇编代码:
00401058  |xor edx,edx ;  条件表达.00427A60       
0040105A  |cmp [local.1],0x5                //直接进行比较
0040105E  |setne dl        //如果相等的话此时dl为0,不相等则为1   如果A比B大呢?
00401061  |add edx,0x5                //加上5,则可确定最后的值
00401064  | push edx  ;  条件表达.00427A60
00401065  |push 条件表达.0042501C  ;  ASCII "%d\n"
0040106A  |call 条件表达.00401120
0040106F  |add esp,0x8

2.简单比较并且最后两种结果的差大于1,例如printf("%d\n",num==5?5:10);
此时反汇编代码:
00401072  | mov eax,[local.1]
00401075  | sub eax,0x5                //先让自变量减去5
00401078  |neg eax        //这是个求补指令,用在这里很巧妙,只要参数不为5,此时的EAX就不为0,一求补,符号位必然发生改变,那么影响的就是CF标志位,就会影响接下来的sbb指令
0040107A  |sbb eax,eax                //带借位的减法指令,sbb就相当于eax-eax-CF,如果之前的CF为1那么现在eax就等于FFFF FFFF
0040107C  |and eax,0x5  //如果前面的相等eax为0,这条语句执行完后eax仍然为0,如果之前是FFFF FFFF那么执行完这条语句之后就变成5了
0040107F  |add eax,0x5 //这里再加上A和B的差值,最后EAX就保存着结果了
00401082  | push eax
00401083  |push 条件表达.0042501C ;  ASCII "%d\n"
00401088  |call 条件表达.00401120
0040108D  |add esp,0x8

3.复杂的比较且最后两种结果的差值大于1,例如printf("%d\n",num<6?5:10);
此时的反汇编代码:
00401090  |xor ecx,ecx  ;  条件表达.00427A60
00401092  |cmp [local.1],0x6
00401096  |setge cl //这个setge应该就是setg命令,大于等于置位命令 , 就是此时参数大于6时cl会被置为1
00401099  |dec ecx  ;  条件表达.00427A60  //此时ECX减1,那么ECX的值就只有0跟FFFF FFFF两种情况
0040109A  | and ecx,-0x5 //这里and -5其实就是A-B的差,为的就是区分出来前面的值,0的话此时不变FFFF FFFF的话变为-5
0040109D  |add ecx,0xA //再加上10,就能出结果了
004010A0  |push ecx  ;  条件表达.00427A60
004010A1  |push 条件表达.0042501C  ;  ASCII "%d\n"
004010A6  | call 条件表达.00401120
004010AB  | add esp,0x8
走一遍啊:刚开始输入5,接下来的cmp命令就是跟setge命令一起比较条件是否成立,成立的话cl就赋值为0,不成立的话就赋为1。再将这个值减去1(此时为的就是接下来做and运算),然后and A和
B的差,因为输入的5条件成立,所以此时ECX为FFFF FFFF,一and那么ECX变为-5,之后再加上10,就出结果了
这个代码多看几遍,再好好想想如果是复杂的比较且最后两种结果的差值等于1呢

4.A或者B是参数的,例如:printf("%d\n",num==5?k:10);
此时的反汇编代码:
004010AE  |cmp [local.1],0x5
004010B2  | jnz short 条件表达.004010BC
004010B4  | mov edx,[local.2]
004010B7  |mov [local.3],edx ;  条件表达.00427A60
004010BA  |jmp short 条件表达.004010C3
004010BC  |mov [local.3],0xA
004010C3  |mov eax,[local.3]
004010C6  |push eax
004010C7  |push 条件表达.0042501C ;  ASCII "%d\n"
004010CC  |call 条件表达.00401120
004010D1  |add esp,0x8
这时的代码才是正常的,先比较然后跳转赋值的代码

5.复杂的比较且最后两种结果的差值等于1,例如:printf("%d\n",num<6?5:6);
此时的汇编代码:
004010AB  |add esp,0x8
004010AE  |xor edx,edx  ;  条件表达.00427A60
004010B0  |cmp [local.1],0x6
004010B4  |setge dl
004010B7  |add edx,0x5 //哈哈,其实在获取dl之后再加上A就好了
004010BA  | push edx  ;  条件表达.00427A60
004010BB  |push 条件表达.0042501C ;  ASCII "%d\n"
004010C0  |call 条件表达.00401120
004010C5  |add esp,0x8
到这的话,再想想,如果是A>B呢,现在再加上A的值不就错了嘛,num<6?6:5是不是等价于num>=6?5:6呢,那么其实就是把setge命令换成setl(小于置位命令就好了)

最后再附上源码跟程序好了:https://www.lanzous.com/i675dij
好了,到这里今天的学习就结束了,能力有限,可能会有疏漏之处,欢迎在评论区指出。
感谢各位看官!




THE END
喜欢就支持以下吧
点赞0
分享
评论 抢沙发
  • 管埋员

    昵称

  • 取消
    昵称