动态加密算法设计方案

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

动态加密算法设计方案

一、需求概述

在当前大多数的C/S结构系统中,客户端同服务器之间的通讯协议加密算法大多为一端使用一固定算法对协议数据加密,另一端采用一对应的解密算法进行解密的形式。

因为协议解密算法就保存在客户端,这就为反汇编分析解密算法成为可能。在游戏外挂逐渐的产业化,游戏外挂制作者越来越职业化的今天,这种传统的单一算法加密方式已远远不能满足实际的需要。为更好的保护游戏通讯协议的安全性,增加游戏外挂制作者的破解难度。就需要一种更为可靠不易于被破解掉的通讯协议加密技术。

二、设计目标

本方案分服务器调用模块和客户端调用模块两部分组成。当客户端和服务器端成功的建立一个会话机制后,由服务器端随即产生一个协议加密算法给分配给客户端,以后凡客户端发往服务器的所有通讯数据都使用该算法进行加密,服务器收到该加密数据后使用一个与之对应的解密算法解密并使用。针对服务器和客户端分别提供一个类库的形式供服务器和客户端调用。其中服务器端可以从一个动态连接库(DLL)文件中提取算法。

三、功能模块

a)加解密算法库DLL编写约束

1、加解密算法函数导出序号必须按照实现实现代码中的排列顺序进行排序。

2、必须实现一个空的函数放在所有函数的结尾,以备用来计算最后一个可用算法

的代码长度。如不实现该函数则最后一个可用算法函数将被忽略。

3、加密函数算法和解密函数算法分别在两个不同的DLL中实现,其函数的加解

密关系必须按照函数导出顺序一一对应。

4、加密函数和解密函数的参数及函数调用规范必须一致。(统一使用__stdcall调

用规范)

加解密函数类型如下:

typedef int (__stdcall *FUNC)(LPBYTE lpByte, int Len);

5、导出函数中不能使用全局变量、指向非函数内部地址的指针、函数地址等。只

能使用纯算法对lpByte中的数据进行变形运算。

b)服务器端加解密算法DLL管理工具

对加解密模块DLL的增删操作使用一个管理工具实现,由管理工具生成一个配置信息XML文件存储当前使用加解密算法DLL模块列表,操作完成后配置工

具使用内核信号量的方式通知服务器配置更改信号。服务器收到信号后解析XML

文件获取新的配置信息并更新内存中算法列表。

管理工具在添加一个新的DLL算法库时要检测DLL中导出的每个算法是否可用。判断方式为对一个固定数据进行加密解密,判断加解密后的数据是否相同,加

解密过程中是否出现异常等。

c)加解密算法装载模块

该模块完成对DLL信息的管理。包括DLL类型(即加密算法模块或是解密算法模块),导出函数的个数,导出函数地址等信息。

d)供服务器调用模块

由服务器启动时调用该模块导出的接口对该模块进行初始化,该模块根据Config.xml配置文件装载加解密算法DLL,提取DLL中导出函数序号、函数地址、函数长度等信息。并实现方便服务器访问的接口。

该模块初始化完成后,由服务器调用启动一个用来监视DLL模块配置信息更改的线程。该线程等待在一个内核事件上,当该线程收到DLL模块信息更改的事件信号,则重新解析Config.xml,根据配置进行增加或删除更改部分的模块。

e)客户端代码执行模块

该模块负责将服务器传输来到Code Data进行解析,并返回PROC

类型加密和

解密函数指针给客户端程序,由客户端程序根据返回函数地址进行调用。

实现方式为在内存中分配一段具有可读写可执行属性的内存空间,将算法执行体数据写入该空间,使用该空间内存地址作为函数地址使用即可。

四、接口定义

a)加解密算法装载模块与配置工具之间接口

1.配置工具生成Config.xml文件格式如下:

Config.xml文件格式如下:

-

-

其中,changed结点代表本次操作对DLL模块的更新动作,added属性为true时表示做了添加DLL的操作,deleted为true是代表做了删除DLL的操作。当监视线程根据最新的配置信息更新了最新配置后,将这两个值重新设为false。(添加该结点是考虑到实际应用中添加新的DLL的做法较为常见,为了避免刷新所有模块可能会引起系统的不稳定性,当有新DLL加入时只须装载新的DLL接口,不必修改原有DLL信息。)

2.配置工具通知加解密算法装载模块配置更新的事件名称为:

#define EVENT_NAME_CONFIG_CHANGED"Event_Dynamic_DEcryptLib_ConfigChange080414"

b)供服务器调用模块与服务器之间接口

1.int GetArithmeticCount();

获取当前可用的算法个数。一个加密函数和一个与之对应的解密函数记为一个

算法。

返回值:如果成功则返回当前可用的算法个数,失败返回0。

2.int GetEncryptFuncLength([in]int nNumber);

根据指定的索引值获取指定加密函数的代码长度。

输入参数:nNumber为大于等于零小于算法个数的整数类型值。

返回值:成功则返回指定函数的代码长度,失败返回0。

3.LPBYTE GetEncryptFuncAddress([in]int nNumber);

根据指定的索引值获取指定加密函数的代码地址。

输入参数:nNumber为大于等于零小于算法个数的整数类型值。

返回值:成功则返回指定函数的代码地址,失败返回空指针。

4.int GetDecryptFuncLength([in]int nNumber);

同上。

5.int GetDecryptFuncAddress([in]int nNumber);

同上。

6.int CopyCodeData([in]int nNumber, [in]LPBYTE lpAddress, \

[in]DWORD dwBufferSize, [out]DWORD dwWriteSize);

将指定索引值下的算法体组装成Code Data结构体形式写入到lpAddress指向的

内存空间内。(CodeData结构体定义见CodeData结构体示意图)

输入参数:nNumber为指定索引值,lpAddress为用来接收生成的CodeData结

构的内存空间地址,dwBufferSize为该内存块的大小,dwWriteSize为生成的

CodeData结构体块的大小。

返回值:成功返回1,失败返回0。如因为传入的内存块大小不够则在

dwWriteSize中保存所需内存块大小。

7.int RandomGenerateCodeData([in]LPBYTE lpAddress, [in]DWORD

dwBufferSize, [out]DWORD dwWriteSize);

随即选择一个算法并组装成Code Data结构体写入到指定内存块中。参数定义

同CopyCodeData函数。

8.HANDLE StartWatchThread();

相关文档
最新文档