buu [MRCTF2020]EasyCpp
阅读原文时间:2023年07月09日阅读:1

上次没写出,这次认真分析了一下,发现自己的调试水平也有了上涨,也看了一些C++逆向的文章,尤其是stl,发现C++的oop还是挺复杂,这题还没考啥虚函数的还行了。

一.拖入ida,找到主函数,还是挺容易的

int __cdecl main(int argc, const char **argv, const char **envp)
{
  double v3; // xmm0_8
  __int64 v4; // rax
  __int64 v5; // rcx
  __int64 v6; // r8
  __int64 v7; // r9
  __int64 v8; // rbx
  __int64 v9; // rax
  int v10; // ebx
  __int64 v11; // rax
  __int64 v12; // rax
  __int64 v13; // rax
  __int64 v14; // rax
  __int64 v15; // rax
  __int64 v16; // rax
  char v18; // [rsp+0h] [rbp-140h]
  __int64 v19; // [rsp+28h] [rbp-118h]
  __int64 v20; // [rsp+30h] [rbp-110h]
  int v21; // [rsp+3Ch] [rbp-104h]
  char v22; // [rsp+40h] [rbp-100h]
  char v23; // [rsp+60h] [rbp-E0h]
  char v24; // [rsp+90h] [rbp-B0h]
  char v25; // [rsp+AFh] [rbp-91h]
  char v26; // [rsp+B0h] [rbp-90h]
  char v27; // [rsp+DFh] [rbp-61h]
  char v28; // [rsp+E0h] [rbp-60h]
  int v29; // [rsp+104h] [rbp-3Ch]
  char *v30; // [rsp+108h] [rbp-38h]
  int *v31; // [rsp+110h] [rbp-30h]
  _DWORD *v32; // [rsp+118h] [rbp-28h]
  int *v33; // [rsp+120h] [rbp-20h]
  int i; // [rsp+128h] [rbp-18h]
  int v35; // [rsp+12Ch] [rbp-14h]

  v35 = 0;
  std::vector<int,std::allocator<int>>::vector(&v24, argv, envp);
  std::vector<bool,std::allocator<bool>>::vector(&v23);
  std::allocator<char>::allocator(&v25);
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v22, &unk_500E, &v25);
  std::allocator<char>::~allocator(&v25);
  v4 = std::operator<<<std::char_traits<char>>(&std::cout, "give me your key!");
  std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
  for ( i = 0; i <= 8; ++i )
  {
    std::istream::operator>>(&std::cin, &keys[i]);
    std::__cxx11::to_string((std::__cxx11 *)&v26, keys[i], (unsigned int)keys[i], v5, v6, v7);
    std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(&v22, &v26);
    std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v26);// 输入9组字符
  }
  v32 = keys;
  v33 = keys;
  v31 = (int *)&unk_83E4;
  while ( v33 != v31 )
  {
    v21 = *v33;
    std::vector<int,std::allocator<int>>::push_back(&v24, &v21);
    ++v33;
  }                                             // 将输入的字符串存入vector中
  v8 = std::vector<int,std::allocator<int>>::end(&v24);
  v9 = std::vector<int,std::allocator<int>>::begin(&v24);
  std::for_each<__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>,main::{lambda(int &)#1}>(// 每组异或1
    v8,
    v9,
    v8);
  v30 = &v24;
  v20 = std::vector<int,std::allocator<int>>::begin(&v24);
  v19 = std::vector<int,std::allocator<int>>::end(v30);// 类似头指针和尾指针
  while ( (unsigned __int8)__gnu_cxx::operator!=<int *,std::vector<int,std::allocator<int>>>(&v20, &v19) )
  {
    v29 = *(_DWORD *)__gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator*(&v20);
    std::allocator<char>::allocator(&v27);
    std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v18, &unk_500E, &v27);// 定义string
    std::allocator<char>::~allocator(&v27);
    depart(v29, (__int64)&v18, v3);             // 一波骚操作
    {lambda(std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>> &)#1}::operator()(
      (__int64)&func,                           // 一波替换
      (__int64)&v18);
    std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v28, &v18);// string复制
    v10 = (unsigned __int64){lambda(std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,int)#2}::operator()(
                              (__int64)&check,  // 比较函数
                              (__int64)&v28,
                              v35) ^ 1;
    std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v28);
    if ( (_BYTE)v10 )
    {
      v11 = std::operator<<<std::char_traits<char>>(&std::cout, "Wrong password!");
      std::ostream::operator<<(v11, &std::endl<char,std::char_traits<char>>);
      system("pause");
      exit(0);
    }
    ++v35;
    std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v18);
    __gnu_cxx::__normal_iterator<int *,std::vector<int,std::allocator<int>>>::operator++(&v20);// 头指针加一
  }
  v12 = std::operator<<<std::char_traits<char>>(&std::cout, "right!");
  std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>);
  v13 = std::operator<<<std::char_traits<char>>(&std::cout, "flag:MRCTF{md5(");
  v14 = std::operator<<<char,std::char_traits<char>,std::allocator<char>>(v13, &v22);
  v15 = std::operator<<<std::char_traits<char>>(v14, ")}");
  std::ostream::operator<<(v15, &std::endl<char,std::char_traits<char>>);
  v16 = std::operator<<<std::char_traits<char>>(
          &std::cout,
          "md5()->{32/upper case/put the string into the function and transform into md5 hash}");
  std::ostream::operator<<(v16, &std::endl<char,std::char_traits<char>>);
  system("pause");
  std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v22);
  std::vector<bool,std::allocator<bool>>::~vector(&v23);
  std::vector<int,std::allocator<int>>::~vector(&v24);
  return 0;
}

把我的分析都写在注释里了,发现这个程序大体的逻辑是,输入9个数字,每个数字异或1,之后,遍历每个数字,进过depart函数,再进行替换,flag里面包含是md5加密的输入的9个数字。这里比较坑的有几点:

1.

当时一直没找到这个函数在哪。。原来点击那个Lambda就可以进入函数中了,lambda之前也百度了一下,之前一道加密题也碰到过,不过是python的语法,C++里面这个和python里面意思大体一致,相当于一个匿名函数,在主函数体里面定义,()里面是指的捕捉对象,具体,用的时候,再回忆。

2.

depart函数,这个递归感觉会劝退很多人,这个函数意思就是将数字分解,最后将除数和最后一个数字拼接成字符串。

二.根据我们的思路逆向写出一个脚本,最后的数字找个在线网站直接加密下就好了。

strs=["=zqE=z=z=z","=lzzE","=ll=T=s=s=E","=zATT","=s=s=s=E=E=E","=EOll=E","=lE=T=E=E=E","=EsE=s=z","=AT=lE=ll"]
def replacediy(str):
    str=str.replace("O","0")
    str=str.replace("l","1")
    str=str.replace("z","2")
    str=str.replace("E","3")
    str=str.replace("A","4")
    str=str.replace("s","5")
    str=str.replace("G","6")
    str=str.replace("T","7")
    str=str.replace("B","8")
    str=str.replace("q","9")
    str=str.replace("="," ")
    return str
flag=""
for i in strs:
    tmp=replacediy(i).split(" ")[1:]
    print tmp
    sum=1
    for j in range(len(tmp)):
        sum*=int(tmp[j],10)
    sum^=1
    flag+=str(sum)
print flag