首先感谢您能看这篇文章,写的不好,请您见谅!
目的:普及一下Rockey4锁的基本知识及分析的一些方法。
      有机会分析一下Rockey4的锁壳。
练习内容:系统所带的文件
说明:Rockey4 下文中简称R4 R4分并口和USB锁,外壳颜色有区分
      硬件ID也常是下文中说的流水号

一、调用锁的指令

1. 查找锁(RY_FIND)
目的: 查找指定密码的加密锁是否存在
输入参数:
function = RY_FIND  功能码 1
*p1 = 密码1    //必须
*p2 = 密码2    //必须
*p3 = 密码3 (可选)
*p4 = 密码4 (可选)
返回:
retcode = 0 表示成功,其它为错误码。无锁错误码为3
当成功时,*lp1 中为加密锁的硬件ID

//说明:1)密码1及密码2的是必须的,也是查找锁的基础,也称为一级口令。
        密码3和密码4是高级密码,只有有了这一组密码才可以写锁的用
        户ID区,模块区,自定义算法区,这三块的内容中除用户ID区
        外,其它二个正是锁的复制难点之处。
        2)返回的lp1中数据类型为无符号整数,这一个也正是识别不同的R4
        锁的重要之处。同时也是一些软件加密要用的内容。因为厂商号称
        硬件ID全世界唯一。

2.查找下一锁(RY_FIND_NEXT)
目的: 查找是否还有指定密码的加密锁
输入参数:
function = RY_FIND_NEXT
*p1 = 密码1
*p2 = 密码2
*p3 = 密码3 (可选)
*p4 = 密码4 (可选)
*lp1 = RY_FIND或RY_FIND_NEXT所找到的上一把加密锁的硬件ID
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,*lp1 中为加密锁的硬件ID

3. 打开锁(RY_OPEN)
目的: 打开指定密码及硬件ID 的加密锁
输入参数:
function = RY_OPEN
*p1 = 密码1   //和1功能中应该相同,且不可改变Lp1中的硬件ID
*p2 = 密码2   //和1功能中应该相同
*p3 = 密码3 (可选)
*p4 = 密码4 (可选)
*lp1 = 硬件ID
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,*handle 为加密锁的句柄
lp2 为加密锁的类型
TYPE_ROCKEY4      1 // ROCKEY4 标准并口类型
TYPE_ROCKEY4P     2 // ROCKEY4+增强并口类型
TYPE_ROCKEYUSB    3 // ROCKEY4 标准USB 类型
TYPE_ROCKEYUSBP   4 // ROCKEY4+增强USB 类型
TYPE_ROCKEYNET    5 // ROCKEY4 网络并口类型
TYPE_ROCKEYUSBNET 6 // ROCKEY4 网络USB 类型

//说明: 在lp2中的类型比较重要,一些锁用的比较好的。会判断当
         前的锁的类型,如果类型不对,就是其它的参数相同,也会
         不认当前的锁。
         在这里请注意锁的类型不同,相应的数据量也不同,标版内
         存区为24个字节,自定义算法区 32条指令,增强版及网络版
         内存区为120个字节,自定义算法区为80条指令。

4. 关闭锁(RY_CLOSE)
目的: 关闭相应handle 的加密锁
输入参数:
function = RY_CLOSE
*handle = 锁的句柄
返回:
retcode = 0 表示成功,其它为错误码。


5. 读锁(RY_READ)
目的: 读出加密锁用户读写区的内容
输入参数:
function = RY_READ
*handle = 锁的句柄
*p1 = 位置
*p2 = 长度(以字节为单位)
buf = 缓冲区的指针
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,buf 中为读入的内容。

//buf是直接的内存区,在读数据时要根据功能3中返回的类型判断长度,不
  要超长,标版24 增强及网络版是120。

6. 写锁(RY_WRITE)
目的: 向用户读写区内写入内容
输入参数:
function = RY_WRITE
*handle = 锁的句柄
*p1 = 位置
*p2 = 长度(以字节为单位)
buffer = 缓冲区的指针
返回:
retcode = 0 表示成功,其它为错误码。

//说明同上

7. 随机数(RY_RANDOM)
目的: 从加密锁得到一个随机数
输入参数:
function = RY_RANDOM
*handle = 锁的句柄
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,*p1 中为加密锁返回的随机数

//这个在实际加密的过程中没有多大的意义,在自定义的算法中有意
  义,但不是我们调用得到的。这个功能对用户开放无多大的意义。

8. 种子码(RY_SEED)
目的: 得到种子码的返回码
输入参数:
function = RY_SEED
*handle = 锁的句柄
*lp2 = 种子码    //重要之处,在分析时一定要注意这个入口值是多少
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,
*p1 = 返回码1
*p2 = 返回码2
*p3 = 返回码3
*p4 = 返回码4

//说明:4个返回值用处很大,也是加密者经常使用的功能,这个种子码和锁的密
        码相关,同号锁(指密码相同)生成的种子返回值都是相同的。
        这个功能在锁壳的分析中也是难度最大的,如果没有锁,那是没有办法
        知道返回值的,但可以采用变通的方式来完成,从而取得种子码的返回
        值,也就是常说的无锁脱锁壳的方法。

9. 写用户ID [*] (RY_WRITE_USERID)
目的: 写入用户定义的ID
输入参数:
function = RY_WRITE_USERID
*handle = 锁的句柄
*lp1 = 用户ID     //是一个无符号长整型
返回:
retcode = 0 表示成功,其它为错误码。

//这个功能要求在1功能和3功能中打开锁时指定高级密码,否则是不允许写入的,
  如果无高级密码状态下写入次数过多,将可能会损坏锁或将锁锁死,请慎重操作。

10. 读用户ID (RY_READ_USERID)
目的: 读出用户定义的ID
输入参数:
function = RY_READ_USERID
*handle = 锁的句柄
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,*lp1 为用户ID

//读可以不用高级密码。

11. 设置模块[*] (RY_SET_MOUDLE)
目的: 设置模块字及递减属性
输入参数:
function = RY_SET_MOUDLE
*handle = 锁的句柄
*p1 = 模块号
*p2 = 用户模块字
*p3 = 是否允许递减(1 = 允许,0 = 不允许)
返回:
retcode = 0 表示成功,其它为错误码。

//模块的数据比较特殊,只有有高级密码的情况下才可以写,但就是具有了全部的
密码,也不能读出模块的内容,但可以用变通的方法来读出它的数值。

12. 检查模块属性(RY_CHECK_MOUDLE)
目的: 检查模块属性字
输入参数:
function = RY_CHECK_MOUDLE
*handle = 锁的句柄
*p1 = 模块号
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,
*p2 = 1 表示此模块有效
*p3 = 1 表示此模块可以递减

//这一项功能常用在一些试用版的软件上,使用了递减功能,使模块内的数据逐步
  减1,当为0时,当前模块将无效,测试功能也就结束了。


13. 写算法[*] (RY_WRITE_ARITHMETIC)
目的: 向加密锁中写入自定义算法
输入参数:
function = RY_WRITE_ARITHMETIC
*handle = 锁的句柄
*p1 = 算法区位置
buffer = 算法指令串
返回:
retcode = 0 表示成功,其它为错误码。

// 自定义是难度最高的部分,也是这个R4的锁特点之一,可以将一些关键计算写到
锁中,指令格式见后面。但因为锁的自身原因,不可能写入太多的指令,否则软件
的速度会很受影响,算法常是1-10条之间,当然并不一定,如果指令少,还可以用
猜的办法来获得算法,但如果过长,那时间将是天文数字。


14. 计算1 (RY_CALCULATE1)   功能码:E
目的: 让加密锁进行指定方式的运算,计算结果由用户算法决定。
输入参数:
function = RY_CALCULATE1
*handle = 锁的句柄
*lp1 = 计算起始点     //从第几行代码开始执行
*lp2 = 模块号         //模块参与运算
*p1 = 输入值1
*p2 = 输入值2
*p3 = 输入值3
*p4 = 输入值4
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,
*p1 = 返回值1 
*p2 = 返回值2
*p3 = 返回值3
*p4 = 返回值4

//如果指定的起始点不是锁内的自定义算法起始点,那么返回的值都是随机数,
没有多少意义,但正是利用这一点,我们可以判断出锁内有几组算法区。

15. 计算2 (RY_CALCULATE2)  功能码:F
目的: 让加密锁进行指定方式的运算,计算结果由用户算法决定。
输入参数:
function = RY_CALCULATE2
*handle = 锁的句柄
*lp1 = 计算起始点
*lp2 = 种子码    //种子码参与运算
*p1 = 输入值1
*p2 = 输入值2
*p3 = 输入值3
*p4 = 输入值4
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,
*p1 = 返回值1
*p2 = 返回值2
*p3 = 返回值3
*p4 = 返回值4

16. 计算3 (RY_CALCULATE3)   功能码:10H
目的: 让加密锁进行指定方式的运算,计算结果由用户算法决定。
输入参数:
function = RY_CALCULATE3
*handle = 锁的句柄
*lp1 = 计算起始点
*lp2 =模块字起始地址    //完全由模块来参与运算,
*p1 = 输入值1
*p2 = 输入值2
*p3 = 输入值3
*p4 = 输入值4
返回:
retcode = 0 表示成功,其它为错误码。
当成功时,
*p1 = 返回值1
*p2 = 返回值2
*p3 = 返回值3
*p4 = 返回值4



//对于算法来说,直接参数应该是9个,1是位置的起始点 2是 p1,p2,p3,p4 对
  应ABCD 4个入口参数 3就是锁内的E F G H,对应由LP2指定功能区数据,
  E功能中 E硬件ID高位  F硬件ID低位  G模块字    H随机
  F功能中 E是种子码生成的数值1  F数值2   G 数值3   H 数值4 
  10功能中就是模块的值了,由LP2指定的开始模块的连续4个。

17. 递减(RY_DECREASE)
目的: 对指定模块字进行递减操作
输入参数:
function = RY_DECREASE
*handle = 锁的句柄
*p1 = 模块号
返回:
retcode = 0 表示成功,其它为错误码。

//用于测试值中递减模块中的数据

常用错误码
ERR_SUCCESS                0 //没有错误         **最好的一个
ERR_NO_DRIVER              2 //没安装驱动程序 
ERR_NO_ROCKEY              3 //没有ROCKEY       **易用的一个
ERR_INVALID_PASSWORD       4 //有ROCKEY锁,但基本密码错   
ERR_OPEN_OVERFLOW         16 //打开的锁太多(>16)

                    Rockey 4标准版   Rockey4+增强版   NetRockey网络锁
用户可读写内存区大小    24             120                 120
模块字区大小            32              32                  32
算法区大小              64              80                  80
是否支持网络调用        否              否                  是


参数格式:
WORD Rockey
(
 WORD  function,
 WORD*  handle,
 DWORD* lp1,
 DWORD* lp2,
 WORD*  p1,
 WORD*  p2,
 WORD*  p3,
 WORD*  p4,
 BYTE*  buffer
);
 C 语言调用样例,下面的说明都会依照这个样例来说明:
retcode = Rockey(function,handle,lp1,lp2,p1,p2,p3,p4,buffer);
ROCKEY函数的参数定义如下:
 参数名称  参数类型      参数含义
Function  16位数        API 函数功能
Handle    16位数的地址  锁操作句柄的指针
lp1       32位数的地址  长参数1
lp2       32位数的地址  长参数2
p1        16位数的地址  参数 1
p2        16位数的地址  参数 2
p3        16位数的地址  参数 3
p4        16位数的地址  参数 4
Buffer     8位数的地址  字符缓冲区指针
<注意>:
所有的接口参数必须在程序中定义,不能传递一个 NULL 类型的空指针过去,否则程序会出现错误。
1.1 function 是 16 位数字,它代表具体的功能,其定义如下:
 RY_FIND                 1 //找锁
 RY_FIND_NEXT            2 //找下一把锁
 RY_OPEN                 3 //打开锁
 RY_CLOSE                4 //关闭锁
 RY_READ                 5 //读锁
 RY_WRITE                6 //写锁
 RY_RANDOM               7 //产生随机数
 RY_SEED                 8 //产生种子码
 RY_WRITE_USERID         9 //写用户 ID
 RY_READ_USERID         10 //读用户 ID
 RY_SET_MOUDLE          11 //设置模块字
 RY_CHECK_MOUDLE        12 //检查模块状态
 RY_WRITE_ARITHMETIC    13 //写算法
 RY_CALCULATE1          14 //计算 1
 RY_CALCULATE2          15 //计算 2
 RY_CALCULATE3          16 //计算 3
 RY_DECREASE            17 //递减模块单元


算法指令格式

我们所有的算法指令必须是下列形式:
reg1 = reg2 op reg3/value
其中 reg1,reg2,reg3 都是某个寄存器,value 是个立即数,op 是运算符。
例如: A = A + B
我们所支持的所有运算符有:
  +  加法   -  减法   <  循环左移  *  乘法
  ^  异或   &  与     |  或        ~  取反(标准版)
  ?  比较(增强版和网络版)
value 是数值,只能是 0 - 63 之间的十进制数值。

<注意>:

~ 是我们标准版加密锁才有的指令,在增强版和网络版中,原来的这个指令代码被用于
比较,使用新的符号 "?"。
1) ~ 指令是单参数操作符,所以 A = A ~ B 就是 A = ~A 后面的 B 参数被忽略。
2) ? 指令用于比较两个操作数,例如 C = A ? B,比较结果如下:

C    A?B    B?A
A<B   0    FFFF
A=B  FFFF  FFFF
A>B  FFFF  0
C 里面会根据比较结果放入 0 或者 FFFF

算法指令的一些限制

  在开发者编写加密锁算法指令的时候,会有一些特定的限制,结合一些例子,我们会介
绍这些限制是什么:
A = A + B  合法指令
D = D ^ D  合法指令
A = B    非法指令,必须按算法格式,可写成 A = B | B
A = 0    非法指令,必须按算法格式,可写成 A = A ^ A
C = 3 * B  非法指令,常数必须放在后面,可写成 C = B * 3
D = 3 + 4  非法指令,一条指令内只能使用一个常数
A = A / B  非法指令,我们不支持除法运算符
H = E*200  非法指令,常数必须小于 64
A = A*63   看情况,我们不允许在算法中的第一条指令和最后一条指令中使用常数。

如果这条指令出现在中间就是合法指令,如果是算法的第一条或最后一条指令就是非法指令。