Jump to content
Sign in to follow this  
Ascend4nt

File + Process Imports and Exports - DLL, EXE etc

Recommended Posts

Ascend4nt

File + Process Imports/Exports Information UDFs

Posted ImagePosted Image

Forwarder String Support, C++ Name Undecorating Added!!

(Extreme case of string forwarding from wsock32.dll example in this post)

This UDF gets Function Imports and Exports for any Windows PE file (.DLL, .EXE), both 32-bit and 64-bit (unlike most programs out there), and from either a 32-bit or 64-bit Process.

I created this due to my frustration with other programs either working only *some* of the time, or having a common inability to read PE32+ (x64) file format tables properly.

There's just two functions in the main UDF - _FileGetWinPEImports or _FileGetWinPEExports. The bundled TestImportExportsList program lets you explore files on your system.

*Newly included are: _ProcessGetWinPEImports, _ProcessGetWinPEExports and TestProcessImportExportsList program (requires my Process Functions UDF).

NOTE: *Compressed* executable files will only give the Import information for the 'decompressor'. The only way to get the compressed executable's Import information is to decompress the executable.

Anyway, enjoy my hard work. Either read on for more information about some of the features, or see below for the License agreement and Download link.

Information on 'Virtual Offset of Thunk':

These address offsets you see are offsets from the base of the .DLL or .EXE file (uncompressed only!), where the actual function location of an 'Import' gets placed. All calls to these functions load addresses from these Thunk locations in order to correctly place a call to the right DLL function. (This is totally different than the old Import fixup location lists of earlier pre-NT systems). Technically, you could overwrite these Thunks with addresses to your own functions, but this is a dangerous thing to do. Its a neat tool to have though.

Forwarder functions? An explanation:

The whole 'DLLNAME.Functionname' string might be confusing to you, but here's an explanation of why an address can not and should not be returned. To better understand all this, grab a copy of DLL Export Viewer, (which doesn't report Relative/Function addresses correctly for Forwarded functions) and then follow along: *update: as of v1.50, DLL Export Viewer now reports forwarder string info (I was the one that reported the bug heh)

Okay, open up DLL Export Viewer and look at (for this example) KERNEL32.DLL - lets pick 'HeapFree', a known Forwarded function. DLL Export Viewer reports the following (on XP SP3):Relative Address: 0x0000910c, 'Loaded' address: 0x7c80910c. *Neither* is the case, though - 0x0000910c is in fact just the virtual address of the forwarder string!

Now, with my Exports function, you'll find that 'HeapFree' is reported (correctly) as a Forwarder string. What you'll see then is 'NTDLL.RtlFreeHeap'. What does that mean? It means that:

  • HeapFree is not a part of KERNEL32.DLL (and hasn't been for a while),
  • When that function is called or the address retrieved via 'GetProcAddress', the function 'RtlFreeHeap' in NTDLL.DLL is the function that's actually called (or returned as an address). Hopefully the 'DLLNAME.FunctionName' structure of a Forwarder string is starting to make sense now?
  • The address you get when you do 'GetProcAddress' does *not* correspond to what you see in DLL Export Viewer - in fact, 'HeapFree's reported address lies entirely OUTSIDE of kernel32.dll's memory space - pointing instead inside of NTDLL.DLL, at (guess what?): RtlFreeHeap.
So, on XP SP3, looking up 'HeapFree' with GetProcAddress, you get: 0x7C90FF2D. Doesn't match what was reported with DLL Export Viewer AT ALL. However - go back, and now look at NTDLL.DLL with DLL Export Viewer, and at function 'RtlFreeHeap' (following the logic of the Forwarder Function string). What is reported for RtlFreeHeap? Relative Address: 0x0000ff2d, 'Loaded' address: 0x7c90ff2d. See now how it lines up with what was reported via GetProcAddress for 'HeapFree' in KERNEL32.DLL?

So, there you have it in a nutshell - Forwarder functions are functions 'rerouted' to another DLL. The DLL's that are being rerouted to are either:

  • A.) Pre-loaded by the system (Important DLL's like NTDLL.DLL, KERNEL32.DLL, USER32.DLL, GDI32.DLL, etc - are all permanently loaded)
  • B.) Loaded upon a program's execution if the function is in its 'Imports' list, or
  • C.) Loaded upon a call to GetProcAddress. To see how this works clearly, list the modules that are loaded (my Process Functions UDF GUI can do this for you), then call GetProcAddress for 'GetServiceW' from WSOCK32.DLL, and then re-list the modules again. You'll see a new module loaded up - MSWSOCK.DLL (the location of the forwarder function). Wa-la, forwarder is set up.
Ascend4nt's AutoIT Code License agreement:

While I provide this source code freely, if you do use the code in your projects, all I ask is that:

  • If you provide source, keep the header as I have put it, OR, if you expand it, then at least acknowledge me as the original author, and any other authors I credit
  • If the program is released, acknowledge me in your credits (it doesn't have to state which functions came from me, though again if the source is provided - see #1)
  • The source on it's own (as opposed to part of a project) can not be posted unless a link to the page(s) where the code were retrieved from is provided and a message stating that the latest updates will be available on the page(s) linked to.
  • Pieces of the code can however be discussed on the threads where Ascend4nt has posted the code without worrying about further linking.

Download the ZIPs from my Site

UPDATES:

7-21-2010:

Added:

  • C++ Function Name Undecorating/Unmangling option. For an example of what this causes function name results to be, check out something like 'msvcrt.dll'. It will report alot more than just a function name! If you choose to do the Undecorating yourself, just call the included function _WinAPI_UndecorateName().

    Example: "??3@YAXPAX@Z" becomes "void __cdecl operator delete(void *)" unmanged/undecorated

  • New _ProcessGetWinPEImportExports module (with Test program) as a separate download - requires use of my Process Functions UDF. The biggest benefits, besides looking into loaded DLL's that might not be on the disk? Addresses reported are real, and Imported function addresses are reported (as pulled from Thunk locations).
7-12-2010:

Fixed:

  • Oops, Big-time logic errors in mapping Export function names to addresses and using ordinals to look them up from pointer tables. Now everything points to where it should!
  • Ordinal #'s are now correctly calculated with the 'Base' # part of the EXPORT DIRECTORY TABLE.
Added:
  • 'Forwarder' string lookup & reporting! Not even DLL Export Viewer does this! Basically, certain function 'pointers' aren't really code offsets, but offsets to Forwarder strings. My function looks those strings up and puts them in the list instead of a phoney address.
7-11-2010:

Fixed:

  • Executables linked with Borland's TLINK32.exe do not set the 'ImportLookupTableRVA' element correctly. This was easy to work around, as the 'Thunks' list also contains pointers to the same information (until an executable/DLL is loaded by the O/S, at least)
Added:
  • Imports: Extra column: Virtual Offset of Thunk ( [3] ). When an .EXE or .DLL is loaded, this is the Offset from the base of the .EXE or .DLL which will hold the actual function address. This could be used for redirection of calls (dangerous though!).

    ...

    An important note on this: Compressed executables are a completely different beast, and in fact the whole Import section is for the Decompressor itself, which disappears once the executable is loaded! The only way to get the actual Imports for Compressed Executables is to Decompress them first.

Edited by Ascend4nt
  • Like 1

Share this post


Link to post
Share on other sites
wraithdu

Nicely done.

To ease your frustration though, you should check out DLL Export Viewer from NirSoft.

Edited by wraithdu

Share this post


Link to post
Share on other sites
Ascend4nt

Thanks. I've been using DLL Export Viewer actually - But it doesn't report on Imports, and I'd rather not have to rely on using another program just for Exports.

Share this post


Link to post
Share on other sites
Shafayat

Fascinating work.

This is really going to come in handy.


[Not using this account any more. Using "iShafayet" instead]

Share this post


Link to post
Share on other sites
jfcby

This is a very useful UDF.


Determined -- Devoted -- Delivered Make your mind up -- to seriously apply yourself -- accomplishing the desired results. **** A soft answer turneth away wrath: but grievous words stir up anger. Proverbs 15:1 KJB ****

Share this post


Link to post
Share on other sites
Ascend4nt

Thanks everyone for the compliments.

I've updated the UDF after reading about Borland's TLINK32 issue. All files should report the right Import information now, though I still have yet to figure out the 'forwarding' thing with certain Exports (that return an Offset of 0).

UPDATES:

7-11-2010:

Fixed:

  • Executables linked with Borland's TLINK32.exe do not set the 'ImportLookupTableRVA' element correctly. This was easy to work around, as the 'Thunks' list also contains pointers to the same information (until an executable/DLL is loaded by the O/S, at least)
Added:

  • Imports: Extra column: Virtual Offset of Thunk ( [3] ). When an .EXE or .DLL is loaded, this is the Offset from the base of the .EXE or .DLL which will hold the actual function address. This could be used for redirection of calls (dangerous though!).

    ...

    An important note on this: Compressed executables are a completely different beast, and in fact the whole Import section is for the Decompressor itself, which disappears once the executable is loaded! The only way to get the actual Imports for Compressed Executables is to Decompress them first.

Edited by Ascend4nt

Share this post


Link to post
Share on other sites
Ascend4nt

Sorry for the short time between updates, but I found a major issue with my code, and at the same time added something new - not even DLL Export Viewer has Forwarder-String information :blink:

Check out these examples of Forwarder strings inside DLL's (2nd example is an extreme case!)

Posted Image..Posted Image

Onto the updates:

UPDATES:

7-12-2010:

Fixed:

  • Oops, Big-time logic errors in mapping Export function names to addresses and using ordinals to look them up from pointer tables. Now everything points to where it should!
  • Ordinal #'s are now correctly calculated with the 'Base' # part of the EXPORT DIRECTORY TABLE.
Added:

  • 'Forwarder' string lookup & reporting! Not even DLL Export Viewer does this! Basically, certain function 'pointers' aren't really code offsets, but offsets to Forwarder strings. My function looks those strings up and puts them in the list instead of a phoney address.
Edited by Ascend4nt

Share this post


Link to post
Share on other sites
Fire

Really Awesome work!

Thxs for share!


[size="5"] [/size]

Share this post


Link to post
Share on other sites
Ascend4nt

Updated!

7-21-2010:

Added:

  • C++ Function Name Undecorating/Unmangling option. For an example of what this causes function name results to be, check out something like 'msvcrt.dll'. It will report alot more than just a function name! If you choose to do the Undecorating yourself, just call the included function _WinAPI_UndecorateName().

    Example: "??3@YAXPAX@Z" becomes "void __cdecl operator delete(void *)" unmanged/undecorated

  • New _ProcessGetWinPEImportExports module (with Test program) as a separate download - requires use of my Process Functions UDF. The biggest benefits, besides looking into loaded DLL's that might not be on the disk? Addresses reported are real, and Imported function addresses are reported (as pulled from Thunk locations).

Share this post


Link to post
Share on other sites
aef03

Would it be possible to use parts of this library to validate that exports of a system DLL have not been dynamically remapped within the process where my script is running?

D.

Share this post


Link to post
Share on other sites
Ascend4nt

I'm not sure I understand. Do you mean that imports in your process (which are mapped to exports from DLL's) are being redirected to a different address than they should be? Theoretically it would be possible to check them, if the LoadLibrary/GetProcAddress API functions needed by DLLCall() were not themselves remapped to something that prevents them from working correctly.

Probably the best thing for you to do is to use UPX or some other compression utility which makes it more difficult for someone to get and remap the imports for your app.

I would also say that its possible to do using compiled machine code that goes through the PEB and module lists, but machine code still requires a DLLCall() to use from AutoIt..

Share this post


Link to post
Share on other sites
aef03

I'm actually trying to detect when aclayers.dll might be redirecting registry writes.

Share this post


Link to post
Share on other sites
Ascend4nt

Not sure what aclayers is, but sounds easy enough. Use DLLCall to call 'GetProcAddress' for the different registry API calls, and compare those returned values to the process's loaded addresses for those API calls. If there's a difference, then they are being redirected. You can even go further to see where the module address is located by comparing it against the loaded modules' start and 'end' (start+size) addresses.

Share this post


Link to post
Share on other sites
Ascend4nt

First off, you mean 33.4KB uncompressed (for the File Import/Exports info).

Secondly, NirSoft's DLL Export Viewer incorrectly reports the code address, because that function doesn't actually exist in kernel32.dll. In the PE, it gives an offset that points to a 'forwarder' string. That means that "NTDLL.RtlAddVectoredExceptionHandler" tells you where the function really exists - in NTDLL.DLL, as the function name RtlAddVectoredExceptionHandler. Read my first post, hopefully that will help you understand what forwarding is, and why NirSoft's program reports bad information.

Share this post


Link to post
Share on other sites
Ascend4nt

How about that - Nirsoft actually listened to feedback :huh2:

DLL Export Viewer finally has forwarder string information reported correctly as of v1.50.

On another note.. I've noticed some .EXE files are putting Imports all over - inside different sections of the PE. wth? Anyway.. causes the program to crash currently, so if anyone sees a crash, this is most likely whats happening. I'd call it non-standard, but Windows handles it fine, as do some other PE viewers (some crash though). That was a very annoying bugger to track down.

What this means is that I need to search for the right section and recalculate RVA Offsets for each and every Import. What a pain.. Anyhoo.. that's on my to-do list for the next version. Just thought I'd at least log the problem here in the meantime and tell y'all to update your copy of DLL Export Viewer as well ;)

Share this post


Link to post
Share on other sites
mailro

Any sample code how you use export functions of a dll to my own script would appreciated?

Thanks

Edited by mailro

Share this post


Link to post
Share on other sites
Ascend4nt

You'd need to figure that out for yourself. If you are planning on calling a function in a DLL, you need to know what parameters it takes, as well as the return value. If its a standard Microsoft DLL, you can find the documentation for the function on MSDN. Any other DLL's, you need to know who made it and then check their website for info on calling the functions. I think WinAPIOverride32 lets you explore how certain DLL functions are called, though the program seems to crash more than anything for me.

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  

  • Similar Content

    • Miliardsto
      By Miliardsto
      I want to detect if exact process or window uses directx or opengl or maybe something else library used in applications.
      Thats becouse there could be many windows with same names and different names and the same with process. I got so much process names I want to my script works with all, so i want standardize.
      All of this processes uses DirectX or OpenGL so then If I check this window/process uses these libraries I will be sure thats the right process
    • VADemon
      By VADemon
      I've encountered a problem with a single file where I cannot retrieve it's Date-time. So far my code has worked well for over 30 files, but this one is a mystery I cannot debug myself due to insufficient Au3 knowledge.
      In line 11 "_Date_Time_FileTimeToArray" is called and for this particular file it sets the @error to 10. I don't know what that error code means, but it's not set by the _Date functions themselves I think.
      Overall, it could be a problem caused by any of the functions below, how can I properly debug this? / Does anybody know a what's causing this?
      _WinAPI_CreateFile() / _Date_Time_GetFileTime() / _Date_Time_FileTimeToArray()
      Func _SetFileTimes($sFilePath) Local $monthNumber[13] = ["", "January", "February", "March", "April", "May", "Juny", "July", "August", "September", "October", "November", "December"] Local $dayNumber[7] = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] Local $fHandle = _WinAPI_CreateFile($sFilePath, 2, 2) ; read-only ; may NOT return a valid date for some reason! TODO Local $fTagFILETIME = _Date_Time_GetFileTime($fHandle) _WinAPI_CloseHandle($fHandle) ; This will return an empty array if theres no valid date $fModTime = _Date_Time_FileTimeToArray($fTagFILETIME[2]) ; last Modified if @error <> 10 then Local $year = $fModTime[2] Local $month = $fModTime[0] Local $day = $fModTime[1] Local $hour = $fModTime[3] Local $min = $fModTime[4] Local $sec = $fModTime[5] Local $ms = $fModTime[6] Local $weekday = $fModTime[7] Global $prettyTimestamp = StringFormat("%s, %s %d, %04d %02d:%02d:%02d", $dayNumber[$weekday], $monthNumber[$month], $day, $year, $hour, $min, $sec) Global $uploadDate = StringFormat("%04d-%02d-%02d", $year, $month, $day) $fModTime = _Date_Time_FileTimeToArray(_Date_Time_FileTimeToLocalFileTime($fTagFILETIME[2])) ; last Modified Local $year = $fModTime[2] Local $month = $fModTime[0] Local $day = $fModTime[1] Local $hour = $fModTime[3] Local $min = $fModTime[4] Local $sec = $fModTime[5] Local $ms = $fModTime[6] Local $weekday = $fModTime[7] ; GetUnixTime accounts for Local time, hence feed it local time Global $unixTimestamp = _GetUnixTime($year &"/"& $month &"/"& $day &" "& $hour&":"& $min &":"& $sec) else Global $prettyTimestamp = "N/A" Global $uploadDate = "" Global $unixTimestamp = "N/A" endif endfunc  
      _GetUnixTime returned the year 1601 start date, showing that $fModTime is probably equal 0. (But Why?)
      The file reports these dates in Explorer, it's on local NTFS drive:
      Created: ‎‎Wednesday, ‎31. ‎Januar ‎2018, ‏‎18:55:02
      Modified: ‎Wednesday, ‎10. ‎Januar ‎2018, ‏‎12:39:23
      Accessed: ‎Wednesday, ‎10. ‎Januar ‎2018, ‏‎12:39:23
    • Emmhor1
      By Emmhor1
      Hi All,

      MAIN QUESTION:
      Is it possible to Call specific function within a GUI

      So I have a script with multiple functions although I don't want to use every function every time.
      My Idea is to create a simple GUI which allows me to select what functions I want to use then run the funtions by clicking a button.
      I have already made a GUI which allows me to select specific .exe's I would like to run after selection it runs the .exe one by one.
      This script is on my work laptops and cannot access it right now.
       
      Who can help me with this?
      GUIcreate
      Func1 
      Func2
      Func3
      Then have a boxes which allows me to select the specif Func.(I used GUIChecked and Unchecked in my other script)
      Then a button which executes/calls the selected functions
    • TryWare90Days
      By TryWare90Days
      I'm trying to kill a malware process, that I can't remove with my www.sophus.com/hom antivirus.

      The malware is known as coinminer,config and my Sophus only creates popups of blocking the malware.

      I know that the malware is constantly launching a svchost *32.exe processes, where the svchost.exe processes are from my Windows 7 operating system.
      I have with no luck tried to do this:
      Global $_bStatus = False
      While $_bStatus = False
                 Global $_iPid
                 Global $_sActiveTitleNew = "svchost *32.exe"
                 $_iPid = WinGetProcess($_sActiveTitleNew)
                 If $_iPid <> -1 Then $_bStatus = ProcessClose($_iPid)   
      Wend
      EXIT
       
      But the $_iPid doesn't ever show anything else than  -1, even if I can see the svchost *32.exe process in my TaskManager
       
      YES - I know I shouldn't EXIT after killing the first malware detection, but it is easier to explain the above for you, so I can get a solution.
    • cdeb
      By cdeb
      I'm trying to verify which is the default scanner and if it is different from what I need to propose a choice among those available.
      All this is possible with eztw32.dll however I can not make certain functions work
      Are these:
      int TWAIN_GetDefaultSourceName(LPSTR pzName)
      string TWAIN_DefaultSourceName()
      int TWAIN_GetSourceList(void)
      source: http://www.eztwain.com/pub/eztp/EZTwain_User_Guide.pdf
      I tried this way but they do not work:
      Local $pzName
      $pzName = DllCall($pathDLL,"int","TWAIN_DefaultSourceName") ;
      $rc = DllCall($pathDLL,"int","TWAIN_GetDefaultSourceName", "str*", $pzName) ;
      $rc = DllCall($pathDLL,"int","TWAIN_GetDefaultSourceName","str", $pzName) ;
      $rc = DllCall($pathDLL,"int","TWAIN_GetSourceList")
      $rc = DllCall($pathDLL,"int","TWAIN_GetSourceList", "NONE", "") ;
       
      Can anyone help me?
      Everything else works, here is the code:
       
      Local $pathDLL = @ScriptDir&"\_res\eztw32.dll" Local $rc = DllCall($pathDLL,'int','TWAIN_EasyVersion') if @error <> 0 then MsgBox(16+262144, "DllCall Error", "Error load eztw32.dll") else ConsoleWrite('--> eztw32.dll version: ' & $rc[0]/100 & @CRLF) $rc = DllCall($pathDLL,"int","TWAIN_IsAvailable") If @error > 0 Then MsgBox(16+262144, "DllCall Error", "Error call DLL - TWAIN_IsAvailable") if $rc[0] <> 0 then ConsoleWrite('--> TWAIN available: RC = ' & $rc[0]&@CRLF) ;;;;;;;;;;;;;;;;;;;;;; I NEED HERE ;manual select scanner Local $hwnd $rc = DllCall($pathDLL,"long","TWAIN_SelectImageSource",'hwnd',$hwnd) ConsoleWrite('--> TWAIN_SelectImageSource = ' & $rc[0]&@CRLF) if $rc[0] <> 0 then ConsoleWrite("--> TWAIN device selected"&@CRLF) else ConsoleWrite("--> no TWAIN device selected"&@CRLF) endif Else ConsoleWrite('--> TWAIN NOT available: RC = ' & $rc[0]&@CRLF) ; es: 0 endif endif thank you
×