[HUBUCTF 2022 新生赛]simple_RE

发布时间 2023-07-15 18:53:43作者: Zer0o

[HUBUCTF 2022 新生赛]simple_RE

查壳,64位

找main函数,F5查看伪代码,简单分析一下

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+24h] [rbp-44h] BYREF
  void *Buf1; // [rsp+28h] [rbp-40h] BYREF
  char v6[56]; // [rsp+30h] [rbp-38h] BYREF

  sub_401770(argc, argv, envp);
  printf("please input the flag:");
  scanf("%s", v6);                              // v6是flag
  Buf1 = 0i64;                                  // 初始化Buf1
  sub_401570(v6, &Buf1, &v4);                   // v6进行base64编码,但是不是根据A-Z,...,而是根据这串字符编码qvEJAfHmUYjBac+u8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD
  if ( !memcmp(Buf1, a5mc58bphliax7j, v4) )     // 对这串字符串"5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8=="进行微改变的base64解码,即得flag
    printf("\nsuccess!");
  else
    printf("\nfailed!");
  if ( Buf1 )
    free(Buf1);
  return 0;
}

v6是flag,经过sub_401570函数加密,得到a5mc58bphliax7j对应的加密后的值,即加密后的flag值

 

这里的重点就是sub_401570函数,我们需要了解经过怎么样的加密,接下来我们点进去看看

sub_401570函数

__int64 __fastcall sub_401570(const char *a1, _QWORD *a2, int *a3)
{
  int v6; // r15d
  int v7; // r12d
  int v8; // r13d
  __int64 v9; // r14
  _BYTE *v10; // rax
  _BYTE *v11; // r9
  __int64 v12; // r8
  char v13; // cl
  char v14; // r11
  char v15; // r10
  __int64 result; // rax

  v6 = strlen(a1);
  v7 = v6 % 3;
  if ( v6 % 3 )
  {
    v8 = 4 * (v6 / 3) + 4;
    v9 = v8;
    v10 = malloc(v8 + 1i64);
    v10[v8] = 0;
    if ( v6 <= 0 )
      goto LABEL_5;
  }
  else
  {
    v8 = 4 * (v6 / 3);
    v9 = v8;
    v10 = malloc(v8 + 1i64);
    v10[v8] = 0;
    if ( v6 <= 0 )
      goto LABEL_8;
  }
  v11 = v10;
  v12 = 0i64;
  do
  {
    v11 += 4;
    v13 = a1[v12];
    *(v11 - 4) = aQvejafhmuyjbac[v13 >> 2];
    v14 = a1[v12 + 1];
    *(v11 - 3) = aQvejafhmuyjbac[(v14 >> 4) | (16 * v13) & 0x30];
    v15 = a1[v12 + 2];
    v12 += 3i64;
    *(v11 - 2) = aQvejafhmuyjbac[(v15 >> 6) | (4 * v14) & 0x3C];
    *(v11 - 1) = aQvejafhmuyjbac[v15 & 0x3F];
  }
  while ( v6 > (int)v12 );
LABEL_5:
  if ( v7 == 1 )
  {
    v10[v9 - 2] = 61;
    v10[v9 - 1] = 61;
  }
  else if ( v7 == 2 )
  {
    v10[v9 - 1] = 61;
  }
LABEL_8:
  *a2 = v10;
  result = 0i64;
  *a3 = v8;
  return result;
}

看不懂不要紧,为了这个,我专门用一天时间消化base64编码与解码的原理,链接如下:base64详解 - Zer0o - 博客园 (cnblogs.com)

看完,就能对base64原理了解的八九不离十了

 

这段代码一看移位运算,或运算,与运算,与base64编码一样,只不过base64是根据ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/编码,而这里修改为aQvejafhmuyjbac对应的字符串

双击进入,知道这个base64是根据这串字符串编码的qvEJAfHmUYjBac+u8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD,而不是ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

知道原理了,返回main函数

简单捋一下,就是将flag进行变异的base64编码,编码结果为a5mc58bphliax7j对应的数据,即5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8==

写出源码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char base64CharsArr[] = "qvEJAfHmUYjBac+u8Ph5n9Od17FrICL/X0gVtM4Qk6T2z3wNSsyoebilxWKGZpRD";

void base64decode(char str[]) {
    int length = strlen(str);
    int padding = 0;

    // 计算填充字符数量
    if (str[length - 1] == '=') {
        padding++;
        if (str[length - 2] == '=')
            padding++;
    }

    // 计算解码后的字符数量
    int decodedLength = (length * 3) / 4 - padding;

    // 分配存储解码结果的内存
    char* decodedStr = (char*)malloc(decodedLength + 1);

    int outIndex = 0;
    for (int i = 0; i < length; i += 4) {
        char char1 = -1, char2 = -1, char3 = -1, char4 = -1;

        // 查找每个字符在Base64字符集中的索引
        for (int j = 0; j < 64; j++) {
            if (base64CharsArr[j] == str[i]) {
                char1 = j;
                break;
            }
        }

        for (int j = 0; j < 64; j++) {
            if (base64CharsArr[j] == str[i + 1]) {
                char2 = j;
                break;
            }
        }

        for (int j = 0; j < 64; j++) {
            if (base64CharsArr[j] == str[i + 2]) {
                 char3 = j;
                break;
            }
        }

        for (int j = 0; j < 64; j++) {
            if (base64CharsArr[j] == str[i + 3]) {
                 char4 = j;
                break;
            }
        }

        // 解码并存储结果
        decodedStr[outIndex++] = (char1 << 2) | ((char2 & 0x30) >> 4);
        if (char3 != -1)
            decodedStr[outIndex++] = ((char2 & 0xf) << 4) | ((char3 & 0x3c) >> 2);
        if (char4 != -1)
            decodedStr[outIndex++] = ((char3 & 0x3) << 6) | char4;
    }

    // 添加字符串结束符
    decodedStr[decodedLength] = '\0';

    printf("Decoded string: %s\n", decodedStr);

    // 释放内存
    free(decodedStr);
}

int main() {
    char str[100]="5Mc58bPHLiAx7J8ocJIlaVUxaJvMcoYMaoPMaOfg15c475tscHfM/8=="; // Example base64 encoded string
    base64decode(str);
    return 0;
}

 

 

flag:NSSCTF{a8d4347722800e72e34e1aba3fe914ae}