Is it possible to examine a dll, not installed in the registry, to see if it an ActiveX, the public methods, if it supports COM, etc. Is there some other tool with which to analyze a dll?
That's a very generic question, but you can analyze a dll's exported methods and ASM code using some decompiler/debugger like OllyDbg. Of course you need to have a good understanding of ASM and Windows inner workings.
http://www.ollydbg.de/version2.html
if you have Visual Studio and just want to know if the dll contains a COM component, you can open the visual studio command prompt, and use:
dumpbin /exports filename.dll
to show the dll's exported functions. If the dll exports DllGetClassObject, DllRegisterServer and DllUnregisterServer, it contains a COM component.
Example:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC>dumpbin /exports c:\windows\system32\quartz.dll
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file c:\windows\system32\quartz.dll
File Type: DLL
Section contains the following exports for QUARTZ.dll
00000000 characteristics
5215E909 time date stamp Thu Aug 22 12:33:45 2013
0.00 version
1 ordinal base
8 number of functions
8 number of names
ordinal hint RVA name
1 0 0003B34C AMGetErrorTextA
2 1 0003B41C AMGetErrorTextW
3 2 0003B2C8 AmpFactorToDB
4 3 0003B314 DBToAmpFactor
5 4 00002848 DllCanUnloadNow
6 5 000032E0 DllGetClassObject
7 6 0003AFA0 DllRegisterServer
8 7 0003B2A0 DllUnregisterServer
Summary
36000 .data
4000 .idata
F000 .pdata
4000 .reloc
B000 .rsrc
157000 .text
1000 RT_CODE
Related
I created a simple console application in both .NET Framework 4.8 and .NET 5 (same code in both), but symbols resolve differently across various debugging tools.
If I run both applications, launch Process Hacker, open the process's properties, click on the Threads tab, and open the Stack for the primary managed thread, the .NET 4.8 Stack shows resolved symbols for my classes and methods, but the .NET 5 Stack does not -- it shows hex strings like 0x7ffbac6087a3.
In both cases, calls to System.Console.dll!System.Console.ReadKey() resolve correctly, so I know I have my symbol loading configured correctly (_NT_SYMBOL_PATH = "srv*C:\Source\symbols*https://msdl.microsoft.com/download/symbols"). In both cases, the projects are configured for full debug type and to include debug symbols. In both cases, there is a .pdb to go along with the .exe.
Sysinternals Process Explorer won't display any of that - the bottom of the call stack is 0x0.
If I take a dump of the applications, I can load them into WinDbg Preview and am able to see all of my code as expected. For the .NET 5 application, the normal Stack shows the same thing as Process Hacker (e.g. 0x7ffbac6087a3), but if I run the command !CLRStack -a, those hex values get properly resolved (e.g. 000000BD4F17E840 00007ffbac6087a3 SymbolsCoreConsoleApp.Program.Run() [C:\Source\research\SymbolsCore\SymbolsCoreConsoleApp\Program.cs # 18]).
So, there's the background. Here are the questions:
1.) Why doesn't the Process Hacker Stack resolve symbols for my classes in a .NET 5 application, but it does for the exact same code in a .NET Framework 4.8 application?
2.) Why doesn't Sysinternals Process Explorer display any of my code (just 0x0) for either application? In case it matters, I run procexp64.exe and my machine is x64 Windows 10 Enterprise. If I run 'procexp.exe`, it ultimately launches the x64 version anyhow. Mentioning this in case there is an issue with 32 vs. 64 bit.
3.) Both Process Hacker and Process Explorer have process tabs specifically for .NET (e.g. .NET assemblies and .NET performance), and those tabs only show up for the .NET Framework 4.8 application, but not for the .NET 5 application. Is this by-design or do I have something configured wrong?
4.) In WinDbg Preview, is this behavior by-design? If so, why?
5.) Are there other special things to consider when debugging/analyzing .NET 5/Core applications outside of Visual Studio?
That's a lot of questions, but they're all closely related, and I suspect there may be some fundamental thing(s) that I'm missing here.
Thanks in advance!
EDIT: 20210803 10:55 AM CDT
Per magicandre1981's comment, I installed the nightly of Process Hacker (v3.0.4234).
It still doesn't resolve those symbols.
It does show .NET assemblies and .NET performance tabs for the .NET 5 application now, but there are no values on the .NET performance tab.
EDIT: 20210803 05:05 PM CDT
I ran symchk and dumpbin against both of the applications in case this will help anyone diagnose the problem.
.NET 5
net5.0> $> pwd
C:\Source\research\SymbolsCore\SymbolsCoreConsoleApp\bin\Debug\net5.0
net5.0> $> & 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symchk.exe' .\SymbolsCoreConsoleApp.exe /r
SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 1
net5.0> $> & 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x64\dumpbin.exe' /PDBPATH:VERBOSE .\SymbolsCoreConsoleApp.exe
Microsoft (R) COFF/PE Dumper Version 14.29.30040.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file .\SymbolsCoreConsoleApp.exe
File Type: EXECUTABLE IMAGE
PDB file 'C:\Source\research\SymbolsCore\SymbolsCoreConsoleApp\bin\Debug\net5.0\apphost.pdb' checked. (File not found)
PDB file 'D:\workspace\_work\1\s\artifacts\obj\win-x64.Release\corehost\cli\apphost\standalone\Release\apphost.pdb' checked. (File not found)
PDB file 'C:\WINDOWS\symbols\exe\apphost.pdb' checked. (File not found)
PDB file 'C:\WINDOWS\exe\apphost.pdb' checked. (File not found)
PDB file 'C:\WINDOWS\apphost.pdb' checked. (File not found)
Summary
2000 .data
2000 .pdata
9000 .rdata
1000 .reloc
1000 .rsrc
14000 .text
1000 _RDATA
net5.0> $> & 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symchk.exe' .\SymbolsCoreConsoleApp.dll /r
SYMCHK: SymbolsCoreConsoleApp.dll FAILED - SymbolsCoreConsoleApp.pdb mismatched or not found
SYMCHK: SymbolsCoreConsoleApp.dll FAILED - No CodeView information found.
SYMCHK: FAILED files = 2
SYMCHK: PASSED + IGNORED files = 0
net5.0> $> & 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x64\dumpbin.exe' /PDBPATH:VERBOSE .\SymbolsCoreConsoleApp.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30040.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file .\SymbolsCoreConsoleApp.dll
File Type: EXECUTABLE IMAGE
PDB file found at 'C:\Source\research\SymbolsCore\SymbolsCoreConsoleApp\bin\Debug\net5.0\SymbolsCoreConsoleApp.pdb'
Summary
2000 .reloc
2000 .rsrc
2000 .text
.NET 4.8
Debug> $> pwd
C:\Source\research\SymbolsFramework\SymbolsFrameworkConsoleApp\bin\Debug
Debug> $> & 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\symchk.exe' .\SymbolsFrameworkConsoleApp.exe /r
SYMCHK: SymbolsFrameworkConsoleApp.exe FAILED - SymbolsFrameworkConsoleApp.pdb mismatched or not found
SYMCHK: FAILED files = 1
SYMCHK: PASSED + IGNORED files = 0
Debug> $> & 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x64\dumpbin.exe' /PDBPATH:VERBOSE .\SymbolsFrameworkConsoleApp.exe
Microsoft (R) COFF/PE Dumper Version 14.29.30040.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file .\SymbolsFrameworkConsoleApp.exe
File Type: EXECUTABLE IMAGE
PDB file found at 'C:\Source\research\SymbolsFramework\SymbolsFrameworkConsoleApp\bin\Debug\SymbolsFrameworkConsoleApp.pdb'
Summary
2000 .reloc
2000 .rsrc
2000 .text
EDIT: 20210803 07:54 PM CDT
Per hanpassant's comment, here is the project file (it already had the DebugType set to full).
SymbolsCoreConsoleApp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
</Project>
EDIT: 20210803 08:40 PM CDT
Here are a few screenshots in case it wasn't clear from my explanation.
Notice the 0x7xfbb03a8 addresses instead of resolved symbols.
Notice the resolved symbols for SymbolsFramework.ConsoleApp.Program instead of the unresolved 0x7xfbb03a8 addresses.
Notice the 0x0 address instead of any resolved symbols.
The .NET Assemblies tab shows up for .NET 5 and appears to populate correctly.
The .NET Performance tab shows up for .NET 5, but it has no values.
I opened an issue with Process Hacker on GitHub and it was closed a few days back with a fix in the nightly build. I confirmed that it now works as expected.
I'm building zlib from source using Visual Studio 2012. Note, I didn't tag zlib here simply because I don't think the question is specific to any given project.
The build succeeds but when I use dumpbin /EXPORTS the output looks like this:
C:\Source\zlib>dumpbin /EXPORTS ./zlib1.dll
Microsoft (R) COFF/PE Dumper Version 11.00.61232.400
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file ./zlib1.dll
File Type: DLL
Section contains the following exports for zlib1.dll
00000000 characteristics
5DD6A00D time date stamp Thu Nov 21 08:32:45 2019
0.00 version
1 ordinal base
165 number of functions
119 number of names
ordinal hint RVA name
1 1 00001000 adler32
140 2 00001340 adler32_combine
2 3 00001410 compress
39 4 00001360 compress2
46 5 00001430 compressBound
However, when I examine a version someone else built (using VC6 - not sure if that matters), the output looks like:
C:\Source\zlib-1.2.7-win32>dumpbin /EXPORTS ./zlib1.dll
Microsoft (R) COFF/PE Dumper Version 11.00.61232.400
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file ./zlib1.dll
File Type: DLL
Section contains the following exports for zlib1.dll
00000000 characteristics
509EFCCB time date stamp Sat Nov 10 19:18:03 2012
0.00 version
1 ordinal base
76 number of functions
76 number of names
ordinal hint RVA name
1 0 00001000 adler32 = _adler32
2 1 00001270 adler32_combine = _adler32_combine
3 2 00001340 adler32_combine64 = _adler32_combine64
4 3 00001400 compress = _compress
5 4 00001360 compress2 = _compress2
6 5 00001420 compressBound = _compressBound
I'm having problems finding the visual studio setting that changes this output type. Next I tried just changing the .def file from
LIBRARY
; zlib data compression and ZIP file I/O library
VERSION 1.2
EXPORTS
adler32 #1
to
LIBRARY
; zlib data compression and ZIP file I/O library
VERSION 1.2
EXPORTS
_adler32=adler32 #1
But that appears to simply rename the export so instead of getting:
ordinal hint RVA name
1 0 00001000 adler32 = _adler32
I get:
ordinal hint RVA name
1 0 00001000 _adler32
and if you switch them around in the .def file, the project doesn't build/link correctly(makes sense).
So is there a setting in newer (than VC6) versions of VS that give /EXPORTS in the format somefunc=_somefunc?
According to this answer (C++ DLL Export: Decorated/Mangled names), they must have used Generate Debug Info = Yes
How do I interpret the CorFlags flags and how should I use it to determine if a .NET assembly was built for x86 or x64?
Could it be the following?
corflags MyAssembly.dll
Microsoft .NET 4.5 introduced a new option, Any CPU 32-bit Preferred. In the new version of CorFlags.exe, the 32BIT flag no longer exists, instead, two new flags were added, 32BITREQ and 32BITPREF.
Somewhere based on the below explanation, we can interpret new CorFlags as follows.
CPU Architecture PE 32BITREQ 32BITPREF
------------------------ ----- -------- ---------
x86 (32-bit) PE32 1 0
x64 (64-bit) PE32+ 0 0
Any CPU PE32 0 0
Any CPU 32-Bit Preferred PE32 0 1
Flags displayed by the CorFlags.exe located at C:\Program Files
(x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools
Version : Assembly's target framework.
Header : 2.0/2.5 (Must have version of 2.5 or greater to run natively)
PE : PE32 (32-bit)/PE32+ (64-bit)
CorFlags : Hexadecimal value, computed based on below 4 flags.
ILONLY : 1 if MSIL otherwise 0
32BITREQ : 1 if 32-bit x86 only assembly otherwise 0
32BITPREF : 1 if 32-bit x86 only preferred in Any CPU architecture otherwise 0
Signed : 1 if signed with strong name otherwise 0
The following example illustrates the output of C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools\CorFlags.exe for different assemblies.
PresentationCore.dll from GAC_32
CorFlags.exe "C:\Windows\Microsoft.NET\assembly\GAC_32\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll"
Version : v4.0.30319
CLR Header: 2.5
PE : PE32
CorFlags : 0xb
ILONLY : 1
32BITREQ : 1
32BITPREF : 0
Signed : 1
System.Data.dll from GAC_64
CorFlags.exe "C:\Windows\Microsoft.NET\assembly\GAC_64\System.Data\v4.0_4.0.0.0__b77a5c561934e089\System.Data.dll"
Version : v4.0.30319
CLR Header: 2.5
PE : PE32+
CorFlags : 0x18
ILONLY : 0
32BITREQ : 0
32BITPREF : 0
Signed : 1
System.dll from GAC_MSIL
CorFlags.exe "C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll"
Version : v4.0.30319
CLR Header: 2.5
PE : PE32
CorFlags : 0x9
ILONLY : 1
32BITREQ : 0
32BITPREF : 0
Signed : 1
To know more about Any CPU 32-bit Preferred assemblies refer
What AnyCPU Really Means As Of .NET 4.5 and Visual Studio 11
Open the Visual Studio Command Prompt (in Windows: menu Start → Programs → Microsoft Visual Studio → Visual Studio Tools → Visual Studio 2010 Command Prompt)
CD to the directory containing the DLL in question.
Run corflags like this:
corflags MyAssembly.dll
The output looks like this:
Microsoft (R) .NET Framework CorFlags Conversion Tool. Version 4.0.30319.1
Copyright (c) Microsoft Corporation. All rights reserved.
Version : v4.0.30319
CLR Header: 2.5
PE : PE32
CorFlags : 1
ILONLY : 1
32BIT : 0
Signed : 0
The flags' interpretation:
Any CPU: PE = PE32 and 32BIT = 0
x86: PE = PE32 and 32BIT = 1
64-bit: PE = PE32+ and 32BIT = 0
To add more detail to the other answers, the actual important value is the hexadecimal CorFlags value since it carries the most information. Here's the list of bits that comprise it:
[Flags]
public enum CorFlags
{
ILOnly = 0x00000001,
Requires32Bit = 0x00000002,
ILLibrary = 0x00000004,
StrongNameSigned = 0x00000008,
NativeEntryPoint = 0x00000010,
TrackDebugData = 0x00010000,
Prefers32Bit = 0x00020000,
}
Corflags outputs the four bits of this value separately (ILONLY, 32BITREQ, 32BITPREF and Signed). However the full CorFlags value also contains information about whether the assembly is strong-name signed or delay signed (0x8 bit) as well as ILLibrary, NativeEntryPoint and TrackDebugData bits (I don't know what those mean).
Note that CorFlags output Signed is not exactly the StrongNameSigned bit. It will print Signed 1 if the assembly is either delay-signed or fully signed, whereas StrongNameSigned bit is set if the assembly is fully signed only.
You can also use this table:
CPU | PE | 32BIT
----------|-------|------
x86 | PE32 | 1
Any CPU | PE32 | 0
x64 | PE32+ | 0
I have been scouring the web trying to find an answer to this question, but it seems to be eluding me. I have consulting the following sources before asking this question.
http://www.csn.ul.ie/~caolan/publink/winresdump/winresdump/doc/pefile.html
http://msdn.microsoft.com/en-us/magazine/cc301805.aspx
I understand the PE format (or at least I think I do). Using the command-line debugger (cdb), I would like to be able to disassemble the address where the RVA is to see what the first call is. For a native application (like Notepad), I would expect to see notepad!WinMainCRTStartup, and for a .NET application, I would expect to see a jmp command to the CLR.
Using Notepad as an example, I executed dumpbin /headers on it, and got a value of 3570 for the entry point. When I execute cdb notepad and perform this command - u [base address in memory]+0x3570 - I do not get the WinMainCRTStartup call.
Am I misinterpreting the PE output from dumpbin? How can I know exactly where to look in memory for the starting function of an application?
Edit (1/7/13): I forgot to mention that I am running this on 64-bit Windows 7. If I try to use cdb in Windows XP Mode (to get results from a 32-bit OS), disassembling the AddressOfEntryPoint that I get from an analysis of the PE file gets me the call to WinMainCRTStartup as I would expect. In other words, the exact address I am told to look at contains what I think it should in a 32-bit OS. Does running the application on a 64-bit machine truly make that much of a difference?
Just to add complexity, if I do a !dh on the ImageBaseAddress in the 64-bit OS in cdb, I get the EXACT AddressOfEntryPoint that I need to use.
Use the Microsoft Symbol Server to obtain symbol debugging information. http://support.microsoft.com/kb/311503/en-us
0:001> !dh -a notepad
....
3689 address of entry point
...
00ac0000 image base
...
0:001> u ac3689
notepad!WinMainCRTStartup:
Edit: add dumpbin output (entry point the same offset, image base may be different because ASLR works when image loads in memory):
Microsoft (R) COFF/PE Dumper Version 11.00.50727.1
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file c:\windows\notepad.exe
PE signature found
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (x86)
4 number of sections
4A5BC60F time date stamp Tue Jul 14 03:41:03 2009
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
102 characteristics
Executable
32 bit word machine
OPTIONAL HEADER VALUES
10B magic # (PE32)
9.00 linker version
A800 size of code
22400 size of initialized data
0 size of uninitialized data
3689 entry point (01003689) _WinMainCRTStartup
Edit 2 add output for x64
dumpbin:
Microsoft (R) COFF/PE Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file c:\windows\notepad.exe
PE signature found
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
8664 machine (x64)
6 number of sections
4A5BC9B3 time date stamp Tue Jul 14 03:56:35 2009
0 file pointer to symbol table
0 number of symbols
F0 size of optional header
22 characteristics
Executable
Application can handle large (>2GB) addresses
OPTIONAL HEADER VALUES
20B magic # (PE32+)
9.00 linker version
A800 size of code
25800 size of initialized data
0 size of uninitialized data
3570 entry point (0000000100003570) WinMainCRTStartup
windbg:
0:000> !dh -a notepad
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
8664 machine (X64)
...
1000 base of code
----- new -----
00000000ff0c0000 image base
...
0:000> u ff0c0000+3570
notepad!WinMainCRTStartup:
Does anyone know whether the 'import address table' in the PE executable format on Windows is 'per dll' or 'per exe'?
Any PE can have an import address table, so both DLLs and EXEs can have them. This makes sense since both can have dependencies (imports) on other binaries. Unless you're doing dynamic loading (LoadLibrary/GetProcAddress), you'll have an import address table when calling into another module.
You can use the dumpbin utility with Visual Studio to see the imports of a PE:
An example on user32.dll:
C:\Windows\System32> dumpbin /imports
user32.dll
Microsoft (R) COFF/PE
Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation.
All rights reserved.
Dump of file user32.dll
File Type: DLL
Section contains the following
imports:
ntdll.dll
7DC60000 Import Address Table
7DCCACEC Import Name Table
0 time date stamp
0 Index of first forwarder reference
15A NtOpenKey
7A9 wcscat_s
7AD wcscpy_s
...
...and for notepad.exe...
C:\Windows\System32> dumpbin /imports
notepad.exe
Microsoft (R) COFF/PE
Dumper Version 10.00.30319.01
Copyright (C) Microsoft Corporation.
All rights reserved.
Dump of file notepad.exe
File Type: EXECUTABLE IMAGE
Section contains the following
imports:
ADVAPI32.dll
1001000 Import Address Table
100A234 Import Name Table
FFFFFFFF time date stamp
FFFFFFFF Index of first forwarder reference
77C71C82 27E RegSetValueExW
77C7BCD5 26E RegQueryValueExW
77C7BED4 230 RegCloseKey
...
Short answer:
IAT(Import Address Table) is per PE file(dll and exe).
Long answer:
When the loader load exe file its copy each section of the PE to the process memory, unless IMAGE_SCN_MEM_DISCARDABLE is set for this sections. The IAT is in the .idata section (msdn):
The PE file's .idata section contains the information necessary for the loader to determine the addresses of the target functions and patch them into the executable image. The .idata section (or import table, as I prefer to call it) ...
IMAGE_SCN_MEM_DISCARDABLE is not set for idata section. Therefore- idata section copied to memory, and both exe and dll have this section- meaning IAT is per PE.
I wrote a simple dll loader here, if it help you understand.