首页
论坛
课程
招聘
[原创]2019看雪CTF 晋级赛Q3 签到题:乱世鬼雄 by 心学
2019-9-18 19:23 3451

[原创]2019看雪CTF 晋级赛Q3 签到题:乱世鬼雄 by 心学

htg 活跃值
2
2019-9-18 19:23
3451
这是一道简单的根据【 用户名 】和【序列号】校验是否符合要求。
其逻辑是:【用户名】与【序列号】异或后,计算MD5值,并与内置的16字节数据进行比较,相等则通过。
知道处理过程后,进行计算
KCTF对应的序列号是:8DA79EF3CED2B8FCCFB2BBB6CBEFBCE1

一、Python计算代码:

# -*- coding: UTF-8 -*-
import binascii
print('输入信息:')
username_Str = 'KCTF'
builtin_HexStr = 'C6E4CAB5CED2B8FCCFB2BBB6CBEFBCE1'
print('username:\t%s'%(username_Str))
print('builtinHex:\t%s'%(builtin_HexStr))

print('\n转换成字节流')
username_Bytes = str.encode(username_Str)
builtin_Bytes = binascii.unhexlify(builtin_HexStr)
print('username:\t%s'%(username_Bytes))
print('builtinHex:\t%s'%(builtin_Bytes))

print('\n转换成整数:小端获取')
username_hex =  int.from_bytes(username_Bytes, byteorder = 'little')
builtin_Hex =  int.from_bytes(builtin_Bytes, byteorder = 'little')
print('username:\t%02X'%(username_hex))
print('builtinHex:\t%02X'%(builtin_Hex))

print('\n异或操作:此结果是字节反转的。主要是为了进行异或操作的对齐')
xorAB = username_hex^builtin_Hex
print('xor:\t\t%02X'%(xorAB))

print('\n转换成字节流')
SN_Re_HexStr = '%02X'%(xorAB)
SN_Re_Bytes = binascii.unhexlify(SN_Re_HexStr)
print('序列号字节流:\t%s'%(SN_Re_Bytes))

print('\n转换成整数:小端获取')
SN =  int.from_bytes(SN_Re_Bytes, byteorder = 'little')
print('序列号:\t\t%02X'%(SN))
#8DA79EF3CED2B8FCCFB2BBB6CBEFBCE1

二、内置一个结构

00000000 MyMD5           struc ; (sizeof=0x58, mappedto_60)
00000000                                         ; XREF: sub_8819D0/r
00000000 unkownUInt      dd ?                    ; XREF: sub_8819D0+191/w
00000000                                         ; sub_8819D0+1DB/r ...
00000004 unkownInt       dd ?                    ; XREF: sub_8819D0+19D/w
00000008 vectorOrMD5Value __m128i ?              ; XREF: sub_8819D0+1A9/w
00000008                                         ; sub_8819D0+1B4/w ...
00000018 value           __m128i ?
00000028 unkownM128I     __m128i 3 dup(?)
00000058 MyMD5           ends

三、主要代码

主函数是sub_8819D0()
int sub_8819D0()
{
  unsigned int v0; // kr00_4
  signed int i; // esi
  unsigned __int8 v2; // cl
  char v3; // dl
  signed int j; // esi
  __int128 *serialNoStrByHexRef; // edi
  int v6; // eax
  unsigned int v7; // ecx
  int v8; // eax
  unsigned int v9; // esi
  bool v10; // cf
  char *v11; // ecx
  unsigned int k; // edx
  __int8 v13; // al
  __int8 *v14; // ecx
  unsigned int m; // edx
  char v16; // al
  __int128 *v17; // ecx
  char *v18; // edx
  unsigned int v19; // esi
  const char *strTips; // esi
  MyMD5 myClassA; // [esp+8h] [ebp-E8h]
  __m128i dataByusernameXorserialNoHex; // [esp+60h] [ebp-90h]
  __int128 v24; // [esp+70h] [ebp-80h]
  __int128 serialNoStr; // [esp+80h] [ebp-70h]
  __int128 v26; // [esp+90h] [ebp-60h]
  char v27; // [esp+A0h] [ebp-50h]
  __int128 serialNoStrByHex; // [esp+B0h] [ebp-40h]
  __int128 v29; // [esp+C0h] [ebp-30h]
  char v30; // [esp+D0h] [ebp-20h]

  PrintFunc("【请输入您的用户名与序列号】\n");
  PrintFunc("请输入用户名:");
  GetInputStr("%16s", &username, 17);
  v0 = strlen((const char *)&username);
  sub_8829C0((char *)&username + v0, 0, 16 - v0);
  PrintFunc("请输入序列号:");
  v27 = 0;
  serialNoStr = 0i64;
  v26 = 0i64;
  serialNoStrByHex = 0i64;
  v29 = 0i64;
  v30 = 0;
  serialNoHex = 0i64;
  GetInputStr("%33s", &serialNoStr, 33);        // serialNoStr:输入的16进制字符,是一个字符串
  i = 0;
  do
  {
    v2 = *((_BYTE *)&serialNoStr + 2 * i);
    v3 = v2 - 55;
    if ( v2 <= 0x39u )
      v3 = *((_BYTE *)&serialNoStr + 2 * i);
    *((_BYTE *)&serialNoHex + i) = *((_BYTE *)&serialNoStr + 2 * i + 1)
                                 + 16 * v3
                                 - (*((_BYTE *)&serialNoStr + 2 * i + 1) > 0x39u ? 55 : 48);
    ++i;
  }
  while ( i < 16 );                             // 将serialNoStr转换成对应的Hex数据,比如字符串"1234",会转换成0x1234
  j = 0;
  serialNoStrByHexRef = &serialNoStrByHex;
  do
  {
    sub_881990((int)serialNoStrByHexRef, "%02X", *((unsigned __int8 *)&serialNoHex + j++));
    serialNoStrByHexRef = (__int128 *)((char *)serialNoStrByHexRef + 2);
  }
  while ( j < 16 );                             // 将serialNoyHex转换成对应的String数据,比如字符串0x1234,会转换成"1234"
  v6 = strcmp((const char *)&serialNoStr, (const char *)&serialNoStrByHex);// 检测:输入的序列号,应该是16进制字符
  if ( v6 )
    v6 = -(v6 < 0) | 1;
  if ( v6 )
  {
    PrintFunc(" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
    PrintFunc("【请输入合法序列号!】\n\n");
  }
  else                                          // 计算【用户名】与【序列号】异或后的MD5值,然后与内置的16字节数据进行比较。
  {
    myClassA.unkownUInt = 0;
    myClassA.unkownInt = 0;
    myClassA.vectorOrMD5Value.m128i_i64[0] = 0xEFCDAB8967452301i64;// MD5的标记值:初始向量
    dataByusernameXorserialNoHex = _mm_xor_si128((__m128i)username, (__m128i)serialNoHex);// 将a和b进行按位异或
    myClassA.vectorOrMD5Value.m128i_i64[1] = 0x1032547698BADCFEi64;
    v24 = 0i64;
    sub_881000((int)&dataByusernameXorserialNoHex, (unsigned int *)&myClassA, 0x10u);
    v7 = ((unsigned int)myClassA.unkownUInt >> 3) & 0x3F;
    v8 = 0x78 - v7;
    v9 = 0x38 - v7;
    v10 = v7 < 0x38;
    v11 = (char *)&myClassA.unkownUInt + 1;
    if ( !v10 )
      v9 = v8;
    k = 0;
    do
    {
      v13 = *(v11 - 1);
      v11 += 4;
      dataByusernameXorserialNoHex.m128i_i8[k] = v13;
      dataByusernameXorserialNoHex.m128i_i8[k + 1] = *(v11 - 4);
      dataByusernameXorserialNoHex.m128i_i8[k + 2] = *(v11 - 3);
      dataByusernameXorserialNoHex.m128i_i8[k + 3] = *(v11 - 2);
      k += 4;
    }
    while ( k < 8 );
    sub_881000((int)&unk_8A08C0, (unsigned int *)&myClassA, v9);
    sub_881000((int)&dataByusernameXorserialNoHex, (unsigned int *)&myClassA, 8u);// 调用MD5进行计算。
    v14 = &myClassA.vectorOrMD5Value.m128i_i8[1];// md5Value--->v14
    m = 0;
    do
    {
      v16 = *(v14 - 1);
      v14 += 4;
      *((_BYTE *)&v24 + m) = v16;
      *((_BYTE *)&v24 + m + 1) = *(v14 - 4);
      *((_BYTE *)&v24 + m + 2) = *(v14 - 3);
      *((_BYTE *)&v24 + m + 3) = *(v14 - 2);
      m += 4;
    }
    while ( m < 0x10 );                         // 该循环功能是:直接拷贝16字节:V14 ----> v24
    v17 = &v24;                                 // v24---->v17:结果就是md5Value--->v17
    v18 = &constBuiltinHex;                     // 这是一个常量
    v19 = 12;
    while ( *(_DWORD *)v17 == *(_DWORD *)v18 )  // 比较是否相等,不等则退出
    {
      v17 = (__int128 *)((char *)v17 + 4);
      v18 += 4;
      v10 = v19 < 4;
      v19 -= 4;
      if ( v10 )
      {
        strTips = "【验证正确!】\n\n";
        goto LABEL_22;
      }
    }
    strTips = "【验证错误!】\n\n";
LABEL_22:
    PrintFunc(" * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
    PrintFunc(strTips);
  }
  sub_88507E("\npause\n");
  return 0;
}

unsigned int __usercall sub_881000@<eax>(int a1@<edx>, unsigned int *a2@<ecx>, unsigned int a3)
{
  unsigned int v3; // ebx
  #59 *myClassA; // esi
  unsigned int v5; // edx
  unsigned int v6; // edi
  unsigned int v7; // ecx
  unsigned int i; // esi
  unsigned int *v10; // [esp+Ch] [ebp-8h]
  int v11; // [esp+10h] [ebp-4h]
  unsigned int v12; // [esp+1Ch] [ebp+8h]
  _DWORD *v13; // [esp+1Ch] [ebp+8h]

  v3 = a3;
  myClassA = (#59 *)a2;
  v11 = a1;
  v10 = a2;
  v5 = (*a2 >> 3) & 0x3F;
  v6 = 64 - v5;
  v7 = *a2 + 8 * a3;
  v12 = v10[1];
  *v10 = v7;
  if ( v7 < 8 * v3 )
    *((_DWORD *)myClassA + 1) = ++v12;
  *((_DWORD *)myClassA + 1) = v12 + (v3 >> 29);
  if ( v3 < v6 )
  {
    v6 = 0;
  }
  else
  {
    sub_897B30((unsigned int)myClassA + v5 + 24, v11, 64 - v5);
    v13 = (_DWORD *)((char *)myClassA + 8);
    GetMD5((_DWORD *)myClassA + 2, (int)myClassA + 24);// 计算MD5值。
    for ( i = v6 + 64; i <= v3; v6 += 64 )
    {
      GetMD5(v13, i + v11 - 64);
      i += 64;
    }
    myClassA = (#59 *)v10;
    v5 = 0;
  }
  return sub_897B30((unsigned int)myClassA + v5 + 24, v6 + v11, v3 - v6);
}


[注意] 招人!base上海,课程运营、市场多个坑位等你投递!

收藏
点赞0
打赏
分享
最新回复 (5)
雪    币: 63
活跃值: 活跃值 (84)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
郝若宁 活跃值 2019-10-7 12:33
2
0
你好,有个问题想请教一下:


看大佬提供的反汇编的代码有中文字符也显示了相关函数调用,为什么我这个就是&unk_41E728这个样子呢。是不是ida pro有相关的设置,导致我这个显示不出来。请大佬看看是哪儿需要设置一下呢。感谢!
雪    币: 2749
活跃值: 活跃值 (88)
能力值: ( LV12,RANK:214 )
在线值:
发帖
回帖
粉丝
htg 活跃值 2 2019-10-8 19:20
3
0
unk_41E728点进去,然后按a键盘,它会转换成字符形式
雪    币: 63
活跃值: 活跃值 (84)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
郝若宁 活跃值 2019-10-9 17:42
4
0
感谢解答。还有一个问题:
如下图所示,这个函数的调用怎么能显示出来呢。

雪    币: 701
活跃值: 活跃值 (1682)
能力值: ( LV9,RANK:176 )
在线值:
发帖
回帖
粉丝
nevinhappy 活跃值 2 2019-10-9 18:03
5
0
郝若宁 感谢解答。还有一个问题:如下图所示,这个函数的调用怎么能显示出来呢。
动手去跟一下上在的几个函数,你就会发现它是啥功能,然后在IDA里按N给函数改个名字,帮助自己记忆,名字可以随便起,但是是自己改的,不是IDA自动 识别的,有一些库如果在IDA的FLIRT库里,有可能识别出来,但是业务代码基本是没有识别的。
雪    币: 63
活跃值: 活跃值 (84)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
郝若宁 活跃值 2019-10-11 11:13
6
0
嗯嗯,感谢大佬解答
游客
登录 | 注册 方可回帖
返回