This code works for reading th export table. How can I modify it to read the import table?
enumlib proc szlib
local nfuncs, pnames
invoke LoadLibrary, szlib
mov edx, eax
add edx, [edx].IMAGE_DOS_HEADER.e_lfanew
mov edx, [edx].IMAGE_NT_HEADERS.OptionalHeader.DataDirectory.VirtualAddress
add edx, eax
m2m nfuncs, [edx].IMAGE_EXPORT_DIRECTORY.NumberOfNames
add eax, [edx].IMAGE_EXPORT_DIRECTORY.AddressOfNames
mov pnames, eax
; now pnames -> name table, nfuncs=# of ptrs in table
If you search this forum for information on PE and the PE format there was some code that does what you want.
If you download the system library from my website you will find the GetPEImports and GetPEExports functions that demonstrate how to read both the import and export directories of a PE file...
http://donkey.visualassembler.com/
Click on libraries and download the system library, it comes with GoAsm source code.
Greg,
You can also grab the example by chetnik in that MASM32 subforum as it does some interesting stuff.
Hi gflalen,
Did you check Iczelion's PE tutorial set? It has all the answers :U
First you have to check if there is import table by doing this : (DataDirecotry is 8 bytes long)
mov ebx, nthdr.OptionalHeader.DataDirectory[1*8].VirtualAddress
or ebx, ebx
jz @F
IMPORT TABLE is second in DataDirecotry so you multiplay 1 by 8 or if you want to find any other Data Directory you multiplay index by 8 =) if VirtualAdress = 0 that means that there is no such data direcotry, my small code shows it.
Next thing you have to know how ImportTable is structured. Ok at the begning of IMPORT TABLE is IMAGE_IMPORT_DESCRIPTOR list, which is terminated with IMAGE_IMPORT_DESCRIPTOR filled with 0, and that's how you know where it ends.
Something like this :
IMAGE_IMPORT_DESCRIPTOR STRUCT for 1st dll, IMAGE_IMPORT_DESCRIPTOR STRUCT for 2nd dll, IMAGE_IMPORT_DESCRIPTOR STRUCT for 3rd dll, IMAGE_IMPORT_DESCRIPTOR STRUCT filled with 0.
Ok when you get VirtualAdress add it to memory where is file maped.
simple --> folow previous example
add ebx, memptr
where memptr is begning of maped file =)
Here is IMAGE_IMPORT_DESCRIPTOR from windows.inc
IMAGE_IMPORT_DESCRIPTOR STRUCT
union
Characteristics dd ?
OriginalFirstThunk dd ?
ends
TimeDateStamp dd ?
ForwarderChain dd ?
Name1 dd ?
FirstThunk dd ?
IMAGE_IMPORT_DESCRIPTOR ENDS
Name1 is VirtualAddres to DLL name, I usally check if Name1 is 0, if it is 0 it is end of IMPORTS (b/c struct is filled with 0, this didn't faill me yet, but who knows =)) You will find at that VirtualAddres for example "kernel32.dll", "user32.dll" or so...
OriginalFirstThunk is pointer to list of pointers to API name(it is RVA)... so ->>>
ASSUME ebx:ptr IMAGE_IMPORT_DESCRIPTOR
mov edx, [ebx].OriginalFirstThunk
add edx, memptr
mov ecx, [edx]
add ecx, memptr
add ecx, 2 ;<---- API names in Import has 2 non-ascii character so erase them
And now you should be able to see first API name from IMPORT TABLE.
By adding 4 to edx you will go to next RVA pointer to API list, and so on. You can see that in my examples at the botoom of my post.
Next important member of IMAGE_IMPORT_DESCRIPTOR is this one :
FirrstThunk whis is RVA to API address list. It points to API address list, filled by loader.
Next thing that is important to know is that you should have counter. I usaually use eax =)
And here is why, look at this picture =) :
index=OriginalFirstThunk (rva) API name ========= FirstThink
1 ===1234 =========== GetModuleHandleA ======= 7045678
2 ===1238 =========== LoadLibraryA ======= 7012345
3 ===1242 =========== GetProcAddress ======= 7053214
4 ===1246 =========== ExitProcess ======= 7084938
As you can see index of OriginalFirstThunk is used to find address of API in FirstThunk
so your code should look like this =)
For example you are looking for ExitProcess ->
Look at OrginalFirstThunk wich is list of RVAs to API names ->>>
xor eax, eax
mov ebx, OrginalFirstThunk
add ebx, memptr
loop goes from here:
mov ecx, [ebx]
add ecx, memptr
add ecx, 2 ;<--- erase 2 non-asci string
check if ecx points to ExitProcess if not
inc eax
add ebx, 4
jmp to loop
Aslo if ecx is pointing to NULL it is end of our imports from this dll
Now we have index in eax and we can find address in FirstThunk
mov ebx, FirstThunk
add ebx, memptr
mov eax, [ebx+eax*4]
and voila, you have address of impored ExitProcess in eax =))
Ok here are examples on this :
IAT API hijacking : http://nonenone.net/progz/iathook.zip
(how to read and scan IAT table)
PE loader : http://nonenone.net/progz/pe-mem.zip
PE loader with error checking, cmd line parsing : http://nonenone.net/progz/pe-memup.zip
pe-mem is dealing with IAT filling, trying to simulate PE loader =)
Also you should read this about PE -- LUEVELSMEYER pe description
http://nonenone.net/misc/pe1.zip
I hope, I halped you with this post =)
Best regards
Ок I think that this was to much theorry so here is example on how to list IMPORTS ... streight and forward : (run it in console so you can see it's otuput) :U (I wrote it just few minutes ago for you :bg)
.486
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\masm32.lib
.data
format db "index : %d Address : 0x%X API : %s",10, 13,0
text db 128 dup (0)
dll db "user32.dll",0
formatdll db "[%s]",10, 13,0
.data?
handle dd ?
.code
start:
invoke GetModuleHandle, NULL
mov handle, eax
mov ebx, handle
add ebx, [ebx+3ch] ;<------- Go to PE header
ASSUME ebx : ptr IMAGE_NT_HEADERS32
;Lets go to Import table
mov ebx, [ebx].OptionalHeader.DataDirectory[1*8].VirtualAddress
or ebx, ebx
jz @error
add ebx, handle ;<---- EBX is pointing to Import Table
;<--- Next thing to do is to see how many IMAGE_IMPORT_DESCRIPTORs are there
ASSUME ebx : ptr IMAGE_IMPORT_DESCRIPTOR
@loop_dll:
mov ecx, [ebx].Name1 ;<---- if Name1 = 0 end of IMAGE_IMPORT_DESCRIPTOR list
or ecx, ecx
jz @error
add ecx, handle
invoke wsprintf, ADDR text, ADDR formatdll, ecx
invoke StdOut, ADDR text ;<---- print dll name
xor eax, eax ;<---- index counter
mov ecx, [ebx].OriginalFirstThunk
add ecx, handle ;<---- points to list of pointer to API names
@loop_api:
mov esi, [ecx]
or esi, esi ;<---- if esi = 0 no more imports from this dll
jz @F
add esi, handle
add esi, 2 ;<---- erase 2 non asci
mov edx, [ebx].FirstThunk
add edx, handle
mov edx, [edx+eax*4] ;<---- edx has API address
push eax ;<---- save counter
push ebx ;<---- save pointer to IMAGE_IMPORT_DESCRIPTOR
push ecx ;<---- save pointer to list of pointers to API names
invoke wsprintf, ADDR text, ADDR format, eax, edx, esi
invoke StdOut, ADDR text
pop ecx ;<---- Restore pointer to list of pointer to API names
pop ebx ;<---- Restore pointer to IMAGE_IMPORT_DESCRIPTOR
pop eax ;<---- Restore counter
inc eax ;<---- increment counter
add ecx, 4 ;<---- incrment ecx, points to next API name
jmp @loop_api
@@:
add ebx, size IMAGE_IMPORT_DESCRIPTOR ;<---- go to next IMAGE_IMPORT_DESCRIPTOR
jmp @loop_dll
@error:
invoke ExitProcess, NULL
end start
And that's how to list IMPORT TABLE :dance: You can also use at line 25, invoke GetModuelHandle, ADDR dll to list all imports from user32.dll :dance:
Have fun :dance: :dance: :dance: :dance: (I like this smile)
Thanks alot cetnik - sorry for the delay in replying. Those links you posted did the trick.
It took about 2 hours last night to come up with this code:
invoke LoadLibrary, szDll
mov edi, eax
mov ebx, eax
add ebx, [ebx].IMAGE_DOS_HEADER.e_lfanew
assume ebx:ptr IMAGE_NT_HEADERS
mov ebx, [ebx].OptionalHeader.DataDirectory[8].VirtualAddress
.if ebx
assume ebx:ptr IMAGE_IMPORT_DESCRIPTOR
add ebx, edi
.while [ebx].Name1 ; Name1 = RVA of file name
mov eax, [ebx].Name1
; [eax+edi] = ptr to file name
mov esi, [ebx].OriginalFirstThunk
add esi,edi
.while .d[esi] ; .d[esi] = RVA api name
lodsd
.continue .if eax & 80000000h ; MSB set: ordinal - no asciiz
; 2[eax+edi] = ptr to api name
.endw
add ebx, type IMAGE_IMPORT_DESCRIPTOR
.endw
.endif
Yap code is working :U Very nice and small :clap:
Best Regards
:dance: :dance: :dance:
Try now to change OriginalFirstThunk so it points to list of ordinals :U Import procs by ordinal and not by name :bg
http://www.masmforum.com/simple/index.php?topic=381.0 :dance: :dance: :dance:
No practical use I guess, but it was fun coding progy like this :8)