Win32汇编练习_电话本_源码

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/D_K_01/article/details/79516269

Win32汇编_电话本

功能

  1. 独立密码,可修改;
  2. 增删改查;
  3. 保存二进制文件,保存文本文件;

截图

电话本主界面
电话本主界面

查看所有
查看所有

保存文本文件
保存文本文件

练习目的

初学汇编,简单的电话本实现增删改查练手,
难点部分是数据对比和数据拷贝,文件操作;
练习汇编命令,特别是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

End

猜你喜欢

转载自blog.csdn.net/D_K_01/article/details/79516269