News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Need a replacement for wsprintf()

Started by NoCforMe, October 24, 2011, 02:57:57 AM

Previous topic - Next topic

MichaelW

#15
This depends only on MSVCRT. It effectively eliminates the buffer-overrun problem, but not the potential problems with a user-defined format string.

;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================

printf MACRO format:REQ, args:VARARG
    IFNB <args>
        invoke crt_printf, cfm$(format), args
    ELSE
        invoke crt_printf, cfm$(format)
    ENDIF
    EXITM <>
ENDM

;==============================================================================

snprintf MACRO pBuffer:REQ, count:REQ, format:REQ, args:VARARG
    IFNB <args>
        invoke crt__snprintf, pBuffer, count, cfm$(format), args
    ELSE
        invoke crt__snprintf, pBuffer, count, cfm$(format)
    ENDIF
    mov edx, pBuffer
    ;;---------------------------------------------------
    ;; Add a null terminator after the last byte stored.
    ;; A negative return value means the output was
    ;; truncated to fit the buffer. Otherwise the return
    ;; value is the number of bytes stored.
    ;;---------------------------------------------------
    .IF eax & 80000000h
        mov BYTE PTR [edx+count], 0
    .ELSE
        mov BYTE PTR [edx+eax], 0
    .ENDIF
    EXITM <eax>
ENDM

;==============================================================================
    .data
        r8    REAL8 ?
        buff1 db    10  dup(0)
        buff2 db    20  dup(0)
        str1  db    "my other brother darryl",0
    .code
;==============================================================================
start:
;==============================================================================

    mov eax, snprintf(OFFSET buff1, SIZEOF buff1-1, "%d", 123456789)
    printf("%d\t|%s|\n",eax,OFFSET buff1)
    mov eax, snprintf(OFFSET buff1, SIZEOF buff1-1, "%Xh", 55AA55AAh)
    printf("%d\t|%s|\n",eax,OFFSET buff1)
    fldpi
    fstp r8
    mov eax, snprintf(OFFSET buff1, SIZEOF buff1-1, "%f", r8)
    printf("%d\t|%s|\n",eax,OFFSET buff1)
    mov eax, snprintf(OFFSET buff1, SIZEOF buff1-1, "%.15f", r8)
    printf("%d\t|%s|\n",eax,OFFSET buff1)
    mov eax, snprintf(OFFSET buff2, SIZEOF buff2-1, "%.15f", r8)
    printf("%d\t|%s|\n",eax,OFFSET buff2)
    mov eax, snprintf(OFFSET buff2, SIZEOF buff2-1, "%I64Xh", r8)
    printf("%d\t|%s|\n",eax,OFFSET buff2)
    mov eax, snprintf(OFFSET buff2, SIZEOF buff2-1, "%s", OFFSET str1)
    printf("%d\t|%s|\n\n",eax,OFFSET buff2)

    inkey "Press any key to exit..."
    exit
;==============================================================================
end start


9       |123456789|
9       |55AA55AAh|
8       |3.141593|
-1      |3.1415926|
17      |3.141592653589793|
17      |400921FB54442D18h|
-1      |my other brother da|


MSDN: _snprintf, _snwprintf

eschew obfuscation

dedndave

sounds like a case against wsprintf
what kills you with buffer overflow is all the string expansions
it gives a malicious attacker an "in"

ToutEnMasm

#17
I have retook the sample of michaelW.
This one generate an "invalid Argument" because the gen_buffer is too small and show a complet soluce using the secured functions of the crt.
See windows.inc subforum for include files
Quote
.NOLIST
.386
.model flat,stdcall
option casemap:none 
extern c _FPinit:dword   
   include translate.inc
   include windows.sdk
   include \vc\stdio.sdk
   include \vc\stdlib.sdk
   ;include macros.inc
includelib  libcmt.lib
includelib  kernel32.lib
includelib  user32.lib
Display PROTO
.const
invalid_parameter PROTO C :DWORD,  :DWORD,  :DWORD,  :DWORD,  :DWORD

.data   
   gen_buffer db 200 dup (0)
   result_buffer db 30 dup (0)
   r8 REAL8 0.0
   decimal_form    db "decimal form : %d",13,10,0
   hexadecimal_form db "hexadecimal form : %Xh",13,10,0
   float_form db "float standard form : %f",13,10,0
   float1_form db "float digit form : %.15f",13,10,0
   float2_form db "float hexa form : %I64Xh",13,10,0
   string_form db "%s",13,10,0   
   result_form db "rest char in buffer : %d",0
   str1  db    "Don't forget to made a count of what stay in the buffer ",0
   invalid db "invalid parameter",0     
.code

;################################################################
invalid_parameter PROC C expression:DWORD,function,file,line,pReserved
         Local  retour:DWORD
         mov retour,1
   ;all parameters expression:DWORD,function,file,line,pReserved are NULL   
   invoke MessageBox,NULL,ADDR invalid,NULL,MB_OK
Findeinvalid_parameter:
         mov eax,retour
         ret
invalid_parameter endp

;################################################################



;################################################################
Display PROC uses ebx
   Local bufsize:DWORD
   Local  retour:DWORD
   ;----------------------------------
   mov bufsize,sizeof gen_buffer -1 ;keep place for zero terminating
   mov ebx,offset gen_buffer
   ;----------------------------------
   ;invoke sprintf_s,addr buffer,sizeof buffer,addr format,double
   ;return number of byte written or -1
   invoke sprintf_s,ebx,bufsize,addr decimal_form,123456789
   call verify_and_count
   invoke sprintf_s,ebx,bufsize,addr hexadecimal_form,55AA55AAh   
   call verify_and_count
       fldpi    ;load PI
       fstp r8   
   invoke sprintf_s,ebx,bufsize,addr float_form,r8
   call verify_and_count
   invoke sprintf_s,ebx,bufsize,addr float1_form,r8
   call verify_and_count   
   invoke sprintf_s,ebx,bufsize,addr float2_form,r8
   call verify_and_count      
   invoke sprintf_s,ebx,bufsize,addr string_form,addr str1   
   call verify_and_count
   invoke sprintf_s,addr result_buffer,sizeof result_buffer,addr result_form,bufsize
         
   invoke MessageBox,NULL,addr gen_buffer,addr result_buffer,MB_OK
FindeDisplay:
         mov eax,0
         ret
verify_and_count:
   .if bufsize > eax    && eax != -1   ;= no enought size
      sub bufsize,eax         
   .else
      pop eax   ;unstack the adress call,can be omitted
      jmp FindeDisplay
   .endif
   add ebx,eax
retn
Display endp

;################################################################
   
WinMain proc hInst:DWORD,hPrevInst:DWORD,lpCmdLine:DWORD,nShowCmd:DWORD
   invoke _set_invalid_parameter_handler,invalid_parameter
   invoke Display
   mov eax,0
   ret
WinMain endp

end