2012年7月4日星期三

遍历导入表

;made by correy
;made in 16.08.2009
;Email:leguanyuan@126.com
;QQ:112426112
;rc me.rc
;ml /coff test.asm /link /subsystem:windows me.res
;此文件我花了半个月的时间才完成,
;用十天的时间完成rvatooffset子程序
;用三天的时间完成遍历dll文件
;用三天的时间完成遍历api函数。
;此文件没有加入seh异常处理,对一些文件不能查询。
;本文件完全用汇编语言编成,没有汇编语言的高级语法。

;此文件没有考虑pe+的情况


.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
include comdlg32.inc

includelib user32.lib
includelib kernel32.lib
includelib comdlg32.lib

.data
correy db "made by correy",0
wrong db "will over!",0
FilterString db "pe File (*.exe, *.dll)",0,"*.exe;*.dll",0,0
h db "%8x",0

.data?
ofn OPENFILENAME <>
buffer db 256 DUP (?)
mz dd ?
pe dd ?
OptionalHeader dd ?
header dd ?
magic word ?
sizeOfOptionalHeader dd ?
sections dd ?
v dd ?

.code

rvatooffset proc sectionsn,head,rva
push esi
push edi
push ecx

mov edi,rva
mov esi,head
mov ecx,sectionsn

again:cmp ecx,0
jna show
cmp edi,[esi+12]
jb add40
mov eax,[esi+12]
add eax,[esi+16]
cmp edi,eax
jnb add40
mov eax,[esi+12]
sub edi,eax
mov eax,[esi+20]
add eax,edi
jmp show
add40:add esi,40
dec ecx
jmp again

show:pop ecx
pop edi
pop esi
ret
rvatooffset endp

start:
mov ofn.lStructSize,SIZEOF ofn
mov ofn.lpstrFilter, OFFSET FilterString
mov ofn.lpstrFile, OFFSET buffer
mov ofn.nMaxFile,512
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
invoke GetOpenFileName, ADDR ofn
cmp eax,0
je exit
invoke CreateFile, addr buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
cmp eax,INVALID_HANDLE_VALUE
je exit
invoke CreateFileMapping,eax, NULL, PAGE_READONLY,0,0,0
cmp eax,0
je exit
invoke MapViewOfFile,eax,FILE_MAP_READ,0,0,0
cmp eax,0
je exit

mov mz,eax

mov esi,mz
add esi,3ch
mov esi,[esi]
mov eax,mz
add esi,eax
mov pe,esi

mov esi,pe
add esi,6
mov dx,word ptr [esi]
movsx edx,dx
mov sections,edx

mov esi,pe
add esi,24
mov OptionalHeader,esi ;保存可选头的地址。

mov esi,pe
add esi,20
mov dx,word ptr [esi]
movsx edx,dx
mov sizeOfOptionalHeader,edx

mov esi,OptionalHeader
add esi,sizeOfOptionalHeader
mov header,esi ;保存节头的地址。

mov esi,OptionalHeader
add esi,104
mov esi,[esi]

invoke rvatooffset,sections,header,esi
mov edi,eax
mov esi,eax
add edi,mz
again2:cmp dword ptr [edi+12],0
je exit

cmp dword ptr [edi+16],0
je exit

add eax,12
add eax,mz
mov eax,[eax]
invoke rvatooffset,sections,header,eax
add eax,mz
invoke MessageBox,0,eax,addr correy,0
   
    mov eax,[edi+16]
    invoke rvatooffset,sections,header,eax
    add eax,mz
    again3:push eax
    cmp dword ptr [eax],0
      je exit2
      test dword ptr [eax],80000000h
      jne exit2
      invoke rvatooffset,sections,header,dword ptr [eax]
      add eax,mz
      add eax,2
      invoke MessageBox,0,eax,addr correy,0
      pop eax
      add eax,4
      jmp again3
   
    exit2:
add edi,20
add esi,20
mov eax,esi
jmp again2

exit:invoke MessageBox,0,addr wrong,addr correy,0
invoke ExitProcess,NULL
end start


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


#include <Windows.h>
#include <stdio.h>              // for printf


/*
写作目的:遍历一个PE文件导入的DLL及其函数。

made by correy
made at 2015.06.23
*/


unsigned int RVATOOFFSET(IN PVOID lpFileBase,IN unsigned int rva)
    /*
    返回0表示失败,其他的是在文件中的偏移。
    */
{
    unsigned int offset = 0;//返回值。

    IMAGE_DOS_HEADER * p_image_dos_header = (IMAGE_DOS_HEADER * )lpFileBase;

    ULONG  ntSignature = (ULONG)p_image_dos_header + p_image_dos_header->e_lfanew;
    ntSignature = * (ULONG *)ntSignature;

    DWORD  CoffHeaderOffset = (ULONG)p_image_dos_header + p_image_dos_header->e_lfanew + sizeof(ULONG);
    IMAGE_FILE_HEADER * p_image_file_header = (IMAGE_FILE_HEADER *)CoffHeaderOffset;

    //注意这里用的永远是:IMAGE_OPTIONAL_HEADER32.
    //要分析IMAGE_OPTIONAL_HEADER64的一个办法是:强制定义一个,载赋值转换.
    //其实这个结构的大小是固定的,只不过32位的和64位的不一样.但还是用规范建议的.IMAGE_FILE_HEADER的成员访问好.
    IMAGE_OPTIONAL_HEADER * p_image_optional_header = (IMAGE_OPTIONAL_HEADER *)((ULONG)p_image_file_header + sizeof(IMAGE_FILE_HEADER));

    IMAGE_SECTION_HEADER  * p_image_section_header = (IMAGE_SECTION_HEADER *)((ULONG)p_image_optional_header + p_image_file_header->SizeOfOptionalHeader);//必须加(ULONG),不然出错.

    for (int i = 0;i < p_image_file_header->NumberOfSections;i++) //规范规定是从1开始的.
    {
        if (rva >= p_image_section_header[i].VirtualAddress && rva <= (p_image_section_header[i].VirtualAddress + p_image_section_header[i].Misc.VirtualSize))
        {
            offset = rva - p_image_section_header[i].VirtualAddress + p_image_section_header[i].PointerToRawData;
            break;
        }
    }

    return offset;
}


void DumpFile(LPCWSTR filename)
    /*
    摘自:Peering Inside the PE: A Tour of the Win32 Portable Executable File Format.有改动。
    */
{  
    HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);                  
    if ( hFile == INVALID_HANDLE_VALUE )
    {
        printf("Couldn't open file with CreateFile()\n");
        return;
    }
   
    HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if ( hFileMapping == 0 )
    {  
        CloseHandle(hFile);
        printf("Couldn't open file mapping with CreateFileMapping()\n");
        return;
    }
   
    LPVOID lpFileBase = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
    if ( lpFileBase == 0 )
    {
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        printf("Couldn't map view of file with MapViewOfFile()\n");
        return;
    }
 
    PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)lpFileBase;
    if ( dosHeader->e_magic != IMAGE_DOS_SIGNATURE )
    {
        printf("dosHeader->e_magic != IMAGE_DOS_SIGNATURE\n");
        UnmapViewOfFile(lpFileBase);
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        return;
    }

    LONG e_lfanew = dosHeader->e_lfanew;

    PIMAGE_NT_HEADERS ntHeader = (PIMAGE_NT_HEADERS)((PCHAR)dosHeader + e_lfanew);
    if (ntHeader->Signature != IMAGE_NT_SIGNATURE)
    {
        printf("ntHeader->Signature != IMAGE_NT_SIGNATURE\n");
        UnmapViewOfFile(lpFileBase);
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        return;
    }

    //if (FlagOn(ntHeader->FileHeader.Characteristics, IMAGE_FILE_DLL) || FlagOn(ntHeader->FileHeader.Characteristics, IMAGE_FILE_SYSTEM))
    //{
    //    return;
    //}

    PIMAGE_IMPORT_DESCRIPTOR InportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress + (SIZE_T)lpFileBase);
    ULONG InportSize = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;
    //IMPORT_DESCRIPTOR = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData ((SIZE_T)lpFileBase, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &InportSize);//经测试二者相等。这一行等于上面的两行。
    if (InportDescriptor == NULL)
    {
        //没有导出表。
        //__debugbreak();
        printf("InportDescriptor == NULL\n");
        UnmapViewOfFile(lpFileBase);
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        return;
    }

    InportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)(RVATOOFFSET(lpFileBase, (SIZE_T)InportDescriptor - (SIZE_T)lpFileBase) + (SIZE_T)lpFileBase);

    int dll_count = 0;//
    for ( ; ;dll_count++ )
    {
        //if (InportDescriptor->Characteristics == 0 && InportDescriptor->FirstThunk == 0 && InportDescriptor->ForwarderChain == 0 &&
        //    InportDescriptor->Name == 0 && InportDescriptor->OriginalFirstThunk && InportDescriptor->TimeDateStamp == 0)
        //{
        //    break;
        //}

        //结束标志。
        if (InportDescriptor->Name == 0)
        {
            break;
        }

        //printf("Characteristics == 0x%x\n", InportDescriptor->Characteristics);
        //printf("OriginalFirstThunk == 0x%x\n", InportDescriptor->OriginalFirstThunk);//这个不打印,原因是和Characteristics一样。
        //printf("TimeDateStamp == 0x%x\n", InportDescriptor->TimeDateStamp);//这个域一直被设置为 0,直到映像被绑定。当映像被绑定之后,这个域被设置为这个 DLL 的日期/时间戳。
        //printf("ForwarderChain == 0x%x\n", InportDescriptor->ForwarderChain);

        char * name = (char *)(RVATOOFFSET(lpFileBase, InportDescriptor->Name) + (SIZE_T)lpFileBase);
        printf("\n\n\nDllName:%s\n", name);
        //printf("FirstThunk == 0x%x\n", InportDescriptor->FirstThunk);//注意这个成员是有值的,值是地址,地址的内容是没初始化的。必须有值的。

        //PIMAGE_IMPORT_BY_NAME import_by_name = (PIMAGE_IMPORT_BY_NAME)InportDescriptor->Characteristics;
        //PIMAGE_THUNK_DATA thunk_data = (PIMAGE_THUNK_DATA)InportDescriptor->FirstThunk;
        //PIMAGE_IMPORT_BY_NAME import_by_name = (PIMAGE_IMPORT_BY_NAME)(RVATOOFFSET(lpFileBase, InportDescriptor->Characteristics) + (SIZE_T)lpFileBase);
        //PIMAGE_THUNK_DATA thunk_data = (PIMAGE_THUNK_DATA)(RVATOOFFSET(lpFileBase, InportDescriptor->FirstThunk) + (SIZE_T)lpFileBase);

        PIMAGE_THUNK_DATA thunk_data = (PIMAGE_THUNK_DATA)(RVATOOFFSET(lpFileBase, InportDescriptor->Characteristics) + (SIZE_T)lpFileBase);
        //PIMAGE_IMPORT_BY_NAME import_by_name = (PIMAGE_IMPORT_BY_NAME)(RVATOOFFSET(lpFileBase, thunk_data->u1.AddressOfData) + (SIZE_T)lpFileBase);

        int api_count = 0;
        for ( ; ;api_count++ )
        {
            //结束标志。
            if (*(SIZE_T *)thunk_data == 0)
            {
                break;
            }

            PIMAGE_IMPORT_BY_NAME import_by_name = (PIMAGE_IMPORT_BY_NAME)(RVATOOFFSET(lpFileBase, thunk_data->u1.AddressOfData) + (SIZE_T)lpFileBase);

            printf("\tAPIName:%s\n", import_by_name->Name);

            thunk_data++;
        }

        InportDescriptor++;
    }

    UnmapViewOfFile(lpFileBase);
    CloseHandle(hFileMapping);
    CloseHandle(hFile);
}


int wmain(int argc, wchar_t *argv[])
{
    if ( argc != 2 )
    {
        return 1;
    }

    DumpFile(argv[1]);

    return 0;
}

没有评论:

发表评论