首页
社区
课程
招聘
[原创]CTF2016第一组凉飕飕的CrackMe破解分析作业
发表于: 2016-11-3 00:57 3725

[原创]CTF2016第一组凉飕飕的CrackMe破解分析作业

2016-11-3 00:57
3725
标题:CTF2016第一组凉飕飕的CrackMe破解分析作业
工具:OD+IDA
CrackMe下载:点这里

比赛在工作日,刚坐下屁股就被老板叫去干活,实在没时间参加攻击组,还好我也参加了防御组。
代码为今天晚上分析时将关键几处算法摘录,可能注释得不是很完整,但思路是有的,将就看吧。

先把结论写在开头:
注册码第1位为“1”,第2位为“2”,第3位为“1”,第4位为“5”,第5位为“p”,第6位为“b”,第7位为“8”
连接在一起为:1215pb8,测试成功,但是测试第2次时又提示错误,难道是暗桩?
这与比赛规格“对于正确的注册码必须在何时都能提示成功信息,否则设计不合理”相违背,作者会不会被取消参赛资格或扣除一半分数?
其BUG代码位于00401790处,不应取测试次数关联到取字符串起始位置和长度,导致每次注册码都会改变,甚至后续几次测试无答案。
作品算法方面没有新意,将简单的注册码校验过程拆解成很多片段,绕得人头晕。


摘录分析过程:

//反调试,修改返回值为0 (还有其他反调试、花指令,直接无视)
CALL 004048DE

//要求注册码包含字母“b”
CALL 00401C00

//要求注册码包含字母“p”
CALL 00402A50

//注册码位数为7位
00401DE6   .  83FE 07       CMP ESI,0x7
00401DE9   .  73 0B         JNB XCrack_Me.00401DF6
00401DEB   .  6A 00         PUSH 0x0
00401DED   .  6A 00         PUSH 0x0
00401DEF   .  68 0E040000   PUSH 0x40E
00401DF4   .  EB 0B         JMP XCrack_Me.00401E01
00401DF6   >  76 2C         JBE XCrack_Me.00401E24

BOOL __fastcall sub_401A60(int a1, void *a2)
//调试到这里了

00401BA8  |> /83F8 02              /CMP EAX,0x2
00401BAB  |. |73 07                |JNB XCrack_Me.00401BB4

//注册码第一位、第二位字符与0xf异或
00401BAD  |. |66:833446 0F         |XOR WORD PTR DS:[ESI+EAX*2],0xF
00401BB2  |. |EB 11                |JMP XCrack_Me.00401BC5
00401BB4  |> |83F8 04              |CMP EAX,0x4
00401BB7  |. |73 07                |JNB XCrack_Me.00401BC0

//注册码第三位、第四位字符与0x50异或
00401BB9  |. |66:833446 50         |XOR WORD PTR DS:[ESI+EAX*2],0x50
00401BBE  |. |EB 05                |JMP XCrack_Me.00401BC5

//注册码第五位、第六位、第七位字符与0x42异或
00401BC0  |> |66:833446 42         |XOR WORD PTR DS:[ESI+EAX*2],0x42
00401BC5  |> |40                   |INC EAX
00401BC6  |. |3BC1                 |CMP EAX,ECX
00401BC8  |.^\72 DE                \JB XCrack_Me.00401BA8

//填充0x30-0x39,对应ASCII“0-9”
0040189D   .  B8 30000000          MOV EAX,0x30
004018A2   >  66:8901              MOV WORD PTR DS:[ECX],AX
004018A5   .  8D49 02              LEA ECX,DWORD PTR DS:[ECX+0x2]
004018A8   .  40                   INC EAX
004018A9   .  83F8 39              CMP EAX,0x39
004018AC   .^ 7E F4                JLE XCrack_Me.004018A2

//填充0x61-0x7a,对应ASCII“a-z”
004018AE   .  B8 61000000          MOV EAX,0x61
004018B3   .  8D4D B0              LEA ECX,DWORD PTR SS:[EBP-0x50]
004018B6   >  66:8901              MOV WORD PTR DS:[ECX],AX
004018B9   .  8D49 02              LEA ECX,DWORD PTR DS:[ECX+0x2]
004018BC   .  40                   INC EAX
004018BD   .  83F8 7A              CMP EAX,0x7A
004018C0   .^ 7E F4                JLE XCrack_Me.004018B6

//填充0x41-0x5a,对应ASCII“A-Z”
004018E0    0FB7444D B0            MOVZX EAX,WORD PTR SS:[EBP+ECX*2-0x50]
004018E5    83F8 61                CMP EAX,0x61
004018E8    72 0D                  JB XCrack_Me.004018F7
004018EA    83F8 7A                CMP EAX,0x7A
004018ED    77 08                  JA XCrack_Me.004018F7
004018EF    83C0 E0                ADD EAX,-0x20
004018F2    66:89444D B0           MOV WORD PTR SS:[EBP+ECX*2-0x50],AX
004018F7    41                     INC ECX
004018F8    3BCA                   CMP ECX,EDX
004018FA  ^ 72 E4                  JB XCrack_Me.004018E0

//注册码校验,详细见下文分析
CALL 00401870

//内存数据
001673D8  007F006D
001673DC  00640063
001673E0  00740077
001673E4  00000075

00401920    83F8 02                CMP EAX,0x2
00401923    73 07                  JNB XCrack_Me.0040192C

//变形后注册码第一位、第二位字符与0xf异或
00401925    66:833447 0F           XOR WORD PTR DS:[EDI+EAX*2],0xF
0040192A    EB 11                  JMP XCrack_Me.0040193D
0040192C    83F8 04                CMP EAX,0x4
0040192F    73 07                  JNB XCrack_Me.00401938

//变形后注册码第三位、第四位字符与0x50异或
00401931    66:833447 50           XOR WORD PTR DS:[EDI+EAX*2],0x50
00401936    EB 05                  JMP XCrack_Me.0040193D

//变形后注册码第五位、第六位、第七位字符与0x42异或
00401938    66:833447 42           XOR WORD PTR DS:[EDI+EAX*2],0x42
0040193D    40                     INC EAX
0040193E    3BC1                   CMP EAX,ECX
00401940  ^ 72 DE                  JB XCrack_Me.00401920

异或完之后的注册码又变回明文

//内存数据
001673D8  00700062
001673DC  00340033
001673E0  00360035
001673E4  00000037

//注册码小写转为大写
00401960    0FB7044F               MOVZX EAX,WORD PTR DS:[EDI+ECX*2]
00401964    83F8 61                CMP EAX,0x61
00401967    72 0C                  JB XCrack_Me.00401975
00401969    83F8 7A                CMP EAX,0x7A
0040196C    77 07                  JA XCrack_Me.00401975
0040196E    83C0 E0                ADD EAX,-0x20
00401971    66:89044F              MOV WORD PTR DS:[EDI+ECX*2],AX
00401975    41                     INC ECX
00401976    3BCA                   CMP ECX,EDX
00401978  ^ 72 E6                  JB XCrack_Me.00401960

//内存数据
001673D8  00500042
001673DC  00340033
001673E0  00360035
001673E4  00000037

//检查注册码每一位,大写字母只能有2个
0040199B    0FB710                 MOVZX EDX,WORD PTR DS:[EAX]                   ; 取注册码每一位
0040199E    8D4D B0                LEA ECX,DWORD PTR SS:[EBP-0x50]
004019A1    33C0                   XOR EAX,EAX
004019A3    66:3B11                CMP DX,WORD PTR DS:[ECX]
004019A6    74 10                  JE XCrack_Me.004019B8                         ; 比较注册码每一位是否为在A-Z之中
004019A8    40                     INC EAX
004019A9    8D4D B0                LEA ECX,DWORD PTR SS:[EBP-0x50]
004019AC    66:833C41 00           CMP WORD PTR DS:[ECX+EAX*2],0x0
004019B1    8D0C41                 LEA ECX,DWORD PTR DS:[ECX+EAX*2]
004019B4  ^ 75 ED                  JNZ XCrack_Me.004019A3
004019B6    EB 0B                  JMP XCrack_Me.004019C3
004019B8    66:8B4445 B0           MOV AX,WORD PTR SS:[EBP+EAX*2-0x50]
004019BD    66:8903                MOV WORD PTR DS:[EBX],AX
004019C0    83C3 02                ADD EBX,0x2
004019C3    66:8B4D B0             MOV CX,WORD PTR SS:[EBP-0x50]
004019C7    46                     INC ESI
004019C8    66:833C77 00           CMP WORD PTR DS:[EDI+ESI*2],0x0
004019CD    8D0477                 LEA EAX,DWORD PTR DS:[EDI+ESI*2]
004019D0  ^ 75 C4                  JNZ XCrack_Me.00401996
004019D2    8B5D AC                MOV EBX,DWORD PTR SS:[EBP-0x54]
004019D5    33C9                   XOR ECX,ECX
004019D7    8D45 F0                LEA EAX,DWORD PTR SS:[EBP-0x10]
004019DA    66:394D F0             CMP WORD PTR SS:[EBP-0x10],CX
004019DE    74 59                  JE XCrack_Me.00401A39
004019E0    8D40 02                LEA EAX,DWORD PTR DS:[EAX+0x2]
004019E3    41                     INC ECX
004019E4    66:8338 00             CMP WORD PTR DS:[EAX],0x0
004019E8  ^ 75 F6                  JNZ XCrack_Me.004019E0
004019EA    83F9 02                CMP ECX,0x2
004019ED    75 4A                  JNZ XCrack_Me.00401A39

//校验码
004019F1    C745 F0 31003500       MOV DWORD PTR SS:[EBP-0x10],0x350031                    ; 校验 0x31 0x35 0x50 0x42
004019F8    C745 F4 50004200       MOV DWORD PTR SS:[EBP-0xC],Crack_Me.00420050

//内存数据
00E3FC2C  00350031
00E3FC30  00420050  Crack_Me.00420050

//校验注册码与校验码是否相同,要求:1、5、P、B
00401A10    66:8B444D F0           MOV AX,WORD PTR SS:[EBP+ECX*2-0x10]
00401A15    66:3B06                CMP AX,WORD PTR DS:[ESI]                                ; 注册码第三位必须为“1”,第四位为“5”
00401A18    75 1F                  JNZ XCrack_Me.00401A39                                  ; 第五位为“P”,第六位为“B”(转换为大写后)
00401A1A    41                     INC ECX
00401A1B    83C6 02                ADD ESI,0x2
00401A1E    83F9 04                CMP ECX,0x4
00401A21  ^ 72 ED                  JB XCrack_Me.00401A10                                   ; 4次循环

注册码格式推测:??15pb?,先假设假的注册码:1215pb7

跟踪如下校验子程序:
00401A27    E8 14FDFFFF            CALL Crack_Me.00401740

//查看内存
00E4FB8C  0016C668  UNICODE "123456789215PB7"
00E4FB90  0016C738  UNICODE "1215PB7"

//关键代码摘录
0040178C    8B02            MOV EAX,DWORD PTR DS:[EDX]               ; 读取测试次数
0040178E    33F6            XOR ESI,ESI
00401790    8D0C43          LEA ECX,DWORD PTR DS:[EBX+EAX*2]         ; BUG代码,不应该随测试次数改变ECX值,作者可能会被取消参赛资格或者扣除一半分数

004017AF    E8 1C110000     CALL Crack_Me.004028D0                   ; 生成“123456789”跟注册码第2-7位连接
004017B4    8D76 FF         LEA ESI,DWORD PTR DS:[ESI-0x1]
004017B7    8BF8            MOV EDI,EAX
004017B9    8D0473          LEA EAX,DWORD PTR DS:[EBX+ESI*2]
004017BC    897D B8         MOV DWORD PTR SS:[EBP-0x48],EDI
004017BF    33F6            XOR ESI,ESI
004017C1    8945 B0         MOV DWORD PTR SS:[EBP-0x50],EAX
004017C4    66:3975 DC      CMP WORD PTR SS:[EBP-0x24],SI
004017C8    74 31           JE XCrack_Me.004017FB
004017CA    0FB738          MOVZX EDI,WORD PTR DS:[EAX]              ; 取注册码最后一位
004017CD    8D4D DC         LEA ECX,DWORD PTR SS:[EBP-0x24]
004017D0    83E7 01         AND EDI,0x1                              ; EDI=1
004017D3    66:8B01         MOV AX,WORD PTR DS:[ECX]                 ; 取123456789的每一位
004017D6    66:C1E8 02      SHR AX,0x2                               ; 密码表ASCII\4 忽略余数
004017DA    66:03C7         ADD AX,DI                                ; AX=C+1=D
004017DD    66:83F8 32      CMP AX,0x32                              ; 如果AX=0x32
004017E1    74 78           JE XCrack_Me.0040185B
004017E3    66:83F8 64      CMP AX,0x64                              ; 如果AX=0x32
004017E7    74 0F           JE XCrack_Me.004017F8
004017E9    46              INC ESI
004017EA    8D4D DC         LEA ECX,DWORD PTR SS:[EBP-0x24]
004017ED    8D1436          LEA EDX,DWORD PTR DS:[ESI+ESI]
004017F0    03CA            ADD ECX,EDX
004017F2    66:8339 00      CMP WORD PTR DS:[ECX],0x0                ; 比较下一位是否结尾
004017F6  ^ 75 DB           JNZ XCrack_Me.004017D3
004017F8    8B7D B8         MOV EDI,DWORD PTR SS:[EBP-0x48]
004017FB    8D4D DC         LEA ECX,DWORD PTR SS:[EBP-0x24]
004017FE    8BF3            MOV ESI,EBX
00401800    8BC1            MOV EAX,ECX
00401802    BA 31000000     MOV EDX,0x31                             ; EDX=0x31
00401807    2BF0            SUB ESI,EAX
00401809    0F1F            ???                                      ; 未知命令
0040180B    8000 00         ADD BYTE PTR DS:[EAX],0x0
0040180E    0000            ADD BYTE PTR DS:[EAX],AL
00401810    66:8B01         MOV AX,WORD PTR DS:[ECX]
00401813    66:3B040E       CMP AX,WORD PTR DS:[ESI+ECX]             ; 注册码第一位必须为“1”,第二位必须为“2”
00401817    75 42           JNZ XCrack_Me.0040185B
00401819    83C2 06         ADD EDX,0x6                              ; EDX=37
0040181C    83C1 02         ADD ECX,0x2
0040181F    83FA 39         CMP EDX,0x39                             ; 此处只比较注册码前两位
00401822  ^ 7E EC           JLE XCrack_Me.00401810
00401824    0FB74F 12       MOVZX ECX,WORD PTR DS:[EDI+0x12]
00401828    0FB703          MOVZX EAX,WORD PTR DS:[EBX]
0040182B    03C8            ADD ECX,EAX
0040182D    83F9 63         CMP ECX,0x63
00401830    75 29           JNZ XCrack_Me.0040185B
00401832    8B45 B4         MOV EAX,DWORD PTR SS:[EBP-0x4C]
00401835    0FB74F 0C       MOVZX ECX,WORD PTR DS:[EDI+0xC]          ; 把密码表0x37取出
00401839    0308            ADD ECX,DWORD PTR DS:[EAX]               ; 密码表0x37与第0x1次相加=0x38
0040183B    8B45 B0         MOV EAX,DWORD PTR SS:[EBP-0x50]
0040183E    0FB700          MOVZX EAX,WORD PTR DS:[EAX]              ; 读取注册码第7位,与0x38比较,说明第7位必须为“8”
00401841    3BC1            CMP EAX,ECX
00401843    75 16           JNZ XCrack_Me.0040185B

//IDA关键代码(摘录片段)

// 此处有BUG,不应取测试次数关联到取字符串起始位置和长度。
// 造成比赛规则无法满足,作者可能会被取消资格或扣除分数。
v8 = sub_4028D0((int)&v20, v2 + 2 * *(_DWORD *)v3);                                                

LABEL_12:
    v14 = &v20;
    v15 = 0x31;
    while ( *(_WORD *)v14 == *(_WORD *)((char *)v14 + v2 - (_DWORD)&v20) )
    {
      v15 += 6;
      v14 = (__int128 *)((char *)v14 + 2);
      if ( v15 > 0x39 )
      {
        if ( *(_WORD *)v2 + *((_WORD *)v8 + 9) == 0x63 && *(_WORD *)v17 == *(_DWORD *)v18 + *((_WORD *)v8 + 6) )
          return 1;
        return 0;
      }
    }

//IDA关键代码(摘录片段)
BOOL __fastcall sub_401870(int a1, int a2)
{
  v2 = a1;
  v3 = a2;
  v32 = a1;
  sub_4039D0(v33, 0, 54);
  v4 = &v34;
  v5 = 48;
  do
  {
    *(_WORD *)v4 = v5;
    v4 += 2;
    ++v5;
  }
  while ( v5 <= 57 );
  v6 = 97;
  v7 = (int)v33;
  do
  {
    *(_WORD *)v7 = v6;
    v7 += 2;
    ++v6;
  }
  while ( v6 <= 122 );
  v8 = 0;
  v9 = (int)v33;
  if ( v33[0] )
  {
    do
    {
      v9 += 2;
      ++v8;
    }
    while ( *(_WORD *)v9 );
  }
  v10 = 0;
  if ( v8 )
  {
    do
    {
      v11 = (unsigned __int16)v33[v10];
      if ( v11 >= 0x61 && v11 <= 0x7A )
        v33[v10] = v11 - 32;
      ++v10;
    }
    while ( v10 < v8 );
  }
  v12 = 0;
  v13 = v3;
  if ( v3 )
  {
    if ( *(_WORD *)v3 )
    {
      do
      {
        v13 += 2;
        ++v12;
      }
      while ( *(_WORD *)v13 );
    }
    v14 = 0;
    if ( v12 )
    {
      do
      {
        if ( v14 >= 2 )
        {
          if ( v14 >= 4 )
            *(_WORD *)(v3 + 2 * v14) ^= 0x42u;
          else
            *(_WORD *)(v3 + 2 * v14) ^= 0x50u;
        }
        else
        {
          *(_WORD *)(v3 + 2 * v14) ^= 0xFu;
        }
        ++v14;
      }
      while ( v14 < v12 );
    }
    v15 = 0;
    for ( i = v3; *(_WORD *)i; ++v15 )
      i += 2;
    v17 = 0;
    if ( v15 )
    {
      do
      {
        v18 = *(_WORD *)(v3 + 2 * v17);
        if ( v18 >= 0x61 && v18 <= 0x7A )
          *(_WORD *)(v3 + 2 * v17) = v18 - 0x20;
        ++v17;
      }
      while ( v17 < v15 );
    }
  }
  v19 = 0;
  _mm_storel_epi64((__m128i *)&v35, 0i64);
  v36 = 0;
  if ( *(_WORD *)v3 )
  {
    v20 = v33[0];
    v21 = &v35;
    v22 = v3;
    do
    {
      if ( v20 )
      {
        v23 = *(_WORD *)v22;
        v24 = v33;
        v25 = 0;
        while ( v23 != *v24 )
        {
          ++v25;
          v24 = &v33[v25];
          if ( !v33[v25] )
            goto LABEL_37;
        }
        *(_WORD *)v21 = v33[v25];
        v21 = (__int64 *)((char *)v21 + 2);
LABEL_37:
        v20 = v33[0];
      }
      ++v19;
      v22 = v3 + 2 * v19;
    }
    while ( *(_WORD *)(v3 + 2 * v19) );
    v2 = v32;
  }
  v26 = 0;
  v27 = &v35;
  if ( (_WORD)v35 )
  {
    do
    {
      v27 = (__int64 *)((char *)v27 + 2);
      ++v26;
    }
    while ( *(_WORD *)v27 );
    if ( v26 == 2 )
    {
      LODWORD(v35) = 0x350031;
      HIDWORD(v35) = &unk_420050;
      v28 = v3 + 4;
      v36 = 0;
      v29 = 0;
      while ( *((_WORD *)&v35 + v29) == *(_WORD *)v28 )
      {
        ++v29;
        v28 += 2;
        if ( v29 >= 4 )
        {
          if ( !sub_401740(v2, v3) )
            break;
          v31 = 0x40B;  //消息传递0x40B对应注册成功代码
          return PostMessageW(*(HWND *)(v2 + 4), 0x111u, v31, 0);
        }
      }
    }
  }
  v31 = 0x40A;
  return PostMessageW(*(HWND *)(v2 + 4), 0x111u, v31, 0);
}

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//