包含以下几块,如果没你需要的东西,可以继续赶路了
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 ) ;[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 delegate int _DeleGateMemPreAlloc(byte [] plaintext, int plaintext_length, byte []);/:委托函数的实例化 _DeleGateMemPreAlloc MemPreAlloc; DllInvoke dllInvoke = new DllInvoke(SECUREDLL); 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; File.WriteAllBytes(tempFile, byDll); return tempFile; } ~LoadResource() { } } }
最后获取扒拉一下dll中函数名字的获取和原型的获取
名字比较简单: dll export viewer
原型获取,就需要动用大名鼎鼎的IDA了,这里安利一下看雪学院,工具都可以下载,也建议多看看。
打开dll,然后找找目标函数,然后双击进入,按一下F5 。。。不上图了。。自己看吧