Log in

View Full Version : All DLLs - Not in IAT?


live_dont_exist
February 21st, 2012, 14:28
Hi All,
I was trying to get a list of all the DLLs that are loaded by an executable using the PeFile module in Python. So I took up 'Minesweeper'. I read the PE header and got all the DLLs that minesweeper imported; and all the dependencies for each of these DLLs as well. For e.g winmine.exe had 9 DLLs in its IMPORT DIRECTORY TABLE. Of these some DLLs again had their own imports. So I got those as well. Here is my output:

This is a list of all the DLL's imported by winmine.exe

Code:

['WINMM.dll', 'GDI32.dll', 'SHELL32.dll', 'KERNEL32.dll', 'msvcrt.dll', 'RPCRT4.dll', 'ADVAPI32.dll', 'ntdll.dll', 'SHLWAPI.dll', 'USER32.dll', 'COMCTL32.dll']
>>>


But now when I look in Olly there are 4 or 5 more DLLs marked in red for some reason ...here is a full list...

Code:

Executable modules
Base Size Entry Name File version Path
01000000 00020000 01003E21 winmine 5.1.2600.0 (xpcl C:\WINDOWS\system32\winmine.exe
5AD70000 00038000 5AD71626 UxTheme 6.00.2900.2180 ( C:\WINDOWS\system32\UxTheme.dll
5CB70000 00026000 5CB78E39 ShimEng 5.1.2600.2180 (x C:\WINDOWS\system32\ShimEng.dll
6F880000 001CA000 6F8A5E1A AcGenral 5.1.2600.2180 (x C:\WINDOWS\AppPatch\AcGenral.DLL
76390000 0001D000 763912C0 IMM32 5.1.2600.2180 (x C:\WINDOWS\system32\IMM32.DLL
769C0000 000B3000 769C15D4 USERENV 5.1.2600.2180 (x C:\WINDOWS\system32\USERENV.dll
76B40000 0002D000 76B42B69 WINMM 5.1.2600.2180 (x C:\WINDOWS\system32\WINMM.dll
77120000 0008C000 77121558 OLEAUT32 5.1.2600.2180 C:\WINDOWS\system32\OLEAUT32.dll
773D0000 00102000 773D42B3 COMCTL32 6.0 (xpsp_sp2_rt C:\WINDOWS\WinSxS\x86_Microsoft.Windows.Common-Controls_6595b64144ccf1df_6.0.2600.2180_x-ww_a84f1ff9\COMCTL32.dll
774E0000 0013C000 774F20C1 ole32 5.1.2600.2180 (x C:\WINDOWS\system32\ole32.dll
77BE0000 00015000 77BE1292 MSACM32 5.1.2600.2180 (x C:\WINDOWS\system32\MSACM32.dll
77C00000 00008000 77C01135 VERSION 5.1.2600.2180 (x C:\WINDOWS\system32\VERSION.dll
77C10000 00058000 77C1F2A1 msvcrt 7.0.2600.2180 (x C:\WINDOWS\system32\msvcrt.dll
77D40000 00090000 77D50EB9 USER32 5.1.2600.2180 (x C:\WINDOWS\system32\USER32.dll
77DD0000 0009B000 77DD70D4 ADVAPI32 5.1.2600.2180 (x C:\WINDOWS\system32\ADVAPI32.dll
77E70000 00091000 77E76284 RPCRT4 5.1.2600.2180 (x C:\WINDOWS\system32\RPCRT4.dll
77F10000 00046000 77F163CA GDI32 5.1.2600.2180 (x C:\WINDOWS\system32\GDI32.dll
77F60000 00076000 77F651D3 SHLWAPI 6.00.2900.2180 ( C:\WINDOWS\system32\SHLWAPI.dll
7C800000 000F4000 7C80B436 kernel32 5.1.2600.2180 (x C:\WINDOWS\system32\kernel32.dll
7C900000 000B0000 7C913156 ntdll 5.1.2600.2180 (x C:\WINDOWS\system32\ntdll.dll
7C9C0000 00814000 7C9DFA10 SHELL32 6.00.2900.2180 ( C:\WINDOWS\system32\SHELL32.dll


The ones marked in Bold above were not visible in the Import Directory Table in PeView or extracted by my Python code. However they were visible in LordPe and ProcessExplorer and of course Olly 1.10 too.

Why is this? Where else does an EXE get its list of DLLs from if not from the IMPORT DIRECTORY TABLE?

Do let me know.

Thanks
Arvind

Extremist
February 21st, 2012, 20:03
LoadLibrary()

Aimless
February 21st, 2012, 21:47
Of course, you should be aware that DLLs get loaded in 3 manners:-

1. Via import table (what you saw)

2. Delayed Load (only when necessary OR subsequent to attachment of certain other Dlls)

3. Dynamically Loaded (Loadlibrary, attachprocess, etc.)

You generally cannot see 2 and 3 in any tools that check the Dlls via import. Instead, you have to profile them at runtime.

Get a software (very small, but NOT the one available in Visual Studio) called Dependency Walker.

This software tells you all dlls --- loaded via import tables, delayed loads, dynamically loaded. And then some!

It's a fantastic software to see what your program is REALLY doing and Calling...

Have Phun,

live_dont_exist
February 22nd, 2012, 00:26
Thanks extremist,aimless.

I did use Dep Walker too..thanks and it did show me everything. As did LordPe, ProcessExplorer and of course Olly. So I guess these tools use all 3 techniques you mentioned.

How do these tools work internally though? Like for example: I know that the IMPORT_DIRECTORY structure is read and DLL imports got from there. How do tools detect the other 2 techniques and give a list of DLLs in the end?

I'm asking because I'm trying to automate just that part using Python. For Imports I could use the PeFile module and read the PE header. What would I have to do for the rest?

Edit: I found that Delay Loaded DLLs have a directory under IMAGE_OPTIONAL_HEADER [DELAY IMPORT DESCRIPTORS] in the PE Header whenever they are used. PEView only displays it when its used. Have attached a screenshot. The funny thing now though is that Shell32.dll has a huge number of DLLs under delayed imports. However, not all of them are used; as in loaded by winmine.exe.

2546

Thanks
Arvind

aqrit
February 22nd, 2012, 04:41
The "official" way is to debug the process so Windows will notify your debugger about loaded dlls
see: CreateProcess( DEBUG_PROCESS ) or DebugActiveProcess

live_dont_exist
February 22nd, 2012, 06:32
There's no way to do it through Python ..then? I have to use the Windows API..compulsorily?

anom
February 22nd, 2012, 11:06
There are debugging modules for python, plus there's ctypes. What else do you need?

live_dont_exist
February 22nd, 2012, 11:27
I'm not sure..I've written a total of 5 Python programs so far ... most from the Google Python class so checking. Thanks though anom.

But my earlier question is sort of still un-answered...

Quote:

The funny thing now though is that Shell32.dll has a huge number of DLLs (say > 20) under delayed imports. However, not all of them are used; as in loaded by winmine.exe ...


.... and only around 5 or 6 [Marked in Bold earlier]... are loaded. Now I understand the best way is to use Ctypes etc and do it the 'official' way as aqrit mentioned. That's fine and I'll do that. But what decides ...which subset of 'Delay Loaded DLLs' is loaded...and when?

Thnx
Arvind

live_dont_exist
March 2nd, 2012, 01:09
Right .. so I wrote some code. It basically reads the IMPORT TABLE recursively and loads all the DLLs possible. So if winmine.exe needs kernel32.dll; it will store kernel32.dll. It will then load kernel32.dll and get its dependencies which is ntdll.dll and so on. So this works...as far as the import table is concerned.

I then tried to repeat the same logic for the DELAYED IMPORTS. There were 2 problems I faced:

a) I couldn't find some DLL files; due to me hardcoding the System32 path. I am guessing I have to search in some environment variable for all possible paths where DLs can be there.
b) For whatever DLLs in the DELAY section that did get parsed; I got a huge huge list; which certainly seems to be much much more than what I can see in Olly. Looking at the previous posts here I can say that there are exactly 9 extra DLLs which I cannot explain.

I dont think (logically) its at runtime as I've not even started the file in Olly. And other PE editors like LordPE also seem to get the exact list. So I'm leaning towards - "There is some place in the PE header from where I can deduce an exact list as in all these tools". The question is where.

I'm attaching my code too. Any ideas? The password for the zip file is code123!

2556

Kayaker
March 2nd, 2012, 23:21
You can get the complete list of runtime dlls from the PEB.Ldr.InInitializationOrderModuleList / InLoadOrderModuleList / InMemoryOrderModuleList
That is what you see in Olly and other apps. LordPE won't show that if you only open the exe statically.

Here's an example for winmine (running)

Code:

kd> !process 0 1 winmine.exe
PROCESS 8969c7c8

kd> .process 8969c7c8
Implicit process is now 8969c7c8

0: kd> !peb
PEB at 7ffdd000

Ldr.InInitializationOrderModuleList: 001a1f28 . 001a2fa8
Ldr.InLoadOrderModuleList: 001a1ec0 . 001a2f98
Ldr.InMemoryOrderModuleList: 001a1ec8 . 001a2fa0
Base TimeStamp Module
1000000 3b7d8475 Aug 17 16:54:13 2001 C:\WINDOWS\system32\winmine.exe
7c900000 4d00f27d Dec 09 10:15:09 2010 C:\WINDOWS\system32\ntdll.dll
7c800000 49c4f482 Mar 21 10:06:58 2009 C:\WINDOWS\system32\kernel32.dll
77c10000 4802a188 Apr 13 20:12:56 2008 C:\WINDOWS\system32\msvcrt.dll
77dd0000 49901d48 Feb 09 07:10:48 2009 C:\WINDOWS\system32\ADVAPI32.dll
77e70000 4c68fa8c Aug 16 04:45:00 2010 C:\WINDOWS\system32\RPCRT4.dll
77fe0000 4a433476 Jun 25 04:25:26 2009 C:\WINDOWS\system32\Secur32.dll
77f10000 49006fbe Oct 23 08:36:14 2008 C:\WINDOWS\system32\GDI32.dll
7e410000 4802a11b Apr 13 20:11:07 2008 C:\WINDOWS\system32\USER32.dll
7c9c0000 4d399bd5 Jan 21 09:44:37 2011 C:\WINDOWS\system32\SHELL32.dll
77f60000 4b1e1b10 Dec 08 04:23:28 2009 C:\WINDOWS\system32\SHLWAPI.dll
76b40000 4802a13c Apr 13 20:11:40 2008 C:\WINDOWS\system32\WINMM.dll
773d0000 4c729dd1 Aug 23 12:12:01 2010 C:\WINDOWS\WinSxS\x86_Microsoft.W
indows.Common-Controls_6595b64144ccf1df_6.0.2600.6028_x-ww_61e65202\COMCTL32.dll

5cb70000 4802a114 Apr 13 20:11:00 2008 C:\WINDOWS\system32\ShimEng.dll
6f880000 4802a098 Apr 13 20:08:56 2008 C:\WINDOWS\AppPatch\AcGenral.DLL
774e0000 4eb0192e Nov 01 12:07:10 2011 C:\WINDOWS\system32\ole32.dll
77120000 4d0f931f Dec 20 12:32:15 2010 C:\WINDOWS\system32\OLEAUT32.dll
77be0000 4802a117 Apr 13 20:11:03 2008 C:\WINDOWS\system32\MSACM32.dll
77c00000 4802a11d Apr 13 20:11:09 2008 C:\WINDOWS\system32\VERSION.dll
769c0000 4802a11c Apr 13 20:11:08 2008 C:\WINDOWS\system32\USERENV.dll
5ad70000 4802a11e Apr 13 20:11:10 2008 C:\WINDOWS\system32\UxTheme.dll
76390000 4802a0e7 Apr 13 20:10:15 2008 C:\WINDOWS\system32\IMM32.DLL
10000000 4eef85d3 Dec 19 13:43:31 2011 C:\WINDOWS\system32\guard32.dll
4ffe0000 4802a0c4 Apr 13 20:09:40 2008 C:\WINDOWS\system32\fltlib.dll
5cd70000 3b7dfebb Aug 18 01:35:55 2001 C:\WINDOWS\system32\serwvdrv.dll
5b0a0000 3b7dfeb9 Aug 18 01:35:53 2001 C:\WINDOWS\system32\umdmxfrm.dll
755c0000 4802a12d Apr 13 20:11:25 2008 C:\WINDOWS\system32\msctfime.ime


ProcessParameters: 00020000



This is slightly OT, but to explain why you're seeing some of the dlls such as AcGenral.DLL and the several following dependant modules..


Note that some of the imports you see in winmine and other specific apps are loaded by dependancies due to shimeng.dll, or the Microsoft Application Compatibility Interface.

http://www.alex-ionescu.com/?p=39 (3 parts to the article)

http://www.woodmann.com/forum/showthread.php?14109-Looking-for-information-on-Shims


If you look at /%windir%/AppPatch/sysmain.sdb in a hex editor you'll see that "winmine.exe" is included there as a unicode string. As mentioned in the forum thread, the Shim Database (.sdb) file specifies the following will be applied:

NAME="AddProcessParametersFlags"
DLLFILE="AcGenral.DLL"
DESCRIPTION="Add flags to Peb-ProcessParameter-Flags


If you search for "AddProcessParametersFlags" in the following thread, we see that its purpose seems to be to apply DEP to Winmine, and will explain the
ProcessParameters: 00020000
line in the !peb output above

http://technet.microsoft.com/en-us/library/bb490630.aspx

Now if you go into Process Explorer and select View/Select Columns/Dep Status, you'll see that every MS process with DEP enabled also has AcGenral.DLL loaded. And the ones that don't, don't.


Olly seems to order dlls by Base Address, that's a little confusing if trying to make sense of where those "9 extra DLLs" you wondered about came from. Try using TopToBottomNt by SmidgeonSoft (or maybe Dependency Walker), where you can list the dll imports by InInitializationOrderModuleList / InLoadOrderModuleList / InMemoryOrderModuleList. That should make the dependancies and _why_ a specific dll was loaded make a bit more sense.

Cheers,
Kayaker

live_dont_exist
March 15th, 2012, 00:22
Thanks Kayaker. I tried doing all of this in WinDBG (which is painful after using Olly all this while ). The thing though, is that those 9 'extra' DLLs seem to get loaded only after I 'run' ( g in WinDBG) winmine.exe.

If I look at it prior to run ( !peb ) then it seems to list only a partial list (initial problem). If I run winmine and then close the app and list the PEB again, it gives the complete list. So this I guess means its not there in PEB too right from the start..and is 'handled at runtime'. My screenshots are attached too so everyone can see what exactly is going on.

I also tried DepWalker but that seems to do things I do... get a huge list of all dependencies and not just the exact list that Olly gives. And all these dependencies are internal to each DLL. The main list only contains the DLLs that are there in the IAT...just like I earlier mentioned. For e.g IMM32.DLL is 1 which is loaded by Olly and OLEACC.DLL is NOT...but both are loaded by DepWalker (as dependencies of COMCTL32), where as in Olly ... only IMM32 is loaded and not OLEACC. Screenshot attached.

This is another link that I refered - http://www.archivum.info/microsoft.public.windbg/2009-10/00044/Re-How-to-!list-and-t-LDR_DATA_TABLE_ENTRY.InMemoryOrderLinks.Flink.html

So the point still remains...Is it possible to get a complete list of DLLs before starting the EXE? Like in Olly? You're right about LordPE though...I can see the list of DLLs only after I load the file; not before.

Thanks
Arvind
p.s.. SmidgeonSoft hangs in my VM.

Kayaker
March 15th, 2012, 18:43
Try setting a breakpoint on the EP before pressing 'g', which by itself simply executes the program.

> bp $exentry
> g

or
> g @$exentry

If you want to find out what the pseudo-register $exentry (Entry Point) is, you can evaluate that expression with

> ? $exentry
Evaluate expression: 16793121 = 01003e21



The initial break in WinDbg is generally at
ntdll!DbgBreakPoint
If you step through the RET you should be in
ntdll!LdrpInitializeProcess

Trace down a few instructions and you should see
ntdll!LdrpLoadShimEngine

Step over the call and you should see in the command window the relevant shim dlls being loaded (if running Winmine or other applicable exe), or do a !peb before and after tracing over LdrpLoadShimEngine. For me there are 8 new modules loaded, starting with AcGenral.DLL and ending with UxTheme.dll.


A little further on you should see a call to
LdrpRunInitializeRoutines

Again you should see some more dlls being loaded after stepping over this call (my list starts with IMM32.dll).

So you see, there are at least 2 "places" where dlls not listed in the static PE file are loaded before ever reaching the Entry Point.


Continue tracing and you should reach ZwContinue, stepping over it will execute the program (unless you've set the $exentry breakpoint).


So to answer the question "Is it possible to get a complete list of DLLs before starting the EXE? Like in Olly?"
Yes, but you will need to let the PE Loader execute at least until ZwContinue. Maybe you'll need to code a basic debugger with which you can control execution.

Does that clear things up?

Kayaker

live_dont_exist
March 16th, 2012, 01:55
Awesome thanks. That worked exactly like you said. So effectively this means that the OS loader, at different points, loads DLLs for different purposes [Like the ShimEng DLLs as you explained earlier] into memory; in this case the PEB. This doesn't have to be a static list, like in this case [winmine.exe].

I tried replicating the exact same thing with Olly 1.10. I stopped at System Breakpoint and set breakpoints at exactly the same places as I'd set in WinDBG. That's addresses 7C9216B1 and 7C921739. This was nearly the same with 1 difference. In Olly, when I broke at 7C9216B1 (ShimEng) all the same DLLs got loaded except UxTheme.DLL and IMM32.DLL. When I broke again at 7C921739 UxTheme got loaded but IMM32 never got loaded at all. In WinDBG UxTheme.DLL was loaded on the first break and IMM32 on the 2nd break. But that apart everything seems similar.

Now what aqrit said earlier and you nowmakes sense
The "official" way is to debug the process so Windows will notify your debugger about loaded dlls. see: CreateProcess( DEBUG_PROCESS ) or DebugActiveProcess

Effectively then, similar to these calls before EntryPoint in winmine.exe, there might be "other such calls" to load "other DLLs" in "other executables". Right? In that case, I will need to modify my code and make it totally generic, so that the 'loading' automatically happens and populates the PEB. Reading the IAT from the PE header or any other static location seems to be an incomplete way to do things.

Am I correct?

Thanks so much
Arvind

Maximus
March 16th, 2012, 11:00
your question is even more complex than it seems - read this:
http://en.wikipedia.org/wiki/DLL_Hell

the 'dll hell' bugged developers since ages, and the only partial "solution" M$ found to it - you can see it in Vista/Seven, where many different copies/versions of the 'same' dlls (say MSVCxx) exists and are allocated 'on need'.
One note: if you dynamically load an exe, remember that you might give it a chance to 'escape' your debugger and execute unwanted code, even if you think it wont happen. So, if that's malware, just dont do it (unless you do it in a VM, but then it might be that... etc.)

live_dont_exist
April 4th, 2012, 12:34
I wrote a small blog summarizing all that I had learnt from this site and my reading. Do correct me if I am factually incorrect anywhere

http://ardsec.blogspot.in/2012/04/exe-dependencies-read-from-peb.html

evaluator
April 29th, 2012, 05:57
can't resist to write this direct explanation for initial question:

other DLLs, which are not linked with EXE-file, CAN be linked with DLLs, which are linked with EXE.. so on, so on..