CANoe DLL编程—— DLL 的二次封装

Posted 蚂蚁小兵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CANoe DLL编程—— DLL 的二次封装相关的知识,希望对你有一定的参考价值。

相关文章

CANoe DLL编程(一)—— Visual Studio 创建DLL以及动态调用

CANoe DLL编程(二)—— 创建CANoe适用的DLL以及调用

CANoe DLL编程(三)——DLL和回调函数
CANoe DLL编程(四)——SendKey DLL的CANoe应用
CANoe DLL编程(五)——通过VS 生成 SendKey.dll


前言

  • 实际工程中,会产生这种情况,OEM给了你seedkey.dll ,没有给你具体算法,因为它不希望自己密钥泄露,作为供应商,还有自己的subfunction,这个时候,我们就需要在OEM提供的DLL基础上,再封装一层。

  • 这一节内容依赖 CANoe DLL编程(一)的内容,请先阅读,再看这一节。

  • 软件环境:
    win10 x64
    visual studio 2019
    CANoe 11 x64



增加 27服务 13 subfunction

①,这里假设我们之前生成的DLL SeednKey_Opt_More.dll 是客户给的,seedkey 的算法是保密的,只有level1和level 11,现在我们要把自己的level 13加进去`

  • 我们把 KeyGenDll_GenerateKeyEx - Copy 拷贝一份KeyGenDll_GenerateKeyEx_Level_13


②,我们完善KeyGenDll_GenerateKeyEx_Level_13工程中的代码,然后重新rebuild。

  • 我原来实际工程可以直接 LoadLibrary(_T(“SeednKey_Opt_More.dll”))
    就可以了,这里不知道为什么不行了,必须用绝对路径才行

  • 就两个函数 GenerateKeyExOpt ,CANoe API的接口,和原来一样;GenerateKeyExOpt_new 我自己新定义的,用来封装DLL

// KeyGeneration.cpp : Defines the entry point for the DLL application.
//

#include <windows.h>
#define KEYGENALGO_EXPORTS
#include "KeyGenAlgoInterfaceEx.h"
#include <tchar.h>
#include <iostream>


BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    return TRUE;
}

int GenerateKeyExOpt_new(
    const unsigned char* ipSeedArray,     /* Array for the seed [in] */
    unsigned int          iSeedArraySize, /* Length of the array for the seed [in] */
    const unsigned int    iSecurityLevel, /* Security level [in] */
    const char* iVariant,       /* Name of the active variant [in] */
    const char* ipOptions,
    unsigned char* ioKeyArray,     /* Array for the key [in, out] */
    unsigned int          iKeyArraySize,  /* Maximum length of the array for the key [in] */
    unsigned int& oSize           /* Length of the key [out] */
)
{

    HINSTANCE handle = LoadLibrary(_T("C:\\\\Users\\\\Public\\\\Documents\\\\Vector\\\\CANoe\\\\Sample Configurations 11.0.55\\\\CAN\\\\Diagnostics\\\\UDSSystem\\\\SecurityAccess\\\\SeednKey_Opt_More.dll"));//LoadLibrary填入ddl文件名赋值给句柄
    printf("dll的句柄返回值%d\\n", handle); //打印吧

    if (handle) //判读句柄内dll是否可用
    {

        typedef int(*DLL_FUNCTION_GenerateKeyExOpt) (const unsigned char*, unsigned int, const unsigned int, const char*, const char*, unsigned char*, unsigned int, unsigned int&); //typedef定义一下函数指针,你不懂的话就记住末尾两个是你需要函数的形参。

        DLL_FUNCTION_GenerateKeyExOpt dll_GenerateKeyExOpt = (DLL_FUNCTION_GenerateKeyExOpt)GetProcAddress(handle, "GenerateKeyExOpt"); //使用GetProcAddress得到函数,参数是句柄名和函数名
        printf("dll_函数返回值%d\\n", dll_GenerateKeyExOpt); //打印吧
        if (dll_GenerateKeyExOpt) //还是判断一下函数指针是否有效
        {
            int result = dll_GenerateKeyExOpt(ipSeedArray, iSeedArraySize, iSecurityLevel, iVariant, ipOptions, ioKeyArray, iKeyArraySize, oSize);
        }
        FreeLibrary(handle); //卸载句柄,,
    }
    return 0;
}

KEYGENALGO_API VKeyGenResultEx GenerateKeyExOpt(
      const unsigned char*  ipSeedArray,     /* Array for the seed [in] */
      unsigned int          iSeedArraySize, /* Length of the array for the seed [in] */
      const unsigned int    iSecurityLevel, /* Security level [in] */
      const char*           iVariant,       /* Name of the active variant [in] */
      const char* ipOptions,
      unsigned char*        ioKeyArray,     /* Array for the key [in, out] */
      unsigned int          iKeyArraySize,  /* Maximum length of the array for the key [in] */
      unsigned int&         oSize           /* Length of the key [out] */
      )
{
    int result;
    if (iSeedArraySize>iKeyArraySize)
      return KGRE_BufferToSmall;
    if (iSecurityLevel == 0x01)
    {
        result = GenerateKeyExOpt_new(ipSeedArray, iSeedArraySize, iSecurityLevel, iVariant, ipOptions, ioKeyArray, iKeyArraySize, oSize);
    }
    else if (iSecurityLevel == 0x11)
    {
        result = GenerateKeyExOpt_new(ipSeedArray, iSeedArraySize, iSecurityLevel, iVariant, ipOptions, ioKeyArray, iKeyArraySize, oSize);
    }
    else if (iSecurityLevel == 0x13)
    {
        for (unsigned int i = 0; i < iSeedArraySize; i++)
            ioKeyArray[i] = ipSeedArray[i] - 1;
    }
    else
    {
        return KGRE_SecurityLevelInvalid;
    }
    oSize = iSeedArraySize;  
  return KGRE_Ok;
}

  • 生成新的DLL,重命名为 SeednKey _Opt_More_level13.dll ,拷贝到 SecurityAccess文件路径下


③,因为官方示例中诊断控制台没有 level 13的诊断定义,暂时手上也没有编辑工具,我们只能在simulation node脚本中处理下:

  • DoorFL.can 中更改代码如下,当收到 27 1327 14 xx xx诊断请求的时候,给诊断仪响应
on diagRequest DoorFL.*
{
//  ResetSession();
//  diagSendNegativeResponse(this, cNRC_ServiceNotSupported); 
    diagResponse DoorFL.SeedLevel_0x01_Request rqRequestSeed;
    diagResponse DoorFL.KeyLevel_0x01_Send rqKeytSeed;
    diagResponse this resp;
    long result_1,result_2;
    word random;

    result_1 = DiagGetPrimitiveByte(this,0);
    result_2 = DiagGetPrimitiveByte(this,1);
    write("*diagRequest*****result_1:%x ;result_2:%x ;*****",result_1,result_2);
  if ((result_1 == 0x27) && (result_2 == 0x13) )
  {
    random=random(0x10000);
    write("****** random Seed is 0x%x ******",random);
    DiagSetPrimitiveByte(rqRequestSeed,0,0x27);
    DiagSetPrimitiveByte(rqRequestSeed,1,0x13);
    DiagSetPrimitiveByte(rqRequestSeed,2,random&0xFF);
    DiagSetPrimitiveByte(rqRequestSeed,3,(random>>8)&0xFF); 
    rqRequestSeed.SendPositiveResponse() ; 
  }  
    if ((result_1 == 0x27) && (result_2 == 0x14) )
  {
    DiagSetPrimitiveByte(rqKeytSeed,0,0x27);
    DiagSetPrimitiveByte(rqKeytSeed,1,0x14);
    rqKeytSeed.SendPositiveResponse() ; 
  }  
}

  • TesterPanelControl.can 中更改代码如下:
  • 按键‘b’ ,发送27 13请求。
  • 当收到 27 13 xx xx 响应的种子时,计算key,然后 发送27 14 xx xx
on diagResponse DoorFL.*
{
//  ResetSession();
//  diagSendNegativeResponse(this, cNRC_ServiceNotSupported); 
  
  diagRequest DoorFL.KeyLevel_0x01_Send reqKeySend;
  
  word seed;
  word securityKey;
  byte seedArray[2];
  byte keyArray[2];
  dword keyActualSizeOut;
  long result_1,result_2;
  word random;

  result_1 = DiagGetPrimitiveByte(this,0);
  result_2 = DiagGetPrimitiveByte(this,1);
  write("**diagResponse****result_1:%x ;result_2:%x ;*****",result_1,result_2);
  if ((result_1 == 0x27) && (result_2 == 0x13) )
  {
  seedArray[0]=DiagGetPrimitiveByte(this,2);
  seedArray[1]=DiagGetPrimitiveByte(this,3);
  
  write("**diagResponse****seedArray[0]:%x ;seedArray[1]:%x ;*****",seedArray[0],seedArray[1]);
  diagGenerateKeyFromSeed(gECU, seedArray , 2, 0x13, "", "" , keyArray, elcount(keyArray), keyActualSizeOut); 
  
  securityKey=(((word)keyArray[1])<<8) | keyArray[0];
  write("****** create key (27 02 send) is 22222 step exec ******");
  write("**diagResponse****keyArray[0]:%x ;keyArray[1]:%x ;*****",keyArray[0],keyArray[1]);
  DiagSetPrimitiveByte(reqKeySend,0,0X27);
  DiagSetPrimitiveByte(reqKeySend,1,0X14);
  DiagSetPrimitiveByte(reqKeySend,2,keyArray[0]);
  DiagSetPrimitiveByte(reqKeySend,3,keyArray[1]);
  // Checking on return values indicating an error when sending the requests or when receiving the responses was omitted here to simplify the example
  reqKeySend.SendRequest();
  } 
}

On key 'b' 
{
  diagRequest DoorFL.SeedLevel_0x01_Request rqRequestSeed;
  diagRequest DoorFL.ExtendedDiagnosticSession_Start reqExtSession;
  reqExtSession.SendRequest();  
  DiagSetPrimitiveByte(rqRequestSeed,0,0x27);
  DiagSetPrimitiveByte(rqRequestSeed,1,0x13);
  rqRequestSeed.SendRequest();
 
}

④,配置下新创建的DLL SeednKey _Opt_More_level13.dll

  • 在诊断控制台 分别发送 1003 / 2701/2702/2711/2712 ,控制台输出结果如下图,可以看出 level 1 和 11seedkey 是能够正常响应的,没问题的。

  • 按下按键’b‘ ,发送 27 13,这里只能在write 窗口和 trace 中观察结果,key值计算正确的。这说明通过二次封装DLL成功了。



总结

这个系列演示用到的源码

  • 要有最朴素的生活,最遥远的梦想,即使明天天寒地冻,路遥马亡!
  • 如果这篇博客对你有帮助,请 “点赞” “评论”“收藏”一键三连 哦!码字不易,大家的支持就是我坚持下去的动力。

以上是关于CANoe DLL编程—— DLL 的二次封装的主要内容,如果未能解决你的问题,请参考以下文章

CANoe DLL编程—— 创建CANoe适用的DLL以及调用

CANoe DLL编程——SendKey DLL的CANoe应用

CANoe DLL编程——通过VS 生成 SendKey.dll

CANoe DLL编程——DLL和回调函数

CANoe不能自动识别串口号?那就封装个DLL让它必须行

C# winform多线程案例