# 缘由

对接供应商时需要提供一个 27 服务的安全解密算法 dll,于是学了一下 vs 批处理生成 C++ 模板的 dll,并使用 C++ 或者 C# 调用 dll 来验证,虽然其中结果有点曲折。难点主要是 C++ 到 C# 数据类型的映射,这个是最麻烦的。

# DLL 封装

UDS 27 服务需要用到安全算法 dll 解密。这里使用的模板是 Canoe 的 dll 生成模板,但是模板代码使用的是 Diva 里的模板代码,模板可以去 vector 官网下载 demo 版,以下是粗略的步骤。

  1. 在配置管理器中选择生成的 DLL 平台

  2. 在批生成界面选择对应平台的 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# 数据类型映射这一块,真的有大坑,不过我不跳,哈哈。

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Jelly27th 微信支付

微信支付

Jelly27th 支付宝

支付宝