使用匯編構造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