好友
阅读权限10
听众
最后登录1970-1-1
|
雪魔王遗风
发表于 2019-9-16 16:10
不知道小白有没有这样的困惑,就是单独一条的汇编语句能读懂,但是好几条组合到一起就感觉云里雾里了
那你就适合跟我们一起来读反汇编代码了,把基础指令的反汇编代码读懂才能逆向出一些更难的算法,今天我们一起来读的就是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.lanzouj.com/i675dij
好了,到这里今天的学习就结束了,能力有限,可能会有疏漏之处,欢迎在评论区指出。
感谢各位看官!
|
免费评分
-
查看全部评分
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|