汇编实验

汇编实验

对应基础4的练习
本章题比较多

布尔计算器

创建程序,其功能为简单的32位整数布尔运算。显示菜单提示用户选择下表中的一项,然后提示输入后并把运算结果以16进制形式显示在屏幕上,菜单如下:

  1. x AND y
  2. x OR y
  3. NOT x
  4. x XOR y
  5. Exit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
INCLUDE Irvine32.inc
enter_key = 13

.data
MenuList BYTE "1.x AND y", 13, 10
BYTE "2.x OR y", 13, 10
BYTE "3.NOT x", 13, 10
BYTE "4.x XOR y", 13, 10
BYTE "5.Exit",13, 10, 0
prompt BYTE "Please choose a number:", 0
prompt1 BYTE "Enter Two Number", 0
prompt2 BYTE "Enter A Number", 0
CaseTable DWORD 1 ;查询地址
DWORD Process_1 ;过程地址
DWORD 2
DWORD Process_2
DWORD 3
DWORD Process_3
DWORD 4
DWORD Process_4
DWORD 5
DWORD Process_5
EntryNumber = 5
EntrySize = ($ - CaseTable) / 5

.code
main PROC
L1:
mov edx, OFFSET MenuList
call WriteString
mov edx, OFFSET prompt
call readInt ;读入EAX
mov esi, OFFSET CaseTable
mov ecx, EntryNumber ;循环次数
L2:
cmp eax, [esi] ;搜索是否匹配
jne L3 ;不相等跳转
call NEAR PTR [esi+4]
call Crlf
jmp L1
L3:
add esi, EntrySize
loop L2
call WaitMsg ;错误输入
jmp L1

Process_1 PROC
mov edx, OFFSET prompt1
call WriteString
call readInt
mov ebx, eax
call readInt
and eax, ebx
call WriteHex
ret
Process_1 ENDP

Process_2 PROC
mov edx, OFFSET prompt1
call WriteString
call readInt
mov ebx, eax
call readInt
or eax, ebx
call WriteHex
ret
Process_2 ENDP

Process_3 PROC
mov edx, OFFSET prompt2
call WriteString
call readInt
not eax
call WriteHex
ret
Process_3 ENDP

Process_4 PROC
mov edx, OFFSET prompt1
call WriteString
call readInt
mov ebx, eax
call readInt
xor eax, ebx
call WriteHex
ret
Process_4 ENDP


Process_5 PROC
call Crlf
call WaitMsg
exit
Process_5 ENDP

main ENDP
END main

消息加密

例题版

利于XOR的特性,一个数和另一个数异或后再和该数异或就能得到原本的数,对输入的字符的ASCII码与一个key异或加密,再异或一次解密,将结果输出到屏幕上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
;简单对称加密,利用XOR
INCLUDE Irvine32.inc
KEY = 239 ;1-255间任意一值
BUFMAX = 128 ;缓冲区最大容量

.data
sPrompt BYTE "Enter the plain text:", 0
sEncrypt BYTE "Cipher text:", 0
sDecrypt BYTE "Decrypted:", 0
buffer BYTE BUFMAX+1 DUP(0)
bufSize DWORD ?

.code
main PROC
call InputTheString ;输入明文
call TranslateBuffer ;加密缓冲区
mov edx, OFFSET sEncrypt
call DisplayMessage
call TranslateBuffer ;解密缓冲区
mov edx, OFFSET sDecrypt
call DisplayMessage ;显示解密消息
call WaitMsg
exit
main ENDP

InputTheString PROC
;----------------------
;提示用户输入一个纯文本字符串,保存进buffer
;无参数
;无返回
;-----------------------
pushad ;保存32位寄存器
mov edx, OFFSET sPrompt
call WriteString
mov ecx, BUFMAX
mov edx, OFFSET buffer ;指向缓冲区
call ReadString ;输入字符串
mov bufSize, eax ;保存长度
call Crlf
popad
ret
InputTheString ENDP

DisplayMessage PROC
;--------------------
;显示加密或解密消息
;参数:EDX指向消息
;无返回值
;--------------------
pushad
call WriteString
mov edx, OFFSET buffer
call WriteString
call Crlf
call Crlf
popad
ret
DisplayMessage ENDP

TranslateBuffer PROC
;-----------------------
;字符串的每个字节都与密钥异或实现转换
;无参数
;无返回值
;------------------------
pushad
mov ecx, bufSize
mov esi, 0
L1:
xor buffer[esi], KEY
inc esi
loop L1
popad
ret
TranslateBuffer ENDP

END main


修改

创建包含多个字符的密钥,使用该密钥与明文相应位进行按位异或,来对明文加密和解密,需重复使用密钥直到明文中的所有字符都转换完,假设密钥为ABXmv#7,(明文第8位与A异或)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
.code
key BYTE "ABXmv#7", 0 ;指定key

.data
TranslateBuffer PROC
;-----------------------
;字符串的每个字节都与密钥异或实现转换
;无参数
;无返回值
;------------------------
pushad
mov ecx, bufSize
mov esi, 0
mov edi, 0
L1:
mov al, key[edi]
xor buffer[esi], al
inc esi
inc edi
cmp edi, LENGTHOF key
je ResetEDI
L2:
loop L1
popad
ret
ResetEDI:
xor edi, edi ;归零
jmp L2
TranslateBuffer ENDP

奇偶性检查

数据传输系统和文件子系统常常依靠计算数据块的奇偶性(奇偶校验)来检查错误,我们需要创建一个过程,计算整个字节数组中的所有位,如果有偶数个1,则eax需要置1,反之eax需要置0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
.386
.model flat,stdcall
.stack 4096
ExitProcess proto ,dwExitCode:DWORD

.data
array1 BYTE 1111b,111b,11b,1b,1b,0b,0b,0b,0b,0b ;奇校验
array2 BYTE 11111b,1110b,1110b,1110b,1110b,10b,0b,0b,0b,0b ;偶校验
.code
main proc
mov esi, OFFSET array1
mov edi, LENGTHOF array1
call Check
mov esi, OFFSET array2
mov edi, LENGTHOF array2
call Check
invoke ExitProcess,0
main ENDP

Check PROC
;------------------------
;用于验证字节数组的所有位是奇校验还是偶校验
;参数: ESI=数组指针, EDI=数组大小
;返回值: EAX=0表示为奇校验,反之为偶校验
;------------------------
mov ecx, edi
dec ecx ;少执行一次
mov edx, 0
mov al, [esi]
L1:
inc edx
mov bl, [esi+edx]
xor al, bl
loop L1
xor al, 0
jp END1 ;偶校验
mov eax, 0
ret
END1:
mov eax, 1
ret
Check ENDP

END main

调试查看程序结果即可

循环内的if嵌套

把下面C++的代码转成汇编代码

1
2
3
4
5
6
7
8
9
10
11
int array[] = {1,2,3,4,5,6,7,8,9,10}
int sample = 3
int ArraySize = sizeof(array)/ sizeof(int)
int index = 0
int sum = 0
while( index < ArraySize ){
if(array[index] > sample){
sum += array[index]
}
index++
}

尽量使用较少的指令数来用汇编实现,下面是我的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.data
sum DWORD 0
sample DWORD 3
array DWORD 1,2,3,4,5,6,7,8,9,10
ArraySize = ($-array) / TYPE array
.code
mov eax, OFFSET sum ;便于调试寻找内存
mov ecx, ArraySize
mov esi, 0
L1:
mov eax, array[esi * TYPE array]
cmp eax, sample
jbe next ;小于,不求和
add sum, eax
next:
inc esi
loop L1

我们可以看到如果仅是判断次数的while循环(可以用for替代)LOOP就会比条件判断容易很多,但如果是条件判断,写法就要复杂一些

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
;不使用loop

.code
mov eax, OFFSET sum ;便于调试寻找内存
mov ecx, 0
mov esi, 0
L1:
cmp ecx, ArraySize
jae quit
inc ecx
mov eax, array[esi * TYPE array]
cmp eax, sample
jbe next ;小于,不求和
add sum, eax
next:
inc esi
jmp L1
quit:

我们只需要在第一个while判断时使用cmp,把使用结束循环的情况跳转到结束语句或者后面的语句即可

写在后面

要加快速度了,毕竟想学的东西太多了,但还是要一点一点来学,一遍尽量学扎实
空格咋抽风了,看着贼难受

Author

Ctwo

Posted on

2019-07-30

Updated on

2020-10-25

Licensed under

Comments