Jump to content

Can DLLStructSetData() overrun a buffer?


c.haslam
 Share

Recommended Posts

Here is an example:

Local $tstruct = DllStructCreate('char[20]')
DllStructSetData($tstruct,1,'12345678901234567890')
ConsoleWrite('@error='&@error&@CRLF& _
    'DllStructGetData($tstruct,1)='&DllStructGetData($tstruct,1)&@CRLF& _
    'DllStructGetSize($tstruct)='&DllStructGetSize($tstruct)&@CRLF)

This writes to the Console:

@error=0
DllStructGetData($tstruct,1)=12345678901234567890
DllStructGetSize($tstruct)=20

So it looks to me like the null character at the end of the string is being written just beyond the buffer without @error being set.

Thoughts?

 

Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Link to comment
Share on other sites

What makes you think that the "string" in struct is appended a Null byte?  It isn't technically a "string", it's an array of chars and so there is no need to add any kind of termination because the available size is bounded by it's own declaration.
Making the string written there any longer doesn't make a difference: only the first 20 chars are stored (after being converted to ANSI) and retrieved.

Local $tstruct = DllStructCreate('char[10]')
DllStructSetData($tstruct,1,"I᾽m a kingsize string and will overflow this poor buffer!")
ConsoleWrite('@error='&@error&@CRLF& _
    'DllStructGetData($tstruct,1)='&DllStructGetData($tstruct,1)&@CRLF& _
    'DllStructGetSize($tstruct)='&DllStructGetSize($tstruct)&@CRLF)

You'll find that the apostrophe becomes a question mark once displayed (even before being stored). That's because I cheated and used the Unicode character ᾽ (U+1FBD = Coronis, an ancient greek character). Since it most probably has no equivalent in your ANSI codepage (well, unless your language setting is "ancient Greek", unlikely to exist) it's converted to ? before storage. That was to illustrate how AutoIt Unicode strings get converted to ANSI char type.

Of course if the struct used wchar instead of char this character would have been stored and retrieved verbatim, even if this particular codepoint can't show correctly in the console (use MsgBox to see that Unicode is retained).

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

as you can see no overflow 

for @error the doc handle  no  such case !!!

Local $tstruct = DllStructCreate('char[20];char[1]')
DllStructSetData($tstruct,2,'x')

DllStructSetData($tstruct,1,'1234567890123456789012')
ConsoleWrite('@error='&@error&@CRLF& _
    'DllStructGetData($tstruct,1)='&DllStructGetData($tstruct,1)&@CRLF& _
    'DllStructGetSize($tstruct)='&DllStructGetSize($tstruct)&@CRLF)

Local $sget = DllStructGetData($tstruct,2)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $sget = ' & $sget & @CRLF & '>Error code: ' & @error & '    Extended code: ' & @extended & ' (0x' & Hex(@extended) & ')' & @CRLF) ;### Debug Console

 

Edited by jpm
Link to comment
Share on other sites

Thank you for the comforting words!

Here's what led me to think that a terminating null character might be stored:

  • A .jpg from a camera has several dateTime properties. These property items are ASCII and 20 bytes long, but the dateTime value is 19 characters, e.g. 2018:04:30 12:42:34 . So it looked to me as though the writers of the Exif standard might have needed to allow for storing a null character.
  • I have written a script that is a photo viewer/editor with the ability to annotate pictures in Rich Text Format. Its Deskew feature (which is thanks to UEZ) was added several months ago. It uses GDIPlus. It works AOK.
  • But because it de-skews using GDI clones, images (and images saved as jpegs) lose their properties when de-skewed. Recently I have been working on copying Exif data from the image of the picture to the clone. Getting property items is crashing AutoIt. Without getting property items the script never crashes. The only place where the script codes DLLStruct* functions is for Exif properties.
  • The UDFs that handle the properties involve structs. (They are here.) Getting a property item reads a property item stored by GDI as a struct and a sub-struct, and returns a 1-d array, its value element being a 1-d array. Setting a property does the inverse.

I am still looking for why AutoIt crashes.

Edited by c.haslam
Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Link to comment
Share on other sites

  • 3 weeks later...

If You use a pointer to define a DllStruct You can Sometimes create situations that crash autoit when accessing memory that isn't yours inadvertently..

;Local $tPtr = Dllstructcreate("ptr", 0) ;AutoIt catches this..
;Local $tPtr = Dllstructcreate("ptr",0xFFFF0000) ;Crashes x32 & x64
;Local $tPtr = Dllstructcreate("ptr",0xFFFFFFFF00000000) ;Crashes x64
Local $tPtr = Dllstructcreate("ptr", -1);Crashes All
Local $tTest = Dllstructcreate("int;long;ptr;", dllStructGetPtr($tPtr, 1))
DllStructSetData($tTest, 1, 1)
DllStructSetData($tTest, 2, 1)
Consolewrite(Dllstructgetdata($tTest, 1) & ":" &Dllstructgetdata($tTest, 2) & ":" &Dllstructgetdata($tTest, 3) & ":" & dllStructGetPtr($tTest) & @crlf)

 

Link to comment
Share on other sites

This isn't overflowing. In fact this is a rare instance where AutoIt allows use of a pointer. Of course this is a big risk but is necessary in corner cases.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

You Could use _WinAPI_IsBadCodePtr() to get some insight into this particular issue

Just be aware it should only be used in a debug situation as:

It is an obsolete function, Can cause crashes elsewhere,  Slows your function down

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Run_Tidy=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <WinAPIMem.au3>

;;_WinAPI_IsBadCodePtr
;;Important  This function is obsolete and should not be used.
;;Despite its name, it does not guarantee that the pointer is valid or that the memory pointed to is safe to use. 
;;For more information, see Remarks https://msdn.microsoft.com/en-us/library/windows/desktop/aa366713(v=vs.85).aspx
;;
Local $tTest
Local $tPtr0 = DllStructCreate("ptr", 0) ;AutoIt catches this..
Local $tPtr1 = DllStructCreate("ptr", 0xFFFF0000) ;Crashes x32 & x64
Local $tPtr2 = DllStructCreate("ptr", 0xFFFFFFFF00000000) ;Crashes x64
Local $tPtr3 = DllStructCreate("ptr;", -1) ;Crashes All

If _WinAPI_IsBadCodePtr(DllStructGetPtr($tPtr0, 1)) Then
    If MsgBox($MB_YESNO, "Error Ptr0", "Bad Pointer Skip It?") = $IDNO Then
        $tTest = DllStructCreate("int;long;ptr;", DllStructGetPtr($tPtr0, 1))
        DllStructSetData($tTest, 1, 1)
        DllStructSetData($tTest, 2, 1)
        ConsoleWrite(DllStructGetData($tTest, 1) & ":" & DllStructGetData($tTest, 2) & ":" & DllStructGetData($tTest, 3) & ":" & DllStructGetPtr($tTest) & @CRLF)
    EndIf
EndIf

If _WinAPI_IsBadCodePtr(DllStructGetPtr($tPtr1, 1)) Then
    If MsgBox($MB_YESNO, "Error Ptr1", "Bad Pointer Skip It?") = $IDNO Then
        $tTest = DllStructCreate("int;long;ptr;", DllStructGetPtr($tPtr1, 1))
        DllStructSetData($tTest, 1, 1)
        DllStructSetData($tTest, 2, 1)
        ConsoleWrite(DllStructGetData($tTest, 1) & ":" & DllStructGetData($tTest, 2) & ":" & DllStructGetData($tTest, 3) & ":" & DllStructGetPtr($tTest) & @CRLF)
    EndIf
EndIf

If _WinAPI_IsBadCodePtr(DllStructGetPtr($tPtr2, 1)) Then
    If MsgBox($MB_YESNO, "Error Ptr2", "Bad Pointer Skip It?") = $IDNO Then
        $tTest = DllStructCreate("int;long;ptr;", DllStructGetPtr($tPtr2, 1))
        DllStructSetData($tTest, 1, 1)
        DllStructSetData($tTest, 2, 1)
        ConsoleWrite(DllStructGetData($tTest, 1) & ":" & DllStructGetData($tTest, 2) & ":" & DllStructGetData($tTest, 3) & ":" & DllStructGetPtr($tTest) & @CRLF)
    EndIf
EndIf

If _WinAPI_IsBadCodePtr(DllStructGetPtr($tPtr3, 1)) Then
    If MsgBox($MB_YESNO, "Error Ptr3", "Bad Pointer Skip It?") = $IDNO Then
        $tTest = DllStructCreate("int;long;ptr;", DllStructGetPtr($tPtr3, 1))
        DllStructSetData($tTest, 1, 1)
        DllStructSetData($tTest, 2, 1)
        ConsoleWrite(DllStructGetData($tTest, 1) & ":" & DllStructGetData($tTest, 2) & ":" & DllStructGetData($tTest, 3) & ":" & DllStructGetPtr($tTest) & @CRLF)
    EndIf
EndIf

 

Link to comment
Share on other sites

Thank you for this.

It is possible that I have found what is/was causing AutoIt to crash. It seems that a function in GDIPlus.au3, __GDIPlus_ImageGetPropertyItemSize(), is not returning an error code if a property item does not exist in an image, causing the properties to be written to unallocated memory. The code in the standard UDF is:

Func __GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID)
    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetPropertyItemSize", "handle", $hImage, "uint", $iPropID, "uint*", 0)
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], -1)
    Return $aResult[3]
EndFunc   ;==>__GDIPlus_ImageGetPropertyItemSize

My revised code is:

Func c__GDIPlus_ImageGetPropertyItemSize($hImage, $iPropID)
    Local $aResult = DllCall($__g_hGDIPDll, "int", "GdipGetPropertyItemSize", "handle", $hImage, "uint", $iPropID, "uint*", 0)
    If $aResult[3]=-1 Then
        Return SetError(10,$GDIP_ERRPROPERTYNOTFOUND,-1)    ; GdipGetPropertyItemSize doesn't set it!
    EndIf
    If @error Then Return SetError(@error, @extended, -1)
    If $aResult[0] Then Return SetError(10, $aResult[0], -1)
    Return $aResult[3]
EndFunc   ;==>__GDIPlus_ImageGetPropertyItemSize

My suggested change is made here

Edited by c.haslam
Spoiler

CDebug Dumps values of variables including arrays and DLL structs, to a GUI, to the Console, and to the Clipboard

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...