zoukankan      html  css  js  c++  java
  • 遍历导出表(上课代码)

    // 01 遍历导出表.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:\user32.dll",
            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 +0);
    
        //7 解析导出表的数据目录
        //7.1 得到导出表的文件偏移
        DWORD dwExOffect  = RvaToOffect(pExportDirectory->VirtualAddress, pBuf);
        //7.2 得到导出表结构体
        PIMAGE_EXPORT_DIRECTORY pExport = (PIMAGE_EXPORT_DIRECTORY)(pBuf + dwExOffect);
        //7.3打印dll的名字,注意:并不能直接打印,它提供的只是一个名字的RVA偏移
        char* pName = (char*)(RvaToOffect(pExport->Name, pBuf) + pBuf);
        printf("%s
    ", pName);
        //8 为解析导出表做准备
        //8.1 函数的个数
        DWORD dwNumOfFun =  pExport->NumberOfFunctions;
        //8.2 名称的个数
        DWORD dwNumOfName =  pExport->NumberOfNames;
        //8.3 函数地址表的位置
        PDWORD pOffectOfFun = (PDWORD) 
            (RvaToOffect(pExport->AddressOfFunctions, pBuf) + pBuf);
        //8.4序号表的位置
        PWORD  pOrder = (PWORD)
            (RvaToOffect(pExport->AddressOfNameOrdinals, pBuf) + pBuf);
        //8.5 名称表的位置
        PDWORD pOffectOfName = (PDWORD)
        (RvaToOffect(pExport->AddressOfNames,pBuf) + pBuf);
        //8.6 序号基数
        WORD wBase = pExport->Base;
        //9 开始解析导出表
        for (int i = 0; i < dwNumOfFun;i++){
            //9.1 假如这是一个无效地址
            if (pOffectOfFun[i] == 0)
                continue;
            //9.2 不是无效地址,就去序号表中找到这个序号
            int j = 0;
            for (; j < dwNumOfName; j++){
                if (pOrder[j] == i){
                    //9.2.1找到了这个序号,说明这个函数有名字,属于名称导出
                    char* pNameOfFun = (char*)(RvaToOffect(pOffectOfName[j], pBuf) + pBuf);
                    printf(" 函数序号为:%hx 函数地址为:%X  函数名为:%s
    ",
                        wBase+i,
                        pOffectOfFun[i], pNameOfFun);
                    break;
                }
            }
            if (j == dwNumOfName){
                //9.2.2假如没有找到这个序号,说明这个函数没有名字,只有序号,
                //属于序号导出,这个序号叫做虚序号
                printf(" 函数序号为:%hx 函数地址为:%X 函数名为:NULL
    ",
                    wBase+i,
                    pOffectOfFun[i]);
            }
        }
        return 0;
    }
  • 相关阅读:
    [公告]博客园准备建立SharePoint团队
    [公告]新增三款Skin
    又新增三款Skin
    一个不错的计数器
    [公告]新建新手区
    2005年1月16日 IT Pro 俱乐部活动纪实
    [好消息]祝成科技.微软公司.博客园联合打造IT俱乐部
    [公告]SharePoint团队正式成立
    SharePoint文档库存在问题
    [活动]2004年计算机图书评选
  • 原文地址:https://www.cnblogs.com/Alyoyojie/p/5329481.html
Copyright © 2011-2022 走看看