Jump to content

Recommended Posts

Posted

Brand new to AutoIt, fairly new to the Win32 API, and very experienced with linux C++.

I'm trying to use DllCall's to write a binary file.  As a proof of concept, I'm trying the below code.  As it's written, $buffer isn't initialized, so I understand would write garbage to the file.

The script successfully creates the file, but it remains 0 bytes.  WriteFile is returning 0.  Curiously, _GetLastError() is printing "The operation completed successfully."

I originally tried WriteFile with 0 for lpNumberOfBytesWritten, but in this version I do give it a variable to write to, but that had no effect.  I also tried "'dword*', $bytesWritten, _" for that line.  Giving null here seems to indicate for it to be an asynchronous write, and I'm not sure if going that way then immediately closing causes the OS to wait for the write or to preempt it.  That's the only reason (and for debugging purposes) that I'm not using 0 there.

 

#include <MsgBoxConstants.au3>



Func _GetLastErrorMessage($DisplayMsgBox="")
    Local $ret,$s
    Local $p    = DllStructCreate("char[4096]")
    Local Const $FORMAT_MESSAGE_FROM_SYSTEM     = 0x00001000

    If @error Then Return ""

    $ret    = DllCall("Kernel32.dll","int","GetLastError")

    $ret    = DllCall("kernel32.dll","int","FormatMessage", _
                        "int",$FORMAT_MESSAGE_FROM_SYSTEM, _
                        "ptr",0, _
                        "int",$ret[0], _
                        "int",0, _
                        "ptr",DllStructGetPtr($p), _
                        "int",4096, _
                        "ptr",0)
    $s  = DllStructGetData($p,1)
    ;DllStructDelete($p)
    If $DisplayMsgBox <> "" Then MsgBox(0,"_GetLastErrorMessage",$DisplayMsgBox & @CRLF & $s)
    return $s
 EndFunc



$buffer = DllCall('kernel32.dll', _
   'ptr', 'VirtualAlloc', _
   'ptr', 0, _ ; lpAddress = NULL (system determines where to allocate memory)
   'ulong_ptr', 386584, _ ; dwSize = 386,584 bytes
   'dword', 12288, _ ; flAllocationType = 12288 (0x3000) = MEM_COMMIT | MEM_RESERVE
   'dword', 0)

$fileHandle = DllCall('Kernel32.dll', _
   'HANDLE', 'CreateFile', _
   'str', 'helloWorld.out', _ ; lpFileName
   'DWORD', 0x40000000, _ ; dwDesiredAccess = GENERIC_WRITE
   'DWORD', 0, _ ; dwShareMode = 0 (file cannot be opened again until handle is closed)
   'DWORD', 0, _ ; lpSecurityAttributes = NULL (handle cannot be inherited by child processes)
   'DWORD', 2, _ ; dwCreationDisposition = CREATE_ALWAYS (create new file always, if alrady exists, overwrite)
   'DWORD', 128, _ ; dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL (no attributes set)
   'HANDLE', 0) ; hTemplateFile = NULL (template could supply attributes and extended attributes for file

If $fileHandle = -1 Then
   MsgBox(0, "fileHandle", $fileHandle & @CRLF & "@ERROR: " & @ERROR & @CRLF & "@EXTENDED: " & @EXTENDED)
   Exit
EndIf

$bytesWritten = 0
$writeFileRet = DllCall('Kernel32.dll', _
   'int', 'WriteFile', _
   'HANDLE', $fileHandle, _ ; hFile
   'PTR', $buffer, _ ; LPCVOID lpBuffer
   'DWORD', 386584, _ ; nNumberOfBytesToWrite
   'LPDWORD', $bytesWritten, _ ; LPDWORD lpNumberOfBytesWritten
   'LPOVERLAPPED', 0) ; LPOVERLAPPED lpOverlapped

If $writeFileRet = 0 Then
   MsgBox(0,"writeFileRet", "writeFileRet: " & $writeFileRet & @CRLF & "bytesWritten: " & $bytesWritten & @CRLF & "@ERROR: " & @ERROR & @CRLF & "@EXTENDED: " & @EXTENDED)
   _GetLastErrorMessage("writeFileRet")
   Exit
EndIf

$closeHandleRet = DllCall('Kernel32.dll', _
   'int', 'CloseHandle', _
   'HANDLE', $fileHandle)

If $closeHandleRet = 0 Then
   MsgBox(0,"closeFileRet", $closeFileRet & @CRLF & "@ERROR: " & @ERROR & @CRLF & "@EXTENDED: " & @EXTENDED)
   Exit
EndIf

 

Posted

Just found 2 things, that don't fix the issue, but might come up:

1. I found that having my MsgBox() before the _GetLastErrorMessage() (function found on these forums) was changing its output.  Using "@ERROR" must reset the value, or something like that.  Fixing this, I now get "Cannot create a file when that file already exists."

2. But even if I delete the .out file and re-run the script, and have my MsgBox() commented out, _GetLastErrorMessage() still prints: "The operation completed successfully."

Posted

I found here someone mentioned they always have the WinAPI WriteFile return 0, so maybe I have to ignore the return value.  But, the file still shouldn't be zero, so something's still wrong.

They also said they found the write length must be a multiple of 512 (a requirement of writing to a physical disk.)  I tried changing the buffer size and file write size to 387072, which is 756 * 512, but it's still leaving the file as 0 bytes, even with me deleting the file between script runs.

Posted

When i try it this way i get an error in allocation:

#include <MsgBoxConstants.au3>
Global $closeFileRet


Func _GetLastErrorMessage($DisplayMsgBox="")
    Local $ret,$s
    Local $p    = DllStructCreate("char[4096]")
    Local Const $FORMAT_MESSAGE_FROM_SYSTEM     = 0x00001000

    If @error Then Return ""

    $ret    = DllCall("Kernel32.dll","int","GetLastError")

    $ret    = DllCall("kernel32.dll","int","FormatMessage", _
                        "int",$FORMAT_MESSAGE_FROM_SYSTEM, _
                        "ptr",0, _
                        "int",$ret[0], _
                        "int",0, _
                        "ptr",DllStructGetPtr($p), _
                        "int",4096, _
                        "ptr",0)
    $s  = DllStructGetData($p,1)
    ;DllStructDelete($p)
    If $DisplayMsgBox <> "" Then MsgBox(0,"_GetLastErrorMessage",$DisplayMsgBox & @CRLF & $s)
    return $s
 EndFunc

$buffer = DllCall('kernel32.dll', _
   'ptr', 'VirtualAlloc', _
   'ptr', 0, _ ; lpAddress = NULL (system determines where to allocate memory)
   'ulong_ptr', 386584, _ ; dwSize = 386,584 bytes
   'dword', 12288, _ ; flAllocationType = 12288 (0x3000) = MEM_COMMIT | MEM_RESERVE
   'dword', 0)

_GetLastErrorMessage("VirtualAlloc")

$fileHandle = DllCall('Kernel32.dll', _
   'HANDLE', 'CreateFile', _
   'str', 'helloWorld.out', _ ; lpFileName
   'DWORD', 0x40000000, _ ; dwDesiredAccess = GENERIC_WRITE
   'DWORD', 0, _ ; dwShareMode = 0 (file cannot be opened again until handle is closed)
   'DWORD', 0, _ ; lpSecurityAttributes = NULL (handle cannot be inherited by child processes)
   'DWORD', 2, _ ; dwCreationDisposition = CREATE_ALWAYS (create new file always, if alrady exists, overwrite)
   'DWORD', 128, _ ; dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL (no attributes set)
   'HANDLE', 0) ; hTemplateFile = NULL (template could supply attributes and extended attributes for file

_GetLastErrorMessage("CreateFile")

$bytesWritten = 476856
$writeFileRet = DllCall('Kernel32.dll', _
   'int', 'WriteFile', _
   'HANDLE', $fileHandle, _ ; hFile
   'PTR', $buffer, _ ; LPCVOID lpBuffer
   'DWORD', 386584, _ ; nNumberOfBytesToWrite
   'LPDWORD', $bytesWritten, _ ; LPDWORD lpNumberOfBytesWritten
   'LPOVERLAPPED', 0) ; LPOVERLAPPED lpOverlapped

_GetLastErrorMessage("WriteFile")

$closeHandleRet = DllCall('Kernel32.dll', _
   'int', 'CloseHandle', _
   'HANDLE', $fileHandle)

 

Spoiler

Renamer - Rename files and folders, remove portions of text from the filename etc.

GPO Tool - Export/Import Group policy settings.

MirrorDir - Synchronize/Backup/Mirror Folders

BeatsPlayer - Music player.

Params Tool - Right click an exe to see it's parameters or execute them.

String Trigger - Triggers pasting text or applications or internet links on specific strings.

Inconspicuous - Hide files in plain sight, not fully encrypted.

Regedit Control - Registry browsing history, quickly jump into any saved key.

Time4Shutdown - Write the time for shutdown in minutes.

Power Profiles Tool - Set a profile as active, delete, duplicate, export and import.

Finished Task Shutdown - Shuts down pc when specified window/Wndl/process closes.

NetworkSpeedShutdown - Shuts down pc if download speed goes under "X" Kb/s.

IUIAutomation - Topic with framework and examples

Au3Record.exe

Posted

You're absolutely right.  I misunderstood the last value of VirtualAlloc.  Changing it to "64" makes it allocate properly.  (Also have changed dwSize from 386584 to 387072 in case it has to be in 512 byte multiples to write, and inserted an index to the first byte as I found in other code that works allocating this way, but that doesn't write to a file.)

Got rid of the error handling, and just print to the user each time how it went.

VirtualAlloc, CreateFile, and WriteFile print "The operation completed successfully."

CloseHandle prints "The handle is invalid."  Now I'm really confused.  The handle must be valid enough to have created the file, but not valid enough to write to it or close it?

I feel totally out of my comfort zone without strong typing.  Is $fileHandle properly getting the return value from CreateFile, which returns a "HANDLE"?  (Not sure if WIN32 HANDLE is just an integer of some sort, a struct, etc.)

#include <MsgBoxConstants.au3>


Func _GetLastErrorMessage($DisplayMsgBox="")
    Local $ret,$s
    Local $p    = DllStructCreate("char[4096]")
    Local Const $FORMAT_MESSAGE_FROM_SYSTEM     = 0x00001000

    If @error Then Return ""

    $ret    = DllCall("Kernel32.dll","int","GetLastError")

    $ret    = DllCall("kernel32.dll","int","FormatMessage", _
                        "int",$FORMAT_MESSAGE_FROM_SYSTEM, _
                        "ptr",0, _
                        "int",$ret[0], _
                        "int",0, _
                        "ptr",DllStructGetPtr($p), _
                        "int",4096, _
                        "ptr",0)
    $s  = DllStructGetData($p,1)
    ;DllStructDelete($p)
    If $DisplayMsgBox <> "" Then MsgBox(0,"_GetLastErrorMessage",$DisplayMsgBox & @CRLF & $s)
    return $s
 EndFunc



$buffer = DllCall('kernel32.dll', _
   'ptr', 'VirtualAlloc', _
   'ptr', 0, _ ; lpAddress = NULL (system determines where to allocate memory)
   'ulong_ptr', 387072, _ ; dwSize = 387,072 bytes
   'dword', 12288, _ ; flAllocationType = 12288 (0x3000) = MEM_COMMIT | MEM_RESERVE
   'dword', 64)[0]

_GetLastErrorMessage('VirtualAlloc')

$fileHandle = DllCall('Kernel32.dll', _
   'HANDLE', 'CreateFile', _
   'str', 'helloWorld.out', _ ; lpFileName
   'DWORD', 0x40000000, _ ; dwDesiredAccess = GENERIC_WRITE
   'DWORD', 0, _ ; dwShareMode = 0 (file cannot be opened again until handle is closed)
   'DWORD', 0, _ ; lpSecurityAttributes = NULL (handle cannot be inherited by child processes)
   'DWORD', 2, _ ; dwCreationDisposition = CREATE_ALWAYS (create new file always, if alrady exists, overwrite)
   'DWORD', 128, _ ; dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL (no attributes set)
   'HANDLE', 0) ; hTemplateFile = NULL (template could supply attributes and extended attributes for file

_GetLastErrorMessage('CreateFile')

$bytesWritten = 0
DllCall('Kernel32.dll', _
   'int', 'WriteFile', _
   'HANDLE', $fileHandle, _ ; hFile
   'PTR', $buffer, _ ; LPCVOID lpBuffer
   'DWORD', 387072, _ ; nNumberOfBytesToWrite
   'LPWDORD', $bytesWritten, _ ; LPDWORD lpNumberOfBytesWritten
   'LPOVERLAPPED', 0) ; LPOVERLAPPED lpOverlapped

_GetLastErrorMessage("WriteFile")

DllCall('Kernel32.dll', _
   'int', 'CloseHandle', _
   'HANDLE', $fileHandle)

_GetLastErrorMessage("CloseHandle")

 

Posted

Removing the WriteFile, and immediately calling CloseHandle after CreateFile still says "The handle is invalid".

I don't know if that means I'm not opening it right, or if I'm not closing it right, but it at least means WriteFile and the allocated memory aren't invalidating the handle.

Posted

Read more carefully about the DllCall command in the help file and especially about the return values. Note that DllCall returns an array.

Posted
5 hours ago, LarsJ said:

Read more carefully about the DllCall command in the help file and especially about the return values. Note that DllCall returns an array.

Thanks!  Got it working.  That got me in the right direction!  That was my big problem.

Also had to change the last arguments to WriteFile from

'LPWDORD', 0, _
   'LPOVERLAPPED', 0)

to

'dword*', 0, _
   'ptr', 0)

 

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
  • Recently Browsing   0 members

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