汇编语言学习笔记--位运算(应该貌似简单点了吧,差点自己就信了,(:{ ))

基本

1.逻辑运算

能学到汇编的同志们,对于逻辑应该不用详细介绍吧,所以就直接上图了。
在这里插入图片描述
同理,在汇编语言中,也是通过这四个指令实现:

  • and 目的操作数,源操作数
  • or 目的操作数,源操作数
  • xor 目的操作数,源操作数
  • nor 目的操作数
    注意:
    not指令不影响任何标志位,但是其他三条指令会影响:CF、OF、PF、SF、ZF和AF等标志位!
    在这里插入图片描述

2.用途

在逻辑指令中用来改变位值得值通常称为掩码。

  • and:对目的地址中的内容选定的位清零。原理: 任意一位值和1进行与运算,仍是原值;与0进行运算,结果必是0
    在这里插入图片描述
  • or:对选定位置值赋值为1,原理同上
  • 实现高级语言的布尔运算
and flags,11011101b;flag5=false,flag1=false
or flags,00001100b;flag3=true,flag2=true
  • 执行一些算数运算,
1.
mov edx,0
mov ebx,32
div ebx

2.
mov edx,eax
and edx,0000001fh

两种都是求模32并且将结果放在EDX中,但是第二种却更加简单,效率更高!(并且EAX没有商)
原理:

  1. 将edx看作二进制
  2. 因为比32(2的5次方)高的位数都可以被约分,所以只用看后5位的数值,5之前的数都可以用上面的方法进行屏蔽(0000001F)
  3. 剩下的5位就是结果(使用1F进行与运算
  • 处理ASCII码字母的大小写

如下,可以发现"A"和"a"的ASCII码值二进制形式只有一位不同,因此完全可以使用按位取反,从而实现大小写的转换。

A的ASCII码为 0101 0011(二进制形式)	41h(16进制)		65d(10进制)
a的ASCII码为 0111 0011(二进制形式)	61h(16进制)		97d(10进制)

xor eax 0010 0000b;改变大小写
;以下两个完全对称,可能这就是二进制的魅力吧
or eax 0010 0000b;变为小写
and eax 1101 1111b;变为大写 

test

  1. test
    test除了不改变目的操作数之外,它的功能与and指令相同。也就是说,指令test唯一的任务是设置标志位(cmp的指令实质上也相当于设置标志位的sub指令,但是cmp指令不改变目的操作数)。简单来说,就是,test只是检测对比而已,但是不影响原来的数值,只修改标志位。所以拿来和cmp进行比较。
    在这里插入图片描述

在这里插入图片描述
应用

  • 检查特定位的值,并且结合 j- 系列的语句实现跳转
检查13位
test dx,2000h;检测第十三位是0还是1,从而实现跳转
jz temp
  • 获得寄存器中的值的信息
test cx,cx

任意位和自己执行and(test)操作的结果都是本身,但是通过这样可以修改标志位。

移位和循环移位

简单来说,就是将二进制向左移动或者向右移动。使用的命令是**s-**系列。

左移右移
逻辑移位shlshr
算术移位salsar
s- 目的地址,count

count的三种情况

1.
s- 目的地址,1;移动一位

2.
s- 目的地址,8位立即数;一个字节的立即数,一半都会00011111与这个操作数作掩码, 也就是说,在移位前对他进行模32运算,这是因为对一个不超过一个双字节长的操作数来说,做超过32位的移位操作是没有意义的。

3.
s- 目的地址,cl

逻辑移位和算数移位

左移

算数左移和逻辑左移都是一样的。当执行左移时,目的操作数的每一位都向左移动,最右边的空缺补0。移出的左边位被丢失,除了最后移除的一位,它被保存在进位标志位CF中。然后根据目的地址中最后的结果,来设置符号位。

右移

在右移中,则出现了区别,大部分和左移差不多。但是在对左边空缺的填补中,则出现了不同。逻辑右移对左边填充的都是0,而算数右移,则是填充原来的首位符号(也就是保证新数的正负性),缺多少,补多少
在这里插入图片描述
在这里插入图片描述

应用

  • 乘法,除法
    在10进制中,对13扩大10倍,就是对所有位数左移1位,除10则是右移。那么二进制中,也是同理,对一个二进制数扩大2倍,左移1位,缩小2倍,右移2位.但实际上,还是有一些特点,尤其是在除法之中,比如:寄存器EBX中有一个无符号操作数,逻辑右移shr ebx 1把EBX中的每一位都移到相应的2的下一个底次幂,得到初始值的一半。初始单元的位复制到进位标志位CF中,这就是除数的余数(右移,把最后移出的一位保存在CF中,这就是余数)。通常,有些乘法计算用移位运算比用乘法运算指令更快。但是,如果EBX中是一个有符号操作数,那么使用相同指令后,在除数为2时结果几乎是一样的。但是,如果被除数是一个负的奇数,商就被取整,也就是说,右移得出的值可能比用idiv指令得出的值要小。
如:
dx中为FFFF
ax中为FFF7
cx中为0002
那么
idiv cx
之后:ax=fffc,dx=ffff,也就是说商为-4,余数为-1
但是,如果把fffffff7放入ebx中,
sar ebx ,1
结果为:ebx=fffffffb,cf=1,也就是商为-5,余数为+1

以上两种结果都满足:
被除数=除数*商+余数

不同的就是**余数的符号和被除数符号是否相同**,而idiv的规则明确指出:他们应该相同。
  • 与其他逻辑指令一同使用
    一起使用时,可以把不同组的位组合成一个字节或者字,或者把一个字节或者字内的位分解为几个不同的组。
    例题:
    题目:用16进制显示一个整数:
    设计思想
    在这里插入图片描述
    在这里插入图片描述
    这里用几个小技巧:
  • 判断是否为数字
cmp edx,9 ;是否为数字?
jnle elseLetter ;不是则为字母,也就是说,edx中的值小于等于九的话就是数字,大于的话就是字母。别忘了,这时候的edx中还是10进制的整数。
  • 屏蔽其它位
and eax,0000000fh;除最后一位十六进制外,其他都位0
  • 数字转化为ASCII
    在这里插入图片描述
    先看看以上的表码,

(顺便巩固下寄存器):

便于理解统一用二进制标识
eax
					|<------ax-------->|
                    |<-ah-->|  |<--al->|
0000 0000 0000 0000 0000 0000 0000 0000
|<----------------eax----------------->|
                   
按上面的来理解的话:
假设输入100
eax获取的值为
0000 0000 0000 0000 0000 0000 0110 0100 (从最底层理解,100o,eax)

edx的值变化为:
mov edx,eax
0000 0000 0000 0000 0000 0000 0110 0100 (64h,edx)

and edx,0000000fh
0000 0000 0000 0000 0000 0000 0000 0100 (4h,edx)


这里是小于9的情况
or edx,30h
0000 0000 0000 0000 0000 0000 0000 0100(4h,edx)
0000 0000 0000 0000 0000 0000 0011 0000(30h)
--------------------------------------------
0000 0000 0000 0000 0000 0000 0011 0100(34h,edx)

这样的话就实现了从数值到ASCII的转化(数字‘4’变为ASCII码‘4’(34h))

大于9的情况
换一个值输入(11d)
则经过一系列和上面相同的步骤之后,
edx
0000 0000 0000 0000 0000 0000 0000 1011(11o,bh,,edx)


0000 0000 0000 0000 0000 0000 0100 0001(41h,'A')
0000 0000 0000 0000 0000 0000 0000 1010(ah,10d)
----------------------------------------------
0000 0000 0000 0000 0000 0000 0011 0111(37h,55d,'A'-10d)

add edx,'A'-10
0000 0000 0000 0000 0000 0000 0000 1011(11o,bh,,edx)
0000 0000 0000 0000 0000 0000 0011 0111(37h,55d,'A'-10d)
---------------------------------------------------------
0000 0000 0000 0000 0000 0000 0100 0010(42h,'B')

双移位

上面一直说的都是把一个操作数的位移到适当的位置。下面还有两个双移位指令:

  • shlr
  • shrd
sh-d 目的操作数,源操作数,计数
  • 目的操作数:可以是寄存器或存储器中的一个字或者双字
  • 源操作数:寄存器中的一个字或双字
  • 计数:立即数或者寄存器CL中的数

相同之处:
把目的操作数左(右)移
不同之处:
被移动的位是从源操作数最左(右)边一位开始,源操作数不变(shld)

说明:
就是目的操作数照常移位,但是空缺的部分是用源操作数中的对应位置补上(左移就用源操作数的左便开始补上去,右移就用源操作数的右边补上去)
如:

shld:
ecx:12 34 56 78
eax:90 ab cd ef

shld ecx,eax,12(ecx向左移动12位,用eax的左边前12位补上ecx的右边空缺)

ecx:45 67 89 0a
eax:90 ab cd ef

CF 1 ZF 0 SF 0
(最后移出的是‘3’,(0011),最右边为‘1’,也就是最后离开的,所以CF为1)

shrd:
ecx:12 34 56 78
eax:90 ab cd ef

shrd ecx,eax,cl(ecx向右移动8位,用eax的右边后8位补上ecx的左边空缺)

ecx:ef 12 34 56
eax:90 ab cd ef
cl:08
CF 0 ZF 0 SF 0
(最后移出的是‘7’,(0111),最左边为‘0‘,也就是最后离开的,所以CF为0)

循环移位

从字面上就可以理解,循环的意思就是把移出去的位数,换到另一端进行填补。

  • r- 目的操作数,1
  • r- 目的操作数,8位立即数
  • r- 目的操作数,c1

两个指令:

  • rol(循环左移位)
  • ror(循环右移位)
    CF同样被最后一位移出的进行标记

放一段专业源码,有时间的话再实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

作业

题目:
写一个过程Preeven,判断一个串中偶数元素(用位运算)的个数,通过堆栈传递两个参数
(1) 串的首地址
(2) 串中元素个数

;Program: 串中偶数元素(用位运算)的个数
;Author: 龙文汉
;Date: 2020.12.9

.386
.MODEL FLAT

ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD

INCLUDE io.h            ; header file for input/output

cr      EQU     0dh     ; carriage return character
Lf      EQU     0ah     ; line feed

.STACK  4096            ; reserve 4096-byte stack

.DATA                   ; reserve storage for data
prompt1 BYTE "Please input the string:",cr,Lf,0;
prompt2 BYTE "The count of even number:",cr,Lf,0;
str1 BYTE "The length of str:",cr,Lf,0;
str5 BYTE "The String:",cr,Lf,0;
HH BYTE cr,Lf,0;

string WORD 100 DUP(?);
temp WORD 100 DUP(?);
strnum WORD 100 DUP(?);

.CODE                           ; start of main program code
strlen PROC NEAR32
    push ebp;
    mov ebp,esp;
    pushf;
    push eax;
    push ebx;
    sub eax,eax
    mov ebx,[ebp+8];
WhileChar:
    cmp BYTE PTR [ebx],0;
    je endWhileChar;
    inc eax;length + 1
    inc ebx;next char
    jmp WhileChar
endWhileChar:
    mov edx,eax;
    pop ebx;
    pop eax;
    popf;
    pop ebp;
    ret 4;release old eax
strlen ENDP;

Proeven PROC NEAR32
    push ebp;
    mov ebp,esp;

    push ebx;
    push ecx;
    push edx;

    mov ecx,[ebp+8];
    mov ebx,[ebp+10];
    mov eax,0;




WhileIs:
    mov dx,[ebx];
    cmp dx,0;

    je Endwhile;
    test dx,0001h;

    jnz noeven;
    inc eax;
    noeven:
    add ebx,2;byte + 1
    loop WhileIs;

Endwhile:
    pop edx;
    pop ecx;
    pop ebx;
    pop ebp;
    ret;
Proeven ENDP;

CreateStr PROC NEAR32
    push eax;
    push ebx;
    push ecx;
;输入字符串长度
    output str1;
    input temp,100;
    atod temp;

    mov ecx,eax;
    mov strnum,ax;
    output str5;
    lea ebx,string;
;创建字符串
    Dowhile:
        input temp,100;
        atoi temp;
        mov [ebx],ax;
        add ebx,2;
        loop Dowhile;
    pop ecx;
    pop ebx;
    pop eax;
    ret
CreateStr ENDP;

PrintStr PROC NEAR32
    push ebp;
    mov ebp,esp;
    push ebx;
    mov ebx,[ebp+8]
WhileChar:
    cmp WORD PTR [ebx],0;
    je endWhileChar;
    itoa temp,[ebx];
    output temp;
    add ebx,2;
    jmp WhileChar;
endWhileChar:
    output HH;
    pop ebx;
    pop ebp;
    ret
PrintStr ENDP;

_start:
    call CreateStr;

    lea eax,string
    push eax;
    call strlen;

    lea eax,string
    push eax;
    call PrintStr;
    pop eax;


    lea eax,string
    push eax;;string
    push strnum;string_len

    call Proeven;

    output prompt2;
    dtoa temp,eax;
    output temp;


        INVOKE  ExitProcess, 0  ; exit with return code 0
PUBLIC _start                   ; make entry point public

END                             ; end of source code


  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
嗨!对于逆向学习汇编语言学习笔记,我可以给你一些基本的指导。首先,汇编语言是一种低级语言,它与计算机的底层硬件密切相关。逆向工程则是通过分析和理解已编译的程序来获取程序的内部息。 以下是一些学习汇编语言和逆向工程的建议: 1. 学习基础知识:了解计算机体系结构、寄存器、内存和指令集等基础概念是必要的。可以先阅读相关的书籍或在线教程,掌握这些基本概念。 2. 掌握汇编语言的语法和指令集:每种计算机体系结构都有自己的汇编语言语法和指令集。选择一种你感兴趣的体系结构(如x86、ARM等),并学习它的汇编语言。 3. 练习编和调试汇编代码:通过编简单的汇编代码来熟悉语法和指令集。使用调试器来单步执行代码并观察寄存器和内存的变化。 4. 分析已编译程序:选择一个目标程序进行逆向分析。使用反汇编器将程序转换为汇编代码,并分析代码的逻辑和功能。这有助于理解程序的结构和运行过程。 5. 使用调试器进行动态分析:通过调试器来动态地执行程序,并观察程序在运行时的行为。使用断、内存查看器和寄存器查看器等工具来分析程序的状态和数据。 6. 学习逆向工程工具和技术:了解常用的逆向工程工具和技术,如IDA Pro、OllyDbg、Ghidra等。掌握这些工具的使用可以提高你的逆向分析能力。 7. 参考优秀资源:阅读与逆向工程和汇编语言相关的书籍、论文和博客,关注相关的社区和论坛。与其他逆向工程师交流经验也是很有帮助的。 记住,逆向工程是一个需要耐心和实践的过程。持续学习和实践将帮助你提高逆向分析的技能。祝你在学习汇编语言和逆向工程的过程中取得好成果!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hanzoe_lwh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值