Author Topic: possible buffer overflow in printf  (Read 12762 times)

Hesp087

  • Guest
possible buffer overflow in printf
« 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:

Code: [Select]
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

  • Member
  • *****
  • Posts: 1475
  • The base type of a type is the type itself
    • SmplMath macros
Re: possible buffer overflow in printf
« Reply #1 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:

Code: [Select]
movzx edx,SysTime.wYear
printf(...,edx)
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: possible buffer overflow in printf
« Reply #2 on: June 10, 2012, 03:53:40 AM »
What exactly is your problem? This code assembles and runs fine. Below the printf macro.

Code: [Select]
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
Code: [Select]
  ; --------------------------------------------------------------
  ; 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

  • Member
  • *****
  • Posts: 1475
  • The base type of a type is the type itself
    • SmplMath macros
Re: possible buffer overflow in printf
« Reply #3 on: June 10, 2012, 04:06:55 AM »
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: possible buffer overflow in printf
« Reply #4 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 ().

Code: [Select]
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

  • Member
  • *****
  • Posts: 1475
  • The base type of a type is the type itself
    • SmplMath macros
Re: possible buffer overflow in printf
« Reply #5 on: June 10, 2012, 04:20:30 AM »
It is a"known" bug. BYTE-parameters also won't work correct.
MREAL macros - when you need floating point arithmetic while assembling!

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: possible buffer overflow in printf
« Reply #6 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
.data?
SysTime SYSTEMTIME <>
   Init
   invoke GetSystemTime, addr SysTime
   Inkey Str$("SysYear=%i", SysTime.wYear)
   Exit
end start

Hesp087

  • Guest
Re: possible buffer overflow in printf
« Reply #7 on: June 10, 2012, 04:54:38 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:

Code: [Select]
movzx edx,SysTime.wYear
printf(...,edx)

You resolved my problem:

Code: [Select]
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

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: possible buffer overflow in printf
« Reply #8 on: June 10, 2012, 05:20:32 AM »
If you like the printf macro, here is a solution:

Code: [Select]
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

  • Global Moderator
  • Member
  • *****
  • Posts: 1196
Re: possible buffer overflow in printf
« Reply #9 on: June 10, 2012, 10:50:14 AM »
Why not also test for a BYTE arg?
Well Microsoft, here’s another nice mess you’ve gotten us into.

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: possible buffer overflow in printf
« Reply #10 on: June 10, 2012, 03:29:18 PM »
Why not also test for a BYTE arg?

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

Code: [Select]
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

  • Member
  • **
  • Posts: 80
Re: possible buffer overflow in printf
« Reply #11 on: June 10, 2012, 05:14:49 PM »

jj2007

  • Member
  • *****
  • Posts: 13957
  • Assembly is fun ;-)
    • MasmBasic
Re: possible buffer overflow in printf
« Reply #12 on: June 10, 2012, 05:49:39 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.