首页
社区
课程
招聘
[原创]南邮ctf逆向single
发表于: 2019-2-19 18:14 4042

[原创]南邮ctf逆向single

2019-2-19 18:14
4042
1.elf64位程序,直接使用ida进行分析,搜索关键字符串进行定位分析,将输入字符串经过一系列变换之后输出。详细的分析在下面
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char s; // [rsp+0h] [rbp-70h]
  unsigned __int64 v5; // [rsp+68h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  memset(&s, 0, 0x64uLL);
  puts("Input string:");
  scanf("%s", &s);
  sub_40070E(&s);//数据长度不能大于0x51,输入的数据大于47小于等于57
  sub_40078B(&s, (__int64)&unk_602080);
  sub_400AD4((__int64)&unk_602080);
  puts("Congratulations!");
  printf("flag{%s}", &s);
  return 0LL;
}
2.首先分析40070e函数:
size_t __fastcall sub_40070E(const char *a1)
{
  size_t result; // rax
  int i; // [rsp+1Ch] [rbp-14h]

  if ( strlen(a1) > 0x51 )//输入的长度不能大于0x51
    sub_4006F6();//这个函数是错误标志
  for ( i = 0; ; ++i )
  {
    result = strlen(a1);
    if ( i >= result )
      break;
    if ( a1[i] <= 47 || a1[i] > 57 )//输入的数据必须大于47和小于等于57,这里是进行数据范围的限制 0,1,2,3,4,5,6,7,8,9
      sub_4006F6();//错误标志
  }
  return result;
}
2.对40078b函数进行分析,传入unk_602080进行操作。
size_t __fastcall sub_40078B(const char *a1, __int64 a2)
{
  size_t result; // rax
  int i; // [rsp+1Ch] [rbp-14h]

  for ( i = 0; ; ++i )
  {
    result = strlen(a1);
    if ( i >= result )
      break;
    if ( a1[i] != 48 )                          //当a[i]=0的时候可以跳过相应的检测,所以对a2[i]=0的地方应该让a[i]=0
    {
      if ( !a1[i] || *(_BYTE *)(i + a2) )    //a2[i]!=0
        sub_4006F6();
      *(_BYTE *)(i + a2) = a1[i] - 48;//a1[i]-48存入602080处,将字符串转换成数字0,1,2,3,4,5,6,7,8
    }
  }
  return result;
}
4.函数400ad4里面又是另外的两个函数
unsigned __int64 __fastcall sub_400AD4(__int64 a1)
{
  sub_400833(a1);
  sub_4008FE(a1);
  return sub_4009C9(a1);
}
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1)
{
  signed int i; // [rsp+18h] [rbp-28h]
  signed int j; // [rsp+1Ch] [rbp-24h]
  signed int k; // [rsp+1Ch] [rbp-24h]
  char s[24]; // [rsp+20h] [rbp-20h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);                 //这里将数组s都初始化为零
    for ( j = 0; j <= 8; ++j )
      ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++
    for ( k = 1; k <= 9; ++k )
    {
      if ( s[k] != 1 )                                        //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9
        sub_4006F6();
    }
  }
  return __readfsqword(0x28u) ^ v6;
}
4008fe函数同理可得,用来判断每列都必须包含1-9

6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1)
{
  signed int i; // [rsp+1Ch] [rbp-34h]
  int j; // [rsp+20h] [rbp-30h]
  signed int l; // [rsp+20h] [rbp-30h]
  int k; // [rsp+24h] [rbp-2Ch]
  signed int v6; // [rsp+28h] [rbp-28h]
  signed int v7; // [rsp+2Ch] [rbp-24h]
  char s[24]; // [rsp+30h] [rbp-20h]
  unsigned __int64 v9; // [rsp+48h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  v6 = 3;
  v7 = 3;
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);
    for ( j = v6 - 3; j < v6; ++j )
    {
      for ( k = v7 - 3; k < v7; ++k )
        ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9.
    }
    for ( l = 1; l <= 9; ++l )
    {
      if ( s[l] != 1 )
        sub_4006F6();
    }
    if ( v7 == 9 )
    {
      v7 = 3;
      v6 += 3;
    }
    else
    {
      v7 += 3;
    }
  }
  return __readfsqword(0x28u) ^ v9;
}

总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案: flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char s; // [rsp+0h] [rbp-70h]
  unsigned __int64 v5; // [rsp+68h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  memset(&s, 0, 0x64uLL);
  puts("Input string:");
  scanf("%s", &s);
  sub_40070E(&s);//数据长度不能大于0x51,输入的数据大于47小于等于57
  sub_40078B(&s, (__int64)&unk_602080);
  sub_400AD4((__int64)&unk_602080);
  puts("Congratulations!");
  printf("flag{%s}", &s);
  return 0LL;
}
2.首先分析40070e函数:
size_t __fastcall sub_40070E(const char *a1)
{
  size_t result; // rax
  int i; // [rsp+1Ch] [rbp-14h]

  if ( strlen(a1) > 0x51 )//输入的长度不能大于0x51
    sub_4006F6();//这个函数是错误标志
  for ( i = 0; ; ++i )
  {
    result = strlen(a1);
    if ( i >= result )
      break;
    if ( a1[i] <= 47 || a1[i] > 57 )//输入的数据必须大于47和小于等于57,这里是进行数据范围的限制 0,1,2,3,4,5,6,7,8,9
      sub_4006F6();//错误标志
  }
  return result;
}
2.对40078b函数进行分析,传入unk_602080进行操作。
size_t __fastcall sub_40078B(const char *a1, __int64 a2)
{
  size_t result; // rax
  int i; // [rsp+1Ch] [rbp-14h]

  for ( i = 0; ; ++i )
  {
    result = strlen(a1);
    if ( i >= result )
      break;
    if ( a1[i] != 48 )                          //当a[i]=0的时候可以跳过相应的检测,所以对a2[i]=0的地方应该让a[i]=0
    {
      if ( !a1[i] || *(_BYTE *)(i + a2) )    //a2[i]!=0
        sub_4006F6();
      *(_BYTE *)(i + a2) = a1[i] - 48;//a1[i]-48存入602080处,将字符串转换成数字0,1,2,3,4,5,6,7,8
    }
  }
  return result;
}
4.函数400ad4里面又是另外的两个函数
unsigned __int64 __fastcall sub_400AD4(__int64 a1)
{
  sub_400833(a1);
  sub_4008FE(a1);
  return sub_4009C9(a1);
}
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1)
{
  signed int i; // [rsp+18h] [rbp-28h]
  signed int j; // [rsp+1Ch] [rbp-24h]
  signed int k; // [rsp+1Ch] [rbp-24h]
  char s[24]; // [rsp+20h] [rbp-20h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);                 //这里将数组s都初始化为零
    for ( j = 0; j <= 8; ++j )
      ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++
    for ( k = 1; k <= 9; ++k )
    {
      if ( s[k] != 1 )                                        //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9
        sub_4006F6();
    }
  }
  return __readfsqword(0x28u) ^ v6;
}
4008fe函数同理可得,用来判断每列都必须包含1-9

6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1)
{
  signed int i; // [rsp+1Ch] [rbp-34h]
  int j; // [rsp+20h] [rbp-30h]
  signed int l; // [rsp+20h] [rbp-30h]
  int k; // [rsp+24h] [rbp-2Ch]
  signed int v6; // [rsp+28h] [rbp-28h]
  signed int v7; // [rsp+2Ch] [rbp-24h]
  char s[24]; // [rsp+30h] [rbp-20h]
  unsigned __int64 v9; // [rsp+48h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  v6 = 3;
  v7 = 3;
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);
    for ( j = v6 - 3; j < v6; ++j )
    {
      for ( k = v7 - 3; k < v7; ++k )
        ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9.
    }
    for ( l = 1; l <= 9; ++l )
    {
      if ( s[l] != 1 )
        sub_4006F6();
    }
    if ( v7 == 9 )
    {
      v7 = 3;
      v6 += 3;
    }
    else
    {
      v7 += 3;
    }
  }
  return __readfsqword(0x28u) ^ v9;
}

总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案: flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件

size_t __fastcall sub_40070E(const char *a1)
{
  size_t result; // rax
  int i; // [rsp+1Ch] [rbp-14h]

  if ( strlen(a1) > 0x51 )//输入的长度不能大于0x51
    sub_4006F6();//这个函数是错误标志
  for ( i = 0; ; ++i )
  {
    result = strlen(a1);
    if ( i >= result )
      break;
    if ( a1[i] <= 47 || a1[i] > 57 )//输入的数据必须大于47和小于等于57,这里是进行数据范围的限制 0,1,2,3,4,5,6,7,8,9
      sub_4006F6();//错误标志
  }
  return result;
}
2.对40078b函数进行分析,传入unk_602080进行操作。
size_t __fastcall sub_40078B(const char *a1, __int64 a2)
{
  size_t result; // rax
  int i; // [rsp+1Ch] [rbp-14h]

  for ( i = 0; ; ++i )
  {
    result = strlen(a1);
    if ( i >= result )
      break;
    if ( a1[i] != 48 )                          //当a[i]=0的时候可以跳过相应的检测,所以对a2[i]=0的地方应该让a[i]=0
    {
      if ( !a1[i] || *(_BYTE *)(i + a2) )    //a2[i]!=0
        sub_4006F6();
      *(_BYTE *)(i + a2) = a1[i] - 48;//a1[i]-48存入602080处,将字符串转换成数字0,1,2,3,4,5,6,7,8
    }
  }
  return result;
}
4.函数400ad4里面又是另外的两个函数
unsigned __int64 __fastcall sub_400AD4(__int64 a1)
{
  sub_400833(a1);
  sub_4008FE(a1);
  return sub_4009C9(a1);
}
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1)
{
  signed int i; // [rsp+18h] [rbp-28h]
  signed int j; // [rsp+1Ch] [rbp-24h]
  signed int k; // [rsp+1Ch] [rbp-24h]
  char s[24]; // [rsp+20h] [rbp-20h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);                 //这里将数组s都初始化为零
    for ( j = 0; j <= 8; ++j )
      ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++
    for ( k = 1; k <= 9; ++k )
    {
      if ( s[k] != 1 )                                        //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9
        sub_4006F6();
    }
  }
  return __readfsqword(0x28u) ^ v6;
}
4008fe函数同理可得,用来判断每列都必须包含1-9

6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1)
{
  signed int i; // [rsp+1Ch] [rbp-34h]
  int j; // [rsp+20h] [rbp-30h]
  signed int l; // [rsp+20h] [rbp-30h]
  int k; // [rsp+24h] [rbp-2Ch]
  signed int v6; // [rsp+28h] [rbp-28h]
  signed int v7; // [rsp+2Ch] [rbp-24h]
  char s[24]; // [rsp+30h] [rbp-20h]
  unsigned __int64 v9; // [rsp+48h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  v6 = 3;
  v7 = 3;
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);
    for ( j = v6 - 3; j < v6; ++j )
    {
      for ( k = v7 - 3; k < v7; ++k )
        ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9.
    }
    for ( l = 1; l <= 9; ++l )
    {
      if ( s[l] != 1 )
        sub_4006F6();
    }
    if ( v7 == 9 )
    {
      v7 = 3;
      v6 += 3;
    }
    else
    {
      v7 += 3;
    }
  }
  return __readfsqword(0x28u) ^ v9;
}

总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案: flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件

size_t __fastcall sub_40078B(const char *a1, __int64 a2)
{
  size_t result; // rax
  int i; // [rsp+1Ch] [rbp-14h]

  for ( i = 0; ; ++i )
  {
    result = strlen(a1);
    if ( i >= result )
      break;
    if ( a1[i] != 48 )                          //当a[i]=0的时候可以跳过相应的检测,所以对a2[i]=0的地方应该让a[i]=0
    {
      if ( !a1[i] || *(_BYTE *)(i + a2) )    //a2[i]!=0
        sub_4006F6();
      *(_BYTE *)(i + a2) = a1[i] - 48;//a1[i]-48存入602080处,将字符串转换成数字0,1,2,3,4,5,6,7,8
    }
  }
  return result;
}
4.函数400ad4里面又是另外的两个函数
unsigned __int64 __fastcall sub_400AD4(__int64 a1)
{
  sub_400833(a1);
  sub_4008FE(a1);
  return sub_4009C9(a1);
}
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1)
{
  signed int i; // [rsp+18h] [rbp-28h]
  signed int j; // [rsp+1Ch] [rbp-24h]
  signed int k; // [rsp+1Ch] [rbp-24h]
  char s[24]; // [rsp+20h] [rbp-20h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);                 //这里将数组s都初始化为零
    for ( j = 0; j <= 8; ++j )
      ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++
    for ( k = 1; k <= 9; ++k )
    {
      if ( s[k] != 1 )                                        //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9
        sub_4006F6();
    }
  }
  return __readfsqword(0x28u) ^ v6;
}
4008fe函数同理可得,用来判断每列都必须包含1-9

6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1)
{
  signed int i; // [rsp+1Ch] [rbp-34h]
  int j; // [rsp+20h] [rbp-30h]
  signed int l; // [rsp+20h] [rbp-30h]
  int k; // [rsp+24h] [rbp-2Ch]
  signed int v6; // [rsp+28h] [rbp-28h]
  signed int v7; // [rsp+2Ch] [rbp-24h]
  char s[24]; // [rsp+30h] [rbp-20h]
  unsigned __int64 v9; // [rsp+48h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  v6 = 3;
  v7 = 3;
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);
    for ( j = v6 - 3; j < v6; ++j )
    {
      for ( k = v7 - 3; k < v7; ++k )
        ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9.
    }
    for ( l = 1; l <= 9; ++l )
    {
      if ( s[l] != 1 )
        sub_4006F6();
    }
    if ( v7 == 9 )
    {
      v7 = 3;
      v6 += 3;
    }
    else
    {
      v7 += 3;
    }
  }
  return __readfsqword(0x28u) ^ v9;
}

总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案: flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件

unsigned __int64 __fastcall sub_400AD4(__int64 a1)
{
  sub_400833(a1);
  sub_4008FE(a1);
  return sub_4009C9(a1);
}
5.分析400833函数,这段代码很有迷惑性,需要认真的分析
unsigned __int64 __fastcall sub_400833(__int64 a1)
{
  signed int i; // [rsp+18h] [rbp-28h]
  signed int j; // [rsp+1Ch] [rbp-24h]
  signed int k; // [rsp+1Ch] [rbp-24h]
  char s[24]; // [rsp+20h] [rbp-20h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);                 //这里将数组s都初始化为零
    for ( j = 0; j <= 8; ++j )
      ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++
    for ( k = 1; k <= 9; ++k )
    {
      if ( s[k] != 1 )                                        //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9
        sub_4006F6();
    }
  }
  return __readfsqword(0x28u) ^ v6;
}
4008fe函数同理可得,用来判断每列都必须包含1-9

6.下面对4009e9进行分析
unsigned __int64 __fastcall sub_4009C9(__int64 a1)
{
  signed int i; // [rsp+1Ch] [rbp-34h]
  int j; // [rsp+20h] [rbp-30h]
  signed int l; // [rsp+20h] [rbp-30h]
  int k; // [rsp+24h] [rbp-2Ch]
  signed int v6; // [rsp+28h] [rbp-28h]
  signed int v7; // [rsp+2Ch] [rbp-24h]
  char s[24]; // [rsp+30h] [rbp-20h]
  unsigned __int64 v9; // [rsp+48h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  v6 = 3;
  v7 = 3;
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);
    for ( j = v6 - 3; j < v6; ++j )
    {
      for ( k = v7 - 3; k < v7; ++k )
        ++s[*(unsigned __int8 *)(9 * j + k + a1)];//这里分为3*3的数组进行判断,每个3*3数组里面必须包含1-9.
    }
    for ( l = 1; l <= 9; ++l )
    {
      if ( s[l] != 1 )
        sub_4006F6();
    }
    if ( v7 == 9 )
    {
      v7 = 3;
      v6 += 3;
    }
    else
    {
      v7 += 3;
    }
  }
  return __readfsqword(0x28u) ^ v9;
}

总的来说,就是一个简单的数组游戏,9个3*3的数组组成一个9*9的大数组,每个小数组必须包含1-9,大数组每行必须包含1-9,每列必须包含1-9
最后求解处答案,原先初始的地方应该置为零
最后得到答案: flag{401095728057800001802040305000321589500479002923586000105060203300008950269750804}
解题代码见附件

unsigned __int64 __fastcall sub_400833(__int64 a1)
{
  signed int i; // [rsp+18h] [rbp-28h]
  signed int j; // [rsp+1Ch] [rbp-24h]
  signed int k; // [rsp+1Ch] [rbp-24h]
  char s[24]; // [rsp+20h] [rbp-20h]
  unsigned __int64 v6; // [rsp+38h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  for ( i = 0; i <= 8; ++i )
  {
    memset(s, 0, 0xAuLL);                 //这里将数组s都初始化为零
    for ( j = 0; j <= 8; ++j )
      ++s[*(unsigned __int8 *)(9 * i + j + a1)];//相当于s[a[i][j]]++
    for ( k = 1; k <= 9; ++k )
    {
      if ( s[k] != 1 )                                        //判断数组s的每一位,这里需要注意的是,由于初始化为零,所以a[i][j],应该把每一位都遍历到,所以a[i][j]应该包含1-9;每行都有1-9
        sub_4006F6();
    }
  }
  return __readfsqword(0x28u) ^ v6;
}
4008fe函数同理可得,用来判断每列都必须包含1-9

6.下面对4009e9进行分析

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

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