遍历导入表(上课代码)

// 02 遍历导入表.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <windows.h>
//************************************
// Method:    IsPeFile
// FullName:  IsPeFile
// Access:    public 
// Returns:   bool   成功失败
// Qualifier:
// Parameter: TCHAR * szPath  路径
//************************************
bool  IsPeFile(TCHAR* szPath)
{
    BOOL bSuccess = TRUE;
    //1 将PE文件读取到内存
    HANDLE hFile = CreateFile(
        szPath,
        GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL
        , NULL
        );
    DWORD dwSize = GetFileSize(hFile, NULL);
    DWORD dwRubbish = 0;
    unsigned char * pBuf = new unsigned char[dwSize];
    ReadFile(hFile, pBuf, dwSize, &dwRubbish, NULL);
    //2 判断是否是PE文件
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuf;
    if (pDos->e_magic != IMAGE_DOS_SIGNATURE)
    {
        bSuccess = FALSE;
        goto Error;

    }
    PIMAGE_NT_HEADERS  pNt = (PIMAGE_NT_HEADERS)(pBuf + pDos->e_lfanew);
    if (pNt->Signature != IMAGE_NT_SIGNATURE)
    {
        bSuccess = FALSE;
        goto Error;
    }

Error:

    if (pBuf != NULL)
    {
        delete[]pBuf;
    }
    if (hFile != INVALID_HANDLE_VALUE)
    {
        CloseHandle(hFile);
    }
    return bSuccess;
}

//************************************
// Method:    RvaToOffect
// FullName:  RvaToOffect
// Access:    public 
// Returns:   DWORD
// Qualifier: 将RVA转换为Offect
// Parameter: DWORD rva    要转换的RVA
// Parameter: unsigned char * pFile   存储pe文件内容的缓冲区
//************************************
DWORD RvaToOffect(DWORD rva, unsigned char* pFile)
{
    //1 找到NT头
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pFile;
    PIMAGE_NT_HEADERS  pNt = (PIMAGE_NT_HEADERS)(pFile + pDos->e_lfanew);
    //2 找到数据目录表
    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNt);
    //3 判断要转换的位置是不是PE头部
    if (rva < pSection->VirtualAddress)
    {
        return rva;
    }
    //4 在数据目录表中遍历,进行计算
    for (int i = 0; i < pNt->FileHeader.NumberOfSections; i++)
    {
        if (
            (rva >= pSection->VirtualAddress) &&
            (rva <= pSection->VirtualAddress + pSection->Misc.VirtualSize)
            )
        {
            return rva - pSection->VirtualAddress + pSection->PointerToRawData;
        }
        pSection++;
    }
    return -1;
}
int _tmain(int argc, _TCHAR* argv[])
{
    //1 将PE文件读取到内存
    HANDLE hFile = CreateFile(
        L"D:\Test.exe",
        GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        NULL, OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL
        , NULL
        );
    DWORD dwSize = GetFileSize(hFile, NULL);
    DWORD dwRubbish = 0;
    unsigned char * pBuf = new unsigned char[dwSize];
    ReadFile(hFile, pBuf, dwSize, &dwRubbish, NULL);
    //2 找到dos头
    PIMAGE_DOS_HEADER  pDos = PIMAGE_DOS_HEADER(pBuf);
    //3 找到nt头
    PIMAGE_NT_HEADERS pNt = PIMAGE_NT_HEADERS(pBuf + pDos->e_lfanew);
    //4 找到扩展头
    PIMAGE_OPTIONAL_HEADER pOption = &(pNt->OptionalHeader);
    //5 找到数据目录表
    PIMAGE_DATA_DIRECTORY  pDataDirectory = pOption->DataDirectory;
    //6 找到导入表的数据目录
    PIMAGE_DATA_DIRECTORY pExportDirectory = (pDataDirectory + 1);
    
    //7解析导入表的数据目录
    DWORD dwImportOffect = 
        RvaToOffect(pExportDirectory->VirtualAddress, pBuf);
    PIMAGE_IMPORT_DESCRIPTOR pImport = 
        (PIMAGE_IMPORT_DESCRIPTOR)(dwImportOffect + pBuf);
    //8 解析导入表
    while (pImport->OriginalFirstThunk != 0)
    {
        //8.1通过INT的RVA得到INT在文件中的位置
        PIMAGE_THUNK_DATA32  pInt = 
        (PIMAGE_THUNK_DATA32)(RvaToOffect(pImport->OriginalFirstThunk, pBuf) + pBuf);
        char* pDllName = (char*)(RvaToOffect(pImport->Name,pBuf)+pBuf);
        printf("%s
", pDllName);
        while (pInt->u1.Ordinal!=0)
        {
            //8.2得到位置之后,判断一下最高位是不是1
            if ((pInt->u1.Ordinal & 80000000)>>31 != 1)
            {
                //8.2.1如果不是1的话,说明它既有名称也有序号,需要使用PIMAGE_IMPORT_BY_NAME  AddressOfData去解析
                PIMAGE_IMPORT_BY_NAME pNameAndOrder = (PIMAGE_IMPORT_BY_NAME)
                    (RvaToOffect(pInt->u1.AddressOfData, pBuf) + pBuf);
                printf("   序号为:%x",pNameAndOrder->Hint);
                printf("   名称为:%s
",pNameAndOrder->Name);
            }
        
            else
            {
                //8.2.2如果是1的话,说明它没有名称只有序号,直接使用DWORD Ordinal得到序号
                printf("   序号为:%x
", pInt->u1.Ordinal & 0x7FFFFFFF);
            }
            
            pInt++;

        }
        pImport++;
    }


    return 0;
}
原文地址:https://www.cnblogs.com/Alyoyojie/p/5329491.html