一、逻辑运算符
1、或运算(c语言中的 || )
条件真和假 :
非零为真,零为假
++为+(假假为假)
截断原理 if(a || b) 判断前面是否为真,把认为可能行大的放在最前面
c = i || j;
if (c) {}
以汇编指令去看
/*
009E1014 |. C745 FC 330>mov [local.1],0x33
009E101B |. C745 F4 660>mov [local.3],0x66
009E1022 |. 837D FC 00 cmp [local.1],0x0
009E1026 |. 75 0F jnz short 汇编.009E1037 // jnz 不为0 跳转 因 local-1 与 0 比较 不为0 跳转 ,所以导致第二个参数不用判断,效率快
009E1028 |. 837D F4 00 cmp [local.3],0x0 // 如果为0不跳转, 则继续与第二个参数比较 (假假为假)
009E102C |. 75 09 jnz short 汇编.009E1037
009E102E |. C745 F0 000>mov [local.4],0x0
009E1035 |. EB 07 jmp short 汇编.009E103E
009E1037 |> C745 F0 010>mov [local.4],0x1
009E103E |> 8B45 F0 mov eax,[local.4] ; 汇编.envpcurity_cookie_complement
009E1041 |. 8945 F8 mov [local.2],eax
009E1044 |. 8BC0 mov eax,eax
*/
2、按位或(c语言中的 |)
0x33 ==>> 00 11 00 11
| 0x66 + 01 10 01 10
= 0x77 ==> = 01 11 01 11 (假假为假)
/*
009E1046 |. 8B4D FC mov ecx,[local.1] ; msvcr100.72AD266D
009E1049 |. 0B4D F4 or ecx,[local.3]
009E104C |. 894D F8 mov [local.2],ecx ; msvcr100.__initenv
*/
汇编是使用 or 指令
3、与运算
==>>逻辑与(c语言中的 && )
真真为真
c = a && b // 自己的代码 a 认为 是假 放在前面 。判断前面是否为假,把认为可能行大的放在最前面
if ( c ){}
截断原理
==>>按位与 (c语言中的 &)
0x33 ==>> 00 11 00 11
& 0x66 + 01 10 01 10
= 0x22 ==> = 00 10 0010 (真真为真)
/*
4、非运算
(1)逻辑取反(c语言中的 ! )
假变真, 真变假
sete(setz) 取ZF标志位的值保存
setne(setnz) 将ZF标志位的值取反保存
(2) 按位取反(c语言中的 ~ )
c语言代码中的汇编指令
#include <cstdio>
int main(){
printf("fsadfasd");
int i, j;
i = 0x7787;
j = !i ; // 0
/*
*/
__asm mov eax, eax
j = ~i;
return 0;
}
NOT 指令
5、异或运算
(1)按位异或(c语言中的^)
1^1 = 0 , 0^0 = 0 ,相同为0
0^1 = 1 , 1^0 = 1 , 不同为1
eg : 1101
^ 0110
= 1011
经典练习题:
(1)不借助第三个变量,将两个数交换(数值大的数会有问题,溢出)
int a = 5, b = 7;
a = a+b; // a = 12
b = a - b; // b = 12 - 7 = 5
a = a - b; // a = 12 - 5 = 7
(2)用异或计算高效
逻辑运算指令总结:
(1) or : 按位或运算,假假为假(有1为1,全0为0)
如:101100
| 110101
= 111101
(2) and : 按位与运算,真真为真(有0为0,全1为1)
如: 101100
& 110101
= 100100
(3) Not: 取反运算
如:not 1011
= 0100
(4) xor : 异或运算(相同为0,不同为1)
如 : 101100
^ 110101
= 011001
二、字符操作相关指令
1、字符串的比较函数 strcmp 反汇编分析:
2、REPNE和SCASB指令
(1)SCASB指令:
SCASB编译后:
SCASB BTYP PTR ES:[EDI] char s1[0] byte 1
//// SCASW WORD PTR [EDI] short s1[0] word 2
//// SCASD DWORD PTR [EDI] int s1[0] dword 4
相当于
cmp byte prt [edi], al
对标志位的影响相当于SUB指令,同时还会修改寄存器EDI的值
如果标志位DF为0, 则 inc EDI
否则,dec EDI
(2)REPNE指令(连续执行)
repnz scasb 编译后 :repne scas bype ptr es:[edi]
当ecx != 0 并且 ZF = 0 时,重复执行后边的指令 scas bype ptr es:[edi]
每执行一 次EDI的值加1,ECX的值减1
// 此汇编代码 是 获取字符的长度 (主要是实现逻辑思想)
repne 和 repnz 是同一条指令的不同助记符
3、REPE/REPZ和CMPSB, CMPSW, CMPSD指令
(1)CMPS
cmps byte ptr [edi] , byte ptr [esi]
cmps word ptr [edi] , byte ptr [esi]
cmps dword ptr [edi] , byte ptr [esi]
对标志位的影响相当于sub指令, 同时还会修改寄存器EDI和ESI的值
如果标志DF为0, 则EDI, ESI按相对于大小(byte, word, dword) 递增
如果标志DF为1, 则EDI, ESI按相对于大小(byte word dword) 递减
(2)REPE/REPZ
repe/repz cmpsb 当ecx!=0并且zf = 1时, 重复执行后面的指令
每执行一次ecx的值减1
(3)实例运用
比较串是否相等
(4)汇编编写字符串比较函数
(1)asm_strcmp 函数
_declspec(naked) 告诉编译器用纯汇编方式编译函数, 不自动添加
寄存器保护和堆栈平衡代码
(2)STD/CLD指令(DF方向标志位相关)
std df = 1
cld df = 0
三、串存储和串的加载指令
(1)串存储指令STOSB、STOSW、STOSD
STOSB STOS BYTE PTR [EDI]
STOSW STOS WORD PTR [EDI]
STOSD STOS DWORD PTR [EDI]
相当于:
mov byte ptr [edi], al
mov word ptr [edi], ax
mov dword ptr [edi], eax
rep stosb rep stos byte ptr [edi]
用al 的值 填充byte ptr [edi],每次ecx值减1,edi加1
定位main()函数位置的步骤:
第一步:打开程序, 程序启动后停在这里,直接jmp跳转
第二步:jmp跳转跟随之后, 找到call dword ptr [<xxxxx.exit>]退出的代码的位置
第三步:call dword ptr [<xxxxx.exit >] 前一个call就是main函数。
(2) 串载入指令LODSB, LODSW,LODSD
lodsb lods byte ptr [esi]
lodsw lods woedptr [esi]
lodsd lods dword ptr [esi]
rep lodsb ==>> rep lods byte ptr [esi]
用byte ptr [esi] 的值, 填充al, 每次ecx值减1 , esi的值加1