首页
社区
课程
招聘
[原创]2019看雪CTF 晋级赛Q1 第6题
发表于: 2019-3-23 16:53 3153

[原创]2019看雪CTF 晋级赛Q1 第6题

2019-3-23 16:53
3153

一、main函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ecx
  unsigned int v4; // ebx
  char *Str; // [esp+0h] [ebp-68h]
  char v7[4]; // [esp+10h] [ebp-58h]
  char constKey[32]; // [esp+20h] [ebp-48h]
  char inputSn; // [esp+40h] [ebp-28h]

  sub_404930(0x10u, v3, (int)Str);
  sub_4044B0();
  v4 = 0;
  *(_DWORD *)constKey = 0x7F79745E;
  *(_DWORD *)&constKey[4] = 0x2B704C63;
  *(_DWORD *)&constKey[8] = 0x612B5347;         // ^ty.cLp+GS+aGQ-GV(lGJ}y))AGS+ae
  *(_DWORD *)&constKey[12] = 0x472D5147;
  *(_DWORD *)&constKey[16] = 0x476C2856;
  *(_DWORD *)&constKey[20] = 695827786;
  *(_DWORD *)&constKey[24] = 1397178665;
  *(_DWORD *)&constKey[28] = 0x65612B;
  strcpy(v7, "Ansome_Is_Wrong");
  while ( v4 < strlen(constKey) )
  {
    constKey[v4] ^= 0x18u;                      // Flag{Th3_K3y_I5_N0t_Rea11Y_K3y}.
    ++v4;
  }
  puts("Please Input Your Key_ Now!");
  scanf("%s", &inputSn);
  if ( check1(&inputSn) )
  {
    check2(&inputSn);
    system("pause");
  }
  else
  {
    puts(v7);
  }
  return 0;
}
1、初始化一些常量
int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // ecx
  unsigned int v4; // ebx
  char *Str; // [esp+0h] [ebp-68h]
  char v7[4]; // [esp+10h] [ebp-58h]
  char constKey[32]; // [esp+20h] [ebp-48h]
  char inputSn; // [esp+40h] [ebp-28h]

  sub_404930(0x10u, v3, (int)Str);
  sub_4044B0();
  v4 = 0;
  *(_DWORD *)constKey = 0x7F79745E;
  *(_DWORD *)&constKey[4] = 0x2B704C63;
  *(_DWORD *)&constKey[8] = 0x612B5347;         // ^ty.cLp+GS+aGQ-GV(lGJ}y))AGS+ae
  *(_DWORD *)&constKey[12] = 0x472D5147;
  *(_DWORD *)&constKey[16] = 0x476C2856;
  *(_DWORD *)&constKey[20] = 695827786;
  *(_DWORD *)&constKey[24] = 1397178665;
  *(_DWORD *)&constKey[28] = 0x65612B;
  strcpy(v7, "Ansome_Is_Wrong");
  while ( v4 < strlen(constKey) )
  {
    constKey[v4] ^= 0x18u;                      // Flag{Th3_K3y_I5_N0t_Rea11Y_K3y}.
    ++v4;
  }
  puts("Please Input Your Key_ Now!");
  scanf("%s", &inputSn);
  if ( check1(&inputSn) )
  {
    check2(&inputSn);
    system("pause");
  }
  else
  {
    puts(v7);
  }
  return 0;
}
1、初始化一些常量
2、读取sn
3、调用check1进行校验,返回0,则退出。
4、调用check2进行校验。然后暂停。
二、check1函数
signed int __cdecl check1(char *inputSn)
{
  signed int index; // ecx
  signed int v2; // edx
  signed int result; // eax
  int v4; // [esp+0h] [ebp-38h]
  int v5; // [esp+4h] [ebp-34h]
  int v6; // [esp+8h] [ebp-30h]
  char v7; // [esp+Ch] [ebp-2Ch]
  int v8; // [esp+10h] [ebp-28h]
  int v9; // [esp+14h] [ebp-24h]
  int v10; // [esp+18h] [ebp-20h]
  int v11; // [esp+1Ch] [ebp-1Ch]
  int v12; // [esp+20h] [ebp-18h]

  index = 8;
  v2 = 0;
  v8 = 0x72756F59;
  v9 = 0x706E495F;
  v10 = 0x495F7475;
  v11 = 0x72575F73;
  v12 = 0x676E6F;
  v4 = 811151704;
  v5 = 0x74334E75;
  v6 = 0x64303047;
  v7 = 0;
  while ( *((_BYTE *)&v4 + v2) == inputSn[index] )// X1Y0uN3tG00d
  {
    ++v2;
    ++index;
    if ( v2 > 11 )
    {
      result = 1;
      if ( inputSn[20] == 'H' )
        return result;
      return 0;
    }
  }
  return 0;
}
1、初始化一些常量字符串,然后从输入sn第9个字符开始比较,一共比较11次。
signed int __cdecl check1(char *inputSn)
{
  signed int index; // ecx
  signed int v2; // edx
  signed int result; // eax
  int v4; // [esp+0h] [ebp-38h]
  int v5; // [esp+4h] [ebp-34h]
  int v6; // [esp+8h] [ebp-30h]
  char v7; // [esp+Ch] [ebp-2Ch]
  int v8; // [esp+10h] [ebp-28h]
  int v9; // [esp+14h] [ebp-24h]
  int v10; // [esp+18h] [ebp-20h]
  int v11; // [esp+1Ch] [ebp-1Ch]
  int v12; // [esp+20h] [ebp-18h]

  index = 8;
  v2 = 0;
  v8 = 0x72756F59;
  v9 = 0x706E495F;
  v10 = 0x495F7475;
  v11 = 0x72575F73;
  v12 = 0x676E6F;
  v4 = 811151704;
  v5 = 0x74334E75;
  v6 = 0x64303047;
  v7 = 0;
  while ( *((_BYTE *)&v4 + v2) == inputSn[index] )// X1Y0uN3tG00d
  {
    ++v2;
    ++index;
    if ( v2 > 11 )
    {
      result = 1;
      if ( inputSn[20] == 'H' )
        return result;
      return 0;
    }
  }
  return 0;
}
1、初始化一些常量字符串,然后从输入sn第9个字符开始比较,一共比较11次。
2、可知sn格式如下 xxxxxxxxX1Y0uN3tG00dxxxx
3、要求sn第20位置为字符'H',因此 sn为  xxxxxxxxX1Y0uN3tG00dHxxx
三、check2函数
int __cdecl check2(char *inputKey)
{
  char Dest; // [esp+8h] [ebp-10h]

  if ( strlen(inputKey) == 24 )
  {
    if ( check3(inputKey) )
    {
      inputKey[20] -= 'X';
      inputKey[21] -= 'F';
      inputKey[22] -= 3;
      inputKey[23] -= 'k';
      strcpy(&Dest, inputKey);
    }
  }
  else
  {
    printf("String Length is Wrong");
  }
  return 0;
}
int __cdecl check2(char *inputKey)
{
  char Dest; // [esp+8h] [ebp-10h]

  if ( strlen(inputKey) == 24 )
  {
    if ( check3(inputKey) )
    {
      inputKey[20] -= 'X';
      inputKey[21] -= 'F';
      inputKey[22] -= 3;
      inputKey[23] -= 'k';
      strcpy(&Dest, inputKey);
    }
  }
  else
  {
    printf("String Length is Wrong");
  }
  return 0;
}
1、可知sn长度为24,格式为: xxxxxxxxX1Y0uN3tG00dHxxx
2、调用check3函数。如果check3函数返回0,则表示sn不正确。
3、如果check3函数返回1 ,则对sn的后4位进行修改,同时将sn拷贝到一个局部变量中。
4、可以看出sn长度为24,而局部变量buf长度为0x14,因此会造成栈溢出,恰好sn后四个字节会覆盖返回地址。
四、check3函数
signed int __cdecl check3(char *inputKey)
{
  int v1; // ebx
  int v2; // ecx
  int v3; // esi
  signed int result; // eax

  changeFirst8(inputKey);
  v1 = g_first8Sn3 + 1000 * g_first8Sn0[0] + 100 * g_first8Sn1 + 10 * g_first8Sn2;
  v2 = g_first8Sn5 + 10 * g_first8Sn4;
  v3 = g_first8Sn7 + 10 * g_first8Sn6;
  if ( 2 * (v1 + v2) != 4040 || 3 * v2 / 2 + 100 * v3 != 115 )
    goto LABEL_2;
  result = 1;
  if ( v1 - 110 * v3 != 1900 )
  {
    printf("Key_Is_Wrong,Please_Input_Again!");
LABEL_2:
    result = 0;
  }
  return result;
}
调用 changeFirst8(inputKey);对前8个字符统一减去0x30。
可以看出check3是对前8个字符进行校验的。看起来是个类似方程组。
signed int __cdecl check3(char *inputKey)
{
  int v1; // ebx
  int v2; // ecx
  int v3; // esi
  signed int result; // eax

  changeFirst8(inputKey);
  v1 = g_first8Sn3 + 1000 * g_first8Sn0[0] + 100 * g_first8Sn1 + 10 * g_first8Sn2;
  v2 = g_first8Sn5 + 10 * g_first8Sn4;
  v3 = g_first8Sn7 + 10 * g_first8Sn6;
  if ( 2 * (v1 + v2) != 4040 || 3 * v2 / 2 + 100 * v3 != 115 )
    goto LABEL_2;
  result = 1;
  if ( v1 - 110 * v3 != 1900 )
  {
    printf("Key_Is_Wrong,Please_Input_Again!");
LABEL_2:
    result = 0;
  }
  return result;
}
调用 changeFirst8(inputKey);对前8个字符统一减去0x30。
可以看出check3是对前8个字符进行校验的。看起来是个类似方程组。

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2019-3-23 17:17 被ODPan编辑 ,原因:
收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//