Help! I've been using wsprintf() to format strings. That is, until I read this about it on MSDN:
Quote
Security Considerations
Using this function incorrectly can compromise the security of your application. The string returned in lpOutput is not guaranteed to be NULL-terminated. Also, avoid the use of the %s format, which can lead to a buffer overrun. This can lead to a denial of service if it results in an access violation, or an attacker may inject executable code. Consider using one of the following alternatives: StringCbPrintf, StringCbPrintfEx, StringCbVPrintf, StringCbVPrintfEx, StringCchPrintf, StringCchPrintfEx, StringCchVPrintf, or StringCchVPrintfEx.
Hey, you don't have to warn me twice!
So I checked into StringCbVPrintf(), which looks nice, except that it doesn't seem to be supported by MASM32, and besides, MSDN says the "minimum supported client" is Windows XP with SP2 (I'm on W2K here), using Strsafe.h, also evidently missing from this package.
So what am I supposed to use here? I looked through the MASM32 lib folder, hoping to find a printf() replacement, but no luck. I really don't want to write my own function here.
Also, when using wsprintf(), it seems it doesn't expand tabs (\t), which I would have expected it to do. (Although MSDN says nothing about any formatting characters other than field identifiers, like %d, etc.)
many of the crt functions have been replaced by "secure" versions
all these buffer overflows are supposed to be fixed
and, i am sure they are slower and bigger
not sure how to use them - no C for me :bdg
i do use kbhit and getch for console mode stuff :P
What do you mean, "crt functions"? This is a generalized function for placing formatted text into a buffer. Similar to the standard C library functions, (x)printf.
How do you format text that you want to output?
C RunTime libraries
not cathode ray tube :P
typically called MSVCRT - maybe followed with version digits
how do i format strings ?
i usually write my own code
that printf stuff looks like some foriegn language - one that i didn't study :P
Well, despite my handle, I find the C conventions for formatting text to be quite useful, and easy to use:
- %(something) defines output fields of various types
- \(something) defines various control characters (newline, tab, etc.)
I wrote a 16-bit version of printf() that was really handy for debugging, but I really don't want to do that here.
Are there any routines in the MASM32 libraries that would help here?
not that i am aware of
however, it shouldn't be too difficult to create an import library for the newer wsprintf
they preceed a lot of the function names with "s" meaning "secure", i guess
here you go - try snprintf, snwprintf, vsnprintf, vsnwprintf, sprintf
there are a bunch of printf functions - have a look in msvcrt.inc
and - to get descriptions - google msdn
here is a list of function names in the msvcrt.lib that is included with masm32 v10r
There is a simple solution to buffer overruns, MEASURE the bufffer length yourself FIRST !!!!!!!!!!! :bg
mov blen, len(buffer)
.if blen > 256
print "Shock Horror, someone is trying out a buffer overrun exploit",13,10
ret
.else
; do whatcha wanna do !
.endif
Quote from: hutch-- on October 24, 2011, 04:14:59 AM
There is a simple solution to buffer overruns, MEASURE the bufffer length yourself FIRST !!!!!!!!!!! :bg
Right. Or use MasmBasic, it's safe :bg:
include \masm32\MasmBasic\MasmBasic.inc ; download (http://www.masm32.com/board/index.php?topic=12460)
Init
Print cStyle$("Your puter\nis a stupid\nbeast\na\tb\tc\n1\t2\t3\n") ; MasmBasic
print cStyle$("Your puter\nis a stupid\nbeast\na\tb\tc\n1\t2\t3\n") ; normal Masm32 print
Inkey Str$("\nIt has run %3f hours since the last boot, give it a break!!!!", Timer/3600000)
Exit
end start
Your puter
is a stupid
beast
a b c
1 2 3
Jokes apart: Hutch is right, check yourself! These "safe" new M$ functions are there to help stupid coders and slow down the system, so that the end user is eventually forced to buy a new Win8 64-bit box. If MB is not for you, then use the good old crt functions and make sure the input is less or equal bufferlen. By the way: standard Masm32 print can be used with the cStyle macro, see above, that is included in MB courtesy of qWord but also available here (http://www.masm32.com/board/index.php?topic=12460.msg96506#msg96506)
Quote from: NoCforMe on October 24, 2011, 02:57:57 AM
Also, when using wsprintf(), it seems it doesn't expand tabs (\t), which I would have expected it to do.
The expansion of
Escape Sequences (http://msdn.microsoft.com/en-us/library/h21280bw(v=VS.80).aspx) is a compiler function. You can use the MASM32 cfm$ macro to specify the format string and it will take care of expanding the escape sequences.
;==============================================================================
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
;==============================================================================
.data
.code
;==============================================================================
start:
;==============================================================================
printf("%d\t%d\t%Xh\n", 123, 456, 1024)
inkey "Press any key to exit..."
exit
;==============================================================================
end start
More powerfull is swprintf_s sprintf_s
Quote
invoke sprintf_s,addr buffer,sizeof buffer,addr format,double
who can work with floating point number
Quote from: MichaelW on October 24, 2011, 07:20:21 AM
You can use the MASM32 cfm$ macro to specify the format string and it will take care of expanding the escape sequences.
Thanks, Michael, I had forgotten that one.
Quote from: MichaelW on December 12, 2007, 06:50:42 PM
And cat$(cfm$("\nTest 4:"),str$(4)) will cause cat$ to write past the end of the data allocated by cfm$.
To keep in mind.
When you use the "cat$" macro you are supposed to specify the buffer to join it all onto, as usual the buffer should be large enough. It can be reassigned back to the same buffer pointer but if you use a fixed length string as the first member then add more to it it will go BANG.
mov pbuffer, cat$(pbuffer,all your other strings .... )
Quote
So I checked into StringCbVPrintf(), which looks nice, except that it doesn't seem to be supported by MASM32, and besides, MSDN says the "minimum supported client" is Windows XP with SP2 (I'm on W2K here), using Strsafe.h, also evidently missing from this package.
This is part of the strsafe.lib who have a few proc in his header's file (c++ allow it).Only old version of strsafe.lib have the full code in them (\WinDDK\6001.18001).
The sprintf_s function is enough secured.You pass the buffer adress and his size.
No need of macros to secure it more (useless).
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 (http://msdn.microsoft.com/en-us/library/2ts7cx93(v=vs.71).aspx)
sounds like a case against wsprintf
what kills you with buffer overflow is all the string expansions
it gives a malicious attacker an "in"
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