版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/D_K_01/article/details/79516269
Win32汇编_电话本
功能
- 独立密码,可修改;
- 增删改查;
- 保存二进制文件,保存文本文件;
截图
电话本主界面
查看所有
保存文本文件
练习目的
初学汇编,简单的电话本实现增删改查练手,
难点部分是数据对比和数据拷贝,文件操作;
练习汇编命令,特别是rep
系列,cmps
系列,jxx
系列;
掌握对汇编数据类型的使用,堆栈的平衡,OD中的调试;
源码
程序主体
;********************************************
; @Brief : Win32汇编电话本
; @Author : D&K
; @Email : [email protected]
; @Date : 2018/3/12
; @Version : ver 1.0
;********************************************
;设置模式
.386
.model flat,stdcall
option casemap:none
;导入头文件
include data.inc
;主函数
main proc
push ebp
mov ebp,esp
;读取文件
call ReadData
;验证密码
call pwd
;循环操作菜单
CYCLE_MAIN:
;清屏
call sys_cls
;显示菜单
call MenuInfo
;输入选项
push offset g_nTemp
push offset g_szScanfFormatD
call crt_scanf
add esp,8 ;循环内平衡堆栈
;其他数字调用菜单
call SwitchMenu
;重新循环
JMP CYCLE_MAIN
MAIN_END:
mov esp,ebp
pop ebp
ret
main endp
end
包含头文件
数据和函数定义
;包含库文件
include windows.inc
include msvcrt.inc
includelib msvcrt.lib
include kernel32.inc
includelib kernel32.lib
;定义数据段
.data
;定义存储结构体
CONTACTSSTRUCT struct
szName db 18 dup(0);姓名
szPhoneNumber db 12 dup(0);号码
CONTACTSSTRUCT ends
;声明全局变量
g_stContacts CONTACTSSTRUCT 100 dup(<'0'>) ;电话号码簿数组
g_nCount dd 0 ;当前容量
g_nCountMax dd 100 ;最大容量
g_strTemContacts CONTACTSSTRUCT <'0','0'> ;临时输入电话本变量
g_nPassword dd 123456 ;数字密码
g_nTemp dd 0 ;临时数字
g_hFileHandle dd 0 ;文件指针
;格式控制符
g_szCLS db "cls",0
g_szPause db "pause",0
g_szScanfFormatD db "%d",0
g_szScanfFormatS db "%s",0
g_szScanfFormatSS db "编号:%d",0dh,0ah,
"姓名:%s",0dh,0ah,
"号码:%s",0dh,0ah,0
;文字字符串
g_szPwd db "请输入密码:",0
g_szErr db "密码错误!请重新输入:",0
g_szPwdNew db "请输入新数字密码:",0
g_szName db "请输入姓名:",0
g_szNember db "请输入号码:",0
g_szModify db "请输入需要修改的编号:",0
g_szDelete db "请输入需要删除的编号:",0
g_szFind db "请输入需要查找的信息:",0
;文件操作
g_szFile db "pwd.db",0
g_szFileTXT db "pwd.txt",0
g_szFileW db "w",0
g_szFileWB db "wb",0
g_szFileRB db "rb",0
;操作提示
g_szOK db "操作成功",0
g_szNO db "操作失败",0
g_szInfoErr db "输入信息有误!",0
g_szPwdOK db "密码正确!",0
g_szEmpty db "暂无数据!",0
g_szMenu db "请输入菜单选项",0dh,0ah,0dh,0ah,
"1 查看",0dh,0ah,
"2 添加",0dh,0ah,
"3 修改",0dh,0ah,
"4 删除",0dh,0ah,
"5 搜索",0dh,0ah,
"6 保存",0dh,0ah,0dh,0ah,
"0 退出",0dh,0ah,
;代码区
.code
;清屏封装
sys_cls proc
push offset g_szCLS
call crt_system
add esp,4
ret
sys_cls endp
;暂停封装
sys_pause proc
push offset g_szPause
call crt_system
add esp,4
ret
sys_pause endp
;验证密码
pwd proc ;无参数
push ebp
mov ebp,esp
;提示输入密码
push offset g_szPwd
push offset g_szScanfFormatS
call crt_printf
add esp,8
mov ebx,[g_nPassword]
;循环验证密码
CYCLE_PWD:
push offset g_nTemp
push offset g_szScanfFormatD
call crt_scanf
add esp,8 ;循环内平衡堆栈
;对比密码
cmp ebx,[g_nTemp]
je PWD_OK ;密码正确跳出循环
call sys_cls
;密码错误提示重新输入
push offset g_szErr
push offset g_szScanfFormatS
call crt_printf
add esp,8
jmp CYCLE_PWD ;重新循环
PWD_OK:
;密码正确
call sys_cls
push offset g_szPwdOK
push offset g_szScanfFormatS
call crt_printf
add esp,8
;平衡堆栈
mov esp,ebp
pop ebp
ret
pwd endp
;输出菜单文字
MenuInfo proc ;无参数
call sys_cls
push offset g_szMenu
call crt_printf
add esp,4
ret
MenuInfo endp
;Switch 菜单
SwitchMenu proc ;无参数
cmp [g_nTemp],0 ;0 退出
jz S0
cmp [g_nTemp],1 ;1 查看
jz S1
cmp [g_nTemp],2 ;2 添加
jz S2
cmp [g_nTemp],3 ;3 修改
jz S3
cmp [g_nTemp],4 ;4 删除
jz S4
cmp [g_nTemp],5 ;5 搜索
jz S5
cmp [g_nTemp],6 ;6 保存
jz S6
cmp [g_nTemp],8 ;8 更改密码
jz S8
jmp SSS
;退出程序
S0:
push 0
call ExitProcess
add esp,4
jmp SSS
;1 查看
S1:
call ShowAll
jmp SSS
;2 添加
S2:
call AddData
jmp SSS
;3 修改
S3:
call ModifyData
jmp SSS
;4 删除
S4:
call DelData
jmp SSS
;5 搜索
S5:
call FindData
jmp SSS
;6 保存
S6:
call SaveTXT
jmp SSS
;8 修改密码
S8:
call NewPwd
;跳出
SSS:
ret
SwitchMenu endp
;查看所有
ShowAll proc
call sys_cls
;传入首地址
lea eax,g_stContacts
xor ebx,ebx
;对比当前容量
cmp dword ptr [g_nCount],0
je Empty
jne CYCLE_READ
;无数据结束
Empty:
push offset g_szEmpty
push offset g_szScanfFormatS
call crt_printf
add esp,8
jmp ShowAll_End
;读取数据
CYCLE_READ:
;传参从右至左
add eax,12h
push eax
sub eax,12h
push eax
push ebx
push offset g_szScanfFormatSS
call crt_printf
add esp,10h
;printf函数会影响A/C/D寄存器的值,需要重新传入地址
inc ebx
mov ecx,sizeof(CONTACTSSTRUCT)
imul ecx,ebx
lea eax,g_stContacts
add eax,ecx
cmp dword ptr [g_nCount],ebx
je ShowAll_End
jmp CYCLE_READ
;查询结束
ShowAll_End:
call sys_pause
ret
ShowAll endp
;添加
AddData proc
push ebp
mov ebp,esp
;请输入姓名
push offset g_szName
push offset g_szScanfFormatS
call crt_printf
add esp,8
;获取姓名
push offset g_strTemContacts.szName
push offset g_szScanfFormatS
call crt_scanf
add esp,8
;请输入号码
push offset g_szNember
push offset g_szScanfFormatS
call crt_printf
add esp,8
;获取号码
push offset g_strTemContacts.szPhoneNumber
push offset g_szScanfFormatS
call crt_scanf
add esp,8
;字符串补0结尾
mov byte ptr [g_strTemContacts.szName+17],0
mov byte ptr [g_strTemContacts.szPhoneNumber+11],0
;数据处理
mov ecx,sizeof(CONTACTSSTRUCT)
mov eax,dword ptr [g_nCount]
lea esi,g_strTemContacts
lea edi,g_stContacts
imul ecx
add edi,eax
rep movsb
inc dword ptr [g_nCount]
;输入成功
push offset g_szOK
push offset g_szScanfFormatS
call crt_printf
add esp,8
jmp In_End
;输入有误
In_Err:
push offset g_szInfoErr
push offset g_szScanfFormatS
call crt_printf
add esp,8
;输入结束,暂停3秒
In_End:
;保存文件
call SaveData
push 3000
call Sleep
add esp,4
mov esp,ebp
pop ebp
ret
AddData endp
;修改
ModifyData proc
push ebp
mov ebp,esp
;请输入要修改的编号
push offset g_szModify
push offset g_szScanfFormatS
call crt_printf
add esp,8
;获取编号
push offset g_nTemp
push offset g_szScanfFormatD
call crt_scanf
add esp,8
;检查编号是否有效
mov eax,dword ptr [g_nCount]
dec eax
cmp dword ptr [g_nTemp],0
jl Modify_Error
cmp dword ptr [g_nTemp],eax
jg Modify_Error
;请输入姓名
push offset g_szName
push offset g_szScanfFormatS
call crt_printf
add esp,8
;获取姓名
push offset g_strTemContacts.szName
push offset g_szScanfFormatS
call crt_scanf
add esp,8
;请输入号码
push offset g_szNember
push offset g_szScanfFormatS
call crt_printf
add esp,8
;获取号码
push offset g_strTemContacts.szPhoneNumber
push offset g_szScanfFormatS
call crt_scanf
add esp,8
;字符串补0结尾
mov byte ptr [g_strTemContacts.szName+17],0
mov byte ptr [g_strTemContacts.szPhoneNumber+11],0
;数据处理
mov ecx,sizeof(CONTACTSSTRUCT)
mov eax,dword ptr [g_nTemp]
lea esi,g_strTemContacts
lea edi,g_stContacts
imul ecx
add edi,eax
rep movsb
;输入成功
push offset g_szOK
push offset g_szScanfFormatS
call crt_printf
add esp,8
jmp Modify_End
Modify_Error:
;输入有误
push offset g_szNO
push offset g_szScanfFormatS
call crt_printf
add esp,8
Modify_End:
;保存文件
call SaveData
push 3000
call Sleep
add esp,4
mov esp,ebp
pop ebp
ret
ModifyData endp
;删除
DelData proc
push ebp
mov ebp,esp
;请输入要删除的编号
push offset g_szDelete
push offset g_szScanfFormatS
call crt_printf
add esp,8
;获取编号
push offset g_nTemp
push offset g_szScanfFormatD
call crt_scanf
add esp,8
;检查编号是否有效
mov eax,dword ptr [g_nCount]
dec eax
cmp dword ptr [g_nTemp],0
jl Del_Err
cmp dword ptr [g_nTemp],eax
jg Del_Err
;计算地址偏移
mov ebx,dword ptr [g_nTemp]
mov ecx,sizeof(CONTACTSSTRUCT)
imul ebx,ecx
;目的地址
lea edi,g_stContacts
add edi,ebx
;源地址
mov esi,edi
add esi,ecx
;计算拷贝数据量
mov eax,dword ptr [g_nCount]
sub eax,dword ptr [g_nTemp]
imul ecx,eax
;循环从后向前拷贝数据
rep movsb
;总数-1
dec dword ptr [g_nCount]
;输入成功
push offset g_szOK
push offset g_szScanfFormatS
call crt_printf
add esp,8
jmp Del_End
Del_Err:
;输入有误
push offset g_szNO
push offset g_szScanfFormatS
call crt_printf
add esp,8
Del_End:
;保存文件
call SaveData
push 3000
call Sleep
add esp,4
mov esp,ebp
pop ebp
ret
DelData endp
;查询
FindData proc
push ebp
mov ebp,esp
;请输入信息
push offset g_szFind
push offset g_szScanfFormatS
call crt_printf
add esp,8
;获取信息
push offset g_strTemContacts.szName
push offset g_szScanfFormatS
call crt_scanf
add esp,8
;字符串补0结尾
mov byte ptr [g_strTemContacts.szName+17],0
;计算字符串长度
xor eax,eax
mov ecx,0FFFFFFFFh
lea edi,[g_strTemContacts.szName]
repne scasb
not ecx
dec ecx
push ecx
mov ebx,0
lea esi,[g_strTemContacts.szName]
lea edi,[g_stContacts]
;循环对比字符串
;cmps会对esi和edi进行偏移,无论是否对比成功,
;esi可以重新赋值
;都必须保证每个段或每次循环edi位置在段首
;每个段中都会对edi进行加减操作,保持位置正确
CYCLE_CMP:
repe cmpsb
jne Find_Nember
;姓名比对成功
sub edi,[esp]
add edi,12h
push edi
sub edi,12h
push edi
push ebx
push offset g_szScanfFormatSS
call crt_printf
add esp,10h
add edi,13h ;恢复edi至初始位置
;姓名对比成功则跳过号码对比
jmp Find_No
;对比电话号码
Find_Nember:
sub edi,1
lea esi,[g_strTemContacts.szName]
mov ecx,[esp]
add edi,12h ;恢复edi至初始位置
repe cmpsb
jne Find_No
;电话对比成功
sub edi,[esp]
push edi
sub edi,12h
push edi
push ebx
push offset g_szScanfFormatSS
call crt_printf
add esp,10h
add edi,13h ;恢复edi至初始位置
;一轮结束
Find_No:
;对比进度,到达当前容量结束对比
inc ebx
cmp ebx,[g_nCount]
je Find_End
;增加地址偏移,继续循环
sub edi,1
lea esi,[g_strTemContacts.szName]
mov ecx,[esp]
add edi,0ch ;恢复edi至初始位置
jmp CYCLE_CMP
;对比结束
Find_End:
add esp,4
;暂停,按键继续
call sys_pause
mov esp,ebp
pop ebp
ret
FindData endp
;保存
SaveData proc
push ebp
mov ebp,esp
;文件句柄清0
mov dword ptr [g_hFileHandle],0
;打开文件
push offset g_szFileWB
push offset g_szFile
call crt_fopen
add esp,08h
mov dword ptr [g_hFileHandle],eax
;存储密码
;这里是文件句柄,没有offset
push g_hFileHandle
;数据数量
push 1
;单个数据数量
push 4
;首地址
lea ebx,[g_nPassword]
push ebx
call crt_fwrite
add esp,10h
;存储文件数量
;这里是文件句柄,没有offset
push g_hFileHandle
;数据数量
push 1
;单个数据数量
push 4
;首地址
lea ebx,[g_nCount]
push ebx
call crt_fwrite
add esp,10h
;存储文件
;这里是文件句柄,没有offset
push g_hFileHandle
;数据数量
lea ebx,[g_nCount]
push ebx
;单个数据数量
mov eax,sizeof(CONTACTSSTRUCT)
push eax
;首地址
lea ebx,[g_stContacts]
push ebx
call crt_fwrite
add esp,10h
;关闭文件
;这里是文件句柄,没有offset
push g_hFileHandle
call crt_fclose
add esp,4
mov dword ptr [g_hFileHandle],0
mov esp,ebp
pop ebp
ret
SaveData endp
;读取文件
ReadData proc
push ebp
mov ebp,esp
;文件句柄清0
mov dword ptr [g_hFileHandle],0
;打开文件
push offset g_szFileRB
push offset g_szFile
call crt_fopen
add esp,08h
mov dword ptr [g_hFileHandle],eax
;文件不存在就结束
cmp dword ptr [g_hFileHandle],0
je Read_End
;读取密码
;这里是文件句柄,没有offset
push g_hFileHandle
;数据数量
push 1
;单个数据数量
push 4
;首地址
lea ebx,[g_nPassword]
push ebx
call crt_fread
add esp,10h
;读取文件数量
;这里是文件句柄,没有offset
push g_hFileHandle
;数据数量
push 1
;单个数据数量
push 4
;首地址
lea ebx,[g_nCount]
push ebx
call crt_fread
add esp,10h
;读取文件
;这里是文件句柄,没有offset
push g_hFileHandle
;数据数量
lea ebx,[g_nCount]
push ebx
;单个数据数量
mov eax,sizeof(CONTACTSSTRUCT)
push eax
;首地址
lea ebx,[g_stContacts]
push ebx
call crt_fread
add esp,10h
Read_End:
;关闭文件
;这里是文件句柄,没有offset
push g_hFileHandle
call crt_fclose
add esp,4
mov dword ptr [g_hFileHandle],0
mov esp,ebp
pop ebp
ret
ReadData endp
;保存文本
SaveTXT proc
push ebp
mov ebp,esp
;检测当前容量
cmp dword ptr [g_nCount],0
je TXT_EMPTY
;句柄清0
mov dword ptr [g_hFileHandle],0
;打开文件
push offset g_szFileW
push offset g_szFileTXT
call crt_fopen
add esp,08h
mov dword ptr [g_hFileHandle],eax
;传入首地址
lea eax,g_stContacts
xor ebx,ebx
CYCLE_TXT:
;传参从右至左
add eax,12h
push eax
sub eax,12h
push eax
push ebx
push offset g_szScanfFormatSS
push g_hFileHandle
call crt_fprintf
add esp,14h
;对比存储进度
inc ebx
mov ecx,sizeof(CONTACTSSTRUCT)
imul ecx,ebx
lea eax,g_stContacts
add eax,ecx
cmp dword ptr [g_nCount],ebx
je TXT_CLOSE
jmp CYCLE_TXT
TXT_CLOSE:
;关闭文件
;这里是文件句柄,没有offset
push g_hFileHandle
call crt_fclose
add esp,4
mov dword ptr [g_hFileHandle],0
;操作成功
push offset g_szOK
push offset g_szScanfFormatS
call crt_printf
add esp,8
jmp TXT_END
TXT_EMPTY:
;操作失败
push offset g_szNO
push offset g_szScanfFormatS
call crt_printf
add esp,8
TXT_END:
;暂停3秒
push 3000
call Sleep
add esp,4
mov esp,ebp
pop ebp
ret
SaveTXT endp
;修改密码,隐藏选项8
NewPwd proc
push ebp
mov ebp,esp
;提示输入密码
push offset g_szPwdNew
push offset g_szScanfFormatS
call crt_printf
add esp,8
push offset g_nPassword
push offset g_szScanfFormatD
call crt_scanf
add esp,8
call SaveData
;操作成功
push offset g_szOK
push offset g_szScanfFormatS
call crt_printf
add esp,8
;暂停3秒
push 3000
call Sleep
add esp,4
mov esp,ebp
pop ebp
ret
NewPwd endp