首页 > 其他分享 >PE导出表--转发函数处理

PE导出表--转发函数处理

时间:2023-11-11 23:46:26浏览次数:30  
标签:cast -- PE Module reinterpret EXPORT 转发 DIRECTORY DWORD

遇事不决,OPENAI

查看导出表信息

E:\IDE\VisualStudio2019\community>dumpbin /exports C:\Windows\System32\version.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30145.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file C:\Windows\System32\version.dll

File Type: DLL

  Section contains the following exports for VERSION.dll

    00000000 characteristics
    927B71E6 time date stamp
        0.00 version
           1 ordinal base
          17 number of functions
          17 number of names

    ordinal hint RVA      name

          1    0 00001080 GetFileVersionInfoA
          2    1 00002190 GetFileVersionInfoByHandle
          3    2 00001DF0 GetFileVersionInfoExA
          4    3 00001040 GetFileVersionInfoExW
          5    4 00001010 GetFileVersionInfoSizeA
          6    5 00001E00 GetFileVersionInfoSizeExA
          7    6 00001050 GetFileVersionInfoSizeExW
          8    7 00001060 GetFileVersionInfoSizeW
          9    8 00001070 GetFileVersionInfoW
         10    9 00001E10 VerFindFileA
         11    A 00002360 VerFindFileW
         12    B 00001E20 VerInstallFileA
         13    C 00002F80 VerInstallFileW
         14    D          VerLanguageNameA (forwarded to KERNEL32.VerLanguageNameA)
         15    E          VerLanguageNameW (forwarded to KERNEL32.VerLanguageNameW)
         16    F 00001020 VerQueryValueA
         17   10 00001030 VerQueryValueW

  Summary

        1000 .data
        1000 .pdata
        2000 .rdata
        1000 .reloc
        1000 .rsrc
        3000 .text

可以发现verson.dll有2个转发函数
VerLanguageNameA (forwarded to KERNEL32.VerLanguageNameA)
VerLanguageNameW (forwarded to KERNEL32.VerLanguageNameW)

导出表结构

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;

关键判断:
如果functionRVA 位于导出表地址范围内(IMAGE_DATA_DIRECTORY),则该地址指向格式为 <MODULE>.<ExportName> 的转发字符串,

if (arFuncs[i] >= pExportEntry->VirtualAddress && arFuncs[i] < pExportEntry->VirtualAddress+pExportEntry->Size)
{
    //function address is RVA to Forwarder String; e.g. NTDLL.RtlDecodePointer
}
else
{
    //function address is RVA to actual code within current module
}

chatgpt 给的代码
第一次并没有给出正确代码,需要去不断纠正,比如指针运算的错误……

#include <windows.h>
#include <iostream>
#include <string>

FARPROC GetExportFunction(HMODULE Module, LPCSTR Name) {
    if (Module == NULL) {
        std::cerr << "Invalid module handle" << std::endl;
        return NULL;
    }

    if (Name == NULL) {
        std::cerr << "Invalid function name" << std::endl;
        return NULL;
    }

    // 获取导出函数地址
    PIMAGE_DOS_HEADER pDosHeader = reinterpret_cast<PIMAGE_DOS_HEADER>(Module);
    PIMAGE_NT_HEADERS pNTHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<BYTE*>(Module) + pDosHeader->e_lfanew);
    PIMAGE_EXPORT_DIRECTORY pExportDir = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(reinterpret_cast<BYTE*>(Module) + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

    DWORD* functions = reinterpret_cast<DWORD*>(reinterpret_cast<BYTE*>(Module) + pExportDir->AddressOfFunctions);
    WORD* ordinals = reinterpret_cast<WORD*>(reinterpret_cast<BYTE*>(Module) + pExportDir->AddressOfNameOrdinals);
    DWORD* names = reinterpret_cast<DWORD*>(reinterpret_cast<BYTE*>(Module) + pExportDir->AddressOfNames);

    for (DWORD i = 0; i < pExportDir->NumberOfNames; ++i) {
        const char* functionName = reinterpret_cast<const char*>(reinterpret_cast<BYTE*>(Module) + names[i]);
        if (strcmp(functionName, Name) == 0) {
            // 找到导出函数
            DWORD functionRVA = functions[ordinals[i]];
            if (functionRVA >= pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress &&
                functionRVA < pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size) {
                // 转发函数
                const char* forwarderString = reinterpret_cast<const char*>(reinterpret_cast<BYTE*>(Module) + functionRVA);

                // 解析转发字符串,加载相应的 DLL
                std::string strForwarder(forwarderString);
                size_t dotPos = strForwarder.find('.');
                if (dotPos != std::string::npos) {
                    std::string dllName = strForwarder.substr(0, dotPos);
                    std::string functionName = strForwarder.substr(dotPos + 1);

                    HMODULE hForwardModule = LoadLibraryA(dllName.c_str());
                    if (hForwardModule != NULL) {
                        // 递归调用 GetExportFunction 获取导出函数地址
                        FARPROC forwardFunction = GetExportFunction(hForwardModule, functionName.c_str());
                        FreeLibrary(hForwardModule);  // 加载后释放模块
                        return forwardFunction;
                    } else {
                        std::cerr << "Failed to load the forwarded DLL: " << dllName << std::endl;
                        return NULL;
                    }
                } else {
                    std::cerr << "Invalid forwarder string: " << forwarderString << std::endl;
                    return NULL;
                }
            } else {
                // 非转发函数
                return reinterpret_cast<FARPROC>(reinterpret_cast<BYTE*>(Module) + functionRVA);
            }
        }
    }

    return NULL;
}

int main() {
    // 使用示例
    HMODULE hModule = LoadLibraryA("YourLibrary.dll");
    if (hModule != NULL) {
        FARPROC functionAddress = GetExportFunction(hModule, "YourFunctionName");
        if (functionAddress != NULL) {
            // 使用获取的函数地址
            // 例如:reinterpret_cast<YourFunctionType>(functionAddress)(arguments);
        } else {
            std::cerr << "Failed to get the function address" << std::endl;
        }
        FreeLibrary(hModule);
    } else {
        std::cerr << "Failed to load the library" << std::endl;
    }

    return 0;
}

更多信息:
https://ferreirasc.github.io/PE-Export-Address-Table/
https://www.cnblogs.com/revercc/p/16703647.html
https://stackoverflow.com/questions/44279216/how-can-i-resolve-the-forwarded-api-from-the-iat-on-pe

P.S.

AI是大势所趋,"滚滚长江东逝水,浪花淘尽英雄"

标签:cast,--,PE,Module,reinterpret,EXPORT,转发,DIRECTORY,DWORD
From: https://www.cnblogs.com/DirWang/p/17826582.html

相关文章

  • 整数类型(3)
    <1>数的范围(1)整体范围:对于一个字节(8bit)可以表达的数的范围为00000000——11111111;(2)在数的范围中00000000——>0;00000001~01111111——>1~127,高位为0,在纯二进制中表示1~127;10000000~11111111——>-1~-128,高位为1,在补码表示-1~-128;计算机中所存在的一切数据都用纯二......
  • SpringFramework介绍
    一、Spring和SpringFramework概念广义的Spring:Spring技术栈(全家桶)​ 广义上的Spring泛指以SpringFramework为基础的Spring技术栈。经过十多年的发展,Spring已经不再是一个单纯的应用框架,而是逐渐发展成为一个由多个不同子项目(模块)组成的成熟技术,例如SpringFramework、......
  • Powershell 实现telnet 服务端
    Write-Host"这是一个简单的TCP服务器,用于监听指定的端口,并接收来自客户端的数据。"Write-Host"客户端请使用telnetIP+端口的方式连接至服务器"Write-Host"目前同时只支持单个客户端,请勿连接多个客户端,会导致程序运行异常"Write-Host"作者:ID404"Write-Host"版本:1.0"......
  • 简易版扫雷游戏的实现(可能)
    其实我没怎么玩过这游戏,除了在古早的xp系统上见到过内置的扫雷软件外,稍微玩过几把后就体验到了脑补雷的位置并推断地雷的位置是一件多么烧脑的事情,遂放弃了。其实我更喜欢玩蜘蛛纸牌。好了废话就讲这几句=-=嗯,首先,我们要知道扫雷游戏是怎么实现的呢?下面来看一张图:这个是微软出品的......
  • Java之集合及其练习
     1.ArrayList集合和数组的优势对比:长度可变添加数据的时候不需要考虑索引,默认将数据添加到末尾1.1ArrayList类概述什么是集合提供一种存储空间可变的存储模型,存储的数据容量可以发生改变ArrayList集合的特点长度可以变化,只能存储引用数据类型。泛型的使用用于约束集合中存储元素......
  • UART串口介绍和演示
    UART(通用异步收发器)是一种广泛用于串口通信的协议,它在嵌入式系统中起着重要的作用。本文将介绍UART串口的基本原理,并通过代码演示如何在嵌入式系统中使用UART进行通信。UART串口概述UART串口是一种异步通信协议,它使用两个引脚进行数据传输:一个用于发送(TX-Transmit)和一个用于接收(R......
  • 【实用小教程】如何批量导出、备份微信通讯录好友
    6-11对于有微信通讯录备份需求的人来说,要把微信的通讯录联系人的微信号、备注的手机号等信息弄出来,有不少困难,因为微信本身不提供这样的功能,所以如果要一个个抄,是不太现实的。本教程要解决的问题就是微信通讯录备份的问题,速度贼快,原理就是通过分析微信存储在本地的文件,直接从文件里......
  • MySQL的函数
    MySQL的函数概述:在MySQL中,为了提高代码重用性和隐藏实现细节,MySQL提供了很多函数函数可以理解为别人封装好的模板代码(相当于java中的方法)在MySQL中,函数非常多,主要可以分为以下几类聚合函数数学函数字符串函数日期函数控制流函数窗口函数聚合函数——group_concat()概述:在MySQL中,聚......
  • IP
    1.IP“与”运算:看作是十进制的相乘1与1=1,1与0=0与0=0,与完后再将转换成十进制例:11010000.10101000.00000010.0110010011111111.11111111.00000000.00000000‘与’运算得11010000.10101000.00000000.00000000 转换为十进制得:208.168.0.02.可用主机位数:子网掩码:1.0:子网......
  • P2722 [USACO3.1] 总分 Score Inflation
    还是选与不选的问题,但是每个背包可以无限次选,所以这是个完全背包!#include<bits/stdc++.h>usingnamespacestd;constintN=2e4+10;intf[N],w[N],t[N];intmain(){ intn,m; cin>>n>>m; for(inti=1;i<=m;i++){ cin>>w[i]>>t[i]; } for(inti=1;i<=m;i+......