鱼C论坛

 找回密码
 立即注册
查看: 3167|回复: 0

[技术交流] 代码放送【Base64编码解码的Win32汇编代码】

[复制链接]
发表于 2016-10-15 11:37:22 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
.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 [EBP - 4],ESP
       
        ;编码
        PUSH        ESP
        PUSH        OFFSET szTest
        PUSH        22
        CALL        _Base64Encode
       
        ;调用_Base64Decode计算解码所需内存
        PUSH        0
        PUSH        DWORD PTR [EBP - 4]
        CALL        _Base64Decode
       
        ;分配内存
        SUB                ESP,EAX
        PUSH        ESP
        POP                DWORD PTR [EBP - 8]
       
        ;解码
        PUSH        ESP
        PUSH        DWORD PTR [EBP - 4]
        CALL        _Base64Decode
       
        ;MessageBoxA显示编码结果
        PUSH        MB_OK
        PUSH        NULL
        PUSH        DWORD PTR [EBP - 4]
        PUSH        NULL
        CALL        MessageBoxA
       
        ;MessageBoxA显示解码结果
        PUSH        MB_OK
        PUSH        NULL
        PUSH        DWORD PTR [EBP - 8]
        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 [EBP - 16]
        MOV                AL,BYTE PTR [EAX]
        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 [EBP - 16]

        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
;
;进入函数后栈使用状况:
;                        [EBP + 16]        = 编码后字符串存储地址
;                        [EBP + 12]        = 源字符串地址
;                        [EBP + 8]        = 源字符串长度
;                        [EBP + 4]        = 函数返回地址
;                        [EBP]                = old EBP
;                        [EBP - 4]        = 源字符串长 / 3   (商)
;                        [EBP - 8]        = 源字符串长 MOD 3 (余数)
;                        [EBP - 12]        = 编码后字符串长度 = 源字符串长 / 3 * 4
;                        [EBP - 16]        = base64 编码表地址
;返回值:EAX
;                        = 0 ;编码错误(源字符串为空)
;                        = 1        ;编码成功
;                        =        ;addrOfDst = NULL,返回编码后字符串所需内存
;*******************************************************************
_Base64Encode        PROC
        @Local_Variant = 16
        PUSH        EBP
        MOV                EBP,ESP
        SUB                ESP,@Local_Variant
       
        MOV                EAX,DWORD PTR [EBP + 12]
               
        ;如果源字符串为NULL,则不处理
        TEST        EAX,EAX
        JE                _Base64Encode_Exit
       
        PUSH        ECX
        PUSH        EDX
       
        MOV                EAX,DWORD PTR [EBP + 8]               
        XOR                EDX,EDX

        PUSH        03H
        POP                ECX
       
        DIV                ECX
       
        ;商 => [EBP - 4]
        MOV                DWORD PTR [EBP - 4],EAX
        ;余数 =〉[EBP - 8]
        MOV                DWORD PTR [EBP - 8],EDX
       
        ;测试源字符串长是否能被3整除
        ;不能整除则需要多分配4个字节的内存
        TEST        EDX,EDX
        JE                _Base64Encode_ZeroModBy3
        INC                EAX

_Base64Encode_ZeroModBy3:
        ;编码后字符串尾需加0结尾,多分配4字节
        INC                EAX
        ; EAX = EAX * 4
        SHL                EAX,2
       
        ;编码后所需内存数 => [EBP - 12]
        MOV                DWORD PTR [EBP - 12],EAX
       
        POP                EDX
        POP                ECX
       
        ;测试编码后字符串存储地址是否为空
        MOV                EAX,DWORD PTR [EBP + 16]
        TEST        EAX,EAX
        ;非空则可进行编码
        JNE                _Base64Encode_Encode
       
        ;为空则返回所需内存数
        MOV                EAX,DWORD PTR [EBP - 12]
        JMP                _Base64Encode_Exit

_Base64Encode_Encode:
        ;为Base64编码表分配64字节内存
        SUB                ESP,040H
        ;保存编码表的首地址
        MOV                DWORD PTR [EBP - 16],ESP
       
        PUSH        ECX
        PUSH        ESI
        PUSH        EDI
       
        ;创建编码表
        MOV                EDI,DWORD PTR [EBP-16]
        CALL        _CreateBase64Table

        ;为编码准备
        MOV                ECX,DWORD PTR [EBP - 4]
        MOV                ESI,DWORD PTR [EBP + 12]
        MOV                EDI,DWORD PTR [EBP + 16]
       
;每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 [EBP - 8]
        ;无字符剩余,直接跳转
        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 [EDI],'='
        INC                EDI
        JMP                _LeftZeroByte

        ;只剩余1字符处理
_LeftOneByte:
        XCHG        AH,AL
        SHR                AL,2
        CALL        _Hex2Base64
        ;补两个'='号
        MOV                BYTE PTR [EDI],'='
        INC                EDI
        MOV                BYTE PTR [EDI],'='
        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
;
;进入函数后栈使用状况:
;                        [EBP + 12]        = 解码后字符串存储地址
;                        [EBP + 8]        = 源字符串地址(以0结尾)
;                        [EBP + 4]        = 函数返回地址
;                        [EBP]                = old EBP
;                        [EBP - 4]        = 源字符串长 或 解码实际所得字符数
;                        [EBP - 8]        = 源字符串长 MOD 4
;                        [EBP - 12]        = 解码所需内存
;                        [EBP - 16]        = base64 编码表地址
;返回值:EAX
;                        = 0                解码错误(源地址为空、源字符串为非法Base64编码)
;                        = 解码所需内存数 (解码后存储地址为NULL)
;                        = 解码实际所得字符
;*******************************************************************
_Base64Decode        PROC
        PUSH        EBP
        MOV                EBP,ESP
        SUB                ESP,@Local_Variant
       
        ;测试源字符串是否为空
        ;为空则返回0
        MOV                EAX,DWORD PTR [EBP + 8]
        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 [EBP - 4],ECX
       
        ;源字符串长 / 4
        PUSH        ECX
        POP                EAX
        XOR                EDX,EDX
        PUSH        4
        POP                ECX
        DIV                ECX

        ;余数 => [EBP - 8]
        MOV                DWORD PTR [EBP - 8],EDX
       
        ;商 * 3 => [EBP - 12]
        ;解码所需内存 = 源码长 / 4 * 3
        XOR                EDX,EDX
        IMUL        EAX,EAX,3
        MOV                DWORD PTR [EBP - 12],EAX
       
        POP                EDI
        POP                EDX
        POP                ECX
       
        ;检测余数是否为0,不为0说明不是合法的Base64编码
        MOV                EAX,DWORD PTR [EBP - 8]
        TEST        EAX,EAX
        ;=0 则说明为合法Base64编码
        JE                _SourceIsRight
        ;!=0 则说明不是合法的Base64编码,返回0
        XOR                EAX,EAX
        JMP                _Base64Decode_Exit
_SourceIsRight:
        ;检测解码后存储地址是否为空
        MOV                EAX,DWORD PTR [EBP + 12]
        TEST        EAX,EAX
        JNE                _DstIsNotNull
        ;为空则返回解码所需内存数
        MOV                EAX,DWORD PTR [EBP - 12]
        JMP                _Base64Decode_Exit
_DstIsNotNull:
        ;在栈里为Base64编码表分配64字节
        SUB                ESP,040H
        ;保存编码表首地址
        MOV                DWORD PTR [EBP - 16],ESP

        PUSH        EBX
        PUSH        ECX
        PUSH        EDX
        PUSH        ESI
        PUSH        EDI
       
        ;创建编码表
        MOV                EDI,DWORD PTR [EBP - 16]
        CALL        _CreateBase64Table

        XOR                EAX,EAX
        ;源字符串长[EBP-4] => ECX 作为循环计数器
        MOV                ECX,DWORD PTR [EBP - 4]
        ;[EBP-4]清零,作为解码字符计数器
        MOV                DWORD PTR [EBP - 4],EAX
        ;源字符串地址 => ESI
        MOV                ESI,DWORD PTR [EBP + 8]
        ;解码字符串地址 => EDI
        MOV                EDI,DWORD PTR [EBP + 12]
       
        ;字符移位计数器 => 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 [EBP - 4]

        POP                EAX
        PUSH        EAX
        ;右移8位保存第二个解码字符
        SHR                EAX,8
        STOSB
        ;计数器 + 1
        INC                DWORD PTR [EBP - 4]

        ;保存第三个解码字符
        POP                EAX
        STOSB
        ;计数器 + 1
        INC                DWORD PTR [EBP - 4]

        ;移位计数器恢复为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 [EBP - 4]

        POP                EAX

        ;检测 CL = 6?
        SUB                ECX,6
        JECXZ        _IsZeroByte
        SHR                EAX,8
        STOSB
        INC                DWORD PTR [EBP - 4]
_IsZeroByte:
        MOV                EAX,DWORD PTR [EBP - 4]

_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鱼币 +5 收起 理由
爱学习520 + 5

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-19 14:25

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表