Mas0n
to be reverse engineer🐧
翻车鱼

DASCTF X BUUOJ 五月大联动 Reverse WriteUp

这次是我做过的最最最水的Re…奈何我一个只会re的只能干看着

PaperPlease

hint: 简单的字符串解密

ELF64文件

https://cdn.shi1011.cn/2021/05/b3d02e9ec6d9ffbd3a336b9e5f46ece0.png?imageMogr2/format/webp/interlace/0/quality/90|watermark/2/text/wqlNYXMwbg/font/bXN5aGJkLnR0Zg/fontsize/14/fill/IzMzMzMzMw/dissolve/80/gravity/southeast/dx/5/dy/5

不管三七二十一直接复制(假的)flag提交一波,果然是假的

老老实实分析

__int64 __fastcall subfhsadkhjbfleiowiuoyfgshjdvbsmnakl(__int64 a1, __int64 fakeFlag)
{
  int i; // [rsp+1Ch] [rbp-24h]
  char *dest; // [rsp+20h] [rbp-20h]
  char *s; // [rsp+28h] [rbp-18h]
​
  dest = (char *)malloc(0x80uLL);
  strcpy(dest, (const char *)(a1 + 7)); //掐头
  dest[strlen(dest) - 1] = 0; // 去尾
  s = (char *)malloc(0x80uLL);
  strcpy(s, (const char *)(fakeFlag + 7)); // 掐头
  s[strlen(s) - 1] = 0; // 去尾
  for ( i = 0; i < strlen(dest); ++i )
    dest[i] ^= *((_BYTE *)unk_6984657 + i); // 简单异或
  return unk_sa7ydu3jb432(dest, s); // 在.init 动态注册strcmp
}

虽然注释写出来了,但是下面还是分析下unk_sa7ydu3jb432,查看交叉引用可以看到这个函数

unsigned __int64 init()
{
  const char *v0; // rax
  char v2[15]; // [rsp+1h] [rbp-Fh] BYREF
​
  *(_QWORD *)&v2[7] = __readfsqword(0x28u);
  strcpy(v2, "a ?WcV");
  v0 = hafsddsfasfsdaevxcvdsfdfdscxvxcv(v2, (__int64)&unk_202A); // 简单字符串加密
  unk_sa7ydu3jb432 = (__int64 (__fastcall *)(_QWORD, _QWORD))dlsym((void *)0xFFFFFFFFFFFFFFFFLL, v0); // 注册函数strcmp
  return __readfsqword(0x28u) ^ *(_QWORD *)&v2[7];
}
const char *__fastcall hafsddsfasfsdaevxcvdsfdfdscxvxcv(const char *a1, __int64 a2)
{
  int i; // [rsp+1Ch] [rbp-14h]
​
  for ( i = 0; i < strlen(a1); ++i )
    a1[i] += *(_BYTE *)(i + a2);
  return a1;
}

c++跑一波就知道v0strcmp

最终subfhsadkhjbfleiowiuoyfgshjdvbsmnakl函数

__int64 __fastcall subfhsadkhjbfleiowiuoyfgshjdvbsmnakl(__int64 a1, __int64 fakeFlag)
{
  int i; // [rsp+1Ch] [rbp-24h]
  char *dest; // [rsp+20h] [rbp-20h]
  char *s; // [rsp+28h] [rbp-18h]
​
  dest = (char *)malloc(0x80uLL);
  strcpy(dest, (const char *)(a1 + 7)); //掐头
  dest[strlen(dest) - 1] = 0; // 去尾
  s = (char *)malloc(0x80uLL);
  strcpy(s, (const char *)(fakeFlag + 7)); // 掐头
  s[strlen(s) - 1] = 0; // 去尾
  for ( i = 0; i < strlen(dest); ++i )
    dest[i] ^= *((_BYTE *)unk_6984657 + i); // 简单异或
  return strcmp(dest, s); // 在.init 动态注册strcmp
}

放c++里跑一遍完事

#include <iostream>
​
std::string hafsddsfasfsdaevxcvdsfdfdscxvxcv(std::string a1, std::string a2)
{
    int i; // [rsp+1Ch] [rbp-14h]
​
    for ( i = 0; i < a1.length(); ++i )
        a1[i] += (int)a2[i];
    return a1;
}
​
int main() {
    using namespace std;
​
    // string str = hafsddsfasfsdaevxcvdsfdfdscxvxcv("a ?WcV", "\x12\x54\x33\x0C\x0A\x1A");
    // cout << str << endl;
    unsigned char unk_2008[32] = {
            0x56, 0x05, 0x53, 0x52, 0x04, 0x03, 0x53, 0x54, 0x04, 0x0B, 0x53, 0x51, 0x06, 0x06, 0x0F, 0x55,
            0x05, 0x5B, 0x03, 0x56, 0x0E, 0x07, 0x57, 0x0E, 0x01, 0x0D, 0x56, 0x00, 0x04, 0x06, 0x0A, 0x5D
    };
    string fakeflag = "5c715207e3abed7dfb7c8ea9c82d0e29";
    for (int i = 0; i < fakeflag.length(); ++i) {
        fakeflag[i] ^= unk_2008[i];
    }
    cout << fakeflag;
    return 0;
}

end

upx壳,脱壳之后放IDA,定位到主函数sub_40238F

int sub_40238F()
{
  int v0; // eax
  int v1; // eax
  int v2; // eax
  int v4[22]; // [esp+18h] [ebp-47Ch] BYREF
  char Buffer[19]; // [esp+71h] [ebp-423h] BYREF
  char v6[16]; // [esp+84h] [ebp-410h] BYREF
  int v7; // [esp+94h] [ebp-400h] BYREF
  int v8[250]; // [esp+98h] [ebp-3FCh] BYREF
  int v9; // [esp+480h] [ebp-14h]
  int v10; // [esp+484h] [ebp-10h]
  int v11; // [esp+488h] [ebp-Ch]
  int i; // [esp+48Ch] [ebp-8h]
​
  sub_402B50();
  i = 0;
  v11 = 0;
  memset(v8, 0, sizeof(v8));
  v9 = 0;
  do
  {
    while ( 1 )
    {
      printf("Please input:");
      scanf("%d", &v7);
      v0 = i++;
      v8[v0] = v7;
      switch ( v7 )
      {
        case 2: // == 's'
          v11 += 7;
          break;
        case 8: // == 'w'
          v11 -= 7;
          break;
        case 6: // == 'd'
          ++v11;
          break;
        case 4: // == 'a'
          --v11;
          break;
        default:
          exit(1);
      }
      if ( !dword_406060[v11] ) 
        exit(1);
      if ( dword_406060[v11] != 1 )
        break;
      printf("continue");
    }
  }
  while ( dword_406060[v11] != 35 ); // 出口
  while ( v8[v9] )
  {
    v1 = v9++;
    v10 += v8[v1];
  }
  sprintf(Buffer, "%d", v10); // int2str
  printf("%s", Buffer); // "80"
​
  // md5
  sub_401410(v4); // md5 init 
  v2 = strlen(Buffer); 
  sub_401451((int)v4, Buffer, v2); // md5 update
  sub_401582(v4, (int)v6); // md5 digest
    
  printf("congratulation");
  printf("the flag is {");
  for ( i = 0; i <= 15; ++i )
    printf("%02x", (unsigned __int8)v6[i]);
  putchar(125); // '}'
  return 0;
}

一看就是7*8迷宫… 方向控制为2,8,6,4,要求是到达0x00000023即35处

dword_406060dump出来

走一遍

https://cdn.shi1011.cn/2021/05/12408edc6591f71a0a9ba5c7564f84f8.png?imageMogr2/format/webp/interlace/0/quality/90|watermark/2/text/wqlNYXMwbg/font/bXN5aGJkLnR0Zg/fontsize/14/fill/IzMzMzMzMw/dissolve/80/gravity/southeast/dx/5/dy/5

2622668662224422666

然后其实不需要分析后面的函数就能出flag,不过还是看了下,就是标准的md5,即 md5(80),这点在最后输出flag时也得到的证实

https://cdn.shi1011.cn/2021/05/d167d4438aa7e0cb4ef66d2832d83bc5.png?imageMogr2/format/webp/interlace/0/quality/90|watermark/2/text/wqlNYXMwbg/font/bXN5aGJkLnR0Zg/fontsize/14/fill/IzMzMzMzMw/dissolve/80/gravity/southeast/dx/5/dy/5
本文链接:https://blog.shi1011.cn/ctf/1472
本文采用 CC BY-NC-SA 4.0 Unported 协议进行许可

Mas0n

文章作者

发表回复

textsms
account_circle
email

翻车鱼

DASCTF X BUUOJ 五月大联动 Reverse WriteUp
这次是我做过的最最最水的Re...奈何我一个只会re的只能干看着 PaperPlease hint: 简单的字符串解密 ELF64文件 不管三七二十一直接复制(假的)flag提交一波,果然是假的 …
扫描二维码继续阅读
2021-05-29