Jump to content

Embed DLLs in script and call functions from memory (MemoryDll UDF)


Ward
 Share

Recommended Posts

  • 1 month later...

Hi Ward, Hope you don't mind this post but I did a little rewrite on your older version so it could be used with new dllcalladdress and make quite a bit smaller. Plus with new static vars, I was able to make it all into one function with no globals so easy to pop into any script. The 3 other short functions for public are just wrappers. And not that your newest version isnt awesome and very educational, I just don't use that many 64bit dlls. As always thanks for your incredible udfs and knowledge Ive learned from them.
 
MemoryDll_Short.au3
 

(Note: Opcodes removed for preview)

_Example()

Func _Example()

    Local $MD5Dll = 'Opcode removed for preview'

    Local $String = "The quick brown fox jumps over the lazy dog"
    Local $Digest = DllStructCreate("byte[16]")

    Local $hMD5 = MemoryDllOpen($MD5Dll)
    Local $iMD5 = MemoryDllGetFuncAddress($hMD5, 'md5')
    DllCallAddress("str", $iMD5, "str", $String, "uint", StringLen($String), "struct*", $Digest)
    MemoryDllClose($hMD5)

    ConsoleWrite('MD5 Hash = ' & DllStructGetData($Digest, 1) & @LF)

EndFunc   ;==>_Example


; ============================================================================================================================
;  Functions : MemoryDllOpen(), MemoryDllGetFuncAddress(), MemoryDllClose()
;  Purpose   : Embedding DLL In Scripts to Call Directly From Memory
;  Author    : Ward
;  Modified  : Brian J Christy (Beege) - Wrapper Functions
; ============================================================================================================================
Func MemoryDllOpen($DllBinary)
    Local $Call = __MemoryDllCore(0, $DllBinary)
    Return SetError(@error, 0, $Call)
EndFunc   ;==>MemoryDllOpen

Func MemoryDllGetFuncAddress($hModule, $sFuncName)
    Local $Call = __MemoryDllCore(1, $hModule, $sFuncName)
    Return SetError(@error, 0, $Call)
EndFunc   ;==>MemoryDllGetFuncAddress

Func MemoryDllClose($hModule)
    __MemoryDllCore(2, $hModule)
EndFunc   ;==>MemoryDllClose

Func __MemoryDllCore($iCall, ByRef $Mod_Bin, $sFuncName = 0)

    Local Static $_MDCodeBuffer, $_MDLoadLibrary, $_MDGetFuncAddress, $_MDFreeLibrary, $GetProcAddress, $LoadLibraryA, $fDllInit = False

    If Not $fDllInit Then

        If @AutoItX64 Then Exit(MsgBox(16, 'Error - x64', 'x64 Not Supported! ' & @LF & @LF & 'Download newest version for x64 support'))

        Local $Opcode = 'Opcode removed for preview'

        $_MDCodeBuffer = DllStructCreate("byte[" & BinaryLen($Opcode) & "]")
        DllCall("kernel32.dll", "bool", "VirtualProtect", "struct*", $_MDCodeBuffer, "dword_ptr", DllStructGetSize($_MDCodeBuffer), "dword", 0x00000040, "dword*", 0) ; PAGE_EXECUTE_READWRITE

        DllStructSetData($_MDCodeBuffer, 1, $Opcode)

        Local $pMDCodeBuffer = DllStructGetPtr($_MDCodeBuffer)
        $_MDLoadLibrary = $pMDCodeBuffer + (StringInStr($Opcode, "59585A51") - 1) / 2 - 1
        $_MDGetFuncAddress = $pMDCodeBuffer + (StringInStr($Opcode, "5990585A51") - 1) / 2 - 1
        $_MDFreeLibrary = $pMDCodeBuffer + (StringInStr($Opcode, "5A585250") - 1) / 2 - 1

        Local $Ret = DllCall("kernel32.dll", "hwnd", "LoadLibraryA", "str", "kernel32.dll")
        $GetProcAddress = DllCall("kernel32.dll", "uint", "GetProcAddress", "hwnd", $Ret[0], "str", "GetProcAddress")
        $LoadLibraryA = DllCall("kernel32.dll", "uint", "GetProcAddress", "hwnd", $Ret[0], "str", "LoadLibraryA")

        $fDllInit = True
    EndIf

    Switch $iCall
        Case 0; DllOpen
            Local $DllBuffer = DllStructCreate("byte[" & BinaryLen($Mod_Bin) & "]")
            DllCall("kernel32.dll", "bool", "VirtualProtect", "struct*", $DllBuffer, "dword_ptr", DllStructGetSize($DllBuffer), "dword", 0x00000040, "dword*", 0) ; PAGE_EXECUTE_READWRITE
            DllStructSetData($DllBuffer, 1, $Mod_Bin)
            Local $Module = DllCallAddress('uint', $_MDLoadLibrary, "uint", $LoadLibraryA[0], "uint", $GetProcAddress[0], "struct*", $DllBuffer)
            If $Module[0] = 0 Then Return SetError(1, 0, 0)
            Return $Module[0]
        Case 1; MemoryDllGetFuncAddress
            Local $Address = DllCallAddress("uint", $_MDGetFuncAddress, "uint", $Mod_Bin, "str", $sFuncName)
            If $Address[0] = 0 Then Return SetError(1, 0, 0)
            Return $Address[0]
        Case 2; DllClose
            Return DllCallAddress('none', $_MDFreeLibrary, "uint", $Mod_Bin)
    EndSwitch

EndFunc   ;==>__MemoryDllCore
; ============================================================================================================================
Link to comment
Share on other sites

  • 4 months later...

Hi.

I'm trying to use your MemoryDll.au3.

This is the guide in the 1st post of this thread:

; -------------------------------------------------------------
;
; Step 1: Try to use the DLLs in the normal method (by DllCall)
;
; -------------------------------------------------------------

$String = "The quick brown fox jumps over the lazy dog"
$Digest = DllStructCreate("byte[16]")
DllCall("md5.dll", "str", "md5", "str", $String, "uint", StringLen($String), "ptr", DllStructGetPtr($Digest))
$Hash = DllStructGetData($Digest, 1)
$Digest = 0
MsgBox(0, 'MD5 Hash', $Hash)


; ----------------------------------------------------------------------------
;
; Step 2: Use MemoryDllGen.au3 to convert the DLL to script form and paste it.
;
; ----------------------------------------------------------------------------

Dim $DllBinary = ''; this line is too long to omit, check the attachment

; --------------------------------------------------------------------------------
;
; Step 3: Replace DllCall to MemoryDllCall, and use $DllBinary instead of dll name
;
; --------------------------------------------------------------------------------

#Include "MemoryDll.au3"
MemoryDllInit()

$String = "The quick brown fox jumps over the lazy dog"
$Digest = DllStructCreate("byte[16]")
MemoryDllCall($DllBinary, "str", "md5", "str", $String, "uint", StringLen($String), "ptr", DllStructGetPtr($Digest))
$Hash = DllStructGetData($Digest, 1)
$Digest = 0
MsgBox(0, 'MD5 Hash', $Hash)

MemoryDllExit()


; -------------------------------------------------------------------------
;
; Step 4: Finally, you have the functions in Pure AutoIt Scirpt. Have fun !
;
; -------------------------------------------------------------------------

Step 1: Use DLLCall() to use the original DLL file - success.

Step 2: Create the AU3 converted File of "my" DLL - success. That one was included in the main script, the variable "$MyDLL" is available in the main script.

 

Step 3: Use "MemoryDLLCall()" instead of "DLLCall()", this doesn't work.

Your 3-Step-examle shows to use the function "MemoryDllInit()", which doesn't seem to exist in MemoryDLL.AU3 file?

Hm...

Could you give a brief example, how to make use a AU3 converted DLL, that was created using your "MemoryDllGen.AU3"?

I couldn't get this even from the other files included in your ZIP archive:

MemoryDll.au3
MemoryDllGen.au3
MemoryDllTest.au3
MemoryFuncCallTest.au3
MemorySQLite.au3
MemorySQLiteTest.au3

Thanks, Rudi.

Edited by rudi

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Link to comment
Share on other sites

  • 2 months later...

@Ward, Beege: any idea why the DLL used in >Water Effects (waterctrl.dll) is crashing when I try to use it from the memory?

Br,

UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Link to comment
Share on other sites

Hi.

I'm trying to use your MemoryDll.au3.

This is the guide in the 1st post of this thread:

; -------------------------------------------------------------
;
; Step 1: Try to use the DLLs in the normal method (by DllCall)
;
; -------------------------------------------------------------

$String = "The quick brown fox jumps over the lazy dog"
$Digest = DllStructCreate("byte[16]")
DllCall("md5.dll", "str", "md5", "str", $String, "uint", StringLen($String), "ptr", DllStructGetPtr($Digest))
$Hash = DllStructGetData($Digest, 1)
$Digest = 0
MsgBox(0, 'MD5 Hash', $Hash)


; ----------------------------------------------------------------------------
;
; Step 2: Use MemoryDllGen.au3 to convert the DLL to script form and paste it.
;
; ----------------------------------------------------------------------------

Dim $DllBinary = ''; this line is too long to omit, check the attachment

; --------------------------------------------------------------------------------
;
; Step 3: Replace DllCall to MemoryDllCall, and use $DllBinary instead of dll name
;
; --------------------------------------------------------------------------------

#Include "MemoryDll.au3"
MemoryDllInit()

$String = "The quick brown fox jumps over the lazy dog"
$Digest = DllStructCreate("byte[16]")
MemoryDllCall($DllBinary, "str", "md5", "str", $String, "uint", StringLen($String), "ptr", DllStructGetPtr($Digest))
$Hash = DllStructGetData($Digest, 1)
$Digest = 0
MsgBox(0, 'MD5 Hash', $Hash)

MemoryDllExit()


; -------------------------------------------------------------------------
;
; Step 4: Finally, you have the functions in Pure AutoIt Scirpt. Have fun !
;
; -------------------------------------------------------------------------

Step 1: Use DLLCall() to use the original DLL file - success.

Step 2: Create the AU3 converted File of "my" DLL - success. That one was included in the main script, the variable "$MyDLL" is available in the main script.

 

Step 3: Use "MemoryDLLCall()" instead of "DLLCall()", this doesn't work.

Your 3-Step-examle shows to use the function "MemoryDllInit()", which doesn't seem to exist in MemoryDLL.AU3 file?

Hm...

Could you give a brief example, how to make use a AU3 converted DLL, that was created using your "MemoryDllGen.AU3"?

I couldn't get this even from the other files included in your ZIP archive:

MemoryDll.au3
MemoryDllGen.au3
MemoryDllTest.au3
MemoryFuncCallTest.au3
MemorySQLite.au3
MemorySQLiteTest.au3

Thanks, Rudi.

I believe that function is called internally

What is what? What is what.

Link to comment
Share on other sites

  • 2 weeks later...

@Ward, Beege: any idea why the DLL used in >Water Effects (waterctrl.dll) is crashing when I try to use it from the memory?

 

Br,

UEZ

No clue right now but its crashing for me as well at memorydllopen. Ill see if I can get a deeper look.
Link to comment
Share on other sites

  • 9 months later...

2015/01/08 Update Note:

* Update the machine code version. Both x86 and x64 DLL are supported.

* TLS callback are supported.

* Remove all MemoryFuncXXX() related functions. Use build-in DllCallAddress instead.

* Add MemoryDllLoadString(), MemoryDllLoadResource() 

* Add _WinAPI_MemoryFindResource(), _WinAPI_MemoryFindResourceEx(), _WinAPI_MemorySizeOfResource(), _WinAPI_MemoryLoadResource(), _WinAPI_MemoryLoadString(), _WinAPI_MemoryLoadStringEx()

* Using BinaryCall.au3 to loading the machine code.

新版 _ArrayAdd 的白痴作者,不管是誰,去死一死好了

 

Link to comment
Share on other sites

  • 1 year later...

First off all, this looks exactly like the solution to a problem of mine.
Thank you Ward, for building this.

Great to see, that so many different opinions were flowing into a single include.

i am unable to download the attachments from the first post. i am eager to test the include for use in one of my projects.

Does someone have the current version to re-upload it somewhere else, for me to get it?

thanks in advance.

Knut J.

Edited by KnutJ

rsRVpv.gif

Link to comment
Share on other sites

@Ward: If you have any objection to my posting this, just let me know, and I'll take it down again a.s.a.p.

@KnutJ:  download link for the MemoryDll version dated 2015.01.08, with BinaryCall version dated 2014.07.24

 

Link to comment
Share on other sites

Thank you RTFC,

could you (or someone else) by any chance upload  "MemoryDllGen.AU3" (or / and the rest of the original package) which was mentioned as a tool to generate the correctly converted representation of a given .dll - file?

Thanks in advance

Edited by KnutJ

rsRVpv.gif

Link to comment
Share on other sites

; ============================================================================================================================
;  File     : MemoryDllGen.au3
;  Purpose  : Convert DLL files to HEX binary data
;  Author   : Ward
; ============================================================================================================================

Dim $VarName = StringStripWS(InputBox("MemoryDllGen", "Select a name of variable:", "DllBinary"), 3)
If $VarName = "" Then Exit

Dim $DllName = FileOpenDialog("Open dll file", @ScriptDir, "DLL file (*.*)")
If $DllName = "" Then Exit

Dim $Handle = FileOpen($DllName, 16)
Dim $DllBinary = FileRead($Handle)
FileClose($Handle)

Dim $LineLen = 2050
Dim $DllString = String($DllBinary)

Dim $Script = "Dim $" & $VarName & " = '" & StringLeft($DllString, $LineLen) & "'" & @CRLF
$DllString = StringTrimLeft($DllString, $LineLen)

While StringLen($DllString) > $LineLen
    $Script &= "    $" & $VarName & " &= '" & StringLeft($DllString, $LineLen) & "'" & @CRLF
    $DllString = StringTrimLeft($DllString, $LineLen)
WEnd

If StringLen($DllString) <> 0 Then $Script &= "    $" & $VarName & " &= '" & $DllString & "'" & @CRLF
ClipPut($Script)


MsgBox(64, 'MemoryDll Generator', 'The result is in the clipboard, you can paste it to your script.')
; ============================================================================================================================
;  File     : MemoryDllTest.au3
;  Purpose  : Test MemoryDll In Both x86 And X64 Mode
;  Author   : Ward
; ============================================================================================================================

#Include "MemoryDll.au3"

Main()

Func Main()
    If @AutoItX64 Then
        Local $InstallDir = RegRead("HKLM\SOFTWARE\Wow6432Node\AutoIt v3\AutoIt", "InstallDir")
        Local $DllPath = $InstallDir & "\AutoItX\AutoItX3_x64.dll"
    Else
        Local $InstallDir = RegRead("HKLM\SOFTWARE\AutoIt v3\AutoIt", "InstallDir")
        Local $DllPath = $InstallDir & "\AutoItX\AutoItX3.dll"
    EndIf
    If Not FileExists($DllPath) Then
        MsgBox(16, "Error", "Cannot Find AutoItX DLL !")
        Return
    EndIf

    Local $DllFile = FileOpen($DllPath, 16)
    Local $DllBin = FileRead($DllFile)
    FileClose($DllFile)

    Local $DllHandle = MemoryDllOpen($DllBin)

    MemoryDllCall($DllHandle, "none", "AU3_ToolTip", "wstr", "Hello, world!" & @CRLF & "AutoIt is best, MemoryDll.au3 is easy and fun", "long", @DesktopWidth / 3, "long", @DesktopHeight / 3)
    MemoryDllCall($DllHandle, "none", "AU3_Sleep", "long", 5000)
    MemoryDllCall($DllHandle, "none", "AU3_ToolTip", "wstr", "", "long", 0, "long", 0)

    MemoryDllClose($DllHandle)
EndFunc
; ============================================================================================================================
;  File     : MemorydllTest.au3
;  Purpose  : Demonstration for MemoryFuncCall
;  Author   : ProgAndy
;  Modifier : Ward
; ============================================================================================================================

#Include "MemoryDll.au3"

Func TestFunc($Param)
    MsgBox(0, 'TestFunc', $Param)
    Return 23
EndFunc

Dim $CallBack = DllCallbackRegister("TestFunc", "int", "str")
Dim $Ret = MemoryFuncCall("int", DllCallbackGetPtr($CallBack), "str", "A string as parameter")
MsgBox(0, 'The return', $Ret[0])
DllCallbackFree($CallBack)

 

Edited by RTFC
Link to comment
Share on other sites

Hello@all,

i tried this udf for some days now, but i am always facing the same problem when trying to call a cdecl-call .dll

Been testing under Win7Pro64bit and Win2k12R2(always 64bit) - the .dll is a 32bit cdecl-call-type-dll

if i run the autoit script, no matter if the .dll is a part of the source, definded as

$variable = '0x ...'

or if i load it via

$hfile=fileopen($File,16)
$variable=fileread($hfile)

every time i hit 

Local $DllHandle = MemoryDllOpen($variable)

i just get

AutoIt3.exe ended.rc:-1073741819

 

i would love to post a complete reproducer, but this specific .dll is not intended to be released to the public. therefore trying to call it from memory directly.

There is a post, where full compatibility is stated regarding stdcall & c-call .dll files.

To me, it looks like this isn't completely true at this moment in time.

anyone out there having an idea, where i could look at, modify something, need more input?

Edited by KnutJ

rsRVpv.gif

Link to comment
Share on other sites

  • 2 years later...

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