160 crackme 之 007
# 起手- 查壳 Borland Delphi v3.0
- 直接用idr吧
# 任务
- 让下边两个按钮不可见
这回学聪明了,先总体看看
一共三个事件,Registerz,Again(原本影藏的按钮),Canella
Registerz,Again中都有改变按钮可见的代码.只要这么走完就可以使得两按钮不可见了.
```
;Registerz中的
CODE:00442FC2 xor edx, edx
CODE:00442FC4 mov eax, ; 'TPrincipale.Registerz:TButton'
CODE:00442FCA call TControl_SetVisible
CODE:00442FCF mov dl, 1
CODE:00442FD1 mov eax, ; 'TPrincipale.Again:TButton'
CODE:00442FD7 call TControl_SetVisible
CODE:00442FDC xor edx, edx
;Again中的
CODE:0044315B xor edx, edx
CODE:0044315D mov eax, ; 'TPrincipale.Again:TButton'
CODE:00443163 call TControl_SetVisible
CODE:00443168 lea edx, ;
CODE:0044316B mov eax, ds:g_strangeHwnd ; this
CODE:00443170 call TControl_GetText
CODE:00443175 lea eax,
CODE:00443178 call UniqueString
CODE:0044317D mov byte ptr , 65h ; 'e'
CODE:00443181 lea eax,
CODE:00443184 call UniqueString
CODE:00443189 mov byte ptr , 64h ; 'd'
CODE:0044318D lea eax,
```
## 总结下
code中没有字符,并且大于0 ->`00442FB9 call sub_4429A8` 返回非零值 ->Registerz不可见, again可见->`00443152 call sub_4429A8` 返回非零值->again不可见
发现两个过程对比函数一样的.但是和ds:dword_445830这个全局变量有关
```
CODE:00443148 mov ecx, ; pName
CODE:0044314B mov edx, esi ; Numcode
CODE:0044314D mov eax, ds:dword_445830 ; 诡异的全局变量,初始值为0.
CODE:00443152 call sub_4429A8
;而且对比完成后全局变量被清零了,也就是说走完后一样要想办法让他重新被赋值
CODE:00442FC2 xor edx, edx
CODE:00442FC4 mov eax, ; 'TPrincipale.Registerz:TButton'
CODE:00442FCA call TControl_SetVisible
CODE:00442FCF mov dl, 1
CODE:00442FD1 mov eax, ; 'TPrincipale.Again:TButton'
CODE:00442FD7 call TControl_SetVisible
CODE:00442FDC xor edx, edx
CODE:00442FDE mov eax, ; 'TPrincipale.Nome:TEdit'
CODE:00442FE4 mov ecx,
CODE:00442FE6 call dword ptr ; 'TControl.SetEnabled'
CODE:00442FE9 xor eax, eax
CODE:00442FEB mov ds:dword_445830, eax ; 又被变成零了
CODE:00442FF0 jmp short loc_44300C
```
Registerz,again事件中,当数字中混有字母,转换出问题的时后,会有一个函数会改变全局变量的值而且都指向sub_442A8C,而且是赋值全局变量的
```
CODE:00442F70 lea edx,
CODE:00442F73 mov eax, ; 'TPrincipale.Codice:TEdit'
CODE:00442F79 call TControl_GetText
CODE:00442F7E mov eax, ; this
CODE:00442F81 call sub_442A8C
CODE:00442F86 mov ds:dword_445830, eax
```
# 4429A8
注册机RegCode2的代码就是还原的4429A8 ,明显,当全局变量 gVal=0的时候 v4永远等于0.这个函数永远返回0
希望寄托于442A8C
# 442A8C
注册机RegCode2的代码就是还原的442A8C, 他可以返回值赋值给全局变量.全局变量有值了,4429A8才会正常工作
# 总结2
那么流程修正为
- 在注册码框输入一个有字母的注册码1,长度大于5.
- 点注册,会提示错误.
- 然后输入注册名,注册码2点注册,注册按钮消失
-在注册码框输入一个有字母的注册码1,长度大于5.
- 点Again,提示错误
- 注册码点注册2,Again按钮消失.任务完成
# 最后看看4429A8比较处的函数
也就是这个.
```
nRet = abs32(v4) % 666666;
Numcode = Numcode % 80 + Numcode / 89 + 1;
if ( nRet == Numcode )
LOBYTE(nRet) = 1;
else
return 0;
```
改写下 `y=x % 80 + x / 89 + 1` 变成一个大家都懂的函数
- 这是一个类周期函数(姑且叫周期吧).函数图像是一个越来越高的锯齿.
- 每一个锯齿长度是80,每89函数锯齿会上移一个单位
- 那么每一个周期80最低点为nRet最多出现在89*(nRet-1)之前
- 每一个周期80最高点为nRet,至少出现在89*(nRet-1-80)之后.
- 那么明显满足条件的解不唯一.在区间全部整数算一遍,就可以得到所有的解.
- 本来可以用直线方程只要计算80次就可以得到全部解了,但是,我的头已经晕了.还是给PC自己去试6000+次算了.
# 注册机
```
#include <iostream>
#include <math.h>
#define LStrLen strlen
#define abs32 abs
int RegCode1(const char* pCodeString)
{
int nRet, v2, v3;
if (LStrLen(pCodeString) <= 5)
{
nRet = 0;
}
else
{
nRet = 891;
v2 = LStrLen(pCodeString) - 1;
if (v2 > 0)
{
v3 = 1;
do
{
nRet += pCodeString * (pCodeString % 0x11u + 1);
++v3;
--v2;
} while (v2);
}
}
return abs32(nRet % 29000);
}
int RegCode2(const char* pName, int gVal)
{
int nRet=0, v4, v5, v15, v7, v6;
if (LStrLen(pName) <= 4)
{
;
}
else
{
v4 = 0;
v5 = LStrLen(pName);
if (v5 > 0)
{
v15 = v5;
v6 = 1;
do
{
v7 = LStrLen(pName);
if (v7 >= 1)
{
do
v4 += gVal * *(pName + v7-- - 1) * *(pName + v6 - 1);
while (v7);
}
++v6;
--v15;
} while (v15);
}
int nStr = abs32(v4) % 666666;
std::cout << "寻找可能Code:" << std::endl;
for (int Numcode = 89 * (nStr - 1 - 80); Numcode < 89 * (nStr - 1); Numcode++)
{
if (nStr == Numcode % 80 + Numcode / 89 + 1)
{
std::cout << "" << Numcode << std::endl;
nRet= Numcode;
}
}
}
return nRet;
}
int main()
{
const char* pCodeInt = "Hello World!";
//注册码1=Wow!so_cool
int gVal=RegCode1("Wow!so_cool");
//用户名=Otoboku 注册码2=Code
int Code = RegCode2("Otoboku", gVal);
std::cout << gVal << " " << Code << std::endl;
}
``` 学习一下 感谢楼主分享经验
页:
[1]