在大连做安天技术论坛 CrackMe3

第三关涉及到一个加密算法和注册机的编写,比较复杂,首先简单破解程序

使用命令 bp GetWindowTextA 下断点,找到获取字符串的关键代码


发现用户名和序列号分别被存在了,004053B0 和 004053A0,果断下内存断点,发现了判断长度的关键代码

在大连做安天技术论坛 CrackMe3_第1张图片

这里其实是Strlen()这个函数翻译成汇编的执行过程,

参考:
重复前缀指令
任何一个串操作指令,都可以在前面加一个重复前缀,以实现串操作的重复执行,重复次数隐含在CX寄存器中
REP        ;REP前缀用在MOVS、STOS、LODS指令前,每次执行一次指令,CX减1;直到CX=0,重复执行结束
REPZ       ;也可以表把为REPE,用在CMPS、SCAS指令前,每执行一次串指令CX减1,并判断ZF标志是否为0
           ;只要CX=0或ZF=0,则重复执行结束
REPNZ      ;也可以表达为REPNE,用在CMPS、SCAS指令前,每执行一次串操作指令CX减1,并判断ZF标志是否为1,只要CX=0或ZF=1,则重复执行结束。

串扫描指令SCAS
SCASB         ;字节串扫描:AL-ES:[DI],DI←DI+/-1
SCASW         ;字串扫描:AX-ES:[DI],DI←DI+/-2
串扫描指令SCAS将附加段中的字节或字内容与AL/AX寄存器内容进行比较,根据比较的结果设置标志,每次比较后修改DI寄存器的值,使之指向下一个元素。


解释:
假设esp+10指向字符串如:"xqiang",长度为6,以0结尾
ecx=FFFFFFFF
eax=0,则al=0
执行repne scas时候:
第一次:
al-'x',di=di-1,即byte ptr es:[edi]指向'q',并置相应的标志位
然后cx-1,则ecx=FFFFFFFE,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第二次:
al-'q',di=di-1,即byte ptr es:[edi]指向'i',并置相应的标志位
然后cx-1,则ecx=FFFFFFFD,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第三次:
al-'i',di=di-1,即byte ptr es:[edi]指向'a',并置相应的标志位
然后cx-1,则ecx=FFFFFFFC,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第三次:
al-'a',di=di-1,即byte ptr es:[edi]指向'n',并置相应的标志位
然后cx-1,则ecx=FFFFFFFB,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第四次:
al-'n',di=di-1,即byte ptr es:[edi]指向'g',并置相应的标志位
然后cx-1,则ecx=FFFFFFFA,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第五次:
al-'g',di=di-1,即byte ptr es:[edi]指向'0',并置相应的标志位
然后cx-1,则ecx=FFFFFFF9,判断是否cx=0或ZF=1,显然该处条件不成立,继续重复执行
第六次:
al-0,di=di-1,即byte ptr es:[edi]指向'未知字符',并置相应的标志位
然后cx-1,则ecx=FFFFFFF8,判断是否cx=0或ZF=1,此时ZF=1,停止串搜索
现在ecx从FFFFFFFF到FFFFFFF8记录了字符串'xqiang'和0的长度
然后not ecx得到ecx=00000007
    dec ecx得到ecx=00000006 该长度就是字符串'xqiang'的实际长度

这里吧jb这个转跳给nop掉,就可以跳过长度的检测。

另外rep 还经常和 movs 和 stos 组合

具体看这里http://jpkc.zzu.edu.cn/hbyycai/courses/list.asp?id=131


根据程序运行的尿性,使用bp createWindowExa下断,找到关键代码

在大连做安天技术论坛 CrackMe3_第2张图片

之前的转跳首先得nop掉,这里直接改成je,下面SetWindowTextA是设置窗口里面的文字的,首先把转跳干掉,再在内存中

写入“恭喜你,注册成功“之类的话,吧指针push进去就行了。

SetWindowTextA的定义如下

BOOL SetWindowText(HWND hwnd,LPCTSTR lpString)

第一个窗口句柄,第二个字符串指针。这么说,上图中eax是句柄,不要动它

ecx是字符串指针,我们修改它。

修改后如下



直接暴力的吧值赋给ecx,再把它push进去就可以了,其他语句用nop填就好,这些修改都改完了,程序的爆破就完成了。



最近试了一些IDA的F5插件感觉不错,把加密的代码直接转成了c,这样分析起来就会格外方便,不过在这里就不分析了,
最近想搞搞破解,先把antiy 的crack做完吧~
HWND __cdecl sub_401BD0(HWND hWnd)
{
  HWND result; // eax@1
  int v2; // edx@5
  int v3; // ecx@5
  unsigned int v4; // eax@6
  signed int v5; // ecx@6
  signed int v6; // ST2C_4@6
  signed int v7; // eax@11
  unsigned int v8; // eax@13
  const CHAR *v9; // ecx@13
  char *v10; // esi@13
  int v11; // edx@15
  int v12; // ecx@15
  unsigned int v13; // eax@16
  signed int v14; // ecx@16
  signed int v15; // ST2C_4@16
  signed int v16; // eax@21
  int v17; // esi@4
  int v18; // ecx@4
  unsigned __int8 v19; // cf@7
  const CHAR v20; // dl@14
  unsigned __int8 v21; // cf@17
  int v22; // [sp+8h] [bp-414h]@5
  char v23; // [sp+Ch] [bp-410h]@5
  int v24; // [sp+4h] [bp-418h]@10
  const CHAR String; // [sp+408h] [bp-14h]@13
  int v26; // [sp+409h] [bp-13h]@13
  int v27; // [sp+40Dh] [bp-Fh]@13
  int v28; // [sp+411h] [bp-Bh]@13
  int v29; // [sp+415h] [bp-7h]@13

  result = 0;
  if ( strlen(String) - 1 >= 4 )
  {
    if ( strlen(dword_4053A0) - 1 >= 8 )
    {
      memset(byte_4047A0, 0, 0xC00u);
      do
      {
        v17 = dword_4053A0[(_BYTE)result & 0xF];
        v18 = String[(_BYTE)result++ & 0xF];
        *(_BYTE *)((_DWORD)byte_40479F + (_DWORD)result) = *(&(*off_401174)[v17] + v18);
      }
      while ( (unsigned int)result < 0xC00 );
      v22 = 0;
      memset(&v23, 0, 0x3FCu);
      v2 = -1;
      v3 = 256;
      do
      {
        v4 = v3 - 1;
        v6 = v3;
        v5 = 8;
        do
        {
          v19 = __MKCSHR__(v4, 1);
          v4 >>= 1;
          if ( v19 )
            v4 ^= 0xEDB88320u;
          --v5;
        }
        while ( v5 );
        *(&v24 + v6) = v4;
        v3 = v6 - 1;
      }
      while ( v6 != 1 );
      v7 = 0;
      do
        v2 = *(&v22 + ((_BYTE)v2 ^ byte_4047A0[v7++])) ^ ((unsigned int)v2 >> 8);
      while ( v7 < 3072 );
      String = 0;
      v9 = &String;
      v10 = (char *)&dword_4010DE + (unsigned __int8)~(_BYTE)v2 % 0x6Du;
      v26 = 0;
      v8 = 0;
      v27 = 0;
      v28 = 0;
      v29 = 0;
      do
      {
        v20 = v10[v8];
        v8 += 2;
        *v9++ = v20;
      }
      while ( v8 < 0x20 );
      v22 = 0;
      memset(&v23, 0, 0x3FCu);
      v11 = -1;
      v12 = 256;
      do
      {
        v13 = v12 - 1;
        v15 = v12;
        v14 = 8;
        do
        {
          v21 = __MKCSHR__(v13, 1);
          v13 >>= 1;
          if ( v21 )
            v13 ^= 0xEDB88320u;
          --v14;
        }
        while ( v14 );
        *(&v24 + v15) = v13;
        v12 = v15 - 1;
      }
      while ( v15 != 1 );
      v16 = 0;
      do
        v11 = *(&v22 + ((_BYTE)v11 ^ *(&String + v16++))) ^ ((unsigned int)v11 >> 8);
      while ( v16 < 16 );
      if ( ~v11 == *((_DWORD *)v10 + 8) )
      {
        result = CreateWindowExA(0x20000u, "STATIC", "提示", 0x10CF0001u, 0, 0, 180, 90, hWnd, 0, 0, 0);
        if ( result )
          result = (HWND)SetWindowTextA(result, &String);
      }
      else
      {
        result = (HWND)MessageBoxA(hWnd, "注册失败", "错?, 0x10u);
      }
    }
  }
  return result;
}




你可能感兴趣的:(在大连做安天技术论坛 CrackMe3)