-
Notifications
You must be signed in to change notification settings - Fork 0
/
PEListImports.c
343 lines (284 loc) · 10.9 KB
/
PEListImports.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
/* list_imports -- list imports of PE files in command line
*
* usage:
* PEListImports <pe_executable_name>...
*/
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
static debugmode;
/* decide whether to dump debug-output */
/* dump of import directory */
/* section begins at pointer 'section base'
* section RVA is 'section_rva'
* import directory begins at pointer 'imp'
* I left out all the bound/unbound stuff, and left out support for broken Borland linkers
* (see 'pe_map.c' for complete version)
*/
static int dump_import_directory(const void *const section_base, const DWORD section_rva, const IMAGE_IMPORT_DESCRIPTOR * imp)
{
/* get memory address given the RVA */
#define adr(rva) ((const void*)((char*)section_base+((DWORD)(rva))-section_rva))
/* continue until address inaccessible or there's no DLL name */
for (; !IsBadReadPtr(imp, sizeof(*imp)) && imp->Name; imp++)
{
const IMAGE_THUNK_DATA *import_entry;
/* output DLL's name */
printf("\nfrom \"%s\":\n", (char *)adr(imp->Name));
if(debugmode)
printf("name table at %#lx, address table at %#lx\n",(unsigned long)imp->OriginalFirstThunk,(unsigned long)imp->FirstThunk);
import_entry = adr(imp->OriginalFirstThunk);
/* listing header */
printf("%6s %s\n", "hint", "name");
printf("%6s %s\n", "----", "----");
/* loop to enumerate imported functions
* ends when 0-bytes in name/ordinal found
*/
for (; import_entry->u1.Ordinal; import_entry++)
{
/* nameless import */
if (IMAGE_SNAP_BY_ORDINAL(import_entry->u1.Ordinal))
printf("%6lu <ordinal>\n", IMAGE_ORDINAL(import_entry->u1.Ordinal));
else
{ /* import with name */
const IMAGE_IMPORT_BY_NAME *name_import = adr(import_entry->u1.AddressOfData);
/* careful string output - some DLLs have horrible names */
printf("%6u %-20.50s\n", name_import->Hint, name_import->Name);
}
}
}
/* was the loop ended because memory was not readable? */
if (IsBadReadPtr(imp, sizeof(*imp)))
{
puts("!! import directory ended unexpectedly !!");
return 1;
}
#undef adr
return 0;
}
/* load a file in RAM (memory-mapped)
* return pointrer to loaded file
* 0 if no success
*/
static void *get_mapped_file(const char *filename)
{
HANDLE hFile, hMapping;
void *basepointer;
if ((hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0)) == INVALID_HANDLE_VALUE)
{
if(debugmode) puts("(could not open)");
return 0;
}
if (!(hMapping = CreateFileMapping(hFile, 0, PAGE_READONLY | SEC_COMMIT, 0, 0, 0)))
{
if(debugmode) puts("(mapping failed)");
CloseHandle(hFile);
return 0;
}
if (!(basepointer = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0)))
{
if(debugmode) puts("(view failed)");
CloseHandle(hMapping);
CloseHandle(hFile);
return 0;
}
CloseHandle(hMapping);
CloseHandle(hFile);
return basepointer;
}
/* this will return a pointer immediatly behind the DOS-header
* 0 if error
*/
static void * skip_dos_stub(const IMAGE_DOS_HEADER * dos_ptr)
{
/* look there's enough space for a DOS-header */
if (IsBadReadPtr(dos_ptr, sizeof(*dos_ptr)))
{
puts("not enough space for DOS-header");
return 0;
}
/* validate MZ */
if (dos_ptr->e_magic != IMAGE_DOS_SIGNATURE)
{
puts("not a DOS-stub");
return 0;
}
/* ok, then, go get it */
return (char*)dos_ptr + dos_ptr->e_lfanew;
}
/* find the directory's section index given the RVA
* Returns -1 if impossible
*/
static int get_directory_index(const unsigned dir_rva, const unsigned dir_length, const int number_of_sections, const IMAGE_SECTION_HEADER *sections)
{
int sect;
int index = -1;
for(sect=0;sect<number_of_sections;sect++)
{
/* output section data */
if(debugmode)
printf("section \"%.*s\": RVA %#lx, offset %#lx, length %#lx\n",
(int)IMAGE_SIZEOF_SHORT_NAME,
sections[sect].Name,
(unsigned long)sections[sect].PointerToRawData,
(unsigned long)sections[sect].VirtualAddress,
(unsigned long)sections[sect].SizeOfRawData
);
/* compare directory RVA to section RVA */
if(sections[sect].VirtualAddress<=dir_rva && dir_rva<sections[sect].VirtualAddress+sections[sect].SizeOfRawData)
{
if(debugmode)
{
puts(" (taken this one)");
index = sect;
}
else
return sect;
}
}
return index;
}
/* dump imports of a single file
* Returns 0 if successful, !=0 else
* *** action starts here ***
*/
static int process_file(const char *filename)
{
const void *basepointer; /* Points to loaded PE file
* This is memory mapped stuff
*/
int number_of_sections;
DWORD import_rva; /* RVA of import directory */
DWORD import_length; /* length of import directory */
int import_index; /* index of section with import directory */
/* ensure byte-alignment for struct tag_header
* sorry, but it's necessary
*/
#include <pshpack1.h>
const struct tag_header
{
DWORD signature;
IMAGE_FILE_HEADER file_head;
IMAGE_OPTIONAL_HEADER opt_head;
IMAGE_SECTION_HEADER section_header[]; /* this is an array of unknown length
* actual number in file_head.NumberOfSections
* if your compiler objects to it length 1 should work
*/
} *header;
/* revert to regular alignment */
#include <poppack.h>
if (debugmode)
printf("starting to process \"%s\"\n", filename);
else
puts(filename);
/* first, load file */
basepointer = get_mapped_file(filename);
if (!basepointer)
{
puts("cannot load file");
return 1;
}
/* get header pointer; validate a little bit */
header = skip_dos_stub(basepointer);
if (!header)
{
puts("cannot skip DOS stub");
UnmapViewOfFile((PVOID)basepointer);
return 2;
}
/* look there's enough space for PE headers */
if(IsBadReadPtr(header, sizeof(*header)))
{
puts("not enough space for PE headers");
UnmapViewOfFile((PVOID)basepointer);
return 3;
}
/* validate PE signature */
if(header->signature!=IMAGE_NT_SIGNATURE)
{
puts("not a PE file");
UnmapViewOfFile((PVOID)basepointer);
return 4;
}
/* some debug output */
if (debugmode)
printf("file header at %#lx\n"
"optional header at %#lx\n"
"data directories at %#lx\n"
"section headers at %#lx\n",
(unsigned long)(long)((char*)header - (char*)basepointer + offsetof(struct tag_header,file_head)),
(unsigned long)(long)((char*)header - (char*)basepointer + offsetof(struct tag_header,opt_head)),
(unsigned long)(long)((char*)header - (char*)basepointer + offsetof(struct tag_header,opt_head) + offsetof(IMAGE_OPTIONAL_HEADER,DataDirectory)),
(unsigned long)(long)((char*)header - (char*)basepointer + offsetof(struct tag_header,section_header))
);
/* get number of sections */
number_of_sections = header->file_head.NumberOfSections;
if(debugmode)
printf("%d sections\n",number_of_sections);
/* check there are sections... */
if(number_of_sections<1)
{
puts("no sections???");
UnmapViewOfFile((PVOID)basepointer);
return 5;
}
/* validate there's enough space for section headers */
if(IsBadReadPtr(header->section_header, number_of_sections*sizeof(IMAGE_SECTION_HEADER)))
{
puts("not enough space for section headers");
UnmapViewOfFile((PVOID)basepointer);
return 6;
}
/* get RVA and length of import directory */
import_rva = header->opt_head.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
import_length = header->opt_head.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
if(debugmode)
printf("import directory at offset %#lx, length %#lx\n",(unsigned long)import_rva,(unsigned long)import_length);
/* check there's stuff to care about */
if(!import_rva || !import_length)
{
puts("no imports");
UnmapViewOfFile((PVOID)basepointer);
return 0; /* success! */
}
/* get import directory pointer */
import_index = get_directory_index(import_rva,import_length,number_of_sections,header->section_header);
/* check directory was found */
if(import_index <0)
{
puts("couldn't find import directory in sections");
UnmapViewOfFile((PVOID)basepointer);
return 7;
}
/* ok, we've found the import directory... action! */
{
/* The pointer to the start of the import directory's section */
const void * section_address = (char*)basepointer + header->section_header[import_index].PointerToRawData;
if(dump_import_directory(section_address,
header->section_header[import_index].VirtualAddress,
/* the last parameter is the pointer to the import directory:
* section address + (import RVA - section RVA)
* The difference is the offset of the import directory in the section
*/
(void*)((char*)section_address+import_rva-header->section_header[import_index].VirtualAddress)))
{
UnmapViewOfFile((PVOID)basepointer);
return 8;
}
}
UnmapViewOfFile((PVOID)basepointer);
return 0;
}
int main(int argc, char **argv)
{
debugmode = 1;
if(argc < 2) {
printf("Usage: %s <pe_executable>\n",argv[0]);
return -1;
}
process_file(argv[1]);
return 0;
}