能力值:
( LV2,RANK:10 )
|
-
-
2 楼
原来还有一个play.dat,把这个暴了就没问题了。
过一段时间写破文。
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
这么好用的软件,只卖25块钱,你好意思破?
缺25块钱是吧?我给你行吗?
我在天桥上也常给人钱的。
|
能力值:
( LV2,RANK:10 )
|
-
-
4 楼
最初由 李克农 发布 这么好用的软件,只卖25块钱,你好意思破? 缺25块钱是吧?我给你行吗? 我在天桥上也常给人钱的。 :o !!软件作者???晕
|
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
供参考,呵呵
【破文作者】 tankaiha[NE365]
【使用工具】 IDA4.7,OllyDbg1.10,FileInfo3.01
【破解平台】 Windows XP
【K G编写】 MASM
【软件名称】 屏幕录像专家5.0 build 20040825
【软件简介】 《屏幕录像专家》是一款专业的屏幕录像制作工具。使用它你可以轻松地将屏幕上的软件操作过程等录制成FLASH动画、AVI动画或者自播放的EXE动画。本软件采用直接录制方式或者先录制,再生成的方式录制屏幕录像,使用户对制作过程更加容易控制。本软件使用简单,功能强大,是制作各种屏幕录像和软件教学动画的首选软件。
用FileInfo检查,无壳,编译软件为BC++ Builder。运行时提示注册,给出机器码,要求输入用户名和密码。随便输入后,显示“注册失败,请检查你的输入是否有误”。运行IDA进行反编译,查找出错信息的明文,定位在下面:
.text:0043827E MessageBoxFailure: ; CODE XREF: sub_437658:ShowFailure j
.text:0043827E mov [ebp+var_A4], 164h
.text:00438287 mov edx, offset szRegisterFail ; 注册失败,请检查你的输入是否有误
向上找到其跳转点.text:004379CB,观察到跳转点向上的代码很像计算代码,并且含有Intel浮点运算指令。一路向上走,来到一个大的跳转口,
.text:00437658 sub_437658 proc near ; DATA XREF: .data:0050BD44
入口处压入了几十个参数,决定用OllyDbg动态调试,断点就设在该处。
用OllyDbg打开软件,随便输入用户名和密码后程序果然停在断点处。一路F8来到下面的代码处:
.text:0043784A mov eax, [ebp+var_C4(dNum)] ; 这一段是计算注册号的关键
.text:00437850 mov dl, [ebp+eax+dest] ; 这里取出用户名
.text:00437857 mov ecx, [ebp+var_C4(dNum)];这里dNum是计数
.text:0043785D xor dl, byte ptr [ebp+ecx+s] ;这里取出机器码进行XOR
.text:00437864 mov eax, [ebp+var_C4(dNum)]
.text:0043786A mov [ebp+eax+KeyCode], dl
.text:00437871 mov edx, [ebp+var_C4(dNum)]
.text:00437877 movsx ecx, [ebp+edx+KeyCode]
.text:0043787F mov [ebp+var_134], ecx;ECX为异或的值
.text:00437885 fild [ebp+var_134] ; 存入st(0)
.text:0043788B add esp, 0FFFFFFF8h ; -8
.text:0043788E fstp [esp+140h+var_140]
.text:00437891 call _fabs
.text:00437896 add esp, 8
.text:00437899 fild [ebp+var_C4(dNum)];入栈
.text:0043789F fmulp st(1), st;栈内数据相乘
.text:004378A1 fild [ebp+var_C0];var_C0是累加和
.text:004378A7 faddp st(1), st
.text:004378A9 call @_ftol$qv ; _ftol(void)
.text:004378AE mov [ebp+var_C0], eax
.text:004378B4 inc [ebp+var_C4(dNum)]
.text:004378BA cmp [ebp+var_C4(dNum)], 14h;是否超过20,实际机器码最长19位
.text:004378C1 jl short loc_43784A ; 不到20跳回去重新运算
.text:004378C3 add [ebp+var_C0], 3039h
.text:004378CD push [ebp+var_C0] ; 根据用户名计算出00003C1C
.text:004378D3 push offset aD_3 ; format
.text:004378D8 lea edx, [ebp+KeyCode]
.text:004378DE push edx ; buffer
.text:004378DF call _sprintf;整数转化为ASCII码
.text:004378E4 add esp, 0Ch
这一段是根据机器码和用户名计算出一个5位长度的ASCII码串,也就var_C0的值,这个ASCII串存在KeyCode中。Var_C0的值很关键,还将用在下面的注册码验证中。无论输入多少位用户名和机器号,都要比较20次,所以在编KeyGen的时候必须留足空间。下面是验证注册码的代码段:
.text:00437944 loc_437944: ; CODE XREF: sub_437658+36A j
.text:00437944 mov eax, [ebp+var_C4(dNum)]
.text:0043794A movsx edx, [ebp+eax+KeyCode] ;刚才得到的ASCII码串
.text:00437952 mov ecx, [ebp+var_C4(dNum)]
.text:00437958 movsx eax, [ebp+ecx+KeyCode2] ; 这里取用户输入的注册码
.text:00437960 add eax, 0FFFFFFECh ; -14
.text:00437963 cmp edx, eax
.text:00437965 jnz short loc_4379C4;有一个不相等就跳转到失败处
.text:00437967 cmp [ebp+var_C4(dNum)], 3
.text:0043796E jnz short loc_4379B5
.text:00437970 mov edx, [ebp+var_C0];这里用到了上面讲的var_C0
.text:00437976 add edx, 4D44h
.text:0043797C mov [ebp+var_134], edx
.text:00437982 fild [ebp+var_134];入栈
.text:00437988 fmul ds:dbl_4382DC;乘以3.14
.text:0043798E fld ds:tbyte_4382E4;另一个10字节的实数入栈
.text:00437994 fmulp st(1), st;再乘
.text:00437996 call @_ftol$qv ; _ftol(void)
.text:0043799B mov [ebp+var_C0], eax ; 将乘出的值送入var_C0
.text:004379A1 mov eax, [ebp+var_C0]
.text:004379A7 mov ecx, 186A0h
.text:004379AC cdq
.text:004379AD idiv ecx
.text:004379AF mov [ebp+var_C0], edx
.text:004379B5
.text:004379B5 loc_4379B5: ; CODE XREF: sub_437658+316 j
.text:004379B5 inc [ebp+var_C4(dNum)]
.text:004379BB cmp [ebp+var_C4(dNum)], 5
.text:004379C2 jl short loc_437944
.text:004379C4
.text:004379C4 loc_4379C4: ; CODE XREF: sub_437658+30D j
.text:004379C4 cmp [ebp+var_C4(dNum)], 5
.text:004379CB
.text:004379CB ShowFailure: ; 失败的跳转
.text:004379CB jl MessageBoxFailure
.text:004379D1 mov eax, [ebp+var_C0]
.text:004379D7 mov ecx, 0Ah
.text:004379DC cdq
.text:004379DD idiv ecx
.text:004379DF mov eax, [ebp+var_C4(dNum)]
.text:004379E5 movsx ecx, [ebp+eax+KeyCode2] ; 取出第6个注册码
.text:004379ED add ecx, 0FFFFFFBFh
.text:004379F0 sub ecx, edx
.text:004379F2 mov [ebp+var_C8], ecx
.text:004379F8 cmp [ebp+var_C8], 0
.text:004379FF jz short loc_437A0E
.text:00437A01 cmp [ebp+var_C8], 5
.text:00437A08 jnz loc_438233
.text:00437A0E
.text:00437A0E loc_437A0E: ; CODE XREF: sub_437658+3A7 j
.text:00437A0E mov [ebp+var_A4], 44h
.text:00437A17 mov edx, offset aVSJgmZ ; "注册成功,谢谢您的支持"
.text:00437A1C lea eax, [ebp+var_1C]
.text:00437A1F call sub_4E6A94
搞清验证的思路,KeyGen的编写就不难了。上面无论输入多少位用户名,和机器号运算后都得到5位字符串,因此可以根据用户输入的机器码和用户名将var_C0计算出来。在验证注册码时可以看出,注册码是6位,前5位分别简单地减去14h,然后和5位ASCII串比较,反过来将计算出来的ASCII串加上14h就可以得出注册码的前5位。第6位是var_C0经过一些浮点运算得到一个值后,减去41h,两者要相等。所以我们可以在计算得出最终值后,加上41h,推出注册码的第6位。。编写过程中第一次用户名和机器码的浮点运算可以不用浮点指令即可完成,第二次没折,因为有两个实数加入运算,所以只能照用了。
|