Here i want to describe a way to display the export table from a packed software with windbg.
As far i know windbg read the symbols for a modules in two way.
From the symbols file OR from the executable.
But what happen with .exe/dll packed whois constructing is export table at run time ?
Here i show the Quick/n/Dirty way of looking at your export table. when everything fail !
I take for my example a Packed protector. this .exe is launched from a game. the exe is packed/crypted
it extract himself and export is functions after he is loaded. YES I KNOW with ollydbg it would not be hard at all
I would just have to take a look at the 'search name in current module'.
But windbg is not that friendly ,it's a small price to pay for such a powerfull debugger.
But it's possible! ok let's start!
First run "!lm"
:002> lm
start end module name
00400000 004ea000 protect (no symbols)
00bf0000 00c0a000 WinsockHookDLL C (export symbols) C:\Program Files\Secway\SimpLite-MSN 2.2\Plugins\WinsockHookDLL.dll
00e50000 00e71000 btkeyind (export symbols) C:\Program Files\WIDCOMM\Bluetooth Software\btkeyind.dll
10000000 10035000 btmmhook (export symbols) C:\Windows\system32\btmmhook.dll
6e360000 6e3d2000 Riched20 (pdb symbols) C:\Program Files\Debugging Tools for Wi
Ok we found the module name now inspect the PE header.
For this we will use "dh", dh is a cool command for inspecting PE header in memory.
Very handy when you are searching an executable image in the process address space.
:001> !dh 00400000
FILE HEADER VALUES
14C machine (i386)
3 number of sections
493D4022 time date stamp Mon Dec 08 16:41:22 2008
25D85729 file pointer to symbol table
0 number of symbols
E0 size of optional header
D03 characteristics
Relocations stripped
Executable
32 bit word machine
RESERVED - UNKNOWN
RESERVED - UNKNOWN
OPTIONAL HEADER VALUES
10B magic #
8.00 linker version
3B000 size of code
14000 size of initialized data
9A000 size of uninitialized data
D5820 address of entry point
9B000 base of code
----- new -----
00400000 image base
1000 section alignment
200 file alignment
2 subsystem (Windows GUI)
4.00 operating system version
0.00 image version
4.00 subsystem version
EA000 size of image
1000 size of headers
7B291 checksum
00100000 size of stack reserve
00001000 size of stack commit
00100000 size of heap reserve
00001000 size of heap commit
B0E50 [ 9D0] address [size] of Export Directory
E90EC [ 1D8] address [size] of Import Directory
D6000 [ 130EC] address [size] of Resource Directory
0 [ 0] address [size] of Exception Directory
6EFE8 [ 1548] address [size] of Security Directory
0 [ 0] address [size] of Base Relocation Directory
0 [ 0] address [size] of Debug Directory
0 [ 0] address [size] of Description Directory
0 [ 0] address [size] of Special Directory
0 [ 0] address [size] of Thread Storage Directory
D59D4 [ 48] address [size] of Load Configuration Directory
0 [ 0] address [size] of Bound Import Directory
0 [ 0] address [size] of Import Address Table Directory
0 [ 0] address [size] of Delay Import Directory
0 [ 0] address [size] of COR20 Header Directory
0 [ 0] address [size] of Reserved Directory
Ok so we found the address of the export directory.
....
B0E50 [ 9D0] address [size] of Export Directory
....
So what interesting at this address ??
First of all. B0E50 point to nothing ! you have to add the ImageBase (a.k.a 0040000 in our example).
0:002> dd 00400000+B0E50 <== see the imagebase added
004b0e50 00000000 493d4021 00000000 000b113e
004b0e60 00000001 00000047 00000047 000b0e78
004b0e70 000b0f94 000b10b0 00006599 00006455
004b0e80 0002db8c 0000630d 0000696d 0000745e
004b0e90 00006d1a 000061aa 00006e50 000070bc
004b0ea0 00006002 000076ca 000071f2 00007328
004b0eb0 00006f86 00006be4 00007594 000066dd
004b0ec0 00006aa3 00006825 00005eaf 000082a4
Here we dump the IMAGE_EXPORT_DIRECTORY it self.
What mean all thous fields ?
For helping us we will take a look at the structure type (available everywhere (google))
public struct IMAGE_EXPORT_DIRECTORY
{
public UInt32 Characteristics; // 00000000
public UInt32 TimeDateStamp; // 493d4021
public UInt16 MajorVersion; // 0000
public UInt16 MinorVersion; // 0000
public UInt32 Name; // 000b113e (in memory 00400000+000b113e)
public UInt32 Base; // 00000001
public UInt32 NumberOfFunctions; // 00000047
public UInt32 NumberOfNames; // 00000047
public UInt32 AddressOfFunctions; // 000b0e78
public UInt32 AddressOfNames; // 000b0f94
public UInt32 AddressOfNameOrdinals; // 000b10b0
}
Now focus on thous ones.
public UInt32 NumberOfFunctions;
public UInt32 NumberOfNames;
public UInt32 AddressOfFunctions; // RVA from base of image
public UInt32 AddressOfNames; // RVA from base of image
public UInt32 AddressOfNameOrdinals; // RVA from base of image
First Step is to extract the 'names' of the functions exported.
AddressOfNames is our man. It contains the address of an array of RVA (address relative to the ImageBase) who will point to the names
of the functions exported.
in code it would be something like that
char *AddressOfNames[]
for (i = 0; i <>
FunctionName = AddressOfNames[ i ]
Now extract the RVA's convert em and print the name!
**Remenber** 'UInt32 AddressOfNames == 000b0f94 ' So for getting the real address add 0x0040000
0:002> .for ( r $t0 = 0; @$t0 < t0 =" @$t0">
004b114a "PSA_CheckFeaturesGrantedByLicense"
004b116c "PSA_DisableFeaturesGrantedByLicense"
004b1190 "PSA_DummyFunction"
004b11a2 "PSA_GetFeaturesGrantedByLicense" <== position 3
004b11c2 "PSA_GetLicenseCreationDateTime"
004b11e1 "PSA_GetLicenseExecutionTimeLimit"
004b1202 "PSA_GetLicenseExpirationDateTime"
004b1223 "PSA_GetLicenseInformation"
004b123d "PSA_GetLicenseLifeTimeLimit"
004b1259 "PSA_GetLicenseNumberOfRunsLimit"
004b1279 "PSA_GetLicenseStoragePath"
004b1293 "PSA_GetNumberOfConnections"
....
Here we get a nice list of function names!
But to which address in the executable code they below ?
For the associated the name to the address in the executable code there is a trick,
Let's take "PSA_GetFeaturesGrantedByLicense", this function is at position 3 [0, 1, 2, 3] into the Array of RVA of names.
you will then extract the value at position 3 in the AddressOfNameOrdinals Array
**NOTE**: this Array use 16 bits menbers
// pseudo code: index_address = UNSIGNED SHORT AddressOfNameOrdinals [ 3 ]
Dump this array!
0:002> .for ( r $t0 = 0; @$t0 < (0x11C/2) ; r $t0 = @$t0 + 2) { dw /c 2 00400000+b10b0+@$t0 l1 }
004b10b0 0000
004b10b2 0001
004b10b4 0002
004b10b6 0003 <== Our Index in AddressOfFunctions
Has you see the Index for our function is 3 too. Now let's see at AddressOfFunction[3].
0:002> .for ( r $t0 = 0; @$t0 < t0 =" @$t0" t1 =" poi(00400000+b0e78+@$t0)+0x00400000">
00406599
00406455
0042db8c
0040630d <== *Gottcha*! our function "PSA_GetFeaturesGrantedByLicense"
0040696d
0040745e
Now you know that's "PSA_GetFeaturesGrantedByLicense" is located at 0x0040630d
There really nothing complicated in the windbg commands i showed to you.
Just remenber to add 0x00400000 (ImageBase of our module) for converting RVA to real address in the process.
Beside that's the ".for" command in wingdb is working like in C.
For reversing purpose, i would add a breakpoint instead of a printf into each address exported.
You could ofcourse do all thous step in one command but i wanted to show it step by step.
Oh... for a reminder and because it's a VERY VERY COMMON question but there is not much information about it
for knowing wich functions are imported from a module.
(showing Import table)
BONUS !
*** How to display the import table of a process with windbg ? ***
Get the address of the import table directory with "!dh"
...
94BC0 [ 1000] address [size] of Import Address Table Directory
...
Retrieve the address of the IAT (Import Table Address) convert it to the real address in memory
/* IAT address is a RVA in the PE header (Relative Memory Address) */
and use the command "dps" (display symbols)
dps 0x00400000+94BC0 l1000/8
NOTE: the /8 mean to take a step of 8 when incrementing the address's displayed (we dont care of the second member of Image Import Name)
that's will print something like that...
...
005fb3cc 76aa52da ADVAPI32!CryptAcquireContextA
005fb3d0 76aa59cc ADVAPI32!CryptGenRandom
005fb3d4 76a99aa5 ADVAPI32!DeregisterEventSource
005fb3d8 76abf429 ADVAPI32!RegCloseKey
005fb3dc 76aad4e8 ADVAPI32!RegOpenKeyExA
005fb3e0 76aad639 ADVAPI32!RegQueryValueExA
005fb3e4 76a98696 ADVAPI32!RegisterEventSourceA
005fb3e8 76a8888d ADVAPI32!ReportEventA
005fb3ec 00000000
005fb3f0 00000000
005fb3f4 770f6ce7 GDI32!BitBlt
005fb3f8 770f693f GDI32!CreateCompatibleBitmap
005fb3fc 770f64cb GDI32!CreateCompatibleDC
005fb400 770fac01 GDI32!CreateDCA
005fb404 770f6a44 GDI32!DeleteDC
005fb408 770f5bed GDI32!DeleteObject
005fb40c 770fbeaa GDI32!GetBitmapBits
VOILA ! that's all !
I know i was suposed to talk about tracing (call flow tracing)
But this post was my surprise ;)
Get wired!
-anti
PS: Take a look of the wonderfull tutorial from Iczellion's it's unvaluable !!!!
No comments:
Post a Comment