用匯編構造__stdcall的sprintf函數

使用匯編構造sprintf函數。
我沒有去逆向sprintf函數,主要是過程太多了,並且只要知道運算結果就能大概推算出過程了。
以下構造並不完整,但能實現sprintf函數大多數功能,比如字符串中的'%%'解析爲'%','%x'解析爲十六進制單字節數,'%X'解析爲十六進制雙字數,'%d'解析爲十進制數,其他的出於時間關係,我就沒寫了。
另外,爲了方便調用,我將過程寫爲__stdcall調用方式,也算是__stdcall的sprintf吧。。。
在使用前應該加上兩個宏:

put macro
    mov     byte ptr [ebp+ecx+08h], al
endm

get macro
    mov     al, byte ptr [ebp+ebx+0ch]
endm

put就是向新指針寫入一字節,get就是向老字符串讀取一字節

目前暫時只能處理ANSI格式字符串,不過對於不熟悉Unicode的童鞋們也夠了
由於直接使用函數過程不能達到變長__stdcall,所以我用的過程表示,在最後ret指令前加上sub     esp, edx這句實現堆棧的還原。

 


廢話不多說,上源碼:




;void sprintf(LPCTSTR lpFormatStr, LPCSTR lpStr, ...)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sprintf:
    push    ebp
    mov     ebp, esp
    ;無局部變量
    xor     ebx, ebx                              ;格式化前指針
    xor     ecx, ecx                              ;格式化後指針
    mov     edx, 0ch                              ;參數指針
@@1:                                              ;主循環
    inc     ecx
    get
    cmp     al, 0
    jz      @@end
    .if     al == '%'
        inc     ebx
        add     edx, 04h
        get
        .if     al == 'x'
            mov     al, '0'
            put

            inc     ecx
            mov     al, 'x'
            put

            xor     eax, eax
            mov     al, byte ptr [ebp+edx]
            ror     eax, 4

            .if     al > 9
                add     al, 37h
            .else
                add     al, 30h
            .endif
            inc     ecx
            put

            rol     eax, 4

            .if     al > 9
                add     al, 37h
            .else
                add     al, 30h
            .endif
            inc     ecx
            put

        .elseif al == 'X'
            mov     al, '0'
            put

            inc     ecx
            mov     al, 'x'
            put

            mov     eax, dword ptr [ebp+edx]
            push    edx

            mov     edx, 8
            .while  edx > 0

                push    eax
                dec     edx

                lea     edx, [edx*4]
                ror     eax, edx
                and     al, 0fh

                .if     al > 9
                    add     al, 37h
                .else
                    add     al, 30h
                .endif
                inc     ecx
                put

                pop     eax
            .endw
            pop     edx

        .elseif al == 'd'
            mov     eax, dword ptr [ebp+edx]

            push    ebx
            push    edx
            xor     ebx, ebx

            .while  eax > 0
                mov     edx, 0ah
                div     edx
                push    edx
                inc     ebx
            .endw

            .while ebx > 0
                pop     eax
                inc     ecx
                put
                dec     ebx
            .endw

            pop     edx
            pop     ebx

        .elseif al == '%'
            sub     edx, 04h
            put
        .endif

    .else
        put
    .endif

    inc     ebx
    jmp     @@1

@@end:                                              ;循環結束
    inc     ecx
    xor     al, al
    put

    leave
    sub     edx, 04h
    sub     esp, edx
    ret

 

 

另外,可以用函數來導出,比如:

std_sprintf proc lpFormatStr, lpStr

    ;函數過程前面自動生成push ebp/mov ebp, esp

    ;sprintf過程前面去掉這句

    jmp sprintf

    ret;這句要不要就無所謂了,不過有時沒有這句編譯不會通過

std_sprintf

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章