红帽杯——childRE

查壳

在这里插入图片描述

拖进ida

main函数

signed __int64 main()
{
  signed __int64 v0; // rax
  __int64 v1; // rax
  const CHAR *v2; // r11
  __int64 v3; // r10
  __int64 v4; // r9
  const CHAR *v5; // r10
  signed __int64 v6; // rcx
  __int64 v7; // rax
  signed __int64 result; // rax
  unsigned int v9; // ecx
  __int64 v10; // r9
  int v11; // er10
  __int64 v12; // r8
  __int128 v13; // [rsp+20h] [rbp-38h]
  __int128 v14; // [rsp+30h] [rbp-28h]

  v13 = 0i64;
  v14 = 0i64;
  sub_140001080("%s", &v13);
  v0 = -1i64;
  do
    ++v0;
  while ( *((_BYTE *)&v13 + v0) );
  if ( v0 != 31 )
  {
    while ( 1 )
      Sleep(0x3E8u);
  }
  v1 = sub_140001280(&v13);
  v2 = name;
  if ( v1 )
  {
    sub_1400015C0(*(_QWORD *)(v1 + 8));
    sub_1400015C0(*(_QWORD *)(v3 + 16));
    v4 = dword_1400057E0;
    v2[v4] = *v5;
    dword_1400057E0 = v4 + 1;
  }
  UnDecorateSymbolName(v2, outputString, 0x100u, 0);
  v6 = -1i64;
  do
    ++v6;
  while ( outputString[v6] );
  if ( v6 == 62 )
  {
    v9 = 0;
    v10 = 0i64;
    do
    {
      v11 = outputString[v10];
      v12 = v11 % 23;
      if ( a1234567890Qwer[v12] != *(_BYTE *)(v10 + 5368722552i64) )
        _exit(v9);
      if ( a1234567890Qwer[v11 / 23] != *(_BYTE *)(v10 + 5368722488i64) )
        _exit(v9 * v9);
      ++v9;
      ++v10;
    }
    while ( v9 < 0x3E );
    sub_140001020("flag{MD5(your input)}\n", v11 / 23, v12, v10);
    result = 0i64;
  }
  else
  {
    v7 = sub_1400018A0(std::cout);
    std::basic_ostream<char,std::char_traits<char>>::operator<<(v7, sub_140001A60);
    result = 0xFFFFFFFFi64;
  }
  return result;
}

分析

观察之后,这道题需要先看下面的,思路倒着回去:

 sub_7FF6E48A1020("flag{MD5(your input)}\n", v11 / 23, v11 % 23, v10);

v11/23v11 % 23根据这里可以算出,

 v9 = 0;
    v10 = 0i64;
    do
    {
      v11 = outputString[v10];
      if ( a1234567890__Qw[v11 % 23] != *(_BYTE *)(v10 + 140698372945016i64) )
        _exit(v9);
      if ( a1234567890__Qw[v11 / 23] != *(_BYTE *)(v10 + 140698372944952i64) )
        _exit(v9 * v9);
      ++v9;
      ++v10;
    }

字符串a1234567890__Qw

unsigned char a1234567890__Qw[] =
{
  0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 
  0x2D, 0x3D, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 
  0x28, 0x29, 0x5F, 0x2B, 0x71, 0x77, 0x65, 0x72, 0x74, 0x79, 
  0x75, 0x69, 0x6F, 0x70, 0x5B, 0x5D, 0x51, 0x57, 0x45, 0x52, 
  0x54, 0x59, 0x55, 0x49, 0x4F, 0x50, 0x7B, 0x7D, 0x61, 0x73, 
  0x64, 0x66, 0x67, 0x68, 0x6A, 0x6B, 0x6C, 0x3B, 0x27, 0x41, 
  0x53, 0x44, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x3A, 0x22, 
  0x5A, 0x58, 0x43, 0x56, 0x42, 0x4E, 0x4D, 0x3C, 0x3E, 0x3F, 
  0x7A, 0x78, 0x63, 0x76, 0x62, 0x6E, 0x6D, 0x2C, 0x2E, 0x2F, 
  0x00
};

字符串v10 + 140698372945016i64

unsigned char ida_chars[] =
{
  0x35, 0x35, 0x35, 0x36, 0x35, 0x36, 0x35, 0x33, 0x32, 0x35, 
  0x35, 0x35, 0x35, 0x32, 0x32, 0x32, 0x35, 0x35, 0x36, 0x35, 
  0x35, 0x36, 0x35, 0x35, 0x35, 0x35, 0x32, 0x34, 0x33, 0x34, 
  0x36, 0x36, 0x33, 0x33, 0x34, 0x36, 0x35, 0x33, 0x36, 0x36, 
  0x33, 0x35, 0x34, 0x34, 0x34, 0x32, 0x36, 0x35, 0x36, 0x35, 
  0x35, 0x35, 0x35, 0x35, 0x32, 0x35, 0x35, 0x35, 0x35, 0x32, 
  0x32, 0x32, 0x00
};

字符串v10 + 140698372944952i64

unsigned char ida_chars[] =
{
  0x28, 0x5F, 0x40, 0x34, 0x36, 0x32, 0x30, 0x21, 0x30, 0x38, 
  0x21, 0x36, 0x5F, 0x30, 0x2A, 0x30, 0x34, 0x34, 0x32, 0x21, 
  0x40, 0x31, 0x38, 0x36, 0x25, 0x25, 0x30, 0x40, 0x33, 0x3D, 
  0x36, 0x36, 0x21, 0x21, 0x39, 0x37, 0x34, 0x2A, 0x33, 0x32, 
  0x33, 0x34, 0x3D, 0x26, 0x30, 0x5E, 0x33, 0x26, 0x31, 0x40, 
  0x3D, 0x26, 0x30, 0x39, 0x30, 0x38, 0x21, 0x36, 0x5F, 0x30, 
  0x2A, 0x26, 0x00
};

strchr()函数包含于头文件:#include<stdio.h>中;

函数原型为:char * strchr(char * str, char/int c);

函数功能为:在字符串str中寻找字符C第一次出现的位置,并返回其位置(地址指针),若失败则返回NULL;

根据代码反推出outputString为:

 char outputString[63] = {0};
    int v10 = 0, yu, shang;
    do {
        shang = strchr(a1234567890__Qw, ida_chars1[v10]) - a1234567890__Qw;
        yu = strchr(a1234567890__Qw, ida_chars2[v10])- a1234567890__Qw;
        outputString[v10] = shang * 23 + yu;
        v10++;
    } while (v10 < 62);
    printf("%s", outputString);

在这里插入图片描述

private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)

然后遇到了 UnDecorateSymbolName这个函数,然后才能求出v2
函数功能: 函数反修饰指定已修饰的 C++ 符号名

 UnDecorateSymbolName(v2, outputString, 0x100u, 0);

参考资料:

  1. c/c++函数名修饰规则
  2. UnDecorateSymbolName

接下来需要把private: char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)通过UnDecorateSymbolName转换为v2.

可以知道UnDecorateSymbolName第二个参数为未修饰的名字,第三个参数为长度,第四个参数为0表示完全修饰,第一个参数为输出地址

  1. 无论 __cdecl,__fastcall还是__stdcall调用方式,函数修饰都是以一个“?”开始,后面紧跟函数的名字。再后面是参数表的开始标识和依照参数类型代号拼出的参数表。
?My_Aut0_PWN
  1. 对于C++的类成员函数(其调用方式是thiscall),函数的名字修饰与非成员的C++函数稍有不同,首先就是在函数名字和参数表之间插入以“@”字 符引导的类名。
?My_Aut0_PWN@R0Pxx
  1. 其次是参数表的开始标识不同,公有(public)成员函数的标识是“@@QAE”,保护(protected)成员函数的标识是 “@@IAE”,私有(private)成员函数的标识是“@@AAE”,假设函数声明使用了constkeyword,则对应的标识应分别为“@@QBE”,“@@IBE”和“@@ABE”。
?My_Aut0_PWN@R0Pxx@@AAE
  1. 接下来就是添加参数了,先加入函数返回值参数,函数的返回值类型为char *
参数表的拼写代号如下:
X–void
D–char
E–unsigned char
F–short
H–int
I–unsigned int
J–long
K–unsigned long(DWORD)
M–float
N–double
_N–bool
U–struct
…
指针的方式有些特别。用PA表示指针,用PB表示const类型的指针。

char *的话也就是PAD

?My_Aut0_PWN@R0Pxx@@AAEPAD
  1. 然后是参数的类型unsigned char *,也就是PAE
?My_Aut0_PWN@R0Pxx@@AAEPADPAE
  1. 参数表后以“@Z”标识整个名字的结束。假设该函数无参数,则以“Z”标识结束。
?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z

在这里插入图片描述

输入ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ASCII码65 ~ 95

name也就是v2我们已经算出来了:

0x50, 0x51, 0x48, 0x52, 0x53, 0x49, 0x44, 0x54, 0x55, 0x4a, 0x56, 0x57, 0x4b, 0x45, 0x42, 0x58, 0x59, 0x4c, 0x5a, 0x5b, 0x4d, 0x46, 0x5c, 0x5d, 0x4e, 0x5e, 0x5f, 0x4f, 0x47, 0x43

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后到了这里,
在这里插入图片描述

v2也就是name,此时v4等于1E也就是30,然后v5对应的值是A,也就是65

0x50, 0x51, 0x48, 0x52, 0x53, 0x49, 0x44, 0x54, 0x55, 0x4a, 0x56, 0x57, 0x4b, 0x45, 0x42, 0x58, 0x59, 0x4c, 0x5a, 0x5b, 0x4d, 0x46, 0x5c, 0x5d, 0x4e, 0x5e, 0x5f, 0x4f, 0x47, 0x43,65

在这里插入图片描述

Z0@tRAEyuP@xAAA?M_A0_WNPx@@EPDP

在这里插入图片描述

flag{63b148e750fed3a33419168ac58083f5}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

寻梦&之璐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值