使用C#调用其它exe中的函数

需求:

目前想改造一个带有窗口的exe文件,将其使用WPF来实现。
这个exe文件中最重要的一段内容就是一个函数(int f(int a,int b)),使用这个f函数来实现其核心的计算功能。

问题:

当前,没有exe文件的源码,因此无法使用C#简单地重写这个f函数。但我们可以考虑在C#代码中直接调用这个函数来进行计算。

困难:

exe没有导出这个f函数,因此在C#中无法直接使用DllImport来进行PInvoke调用。

方法:

1、在C#中通过Windows Api中的LoadLibrary把这个exe文件加载到内存。
2、使用IDA找到f函数在这个exe文件中的偏移量。
3、在C#中通过f函数的地址直接调用。

C语言演示代码:

#include <iostream>

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

int main()
{
    
    
    std::cout << "Hello World! C++\n";
}

这里有一个f函数,还有一个main函数,其中我们要关心的计算函数为f。main是启动函数,我们不用关心。
这里f函数,并未导出。也就是说,在程序的函数导出表中,不存在f函数。其它程序无法使用常用的方式来调用它。

IDA查看函数位置

在这里插入图片描述

C#演示代码

internal class Program
{
    
    
    //定义委托,对应于C语言中的函数原型
    //int f(int a,int b)
    public delegate int F(int a, int b);

    static void Main(string[] args)
    {
    
    
        IntPtr hLib = LoadLibrary("C:\\Users\\Zmrbak\\source\\repos\\ConsoleApplication1\\Debug\\ConsoleApplication1.exe");
        if (hLib == IntPtr.Zero)
        {
    
    
            Console.WriteLine("加载exe文件失败!");
            return;
        }

        //函数地址
        var offset = hLib + 0x12380;

        int a = 10;
        int b = 20;
        var a1 = (F)Marshal.GetDelegateForFunctionPointer(offset, typeof(F));

        if (a1 != null)
        {
    
    
            //调用函数
            var c = a1(a, b);
            Console.WriteLine(c);
        }
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr LoadLibrary(string lpFileName);
}

在C#的启动函数main中,首先将这个exe文件加载到内存,这会得到一个加载的地址。
接下来通过偏移量 0x12380,计算出这个函数在内存中的实际位置。
然后,通过这个地址来调用。
这里需要注意,调用的时候,需要用到委托(delegate ),它可以将一个函数地址转换成一个函数,从而按照C#的标准来调用。

执行结果:

30

C:\Users\Zmrbak\source\repos\ConsoleApplication1\ConsoleApp1\bin\Debug\net6.0\ConsoleApp1.exe (进程 14816)已退出,代码为 0。
要在调试停止时自动关闭控制台,请启用“工具”->“选项”->“调试”->“调试停止时自动关闭控制台”。
按任意键关闭此窗口. . .

后记

另外,你还可以看到,程序运行的时候,只调用了C语言编写的f函数,C语言编写的main函数并未调用。从而达到了我们的目的,完成了我们的需求。

猜你喜欢

转载自blog.csdn.net/u013667796/article/details/130024463