首页
社区
课程
招聘
[原创]2019_Redhat ChildRe PE逆向writeup
发表于: 2025-4-8 08:17 3403

[原创]2019_Redhat ChildRe PE逆向writeup

2025-4-8 08:17
3403

拖进IDA查看,主要功能在main函数中,直接F5

int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  _QWORD *v4; // rax
  const CHAR *v5; // r11
  __int64 v6; // r10
  int v7; // r9d
  const CHAR *v8; // r10
  __int64 v9; // rcx
  __int64 v10; // rax
  unsigned int v12; // ecx
  __int64 v13; // r9
  __int64 v14; // r8
  __int64 v15; // rdx
  _OWORD v16[2]; // [rsp+20h] [rbp-38h] BYREF
 
  memset(v16, 0, sizeof(v16));
  sub_140001080("%s", (const char *)v16);       // //输入31个字符
  v3 = -1LL;
  do
    ++v3;
  while ( *((_BYTE *)v16 + v3) );
 
 
 
 
  if ( v3 != 31 )                               // 如果输入不等于31个字符就一直循环
  {
    while ( 1 )
      Sleep(0x3E8u);
  }
  v4 = XMMI2_FP_Emulation(v16);                 // 这个函数的作用仅仅是申请0x18个字节的内存
  v5 = name;                                    // CHAR name[32] 初始值是0
  if ( v4 )
  {
    sub_1400015C0((unsigned __int8 *)v4[1]);
    sub_1400015C0(*(unsigned __int8 **)(v6 + 16));
    v7 = dword_1400057E0;
    v5[dword_1400057E0] = *v8;
    dword_1400057E0 = v7 + 1;
  }
  UnDecorateSymbolName(v5, outputString, 0x100u, 0);//  CHAR outputString[256]
  v9 = -1LL;
  do
    ++v9;
  while ( outputString[v9] );
  if ( v9 == 62 )
  {
    v12 = 0;
    v13 = 0LL;
    do
    {
      v14 = outputString[v13] % 23;
      if ( a1234567890Qwer[v14] != a46200860044218[v13] )
        _exit(v12);
      v15 = outputString[v13] / 23;
      if ( a1234567890Qwer[v15] != a55565653255552[v13] )
        _exit(v12 * v12);
      ++v12;
      ++v13;
    }
    while ( v12 < 0x3E );
    sub_140001020("flag{MD5(your input)}\n", v15, v14, v13);
    return 0;
  }
  else
  {
    v10 = sub_1400018A0(std::cout);
    std::ostream::operator<<(v10, sub_140001A60);
    return -1;
  }
} int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rax
  _QWORD *v4; // rax
  const CHAR *v5; // r11
  __int64 v6; // r10
  int v7; // r9d
  const CHAR *v8; // r10
  __int64 v9; // rcx
  __int64 v10; // rax
  unsigned int v12; // ecx
  __int64 v13; // r9
  __int64 v14; // r8
  __int64 v15; // rdx
  _OWORD v16[2]; // [rsp+20h] [rbp-38h] BYREF
 
  memset(v16, 0, sizeof(v16));
  sub_140001080("%s", (const char *)v16);       // //输入31个字符
  v3 = -1LL;
  do
    ++v3;
  while ( *((_BYTE *)v16 + v3) );
 
 
 
 
  if ( v3 != 31 )                               // 如果输入不等于31个字符就一直循环
  {
    while ( 1 )
      Sleep(0x3E8u);
  }
  v4 = XMMI2_FP_Emulation(v16);                 // 这个函数的作用仅仅是申请0x18个字节的内存
  v5 = name;                                    // CHAR name[32] 初始值是0
  if ( v4 )
  {
    sub_1400015C0((unsigned __int8 *)v4[1]);
    sub_1400015C0(*(unsigned __int8 **)(v6 + 16));
    v7 = dword_1400057E0;
    v5[dword_1400057E0] = *v8;
    dword_1400057E0 = v7 + 1;
  }
  UnDecorateSymbolName(v5, outputString, 0x100u, 0);//  CHAR outputString[256]
  v9 = -1LL;
  do
    ++v9;
  while ( outputString[v9] );
  if ( v9 == 62 )
  {
    v12 = 0;
    v13 = 0LL;
    do
    {
      v14 = outputString[v13] % 23;
      if ( a1234567890Qwer[v14] != a46200860044218[v13] )
        _exit(v12);
      v15 = outputString[v13] / 23;
      if ( a1234567890Qwer[v15] != a55565653255552[v13] )
        _exit(v12 * v12);
      ++v12;
      ++v13;
    }
    while ( v12 < 0x3E );
    sub_140001020("flag{MD5(your input)}\n", v15, v14, v13);
    return 0;
  }
  else
  {
    v10 = sub_1400018A0(std::cout);
    std::ostream::operator<<(v10, sub_140001A60);
    return -1;
  }
}

这里会验证输入的位数为31位,如果不是31 位则陷入死循环

  do
    ++v3;
  while ( *((_BYTE *)v16 + v3) );

这里会验证outputString,会将outputString的每一位除以23的整数和余数比对,如果不对程序退出

if ( v9 == 62 )
  {
    v12 = 0;
    v13 = 0LL;
    do
    {
      v14 = outputString[v13] % 23;
      if ( a1234567890Qwer[v14] != a46200860044218[v13] )
        _exit(v12);
      v15 = outputString[v13] / 23;
      if ( a1234567890Qwer[v15] != a55565653255552[v13] )
        _exit(v12 * v12);
      ++v12;
      ++v13;
    }while ( v12 < 0x3E );
    sub_140001020("flag{MD5(your input)}\n", v15, v14, v13);
    return 0;
  }

先算出outputString的值,代码如下:

int getout()
{
        char os[63] = { 0 };
        int v13 = 0;
        int v12 = 0;
        do
        {
                //计算v14 即余数部分
                for (int v14 = 0; v14 < sizeof(qwer); v14++)
                {
 
                        if (qwer[v14] == hex218[v13])
                        {
                                os[v13] = v14;
                        }
 
                }
                //计算整数部分
                for (int v15 = 0; v15 < sizeof(qwer); v15++)
                {
                        if (qwer[v15] == hex552[v13])
                        {
                                os[v13] += v15 * 23;
                        }
 
                }
                ++v12;
                ++v13;
 
        } while (v12 < 0x3E);
 
        //
        //char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)
        printf("outputString is %s\n", os);
 
        return 0;
}

算出outputString值为//char * __thiscall R0Pxx::My_Aut0_PWN(unsigned char *)

再往前看,outputString由v5通过

UnDecorateSymbolName(v5, outputString, 0x100u, 0);//  CHAR outputString[256]


获得,UnDecorateSymbolName去除函数修饰,v5即为去修饰之前的值

用以下代码获得v5的值

#include <iostream>
 
class R0Pxx {
public:
        R0Pxx() {
                My_Aut0_PWN((unsigned char*)"hello");
        }
private:
        char* __thiscall My_Aut0_PWN(unsigned char*);
};
 
char* __thiscall R0Pxx::My_Aut0_PWN(unsigned char*) {
        std::cout << __FUNCDNAME__ << std::endl;
 
        return 0;
}
 
int main()
{
        R0Pxx A;
 
        system("PAUSE");
        return 0;
}


 

算出v5的值 为    ?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z

 

再往前看,发现一段略显混乱的代码,这段代码用动态调试发现,其实是对输入的字符串顺序进行打乱

v4 = XMMI2_FP_Emulation(v16);                 // 这个函数的作用仅仅是申请0x18个字节的内存
  v5 = name;                                    // CHAR name[32] 初始值是0
  if ( v4 )
  {
    sub_1400015C0((unsigned __int8 *)v4[1]);
    sub_1400015C0(*(unsigned __int8 **)(v6 + 16));
    v7 = dword_1400057E0;
    v5[dword_1400057E0] = *v8;
    dword_1400057E0 = v7 + 1;
  }

比如我们自己的输入

abcdefghijklmnopqrstuvwxyz12345

顺序打乱之后变成

pqhrsidtujvwkebxylz1mf23n45ogca

 

那么就可以根据这个求得输入,代码如下

 

void rev()
{
        char a1[] = "abcdefghijklmnopqrstuvwxyz12345";
        char a2[] = "pqhrsidtujvwkebxylz1mf23n45ogca";
        char a3[] = "?My_Aut0_PWN@R0Pxx@@AAEPADPAE@Z";
        char a4[32] = "";
 
        for (int i = 0; i < 32; i++)
        {
                for (int j = 0; j < 32; j++)
                {
                        if (a2[j] == a1[i])
                        {
                                a4[i] = a3[j];
                        }
                }
        }
        printf("input is %s\n",a4);
        //输出flag input is Z0@tRAEyuP@xAAA?M_A0_WNPx@@EPDP
}


 

最终的的输入为Z0@tRAEyuP@xAAA?M_A0_WNPx@@EPDP,

根据最后的提示,需要进行MD5运算,

求出最后的flag{63b148e750fed3a33419168ac58083f5}



[培训]科锐逆向工程师培训第53期2025年7月8日开班!

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