Otoboku 发表于 2021-1-16 11:36

160 crackme 之 006

# 起手

- 查壳 Borland Delphi v3.0
- 直接用idr吧



# 任务

- 让下边两个按钮不可见



初期的想法是肯定在文本框中有事件,那么看看吧

# 跟下文本框文字改变事件

- 先看看在名字文本框的文字变化事件中有如下代码段,可以随便输入点东西,在0x00442E60断下后强制修改EIP看看结果,发现OK可以用了.

```assembly
00442E37      lea         edx,
00442E3A      mov         eax,dword ptr ;TPrincipale.Codice:TEdit
00442E40      call      TControl.GetText      ;取出注册码
00442E45      mov         eax,dword ptr
00442E48      push      eax
00442E49      lea         edx,
00442E4C      mov         eax,dword ptr ;TPrincipale.Nome:TEdit
00442E52      call      TControl.GetText   ;        取出名字
00442E57      mov         eax,dword ptr ;ax name
00442E5A      pop         edx ;code
00442E5B      call      00442A3C   ;这里是OK是否可用的关键
00442E60      test      al,al ;等于0么
00442E62>       je          00442E73 ;
00442E64      mov         dl,1    ;不是0可用
00442E66      mov         eax,dword ptr ;;TPrincipale.Ok:TButton
00442E6C      mov         ecx,dword ptr
00442E6E      call      dword ptr ;TControl.SetEnabled
00442E71>       jmp         00442E80 ;是0不可用
00442E73      xor         edx,edx
00442E75      mov         eax,dword ptr ;TPrincipale.Ok:TButton
00442E7B      mov         ecx,dword ptr
00442E7D      call      dword ptr ;TControl.SetEnabled
```

## 00442A3C

```assembly
00442A68      mov         eax,dword ptr
00442A6B      call      @LStrLen
00442A70      cmp         eax,5 ;名字不能小于等于5
00442A73>       jle         00442AC8
00442A75      mov         eax,dword ptr
00442A78      call      @LStrLen
00442A7D      mov         ebx,eax
00442A7F      mov         eax,dword ptr
00442A82      call      @LStrLen
00442A87      mov         edx,eax
00442A89      dec         edx
00442A8A      test      edx,edx ; edx长度
00442A8C>       jle         00442AAE ;;多余的代码
00442A8E      mov         eax,1
00442A93      mov         ecx,dword ptr
00442A96      movzx       ecx,byte ptr
00442A9B      mov         esi,dword ptr
00442A9E      movzx       esi,byte ptr
00442AA2      imul      ecx,esi ;字符第n-1个x第n个 * n n从1开始
00442AA5      imul      ecx,eax
00442AA8      add         ebx,ecx ;长度+ 刚才算出来的
00442AAA      inc         eax
00442AAB      dec         edx ;长度-1 循环n字
00442AAC>       jne         00442A93
00442AAE      mov         eax,dword ptr
00442AB1      call      StrToInt ;注册码
00442AB6      sub         ebx,eax
00442AB8      cmp         ebx,29A ;相减=0x29
00442ABE>       jne         00442AC4
00442AC0      mov         bl,1 ;相等就ebx=1
00442AC2>       jmp         00442ACA
00442AC4      xor         ebx,ebx ;不等就ebx=0
00442AC6>       jmp         00442ACA
```

## 写下如下代码

重启后输入发现正确.OK有效了.

```C#
static stringRegCode(string userName)
{
int nLen = userName.Length;
if (nLen<=5)
{
    return "";
}
int ebx = nLen;
int eax = 1;
int edx = nLen - 1;
do
{
    ebx = userName * userName * eax + ebx;
    edx--;eax++;
} while (edx > 0);
ebx-=0x29A;
return $"{ebx}";
}
```

# 接着看OK按钮的

由代码可知,首先要让Cancella不可见才能继续点OK,所以现在还不能点OK,

```assembly
00442D7A      mov         eax,dword ptr ;TPrincipale.Cancella:TButton
00442D80      cmp         byte ptr ,1; Cancella按钮可见么 TButton.FVisible:Boolean
00442D84>       jne         00442D98
00442D86      mov         edx,442E00;'0'   '可见,那么吧code文本清空
00442D8B      mov         eax,dword ptr ;TPrincipale.Codice:TEdit
00442D91      call      TControl.SetText
00442D96>       jmp         00442DD7
00442D98      lea         edx,;如果Cancella不可见
00442D9B      mov         eax,dword ptr ;TPrincipale.Codice:TEdit
00442DA1      call      TControl.GetText
00442DA6      mov         eax,dword ptr
00442DA9      call      StrToInt
00442DAE      push      eax
00442DAF      lea         edx,
00442DB2      mov         eax,dword ptr ;TPrincipale.Nome:TEdit
00442DB8      call      TControl.GetText
00442DBD      mov         eax,dword ptr
00442DC0      pop         edx
00442DC1      call      00442BA0
00442DC6      test      al,al;必须返回1
00442DC8>       je          00442DD7;
00442DCA      xor         edx,edx      ;    使得OK不可见
00442DCC      mov         eax,dword ptr ;TPrincipale.Ok:TButton
00442DD2      call      TControl.SetVisible
```

# 看Cancella的

实在没地方看了,那就看看这个吧,感觉就是cancel.所以开始也就没注意看了.

结果,大跌眼镜,00442AF4会使得Cancella不可见,Ok可以按下,卧槽,感情刚才文本框的就是都是白玩了.作者真是坏透了

```assembly
00442EBE      lea         edx,
00442EC1      mov         eax,dword ptr ;TPrincipale.Codice:TEdit
00442EC7      call      TControl.GetText
00442ECC      mov         eax,dword ptr
00442ECF      call      StrToInt
00442ED4      push      eax
00442ED5      lea         edx,
00442ED8      mov         eax,dword ptr ;TPrincipale.Nome:TEdit
00442EDE      call      TControl.GetText
00442EE3      mov         eax,dword ptr
00442EE6      pop         edx
00442EE7      call      00442AF4
00442EEC      test      al,al
00442EEE>       je          00442F0C
00442EF0      xor         edx,edx ;如果返回0 则设定cancella不可见
00442EF2      mov         eax,dword ptr ;TPrincipale.Cancella:TButton
00442EF8      call      TControl.SetVisible
00442EFD      mov         dl,1 ;Ok有效可以点击
00442EFF      mov         eax,dword ptr ;TPrincipale.Ok:TButton
00442F05      mov         ecx,dword ptr
00442F07      call      dword ptr ;TControl.SetEnabled
```

##00442AF4

```assembly
00442B25      mov         eax,dword ptr
00442B28      movzx       eax,byte ptr ;第5个字母asc/7
00442B2C      mov         ecx,7
00442B31      xor         edx,edx
00442B33      div         eax,ecx;=eax/ecx,商入eax,余数入edx
00442B35      mov         eax,edx
00442B37      add         eax,2;余数加2
00442B3A      call      00442A20 ;阶乘
00442B3F      mov         esi,eax;放入esi
00442B41      xor         ebx,ebx
00442B43      mov         eax,dword ptr
00442B46      call      @LStrLen
00442B4B      test      eax,eax
00442B4D>       jle         00442B65
00442B4F      mov         edx,1
00442B54      mov         ecx,dword ptr
00442B57      movzx       ecx,byte ptr
00442B5C      imul      ecx,esi   ;ebx=n位字符*esi + ebx
00442B5F      add         ebx,ecx
00442B61      inc         edx
00442B62      dec         eax
00442B63>       jne         00442B54
00442B65      sub         ebx,dword ptr
00442B68      cmp         ebx,7A69
00442B6E>       jne         00442B74
00442B70      mov         bl,1
00442B72>       jmp         00442B7A
```

## 如下代码

cancella不可见了

```C#
static string RegCode2(string userName)
{
int nLen = userName.Length;
if (nLen <= 5)
{
    return "";
}
int esi = (userName % 7) + 2;
esi = Fact(esi);//阶乘
int ebx = 0;
int eax = 1;
int edx = nLen;
do
{
    ebx = userName * esi+ ebx;
    edx--; eax++;
} while (edx > 0);
ebx -= 0x7A69;
return $"{ebx}";
}
```

# 好了,按下Ok的条件满足

关键的call 00442BA0

```assembly
00442BC8      lea         edx,
00442BCB      mov         eax,esi;code
00442BCD      call      IntToStr   ;code转字串
00442BD2      lea         eax,
00442BD5      mov         edx,dword ptr
00442BD8      call      @LStrLAsg    ;复制一份Code的字符串
00442BDD      mov         eax,dword ptr
00442BE0      call      @LStrLen
00442BE5      cmp         eax,5;要求大于等于5长度
00442BE8>       jle         00442C4A
00442BEA      mov         eax,dword ptr
00442BED      call      @LStrLen
00442BF2      mov         esi,eax
00442BF4      cmp         esi,1
00442BF7>       jl          00442C28
00442BF9      lea         eax,
00442BFC      call      UniqueString;独占使用
00442C01      lea         eax, ;指向处理的byte
00442C05      push      eax
00442C06      mov         eax,dword ptr
00442C09      movzx       eax,byte ptr ;倒过来取值
00442C0E      imul      eax ;eax=eax*eax
00442C10      movsx       eax,ax ;取出低16位
00442C13      imul      esi;再乘esi=code字串的长度
00442C15      mov         ecx,19
00442C1A      cdq
00442C1B      idiv      eax,ecx ;eax/0x19 商eax 余数edx
00442C1D      add         edx,41 ;余数+0x41
00442C20      pop         eax;;第n位指针
00442C21      mov         byte ptr ,dl;edx低8位赋值
00442C23      dec         esi
00442C24      test      esi,esi
00442C26>       jne         00442BF9
00442C28      mov         eax,dword ptr ;新的字串和Name比较
00442C2B      mov         edx,dword ptr
00442C2E      call      @LStrCmp
00442C33>       jne         00442C4C
00442C35      mov         eax,dword ptr
00442C38      mov         edx,dword ptr
00442C3B      call      @LStrCmp
00442C40>       jne         00442C46
00442C42      mov         bl,1;相等就返回1
```

## 编写代码

运行后,得到一个用户名,输入点OK,任务完成.

```C#
static string RegCode3(string code)
{
int nLen = code.Length;
if (nLen <= 5)
{
    return "";
}
byte[] bCode = Encoding.Default.GetBytes(code);
int esi = nLen;
do
{
    int eax = bCode;
    eax = ((eax * eax*esi) & 0xffff) % 0x19;
    eax += 0x41;
    bCode = (byte)(eax & 0xff);
    esi-- ;
} while (esi > 0);
return Encoding.Default.GetString(bCode);
}
```

# 总结

- 注册流程
- 先输入一个用户名,运行RegCode2得到注册码,点cancella,cancella消失
- 然后再用这个注册码运行RegCode3得到一个用户名,填入后点OK.OK按钮消失,任务完成
- 人心险恶啊.大家多多保重.
页: [1]
查看完整版本: 160 crackme 之 006