来自于《Intel汇编语言程序设计》(第四版)第六章。
这个例子利用了XOR(异或)指令的一个特性(即对操作数两次异或之后操作效果抵消),对字符串进行加密。
书中代码:
TITLE Encryption Program (Encrypt.asm)
INCLUDE Irvine32.inc
KEY = 239 ; any value between 1-255
BUFMAX = 128 ; maximum buffer size
.data
sPrompt BYTE "Enter the plain text : ",0
sEncrypt BYTE "Cypher text : ",0
sDecrypt BYTE "Decrypted : ",0
buffer BYTE BUFMAX dup(0)
bufsize DWORD ?
.code
main PROC
call InputTheString ; input the plain text
call TranslateBuffer ; encrypt the buffer
mov edx , OFFSET sEncrypt ; display encrypted message
call DisplayMessage
call TranslateBuffer ; decrypt the buffer
mov edx , OFFSET sDecrypt ; display decrypted message
call DisplayMessage
exit
main ENDP
;------------------------------------------------------------------
InputTheString PROC
;
; Asks the user to enter a string from the
; keyboard Saves the string and its length
; in variables.
; Receives : nothing
; Returns : nothing
;------------------------------------------------------------------
pushad
mov edx , OFFSET sPrompt ;display a prompt
call WriteString
mov ecx,BUFMAX ; maximum character count
mov edx,OFFSET buffer ; point to the buffer
call ReadString ; input the string
mov bufsize , eax ; save length
call Crlf
popad
ret
InputTheString ENDP
;------------------------------------------------------------------
DisplayMessage PROC
;
; Display the encrypted or decrypted message
; Receives : EDX points to the message
; Returns : nothing
;------------------------------------------------------------------
pushad
call WriteString
mov edx , OFFSET buffer ;display the buffer
call WriteString
call Crlf
call Crlf
popad
ret
DisplayMessage ENDP
;------------------------------------------------------------------
TranslateBuffer PROC
;
; Translate the string by exclusive-ORing each
; byte with the same integer .
; Receives : nothing
; Returns : nothing
;------------------------------------------------------------------
pushad
mov ecx , bufsize ; loop counter
mov esi , 0 ; index 0 in buffer
L1:
xor buffer[esi] , KEY ; translate a byte
inc esi ; point to next byte
loop L1
popad
ret
TranslateBuffer ENDP
END main
让我们来逐句分析这段程序的代码:
首先,程序包含了作者的一个inc文件,里面有一些常量的定义,随后定义了一个用来加密的数字,这里是239,和一个缓冲长度值,这里是128:
INCLUDE Irvine32.inc
KEY = 239 ; any value between 1-255
BUFMAX = 128 ; maximum buffer size
随后,数据段如下:
.data
sPrompt BYTE "Enter the plain text : ",0
sEncrypt BYTE "Cypher text : ",0
sDecrypt BYTE "Decrypted : ",0
buffer BYTE BUFMAX dup(0)
bufsize DWORD ?
定义了三个字符串,用于程序中的显示,一个buffer数组,还有一个用来存储长度的bufsize变量
接下来的是主程序段,这里有一个main函数和三个子函数,分别是:
InputTheString
DisplayMessage
TranslateBuffer
让我们先看一下三个子函数。
首先是InputTheString ,这个函数用来提示用户输入值,并且将值保存到buffer中,看一下代码:
pushad ; 首先保存所有寄存器的值
mov edx , OFFSET sPrompt ; 将sPrompt的地址赋给edx(用于下面的显示)
call WriteString ; 显示edx中的值
mov ecx,BUFMAX ; 将字符串的数量赋给ecx,因为ecx将用于循环的计数器
mov edx,OFFSET buffer ; 将edx寄存器指向buffer数组的地址
call ReadString ; 读取用户输入的字符串到buffer中
mov bufsize , eax ; 将用户输入字符串的长度值(此时保存在eax寄存器中),赋值给bufsize
call Crlf ; 将光标输出到下一行的开始
popad ; 重新得到所有寄存器的值
ret ; EIP 跳回
整个过程很简单。
然后我们再来看DisplayMessage :
pushad ; 首先保存所有寄存器的值
call WriteString ; 显示edx寄存器中的值,显然这需要在调用函数之前对edx赋值
mov edx , OFFSET buffer ; 将buffer 中保存的值赋值到edx中准备显示
call WriteString ; 显示edx中的值
call Crlf ; 将光标输出到下一行的开始
call Crlf ; 将光标输出到下一行的开始
popad ; 重新得到所有寄存器的值
ret ; EIP 跳回
然后再来看一下 TranslateBuffer :
pushad ; 首先保存所有寄存器的值
mov ecx , bufsize ; 将长度赋值给ecx,用于循环计数
mov esi , 0 ; esi作为数组的index值,从零开始
L1:
xor buffer[esi] , KEY ; 使用key值对每一个字节进行异或操作
inc esi ; 将index值加1
loop L1 ; 重复执行L1,此时ecx值自减1
popad ; 异或操作完成后,重新得到所有寄存器的值
ret ; EIP 跳回
此函数时比较核心的部分,用于执行异或操作。
最后让我们看一下main函数:
call InputTheString ; 得到用户的输入,放到buffer数组中
call TranslateBuffer ; 将buffer数组中的每一个字节进行异或操作,即“加密”操作
mov edx , OFFSET sEncrypt ; 因为DisplayMessage需要用到edx值,所以为edx赋值
call DisplayMessage ; 显示用户输入字符串的加密值
call TranslateBuffer ; 对buffer数组进行第二次异或操作,即“解密”操作
mov edx , OFFSET sDecrypt ; 为edx赋值
call DisplayMessage ; 显示解密后的字符串
exit ; 退出(此函数并不是MASM伪指令,而是作者库中的函数)
以上便是最简单的汇编加密程序的代码分析。