C++函数地址

前言

本文论证了以下结论

  • 类函数本质就是普通函数,第一个参数是类实例 func(cls*, ...)
  • 函数地址就是模块地址(GetModuleHandle)+ 偏移量(dumpbin /exports dll.dll)得到
    • 不包括虚函数,虚函数地址需要通过虚表获取
  • 如果你可以获取到某个类实例地址,那么通过 GetModuleHandle + GetProcAddress 的方式可以调用第三方程序的方法

dll.h

#ifndef FUNC_ADDRESS_DLL_H
#define FUNC_ADDRESS_DLL_H

#ifdef DLL_EXPORTS
#   define DLL_API __declspec(dllexport)
#else
#   define DLL_API __declspec(dllimport)
#endif // DLL_EXPORTS

class DLL_API Dll
{
public:
    Dll();
    
    int add_a(int a, int b);
};

int DLL_API add_b(int a, int b);

extern "C" int DLL_API add_c(int a, int b);

#endif // !FUNC_ADDRESS_DLL_H

dll.cpp

#define DLL_EXPORTS
#include "dll.h"

#include <iostream>

Dll::Dll()
{
}
    
int Dll::add_a(int a, int b)
{
    std::cout << "this = " << this << std::endl;
    return a + b;
}

int add_b(int a, int b)
{
    return a + b;
}

int add_c(int a, int b)
{
    return a + b;
}

main.cpp

#include "dll.h"
#include <iostream>
#include <Windows.h>

using namespace std;

typedef int(*AddFunc)(int a, int b);
typedef int(*HackFunc)(Dll *, int a, int b);

int main()
{
    Dll dll;

    union
    {
        void *pv;
        int(Dll::* pfn)(int, int);
        int(*fn) (Dll *, int a, int b);
    } u;
    u.pfn = &Dll::add_a;
    cout << "Dll::add_a = " << &Dll::add_a << ", u.pv = " << u.pv << endl;

    cout << "u.fn(nullptr, 10, 20) = " << u.fn(nullptr, 10, 20) << endl;
    cout << "u.fn(dll, 10, 20) = " << u.fn(&dll, 10, 20) << endl;
    cout << "(dll.*u.pfn)(10, 20) = " << (dll.*u.pfn)(10, 20) << endl;

    int a = dll.add_a(10, 20);
    cout << "Dll::add_a(20, 30)[" << &Dll::add_a << "] = " << a << endl;

    int b = add_b(10, 20);
    cout << "add_b(10, 20)[" << &add_b << "] = " << b << endl;

    int c = add_c(10, 20);
    cout << "add_c(10, 20)[" << &add_c << "] = " << c << endl;

    HMODULE hmod = GetModuleHandleA("dll.dll");
    cout << "hmod: " << hmod << endl;
    AddFunc proc = (AddFunc)GetProcAddress(hmod, "add_c");
    if (proc)
    {
        cout << "dynamic add_b(10, 20) = " << proc(10, 20) << endl;
    }

    return 0;
}

运行结果

Dll::add_a = 1, u.pv = 00007FFCA42E1073
this = 0000000000000000
u.fn(nullptr, 10, 20) = 30
this = 00000010975DF7D4
u.fn(dll, 10, 20) = 30
this = 00000010975DF7D4
(dll.*u.pfn)(10, 20) = 30
this = 00000010975DF7D4
Dll::add_a(20, 30)[1] = 30
add_b(10, 20)[00007FFCA42E102D] = 30
add_c(10, 20)[00007FFCA42E100A] = 30
hmod: 00007FFCA42E0000
dynamic add_b(10, 20) = 30

dumpbin /exports dll.dll

Microsoft (R) COFF/PE Dumper Version 14.29.30133.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file dll.dll

File Type: DLL

  Section contains the following exports for dll.dll

    00000000 characteristics
    FFFFFFFF time date stamp
        0.00 version
           1 ordinal base
           6 number of functions
           6 number of names

    ordinal hint RVA      name

          1    0 00001136 ??0Dll@@QEAA@XZ = @ILT+305(??0Dll@@QEAA@XZ)
          2    1 0000113B ??4Dll@@QEAAAEAV0@$$QEAV0@@Z = @ILT+310(??4Dll@@QEAAAEAV0@$$QEAV0@@Z)
          3    2 000010A0 ??4Dll@@QEAAAEAV0@AEBV0@@Z = @ILT+155(??4Dll@@QEAAAEAV0@AEBV0@@Z)
          4    3 00001073 ?add_a@Dll@@QEAAHHH@Z = @ILT+110(?add_a@Dll@@QEAAHHH@Z)
          5    4 0000102D ?add_b@@YAHHH@Z = @ILT+40(?add_b@@YAHHH@Z)
          6    5 0000100A add_c = @ILT+5(add_c)

  Summary

        1000 .00cfg
        1000 .data
        2000 .idata
        1000 .pdata
        3000 .rdata
        1000 .reloc
        1000 .rsrc
        9000 .text

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值