破解DataFit 8.0
这是个科学与工程工具(science and engineering,不知道该
怎么译:-)。用于对数据进行统计分析,曲线拟合,绘图等。在RCE
Message Board上见到有人提起,以为是个VB PCode程序,虽然很
讨厌PCode,可是不学不行呀,于是下载回来练手,结果是Native
Code。既来之,则破之,这个倒比较简单。
1.大致看了看,好象没什么别的东西,只要研究主程序就行。在
SmartCheck下加载,运行起来后,有个"New Project"对话框,这
个地方最好选Cancel,否则SmartCheck好象动不了了,可以看到
一大堆对Rnd的调用。我以为是掉到陷阱里了,不过从后面看未必,
只是太慢而已。
从SmartCheck中可以看见,实际上是keyfile保护,会访问
DataFit.lic和Eval.lic。
另外,我习惯性地把text section改为E0000020,结果不能运行。
在SoftIce下没反应,直接运行报找不到Q.dll,看来还有自校验。
先不管它。
2.在SmartCheck下运行,打开Help|License,可以输一个license
number,与用户名无关?输入12345678。
输完后没有反应,也许是重启校验,于是退出程序。在主窗口的
Unload事件处理中,找到对license number的处理(SmartCheck
不能把代码拷出来,这点不如W32Dasm:-),从9C2148开始:
1)license number按奇、偶数位重新组合:
"12345678" -> "24681357"
2)将最后1位放到最前面,循环13次。我的number给得太小,有的数
字用了两次。
这中间调用了LCase,说明number实际上是字母或包含字母。
3)从9C239B起,对license number进行换码(一个大的select case),
26个小写字母乱序后重新得到一个字符串。可见license number
全为字母。
4)从9C2876起,对number再次换码,把26个小写字母看作一个闭合
的环,每个字母左移12位,如'l'->'a','m'->'b'。
以下好象就没什么明显的代码了,无数的Rnd,Double,Chr调用。我
以为这些代码是"逗你玩",于是掉头去看前面,也有很多类似的代
码,而且没有看到上面变换的结果被使用。
3.也许应该试试凑个keyfile。不过在IDA Pro中看看再说。在上面的
代码之后,却可以看到调用__vbaStrCmp进行明码比较。不知为什么
SmartCheck没有报出对__vbaStrCmp的调用。用于与明码比较的字符
串是上面处理过的字符串再次按奇偶数位组合的结果。
比较指令很多,实际上是个循环,在5CD150开始的函数内。比较循环
执行300次,难怪在SmartCheck中那么多重复的代码。问题是用于比
较的明码是用Rnd生成的?
先不管它,用断到的第1个明码"stcrdvgiexsgxqyh"写一个逆反过程
试试:
CString strInput="stcrdvgiexsgxqyh";
//将奇,偶数位重新放置
CString strKey;
for(int i=0;i<strInput.GetLength()/2;i++)
{
strKey += strInput[i + strInput.GetLength()/2];
strKey += strInput[i];
}
//逐字符移位(把26个字母看做封闭的环:-)
int nLen=strKey.GetLength();
for(i=0;i<nLen;i++)
{
strKey.SetAt(i,(strKey[i] + 0xC >'z')?
strKey[i] + 0xC - 0x1A : strKey[i] + 0xC);
}
//换码
char szPlain[]="abcdefghijklmnopqrstuvwxyz";
char szCipher[]="lesiaxkcpgnmvrzfbhjuqdoywt";
for(i=0;i<nLen;i++)
{
for(int j=0;j<26;j++)
{
if(strKey[i]==szCipher[j])
{
strKey.SetAt(i,szPlain[j]);
break;
}
}
}
//把第1位放到最后面,循环13次
for(i=0;i<13;i++)
{
strKey=strKey.Right(nLen - 1) + strKey.Left(1);
}
//再次将奇,偶数位重新放置
CString strOutput;
for(i=0;i<strKey.GetLength()/2;i++)
{
strOutput += strKey[i + strKey.GetLength()/2];
strOutput += strKey[i];
}
TRACE("%s
",strOutput);
把结果"wcczvtsuibhsrpgb"输入,OK:-)。再看看目录下面,并没有
DataFit.lic文件。上述license number被写入了注册表。看来没有
keyfile也行:-)。
4.下面再来看看license number怎么会由随机数生成?以下为相关的汇编
代码。
.text:005CD1F2 mov ebx, 61h ; 'a'
.text:005CD1F7 mov [ebp+var_50], 0FFFFFFFFh
.text:005CD1FE mov edi, 2
.text:005CD203 mov [ebp+var_number], edi
.text:005CD206 lea eax, [ebp+var_number]
.text:005CD209 push eax
.text:005CD20A call ds:rtcRandomNext ; 这里把var_50置为-1,push的
.text:005CD20A ; 却是另一个指针(->2)?
.text:005CD20A ;
.text:005CD20A ; 在SmartCheck中为Rnd(-1),
.text:005CD20A ; 这个是对的
.text:005CD20A ;
.text:005CD210 fstp st
.text:005CD212 lea ecx, [ebp+var_number]
.text:005CD215 mov esi, ds:__vbaFreeVar
.text:005CD21B call esi ; __vbaFreeVar
.text:005CD21D mov word ptr [ebp+var_50], 19h
.text:005CD223 mov [ebp+var_number], edi
.text:005CD226 lea ecx, [ebp+var_number]
.text:005CD229 push ecx
.text:005CD22A call ds:rtcRandomize ; Rnd(25)
.text:005CD230 lea ecx, [ebp+var_number]
.text:005CD233 call esi ; __vbaFreeVar
.text:005CD235 mov [ebp+var_38], 0
.text:005CD23C mov [ebp+var_nCount], 1
.text:005CD243
.text:005CD243 loc_5CD243: ; CODE XREF: sub_5CD150+21D
.text:005CD243 mov eax, 12Ch ; 300次
.text:005CD248 cmp word ptr [ebp+var_nCount], ax
.text:005CD24C jg loc_5CD379
.text:005CD252 mov edx, offset unk_45F354
.text:005CD257 lea ecx, [ebp+var_pCurrLicNum]
.text:005CD25A call ds:__vbaStrCopy
.text:005CD260 mov esi, 1
.text:005CD265
.text:005CD265 loc_5CD265: ; CODE XREF: sub_5CD150+1F2
.text:005CD265 mov eax, 10h ; 1个license number为16位
.text:005CD26A cmp si, ax
.text:005CD26D jg l_cmp
.text:005CD273 mov [ebp+var_50], 80020004h
.text:005CD27A mov [ebp+var_number], 0Ah
.text:005CD281 lea edx, [ebp+var_number]
.text:005CD284 push edx
.text:005CD285 call ds:rtcRandomNext
.text:005CD28B fstp [ebp+var_rnd]
.text:005CD291 mov eax, 7Ah ; 'z'
.text:005CD296 sub ax, bx ; bx=0x61 ->'a'
.text:005CD299 jo l_exception
.text:005CD29F add ax, 1
.text:005CD2A3 jo l_exception
.text:005CD2A9 movsx eax, ax
.text:005CD2AC mov [ebp+var_int], eax
.text:005CD2B2 fild [ebp+var_int] ; 装入整数到st(0)
.text:005CD2B8 fstp [ebp+var_194] ; var_194 <-st(0)
.text:005CD2BE fld [ebp+var_194] ; 装入实数到st(0)
.text:005CD2BE ; 这几句把0x7A转化为实数
.text:005CD2BE ; 0x7A->字符'z'
.text:005CD2C4 fmul [ebp+var_rnd]
.text:005CD2CA movsx ecx, bx
.text:005CD2CD mov [ebp+var_198], ecx
.text:005CD2D3 fild [ebp+var_198]
.text:005CD2D9 fstp [ebp+var_19C]
.text:005CD2DF fadd [ebp+var_19C] ; 加,不用再看下去了:-)
.text:005CD2E5 fnstsw ax
.text:005CD2E7 test al, 0Dh
.text:005CD2E9 jnz loc_5CD74E
.text:005CD2EF call ds:__vbaR8IntI2
.text:005CD2F5 mov edi, eax
.text:005CD2F7 lea ecx, [ebp+var_number]
.text:005CD2FA call ds:__vbaFreeVar
.text:005CD300 mov edx, [ebp+var_pCurrLicNum]
.text:005CD303 push edx
.text:005CD304 movsx eax, di
.text:005CD307 push eax
.text:005CD308 call ds:rtcBstrFromAnsi
.text:005CD30E mov edx, eax
.text:005CD310 lea ecx, [ebp+var_48]
.text:005CD313 mov edi, ds:__vbaStrMove
.text:005CD319 call edi ; __vbaStrMove
.text:005CD31B push eax
.text:005CD31C call ds:__vbaStrCat
.text:005CD322 mov edx, eax
.text:005CD324 lea ecx, [ebp+var_pCurrLicNum]
.text:005CD327 call edi ; __vbaStrMove
.text:005CD329 lea ecx, [ebp+var_48]
.text:005CD32C call ds:__vbaFreeStr
.text:005CD332 mov eax, 1
.text:005CD337 add ax, si
.text:005CD33A jo l_exception
.text:005CD340 mov esi, eax
.text:005CD342 jmp loc_5CD265
.text:005CD347 ; ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
.text:005CD347
.text:005CD347 l_cmp: ; CODE XREF: sub_5CD150+11D
.text:005CD347 mov ecx, [ebp+arg_pPtInputedLicNum]
.text:005CD34A mov edx, [ecx]
.text:005CD34C push edx
.text:005CD34D mov eax, [ebp+var_pCurrLicNum]
.text:005CD350 push eax
.text:005CD351 call ds:__vbaStrCmp
.text:005CD357 test eax, eax
.text:005CD359 jz short loc_5CD372
.text:005CD35B mov eax, 1
.text:005CD360 add ax, word ptr [ebp+var_nCount]
.text:005CD364 jo l_exception
.text:005CD36A mov [ebp+var_nCount], eax
.text:005CD36D jmp loc_5CD243
没有太大的意思。见MSDN对Randomize的解释:若想得到重复的随机数序列,
在使用具有数值参数的 Randomize 之前直接调用具有负参数值的Rnd。这里
先用-1去调Rnd,得到固定的"随机数"序列,用来在'a'-'z'间取值。可以
照葫芦画瓢,做出300个license number,一网打尽:-)。
Rnd (-1)
Randomize (25)
For i = 1 To 300 '300个license number
CurrLicNum = ""
For j = 1 To 16 '每个16字符
CurrLicNum = CurrLicNum + Chr(&H61 + Int(26 * Rnd))
Next j
Next i
这里只是明文,还要逆回去。难道厂商只打算卖300份?或许这300个license
number用完了,就要用keyfile了:-)