今天在分析一个样本的时候,发现一段代码。
1 // .text:100012DF sub esi, 0B7h // 183 2 // .text:100012E5 neg esi 3 // .text:100012E7 sbb esi, esi 4 // .text:100012EA inc esi
如果源操作数是 0,则 CF 标志清除为 0;否则设置为 1。OF、SF、ZF、AF 及 CF 标志根据结果设置。
neg求补指令:相当于按各位取反加1
现在代入三种值来进行验证:
1、esi 等于 183。则有:
sub esi, 0b7h; esi == 0; cf == 0;
neg esi; esi == 0; cf == 0;
sbb esi, esi; esi == 0; cf == 0;
inc esi; esi == 1;
最终结果为:1
2、esi 小于 183。则有:
sub esi, 0b7h; esi == 负数; cf == 1;
neg esi; esi == 正数; cf == 1;
sbb esi, esi; esi == -1; cf == 1; sbb指令带cf(进位、借位)减法.多减去一个1.则为-1
inc esi; esi == 0; cf == 1;
最终结果为:0
3、esi 大于 183。则有:
sub esi, 0b7h; esi == 正数; cf == 0;
neg esi; esi == 负数; cf == 1;
sbb esi, esi; esi == -1; cf == 1; sbb指令带cf(进位、借位)减法.多减去一个1.则为-1
inc esi; esi == 0; cf == 1;
最终结果为:0
那么遇到以上代码。则为vc编译器在02中,对逻辑跳转进行的优化。
直接还原为:
if (esi == 183)
{
return true;
}
return false;
==============================================================
计算机中数码的表示:
定义-》
正数:原码,反码,补码相同。
负数:原码为其对应正数原码最高符号位取反。
反码为其原码除符号位外都取反。
补码为其原码除符号位外取反加1。
所以最高位符号位都不变。
补码机:正数补码为其原码,负数为其正数原码取反加1。
NEG指令,相当于0-OPR,并影响进位标志CF.
数学意义上相当于:相当于0-OPR
在计算时实际是以补码形式运算,运算时只有0不影响CF,其它情况都影响CF.为什么,请看以下分析:
(1)假设有数:a=3;
那么:NEG a
分析:a补码为0011,0的补码为0000,所以0000-0011最终会向高位借1所以会有CF=1
(2)假设有数:a=-3;
那么:NEG a
分析:a为负数,补码为1101,所以0000-1101=0011即正数3,所以CF=1
NEG+SBB指令
假设有C语言:
if(foo() != 0)
{
return(FALSE);
}else{
return(TURE);
}
也可以是:
if(foo() != 0) return(FALSE);
return TURE;
可以这样汇编(用fasm语法):
call [foo];调用foo(),返回值在eax中
neg eax;把操作数按位求反后末位加1, 且if(EAX==0){CF=0}else{CF=1}
sbb eax,eax; eax-eax-cf ==> (eax)
;操作结果:如果foo的返回值不是 0,此时 (eax) = -1
; :如果foo的返回值是 0,此时 (eax) = 0
inc eax ; 操作结果:如果foo的返回值不是 0,此时 (eax) = 0
; :如果foo的返回值是 0,此时 (eax) = 1
; 进一步解释
; if (EAX)=0 则:
; NEG EAX ;等价于: 0 - (EAX) = 0 , 结果: (EAX)=0 ,CF=0
; SBB EAX, EAX ; 等价于 (EAX)-(EAX)-(CF) , 结果为: (EAX)=0
; INC EAX ; ,结果 (EAX)=1
;if EAX!=0 (假设 EAX=5) 则:
; NEG EAX 等价于: 0 - 5 = -5 所以: (EAX)= -5 ,但CF=1
; SBB EAX, EAX 等价于 (EAX)-(EAX)-(CF) 即: (EAX)= -1
; INC EAX 结果 (EAX)=0