代码放送【Base64编码解码的Win32汇编代码】
.386.MODEL FLAT
INCLUDE WINDOWS.INC
INCLUDELIB IMPORT32.LIB
EXTRN ExitProcess:PROC
EXTRN MessageBoxA:PROC
EXTRN LoadLibraryA:PROC
EXTRN GetProcAddress:PROC
.DATA
szTest db 'Hello,world!Good luck.',0
.CODE
;测试代码
_Start:
PUSH EBP
MOV EBP,ESP
SUB ESP,8
;调用_Base64Encode计算编码所需内存
PUSH 0
PUSH OFFSET szTest
PUSH 22
CALL _Base64Encode
;分配内存
SUB ESP,EAX
MOV DWORD PTR ,ESP
;编码
PUSH ESP
PUSH OFFSET szTest
PUSH 22
CALL _Base64Encode
;调用_Base64Decode计算解码所需内存
PUSH 0
PUSH DWORD PTR
CALL _Base64Decode
;分配内存
SUB ESP,EAX
PUSH ESP
POP DWORD PTR
;解码
PUSH ESP
PUSH DWORD PTR
CALL _Base64Decode
;MessageBoxA显示编码结果
PUSH MB_OK
PUSH NULL
PUSH DWORD PTR
PUSH NULL
CALL MessageBoxA
;MessageBoxA显示解码结果
PUSH MB_OK
PUSH NULL
PUSH DWORD PTR
PUSH NULL
CALL MessageBoxA
MOV ESP,EBP
POP EBP
PUSH 0
CALL ExitProcess
;*******************************************************************
;_Hex2Base64 PROC stdcall
;功能:
; 将6bit二进制数转换为Base64编码
;参数:
; 无栈参数,以寄存器传递参数
; AL : 6Bits 二进制数
; EDI : 编码后存储内存地址
;返回值:
; 无
;*******************************************************************
_Hex2Base64 PROC
PUSH EAX
AND EAX,0FFH
ADD EAX,DWORD PTR
MOV AL,BYTE PTR
STOSB
POP EAX
RET
_Hex2Base64 ENDP
;*******************************************************************
;Base642Hex PROC stdcall
;功能:
; 将Base64编码转换为6bit二进制数
;参数:
; 无栈参数,以寄存器传递参数
; AL : Base64编码字符
;返回值:EAX
; = -1 ;AL为非法的Base64编码
; = 0-63 ;转换后的6Bit二进制数
;*******************************************************************
_Base642Hex PROC
PUSH ECX
PUSH EDI
PUSH 041H
POP ECX
MOV EDI,DWORD PTR
REPNE SCASB
TEST ECX,ECX
JECXZ _IsNotBase64
PUSH 040H
POP EAX
SUB EAX,ECX
JMP _IsBase64
_IsNotBase64:
XOR EAX,EAX
DEC EAX
_IsBase64:
POP EDI
POP ECX
RET
_Base642Hex ENDP
;*******************************************************************
;_CreateBase64Table PROC stdcall
;功能:
; 生成Base64编码表
;参数:
; 无栈参数,以寄存器传递参数
; EDI : 编码表首地址
;返回值:无
;*******************************************************************
_CreateBase64Table PROC
MOV AL,'A'
PUSH 26
POP ECX
;循环存储 'A' - 'Z'
_CreateBase64Table@1:
STOSB
INC AL
LOOP _CreateBase64Table@1
MOV AL,'a'
PUSH 26
POP ECX
;循环存储 'a' - 'z'
_CreateBase64Table@2:
STOSB
INC AL
LOOP _CreateBase64Table@2
MOV AL,'0'
PUSH 10
POP ECX
;循环存储 '0' - '9'
_CreateBase64Table@3:
STOSB
INC AL
LOOP _CreateBase64Table@3
;存储 '+'
MOV AL,'+'
STOSB
;存储 '/'
MOV AL,'/'
STOSB
RET
_CreateBase64Table ENDP
;*******************************************************************
;_Base64Encode PROC stdcall,lenOfSrc:DWORD,addrOfSrc:DWORD,addrOfDst:DWORD
;参数说明:
; lenOfSrc : 源字符串长度
; addrOfSrc: 源字符串地址
; addrOfDst: 编码后字符串存储地址
;调用方式:
; PUSH addrOfDst
; PUSH addrOfSrc
; PUSH lenOfSrc
; CALL _Base64Encode
;
;进入函数后栈使用状况:
; = 编码后字符串存储地址
; = 源字符串地址
; = 源字符串长度
; = 函数返回地址
; = old EBP
; = 源字符串长 / 3 (商)
; = 源字符串长 MOD 3 (余数)
; = 编码后字符串长度 = 源字符串长 / 3 * 4
; = base64 编码表地址
;返回值:EAX
; = 0 ;编码错误(源字符串为空)
; = 1 ;编码成功
; = ;addrOfDst = NULL,返回编码后字符串所需内存
;*******************************************************************
_Base64Encode PROC
@Local_Variant = 16
PUSH EBP
MOV EBP,ESP
SUB ESP,@Local_Variant
MOV EAX,DWORD PTR
;如果源字符串为NULL,则不处理
TEST EAX,EAX
JE _Base64Encode_Exit
PUSH ECX
PUSH EDX
MOV EAX,DWORD PTR
XOR EDX,EDX
PUSH 03H
POP ECX
DIV ECX
;商 =>
MOV DWORD PTR ,EAX
;余数 =〉
MOV DWORD PTR ,EDX
;测试源字符串长是否能被3整除
;不能整除则需要多分配4个字节的内存
TEST EDX,EDX
JE _Base64Encode_ZeroModBy3
INC EAX
_Base64Encode_ZeroModBy3:
;编码后字符串尾需加0结尾,多分配4字节
INC EAX
; EAX = EAX * 4
SHL EAX,2
;编码后所需内存数 =>
MOV DWORD PTR ,EAX
POP EDX
POP ECX
;测试编码后字符串存储地址是否为空
MOV EAX,DWORD PTR
TEST EAX,EAX
;非空则可进行编码
JNE _Base64Encode_Encode
;为空则返回所需内存数
MOV EAX,DWORD PTR
JMP _Base64Encode_Exit
_Base64Encode_Encode:
;为Base64编码表分配64字节内存
SUB ESP,040H
;保存编码表的首地址
MOV DWORD PTR ,ESP
PUSH ECX
PUSH ESI
PUSH EDI
;创建编码表
MOV EDI,DWORD PTR
CALL _CreateBase64Table
;为编码准备
MOV ECX,DWORD PTR
MOV ESI,DWORD PTR
MOV EDI,DWORD PTR
;每3个字节循环编码
_Base64Encode_Loop:
XOR EAX,EAX
;编码第一个字符
LODSB
SHL AX,6
XCHG AH,AL
CALL _Hex2Base64
SHR AX,6
;编码第二个字符
LODSB
SHL AX,4
XCHG AH,AL
CALL _Hex2Base64
SHR AX,4
;编码第三个字符
LODSB
SHL AX,2
XCHG AH,AL
CALL _Hex2Base64
;第三个字符的后6Bit处理
XCHG AH,AL
SHR AL,2
CALL _Hex2Base64
;循环
LOOP _Base64Encode_Loop
;循环结束后,对不足3个字符的处理
MOV ECX,DWORD PTR
;无字符剩余,直接跳转
JECXZ _LeftZeroByte
;处理剩下的第一个字符
XOR EAX,EAX
LODSB
SHL AX,6
XCHG AH,AL
CALL _Hex2Base64
DEC ECX
;只剩余1字符,跳转
JECXZ _LeftOneByte
;剩余2字符处理
SHR AX,6
LODSB
SHL AX,4
XCHG AH,AL
CALL _Hex2Base64
XCHG AH,AL
SHR AL,2
CALL _Hex2Base64
;补一个'='号
MOV BYTE PTR ,'='
INC EDI
JMP _LeftZeroByte
;只剩余1字符处理
_LeftOneByte:
XCHG AH,AL
SHR AL,2
CALL _Hex2Base64
;补两个'='号
MOV BYTE PTR ,'='
INC EDI
MOV BYTE PTR ,'='
INC EDI
;无字符剩余
_LeftZeroByte:
XOR EAX,EAX
STOSB
INC EAX
POP EDI
POP ESI
POP ECX
_Base64Encode_Exit:
;恢复栈
MOV ESP,EBP
POP EBP
RET 12
_Base64Encode ENDP
;*******************************************************************
;_Base64Decode PROC stdcall,addrOfSrc:DWORD,addrOfDst:DWORD
;参数说明:
; addrOfSrc: 源字符串地址
; addrOfDst: 解码后字符串存储地址
;调用方式:
; PUSH addrOfDst
; PUSH addrOfSrc
; CALL _Base64Decode
;
;进入函数后栈使用状况:
; = 解码后字符串存储地址
; = 源字符串地址(以0结尾)
; = 函数返回地址
; = old EBP
; = 源字符串长 或 解码实际所得字符数
; = 源字符串长 MOD 4
; = 解码所需内存
; = base64 编码表地址
;返回值:EAX
; = 0 解码错误(源地址为空、源字符串为非法Base64编码)
; = 解码所需内存数 (解码后存储地址为NULL)
; = 解码实际所得字符
;*******************************************************************
_Base64Decode PROC
PUSH EBP
MOV EBP,ESP
SUB ESP,@Local_Variant
;测试源字符串是否为空
;为空则返回0
MOV EAX,DWORD PTR
TEST EAX,EAX
JE _Base64Decode_Exit
PUSH ECX
PUSH EDX
PUSH EDI
;计算源字符串长(T-Null String:即以0结尾的字符串)
PUSH EAX
POP EDI
XOR EAX,EAX
XOR ECX,ECX
DEC ECX
REPNE SCASB
NOT ECX
DEC ECX
;保存源字符串长
MOV DWORD PTR ,ECX
;源字符串长 / 4
PUSH ECX
POP EAX
XOR EDX,EDX
PUSH 4
POP ECX
DIV ECX
;余数 =>
MOV DWORD PTR ,EDX
;商 * 3 =>
;解码所需内存 = 源码长 / 4 * 3
XOR EDX,EDX
IMUL EAX,EAX,3
MOV DWORD PTR ,EAX
POP EDI
POP EDX
POP ECX
;检测余数是否为0,不为0说明不是合法的Base64编码
MOV EAX,DWORD PTR
TEST EAX,EAX
;=0 则说明为合法Base64编码
JE _SourceIsRight
;!=0 则说明不是合法的Base64编码,返回0
XOR EAX,EAX
JMP _Base64Decode_Exit
_SourceIsRight:
;检测解码后存储地址是否为空
MOV EAX,DWORD PTR
TEST EAX,EAX
JNE _DstIsNotNull
;为空则返回解码所需内存数
MOV EAX,DWORD PTR
JMP _Base64Decode_Exit
_DstIsNotNull:
;在栈里为Base64编码表分配64字节
SUB ESP,040H
;保存编码表首地址
MOV DWORD PTR ,ESP
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
;创建编码表
MOV EDI,DWORD PTR
CALL _CreateBase64Table
XOR EAX,EAX
;源字符串长 => ECX 作为循环计数器
MOV ECX,DWORD PTR
;清零,作为解码字符计数器
MOV DWORD PTR ,EAX
;源字符串地址 => ESI
MOV ESI,DWORD PTR
;解码字符串地址 => EDI
MOV EDI,DWORD PTR
;字符移位计数器 => EDX
PUSH 18
POP EDX
XOR EBX,EBX
_Base64Decode_Loop:
;除了立即数只有 CL 寄存器可作为移位计数器
XCHG EDX,ECX
;获取一个字符
LODSB
;= '='则说明解码到了末尾
CMP AL,'='
JE _IsBase64CodeTail
;调用函数解码
CALL _Base642Hex
;测试返回值是否 = -1
INC EAX
TEST EAX,EAX
;= -1说明源字符串中有非Base64编码字符
JE _Base64Error
;恢复返回值
DEC EAX
;EAX左移CL位 CL = 18,12,6,0
SHL EAX,CL
;将新解码的6Bits保存进 EBX
OR EBX,EAX
;CL = 0 说明解码进行了4次
JECXZ _Decode4Bytes
SUB ECX,6
;CL != 0 循环解码
XCHG EDX,ECX
LOOP _Base64Decode_Loop
;4次解码后则可保存解码结果
_Decode4Bytes:
PUSH EBX
POP EAX
PUSH EAX
;右移16位保存第一个解码字符
SHR EAX,16
STOSB
;计数器 + 1
INC DWORD PTR
POP EAX
PUSH EAX
;右移8位保存第二个解码字符
SHR EAX,8
STOSB
;计数器 + 1
INC DWORD PTR
;保存第三个解码字符
POP EAX
STOSB
;计数器 + 1
INC DWORD PTR
;移位计数器恢复为18
PUSH 18
POP ECX
XOR EBX,EBX
;恢复移位计数器和循环计数器
XCHG EDX,ECX
LOOP _Base64Decode_Loop
;如果循环从此处退出,EDX => ECX
XCHG ECX,EDX
;解码末尾处理
;因为合法的Base64编码末尾可能有的'='个数(0,1,2)
;0个 '='时 CL = 18
;一个'='时 CL = 0
;二个'='时 CL = 6
;不满足上述3条件,则为非法Base64编码
_IsBase64CodeTail:
;保存ECX => EDX
XCHG ECX,EDX
;检测 CL = 18 ?,是则说明有 0 个 '='
SUB ECX,18
JECXZ _IsZeroByte
;恢复ECX
XCHG ECX,EDX
CMP ECX,6
JLE _IsOneTwoBytes
;ECX > 6 为非法Base64编码,返回0
XOR EAX,EAX
JMP _Base64Error
_IsOneTwoBytes:
;有1或2个'='的处理
PUSH EBX
POP EAX
PUSH EAX
;右移16位保存第一个解码字符
SHR EAX,16
STOSB
;计数器 + 1
INC DWORD PTR
POP EAX
;检测 CL = 6?
SUB ECX,6
JECXZ _IsZeroByte
SHR EAX,8
STOSB
INC DWORD PTR
_IsZeroByte:
MOV EAX,DWORD PTR
_Base64Error:
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
_Base64Decode_Exit:
MOV ESP,EBP
POP EBP
RET 8
_Base64Decode ENDP
End _Start
页:
[1]