汇编语言程序设计 实验4 汇编应用编程和c语言程序反汇编分析
汇编语言程序设计 实验4 汇编应用编程和c语言程序反汇编分析
一、实验目的
1. 理解80×25彩色字符模式显示原理
2. 理解转移指令jmp, loop, jcxz的跳转原理,掌握使用其实现分支和循环的用法
3. 理解转移指令call, ret, retf的跳转原理,掌握组合使用call和ret/retf编写汇编子程序的方法,掌握参数传递方式
4. 理解标志寄存器的作用
5. 理解条件转移指令je, jz, ja, jb, jg, jl等的跳转原理,掌握组合使用汇编指令cmp和条件转移指令实现分支和循环的用法
6. 了解在visual studio/Xcode等环境或利用gcc命令行参数反汇编c语言程序的方法,理解编译器生成的反汇编代码
7. 综合应用寻址方式和汇编指令完成应用编程
二、实验内容及结果
(一)实验任务一
教材「实验9 根据材料编程」(P187-189)
编程:在屏幕中间分别显示绿色、绿底红色、白底蓝色的字符串'welcome to masm!' 。
源代码如下:
assume cs:codedata segment
db 'welcome to masm!' ;要显示的内容
data ends
code segment
start: ;设置数据段地址
mov ax,data
mov ds,ax
mov ax,0B800H ;B800H显示缓冲区的起始地址
mov es,ax
mov bx,0 ;字符串内容的偏移地址,每次增加1
mov bp,64 ;缓冲区的偏移地址,每次增加2
mov cx,16 ;循环16次
a: mov al,ds:[bx] ;取得字符串的字节数据
mov ah,02H ;黑底绿色
mov es:[bp+6E0H],ax ;(垂直居中)显示在第11行上
mov ah,24H ;绿底红色
mov es:[bp+780H],ax ;(垂直居中)显示在第12行上
mov ah,71H ;白底蓝色
mov es:[bp+820H],ax ;(垂直居中)显示在第13行上
inc bx ;累加操作
add bp,2
loop a
mov ax,4C00H
int 21H
code ends
end start
使用masm、link对exp9.asm进行汇编、链接,得到可执行文件exp9.exe,运行并观察结果。
1、具体的汇编、链接过程可以参考《汇编语言程序设计 实验2 汇编源程序编写与汇编、调试》。运行exp9.exe文件,得到结果:
(二)实验任务二
编写子程序printStr,实现以指定颜色在屏幕上输出字符串。调用它,完成字符串输出。
使用任意文本编辑器,录入汇编源程序task2.asm,源代码如下:
assume cs:code, ds:datadata segment
str db
'try', 0data ends
code segment
start:
mov ax, data
mov ds, ax
mov si, offset str
mov al,
2call printStr
mov ah, 4ch
int 21hprintStr:
push bx
push cx
push si
push di
mov bx, 0b800H
mov es, bx
mov di,
0s: mov cl, [si]
mov ch,
0jcxz over
mov ch, al
mov es:[di], cx
inc si
add di,
2jmp s
over: pop di
pop si
pop cx
pop bx
ret
code ends
end start
使用masm、link对task2.asm进行汇编、链接,得到可执行文件task2.exe,运行结果如下所示:
对源程序做如下修改:
把line3改为:
str db 'another try', 0
修改后的结果如下所示:
把line12改为:
mov al, 4
修改后的结果如下所示:
可以得知:mov al改变了字符的颜色属性
基于运行结果,理解源代码,以及,组合使用转移指令call和ret实现子程序的原理与方法。具体地,在line18-40中:
line19-22, line36-39,这组对称使用的push、pop,这样用的目的是:利于恢复各寄存器的值。
line30的功能是:通过“mov es:[di], cx”可以读取目标数据存入es。
(三)实验任务三
使用任意文本编辑器,录入汇编源程序task3.asm,源代码如下所示:
assume cs:code, ds:datadata segment
x dw
1984str db
16 dup(0)data ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, x
mov di, offset str
call num2str
mov ah, 4ch
int 21hnum2str:
push ax
push bx
push cx
push dx
mov cx,
0mov bl,
10s1:
div bl
inc cx
mov dl, ah
push dx
mov ah,
0cmp al,
0jne s1
s2:
pop dx
or dl, 30h
mov [di], dl
inc di
loop s2
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start
首先使用u命令对task.exe进行反汇编,结果如下所示:
使用g命令执行到line15(程序退出之前)
-g 0e
使用d命令查看数据段内容 ,结果如下所示:
对task3.asm源代码进行修改、完善,把task2.asm中用于输出以0结尾的字符串的子程序加进来,实现对转换后的字符串进行输出。 源代码如下所示:
assume cs:code, ds:datadata segment
x dw
1984str db
16 dup(0)data ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, x
mov di, offset str
call num2str
mov si, offset str
call printStr
mov ah, 4ch
int 21hnum2str:
push ax
push bx
push cx
push dx
mov cx,
0mov bl,
10s1:
div bl
inc cx
mov dl, ah
push dx
mov ah,
0cmp al,
0jne s1
s2:
pop dx
or dl, 30h
mov [di], dl
inc di
loop s2
pop dx
pop cx
pop bx
pop ax
ret
printStr:
push bx
push cx
push si
push di
mov bx, 0b800H
mov es, bx
mov di,
0s:
mov cl, [si]
mov ch,
0jcxz over
mov ch, al
mov es:[di], cx
inc si
add di,
2jmp s
over: pop di
pop si
pop cx
pop bx
ret
code ends
end start
结果如下所示:
把task3.asm源代码中,line3中整数改成0~2559之间的任意数值,运行测试,结果如下所示:
(四)实验任务四
使用任意文本编辑器,录入汇编源程序task4.asm,源代码如下所示:
assume cs:code, ds:datadata segment
str db
80 dup(?)data ends
code segment
start:
mov ax, data
mov ds, ax
mov si,
0s1:
mov ah,
1int 21h
mov [si], al
cmp al, '#'
je next
inc si
jmp s1
next:
mov cx, si
mov si, 0
s2: mov ah, 2
mov dl, [si]
int 21h
inc si
loop s2
mov ah, 4ch
int 21h
code ends
end start
运行结果如下所示:
line12-19实现的功能是:含有中断转移指令和条件跳转指令,判断输入的字符是否为#,并将不是#的字符存入栈中
line21-27实现的功能是:含有循环指令,输出存在栈内的字符
(五)实验任务五
在visual studio集成环境中,编写一个简单的包含有函数调用的c程序。代码如下:
#include <stdio.h>int sum(int, int);
int main() {
int a = 2, b = 7, c;
c = sum(a, b);
return 0;
}
int sum(int x, int y) {
return (x + y);
}
在line7和line13处添加断点,如图所示:
在调试状态下(快捷键F5)点击“调试”->“窗口”->“反汇编”,即查看反汇编代码,结果如下:
结果如下所示:
int sum(int x, int y) {00211740 push ebp00211741 mov ebp,esp00211743 sub esp,0C0h00211749 push ebx0021174A push esi
0021174B push edi
0021174C lea edi,[ebp
-0C0h]00211752 mov ecx,30h00211757 mov eax,0CCCCCCCCh0021175C rep stos dword ptr es:[edi]
0021175E mov ecx,offset _7FF23424_test@cpp (021C003h)
00211763 call @__CheckForDebuggerJustMyCode@4 (021130Ch)return (x + y);00211768 mov eax,dword ptr [x]0021176B add eax,dword ptr [y]
}
0021176E pop edi
0021176F pop esi
00211770 pop ebx00211771 add esp,0C0h00211777 cmp ebp,esp00211779 call __RTC_CheckEsp (0211235h)0021177E mov esp,ebp
00211780 pop ebp00211781 ret
反汇编代码分析:(红色为c语言程序,蓝色为汇编语言程序,黑色为分析)
int main() {
002117B0 push ebp ;保存ebp,此时EBP =005BFA38,ESP = 005BFA18
002117B1 mov ebp,esp ;将esp放入ebp中,此时ebp和esp相同,即执行后ESP = 005BFA18 ,EBP = 005BFA18。原EBP值已经被压栈(位于栈顶),而新的EBP又恰恰指向栈顶。
002117B3 sub esp,0E4h ;把esp往上移动一个范围,等于在栈中空出一片空间来存局部变量,执行这句后ESP = 005BF934, EBP = 005BFA18,EBX = 00745000
002117B9 push ebx
002117BA push esi
002117BB pushedi ;保存三个寄存器的值
002117BC lea edi,[ebp-0E4h] ;把ebp-oE4h加载到edi中,保存局部变量的区域
002117C2 mov ecx,39h
002117C7 mov eax,0CCCCCCCCh
002117CC rep stos dword ptr es:[edi] ;从ebp-0E4h开始的区域初始化成全部0CCCCCCCCh,初始化局部变量空间
int a = 2, b = 7, c;
002117D8 mov dword ptr [a],2 ;把2赋给a
002117DF mov dword ptr [b],7 ;把7赋给b
c = sum(a, b);
00FD17E6 mov eax,dword ptr [b] ;把b的值赋给eax
00FD17E9 push eax ;eax入栈
00FD17EA mov ecx,dword ptr [a] ;把a的值赋给ecx
00FD17ED push ecx ;ecx入栈
00FD17EE call sum (0FD116Dh) ;调用sum函数,可以按F11跟进
00FD17F3 add esp,8 ;调用完函数后恢复/释放栈,执行后ESP = 0079F75C,与sum函数的参数入栈前的数值一致
00FD17F6 mov dword ptr [c],eax ;将结果存放在result中
return 0;
00FD17F9 xor eax,eax ;异或后寄存器清零
}
00FD17FB pop edi
00FD17FC pop esi
00FD17FD pop ebx ;恢复原来寄存器的值
00FD17FE add esp,0E4h ;恢复ESP,对应之前的sub esp,0E4h
00FD1804 cmp ebp,esp ;检查esp是否正常,不正常就进入下边的call里面debug
00FD1806 call __RTC_CheckEsp (0FD1235h) ;处理可能出现的堆栈异常,如果有的话,就会陷入debug
00FD180B mov esp,ebp
00FD180D pop ebp ;恢复原来的esp和ebp,让上一个调用函数正常使用
00FD180E ret ;将返回地址存入eip,转移流程
以上是主函数调用的反汇编过程,以下部分是调用sum函数的过程:
int sum(int x, int y) {
00FD1740 push ebp
00FD1741 mov ebp,esp
00FD1743 sub esp,0C0h
00FD1749 push ebx
00FD174A push esi
00FD174B push edi
00FD174C lea edi,[ebp-0C0h]
00FD1752 mov ecx,30h
00FD1757 mov eax,0CCCCCCCCh
00FD175C rep stos dword ptr es:[edi]
00FD175E mov ecx,offset _7FF23424_test@cpp (0FDC003h)
00FD1763 call @__CheckForDebuggerJustMyCode@4 (0FD130Ch) ;与主函数的调用过程几乎相似
return (x + y);
00FD1768 mov eax,dword ptr [x] ;取第一个参数放在eax
00FD176B add eax,dword ptr [y] ;取第二个参数,与eax中的数值相加并存在eax中
}
00FD176E pop edi
00FD176F pop esi
00FD1770 pop ebx
00FD1771 add esp,0C0h
00FD1777 cmp ebp,esp
00FD1779 call __RTC_CheckEsp (0FD1235h)
00FD177E mov esp,ebp
00FD1780 pop ebp
00FD1781 ret ;与主函数的调用过程几乎相似
三、实验总结
以上是 汇编语言程序设计 实验4 汇编应用编程和c语言程序反汇编分析 的全部内容, 来源链接: utcz.com/a/74460.html