C# 调用dll以及内置dll到exe内部

包含以下几块,如果没你需要的东西,可以继续赶路了

1: C# 对的dll的两种调用

2: dll包含到exe中

3:dll的函数原型获取

最近听闻人到中年的比尔盖茨收购了github并免费了私有的代码仓库,不由的给他点了一波赞,然后嘛就顺手把一个小项目用C#重写了一下,毕竟自从net开源了mono和.net core后,以后做gui也可以用C#这种快速预言了。哈哈,不用整天纠结在C++(QT)的各种内存泄漏等问题了。

额外吐槽一下C#反编译的问题,就你麻麻的没有加密,反编译出来就是源码。。。几个意思啊

现在开始正题, Part 1: C# call dll (这里的库没有广泛测试,各位DIY一下)。

Method 1: DLLimport

1
2
3
4
5
6
7
8
9
10
11
12
13
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern void FreeLibrary(IntPtr hModule);

[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr LoadLibrary(string lpFileName);

[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern IntPtr GetProcAddress(IntPtr hModule, string lpFileName);

//static load dll
[DllImport("test.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode, EntryPoint = "MemPreAlloc")]

public static extern int MemPreAlloc(byte[] plaintext, int plaintext_length, byte[] ciphertext, int ciphertext_length);

然后就这么简单。。哈哈

Method 2: 动态导入

有时需要动态调用dll中的函数,比如我,为了避免神奇的乙方多次搞丢dll的问题,需要把dll内嵌到exe的资源区段中,需要的时候释放出来(这个是改日聊内容)。

这里需要用到 IntPtr GetProcAddress(IntPtr hModule, string lpFileName)函数获取对应函数的地址,然后再使用C#的delegate委托方法调用。。其实感觉委托就是C语言中的函数申明。。。(C#高手放过不专业的描述)

实现逻辑如下:

1: 声明待导出函数的原型(C#变量对应问题,请自行百度)

2:打开dll (LoadLibrary)

3: 获取函数地址,通过Marshal.GetDelegateForFunctionPointer 函数对函数进行类型转换到目标的委托方法

4: 自己调用了。。

上代码:

1
2
3
4
5
6
7
8
9
10
//1:委托函数的类型声明,感觉等同于C语言函数指针的声明
delegate int _DeleGateMemPreAlloc(byte[] plaintext, int plaintext_length, byte[]);
/:委托函数的实例化
_DeleGateMemPreAlloc MemPreAlloc;

//委托函数的赋值

DllInvoke dllInvoke = new DllInvoke(SECUREDLL);//这个类看下边哈。。。包含打开dll,获取函数
MemPreAlloc = (_DeleGateMemPreAlloc)dllInvoke.Invoke("MemPreAlloc", typeof(_DeleGateMemPreAlloc));

这里有两个大坑导致 C# 不能导出dll中的函数地址,没经验没办法,记录下来给大家分享:

1: 调用目标程序的类型需要和dll一致,如x86,x64必须一致,至于x64能不能call x86,你们自己测试吧,理论应该可以的

2:LoadLibrary 功能不能和调用函数在同一个文件中。。原因母鸡,解决方法就是对LoadLibrary 进行一层包装,说白了定时定义一个类包起来。。。上代码不BB DllInvoke.cs: 然后就德芙巧克力一样的丝滑了。。。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace DMT_AES_TOOL
{
public class DllInvoke
{
#region Win API
[DllImport("kernel32.dll")]
private extern static IntPtr LoadLibrary(string path);

[DllImport("kernel32.dll")]
private extern static IntPtr GetProcAddress(IntPtr lib, string funcName);

[DllImport("kernel32.dll")]
private extern static bool FreeLibrary(IntPtr lib);
#endregion

private IntPtr hLib;
public DllInvoke(String DLLPath)
{
hLib = LoadLibrary(DLLPath);
}

~DllInvoke()
{
FreeLibrary(hLib);
}

//将要执行的函数转换为委托
public Delegate Invoke(string APIName, Type t)
{
IntPtr api = GetProcAddress(hLib, APIName);
if (api == IntPtr.Zero)
throw new ArgumentNullException("找不到img资源入口");
else
return (Delegate)Marshal.GetDelegateForFunctionPointer(api, t);
}
}
}

最后贴一个内置dll文件到exe内,并悄悄释放,然后调用的实现。

1: 我这里dll改名成test.img, 然后在C#工程中添加一个资源文件Resource1.resx

2: 释放dll资源到临时文件,这里直接上代码 LoadResource.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DMT_AES_TOOL
{
class LoadResource
{
LoadResource()
{

}
public static string Load()
{

string tempFile = Path.GetTempFileName();//临时文件准尉

byte[] byDll = Resource1.test;//看这里看这里。我之前的文件是test.img这里直接就能获取到目标的byte[]数据了

File.WriteAllBytes(tempFile, byDll);//释放了dll到临时文件
// Clipboard.SetDataObject(tempFile, true);
// MessageBox.Show("temp resource file -> " + tempFile + " size ->" + byDll.GetLength(0).ToString());

return tempFile;//文件释放出来给DllInvoke导出函数哈哈哈
}
~LoadResource()
{

}

}
}

最后获取扒拉一下dll中函数名字的获取和原型的获取

名字比较简单: dll export viewer

原型获取,就需要动用大名鼎鼎的IDA了,这里安利一下看雪学院,工具都可以下载,也建议多看看。

打开dll,然后找找目标函数,然后双击进入,按一下F5 。。。不上图了。。自己看吧