破解PE文件

来源:互联网 发布:阁和楼的区别 知乎 编辑:程序博客网 时间:2024/06/07 17:33

★工具用法
1.OllyICE/OllyDB
(1)标题栏中"模块-"后的程序名就是程序领空;双击命令字节码设置/取消断点,双击汇编语句编辑代码(重新载入后消失),输入‘;’可输入注释。其他不详功能点右键发现。
(2)在反汇编窗口,右键快捷菜单里选择"查找->所有参考文本字串"可以查找字符串.使用右键快捷菜单里"超级字串参考->"插件的功能更强大,可以查出许多内置查找功能无法找到的有用信息.在字符串上双击可以进入引用字符串的代码处。
(3)对内存地址选中后在右键菜单中选择"数据窗口中跟随数值"就可以转到相应位置,或者在内存窗口里,右键菜单选择"转到",又或者在命令行输入"d 内存地址".
(4)在右键菜单里选择"查找->当前模块中的名称 (标签) Ctrl+N"就可以显示当前的API函数,在显示窗口里直接输入API函数名就可以查找,输入的函数名在标题栏显示.对选中的API函数设断点要在右键菜单里选择"在每个参考上设置断点".
(5)选中内存窗口的数据,就可以在它的地址上点右键设置内存断点.删除时可在任意一个内存地址点右键,选择"内存->删除内存断点"即可.
(6)在W窗口中可以看到当前组件的句柄,在这个窗口里点右键选择设置消息断点,在弹出的窗口里可以设置所要中断的消息.然后,在调试选项里设置"跟踪"选项,调试菜单里打开RUN跟踪,在反汇编窗口里点右键,选择"RUN 跟踪->添加所有函数过程的入口".再然后打开M窗口,在代码段(一般是地址401000)点右键设置访问中断(或按F2).最后运行程序,OllyICE中断,然后再按F9,然后就可以查看RUN跟踪窗口,选择模块列为要调试的程序名的一行,点右键,选择统计模块,随便选择一行只执行过一次的命令,就可以找到要调试的程序的正确位置,可以在此位置设置断点试试.
(7)修改代码后(爆破),点击E字母的快捷图标,选择主程序的模块,右键选择 复制到可执行文件->所有修改->全部复制->(再点右键)保存文件。
2.IDA
(1)IDA显示大量的"db",参考字符串,仅有代码。则按'c'后会进行反编译.


★破解法分类详述
***注册码/序列号***
一.爆破
1.三种情况
(1)当输入name, company, password 後, 立即比对, 正确的话立即做注册处理, 以後再也不判断, 不正确要求再输入. 不输入 name 的话, 保持 shareware 版.
(2) 同1, 但以後一执行程式还是会判断.
(3) 输入时不比对, 只写入资料於 *.ini, 程式执行时再比对.
对于(1),只需要找到注册失败窗口的call(在ollyice里只需要对messageboxa设断点就可以轻易找到),在向上找一个可以跳过这个call的jz或jnz,修改一个判断点就可以搞定.可以在ollyice中动态调试完成注册过程.
对于(2)和(3),可以追进比较注册码的Call里,更改关键的比较点.如果不奏效就要在多处查找有关的比较注册码片段并修改了.


2.分析出关键的判断点(最后向成功或失败跳转的点,也可能有多个~要关注cmp和test语句)
(1)使用W32DASM查找可用的提示信息,从而静态分析出关键的跳转点.
(2)使用各种方法找到注册检查片段的入口后,使用OllyICE进行加载,分析检查注册的过程,从而动态分析出关键的判断点.
3.使用OllyICE更改这些关键的判断点,进行调试.成功后就保存成可执行文件.


二.W32DASM/SoftICE(找入口)+OllyICE(动态调试)
1.使用W32DASM静态分析可用的提示信息,从而确定注册检查片段的入口.或者使用SoftICE设常用的API断点(如getwindowtexta和getdlgitemtexta,getdlgitemint等等,备注:使用memcpy一般没有什么效果)来拦截注册程序,回到该程序领空后记下当前命令的代码,回到OllyICE中查找即可确定注册检查片段的入口.备注:可以直接使用ollyice来设置API断点.
由于S命令忽略不在内存中的页面,因此你可以使用32位平面地址数据段描述符30h在整个4GB(0~FFFFFFFFh)空间查找(但一般是用在Windows9x下面).具体步骤为:先输入姓名或假的序列号(如:78787878),按Ctrl+D切换到SoftICE下,下搜索命令:s 30:0 L ffffffff '78787878'.会搜索出地址: ss:ssssssss(这些地址可能不止一个),然后用bpm断点监视搜索到的假注册码,第一次访问假注册号的地方应该就是注册检查片段的入口.备注:在ollyice内存窗口可执行搜索操作.
2.使用OllyICE进行加载,对注册过程进行分析,首先观察CPU的寄存器窗口是否出现明码比较.如果没有明码比较则应该详细分析对用户名和注册码进行操作的部分,以做出注册机.这时要先粗跟踪(在跟踪时要大块大块地跟踪,也就是说每次遇到调用CALL指令,重复操作指令REP.循环操作LOOP指令以及中断调用INT指令等,一般不要跟踪进去,而是根据执行结果分析该段程序的功能.),后细跟踪(对软件进行了一定程度的粗跟踪之后,便可以获取软件中我们所关心的注册部分的位置,这样就可以针对性地对该位置起的代码保存到文件以详细分析).详细分析时可以把OllyICE的代码和注释都复制到文件里,再逐句的进行分析注释.可以考虑以循环片段作分析的对象,注释出循环的起始和结束位置,然后再依次分析各个循环的功能.对循环片段的分析中应着重注释出跳出循环的语句和跳出条件,并在跳转到的语句处也给予注释以说明可能因为哪些原因跳转至此.如果程式太长了,不是太好分析,那么对付这种长程式的方法有两种,一种就是在调试过程中直接算出密码来,另一种是用把它的初状态记下来,然后把整个CALL编成一个程序来用计算机来运行.


***keyfile***
一.爆破
1.分析出关键的判断点(最后向成功或失败跳转的点,也可能有多个~要关注cmp和test语句)
(1)使用W32DASM查找可用的提示信息,从而静态分析出关键的跳转点.
(2)使用各种方法找到检查注册文件的片段的入口后,使用OllyICE进行加载,分析检查注册文件的过程,从而动态分析出关键的判断点.
2.使用OllyICE更改这些关键的判断点,进行调试.成功后就保存成可执行文件.


二.W32DASM/SoftICE(找入口)+OllyICE(动态调试)
1.使用文件监视器来确定keyfile的名称和扩展名(一般为key或dat).或者使用W32DASM静态反汇编也可以找到keyfile的文件名,SoftICE设断点createfilea也可以拦截并分析出文件名.
2.使用hiew来生成同名的keyfile文件,内容(即注册码)设定为特定值,如'7878787878'.(以后调试时对注册码的更改也必须使用hiew)
3.使用SoftICE设断点createfilea,readfile,_lopen,findfirstfilea等来拦截注册程序,回到该程序领空后记下当前命令的代码,回到OllyICE中查找即可确定检查注册文件的片段的入口.或者使用W32DASM静态分析可用的提示信息,也可以确定检查注册文件的片段的入口.
4.使用OllyICE进行加载,对注册文件的检查过程进行分析,一般需要详细分析对注册码(即文件内容)进行操作的部分,以分析得出最简单的注册文件或者做出注册机才可以.这时要先粗跟踪(在跟踪时要大块大块地跟踪,也就是说每次遇到调用CALL指令,重复操作指令REP.循环操作LOOP指令以及中断调用INT指令等,一般不要跟踪进去,而是根据执行结果分析该段程序的功能.),后细跟踪(对软件进行了一定程度的粗跟踪之后,便可以获取软件中我们所关心的?榛虺绦蚨?这样就可以针对性地对该?榻芯咛宥晗傅馗俜治?.详细分析时可以把OllyICE的代码和注释都复制到文件里,再逐句的进行分析注释.可以考虑以循环片段作分析的对象,注释出循环的起始和结束位置,然后再依次分析各个循环的功能.对循环片段的分析中应着重注释出跳出循环的语句和跳出条件,并在跳转到的语句处也给予注释以说明可能因为哪些原因跳转至此.如果程式太长了,不是太好分析,那么对付这种长程式的方法有两种,一种就是在调试过程中直接算出密码来,另一种是用把它的初状态记下来,然后把整个CALL编成一个程序来用计算机来运行.


***Nag窗口***
一.修改程序的资源
可以将可执行文件中的Nag窗口的属性改成透明,不可见,这样就变相去除了Nag窗口.


二.静态跟踪
使用W32DASM分析可用的信息,找到Nag窗口的Call,屏蔽掉即可(其前的多个传递参数的push也要一起屏蔽掉).或者如果是开始不久就弹出的Nag窗口,可以用OllyICE加载后,在入口的下一句设断点并逐步运行程序,直至Nag窗口出现.(或自己寻找下一个Call并设断点来不断跳跃式前进)


三.动态跟踪
只需找到创建此窗口的代码,跳过即可.常用的显示窗口的函数有MessageBoxA,MessageBoxExA,MessageBeep ,DialogBoxParamA ,ShowWindow,CreateWindowExA等,在ollyice中对这些API设置断点一般都能成功拦截.然而某些Nag窗口用这些断点不管用,就可试试利用消息设断点,一般都应能拦截下来.
切换到SOFTICE下命令: HWND .在所列的列表中查找相关应用程序的窗口句柄.如果NAG窗口上有OK按钮,在class name查找"button".如果NAG窗口上什么都没有,那可试验找出正确的句柄.句柄列表可能非常长,但通常NAG窗口的句柄一般在列表的前面.一但找到NAG窗口的句柄,应用BMSG命令在Windows的消息上下断点BMSG 句柄 WM_DESTROY.


***时间限制***
一.查找日期法
要记住当前年份,月份的十六进制的一些表示方法,如:2007年的十六进制是07D7,然后用W32DASM反汇编你的程序,用查找字符串的方法找D707(在机器码中位置颠倒了一下)或其它类似时间的数字,有可能会找到有价值的线索.


二.设断点找关键点
可以在SoftICE中设以下断点来确定注册检查的关键点所在.定时器可以设断点settimer或gettickcount,与读取时间相关的断点有getsystemtime,getlocaltime和systemtimetofiletime等.


三.比较法
如果这软件只是直接调用windows的系统时间,即只要向前改一下系统时间,那么软件就不再过时了,对于这种软件的破解方法,最好就是采用比较法,就是先使它过时,追踪一次程序,把可疑的地方记下来,再把时间改过来,然后再追踪多一次程序,看看那些可疑的地方是否是关键之处,如果是那就大功告成了


***功能限制***
一.菜单中部分选项是灰色的不能用,一般可以在SoftICE中设以下两种断点来拦截:enablemenuitem和enablewindow.


***CD检测***
简单也最常见的光盘保护就是程序在启动时判断光驱中的光盘上是否存在特定的文件,如果不存在则认为用户没有正版光盘,拒绝运行.在程序运行的过程当中一般不再检查光盘的存在与否.Windows下的具体实现一般是这样的:先用GetLogicalDriveStringsa( )或GetLogicalDrives( )得到系统中安装的所有驱动器的列表,然后再用GetDriveTypea( )检查每一个驱动器,如果是光驱则用CreateFileA( )或FindFirstFileA( ),GetFileAttributesA,GetFileSize等函数检查特定的文件存在与否,并可能进一步地检查文件的属性,大小,内容等. 这种光盘检查是比较容易被破解的,解密者只要利用上述函数设断点找到程序启动时检查光驱的地方,修改判断指令就可以跳过光盘检查.(以上所提到的各个函数都可以直接在SoftICE中设断点)
可将游戏(或其它程序)的光盘拿出,运行游戏,将出现一些错误提示,如: Please insert the - CD, or: You need the CD to play the - . 利用这提示可在W32DASM中利用串式数据参考功能查找相应的代码进行分析.


***VB程序***
2.动态跟踪
虽然大部分 VB 程序仍调用 Win32 API 函数,但如想在 VB dll 运行库中设断的话,你就必须把 VB dll 运行库加入 SOFTICE 配制里去.如:c:\windows\system\msvbvm60.dll(Visual Basic 6),c:\windows\system\msvbvm50.dll(Visual Basic 5) 
VB dll 常用函数:1 ,字符处理函数有MultiByteToWideChar, rtcR8ValFromBstr, WideCharToMultiByte, __vbaStrCmp, __vbaStrComp, __vbaStrCopy, __vbaStrMove, __vbaVarTstNe. (注意:这些函数前的下划线 __ 是由两根短线 _ 组成的,不要弄错. 如果你是 crack VB6 程序,你应在断点前增加 msvbvm60! . 如:  bpx msvbvm60!__vbastrcomp ) 2 ,警告窗口函数有rtcBeep, rtcGetPresentDate (time API), rtcMsgBox .
VB(VB4 以上)程序储存和比较字符是用 wide character 格式(本质是中在各字符间填 0x00). 比如:原来字符串 : CRACKZ (43h 52h 41h 43h 4Bh 5Ah). Wide 字符串格式 : C R A C K Z (43h 00h 52h 00h 41h 00h 43h 00h 4Bh 00h 5Ah). 


***手动脱壳***
1.入口点(Entry Point)确定
对初学者来说定位程序解壳后的入口点确定较难,但熟练后,入口点查找是很方便的. 决大多数 PE 加壳程序在被加密的程序中加上一个或多个段. 所以看到一个跨段的 JMP 就有可能是了.如:UPX 用了一次跨段的 JMP , ASPACK 用了两次跨段的 JMP . 这种判断一般是跟踪分析程序而找到入口点.用PEiD可以查找OEP.
2.找到入口点后,在此处可以用 Procdump的FULL DUMP功能来抓取内存中整个文件,也可以用LordPE来Dump.
3.修正刚dump取的文件
如是用 Procdump的FULL DUMP功能脱壳的文件,要用 Procdump或PEditor等PE编辑工具修正入口点(Entry Point).


***自校验***
一.通用对比法.就是将已经触发自校检的程序与原来正常的程序进行关键跳转对比,这种方法比较通用,大部分的自校检可以通过此方法解决(如果软件有防多开窗口的限制,需要先解决这个问题.)
sample1.EXE是一个加了ASPACK的自校检程序,修改任何代码或大小等都会触发校检提示软件被修改。dumped.EXE是脱壳后的文件,由于触发校检运行后出现“文件被非法修改”的提示,现在我们来解决脱壳后文件的自校检问题。打开脱壳后的程序dumped.EXE,下断BP CreateFileA,F9两次后出现出错提示。CTRL+F2重新载入dumped.EXE,下断BP reateFileA,F9一次。这时另开一个OD打开原来的程序sample1.EXE,用脚本到达OEP,命令中也下断BP CreateFileA,F9一次,这时两个OD停在同一个地方,然后在两个OD中逐步单步跟踪,碰到JE、JNE、JBE...之类的关键跳转要对比一下两者的区别。将脱壳版与原版本不同跳转处代码NOP掉或更改掉后另存为dumpedFIX.EXE。试着运行一下,如果正常完事,还不行的话继续跟踪下去。


***加密算法***
一,RSA算法 :
首先, 找出三个数, p, q, e, 
其中 p, q 是两个相异的质数, d 是与 (p-1)(q-1) 互质的数...... 
p, q, e 这三个数便是 private key 
 
接著, 找出 d, 使得 ed == 1 mod (p-1)(q-1)..... 
这个 d 一定存在, 因为 e 与 (p-1)(q-1) 互质, 用辗转相除法就可以得到了..... 
再来, 计算 n = pq....... 
d, n 这两个数便是 public key 
 
编码过程是, 若资料为 a, 将其看成是一个大整数, 假设 a < n.... 
如果 a >= n 的话, 就将 a 表成 s 进位 (s <= n, 通常取 s = 2^t,即2的t次幂), 
则每一位数均小於 n, 然後分段编码...... 
接下来, 计算 b == a^d mod n, (0 <= b < n), 
b 就是编码後的资料...... 
 
解码的过程是, 计算 c == b^e mod pq (0 <= c < pq), 
於是乎, 解码完毕...... 等会会证明 c 和 a 其m是相等的  :) 
 
如果第三者进行窃听时, 他会得到几个数: d, n(=pq), b...... 
他如果要解码的话, 必须想办法得到 e...... 
所以, 他必须先对 n 作质因数分解......... 
要防止他分解, 最有效的方法是找两个非常的大质数 p, q, 
使第三者作因数分解时发生困难......... ]


实际测试结果:n位数大于1024时,加密/解密MD5散列之(128位)的速度仍然可以非常快,完全可以用于注册验证.由于从一般意义上讲,序列号的长度是等于n的(不足位数补0或设计简单的等价变换程序),所以从序列号的角度必然限制n的取值.


二,MD5算法
在一些初始化处理后,MD5以512位分组来处理输入文本,每一分组又划分为16个32位子分组.算法的输出由四个32位分组组成,将它们级联形成一个128位散列值.
首先填充消息使其长度恰好为一个比512位的倍数仅小64位的数.填充方法是附一个1在消息后面,后接所要求的多个0,然后在其后附上64位的消息长度(填充前).这两步的作用是使消息长度恰好是512位的整数倍(算法的其余部分要求如此),同时确保不同的消息在填充后不相同.
四个32位变量初始化为:
A=0x01234567
B=0x89abcdef
C=0xfedcba98
D=0x76543210
它们称为链接变量(chaining variable)
接着进行算法的主循环,循环的次数是消息中512位消息分组的数目.
将上面四个变量复制到别外的变量中:A到a,B到b,C到c,D到d.
主循环有四轮(MD4只有三轮),每轮很相似.第一轮进行16次操作.每次操作对a,b,c和d中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量,文本的一个子分组和一个常数.再将所得结果向右环移一个不定的数,并加上a,b,c或d中之一.最后用该结果取代a,b,c或d中之一.
以一下是每次操作中用到的四个非线性函数(每轮一个).
F(X,Y,Z)=(X&Y)|((~X)&Z)
G(X,Y,Z)=(X&Z)|(Y&(~Z))
H(X,Y,Z)=X^Y^Z
I(X,Y,Z)=Y^(X|(~Z))
(&是与,|是或,~是非,^是异或)
这些函数是这样设计的:如果X,Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的.
函数F是按逐位方式操作:如果X,那么Y,否则Z.函数H是逐位奇偶操作符.
设Mj表示消息的第j个子分组(从0到15),<<<s表示循环左移s位,则四种操作为:
FF(a,b,c,d,Mj,s,ti)表示a=b+((a+(F(b,c,d)+Mj+ti)<<<s)
GG(a,b,c,d,Mj,s,ti)表示a=b+((a+(G(b,c,d)+Mj+ti)<<<s)
HH(a,b,c,d,Mj,s,ti)表示a=b+((a+(H(b,c,d)+Mj+ti)<<<s)
II(a,b,c,d,Mj,s,ti)表示a=b+((a+(I(b,c,d)+Mj+ti)<<<s)
这四轮(64步)是:
第一轮
FF(a,b,c,d,M0,7,0xd76aa478)
FF(d,a,b,c,M1,12,0xe8c7b756)
FF(c,d,a,b,M2,17,0x242070db)
FF(b,c,d,a,M3,22,0xc1bdceee)
FF(a,b,c,d,M4,7,0xf57c0faf)
FF(d,a,b,c,M5,12,0x4787c62a)
FF(c,d,a,b,M6,17,0xa8304613)
FF(b,c,d,a,M7,22,0xfd469501)
FF(a,b,c,d,M8,7,0x698098d8)
FF(d,a,b,c,M9,12,0x8b44f7af)
FF(c,d,a,b,M10,17,0xffff5bb1)
FF(b,c,d,a,M11,22,0x895cd7be)
FF(a,b,c,d,M12,7,0x6b901122)
FF(d,a,b,c,M13,12,0xfd987193)
FF(c,d,a,b,M14,17,0xa679438e)
FF(b,c,d,a,M15,22,0x49b40821)
第二轮
GG(a,b,c,d,M1,5,0xf61e2562)
GG(d,a,b,c,M6,9,0xc040b340)
GG(c,d,a,b,M11,14,0x265e5a51)
GG(b,c,d,a,M0,20,0xe9b6c7aa)
GG(a,b,c,d,M5,5,0xd62f105d)
GG(d,a,b,c,M10,9,0x02441453)
GG(c,d,a,b,M15,14,0xd8a1e681)
GG(b,c,d,a,M4,20,0xe7d3fbc8)
GG(a,b,c,d,M9,5,0x21e1cde6)
GG(d,a,b,c,M14,9,0xc33707d6)
GG(c,d,a,b,M3,14,0xf4d50d87)
GG(b,c,d,a,M8,20,0x455a14ed)
GG(a,b,c,d,M13,5,0xa9e3e905)
GG(d,a,b,c,M2,9,0xfcefa3f8)
GG(c,d,a,b,M7,14,0x676f02d9)
GG(b,c,d,a,M12,20,0x8d2a4c8a)
第三轮
HH(a,b,c,d,M5,4,0xfffa3942)
HH(d,a,b,c,M8,11,0x8771f681)
HH(c,d,a,b,M11,16,0x6d9d6122)
HH(b,c,d,a,M14,23,0xfde5380c)
HH(a,b,c,d,M1,4,0xa4beea44)
HH(d,a,b,c,M4,11,0x4bdecfa9)
HH(c,d,a,b,M7,16,0xf6bb4b60)
HH(b,c,d,a,M10,23,0xbebfbc70)
HH(a,b,c,d,M13,4,0x289b7ec6)
HH(d,a,b,c,M0,11,0xeaa127fa)
HH(c,d,a,b,M3,16,0xd4ef3085)
HH(b,c,d,a,M6,23,0x04881d05)
HH(a,b,c,d,M9,4,0xd9d4d039)
HH(d,a,b,c,M12,11,0xe6db99e5)
HH(c,d,a,b,M15,16,0x1fa27cf8)
HH(b,c,d,a,M2,23,0xc4ac5665)
第四轮
II(a,b,c,d,M0,6,0xf4292244)
II(d,a,b,c,M7,10,0x432aff97)
II(c,d,a,b,M14,15,0xab9423a7)
II(b,c,d,a,M5,21,0xfc93a039)
II(a,b,c,d,M12,6,0x655b59c3)
II(d,a,b,c,M3,10,0x8f0ccc92)
II(c,d,a,b,M10,15,0xffeff47d)
II(b,c,d,a,M1,21,0x85845dd1)
II(a,b,c,d,M8,6,0x6fa87e4f)
II(d,a,b,c,M15,10,0xfe2ce6e0)
II(c,d,a,b,M6,15,0xa3014314)
II(b,c,d,a,M13,21,0x4e0811a1)
II(a,b,c,d,M4,6,0xf7537e82)
II(d,a,b,c,M11,10,0xbd3af235)
II(c,d,a,b,M2,15,0x2ad7d2bb)
II(b,c,d,a,M9,21,0xeb86d391)
常数ti可以如下选择:
在第i步中,ti是4294967296*abs(sin(i))的整数部分,i的单位是弧度
(2的32次方)
所有这些完成之后,将A,B,C,D分别加上a,b,c,d.然后用下一分组数据继续运行算法,最后的输出是A,B,C和D的级联.


***注册程序***
提示等文字都是即时生成的,故无法在W32DASM里查找到.
具体实现方法是把提示信息的ASCII码都计算好后,每个ASCII码处理后(例如减去10)存在数据区.等到使用时,根据条件选择相应的数据作变换(即加10)得到真正的信息.但这种方法对于中文的实现还有待进一步验证. 补记:这样不会在W32DASM找到提示文字,但在相关的位置仍有提示装入某某字符串,只是这个字符串是乱码罢了.这一点仍有待改正.


一种迷惑Cracker的注册过程:
1.验证注册码格式.如果格式正确,保存退出待重启后验证注册码.否则进行假的明码比较.注:为增加迷惑性,可以把注册码长度作为格式,则若小于某个长度或大于某个长度则保存退出,而真实的注册码是大于某个长度的.
2.假的明码比较.运行一个假的错误的注册码算法,得到假注册码.如果输入值等于假注册码就提示注册成功(对付Cracker),否则提示注册码错误.
3.对付Cracker.将假注册码保存在注册表中,例如键名为SN(如果是符合格式的注册码则可以保存成LastCode等,并验证错误后立刻清除痕迹).软件启动时,若存在SN键名,则进行假的注册验证,否则进行真的注册验证.
4.假的注册验证.设计一个永远无法正确的检证算法如果 F1(假码文件值)=F2(机器码)则 界面显示“注册成功” 否则 界面显示“试用” 


ECC签名算法ECDSA和RSA算法是用来防写注册机的,即便是注册用户,也无法写出注册机。ECC比RSA有许多优点,比如密钥短而加密强度高。162bit的ECC密钥相当于1024bit的RSA密钥的加密强度。但在程序中使用这些成熟算法容易被软件检测出来从而极易暴露注册程序的位置,反而容易被爆破.


一种较成熟的保护方式:
(非明码比较,可防止爆破,已有合法"用户名/SN"对时虽然无法生成注册机但可以通过结合爆破手段来解除一机一码限制)
1.对用户名进行MD5散列得到128位值
2.对SN使用公钥进行RSA解密,得到128位值
3.对机器码进行MD5散列得到128位值(如果不需要一机一码可以省略该步)
4.对前3步的结果进行异或得到KEY
5.使用KEY对已加密的关键数据文件进行进行解密(加密算法可以使用DES,也可以简单使用异或,这里不是破解的关键)
6.对解密的数据文件进行CRC检查,如果正确解除该部分功能限制
该算法对应的生成SN的程序:
1.对原始的关键数据文件进行CRC检查,并保存该值.
2.确定一个128位的KEY,并使用该KEY对关键数据文件进行加密
3.对用户名进行MD5散列得到128位值
4.对机器码进行MD5散列得到128位值(如果不需要一机一码可以省略该步)
5.把KEY和前2步的结果异或的到128位的值
6.对上一步结果使用私钥进行RSA加密,所得即为SN


程序不可能在本地机器运行所有功能一次,怎样才能满足这个条件?思路如下:
a.本地机器上不能存在所有功能代码.
这是Demo版软件的特征,那么,正式版应当如何处理呢?
b.在非本地机器上存在本地机器缺失的代码,且这段代码不能在本地机器上执行(否则就相当于本地机器有所有代码)
如果认为这"非本地机器"是硬件,那么就有硬件狗加密方案,如果认为是网络服务器,那么就有CS模式方案


某软件先产生一个number(随机的),每次运行都不同,然后你输入你的注册码去,经过运算后,再与它比较,正确就注册.分析:保护性没有问题,不但一机一码,而且一次一码,连动态调试分析出的本机注册码都不能使用.但注册必须要求用户在运行时再获得注册码,几乎不可能实现,要求太苛刻.可以改进成伪随机号码,比如设立一个20个number的伪随机数组,每次运行后随机选一个序列号出现.当然注册是需要输入用户名的,这些number只是起到类似机器码的作用.而给用户注册码时就附上20个number的各自序列号.这样的改进不能阻止序列号的分发,如果Cracker动态跟踪也可能会发现序列号表.但可以迷惑初级Cracker.


在检查注册时使用随机数参与,比如设随机数为random=0,并且每按一次确认键后,把random与用户名第一位相加后再参加验证,并且使random随机取值.如果不成功,则第二次验证时必然同样的用户名(和机器码)会产生不同的结果.这种方法可以在一定程度上干扰Cracker的破解思路.给用户注册码时一般只需要给第一次验证时的正确注册码,并提醒用户如果第一次输入错误应该关闭后重新输入.


每次"安装"时产生一个随机数字,并用此来参与注册.作用和机器码一样,保证了一机一码,是用来防止序列号分发的(也防止程序拷贝分发).但安全性不如机器码,随机数字有被篡改的可能.但机器码过于死板,用户换个零件就要重新索要注册码.改进:可以使用多核心硬件检测系统,比如检测硬盘序列号,光驱号和主板号,只要注册码满足这三者中的一个就通过.从而减少了机器码的死板.具体实现:注册时用户提供机器码(多个硬件号拼接,考虑长度,硬件号可以截短)和用户名,软件作者提取多个硬件号再与用户名散列值相加后把结果作为生成序列号的依据.程序端检查时,首先用序列号生成的结果减去用户名散列值,再把这个结果依次和多个硬件的散列值比较,若有一个相等的则通过.


多态变形技术 看雪论坛精华6中.


关于软件保护的一般性建议
(1)软件最终发行之前一定要将可执行程序进行加壳/压缩,使得解密者无法直接修改程序.如果时间允许并且有相应的技术能力,最好是设计自己的加壳/压缩方法.如果采用现成的加壳工具,最好不要选择流行的工具,因为这些工具已被广泛深入地加以研究,有了通用的脱壳/解压办法.另外,最好采用两种以上的不同的工具来对程序进行加壳/压缩,并尽可能地利用这些工具提供的反跟踪特性.(1.实际中没有找到支持对已经加壳了的程序还可以再加壳的工具. 2.有些老版本的加壳工具所提供的反跟踪特性已经实效.)
(2)增加对软件自身的完整性检查.这包括对磁盘文件和内存映像的检查,以防止有人未经允许修改程序以达到破解的目的.DLL和EXE之间可以互相检查完整性.(1.互相检查完整性的实现比较困难,但一种可行的思路是DLL对EXE检查完整性,EXE对DLL只检查文件长度,这样在制作DLL文件时对不足的字节补足就可以实现了.但这种方法基本上没有什么意思,因为爆破一般也不会变更文件的长度2.不知道对内存映象的检查方法)
(3)不要采用一目了然的名字来命名函数和文件,如IsLicensedVersion( ),key.dat等.所有与软件保护相关的字符串都不能以明文形式直接存放在可执行文件里,这些字符串最好是动态生成.(1.使用不明确的名称来编程是不可取的习惯.不过仅限于注册部分时可以考虑使用其他有意义的名称代替,如xiaoxiao)
(4)尽可能少地给用户提示信息,因为这些蛛丝马迹都可能导致解密者直接深入到保护的核?比如,当检测到破解企图之后,不要立即给用户提示信息,而是在系统的某个地方做一个记号,随机地过一段时间后使软件停止工作,或者装作正常工作但实际上却在所处理的数据中加入了一些垃圾.(1.从效率上老考虑,这种方法并不明智,如果采用也要权衡保护力度和效率代价2.尽可能少的给用户提示几乎是不合逻辑,不可能的)
(5)将注册码,安装时间记录在多个不同的地方.(1.只是稍稍增加了破解工作的工作量,对破解强度没有本质的提高,而且会降低一定的效率 2.如果分散检查,中间参杂了程序的初始化处理,当然会有好处,但2-3处分散检查的标记足矣.一般说来,这样的实现方式有两种:或者每一处的分散检查都跳转至错误处~容易被一窝端,或者先在内存某处保存标志,以后传递,但这也很容易被察觉,跟踪)
(7)检查注册信息和时间的代码越分散越好.不要调用同一个函数或判断同一个全局标志,因为这样做的话只要修改了一个地方则全部都被破解了.
(8)不要依赖于GetLocalTime( ),GetSystemTime( )这样众所周知的函数来获取系统时间,可以通过读取关键的系统文件的修改时间来得到系统时间的信息.
(9)如果有可能的话,可以采用联网检查注册码的方法,且数据在网上传输时要加密.
(10)除了加壳/压缩之外,还需要自己编程在软件中嵌入反跟踪的代码,以增加安全性.
(11)在检查注册信息的时候插入大量无用的运算以误导解密者,并在检查出错误的注册信息之后加入延时.(1.这样会降低效率,要保证软件启动所需的时间被控制在一个可以接受的程度. 2.优先要考虑的是插入对软件有用的初始化操作作为间隔)
(12)给软件保护加入一定的随机?比如除了启动时检查注册码之外,还可以在软件运行的某个时刻随机地检查注册码.随机值还可以很好地防止那些模拟工具,如软件狗模拟程序.
(13)如果采用注册码的保护方?最好是一机一码,即注册码与机器特征相关,这样一台机器上的注册码就无法在另外一台机器上使用,可以防止有人散播注册码,并且机器号的算法不要太迷信硬盘序列号,因用相关工具可以修改其值.(1.如果一机一码,是否过于限制用户的使用. 2.一机一码,不利于刻成光盘发行.)
(14)如果试用版与正式版是分开的两个版本,且试用版的软件没有某项功能,则不要仅仅使相关的菜单变灰,而是彻底删除相关的代码,使得编译后的程序中根本没有相关的功能代码.
(15)如果软件中包含驱动程序,则最好将保护判断加在驱动程序里,因为驱动程序在访问系统资源时受到的限制比普通应用程序少得多,这也给了软件设计者发挥的余地.
(16)如果采用keyfile的保护方法则keyfile的尺寸不能太小,可将其结构设计得比较复杂,在程序中不同的地方对keyfile的不同部分进行复杂的运算和检查.
(17)自己设计的检查注册信息的算法不能过于简单,最好是采用比较成熟的密码学算法.可以在网上找到大量的源码.




★破解理论
(1)cracker精神与破解总论
用动态破解关键是在出现失败对话框之前(本质上是程序进行注册判断、计算之前)想尽办法设断把程序拦下来。然后跟踪程序运行,从粗到细,确定程序进行注册判断计算的具体位置(call),如果改call的返回结果还不能解决问题就要深入call内部进行修改。
用静态破解关键是查找有用的字符串来确定程序进行注册判断计算的具体位置(call),同样,如果改call的返回结果还不能解决问题就要深入call内部进行修改。
静态破解时,首先跟踪成功对话框前有没有跳转,如果只有一个或多个跳转,那么基本上就是把这些跳转改反了就可以成功了。如果没有跳转,挺糊涂的那种,就试着从跟踪失败对话框前的跳转提示入手,也许可以成功。但一是失败的次数往往比较多。二是不能把所有企图跳转到失败对话框的跳转都拦截下来,因为不输入用户名等情况也是会跳转到失败的,所以要好好考虑。
做cracker的五个必要条件是: 1. 知识 2. 经验 3. 感觉 4. 耐心 5. 运气 。
cracker的几个阶段:
第一个阶段应该算是爆破的阶段(暂不考虑加壳的因素),绝大多数软件都可以通过修改来得到破解,它需要我们大致了解程序加密的过程并准确的找到其判断点,由于一些现成的工具和经验使我们找这些近乎成为机械的运动(尤其是在WINDOWS下的软件)所以爆破一个软件变的相对容易。
第三个阶段应该是追出非明码比较的注册码了,它们通常多为多条件和计算型形式,这个时候你要拿出笔和纸来,在搞清楚部分算法的同时,找到合适的断点让软件的自动计算和你的手动计算结合一起算出注册码来。 
第四个阶段就是作出通用的注册机。这需要你完全搞明白注册算法和加密原理。通常这个过程是非常痛苦的。 
第五个阶段就是学习掌握一定的密码学知识,并了解常见的公共加密算法,做出利用成熟加密算法或密码学原理加密软件的注册机或提出解决之方法。
由于DOS操作系统的脆弱性,在其中运行的普通应用程序几乎可以访问系统中的任何资源,如直接访问任何物理内存、直接读写任何磁盘扇区、直接读写任何I/O端口等,这给软件保护者提供了极大的自由度,使其可以设计出一些至今仍为人称道的保护技术;自Windows 95开始(特别是WinNT和Windows 2000这样严格意义上的多用户操作系统),操作系统利用硬件特性增强了对自身的保护,将自己运行在Ring 0特权级中,而普通应用程序则运行在最低的特权级Ring 3中,限制了应用程序所能访问的资源,使得软件保护技术在一定程度上受到一些限制。开发者要想突破Ring 3的限制,一般需要编写驱动程序,如读写并口上的软件狗的驱动程序等,这增加了开发难度和周期,自然也增加了成本。
一、从软件使用说明和操作中分析软件 二、静态反汇编三、动态跟踪分析1、对软件进行粗跟踪2、对关键部分进行细跟踪


(2)Windows基础知识
Windows程序模块包括KERNEL、USER和GDI,其中KERNEL完成内存管理、程序的装人与执行和任务调度等功能,它需要调用原MS―DOS中的文件管理、磁盘输入输出和程序执行等功能;USER是一个程序库,它用来对声音、时钟、鼠标器及键盘输入等操作进行管理;GDI是一功能十分丰富的子程序库,它提供了图形与文字输出、图象操作和窗口管理等各种与显示和打印有关的功能。
由于Windows程序是运行在386保护模式下,在保护模式下,程序访问存储器所使用的逻辑地址称为虚拟地址(Virual Address,VA)。
文件执行时将被映像到指定内存地址中,这个初始内存地址称为基址(ImageBase)。在Windows NT中,缺省的值是10000h;对于DLLs,缺省值为400000h。在Windows 9x中,10000h不能用来装入32位的执行文件,因为该地址处于所有进程共享的线性地址区域,因此Microsoft将Win32可执行文件的缺省基地址改变为400000h。
文件中的地址与内存中表示不同,它是用偏移量(File offset)来表示的。
在SoftICE和W32Dasm下显示的地址值是内存地址(memory offset),或称之为虚拟地址(Virual Address,VA)。而十六进制工具里,如:Hiew、Hex Workshop等显示的地址就是文件地址,称之为偏移量(File offset) 或物理地址(RAW offset)。
Windows系统中有两种消息队列,一种是系统消息队列,另一种是应用程序消息队列。计算机的所有输入设备由 Windows监控,当一个事件发生时,Windows先将输入的消息放入系统消息队列中,然后再将输入的消息拷贝到相应的应用程序队列中,应用程序中的消息循环从它的消息队列中检索每一个消息并发送给相应的窗口函数中。值得注意的是消息的非抢先性,即不论事件的急与缓,总是按到达的先后排队(一些系统消息除外),这就使得一些外部实时事件可能得不到及时的处理。
由于Windows本身是由消息驱动的,所以解密时跟踪一个消息会得到相当底层的答案。
消息本身是作为一个记录传递给应用程序的,这个记录中包含了消息的类型以及其他信息。
Windows程序各种界面称为资源,这些资源可以定制和修改。
在Windows 3.x中,提供了一个注册数据库Reg.dat,它是一个一般二进制文件, Windows 98采用了一种强大的注册表Registry, 由系统配置注册表文件System.dat, 系统配置注册表备份文件System.da0, 用户平台配置注册表文件User.dat, 用户平台配置注册表备份文件User.da0, 网络管理注册表文件Config.pol, 网络管理注册表备份文件Config.po0五个文件组成的。
注册表的子键都有严格的组织。如果相同的信息出现在超过一个的子键中,如果您只修改了一个子键,那么该修改是否作用于系统依赖于该子键的等级。一般来说,系统信息优先于用户等级。要注意的是,这种情况只发生在您直接编辑注册表时。如果您从“控制面板”中更改系统配置,则所有出现该设置项的地方均会发生相应的改变。


(3)PE格式
PE 的意思就是 Portable Executable(可移植的执行体)。它是 Win32环境自身所带的执行体文件格式。它的一些特性继承自 Unix的 Coff (common object file format)文件格式。PE格式是跨win32平台的 : 即使Windows运行在非Intel的CPU上,任何win32平台的PE装载器都能识别和使用该文件格式。所有 win32执行体 (除了VxD和16位的Dll)都使用PE文件格式,包括NT的内核模式驱动程序(kernel mode drivers)。
所有 PE文件(甚至32位的 DLLs) 必须以一个简单的 DOS MZ header 开始。有了它,一旦程序在DOS下执行,DOS就能识别出这是有效的执行体,然后运行紧随 MZ header 之后的 DOS stub。DOS stub实际上是个有效的 EXE,在不支持 PE文件格式的操作系统中,它将简单显示一个错误提示,类似于字符串 "This program requires Windows" 或者程序员可根据自己的意图实现完整的 DOS代码。紧接着 DOS stub 的是 PE header。执行体在支持PE文件结构的操作系统中执行时,PE装载器将从 DOS MZ header 中找到 PE header 的起始偏移量。因而跳过了 DOS stub 直接定位到真正的文件头 PE header。紧跟 PE header 的是结构数组 section table(节表),每个结构包含对应节的属性、文件偏移量、虚拟偏移量等。PE文件的真正内容划分成块,称之为节。节的划分是基于各组数据的共同属性, 而不是逻辑概念。
装载一PE文件的主要步骤:(1)当PE文件被执行,PE装载器检查 DOS MZ header 里的 PE header 偏移量。如果找到,则跳转到 PE header。(2)PE装载器检查 PE header 的有效性。如果有效,就跳转到PE header的尾部。(3)PE装载器读取节表中的节信息,并采用文件映射方法将这些节映射到内存,同时付上节表里指定的节属性。(4)PE文件映射入内存后,PE装载器将处理PE文件中类似 import table(引入表)的逻辑部分。
一个引入函数是被某模块调用的但又不在调用者模块中的函数,因而命名为"import(引入)"。引入函数实际位于一个或者更多的DLL里。调用者模块里只保留一些函数信息,包括函数名及其驻留的DLL名。引入表实际上是一个结构数组。每个结构包含PE文件引入函数的一个相关DLL的信息。
当PE装载器执行一个程序,它将相关DLLs都装入该进程的地址空间。然后根据主程序的引入函数信息,查找相关DLLs中的真实函数地址来修正主程序。PE装载器搜寻的是DLLs中的引出函数。DLL/EXE要引出一个函数给其他DLL/EXE使用,有两种实现方法: 通过函数名引出或者仅仅通过序数引出。我们不提倡仅仅通过序数引出函数这种方法,这会带来DLL维护上的问题。一旦DLL升级/修改,程序员无法改变函数的序数,否则调用该DLL的其他程序都将无法工作。
重建 PE 文件的Import表,需要将DLLs正常调入内存,或者需要仔细研究它们的输出表才能找到正确的函数地址。


(4)文件保护方式
其验证最基本的有两种,一种是按用户输入的姓名来生成注册码,再同用户输入的注册码比较,公式表示如下:序列号 = F(用户名)。但这种方法等于在用户软件中再现了软件公司生成注册码的过程,实际上是非常不安全的,不论其换算过程多么复杂,解密者只需把你的换算过程从程序中提取出来就可以编制一个通用的注册程序。另外一种是通过注册码来验证用户名的正确性,公式表示如下:用户名称 = F逆(序列号)。这其实是软件公司注册码计算过程的反算法,如果正向算法与反向算法不是对称算法的话,对于解密者来说,的确有些困难,但这种算法相当不好设计。
去除警告窗口常用的三种方法是:修改程序的资源、静态分析,动态分析。去除警告窗口用资源修改工具是个不错的方法,可以将可执行文件中的警告窗口的属性改成透明、不可见,这样就变相去除了警告窗口。如果是动态跟踪调试,只需找到创建此窗口的代码,跳过即可。
Anti-静态分析1.死循环语句2.利用花指令:由于"无用的字节"干扰了W32Dasm对指令起始位置的判断,从而导致反汇编的错误结果。
关于软件保护的一般性建议(1)软件最终发行之前一定要将可执行程序进行加壳/压缩,使得解密者无法直接修改程序。如果时间允许并且有相应的技术能力,最好是设计自己的加壳/压缩方法。另外,最好采用两种以上的不同的工具来对程序进行加壳/压缩,并尽可能地利用这些工具提供的反跟踪特性。(2)增加对软件自身的完整性检查。这包括对磁盘文件和内存映像的检查,以防止有人未经允许修改程序以达到破解的目的。DLL和EXE之间可以互相检查完整性。(3)不要采用一目了然的名字来命名函数和文件,所有与软件保护相关的字符串都不能以明文形式直接存放在可执行文件中,这些字符串最好是动态生成。(4)尽可能少地给用户提示信息,因为这些蛛丝马迹都可能导致解密者直接深入到保护的核心。(5)将注册码、安装时间记录在多个不同的地方。(7)检查注册信息和时间的代码越分散越好。不要使用一个全局标志来判断。(8)不要依赖于GetLocalTime( )、GetSystemTime( )这样众所周知的函数来获取系统时间,可以通过读取关键的系统文件的修改时间来得到系统时间的信息。(9)如果有可能的话,可以采用联网检查注册码的方法,且数据在网上传输时要加密。(10)除了加壳/压缩之外,还需要自己编程在软件中嵌入反跟踪的代码,以增加安全性。(11)在检查注册信息的时候插入大量无用的运算以误导解密者,并在检查出错误的注册信息之后加入延时。(12)给软件保护加入一定的随机性,比如运行时随机地检查注册码。(13)如果采用注册码的保护方式,最好是注册码与机器特征相关。(14)如果试用版与正式版是分开的两个版本,且试用版的软件没有某项功能,则彻底删除相关的代码。(15)如果软件中包含驱动程序,则最好将保护判断加在驱动程序中。因为驱动程序在访问系统资源时受到的限制比普通应用程序少得多,这也给了软件设计者发挥的余地。(16)如果采用keyfile的保护方式,则keyfile的尺寸不能太小,可将其结构设计得比较复杂,在程序中不同的地方对keyfile的不同部分进行复杂的运算和检查。(17)自己设计的检查注册信息的算法不能过于简单,最好是采用比较成熟的密码学算法。


(5)数据约束性的秘诀
这个概念是+ORC提出的,只限于用明文比较注册码的那种保护方式。在大多数序列号保护的程序中,那个真正的、正确的注册码或密码(Password)会于某个时刻出现在内存中,当然它出现的位置是不定的,但多数情况下它会在一个范围之内,即存放用户输入序列号的内存地址±0X90字节的地方。这是由于加密者所用工具内部的一个Windows数据传输的约束条件决定的。


(6)加密算法
RSA算法是第一个能同时用于加密和数字签名的算法。RSA的安全性依赖于大数分解,但是否等同于大数分解一直未能得到理论上的证明。RSA在选择密文攻击面前很脆弱。攻击利用的都是同一个弱点,即存在这样一个事实:乘幂保留了输入的乘法结构。若系统中共有一个模数n,只是不同的人拥有不同的e和d,系统将是危险的。RSA的小指数攻击:有一种提高 RSA速度的建议是使公钥e取较小的值,这样会使加密变得易于实现,速度有所提高。但这样作是不安全的,对付办法就是e和d都取较大的值。RSA的缺点主要有:A)产生密钥很麻烦,受到素数产生技术的限制,因而难以做到一次一密。B)分组长度太大,为保证安全性,n 至少也要 600 bits 以上,使运算代价很高,尤其是速度较慢,较对称密码算法慢几个数量级;且随着大数分解技术的发展,这个长度还在增加,不利于数据格式的标准化。
DES算法具有极高安全性,到目前为止,除了用穷举搜索法对DES算法进行攻击外,还没有发现更有效的办法。DES算法中只用到64位密钥中的其中56位,而第8、16、24、......64位8个位并未参与DES运算,这一点,向我们提出了一个应用上的要求,即DES的安全性是基于除了8的倍数位外的其余56位的组合变化256才得以保证的。因此,在实际应用中,我们应避开使用8的倍数位作为有效数据位。
ElGamal算法既能用于数据加密也能用于数字签名,其安全性依赖于计算有限域上离散对数这一难题。ElGamal的一个不足之处是它的密文成倍扩张。
DSA是Schnorr和ElGamal签名算法的变种。DSA是基于整数有限域离散对数难题的,其安全性与RSA相比差不多。DSA的一个重要特点是两个素数公开,这样,当使用别人的p和q时,即使不知道私钥,你也能确认它们是否是随机产生的,还是作了手脚。RSA算法却作不到。


(7)解释语言知识
解释执行的语言因为解释器不需要直接同机器码打交道所以实现起来较为简单、而且便于在不同的平台上面移植,这一点从现在的编程语言解释执行的居多就能看出来,如 Visual Basic、Visual Foxpro、Power Builder、Java...等。编译执行的语言因为要直接同CPU 的指令集打交道,具有很强的指令依赖性和系统依赖性,但编译后的程序执行效率要比解释语言要高的多,象现在的 Visual C/C++、Delphi 等都是很好的编译语言。
解释语言有一个致命的弱点,那就是解释语言的程序代码都是以伪码的方式存放的,一旦被人找到了伪码与源码之间的对应关系,就很容易做出一个反编译器出来,你的源程序等于被公开了一样。而编译语言因为直接把用户程序编译成机器码,再经过优化程序的优化,很难从程序返回到你的源程序的状态, 但对于熟悉汇编语言的解密者来说,也很容易通过跟踪你的代码来确定某些代码的用途。


(8)加壳脱壳
运行加壳程序时,外壳程序负责把原来的程序在内存中解压缩,并把控制权交还给解开后的真正的程序。脱壳的就是把在内存中真正还原的程序抓取下来,修正后变成可执行的文件。
手动脱壳就是不借助自动脱壳工具,而是用动态调试工具SOFTICE或TRW2000来脱壳。(1)确定壳的种类(2)入口点(Entry Point)确定(3)dump取内存己还原文件(4)修正刚dump取的文件


★破解手记
(1)破解技巧杂记
通过阅读它的帮助,你也知道可以有两种注册方式:Individual和Site License。所以这里对合法的注册码就可能有两次核对。


程式如何判断注册与否?
通常两种方式:
1. 在程式码的某一处, 藏有 "注册印记". 如00表未注册, 01为已注册. 当然也有很奇怪的数字, 如 f8 03 表已注册.
2. install 时程式开 *.ini, 或写入 win.ini, 把资料存在那里.


程式如何保护:
最通常是用你的name当作key, 经过复杂演算法, 算出注册码。但也有一些并不是用你的name当作key算注册码的,而是name与注册码无关,注册码是固定,name是随便输入就可以了。对于前者,较容易可算出注册码,而后者要算注册码就不是一件容易的事了。关于两者的具体处理方法,注册处理:
1. 当输入name, company, password 後, 立即比对, 正确的话立即做注册处理, 以後再也不判断, 不正确要求再输入. 不输入 name 的话, 保持 shareware 版.
2. 同1, 但以後一执行程式还是会判断.
3. 输入时不比对, 只写入资料於 *.ini, 程式执行时再比对.
对于第一种情况,是最容易破解的了,因为只要找到软件注册时的比较失败窗口的call,在向上找一找,就可以找到一个可以跳过这个call的jz或jnz,只要把这个jz改为jmp,就可以随便注册了,因为它们的只进行一次性的比较,所以只要在注册时强行使它们注册成功,则以后就不用管了。
它们的一般形式为:
xxxx:xxxxxxxx call 比较注册码的call
xxxx:xxxxxxxx test eax , eax
xxxx:xxxxxxxx jnz (或jz) xxxxxxxx 只要把这个jnz 改为jmp 就可以了


xxxx:xxxxxxxx call 比较失败的窗口的call
对于第二,第三种情况,就不能这么简单地破解了,而要追进比较注册码的call里去,如果可以算出注册码的,就万事大吉了,如果不能,就比较地麻烦了,只有按下面介绍的方法进行crack了,要知软件始终不是你写的,所以不可能所有的软件都可以crack的,只能各凭功力了。对于不能简单地算出注册码的软件,我们的唯一的方法是先在比较注册码的call里,设一个断点,然后再重新运行软件,如果软件被中断的,那么这个软件就有八成可以破解了,只要在比较注册码的call里找到那些jz或jnz会导致eax的值变化,把这些指令改为nop或jmp(视具体情况而定),则一般都可以迎韧而解了。


如何入手来破解(动态)
首先,将程式的注册对话框打开,输入任意的注册码.
第二步,按CTRL-D呼叫出ICE,然后下中断
第三步,返回注册程式,按下注册窗中的"确定"按钮.
第四步,如果被ICE拦到,说明刚才打的中断发挥作用了,可以继续工作.如果出现的是"注册失败"的对话框,说明ICE的中断没有作用,只有重复第二步,换个中断试试.
第五步,按F10键一步步查看程式会在哪个地方进行注册处理.一般来讲,只要猛按F12键,等到出现"注册失败"的画面时,记下刚才按F12键的按数
第六步,第二次重复第二步至第四步,这次按第五步记下的按数减去1下的按数,停下来.
第七步,开始按F10键单独追寻,直到又出现注册失败的对话框,按下"确定",会返回到ICE,察看一下光标的上一行肯定是一处CALL,这个CALL肯定有问题.
第八步,既然有问题,当然要按F8键进去观察了.当然如果要进入此CALL,必须得再次重复第一步的行动.不要嫌麻烦,CRACK就是这样,要有耐心,才会成功.
第九步,如果你是个懒人的话,或者功力不太高,和我一样,可以试试这个方法: 注意观察这个CALL上面一段程式,是否有哪个地方可以跳过此CALL,一般来讲,只要将那个跳转命令改为无条件跳转(JMP)就可以了.


共享软件时间限制问题:一般来讲,这类软体发现时间过期,都会SHOW出时间过期的对话框,嘿嘿,这就是关键所在,选择中断,在 它开窗之前将它拦截下来,再慢慢TRACE到开窗的地方,往程式流程的上方,看看有什么地方可跳过此CALL,如果找到,修改一下就可以了.


Win API函数与断点设置 
断点设置列表
如何正确设置 S-ICE 的断点
  设置正确的 S-ICE 的断点,无论是 CRACK 软件还是调试软件都是非常重要的。虽然一些 CRACK 教学文件里有教,但往往不够全面,用的时候无从找起。现在整理出这篇可谓是经验凝结的断点集合,分门别类,方便大家查阅。 
       
一般处理 bpx hmemcpy
bpx MessageBox
bpx MessageBoxExA
bpx MessageBeep
bpx SendMessage


bpx GetDlgItemText
bpx GetDlgItemInt
bpx GetWindowText
bpx GetWindowWord
bpx GetWindowInt bpx DialogBoxParamA
bpx CreateWindow
bpx CreateWindowEx
bpx ShowWindow
bpx UpdateWindow


bmsg xxxx wm_move
bmsg xxxx wm_gettext
bmsg xxxx wm_command
bmsg xxxx wm_activate 
时间相关 bpint 21 if ah==2A (DOS)
bpx GetLocalTime
bpx GetFileTime
bpx GetSystemtime 
CD-ROM 或 磁盘相关 bpint 13 if ah==2 (DOS)
bpint 13 if ah==3 (DOS)
bpint 13 if ah==4 (DOS)
bpx GetFileAttributesA
bpx GetFileSize
bpx GetDriveType
bpx GetLastError
bpx ReadFile
bpio -h (Your CD-ROM Port Address) R 
软件狗相关 bpio -h 278 R
bpio -h 378 R 
键盘输入相关 bpint 16 if ah==0 (DOS)
bpint 21 if ah==0xA (DOS) 
文件访问相关 bpint 21 if ah==3dh (DOS)
bpint 31 if ah==3fh (DOS)
bpint 21 if ah==3dh (DOS)
bpx ReadFile
bpx WriteFile
bpx CreateFile
bpx SetFilePointer
bpx GetSystemDirectory
INI 初始化文件相关 bpx GetPrivateProfileString
bpx GetPrivateProfileInt
bpx WritePrivateProfileString
bpx WritePrivateProfileInt
注册表相关 bpx RegCreateKey
bpx RegDeleteKey
bpx RegQueryValue
bpx RegCloseKey
bpx RegOpenKey
注册标志相关 bpx cs:eip if EAX==0
内存标准相关 bpmb cs:eip rw if 0x30:0x45AA==0
显示相关 bpx 0x30:0x45AA do "d 0x30:0x44BB"
bpx CS:0x66CC do "? EAX" 


SoftICE常用命令简介
由于SoftICE命令操作较多,在此就把几个常用的命令介绍一下,其它详细说明请参考附录的"SoftICE手册"。
1、 G命令
语法:G [=start-address] [break-address]
作用:执行程序,后面如果加地址,则执行到该地址为止。
注意: TRW2000 中G命令与SoftICE稍有不同,SoftICE中G命令必须是在当前段中,这时IP(EIP)为指定值才中断;而TRW2000则不管段址如何,只要IP(EIP)是指定的值便停下,TRW2000这个特性大大方便我们的操作。
2、P命令
语法: P [ret]
作用:单步执行程序。
只执行P时,相当于按下F10键。在汇编模式中,当遇到 CALL、INT、LOOP、REP指令时,P将不跟踪进去,直到这些指令执行完毕,控制才返回SoftICE,换句话说,P命令是"跨"过这些指令的。
P RET 命令相当于快捷键 F12。SoftICE将一直单步执行直到它找到一条返回语句(RET、RETF),也就是说让SoftICE一直执行代码,直到出现 RET (XXXX) 命令,再跳出来拦截,这时,当前 IP(EIP) 会是停在 RET (XXXX) 后的某一条语句上,通常是在某一个CALL XXXXXXXX 后面。由于我们通常用SoftICE在某些底层的Windows函数上设置断点,所以 F12 是很管用的。因为程序的作者用的是高级语言,Windows又是提倡"透明",不希望程序员知道底层的操作,而只提供给他们高层的接口,而相当多的高级函数调用某个一定的底层函数,所以当你在底层函数上下断点,再用F12,就可以知道他用的是什么函数了。
3、T命令
语法:T [=start-address] [count] 
start-address:执行起始地址;
count:指定SoftICE将单步跟踪多少次才停止。
作用:单步跟踪。
T命令相当于功能键F8,如没指定起始地址,将从CS:IP(EIP)指向的指令开始执行,此时当遇到 CALL、LOOP等指令时,T将跟踪进去。
注意: F8和F10功能键的主要差别就在这,遇到 CALL、LOOP等指令时,F10是路过,而F8是跟进去。
4、BPX命令
语法:BPX [address] [IF expression] [DO "command1;command2;..."] 
address :断点所在的线性地址;
IF expression:条件表达式,只有条件为"真"时,SoftICE才在断点处弹出;
Do command:当SoftICE弹出时,自动执行的一些命令。
作用:在可执行语句上设置(或清除)断点。
BPX 用来在指令处下断点,程序一旦执行到此,SoftICE就会弹出。当光标在代码窗口中时,直接打入BPX就会在光标所在语句处设断点,再打BPX 就取消。BPX的快捷键是 F9,当光标在代码窗口中时,按F9就是设定(取消)。
BPX 也可用函数名来作地址参数:格式为"BPX 函数名"。
这个函数名可以是任意一个API函数、虚拟机指令、DLL文件的引出函数等等,功能强劲。例:
:bpx messageboxa(不用区分大小写)//只要程序调用了此函数,SoftICE将中断;
:bpx GetWindowTexta if EAX==8 // 当调用GetWindowTexta函数时EAX=8,SoftICE将中断;
:BPX GetWindowTexta do "d EAX"// 当 GetWindowTexta被中断,自动显示EAX的值。 
注意: TRW2000与SoftICE条件格式有点不同,如在SoftICE下的是:bpx loadlibrarya do "dd esp->4",而相同的用法在TRW2000中是:bpx loadlibrarya do "dd *(esp+4)" 。另外SoftICE中用鼠标双击指令行可设断,而TRW2000中不行,只能按F9.
5、BPM命令
语法:BPM[size] address [条件表达式] DO[执行的命令]
size:内存单元大小,B为字节(默认);W 为字;D 为双字;
verb:所进行的操作,R为读;W为写;RW为读写(默认);X 为执行。
作用:设置内存访问断点。
注意: BPM用了DR3-DR0寄存器,所以最多只能设四个断点。
6、BMSG命令
语法:BMSG window-handle [条件表达式] DO[执行的命令]
window-handle:消息发向的窗口句柄,即消息名
作用:在Windows的消息上下断点。
Windows本身是由消息驱动的, 所以跟踪一个消息会得到相当底层的答案。如:
我们执行记事本程序(Notepad),然后Ctrl+D激活SoftICE输入:
   :bmsg wm_char 
   :g 
然后回到Notepad中,随便按一个键,SoftICE就激活了;原因在于我们在按键消息上设置了断点(退出SoftICE别忘下命令"BC *"清除刚才下的断点)。
7、BL命令
语法:BL
作用:显示当前所设的断点
注意: SoftICE会把所有断点按从0开始的编号列出,而TRW2000是从1开始编号列出。
8、BC命令
语法:BC list | *
list:可以清除指定编号的断点,多个时中间用空格或逗号隔开。
* :清除所有的断点。
作用:清除一个或多个断点
9、BD命令
语法: BD list | *
list:可以是单个,也可以是一系列断点,中间用空格或逗号隔开。
* :禁止所有的断点
作用:使一个或多个断点失效。
10、BE命令
语法:BE list | *
作用:使一个或多个断点恢复有效。
用来恢复前次用 BD 命令使之失效的断点。 (每当新定义断点或编辑断点时,系统自动将其置为有效)
11、BPE命令
语法:BPE index_number(断点索引号)
作用:编辑一个已存在的断点。
12、R命令
语法:R 寄存器名
作用:显示或更改寄存器的内容。 
其可更改所有的寄存器的值。此命令较常用的一个功能是更改状态寄存器(PSW )的值,格式:R FL 标志位。比如当前 Z标志位(零位)为置位状态,执行"r fl z"之后会被清除;如果C标志位为清除状态,那么"r fl c"将使之置位。
注意: 利用此命令很方便在一些跳转指令上改变方向。
13、A命令
语法:A [地址]
作用:进入小汇编状态,可直接写入汇编代码。
如不加地址值,直接在当前CS:IP(EIP)处汇编。用SoftICE内置的汇编器在内存中写入汇编代码。汇编器支持标准的80x86指令集,包括386、486、Pentium、Pentium-Pro、MMX协处理器,新版的SoftICE还支持AMD的3D Now!、PII、PIII的特有指令集。
14、D命令
语法:D[size] [address [l length]]
size:B 字节;W 字;D 双字; S 短实型;L 长实型;T 10b长实型
作用:显示某内存区域的内容。
15、S命令
语法:S [-cu][address L length data-list]
address:搜索的起始地址
length :搜索的长度(字节长)
data-lis:可以是一系列字节,也可以是字符串,字符串可以用单引号,也
可以用双引号括住.
-c :使查找区分大小写
-u :查找Unicode 编码的字符串.
作用:在内存中搜寻特定数据,如果找到数据,那将在数据窗口中显示出来,如果在找到后,你还要继续查找,使用不带参数的S命令。由于S命令忽略不在内存中的页面,因此你可以使用32位平面地址数据段描述符30h在整个4GB(0~FFFFFFFFh )空间查找。如:
s 30:0 l FFFFFFFF "78787878" //在此令在内存中查找字串"78787878"位置。
注意: TRW2000中S命令的字串应是单引号(而SoftICE皆可)。如:s 30:0 l FFFFFFFF '78787878'.
16、E命令
语法:E[size] [address [data-list]] 
作用: 修改内存单元
17、U命令
语法:U [address [l length]] | [symbol-name]
address :段:偏移量或选择符:偏移量
symbol-name:将从指定的函数开始反汇编
length :反汇编的长度(字节)
作用: 反汇编指令 
你可以利用此命令抓取汇编代码,运行LOADER32后,将历史缓冲区(history buffer)调大些(默认为256,不能放足够多的缓冲数据)。然后切换到SoftICE调试画面下,来到你要抓取的地方,反汇编这些代码,如:U CS:EIP L 1000 ,立即按Ctrl+D返回到Windows环境,再次来到symbol loader程序,选择"File/Save SoftICE History As…"。
注意: 在TRW2000下可以直接反汇编代码输出到一个文件:
u 401000,402000 >路径/myfile。
18、FAULTS命令
语法:FAULTS [on | off] 
作用:打开或关闭错误跟踪功能 
由于SoftICE做为一个DEBUGGER,FAULTS 默认为ON,所以一旦CPU有非法指令,SoftICE就会不停地弹出。
19、?命令
语法:? 表达式
作用:计算一个表达式的值
一个非常高级的计算器,另外由于可以显示ASCII,所以可以很方便地在各种数制之间察看。
20、.命令
语法: .
作用:在代码窗口中定位当前指令 
当你在代码窗口中上下浏览时,有可能走得很远,那么这时一个"."命令会让你在下一瞬间回到SoftICE当前所在的CS:EIP处。
21、EXP命令
语法: EXP [函数名]
作用: 显示DLL中的出口函数
函数名可以指定出其前几个字符, 可以用?来做替代不定字符,这样你就可查找相关函数及其是哪个DLL文件了。这对于你在Win2K系统上非常实用,Win2K系统的KERNEL32.DLL中许多函数形式和Windows 9x可能不同,用此命令你就可找到正确的函数名了。


一般技术问题
Q:ZIP和RAR之类密码(Word、execel等都属于这一类)能否用SOFTICE或TRW动态跟踪破解?
A:不能,WinZip和WinRAR是通过与CRC结合的方式进行加密,它们在解压的时候会不管3721先把带上用户输入的密码的CRC放进解压流程中,先解出来再说,最后才进行原始的CRC判定,如果最后得到的CRC与原来的不一样,那就是解压失败。因为CRC是不可逆推的,所以也没办法得到原始的密码,同时也因为把对比的过程放在了最后,所以才没办法用SoftICE等工具进行破解,只能穷举(目前来说)。(感谢老罗详细的解释)


Q:为什么在WinNT/2000/XP系统,bpx hmemcpy断点无效?
A:hmemcpy是16 bits windows里的一个函数,全名Huge MEMory CoPY,俗称万能断点,但在一般的编程书籍上很少提到,原因它是底层的东西,没有特殊需要,一般不直接调用。它的操作很简单,只是将内存中的一块数据拷贝到另一个地方,Win9x系统里很频繁地调用它处理数据。在Win NT/2K系统上相关的函数是memcpy,但在Win NT/2K上不同于Windows 9x上,很少再调用memcpy来处理数据了,用此函数设断基本上什么也拦不住。 


Q:为何同一函数有几种形式,如MessageBoxA(W)?
A:MessageBoxA(W)是MessageBoxA,MessageBoxW两种形式缩写,Windows函数是区分字符集的:A表示ANSI,W表示Wide,即Unicode (Wide character-set),前者就是通常使用的单字节方式,而后者是双字节方式,方便处理双字节字符。Win98基本是使用ANSI字符串来进行内部操作的,但它仍可处理少数Unicode字串符函数,如MessageBoxW、MessageBoxExW等。而Win2000/XP所有核心函数都是Unicode字串符。


Q:F11与F12区别?
A:F11对应的命令是:G@ss:sp,假如你目前正中断在程序中,下这个指令会在堆栈的返回地址设个暂时断点并执行到此断点。
F12对应的命令是:P RET 。SoftICE或TRW将一直单步执行直到它找到一条返回语句(RET、RETF),也就是说让SoftICE一直执行代码,直到出现 RET (XXXX) 命令,再跳出来拦截,这时,当前 IP(EIP) 会是停在 RET (XXXX) 后的某一条语句上,通常是在某一个CALL XXXXXXXX 后面。
说明:F11功能键在SoftICE中有效,在TRW中可以用pmodule命令代替F11或F12,可瞬间回到到前程序领空。




Q:SoftICE与TRW2000的断点有什么不同?
A:在这里以G命令来解释,如对G 401000命令,大家都知道是执行到401000停下,但SoftICE认为是到当前段的401000停下(也就是说在当前应用程序领空),而TRW200却不管段址如何,只要EIP是401000便停下。 这样一般跟踪一软件只要G 401000便解决。这个功能看起来简单,却极为有用。有了这条命令,只要把当前跟踪到的EIP记下,下一次一G便到。而在SoftICE下,一般先用其Symbol Loader装载程序,先来到当前应用程序的领空,然后再G 401000才能到达指定地址处。其它断点命令,如bpx原理与此类似。




Q:有一汇编指令:cmp dword [ebp-10],byte +01, 请问dword在这里的作用是什么呢?在这里dword [ebp-10]和[ebp-10]有什么不一样吗? 请问byte +01是一种怎么样的寻址呢?
A:在16位指令中,缺省的类型是字Word,在32位指令中,缺省的类型是双字Dword。byte +01表示方法是TRW2000中特有的,就是数字1,一个字节长。


Q:请问ASCII扩展字符(即ASCII值在080-0ff)如何输入?
A:输入时按住Alt键,然后输入ASCII的十进制码(001~255)。


Q:某一软件,用FI看到有 Win GUI *CRYPTED* 的字样
A:Win GUI只是指Windows图形应用程序,有*CRYPTED* 的字样,是FI认为该软件己加密,但不能识别出加密的类型。


Q:trw怎么抓图?
A:下命令ver keep,然后按Print Screen即将图抓取到剪帖板内,剩下的事就是找下图像处理软件粘贴上去即可。


Q:如何抓取SOFTICE中的汇编代码?
A:第一步运行SOFTICE的symbol loader快捷方式,打开菜单的“SoftICE initialisation settings”选项。将历史缓冲区(history buffer)调大些(默认为256,不能放足够多的缓冲数据)。然后切换到SOFTICE调试画面下,来到你要抓取的地方,反汇编这些代码,如:U CS:EIP L 1000 ,立即按CTRL+D返回到windows环境,再次来到symbol loader程序,选择File/Save SoftICE History As ... 。
或在SOFTICE基础下,装载icedump,用命令 ScreenDump更加方便灵活。


Q:如何抓取TRW2000中的汇编代码?
A:在TRW2000下:u 401000,402000 >myfile或 u 401000 L 100 >myfile 


Q:Delphi、C++ Builder编译的软件用getwindowtext等断点拦不住?
A:这是因为Delphi通过向Edit发送WM_GETTEXT(直接调用WNDProc,而没有使用消息函数)消息来获得Text的内容的,整个过程没有调用过任何Win32 API函数。所以常用的Hmemcpy、GetDlgItemTextA、GetWindowTextA等断点失效是当然的。
那么如何才能将用户输入的字符串拷贝到软件的缓冲区中时使SoftICE中断呢?办法有多种,例如用DeDe反编译得到该事件的地址,对此地址设断拦截。


Q:今后采用密码学方面的软件会越来越多,对于一个CRACKER是否有必要因此学习大量的数论知识?
A:首先我们要明确,加密算法在软件保护中的作用是什么?
加密算法在软件保护中的作用,是防写注册机。而对其他pj方式防护能力较差。
加密算法,在很多情况下是可知的,网络安全中,可以通过阅读通信协议,来了解算法;而软件中,算法往往嵌入在程序代码中。所以基于算法保密上的安全永远是不可靠的。于是人们通过密钥 来解决这个问题。目前所有流行的算法的安全性,都是基于密钥的保密。
而对于软件来说,对称密钥算法,没有什么意义。因为密钥必须嵌入软件中。所以公开密钥(不对称密钥)算法,成为软件加密的理想选择。


对于一个普通的CRACKER包括普通的程序员,是没有必要学习大量的数论知识。因为现在现成算法函数接口很多,随便拿来用就可以,不必自己去一行一行的去写代码,只要搞清算法的加密流程就可以了。一个普通的CRACKER只要跟某段代码时,能够感觉到他大概是什么算法,然后用算法验证软件(我常用cryptool),检查一下,就可以了;而且pj软件的方法很多,比如做补丁,并不是写注册机这一种方法。理论上,软件可以在机器上正常运行所有功能一次,就是可以pj的。


当然,对于想往更高层次发展的Cracker学一些数论知识是必要的,当然我们不太可能发现某的算法的弱点,但至少可以在,某个高人,发现算法的弱点,并公开时,能看懂人家是如何实现的(这需要涉及很多理论性的东西,会涉及数论的),并能写成代码。
(zmworm 回答)


Q:REPZ MOVSD是什么意思?
A: REPZ:→相同的指令有REPE
当ZF=0,退出重复,否则(CX或ECX)←(CX或ECX)-1,并执行其后的串指令,如MOVSD
MOVSD:→同类指令MOVSB字节传送,MOVSW字传送
以双字为单位的串操作指令,由源字符串向目标字符串移动数据
REPZ MOVSD这条指令是在做数据传送,源字符串DS:SI 目标字符串ES:DI  
( aboil回答)


Q:RSA 算法中的MOD运算疑问? 
A:mod是求余运算符。 
如果x与y的积除以z所得的余数为1,即xy = 1 (mod z),则称x和y对于模数z来说互为逆元,这种互为逆元的关系用符号表示为:
x = y的-1次方 (mod z)
x的-1次方 = y (mod z)
其中,-1次方只是个逆元的表示记号而已,是仿照以前的“倒数”的表示法,并非真的就是-1次方。
17 * 593 mod (37-1)(41-1) = 1
17 * 593 mod 1440 = 1
求逆元用扩展欧基里德算法,初等数论书都有讲。
( blowfish 回答)


Q: _lopen("\\\\.\\NTICE",...) 这一句代码,“\\.\NTICE”是驱动模块吗?“\\.”在这里是什么意思?
A: \\.\表示本地计算机,\\servername\表示远程计算机。
   NTICE是softice的驱动程序向Win32应用程序所显露出来的设备的符号名称。每个驱动会创建/管理一个或者多个虚拟的或者物理的设备,每个设备有个设备名,但这个设备名只能在驱动之间引用。需要显露给Win32应用程序的设备除了设备名之外,还要有一个符号名,便于Win32应用程序通过CreateFile/_lopen来引用。在驱动里面是用IoCreateSymbolicLink( )来显露设备符号名的。
( blowfish 回答)


Q:bmsg与bpmsg有什么不同?
A:bmsg与bpmsg皆为中断消息用的,不同之处是bpmsg可预设条件.设法见说明书. 
硬件中断为利用CPU自身的标志寄存器设断.软件中断是软件模拟硬件产生中断. 
I/O中断与硬件中断是完全不同的两个概念.I/O中断用于系统与端口通讯时.一般在硬狗时用


Q:CDQ是什么指令?
A:CDQ是符号扩展指令 
D是dword(4字节),Q是qword(8字节) 
CDQ把EAX寄存器中的数视为有符号的数,将其符号位(即EAX的最高位)扩展到EDX寄存器,即若EAX的最高位是1,则执行后EDX的每个位都是1,结果EDX = FFFFFFFF;若EAX的最高位是0,则执行后EDX的每个位都是0,结果EDX = 00000000。这样就把EAX中的32位带符号的数变成了EDX:EAX中的64位带符号的数,以满足64位运算指令的需要,但转换后的值没变。 
( blowfish 回答)




Q:softice如何在Windows 退出 ?
A:不能退出SOFTICE,他钩住了大量的内核函数!
内核调试器可以实现不关闭计算机停止调试器。
嚣张事情是SOFTICE根本没有为退出调试器做任何处理。。也就是说。他们的调试器不打算被大家所退出!
( kkkkk  回答)


Q:W32Dasm中的“Ord:0109h”是什么? 
A:是Hint,本函数在其所驻留DLL的导出表中的索引号
( firstrose  回答)


VB程序理论
用SoftICE和SmartCheck结合将这个VB6程序搞定。 
注册号是很好找的,用rtcMsgBox或MultiByteToWideChar设断点


VB3程序破解再总结 
1、    用字符比较 
-  开始运行VB3程序,输入假的序列号: 
-  切换到softice下,bpx hmemcpy 设断点 //Windows 98适用
-  按F5键返回应用程序,按注册确定键,将被softice中断 
-  S 0030:0 L FFFFFFFF  8B,CA,F3,A6,74,01,9F92,8D,5E,08,E8,06 
-  在返回地址设断如:  bpx  0030:807019ef  do “d si” 
-  按F5将落在比较代码处 
  : 8BCA        mov cx, dx 
  : F3A6        repz cmpsb  ;<-  这里字符串被比较  
  : 7401        je 8CB6    ;  
  : 9F          lahf 
  : 92          xchg ax,dx 
  : 8D5E08      lea bx, [bp+08] 
  -  如发现输入的假序列号则下d  es:di查看序列号 
-  没有发现继续按F5 
2、    用数值比较 
-  开始运行VB3程序,输入假的序列号: 
-  切换到softice下,bpx hmemcpy 设断点 
-  下WF开浮点监视窗 
-  按F5键返回应用程序,按注册确定键,将被softice中断 
-  S 0030:0 L FFFFFFFF  90,DE,D9,90DF,E0,CD,3D,9E,C3 
-  在返回地址设断如:  bpx  0030:805B5CA5 
-  按F5将至此 
4B57:3C05  90                    NOP 
4B57:3C06  DED9                FCOMPP          //比较注册码 
4B57:3C08  90                    NOP 
4B57:3C09  DFE0                FSTSW  AX 
4B57:3C0B  CD3D                INT      3D 
4B57:3C0D  9E                    SAHF 
4B57:3C0E  C3                    RET 
在浮点监视窗中将会出现注册码 
-  如没有继续按F5


方法一、用SOFTICE: 
1、这是一VB5程序,在winice.dat装载:EXP=c:\windows\system\msvbvm50.dll;winNT用户需在setint配制。 
2、下bpx__vbastrcmp,将中断,按F12走出此CALL,来到0137:0043617E(当然你一直跟进去也能找到序列号) 
3、下BC * 清除其余断点,在0137:00436178设断,将中断如下: 


0137:00436175 8B4DE8            MOV    ECX,[EBP-18] 
0137:00436178 51                PUSH    ECX........中断于此,下 d ecx你输入的注册码 
0137:00436179 688C944000        PUSH    0040948C 
                                        ^^^^^^^^ 
d 40948c,正确的注册码 
0137:0043617E FF1578E24300      CALL    Near [`MSVBVM50!__vbaStrCmp`]...第2步的按F12回到此 
0137:00436184 8BD8              MOV    EBX,EAX 
0137:00436186 8D4DE8            LEA    ECX,[EBP-18] 


4、这程序保护一般,大家想了解更多的Vb序列号破解,请关注网站的更新。 


方法二、用SmartCheck 
1、首先配制好SmartCheck; 
2、装载wintools5.0,运行,一直到时wintools运行结束,在SmartCheck主窗口中,还不断有信息记录产生: 
........... 
Timer1_Timer 
Timer2_Timer 
........... 
此时不管它,点击wintools注册,输入注册码,按OK后,再在SmartCheck下按红色的按钮停止程序的运行,最好快点,不然,还有许多没用的Timer1_Timer产生; 
3、找一找:cmdOk_Click;展开它, 
txtpassword.Text;光标移到这一行,点击菜单的"show all evants" 
4、点击下面一行: 
_vbastrcmp returns DWORD:FFFFF 
看右窗口,哈哈,全在那!


先加载MSVBVM60.DLL的符号表(最好不要同时加载MSVBVM50.DLL和MSVBVM60.DLL的符号表,否则断点应为bpx MSVBVM60!__vbaStrCmp),用bpx __vbaStrCmp设断点之后看见如下的指令段:
0167:00707F0C  CALL      006FCE50                        //计算注册号 
0167:00707F11  MOV      ECX,[EBP-18] 
0167:00707F14  MOV      EDX,[007320FC] 
0167:00707F1A  PUSH      ECX                              //假注册号 
0167:00707F1B  PUSH      EDX                              //正确的注册号 
0167:00707F1C  CALL      [MSVBVM60!__vbaStrCmp] 
0167:00707F22  TEST      EAX,EAX 
0167:00707F24  JNZ      007080A9 


跟踪进 CALL      006FCE50则可以看见生成注册号的过程。根据程序指令可以证实微软的VB6程序确实是真正的EXE,跟用VC、Delphi等编译得到的EXE没有太大分别,而早期的VB4、VB3程序根本不能叫做真正的EXE程序。 


另外,要写注册机的话最好先用SmartCheck看一下生成注册码的大致流程,然后再用SoftICE跟。困难在于微软没有公布MSVBVM50.DLL中的函数接口,所以该DLL中的函数的作用和参数都要靠猜。


破“平安全息万年历”这个VB5的软件。用程序编号的偶数位和注册号码的奇数位组成一个十进制数,再乘以2,用乘积作为下标去查表(查表用的是函数rtcMidBStr,用bpx rtcMidBStr do "d *(esp+4)"可以看见表格,即传递给该函数的第一个参数是表格的首地址,第二个参数是下标)。由于程序编号和注册号码均为8位,故这样总共可以从表中查到4个字节。再从其它地方得到4个字节(这4个字节是如何得到的尚未完全搞清楚),总共得到8个字节, 用__vbaStrComp( )将这8个字节和另外的8个字节(这8个字节是如何得到的也没搞清楚,随程序编号的不同而不同)相比较,如果相同则注册成功。我曾经修改__vbaStrComp( )的返回值强行注册成功,但是启动的时候检查通不过,它又生成一个新的程序编号让我再注册。p-code形式的VB程序也不好patch :-( 
我位仁兄已破了它,它有两个文件必须一一对应,改任一个文件均会要求重新注册。一个在安装目录下,一个在WINDOWS目录下。(无内容)


MSVBVM5.0的一个有趣的现象,兼谈“唤醒者”的。。。。 
我们知道用p-code方式编译的程序的确很难破解,因为我们跟踪用这种方式编译的程序时,看不到程序作者写的程序,只能看到vb的程序,我们只能在微软设计好的vb程序里面兜圈子,但是在兜圈子的过程中,作者的程序已经在执行了。 
在对“唤醒者”的跟踪过程中,想找到作者的比较注册码的程序,可以说是一无所获,根本看不到程序是如何运行的,但是也不能说是没有收获,发现了另外的一个有趣的现象,并且能把这个程序破解掉。 
运行“唤醒者”。 
首先用msvbvm50.rtcmsgbox中断,然后运行程序的电子注册,等SoftICE出现后,在唤醒者的4045cc处中断(我叫它中断1)和在msvbvm50的7637d549(中断2)处中断,我们看到在中断2处是一个条件转移。 
现在保留中断1,把别的中断BD掉。 
运行注册程序,随便输入注册码,点击注册,中断1会起作用,然后把中断2激活,按8次F5后(即经过中断2处8次后),会弹出来注册失败的对话框。 
现在把中断2BD掉(不然的话,它会一直跳出来)重复上面的过程,只是在中断2处经过7次,然后下命令“r fl z”,你会发现,弹出来的是注册成功的对话框。爽否? 
我推测,这里是vb来解释程序的消息循环里面的消息的过程,不跳走就执行这个消息对于的程序功能,跳走就去解释下面的一个消息。 
我们可以做下面的试验来验证一下。 
再运行注册程序,在第1次经过中断2时,下命令“r fl z”,你会发现程序运行的是“设置”的对话框; 
再运行注册程序,在第2次经过中断2时,下命令“r fl z”,你会发现程序运行的是“音乐顺序”的对话框; 
。 
。 
。 
等等。 
你还可以用另外的程序来试试是否这样的。 
对了,再告诉一句,如果你注册成功后,电子注册那个按钮没有了,变成了“关于”,没办法做上面的试验,你只要把 
c:\windows\BoobRou.dll这个文件里面的r=Boo的Boo换成别的就行了。 


不错,这种情况在VB6中也是一样,只是地址不同而已。 
目前用来对付VB的PAGE-CODE方式编译的程序最有效! 
但要注意一个在VB的MSVBVM50.DLL或MSVBVM60.DLL中如何定位的问题。 
因为VB动态链接库在内存中是变换地址的。 
就象上面这位msvbvm50的(中断2)在7637d549处 
而我的msvbvm50的(中断2)在799Ad549处。 
后面的四位是不会变的,前面的四位是会变的。 
谁有好方法能快速定位? 
同样,前几天有人提出的股票之星3.0也可以这样破解。 


(2)静态破解分析
一旦完成反汇编 , 点串式数据参考(string data reference)按钮 , 在列出的字符串列表中找到 : "Incorrect try again!! " 并双击它 . 
现在你必须从这行起向上找 , 直到找到有这样的命令为止 :cmp,jne,je,test 等等 .
//真假序列号比较核心(调用函数lsrcmpa比较)//用eax当旗帜,如相等,则eax=0
再运行程序,还是显示没有注册。看来程序的开始也做了检查
call 00403E78--------->计算结果和公司名比较   用W32DASM看一下其他地方有没有  call 00403E78的。将所有调用处的返回结果改正


W32DASM反汇编查找“未注册”字样,找到后双击鼠标来到他的调用地址向上查找能够跳过此段的地方
此时注册显示成功.但退出重新进入,提示未注册.还需找到检测点
进入比较的call 将call内部的比较结果改正


(2)动态破解分析
1.输入Registeration code:48484848(随意)
2.按CTRL-D 进入WIN S-ICE
3.下S 30:0 LFFFFFFF '48484848' 得一地址30:XXXXXXXX
4.下BPM 30:XXXXXXXX R
5.按F5 退出
6.用鼠标击Register
7.程序被WIN S-ICE 中断
8.按F12回到Hworks32的天空
9.直按F10至以下程式:比较密码的CALL





原创粉丝点击