1. Overview
A Dynamic-link library, or DLL, file is a shared library used on Windows that contains functions and data. Like other executables on Windows, DLL files are of the Portable Executable (PE) file format. PE files have a variety of data in their file headers, which include import tables and export tables.
Import tables are an array of functions and data that the PE file includes from other shared libraries. Export tables are an array of functions and data contained within the PE file wishes to provide to the outside world. These are different than internal functions, which the PE file uses internally.
There are many reasons to need the export data of a DLL file. One of them is so that we can write a program that makes use of the functions in the DLL program. On Linux, we can use a few different tools to extract the export table of a DLL file.
In this tutorial, we’re going to discuss how to extract exported symbols using these tools, which consist of a few different command-line tools and a Python module as well.
2. Wine
Wine is a compatibility tool that aims to run windows programs on POSIX-compliant systems, like Linux. It also comes with a set of supporting tools to work with PE files.
The winedump tool for interacting with DLL PE files. We can use the winedump command to display information about a PE file.
A PE file stores its exported symbols in its export address table. The PE file then stores its export address table in the “export” section of the PE file.
Let’s install winedump:
sudo apt-get install wine64-tools
We use the -j option to display the exported symbols in the export section:
$ winedump -j export kernel32.dll
Contents of kernel32.dll: 725696 bytes
Exports table:
Name: KERNEL32.dll
[...]
Entry Pt Ordn Name
0009417F 1 AcquireSRWLockExclusive (-> NTDLL.RtlAcquireSRWLockExclusive)
000941B5 2 AcquireSRWLockShared (-> NTDLL.RtlAcquireSRWLockShared)
0001E860 3 ActivateActCtx
0001A570 4 ActivateActCtxWorker
00021A70 5 AddAtomA
0000FE30 6 AddAtomW
00022DE0 7 AddConsoleAliasA
00022DF0 8 AddConsoleAliasW
0009423B 9 AddDllDirectory (-> api-ms-win-core-libraryloader-l1-1-0.AddDllDirectory)
000375A0 10 AddIntegrityLabelToBoundaryDescriptor
00053150 11 AddLocalAlternateComputerNameA
000531B0 12 AddLocalAlternateComputerNameW
00020570 13 AddRefActCtx
0001E3C0 14 AddRefActCtxWorker
00035FB0 15 AddResourceAttributeAce
0001F3C0 16 AddSIDToBoundaryDescriptor
00035FC0 17 AddScopedPolicyIDAce
00034600 18 AddSecureMemoryCacheCallback
00094374 19 AddVectoredContinueHandler (-> NTDLL.RtlAddVectoredContinueHandler)
000943B4 20 AddVectoredExceptionHandler (-> NTDLL.RtlAddVectoredExceptionHandler)
0001A6B0 21 AdjustCalendarDate
00022A30 22 AllocConsole
[...]
00019E40 1614 lstrlen
00019E40 1615 lstrlenA
00017930 1616 lstrlenW
0001D240 1617 timeBeginPeriod
0001C2F0 1618 timeEndPeriod
00020470 1619 timeGetDevCaps
00061590 1620 timeGetSystemTime
0001CFE0 1621 timeGetTime
0001A510 1622 uaw_lstrcmpW
00017950 1623 uaw_lstrcmpiW
00033380 1624 uaw_lstrlenW
000333D0 1625 uaw_wcschr
000333F0 1626 uaw_wcscpy
00033420 1627 uaw_wcsicmp
00033430 1628 uaw_wcslen
00033450 1629 uaw_wcsrchr
Done dumping kernel32.dll
3. Radare2
Radare2 is a UNIX-like reverse engineering framework. The Radare2 framework also comes with a set of command-line tools to work with binaries. We can use Radare2 on both Linux and Windows, and it supports the PE file format.
Thus, we can use the rabin2 tool to extract program info from a binary of our choosing.
Let’s install radare2 and rabin2 first:
$ sudo apt-get install radare2
We use the -s option to show the exported symbols of a PE file on the command line:
$ rabin2 -s kernel32.dll
[Symbols]
000 0x0009277f 0x18009417f GLOBAL FUNC 0 KERNEL32.dll_AcquireSRWLockExclusive
001 0x000927b5 0x1800941b5 GLOBAL FUNC 0 KERNEL32.dll_AcquireSRWLockShared
002 0x0001dc60 0x18001e860 GLOBAL FUNC 0 KERNEL32.dll_ActivateActCtx
003 0x00019970 0x18001a570 GLOBAL FUNC 0 KERNEL32.dll_ActivateActCtxWorker
004 0x00020e70 0x180021a70 GLOBAL FUNC 0 KERNEL32.dll_AddAtomA
005 0x0000f230 0x18000fe30 GLOBAL FUNC 0 KERNEL32.dll_AddAtomW
[...]
Also, we need to be aware that the exported symbols from rabin2 are shown a bit differently from the output of winedump.
4. objdump
objdump is a tool that we can use to dump information about binary files. The PE file format is one of the formats supported by the objdump tool.
Let’s install objdump first:
$ sudo apt-get install binutils
Now, we can use objdump to dump the export address table of a PE file:
$ objdump -p kernel32.dll
kernel32.dll: file format pei-x86-64
[...]
The Data Directory
Entry 0 0000000000090190 0000dd40 Export Directory [.edata (or where ever we found it)]
[Ordinal/Name Pointer] Table
[ 0] AcquireSRWLockExclusive
[ 1] AcquireSRWLockShared
[ 2] ActivateActCtx
[ 3] ActivateActCtxWorker
[ 4] AddAtomA
[ 5] AddAtomW
[...]
A disadvantage of using objdump for this is that the export table is shown alongside other information about the PE. Thus, we would need to parse out the lines pertaining to the exported symbols if we wanted to process it more.
We also need to be aware that we may have thousands of lines of data as output, and so we may need to grep and parse accordingly.
5. pefile
Finally, pefile is a python module that we can use to work with PE files.
Let’s install the pefile module using pip:
$ pip3 install pefile
We can use the “exports” flag to dump the exports of a DLL file:
$ python3 -m pefile exports kernel32.dll
0x18009417f b'AcquireSRWLockExclusive' 1
0x1800941b5 b'AcquireSRWLockShared' 2
0x18001e860 b'ActivateActCtx' 3
0x18001a570 b'ActivateActCtxWorker' 4
0x180021a70 b'AddAtomA' 5
[...]
Additionally, we can remove the “b” from the beginning of the symbol names with a one Python liner:
$ python3 -c 'import sys;import pefile;pe = pefile.PE(sys.argv[1]);wr = sys.stdout.write; [wr("%s %s %i\n"%(hex(pe.OPTIONAL_HEADER.ImageBase + exp.address), exp.name.decode("utf-8"), exp.ordinal)) for exp in pe.DIRECTORY_ENTRY_EXPORT.symbols]' kernel32.dll
0x18009417f AcquireSRWLockExclusive 1
0x1800941b5 AcquireSRWLockShared 2
0x18001e860 ActivateActCtx 3
0x18001a570 ActivateActCtxWorker 4
0x180021a70 AddAtomA 5
[...]
Lastly, one thing we should note is that we do need Python on our Linux system to make use of the pefile module.
6. Conclusion
In this article, we looked at using the winedump command-line tool that is part of the wine tool to show exported symbols of a DLL.
Then, we looked at using the rabin2 tool from the Radare2 reverse engineering toolset. After this, we covered using the objdump tool to show information about a PE file.
Finally, we covered using the pefile Python module to extract information from a DLL. We can use any of these options to find out what symbols a DLL file exports on Linux.