• 第3讲:导入表的定位和读取操作


    // ImportFun.cpp : 完整代码如下
    //

    #include "stdafx.h"
    #include <stdio.h>
    #include <windows.h>
    
    
    //用来实现RVA到磁盘文件偏移的转换
    DWORD RVAToOffset(LPVOID lpBase,DWORD VirtualAddress)
    {
    IMAGE_DOS_HEADER *dosHeader;
    IMAGE_NT_HEADERS *ntHeader;
    IMAGE_SECTION_HEADER *SectionHeader;
    int NumOfSections;//Section 的数量
    //定位到PE head
    dosHeader=(IMAGE_DOS_HEADER*)lpBase;
    ntHeader=(IMAGE_NT_HEADERS*)((BYTE*)lpBase+dosHeader->e_lfanew);
    NumOfSections=ntHeader->FileHeader.NumberOfSections;
    for (int i=0;i<NumOfSections;i++)
    {
    SectionHeader=(IMAGE_SECTION_HEADER*)((BYTE*)lpBase+dosHeader->e_lfanew+sizeof(IMAGE_NT_HEADERS))+i;
    if(VirtualAddress>SectionHeader->VirtualAddress&&VirtualAddress<SectionHeader->VirtualAddress+SectionHeader->SizeOfRawData)
    {
    DWORD AposRAV=VirtualAddress-SectionHeader->VirtualAddress;
    DWORD Offset=SectionHeader->PointerToRawData+AposRAV;
    return Offset;
    }
    }
    return 0;
    }
    
    int main(int argc, char* argv[])
    {
    //打开文件
    HANDLE hFile=CreateFile("c:\calc.exe",GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
    if(hFile==INVALID_HANDLE_VALUE)
    {
    printf("CreateFile Failed
    ");
    return 0;
    }
    //创建内存映射文件的内核对象
    HANDLE hMap=CreateFileMapping(hFile,NULL,PAGE_READONLY,NULL,NULL,NULL);
    if(hMap==INVALID_HANDLE_VALUE)
    {
    printf("CreateFileMapping Failed
    ");
    return 0;
    }
    //把文件映射入内存
    LPVOID lpBase=MapViewOfFile(hMap,FILE_MAP_READ,0,0,0);//返回内存文件映射句柄,lpBase
    if(lpBase==NULL)
    {
    printf("MapViewOfFile Failed
    ");
    return 0;    
    }
    
    
    IMAGE_DOS_HEADER *dosHeader;
    IMAGE_NT_HEADERS *ntHeader;
    IMAGE_IMPORT_BY_NAME *ImportName;
    //lpBase由MapViewOfFile函数返回
    dosHeader=(IMAGE_DOS_HEADER*)lpBase;
    //检测是否是有效的PE文件
    if (dosHeader->e_magic!=IMAGE_DOS_SIGNATURE)
    {
    printf("This is not a windows file
    ");
    return 0;
    }
    //定位到PE header
    ntHeader=(IMAGE_NT_HEADERS*)((BYTE*)lpBase+dosHeader->e_lfanew);//e_lfanew成员定位到PE header
    //判断是否是一个有效的win32文件
    if(ntHeader->Signature!=IMAGE_NT_SIGNATURE)
    {
    printf("This is not a win32 file
    ");
    return 0;
    }
    //定位到导入表
    IMAGE_IMPORT_DESCRIPTOR *ImportDec=(IMAGE_IMPORT_DESCRIPTOR*)((BYTE*)lpBase+RVAToOffset(lpBase,ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
    while(ImportDec->FirstThunk)
    {
    //得到DLL文件名
    char *pDllName=(char*)((BYTE*)lpBase+RVAToOffset(lpBase,ImportDec->Name));
    printf("
    DLL文件名:%s
    ",pDllName);
    //通过OriginalFirstThunk定位到PIMAGE_THUNK_DATA结构数组
    PIMAGE_THUNK_DATA pThunk=(PIMAGE_THUNK_DATA)((BYTE*)lpBase+RVAToOffset(lpBase,ImportDec->OriginalFirstThunk));
    while(pThunk->u1.Function)
    {
    //判断函数是用函数名导入的还是序号导入的
    if(pThunk->u1.Ordinal& IMAGE_ORDINAL_FLAG32)//高位为1
    {
    //输出序号
    printf("从此DLL模块导出的函数的序号:%x
    ",pThunk->u1.Ordinal&0xFFFF);
    }
    else//高位为0
    {
    //得到IMAGE_IMPORT_BY_NAME结构中的函数名
    ImportName=(IMAGE_IMPORT_BY_NAME*)((BYTE*)lpBase+RVAToOffset(lpBase,(DWORD)pThunk->u1.AddressOfData));
    printf("从此DLL模块导出的函数的函数名:%s
    ",ImportName->Name);
    }
    pThunk++;
    }
    ImportDec++;
    }
    UnmapViewOfFile(lpBase);
    CloseHandle(hMap);
    CloseHandle(hFile);
    return 0;
    }
  • 相关阅读:
    Linux split分割xls或csv文件
    python安装mysql/mysqlclient 无法打开mysql.h问题解决(win10 64位 )
    Linux Centos 7 安装文件服务器MinIO
    RabbitMQ——Virtual Host
    vue中的for循环数组数据时,修改了数组中的值页面不重新渲染for循环节点数据的问题
    vue刷新数组 Y
    uniapp返回上一页并传参
    linux常用命令基础
    如何解压带密码的压缩包
    hive 视图的使用方法
  • 原文地址:https://www.cnblogs.com/mayingkun/p/4769544.html
Copyright © 2020-2023  润新知