News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

possible buffer overflow in printf

Started by Hesp087, June 10, 2012, 03:03:57 AM

Previous topic - Next topic

Hesp087

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.

qWord

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)
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

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

qWord

MREAL macros - when you need floating point arithmetic while assembling!

jj2007

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

qWord

It is a"known" bug. BYTE-parameters also won't work correct.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

It could be solved in the macro. For good reasons, Str$() is not affected :biggrin:

include \masm32\MasmBasic\MasmBasic.inc   ; download
.data?
SysTime SYSTEMTIME <>
   Init
   invoke GetSystemTime, addr SysTime
   Inkey Str$("SysYear=%i", SysTime.wYear)
   Exit
end start

Hesp087

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:

jj2007

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)

MichaelW

Well Microsoft, here's another nice mess you've gotten us into.

jj2007

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

x64Core

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

jj2007

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
   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.