News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Read Import table... ?

Started by gfalen, January 07, 2005, 10:08:18 PM

Previous topic - Next topic

gfalen

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
   

James Ladd

If you search this forum for information on PE and the PE format there was some code that does what you want.

donkey

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.
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

hutch--

Greg,

You can also grab the example by chetnik in that MASM32 subforum as it does some interesting stuff.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

Vortex

Hi gflalen,

Did you check Iczelion's PE tutorial set? It has all the answers :U

chetnik

#5
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

chetnik

#6
Ок 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)

gfalen

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


chetnik

Yap code is working  :U Very nice and small  :clap:


Best Regards

chetnik

#9
 :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)