Otoboku 发表于 2021-1-17 00:05

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;
}
```

wsf5201314 发表于 2021-1-17 15:56

学习一下 感谢楼主分享经验
页: [1]
查看完整版本: 160 crackme 之 007