- UID
- 2198
注册时间2005-6-29
阅读权限255
最后登录1970-1-1
副坛主
该用户从未签到
|
1.软件的验证方式
——常见的软件保护方式有加壳保护、注册验证(包括网络验证)、发布Demo版(正式版只有注册用户才能够下载)。软件从注册方式上来说可以分为网络验证和本地验证。本地验证可分为直接验证(输入注册码的同时进行验证比较)和重启验证(输入注册码的同时只保存注册信息,软件重启时再来判断注册信息)。其中直接验证的软件,又可将注册信息进行分批验证,即在首次验证中只判断部分注册信息,当使用软件的某功能时再次调用已保存的注册信息进行验证。
以前在看雪见到过这样一个逆否命题:软件的所有功能可以本机上可以运行一次<====>软件就存在被完全破解的可能性。当然这只是一个数学上的逆否命题,但从这其中也可以看出如果一个程序员,在设计软件加密部分缺乏对解密知识的了解,软件就会存在着严重的被破解的隐患。
学习软件的解密,其实就是对软件加密思路的一个逆向思维。我们下载到的共享软件中,当我们输入错误的注册信息时,软件能够提示我们"注册失败"。说明软件在我们输入注册信息后,本身有一套计算注册信息正与否的算法,当我们点击确认后,软件就开始去调用该函数,来进行对我们输入的注册信息进行判断,来得出是否正确的一个结论。这里我们提到了函数,拿到这本教程的朋友,首先一定会问到,学习破解我们需要有什么样的基础?这里我可以告诉大家:学习破解确实需要有扎实的编程功底,但是如果只是进行破解入门,你甚至之前对软件编程方面的知识为零,你需要的只是一个善于思考、善于分析的大脑就可以学习到软件的暴破知识和写出内存注册机。这里我们更多的需要的是大家对验证思路的一个悟性。当然,学习解密技术我们还是希望大家最好能对C语言和汇编语言有一定的了解,这样会方便大家的对某些部分的理解。下面我们从一个软件作者的角度上来分析一下软件本地验证的过程。
当我们输入注册信息并点击确认时(或输入注册信息的同时),软件将调用本程序的注册部分的函数,这里我们使用"Call XXXX"代表一个函数来说明验证机制。
…… (注册验证部分开始)
Call XXXX01(这里我们假定该函数是软件来取出我们输入的注册信息,设注册信息为A)
……
Call XXXX02(这个函数将A进行某个运算 得到运算结果B)
……
Call XXXX03(这个函数将B进行某个运算 得到运算结果C 这里我们假定C为软件的注册码)
……
Call XXXX04(这里再次调用A和C 并在该函数中进行比较是否A=C)
……
JNE XXXX (软件对注册信息的判断跳转 如果A不等于C 则跳走--跳向执行注册失败的代码并执行)
……
Call XXXX05(如果A=C 这个函数将调出一个对话框。提示"注册成功")
…… (以下的代码将执行软件向系统写入注册信息 以保存注册信息)
RETN
…… (如果A不等于C,上方的JNE跳转来到这里,并继续执行)
Call XXXX06(这个函数将调出一个对话框。提示"注册失败")
……
软件在编写过程中,源代码是一行一行来进行编写的。同理,软件在运行过程中也是一行一行来进行执行的。
上面我们只是假设了这么一种软件验证注册信息的思路,大多数软件的验证思路要比上例要复杂的多,调用的函数和参与的运算也将更多。通过上例我们简单的理解函数的作用。软件的验证注册信息部分其实就是一个大的函数,这个大函数中又包含很多个函数来共同完成对注册信息的验证。软件调用的函数中,一种是进行某个操作(如"Call XXXX" 来取我们输入注册信息的位数,如果输入的注册信息的位数等于软件正确注册码的位数,则继续执行,若不等,则跳向注册失败。),另一类函数主要是实现某种运算,来得到某个数值(如执行Call XXXX02的目的就是为了能够返回一个数值B )。在软件注册部分的函数调用,我们更多需要的就是通过调用某个函数,来得到一个返回值(对函数的理解可参看C语言中对函数的讲解),来参与下方指令的运算。
从上例中,我们还看到了一个跳转函数,也就是我们常说的关键跳。这里的"JNE"就是不相等则跳,如果我们把该指令修改为相等则跳,大家想在我们注册中会得到一个什么结果?我们将"JNE"(不相等则跳的指令)修改为"JZ"(相等则跳)的话,那我们输入任意的注册信息,软件都将提示我们"注册成功"。这就是所谓的暴力破解。即通过修改程序关键处的代码来达到破解的目的。
当然上例只是假设了这么一种验证思路,现实中应该很少再遇到这样简单的加密保护。看过上例之后,如果你现在思考的问题是:我如何在软件调用注册函数的时候能让软件停下来,我一步一步的去研究验证过程呢?那么你很适合学习这种技术。万事开头难,也希望你能够做好克服困难的心理准备,因为胜利的曙光就是前方。
这里再给大家一个更接近真实的软件注册验证的思路:
…… (假定是我们按下注册按钮之后 注册信息的验证从这里开始)
CALL XXXX0001(这里取注册码长度)
JEN (不等于软件正确的注册码长度则跳向注册失败)
……
CALL XXXX0002(取软件的机器码——很多软件的注册方式都采取一机一码的形式)
……
CALL XXXX0003(看机器码是否为空)
……
CALL XXXX0004(其他)
……
CALL XXXX0005(其他)
……
CALL XXXX0006(算法CALL)
TEST AL, AL(标志位比较)
JNE (关键跳转 如果标志位都为0则跳转)
……
CALL XXXX0007(若上方不跳 则弹出注册成功)
……
CALL XXXX0008(向系统写入注册信息)
RETN
……
CALL XXXX0009(软件注册失败)
……
RETN
我们跟进CALL XXXX006(算法CALL),看看其内部情况来进行算法分析(我们所使用的破解工具是可以实现这个过程的)
…… 00000000(算法CALL的开始部分)
CALL XXXX0010(取机器码记为B 并与固定数值C进行连接 连接后的数值为E)
……
CALL XXXX0011(取注册码计为A 并与固定数值D进行连接 连接后的数值为F)
……
CALL XXXX0012(将E进行某运算 得到结果G)
……
CALL XXXX0013(将F进行某运算 得到结果H)
……
CALL XXXX0014(比较G和H是否相等)
JNE (不等则跳走)
MOV AL,1(设置标志位为1)
RETN 返回标志位为1的值
…… 00000000(上方JNE跳到这里)
XOR EAX,EAX(寄存器EAX清零)
RETN
相信大家看后这个算法分析后,对于不了解汇编语言的朋友来说,会有一些疑惑:什么是标志位?什么是寄存器?RETN又是返回什么?
大家不必着急,这些内容相信大家在下面的教程中会弄明白的。你需要的就是带上这些疑问继续学习。而我举这个例子是想让大家明白这个验证思路。思考下如果验证成功后,为什么要向系统写入注册信息,软件为什么又有一个叫做算法CALL的。
OK,这两个问题才是我想向大家进行讲解的。
我们学习破解,最好的方法就是把思考角度要定义在程序员的角度来分析问题;如果你是软件的作者,你将怎样去设计这个软件;我们都知道,软件需要去判断某个问题,都需要我们去进行编写相应的代码来实现。那软件是如何知道自己是否注册的呢?如果你是程序设计者,你的设计思路是怎样呢?
这里有一种方法:就是注册后向系统的某文件中写入我们输入的注册信息(可能是无论注册成败都向系统写入注册信息),软件启动时调用该注册信息来进行判断是否为正确的注册信息。而算法CALL这个函数呢,其实就是一个地址,软件注册的时候程序可以调用该地址,软件启动的时候也可以调用该地址(函数)来判断注册信息是否正确。如果从这个角度来讲的话,软件都是重启验证的。
2.16进制的转化
我们知道计算机的运算都是2进制的位运算,一个字节=8位(这里不考虑奇偶位)
比如:00000000 而我们在调试器中所看到的都是对我们调试的程序经过编译过的汇编指令,所有的数值都是16位的。16进制从0~9、A~F(分别代表10、11、12、13、14、15)
对16进制的理解其实很简单,通过从二进制到16进制的转化大家就明白了:一个字节的前四位:0000(可以表示的是从0~15这16个数字)。所以将一个字节分解成两个16进制的一组数值。即:0000 0000
前四为为一个16进制的字符 后四位为一个16进制的字符 两个16进制的字符连到一起,就是该字节的16进制。
如果我们看到 ADD XXXX,10 一定要注意,这里加的不是十进制的10,而是十进制的16。
3.基本汇编语言
JE/JZ 等于转移.(机器码74 或0F84)
JNE/JNZ 不等于时转移.(机器码75或0F85)
JMP 无条件转移指令(机器码EB)
以下四条,测试无符号整数运算的结果(标志C和Z).
JA/JNBE 不小于或不等于时转移.(意思就是大于则就跳)
JAE/JNB 大于或等于转移.
JB/JNAE 小于转移.
JBE/JNA 小于或等于转移.
以下四条,测试带符号整数运算的结果(标志S,O和Z).
JG/JNLE 大于转移.
JGE/JNL 大于或等于转移.
JL/JNGE 小于转移.
JLE/JNG 小于或等于转移.
CALL 过程调用(调用子程序/函数)
RETN/RETF 过程返回(被调用子程序/函数的返回)
NOP 空语句
CMP 比较.(两操作数作减法,仅修改标志位,不回送结果).
MOV A,B (把B的值送给A)
PUSH 把字压入堆栈(压栈)
POP 把字弹出堆栈(出栈)
ADD 加法.
SUB 减法
MUL 无符号乘法
DIV 无符号除法.
AND 与运算.(位运算两个比较数中的二进制数值各位有0则0)
OR 或运算.(位运算两个比较数中的二进制数值各位有1则1)
XOR 异或运算.(位运算两个比较数中的二进制数值各位相同则零)(寄存器与自己作异或运算等于清零动作)
NOT 取反.
TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果).
更多的汇编语句大家可参看附件中给出的文档查阅。 |
|