News:

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

Portable Executable import table

Started by others111, January 11, 2012, 11:10:24 PM

Previous topic - Next topic

others111

How can I display the functions my exe file is importing from the dlls?
help me please

qWord

FPU in a trice: SmplMath
It's that simple!

others111

thank you,but I need some assembly code in masm .As far as I am now ,I mapped the file in memory and I do not know where to go next

donkey

The easiest way is to walk the import table, there is an example of how to do that in Iczelion's tutorials as far as I remember. I have an example of how to list dependancies on my website though it is in GoAsm syntax:

http://www.quickersoft.com/donkey/files/PEDirectories.zip
"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

others111

Thank you for the responce.

Below is my code as far as I am now,but I do not know where to go next.I suppose I have to use the RVA function to grab the import table from Ram memory.If this is right how to I do it?


.386
.model flat, stdcall

includelib msvcrt.lib
includelib kernel32.lib

extern printf             :proc
extern scanf            :proc
extern CreateFileA@28                  :proc
extern CreateFileMappingA@24                 :proc
extern MapViewOfFile@20      :proc
extern CloseHandle@4                   :proc
extern SetFilePointer@16                           :proc
extern ReadFile@20         :proc
extern exit                     :proc

public start

.data
FileName db "c:\vlc.exe"                                         ;address for the file to be mapped               
hFile dword ?                              ;handle  CreateFile
hFileMapping dword ?                                            ;handle  CreateFileMapping
namee  db  "vlc"                                                   ;name for the mapped file
position dword 0   
 
format db "%x", 0
 
.code
start:

        push 0                                                                  ;Handle to template file with Generic_Read access right 
        push 0                                                                  ;Attributes 80h --> FILE_ATTRIBUTE_NORMAL
        push 3                                     ; 3->create new if it does not exist
        push 0                                   ;Security:NULL
        push 1h                                          ;dwShareMode
        push 80000000h OR 40000000h                     ;ACCESS   --> GENERIC_READ OR GENERIC_WRITE 
        push offset FileName                         ;address for the file to be created
        call CreateFileA@28   
        mov  hFile,eax   
                       
      push offset namee
      push 0
      push 0                            
      push 2             ;4 --> ReadWrite | 2 --> ReadOnly
      push 0
      push hFile
      call CreateFileMappingA@24
      mov  hFileMapping,eax
      
      push 0
      push 0                            
      push 0
      push 4
      push hFileMapping
      call MapViewOfFile@20   

      xor  ebx,ebx                     
      
      mov  bx,word ptr [eax+220h]
      mov  position,ebx
      
      push position
      push offset format
      call printf
      
      ;push 0
      ;push 0
      ;push position
      ;push hFile
      ;call SetFilePointer@16
      ;mov memptr,eax
      
      
   ;call exit function
   push 0
   call exit
end start

donkey

Not sure why you would use push/push/call instead of invoke, makes it tougher when you want to port to 64 bit and doesn't make the code any faster but that's your choice I guess. From what I can see all you have done is to map the file so far but it looks OK, it would be easier to tell if you had used invoke since that would make it more readable. To read the import table you can scan the mapped file directly (uses functions from the Dbghelp API):

BuildListOfImports FRAME pMapFile, cbFile
uses esi,ebx,edi
LOCAL szOrdinal[16] :%CHAR
LOCAL hParent :%HANDLE
LOCAL tvins :TVINSERTSTRUCT
LOCAL pIMAGE_NT_HEADERS :%PTR
LOCAL bounds :D
LOCAL ImportName[256] :B

mov eax,[cbFile]
add eax,[pMapFile]
mov [bounds],eax

invoke ImageNtHeader,[pMapFile]
mov edi,eax
mov [pIMAGE_NT_HEADERS],eax

invoke Find_rdata,[pMapFile]
add eax,[edi+IMAGE_NT_HEADERS.OptionalHeader.ImageBase]
mov ebx,eax

mov edi,[edi+IMAGE_NT_HEADERS.OptionalHeader.DataDirectory+8] ; import directory RVA
invoke ImageRvaToVa,[pIMAGE_NT_HEADERS],[pMapFile],edi,NULL
mov edi,eax

jmp >>L2
L1:
invoke ImageRvaToVa,[pIMAGE_NT_HEADERS],[pMapFile],[edi+IMAGE_IMPORT_DESCRIPTOR.Name],NULL

mov [tvins.itemex.pszText],eax
mov D[tvins.hParent],TVI_ROOT
mov D[tvins.itemex.lParam],FALSE
mov D[tvins.hInsertAfter],0
mov D[tvins.itemex.mask],TVIF_TEXT + TVIF_PARAM + TVIF_IMAGE + TVIF_SELECTEDIMAGE + TVIF_CHILDREN
mov D[tvins.itemex.cChildren],TRUE
mov D[tvins.itemex.iImage],0
mov D[tvins.itemex.iSelectedImage],0
invoke SendMessage,[hImportTreeview],TVM_INSERTITEM,0,OFFSET tvins

mov [hParent],eax

cmp D[edi+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk],0
jne >
mov esi,[edi+IMAGE_IMPORT_DESCRIPTOR.FirstThunk]
jmp >T1
:
mov esi,[edi+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk]
T1:

invoke ImageRvaToVa,[pIMAGE_NT_HEADERS],[pMapFile],esi,NULL
mov esi,eax

jmp >>I2
I1:
test D[esi],IMAGE_ORDINAL_FLAG32
jnz >.ImportByOrdinal

.ImportByName
invoke ImageRvaToVa,[pIMAGE_NT_HEADERS],[pMapFile],[esi],NULL
add eax,IMAGE_IMPORT_BY_NAME.Name
invoke wsprintf,offset ImportName,"%s (%0.8Xh)",eax,ebx

lea eax,ImportName
mov [tvins.itemex.pszText],eax
mov eax,[hParent]
mov [tvins.hParent],eax
mov D[tvins.itemex.lParam],FALSE
mov D[tvins.hInsertAfter],0
mov D[tvins.itemex.mask],TVIF_TEXT + TVIF_PARAM + TVIF_IMAGE + TVIF_SELECTEDIMAGE + TVIF_CHILDREN
mov D[tvins.itemex.cChildren],FALSE
mov D[tvins.itemex.iImage],1
mov D[tvins.itemex.iSelectedImage],1
invoke SendMessage,[hImportTreeview],TVM_INSERTITEM,0,OFFSET tvins

jmp >

.ImportByOrdinal
mov edx,[esi]
and edx,0FFFFh
invoke wsprintf,offset szOrdinal,"Ordinal %u",edx
add esp,16

lea eax,szOrdinal
mov [tvins.itemex.pszText],eax
mov eax,[hParent]
mov [tvins.hParent],eax
mov D[tvins.itemex.lParam],FALSE
mov D[tvins.hInsertAfter],0
mov D[tvins.itemex.mask],TVIF_TEXT + TVIF_PARAM + TVIF_IMAGE + TVIF_SELECTEDIMAGE + TVIF_CHILDREN
mov D[tvins.itemex.cChildren],FALSE
mov D[tvins.itemex.iImage],1
mov D[tvins.itemex.iSelectedImage],1
invoke SendMessage,[hImportTreeview],TVM_INSERTITEM,0,OFFSET tvins

:
add esi,4
add ebx,6

I2:
// Be sure we don't go outside the bounds of the file
cmp esi,[bounds]; ebx
jg >>.BREAK
cmp D[esi],0
jne <<I1
add edi,sizeof IMAGE_IMPORT_DESCRIPTOR

L2:
cmp D[edi+IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk],0
jne <<L1
cmp D[edi+IMAGE_IMPORT_DESCRIPTOR.TimeDateStamp],0
jne <<L1
cmp D[edi+IMAGE_IMPORT_DESCRIPTOR.ForwarderChain],0
jne <<L1
cmp D[edi+IMAGE_IMPORT_DESCRIPTOR.Name],0
jne <<L1
cmp D[edi+IMAGE_IMPORT_DESCRIPTOR.FirstThunk],0
jne <<L1
.BREAK

ret
ENDF

Find_rdata FRAME pMapFile
uses edi,esi,ebx

// Get a pointer to IMAGE_NT_HEADERS
mov edi,[pMapFile]
add edi,[edi+IMAGE_DOS_HEADER.e_lfanew]

movzx esi,W[edi+IMAGE_NT_HEADERS.FileHeader.NumberOfSections]

// Get the size of the otpional header and add it to EDI
movzx eax,W[edi+IMAGE_NT_HEADERS.FileHeader.SizeOfOptionalHeader]
add edi,eax
add edi,4 // Here's that stupid +4 again
add edi, SIZEOF IMAGE_FILE_HEADER

// EDI holds a memory pointer to the section table
// ESI holds the number of IMAGE_SECTION_HEADER entries in the table

:
invoke lstrcmpi,edi,".rdata"
jne >.NOTIT
mov eax,[edi+IMAGE_SECTION_HEADER.VirtualAddress]
ret
.NOTIT
add edi,SIZEOF IMAGE_SECTION_HEADER
dec esi
jnz <
:

xor eax,eax
RET
ENDF
"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

others111

The reason why I use push push call is that I have to make the program using an older version of masm which I have attached using the link below.I compile the code using command lines : build_masm example.asm    and then run it typing  example   in command prompt

http://dl.transfer.ro/asm_tools-transfer_RO-12jan-fb0fe9.zip

I use PE Coeff_v8 to learn about what is inside a PE from MSDN and CFF Explorer or Far Manager to view hex.

Still I do not know where to go next to display those funtions my dlls are importing

I do not understand Iczelion's examples very good cause I am a beginner in assembly

dedndave

that is MASM version 10
(which, by the way, i couldn't make work under XP - that one does   :P )

i think the INVOKE macro was introduced in version 6

you don't happen to have any of these files to go with that version of MASM, do you ?
lib.exe
dumpbin.exe
cvtres.exe
rc.exe
rc.dll

others111

No I do not have those files.

To compile a file in this version of masm one has to write the code in notepad then save it and change the extension to .asm.Next step would be to move the file in the masm_minimal folder and launch command prompt.In command prompt one has to change the path to the masm_minimal folder where the .asm file is and write build_masm example.asm to build it.

dedndave

most of us know how to build a project using MASM   :P

what i have to ask is...
what are you trying to do ? - what is the goal of this project ?
why are you limited to that version of MASM, rather than using the Masm32 package

if you can successfully map the file
and you have looked at the PE/COFF spec
and use the code that Edgar posted
you should be able to list the names of the imported functions

these names appear in the EXE file, as it exists on the disk
they do not appear in memory of the loaded EXE, however

qWord

Quote from: dedndave on January 12, 2012, 04:03:41 PMthey do not appear in memory of the loaded EXE, however
the names also exist at runtime in the import table - or what did you mean?
FPU in a trice: SmplMath
It's that simple!

jj2007

Getting the address is not that difficult, see below. You know the forum rules, do you?  :bg

include \masm32\include\masm32rt.inc

.code
start: mov eax, @F+1 ; get the offset
mov ecx, [eax] ; get distance to jump table
mov eax, [eax+ecx+6] ; get address in location in .data
; mov eax, [eax] ; dereference it (or use call dword ptr [eax] below)
push MB_OK
push chr$("Title")
push chr$("Text")
push 0
call dword ptr [eax] ; use it ;-)
exit

@@: call MessageBoxA ; just an empty call
end start

qWord

the following code enumerate all imports of specified module at runtime
include \masm32\include\masm32rt.inc
.code
main proc
LOCAL sz[256]:CHAR

mov ebx,rv(GetModuleHandle,0)
add eax,[ebx].IMAGE_DOS_HEADER.e_lfanew
lea esi,[eax].IMAGE_NT_HEADERS.OptionalHeader.DataDirectory[1*8]
mov eax,[esi].IMAGE_DATA_DIRECTORY.VirtualAddress
lea esi,[ebx+eax]
.while [esi].IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk
mov edi,ebx
add edi,[esi].IMAGE_IMPORT_DESCRIPTOR.OriginalFirstThunk
.while DWORD ptr [edi]
.if !(DWORD ptr [edi] & 80000000h)
mov ecx,DWORD ptr [edi]
and ecx,7fffffffh
lea ecx,[ecx+ebx].IMAGE_IMPORT_BY_NAME.Name1

mov edx,[esi].IMAGE_IMPORT_DESCRIPTOR.Name1
lea edx,[edx+ebx]

fn wsprintf,ADDR sz,"%-30.30s @ %s",ecx,edx
print ADDR sz,13,10
.endif
lea edi,[edi+4]
.endw
lea esi,[esi+SIZEOF IMAGE_IMPORT_DESCRIPTOR]
.endw

inkey
exit
main endp
end main
FPU in a trice: SmplMath
It's that simple!

jj2007

Quote from: qWord on January 12, 2012, 04:19:16 PM
the following code enumerate all imports of specified module at runtime

Very cute :U

others111

how could I translate these codes in masm 1?