Sign in to follow this  
Followers 0
wraithdu

DllCall by Function Pointer

22 posts in this topic

#1 ·  Posted (edited)

UPDATE 12/7/08: Bah, this method is broken by UPX, so it's pretty useless. Use Ward's UDF instead (now compatible with Vista) -

http://www.autoitscript.com/forum/index.php?showtopic=77463

Example -

#include <MemoryDll.au3>
#include <WinAPI.au3>
$l = DllCall("kernel32.dll", "ptr", "GetProcAddress", "ptr", _WinApi_GetModuleHandle("user32.dll"), "str", "LockWorkStation")
$l = $l[0]
MemoryFuncCall("int", $l)
MemoryFuncExit()
Edited by wraithdu

Share this post


Link to post
Share on other sites



Great to see my functions already being used :)

I guess I can use this as well for my D3D development :)


Broken link? PM me and I'll send you the file!

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Quick update for better type handling. Seems Execute() can handle variables just fine, so no sense is messing with Eval().

@monoceres

If you're gonna write something so cool, it's bound to be exploited :)

Edited by wraithdu

Share this post


Link to post
Share on other sites

One more thing to add, this UDF creates and destroys the DllCallback and sets / resets the hook on each func call to avoid the need for an OnAutoItExit() function. Depending on your implementation, it might make more sense to take it apart a bit so some of these things are only done when absolutely necessary.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

One more thing to add, this UDF creates and destroys the DllCallback and sets / resets the hook on each func call to avoid the need for an OnAutoItExit() function. Depending on your implementation, it might make more sense to take it apart a bit so some of these things are only done when absolutely necessary.

Good point. One thing you can do in the UDF is to find some way to only call _AddHookApi once each time the script runs and use _ChangeHookApi with the hook "handle" instead since it's hundreds times faster.

Edited by monoceres

Broken link? PM me and I'll send you the file!

Share this post


Link to post
Share on other sites

Good idea. Done.

I modified your _AddHookApi() function to be able to return only the hook structure so I can do just what you suggested. Then I call it once at the top and make it a global struct so I can use _ChangeHookApi() in _DllCallPtr().

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

I was unhappy, so I rewrote some things :) In an effort to optimize the process, I modularized it. It is now broken down into the following functions, which include some better error checking -

_DllCallPtr_Init() - initialization code
_DllCallPtr_SetHook() - sets the GetProcAddress hook
_DllCallPtr() - calls the function; will call _Init() and _SetHook() if not already done
_DllCallPtr_UnSetHook() - unsets the GetProcAddress hook to return to normal functionality
_DllCallPtr_Free() - frees the callback and kernel32 handle; will call _UnSetHook() if the hook is set

I also slightly changed some of the HookApi functions to fit better with the overall structure -

_AddHookApi() -> _HookApi_Get()
Returns the hook structure for the given module / function.

_ChangeHookApi() -> _HookApi_Set()
Sets the hook

The absolute minimum that must be done to use the UDF is -

_DllCallPtr(); initializes and sets the hook if needed, then calls the function
_DllCallPtr_Free(); unsets the hook if needed, and frees the resources

@monoceres

I hope you don't mind the changes, they just made more logical sense for the way I have the UDF set up.

Edited by wraithdu

Share this post


Link to post
Share on other sites

Updated, see first post.

Share this post


Link to post
Share on other sites

It's working on Windows2000 Workstation and Server, XP and Vista. But why is this not working on Server2003 and Server 2008?!

I get in the SciTE console this code 0x773DDD0D for the first example and this >Exit code: -1073741819 for the second example.

After I have compiled the second example it's displaying the GUI and the msgbox but the "hide taskbar button" checkbox is doing nothing.

Any idea how to get it working on the servers or how to find out what is wrong?

Share this post


Link to post
Share on other sites

It's working on Windows2000 Workstation and Server, XP and Vista. But why is this not working on Server2003 and Server 2008?!

I get in the SciTE console this code 0x773DDD0D for the first example and this >Exit code: -1073741819 for the second example.

After I have compiled the second example it's displaying the GUI and the msgbox but the "hide taskbar button" checkbox is doing nothing.

Any idea how to get it working on the servers or how to find out what is wrong?

Does the same hold true for my entire UDF (which this udf builts upon)?

Oh and the Server editions aren't x64 are they?


Broken link? PM me and I'll send you the file!

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

I wonder if it's an issue with the DllCallback functions? That's about all the 2 UDFs have in common.

Edited by wraithdu

Share this post


Link to post
Share on other sites

LOL .... DEP was preventing the execution.

I did some tests on the 2003/2008 Servers.

The example below is working without deactivating DEP (I have use monoceres UDF and one of his examples)

But it's only working if you use it with F5 in SciTE, It´s not working if you compile it (deactivated DEP).

The Examples of wraithdu are working only if you deactivate DEP, and only if you used with F5 in SciTE.

;~ #include <apihook.au3>
     #include <winapi.au3>
     
     Global $IMAGE_DIRECTORY_ENTRY_IMPORT = 1
     Global $PAGE_READWRITE = 0x04
     Global $IMAGE_IMPORT_DESCRIPTOR = "dword DUMMYUNIONNAME;dword TimeDateStamp;dword ForwarderChain;dword Name;dword FirstThunk"
     Global $IMAGE_THUNK_DATA = "dword u1"
     Global $MEMORY_BASIC_INFORMATION = "ptr BaseAddress;ptr AllocationBase;ptr AllocationProtect;ulong RegionSize;dword State;dword Protect;dword Type;"
     
     
     $GetProcAddress=DllCallbackRegister("GetProcAddress","ptr","ptr;ptr")
     $GetProcAddressPtr=DllCallbackGetPtr($GetProcAddress)
     
     $virtualprotect=_GetProcAddress(_WinAPI_GetModuleHandle("Kernel32.dll"), "VirtualProtect")
     
     $LockWorkStation=_GetProcAddress(_WinAPI_GetModuleHandle("user32.dll"),"LockWorkStation")
     
     $hook = _AddHookApi("Kernel32.dll", "GetProcAddress", $GetProcAddressPtr)
     DllCall("kernel32.dll","int",String($LockWorkStation))
     
     
     Func GetProcAddress($ptr,$str)
         $string = DllStructCreate("char[255]", $str)
     
         if DllStructGetData($string,1)="VirtualProtect" Then
             Return $virtualprotect
         Elseif DllStructGetData($string,1)="VirtualQuery" Then
             Return $virtualquery
         Else
             Return DllStructGetData($string,1)
         EndIf
         Return 0
     EndFunc
     
     Func _AddHookApi($ModuleName, $FunctionName, $NewProcAddress)
        ; Get base address of our app
         $hInstance = _WinAPI_GetModuleHandle(0)
         
        ;; Get module of the module that the function resides in
         $Module = _WinAPI_GetModuleHandle($ModuleName)
         
        ; Get the original function address
         $call = DllCall("Kernel32.dll", "ptr", "GetProcAddress", "ptr", $Module, "str", $FunctionName)
         $OrigAddress = $call[0]
     
        ;; Get the address of the Import directory
         $call = DllCall("Dbghelp.dll", "ptr", "ImageDirectoryEntryToData", "ptr", $hInstance, "int", 1, "ushort", $IMAGE_DIRECTORY_ENTRY_IMPORT, "ulong*", "")
         $ptrtoiid = $call[0]
         
        ; Create a struct from the pointer
         $iid = DllStructCreate($IMAGE_IMPORT_DESCRIPTOR, $ptrtoiid)
         
        ;; Loop through all loaded modules.
         While DllStructGetData($iid, "Name")
             
            ; get the name...
             $str = DllStructCreate("char[255]", $hInstance + DllStructGetData($iid, "Name"))
             
            ; If the name matches, we've found what we're looking for.
             If DllStructGetData($str, 1) = $ModuleName Then ExitLoop
             
            ; Move to the next directory item
             $ptrtoiid += DllStructGetSize($iid)
             $iid = DllStructCreate($IMAGE_IMPORT_DESCRIPTOR, $ptrtoiid)
         WEnd
         
         
         $ptrtoitd = $hInstance + DllStructGetData($iid, "FirstThunk")
         $itd = DllStructCreate($IMAGE_THUNK_DATA, $ptrtoitd)
     
         While DllStructGetData($itd, 1)
             
            ; We have found where the original address is stored
             If DllStructGetData($itd, 1) = $OrigAddress Then
                 
                 
                ;; Prepare the memory for writing
                 $mbi = DllStructCreate($MEMORY_BASIC_INFORMATION)
                 DllCall("Kernel32.dll", "ulong", "VirtualQuery", "ptr", DllStructGetPtr($itd, 1), "ptr", DllStructGetPtr($mbi), "ulong", DllStructGetSize($mbi))
                 DllCall("Kernel32.dll", "int", "VirtualProtect", "ptr", DllStructGetData($mbi, "BaseAddress"), "ulong", DllStructGetData($mbi, "RegionSize"), "dword", $PAGE_READWRITE, "ptr", DllStructGetPtr($mbi, "Protect"))
                 
                ;; Here's where the magic happens
                 DllStructSetData($itd, 1, $NewProcAddress)
     
                 
                 $randomdword = DllStructCreate("dword")
                 DllCall("Kernel32.dll", "int", "VirtualProtect", "ptr", DllStructGetData($mbi, "BaseAddress"), "ulong", DllStructGetData($mbi, "RegionSize"), _
                         "dword", DllStructGetPtr($mbi, "Protect"), "ptr", DllStructGetPtr($randomdword, 1))
                 
                 ExitLoop
             EndIf
             $ptrtoitd += DllStructGetSize($itd)
             $itd = DllStructCreate($IMAGE_THUNK_DATA, $ptrtoitd)
         WEnd
         
         Return $itd
     EndFunc  ;==>_AddHookApi
     
     Func _GetProcAddress($hModule, $FunctionName)
         $call = DllCall("Kernel32.dll", "ptr", "GetProcAddress", "ptr", $hModule, "str", $FunctionName)
         Return $call[0]
     EndFunc  ;==>_GetProcAddress
     
     
     Func _ChangeHookApi($ITDSTRUCT, $NewProc)
        ;; Prepare the memory for writing
         $mbi = DllStructCreate($MEMORY_BASIC_INFORMATION)
         DllCall("Kernel32.dll", "ulong", "VirtualQuery", "ptr", DllStructGetPtr($ITDSTRUCT, 1), "ptr", DllStructGetPtr($mbi), "ulong", DllStructGetSize($mbi))
         DllCall("Kernel32.dll", "int", "VirtualProtect", "ptr", DllStructGetData($mbi, "BaseAddress"), "ulong", DllStructGetData($mbi, "RegionSize"), "dword", $PAGE_READWRITE, "ptr", DllStructGetPtr($mbi, "Protect"))
         
        ;; Here's where the magic happens
         DllStructSetData($ITDSTRUCT, 1, $NewProc)
         
         $randomdword = DllStructCreate("dword")
         DllCall("Kernel32.dll", "int", "VirtualProtect", "ptr", DllStructGetData($mbi, "BaseAddress"), "ulong", DllStructGetData($mbi, "RegionSize"), _
                 "dword", DllStructGetPtr($mbi, "Protect"), "ptr", DllStructGetPtr($randomdword, 1))
         
     EndFunc  ;==>_ChangeHookApi

Share this post


Link to post
Share on other sites

@Christos: could you check this one too: http://www.autoitscript.com/forum/index.ph...st&p=599174 ? I'd like to know if this will work with DEP :)


*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

Damn. I went back through monoceres' UDF with a compiled exe, and it's not calling the new _GetProcAddress callback, so the failure message is from DllCall() saying it can find the function in the DLL. I'm not sure what's up with this at the moment.

Share this post


Link to post
Share on other sites

I can't figure it out. I did find a small unrelated bug though, which I've fixed in the original post. We'll have to wait and let monoceres weigh in on this.

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

I can't figure it out. I did find a small unrelated bug though, which I've fixed in the original post. We'll have to wait and let monoceres weigh in on this.

It's UPX's fault. I just tested and my sample fails when UPX is enabled but works as expected when turned off. My guess is that UPX itself uses some "tricks" (just like I do) on the PE format so it can use compression etc.

Edited by monoceres

Broken link? PM me and I'll send you the file!

Share this post


Link to post
Share on other sites

LOL, cross-posted the answer :)

Any thoughts on fixing it?

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

LOL, cross-posted the answer :)

Any thoughts on fixing it?

Not really no. I added some debugging into the UDF and found out that the UDF successfully finds the address to GetProcAddress and overwrites it with our callback pointer.

I also confirmed that autoit calls the real GetProcAddress as normal so clearly UPX does something to the AutoIt exe so it's not needing/using the Import directory anymore.

Edited by monoceres

Broken link? PM me and I'll send you the file!

Share this post


Link to post
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
Sign in to follow this  
Followers 0