The MASM Forum

General => The Campus => Topic started by: Hesp087 on June 10, 2012, 03:03:57 AM

Title: possible buffer overflow in printf
Post by: Hesp087 on June 10, 2012, 03:03:57 AM
Hi all, I'm new to this forum and sorry for my bad English.

In this simple code:

include masm32rt.inc

.data?

SysTime SYSTEMTIME <?>

.data

.code
start:
invoke GetSystemTime, addr SysTime
printf("%d\n", SysTime.wYear);
inkey "Press a key to continue ..."
invoke ExitProcess, NULL
end start


An error in printf, I'm pretty sure it's because they do not get the correct type for SysTime.wYear (word).
I tried various combinations (%d,%i, etc ...), but not how to fix it. Would be grateful if anyone of you tell me how to fix the runtime error.
Title: Re: possible buffer overflow in printf
Post by: qWord on June 10, 2012, 03:21:28 AM
the problem is probably, that wYear is a WORD, which cause the invoke macro to produce bad code -> move the value to a 32Bit GPR and then pass it to the macro:

movzx edx,SysTime.wYear
printf(...,edx)
Title: Re: possible buffer overflow in printf
Post by: jj2007 on June 10, 2012, 03:53:40 AM
What exactly is your problem? This code assembles and runs fine. Below the printf macro.

include \masm32\include\masm32rt.inc
.data
SysTime SYSTEMTIME <>
.code
start:
mov ebx, esp
invoke GetSystemTime, addr SysTime
printf("%d\n\n", SysTime.wYear);
sub ebx, esp
inkey str$(ebx), 9, "StackDiff"
exit
end start


\masm32\macros\macros.asm
  ; --------------------------------------------------------------
  ; This macro is written to behave as closely as possible to the
  ; C runtime function "printf". The lack of return value is
  ; to allow the closest method to writing C code. It supports
  ; both ASCII and UNICODE and uses the C runtime function
  ; "wprintf" to provide the UNICODE support.
  ;
  ; printf("%d\t%d\t%Xh\n", 123, 456, 1024);
  ;
  ; The return value is available in the EAX register if required.
  ; The original ASCII version was written by Michael Webster.
  ; --------------------------------------------------------------

    printf MACRO format:REQ, args:VARARG
      IFNDEF __UNICODE__
        IFNB <args>
          fn crt_printf, cfm$(format), args
        ELSE
          fn crt_printf, cfm$(format)
        ENDIF
        EXITM <>
      ELSE
        IFNB <args>
          fn crt_wprintf, cfm$(format), args
        ELSE
          fn crt_wprintf, cfm$(format)
        ENDIF
        EXITM <>
      ENDIF
    ENDM
Title: Re: possible buffer overflow in printf
Post by: qWord on June 10, 2012, 04:06:55 AM
(http://image-upload.de/image/p5SZLn/dea021d156.png)
Title: Re: possible buffer overflow in printf
Post by: jj2007 on June 10, 2012, 04:15:06 AM
OK. Seems the macro needs an update ::)

I didn't see a problem because my default assembler is JWasm. The code crashes with ML 6.14...8.0 but assembles fine with ML 9.0 and JWasm ().

0040100D     ³.  66:6A 00            push word 0  <<<<<<<<<########
ThePoint     ³.  66:FF35 00204000    push word ptr [402000]               ; Ú<%d> = 2012.
00401017     ³.  68 10204000         push offset 00402010                 ; ³format = "%d
0040101C     ³.  FF15 C0204000       call near [<&msvcrt.printf>]         ; ÀMSVCRT.printf
Title: Re: possible buffer overflow in printf
Post by: qWord on June 10, 2012, 04:20:30 AM
It is a"known" bug. BYTE-parameters also won't work correct.
Title: Re: possible buffer overflow in printf
Post by: jj2007 on June 10, 2012, 04:32:57 AM
It could be solved in the macro. For good reasons, Str$() is not affected :biggrin:

include \masm32\MasmBasic\MasmBasic.inc   ; download (http://masm32.com/board/index.php?topic=94.0)
.data?
SysTime SYSTEMTIME <>
   Init
   invoke GetSystemTime, addr SysTime
   Inkey Str$("SysYear=%i", SysTime.wYear)
   Exit
end start
Title: Re: possible buffer overflow in printf
Post by: Hesp087 on June 10, 2012, 04:54:38 AM
Quote from: qWord on June 10, 2012, 03:21:28 AM
the problem is probably, that wYear is a WORD, which cause the invoke macro to produce bad code -> move the value to a 32Bit GPR and then pass it to the macro:

movzx edx,SysTime.wYear
printf(...,edx)


You resolved my problem:

include masm32rt.inc

.data?

SysTime SYSTEMTIME <>

.data

.code
start:
invoke GetSystemTime, addr SysTime
movzx edx, SysTime.wYear
printf("%d\n", edx);
inkey "Press a key to continue ..."
invoke ExitProcess, NULL
end start


thank you all for the prompt response and solution.  :biggrin:
Title: Re: possible buffer overflow in printf
Post by: jj2007 on June 10, 2012, 05:20:32 AM
If you like the printf macro, here is a solution:

printf MACRO format:REQ, args:VARARG
      IFNDEF __UNICODE__
        IFNB <args>
if type args eq WORD
movzx eax, args
fn crt_printf, cfm$(format), eax
elseif type args eq SWORD
movsx eax, args
fn crt_printf, cfm$(format), eax
else
fn crt_printf, cfm$(format), args
endif
        ELSE
          fn crt_printf, cfm$(format)
        ENDIF
        EXITM <>
      ELSE
        IFNB <args>
          fn crt_wprintf, cfm$(format), args
        ELSE
          fn crt_wprintf, cfm$(format)
        ENDIF
        EXITM <>
      ENDIF
ENDM


(I haven't touched the lower Unicode part)
Title: Re: possible buffer overflow in printf
Post by: MichaelW on June 10, 2012, 10:50:14 AM
Why not also test for a BYTE arg?
Title: Re: possible buffer overflow in printf
Post by: jj2007 on June 10, 2012, 03:29:18 PM
Quote from: MichaelW on June 10, 2012, 10:50:14 AM
Why not also test for a BYTE arg?

Maybe because MasmBasic cares already for lazy coders?  :lol:

include \masm32\include\masm32rt.inc
printf MACRO format:REQ, args:VARARG
      IFNDEF __UNICODE__
        IFNB <args>
if type args eq WORD or type args eq BYTE
movzx eax, args
fn crt_printf, cfm$(format), eax
elseif type args eq SWORD or type args eq SBYTE
movsx eax, args
fn crt_printf, cfm$(format), eax
else
fn crt_printf, cfm$(format), args
endif
        ELSE
          fn crt_printf, cfm$(format)
        ENDIF
        EXITM <>
      ELSE
        IFNB <args>
          fn crt_wprintf, cfm$(format), args
        ELSE
          fn crt_wprintf, cfm$(format)
        ENDIF
        EXITM <>
      ENDIF
ENDM
.data
TheWord dw 12345
TheByte byte 222
TheSByte sbyte 222
.code
start:
printf("%i\tTheWord\n", TheWord)
printf("%i\tTheByte\n", TheByte)
printf("%i\tTheSByte\n", TheSByte)
inkey "bye"
exit
end start
Title: Re: possible buffer overflow in printf
Post by: x64Core on June 10, 2012, 05:14:49 PM
I was sure that it was MasmBasic by jochen  :biggrin:

http://foro.elhacker.net/asm/supuesto_buffer_overflow_con_printf_en_masm32-t363909.0.html
Title: Re: possible buffer overflow in printf
Post by: jj2007 on June 10, 2012, 05:49:39 PM
Quote from: RHL on June 10, 2012, 05:14:49 PM
I was sure that it was MasmBasic by jochen  :biggrin:

Not really - I just modified the printf macro from the standard Masm32 lib.

In contrast to C printf, MasmBasic separates printing from the string format, which gives more flexibility, i.e. you can choose whether to print directly with Print Str$(), or assign an intermediate string with Let:

include \masm32\MasmBasic\MasmBasic.inc   ; download (http://masm32.com/board/index.php?topic=94.0)
   Init
   mov ah, 111
   Let esi=Str$("This is a byte: %i\n", ah)
   Print esi
   mov cl, 222
   Print Str$("This is a byte: %i", cl), " - ", Hex$(cl), " as hex value", CrLf$
   fldpi
   Print Str$("... and this is PI:\n%Hf\n", ST(0))
   Print "3.1415926535897932384626 is the expected value", CrLf$
   Inkey "bye"
   Exit
end start

It also can handle more input formats, e.g. xmm regs, FPU regs, REAL4... REAL10 etc.
You can even mix the input formats:
   mov eax, 1000
   movd xmm0, eax
   fldpi
   Print Str$("xmm0*ST(0)=%f\n\n", xmm0*ST(0))


Output:
This is a byte: 111
This is a byte: 222 - DE as hex value
... and this is PI:
3.1415926535897932
3.1415926535897932384626 is the expected value
xmm0*ST(0)=3141.593


Under the hood it's the same "if type eq REALX" technique used above for the modified printf.