# 缘由
对接供应商时需要提供一个 27 服务的安全解密算法 dll,于是学了一下 vs 批处理生成 C++ 模板的 dll,并使用 C++ 或者 C# 调用 dll 来验证,虽然其中结果有点曲折。难点主要是 C++ 到 C# 数据类型的映射,这个是最麻烦的。
# DLL 封装
UDS 27 服务需要用到安全算法 dll 解密。这里使用的模板是 Canoe 的 dll 生成模板,但是模板代码使用的是 Diva 里的模板代码,模板可以去 vector 官网下载 demo 版,以下是粗略的步骤。
在配置管理器中选择生成的 DLL 平台
在批生成界面选择对应平台的 DLL
# 测试
# C++ 调用
#include <iostream> | |
#include <Windows.h> | |
#include <tchar.h> | |
enum VKeyGenResultEx { | |
KGRE_Ok = 0, | |
KGRE_BufferToSmall = 1, | |
KGRE_SecurityLevelInvalid = 2, | |
KGRE_VariantInvalid = 3, | |
KGRE_UnspecifiedError = 4 | |
}; | |
int main() { | |
// loading dll handler | |
HINSTANCE handle = LoadLibrary(_T("GenerateYourself.dll")); | |
// get error code if dll handler is not found | |
if (0 == handle) { | |
std::cout << "dll handle result value:"<< handle <<"\n"; | |
std::cout<< GetLastError() <<std::endl; | |
} | |
// caluate $27 server key | |
else { | |
// define function pointers | |
typedef VKeyGenResultEx(*DLL_FUNCTION_GENERATEKEYEX) (const unsigned char*, unsigned int, | |
const unsigned int, const char*, | |
unsigned char*, unsigned int, | |
unsigned int&); | |
// rename dll_GenerateKeyEx from GenerateKeyEx | |
DLL_FUNCTION_GENERATEKEYEX dll_GenerateKeyEx = (DLL_FUNCTION_GENERATEKEYEX)GetProcAddress(handle, "GenerateKeyEx"); | |
std::cout << "dll handle result value:" << handle << "\n"; | |
if (dll_GenerateKeyEx) { | |
unsigned char seed[4] = {your_seed}; | |
unsigned int seedSize = 4; | |
unsigned int SecurityLevel = YourSecurityLevel; | |
char ipVariant[4] = "123"; | |
unsigned char key[4] = {0}; | |
unsigned int maxKeySize = 4; | |
unsigned int KeySize = 4; | |
dll_GenerateKeyEx(seed, seedSize, SecurityLevel, | |
ipVariant, key, maxKeySize, KeySize); | |
std::cout << "seed: "; | |
for (int i = 0; i < sizeof(seed); i++) { | |
std::cout << std::hex <<(int)seed[i] << " "; | |
} | |
std::cout << "\nkey: "; | |
for (int i = 0; i < sizeof(key); i++) { | |
std::cout << std::hex <<(int)key[i] << " "; | |
} | |
FreeLibrary(handle); //free handle | |
} | |
} | |
return 0; | |
} |
注,该代码只能调用 X64 的 DLL,不能调用 32 位的 DLL,推测是因为计算机是 64 位的原因,目前 32 位的 DLL 怎么调用暂时没找到方法。
# C# 调用
using System; | |
using System.Runtime.InteropServices; | |
namespace CallTheDll01 | |
{ | |
class Program | |
{ | |
public enum VKeyGenResultEx { | |
KGRE_Ok = 0, | |
KGRE_BufferToSmall = 1, | |
KGRE_SecurityLevelInvalid = 2, | |
KGRE_VariantInvalid = 3, | |
KGRE_UnspecifiedError = 4 | |
}; | |
// must use CallingConvention.Cdecl,otherwise program will error | |
[DllImport("GenerateYourself.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] | |
public static extern VKeyGenResultEx GenerateKeyEx(Byte[] ipSeedArray, UInt32 iSeedArraySize, | |
UInt32 iSecurityLevel, String ipVariant, | |
Byte[] iopKeyArray, UInt32 iMaxKeyArraySize, | |
ref UInt32 oActualKeyArraySize); | |
static void Main(string[] args) { | |
// Byte 为 8 位的无符号整数类型,范围为 0~255,默认显示十进制 | |
Byte[] seed = {your_seed}; | |
UInt32 seedSize = 4; | |
UInt32 SecurityLevel = YourSecurityLevel; | |
String ipVariant = "123"; | |
Byte[] key = {0x0, 0x0, 0x0, 0x0}; | |
UInt32 maxKeySize = 4; | |
UInt32 KeySize = 4; | |
GenerateKeyEx(seed, seedSize, SecurityLevel, ipVariant, key, maxKeySize, ref KeySize); | |
Console.WriteLine("seed: " + BitConverter.ToString(seed).Replace("-", " ")); | |
Console.WriteLine("key: " + BitConverter.ToString(key).Replace("-", " ")); | |
// Console.ReadKey(); | |
} | |
} | |
} |
这里 C# 调用 DLL 使用的是 P/Invoke 方法,另外还有两种方法,不过不太想了解了。
注:这 C# 鬼东西花了我一天时间才弄完,主要是 C++ 到 C# 数据类型映射这一块,真的有大坑,不过我不跳,哈哈。