首页
社区
课程
招聘
[原创] 看雪ctf 207 第三题-CrackMe
2017-10-30 11:06 2911

[原创] 看雪ctf 207 第三题-CrackMe

aqs 活跃值
5
2017-10-30 11:06
2911
 

第三道题目出的有点问题,导致了问题多解的情况,有点忙,正规的思路还没有来的及分析,只能写一下非预期的做法了 = =

基本逻辑

 

运行效果如上,要求输入一个序列号即输入ok,错误则什么都不输出
主要函数如下

int __stdcall main_logic_434EF0(HWND hDlg, int a2, int a3, int a4)
{
  int v4; // edx@1
  int v5; // eax@14
  int v6; // edx@14
  int v7; // ecx@14
  int v8; // edx@14
  int v9; // edx@14
  int v10; // ST0C_4@17
  CHAR *v11; // esi@17
  int v12; // eax@17
  int v13; // eax@19
  int v14; // edx@19
  int v15; // ecx@19
  signed int v16; // eax@20
  int v17; // ST0C_4@22
  int v18; // ST08_4@22
  int v19; // eax@22
  int v20; // edx@22
  int v21; // ecx@22
  int v23; // [esp+0h] [ebp-1A4Ch]@14
  int v24; // [esp+4h] [ebp-1A48h]@22
  int v25; // [esp+8h] [ebp-1A44h]@22
  int v26; // [esp+Ch] [ebp-1A40h]@1
  int i; // [esp+1C4h] [ebp-1888h]@14
  char hex_string[1032]; // [esp+1D0h] [ebp-187Ch]@16
  char v29[40]; // [esp+5D8h] [ebp-1474h]@14
  int v30; // [esp+600h] [ebp-144Ch]@14
  char v31; // [esp+60Ch] [ebp-1440h]@14
  char v32; // [esp+60Dh] [ebp-143Fh]@14
  char bdecode_2; // [esp+A14h] [ebp-1038h]@14
  char v34; // [esp+A15h] [ebp-1037h]@14
  char bdecode_1; // [esp+E1Ch] [ebp-C30h]@14
  char v36; // [esp+E1Dh] [ebp-C2Fh]@14
  CHAR String; // [esp+1224h] [ebp-828h]@14
  char v38; // [esp+1225h] [ebp-827h]@14
  int v39; // [esp+162Ch] [ebp-420h]@14
  char v40; // [esp+1638h] [ebp-414h]@1
  char v41; // [esp+1639h] [ebp-413h]@1
  int v42; // [esp+1A40h] [ebp-Ch]@1
  unsigned int v43; // [esp+1A48h] [ebp-4h]@1
  int savedregs; // [esp+1A4Ch] [ebp+0h]@1

  memset(&v26, 0xCCu, 0x1A40u);
  v43 = (unsigned int)&savedregs ^ dword_49B344;
  v42 = 0;
  v40 = 0;
  memset_42D5E6((int)&v41, 0, 0x3FF);
  v26 = a2;
  if ( a2 == 0x10 )
    ExitProcess(0); //anti
  if ( v26 == 0x110 )
  {
    v42 = sub_42D4F1();
    if ( v42 == 1 )
      ExitProcess(0);//anti
    v42 = 0;
    v42 = sub_42E428();
    if ( v42 == 1 )
      ExitProcess(0);
    v42 = 0;
    v42 = sub_42D825();
    if ( v42 == 1 )
      ExitProcess(0);//anti
    sub_42D14F(hDlg, 1);
    goto LABEL_21;
  }
  if ( v26 != 0x111 )
  {
LABEL_21:
    v16 = 0;
    goto LABEL_22;
  }
  v26 = (unsigned __int16)a3;
  if ( (unsigned __int16)a3 == 0x3EA )
  {
    String = 0;
    memset_42D5E6((int)&v38, 0, 0x3FF);
    bdecode_1 = 0;
    memset_42D5E6((int)&v36, 0, 0x3FF);
    v5 = GetDlgItemTextA(hDlg, 0x3E9, &String, 0x401); //string you input
    v39 = sub_42DE51(v7, v6, &v23 == &v23, v5);
    bdecode_2 = 0;
    memset_42D5E6((int)&v34, 0, 0x3FF);
    base64_decode_42D267(v8, (int)&String, 0x400, (int)&bdecode_1);// base64decode
    v31 = 0;
    memset_42D5E6((int)&v32, 0, 0x3FF);
    base64_decode_42D267(v9, (int)&bdecode_1, 0x400, (int)&bdecode_2);
    sub_42D96A((int)&bdecode_2, (int)&v31, 0x400);
    v30 = 3;
    sub_42DA78((int)&bdecode_2, 3, (int)v29);   
    for ( i = 0; i < 0x20; ++i )
      sub_42DF05((int)&hex_string[2 * i], "%02x", v29[i]);
    v10 = strlen_42D794(hex_string);
    v11 = &String + strlen_42D794(&String);
    v12 = strlen_42D794(hex_string);
    if ( !check1_42DB27((int)hex_string, (int)&v11[-v12], v10) )// 6 ==
    {
      sub_42D0B4();
      if ( (unsigned __int8)check2_42D9AB((int)&unk_49B000, (int)&v31) == 1 )
      {
        v13 = MessageBoxA(0, "ok", "CrackMe", 0);
        sub_42DE51(v15, v14, &v23 == &v23, v13);
      }
    }
  }
  v16 = 1;
LABEL_22:
  v17 = v4;
  v18 = v16;
  sub_42D65E((int)&savedregs, (int)&dword_435250);
  v19 = sub_42D1E5(v18, v17, (unsigned int)&savedregs ^ v43, v25, v23, v24, v26);
  return sub_42DE51(v21, v20, 1, v19);
}

程序加上了很多反调试,一言不合就 exitprocess
基本逻辑是

  • 首先获取用户的输入 ==> GetDlgItemTextA
  • 然后对用户的输入进行两次base64decode(这是后面调试的时候发现的)
  • 程序会生成一个字符串
    183920f00e15a0433ee3a8fc90dd9ac164c4142ccf63ca189a8f645ec96ff8de
  • 接下来就是两个 check ,这两个check过了就会 弹框 ok

两个check 函数

check1

    for ( i = 0; i < 0x20; ++i )
      sub_42DF05((int)&hex_string[2 * i], "%02x", v29[i]);
    v10 = strlen_42D794(hex_string);
    v11 = &String + strlen_42D794(&String);
    v12 = strlen_42D794(hex_string);
    if ( !check1_42DB27((int)hex_string, (int)&v11[-v12], v10) )
    {

string 是程序生成的字符串,是固定的, v11 是我们输入的字符串,v12,v10 是两个串的长度,所以输入的参数是
( 程序串,输入串-len(程序串),len(程序串))

 

check1 的代码有点长, 不过调试的时候发现 a3 也就是上面 v10 的长度是固定的0x40 ,所以会直接跑到 default那里执行

int __cdecl sub_43AF50(int a1, int a2, int a3)
{
  int result; // eax@11
  int v4; // [esp+0h] [ebp-28h]@20
  int v5; // [esp+4h] [ebp-24h]@15
  int v6; // [esp+8h] [ebp-20h]@13
  int v7; // [esp+Ch] [ebp-1Ch]@7
  int v8; // [esp+10h] [ebp-18h]@5
  int v9; // [esp+14h] [ebp-14h]@3
  int v10; // [esp+1Ch] [ebp-Ch]@2
  int v11; // [esp+1Ch] [ebp-Ch]@4
  int v12; // [esp+1Ch] [ebp-Ch]@6
  int v13; // [esp+1Ch] [ebp-Ch]@12
  int v14; // [esp+1Ch] [ebp-Ch]@14
  int v15; // [esp+1Ch] [ebp-Ch]@19

  switch ( a3 )
  {
    case 0:
      result = 0;
      break;
    case 1:
      result = equal_43B180((unsigned __int8 *)a1, (unsigned __int8 *)a2);
      break;
    case 2:
      v15 = equal_43B180((unsigned __int8 *)a1, (unsigned __int8 *)a2);
      if ( v15 )
        v4 = v15;
      else
        v4 = equal_43B180((unsigned __int8 *)(a1 + 1), (unsigned __int8 *)(a2 + 1));
      result = v4;
      break;
    case 3:
      v13 = equal_43B180((unsigned __int8 *)a1, (unsigned __int8 *)a2);
      if ( v13 )
      {
        v6 = v13;
      }
      else
      {
        v14 = equal_43B180((unsigned __int8 *)(a1 + 1), (unsigned __int8 *)(a2 + 1));
        if ( v14 )
          v5 = v14;
        else
          v5 = equal_43B180((unsigned __int8 *)(a1 + 2), (unsigned __int8 *)(a2 + 2));
        v6 = v5;
      }
      result = v6;
      break;
    case 4:
      v10 = equal_43B180((unsigned __int8 *)a1, (unsigned __int8 *)a2);
      if ( v10 )
      {
        v9 = v10;
      }
      else
      {
        v11 = equal_43B180((unsigned __int8 *)(a1 + 1), (unsigned __int8 *)(a2 + 1));
        if ( v11 )
        {
          v8 = v11;
        }
        else
        {
          v12 = equal_43B180((unsigned __int8 *)(a1 + 2), (unsigned __int8 *)(a2 + 2));
          if ( v12 )
            v7 = v12;
          else
            v7 = equal_43B180((unsigned __int8 *)(a1 + 3), (unsigned __int8 *)(a2 + 3));
          v8 = v7;
        }
        v9 = v8;
      }
      result = v9;
      break;
    default:
      result = sub_43B1F0(a1, a2, a3);
      break;
  }
  return result;
}

sub_43B1f0 如下
也是一堆的 case什么的, 不过前面是进行字符串的比较,如果字符串一样就可以过,跳到check2,虽然不知道是怎么回事,但是总之是进入第二个check了,先看看第二个check吧

  while ( a3 >= 0x20 )
  {
    v6 = equal4_43BB60((unsigned __int8 *)a1, (unsigned __int8 *)a2);
    if ( v6 )
      return v6;
    v7 = equal4_43BB60((unsigned __int8 *)(a1 + 4), (unsigned __int8 *)(a2 + 4));
    if ( v7 )
      return v7;
    v8 = equal4_43BB60((unsigned __int8 *)(a1 + 8), (unsigned __int8 *)(a2 + 8));
    if ( v8 )
      return v8;
    v9 = equal4_43BB60((unsigned __int8 *)(a1 + 0xC), (unsigned __int8 *)(a2 + 0xC));
    if ( v9 )
      return v9;
    v10 = equal4_43BB60((unsigned __int8 *)(a1 + 0x10), (unsigned __int8 *)(a2 + 0x10));
    if ( v10 )
      return v10;
    v11 = equal4_43BB60((unsigned __int8 *)(a1 + 0x14), (unsigned __int8 *)(a2 + 0x14));
    if ( v11 )
      return v11;
    v12 = equal4_43BB60((unsigned __int8 *)(a1 + 0x18), (unsigned __int8 *)(a2 + 0x18));
    if ( v12 )
      return v12;
    v13 = equal4_43BB60((unsigned __int8 *)(a1 + 0x1C), (unsigned __int8 *)(a2 + 0x1C));
    if ( v13 )
      return v13;
    a1 += 0x20;
    a2 += 0x20;
    a3 -= 0x20;
  }
......

check2

check2 的输入是 一堆 01, base64decode(base64decode(输入串))

 

进去看看,发现程序有点复杂呀

 while ( 1 )
  {
    v3 = string;
    input_chr = (char)*string;
    if ( input_chr == 0x20 )
      break;
    if ( v13 != 8 || v12 != 3 )
    {
      input_chr = (char)*string;
      if ( input_chr == 'z' )
      {
        v3 = (_BYTE *)(v10 + v12);
        if ( v10 + v12 >= 0xA )
        {
          LOBYTE(v3) = 0;
          return sub_42DE51(input_chr, v2, 1, (int)v3);
        }
        if ( !*(_DWORD *)(unknow + 0x28 * (v10 + v12) + 4 * v13) )
          v12 += v10;
      }
      if ( *string == 'l' && v8 + v13 < 0xA )
      {
        v3 = (_BYTE *)(unknow + 0x28 * v12);
        input_chr = v8 + v13;
        if ( *(_DWORD *)&v3[4 * (v8 + v13)] )
        {
          LOBYTE(v3) = 0;
          return sub_42DE51(input_chr, v2, 1, (int)v3);
        }
        *(_DWORD *)(unknow + 0x28 * v12 + 4 * v13) = 4;
        v13 += v8;
      }
      if ( *string == 'q' && ((v11 + v12) & 0x80000000) == 0 )
      {
        v3 = (_BYTE *)(unknow + 0x28 * (v11 + v12));
        input_chr = v13;
        if ( *(_DWORD *)&v3[4 * v13] )
        {
          LOBYTE(v3) = 0;
          return sub_42DE51(input_chr, v2, 1, (int)v3);
        }
        *(_DWORD *)(unknow + 0x28 * v12 + 4 * v13) = 4;
        v12 += v11;
      }
      if ( *string == 'p' && ((v9 + v13) & 0x80000000) == 0 )
      {
        v3 = (_BYTE *)(unknow + 0x28 * v12);
        input_chr = v9 + v13;
        if ( *(_DWORD *)&v3[4 * (v9 + v13)] )
        {
          LOBYTE(v3) = 0;
          return sub_42DE51(input_chr, v2, 1, (int)v3);
        }
        v13 += v9;
      }
    }
    ++string;
  }
  LOBYTE(v3) = 1;
  return sub_42DE51(input_chr, v2, 1, (int)v3);
}

一个byte 一个byte的取 base64decode(base64decode(输入串))
然后后面进行一堆的操作和判断,return 0,不过最前面的地方有一个
input_chr==0x20 就break 了,直接就跳到了后面 return 1
所以这里只要可以构造出一个 0x20 出来就赢了
最后构造
II183920f00e15a0433ee3a8fc90dd9ac164c4142ccf63ca189a8f645ec96ff8de
可以直接过
呃,好吧,这怎么看都不是flag的样子
发现有一些类似莫斯点码的东西,不知道有什么用

 

嘛,暂时就先到这里吧,期待大佬 正规writeup = =


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回