BUUCTF reverse wp 41 - 50

[UTCTF2020]basic-re

BUUCTF reverse wp 41 - 50_第1张图片

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char input; // [rsp+Fh] [rbp-21h] BYREF
  double op1; // [rsp+10h] [rbp-20h] BYREF
  double op2; // [rsp+18h] [rbp-18h] BYREF
  unsigned __int64 v7; // [rsp+28h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  printf("Enter an operator (+, -, *,): ");
  __isoc99_scanf("%c", &input);
  printf("Enter two operands: ");
  __isoc99_scanf("%lf %lf", &op1, &op2);
  if ( input == '/' )
  {
    printf("%.1lf / %.1lf = %.1lf", op1, op2, op1 / op2);
    return 0;
  }
  if ( input > '/' )
    goto label_failed;
  if ( input == '-' )
  {
    printf("%.1lf - %.1lf = %.1lf", op1, op2, op1 - op2);
    return 0;
  }
  if ( input > '-' )
    goto label_failed;
  if ( input == '*' )
  {
    printf("%.1lf * %.1lf = %.1lf", op1, op2, op1 * op2);
    return 0;
  }
  if ( input != '+' )
  {
label_failed:
    printf("Error! operator is not correct");
    return 0;
  }
  printf("%.1lf + %.1lf = %.1lf", op1, op2, op1 + op2);
  return 0;
}

看了下主逻辑, 跟flag没啥关系, 直接shift+f12

BUUCTF reverse wp 41 - 50_第2张图片

[ACTF新生赛2020]Oruga

BUUCTF reverse wp 41 - 50_第3张图片

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  int i; // [rsp+0h] [rbp-40h]
  char s1[6]; // [rsp+4h] [rbp-3Ch] BYREF
  char s2[6]; // [rsp+Ah] [rbp-36h] BYREF
  char s[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v8; // [rsp+38h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  memset(s, 0, 0x19uLL);
  printf("Tell me the flag:");
  scanf("%s", s);
  strcpy(s2, "actf{");
  for ( i = 0; i <= 4; ++i )
    s1[i] = s[i];
  s1[5] = 0;
  if ( !strcmp(s1, s2) )
  {
    if ( (unsigned __int8)checker(s) )
      printf("That's True Flag!");
    else
      printf("don't stop trying...");
    return 0LL;
  }
  else
  {
    printf("Format false!");
    return 0LL;
  }
}

_BOOL8 __fastcall checker(__int64 flag)
{
  int v2; // [rsp+Ch] [rbp-Ch]
  int index; // [rsp+10h] [rbp-8h]
  int v4; // [rsp+14h] [rbp-4h]

  v2 = 0;
  index = 5;
  v4 = 0;
  while ( data[v2] != 33 )
  {
    v2 -= v4;                                   // - last move
    if ( *(_BYTE *)(index + flag) != 'W' || v4 == -16 )// up
    {
      if ( *(_BYTE *)(index + flag) != 'E' || v4 == 1 )// right
      {
        if ( *(_BYTE *)(index + flag) != 'M' || v4 == 16 )// down
        {
          if ( *(_BYTE *)(index + flag) != 'J' || v4 == -1 )// left
            return 0LL;
          v4 = -1;
        }
        else
        {
          v4 = 16;
        }
      }
      else
      {
        v4 = 1;
      }
    }
    else
    {
      v4 = -16;
    }
    ++index;
    while ( !data[v2] )                         // move until not 0
    {
      if ( v4 == -1 && (v2 & 0xF) == 0 )
        return 0LL;
      if ( v4 == 1 && v2 % 16 == 15 )
        return 0LL;
      if ( v4 == 16 && (unsigned int)(v2 - 240) <= 0xF )
        return 0LL;
      if ( v4 == -16 && (unsigned int)(v2 + 15) <= 0x1E )
        return 0LL;
      v2 += v4;
    }
  }
  return *(_BYTE *)(index + flag) == '}';
}

隐约中看出是一个迷宫, 长度为16, 移动方式为4个方向, 用python处理一下迷宫数据

maps = [
    0,   0,   0,   0,  35,   0,   0,   0,   0,   0, 
    0,   0,  35,  35,  35,  35,   0,   0,   0,  35, 
   35,   0,   0,   0,  79,  79,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
   79,  79,   0,  80,  80,   0,   0,   0,   0,   0, 
    0,  76,   0,  79,  79,   0,  79,  79,   0,  80, 
   80,   0,   0,   0,   0,   0,   0,  76,   0,  79, 
   79,   0,  79,  79,   0,  80,   0,   0,   0,   0, 
    0,   0,  76,  76,   0,  79,  79,   0,   0,   0, 
    0,  80,   0,   0,   0,   0,   0,   0,   0,   0, 
    0,  79,  79,   0,   0,   0,   0,  80,   0,   0, 
    0,   0,  35,   0,   0,   0,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
   35,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
   77,  77,  77,   0,   0,   0,  35,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,   0,  77,  77,  77, 
    0,   0,   0,   0,  69,  69,   0,   0,   0,  48, 
    0,  77,   0,  77,   0,  77,   0,   0,   0,   0, 
   69,   0,   0,   0,   0,   0,   0,   0,   0,   0, 
    0,   0,   0,   0,   0,   0,  69,  69,  84,  84, 
   84,  73,   0,  77,   0,  77,   0,  77,   0,   0, 
    0,   0,  69,   0,   0,  84,   0,  73,   0,  77, 
    0,  77,   0,  77,   0,   0,   0,   0,  69,   0, 
    0,  84,   0,  73,   0,  77,   0,  77,   0,  77, 
   33,   0,   0,   0,  69,  69
]

cnt = 0
for i in maps:
    cnt += 1
    if i != 0:
        print(chr(i), end=' ')
    else: print(i, end=' ')
    if cnt % 16 == 0: 
        print()

'''
0 0 0 0 # 0 0 0 0 0 0 0 # # # # 
0 0 0 # # 0 0 0 O O 0 0 0 0 0 0
0 0 0 0 0 0 0 0 O O 0 P P 0 0 0
0 0 0 L 0 O O 0 O O 0 P P 0 0 0
0 0 0 L 0 O O 0 O O 0 P 0 0 0 0
0 0 L L 0 O O 0 0 0 0 P 0 0 0 0
0 0 0 0 0 O O 0 0 0 0 P 0 0 0 0
# 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 # 0 0 0
0 0 0 0 0 0 M M M 0 0 0 # 0 0 0
0 0 0 0 0 0 0 M M M 0 0 0 0 E E
0 0 0 0 0 M 0 M 0 M 0 0 0 0 E 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 E E
T T T I 0 M 0 M 0 M 0 0 0 0 E 0
0 T 0 I 0 M 0 M 0 M 0 0 0 0 E 0
0 T 0 I 0 M 0 M 0 M ! 0 0 0 E E
'''

从左上角出发到!位置结束, 不要碰到边界否则return 0, 碰到非0数据之前会停下
W ↑; E →; M ↓; J ←

盯着地图走一走就是flag

[BJDCTF2020]BJD hamburger competition

Unity游戏逆向, dnSpy打开\BJD hamburger competition_Data\Managed\Assembly-CSharp.dll进行分析, 定位到关键字符串BJDCTF{

	// Token: 0x0600000C RID: 12 RVA: 0x000021C8 File Offset: 0x000003C8
	public void Spawn()
	{
		FruitSpawner component = GameObject.FindWithTag("GameController").GetComponent<FruitSpawner>();
		if (component)
		{
			if (this.audioSources.Length != 0)
			{
				this.audioSources[Random.Range(0, this.audioSources.Length)].Play();
			}
			component.Spawn(this.toSpawn);
			string name = this.toSpawn.name;
			if (name == "汉堡底" && Init.spawnCount == 0)
			{
				Init.secret += 997;
			}
			else if (name == "鸭屁股")
			{
				Init.secret -= 127;
			}
			else if (name == "胡罗贝")
			{
				Init.secret *= 3;
			}
			else if (name == "臭豆腐")
			{
				Init.secret ^= 18;
			}
			else if (name == "俘虏")
			{
				Init.secret += 29;
			}
			else if (name == "白拆")
			{
				Init.secret -= 47;
			}
			else if (name == "美汁汁")
			{
				Init.secret *= 5;
			}
			else if (name == "柠檬")
			{
				Init.secret ^= 87;
			}
			else if (name == "汉堡顶" && Init.spawnCount == 5)
			{
				Init.secret ^= 127;
				string str = Init.secret.ToString();
				if (ButtonSpawnFruit.Sha1(str) == "DD01903921EA24941C26A48F2CEC24E0BB0E8CC7")
				{
					this.result = "BJDCTF{" + ButtonSpawnFruit.Md5(str) + "}";
					Debug.Log(this.result);
				}
			}
			Init.spawnCount++;
			Debug.Log(Init.secret);
			Debug.Log(Init.spawnCount);
		}
	}

// ButtonSpawnFruit
// Token: 0x0600000A RID: 10 RVA: 0x00002110 File Offset: 0x00000310
public static string Md5(string str)
{
	byte[] bytes = Encoding.UTF8.GetBytes(str);
	byte[] array = MD5.Create().ComputeHash(bytes);
	StringBuilder stringBuilder = new StringBuilder();
	foreach (byte b in array)
	{
		stringBuilder.Append(b.ToString("X2"));
	}
	return stringBuilder.ToString().Substring(0, 20);
}

先解sha1的DD01903921EA24941C26A48F2CEC24E0BB0E8CC7再md5后取前20位, 注意"X2"是输出大写16进制

[Zer0pts2020]easy strcmp

BUUCTF reverse wp 41 - 50_第4张图片

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  if ( a1 > 1 )
  {
    if ( !strcmp(a2[1], "zer0pts{********CENSORED********}") )
      puts("Correct!");
    else
      puts("Wrong!");
  }
  else
  {
    printf("Usage: %s \n", *a2);
  }
  return 0LL;
}

a2参数会经过处理, 所以不是直接的zer0pts{********CENSORED********}
查看call flow
BUUCTF reverse wp 41 - 50_第5张图片

init的时候会调用sub_795

// write access to const memory has been detected, the output may be wrong!
int (**sub_795())(const char *s1, const char *s2)
{
  int (**result)(const char *, const char *); // rax

  result = &strcmp;
  qword_201090 = (__int64 (__fastcall *)(_QWORD, _QWORD))&strcmp;
  off_201028 = sub_6EA;
  return result;
}

在这里插入图片描述
会把strcmpplt表修改到sub_6EA

__int64 __fastcall sub_6EA(__int64 a1, __int64 a2)
{
  int i; // [rsp+18h] [rbp-8h]
  int v4; // [rsp+18h] [rbp-8h]
  int j; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; *(_BYTE *)(i + a1); ++i )
    ;
  v4 = (i >> 3) + 1; // v4 is bytes number
  for ( j = 0; j < v4; ++j )
    *(_QWORD *)(8 * j + a1) -= qword_201060[j];
  return qword_201090(a1, a2); // strcmp
}

这个才是真正的比较函数, 经过处理以后再strcmp, qword_201060是硬编码的数据, 直接逆

#include 
#include 

int main() 
{
    uint64_t values[] = {0, 0x410A4335494A0942, 0x0B0EF2F50BE619F0, 0x4F0A3A064A35282B};
    unsigned char res[] = "zer0pts{********CENSORED********}";
    uint64_t flag[16] = {};
    for (int i = 0; i < sizeof(values) / sizeof(uint64_t); ++i) 
        flag[i] = *(uint64_t *)&res[i * 8] + values[i];
    
    flag[4] = '}';
    printf("%s\n", flag);
}

坑点注意, 如果shift + e导出char数组进行逐字节还原, 会出现4个字节不对的情况

#include 
#include 
#include 
using namespace std;

unsigned char values[] =
{
    0,   0,   0,   0,   0,   0,   0,   0,  66,   9, 
   74,  73,  53,  67,  10,  65, 240,  25, 230,  11, 
  245, 242,  14,  11,  43,  40,  53,  74,   6,  58, 
   10,  79,   0,   0,   0,   0,   0,   0,   0,   0
};

unsigned char res[] =
{
  122, 101, 114,  48, 112, 116, 115, 123,  42,  42, 
   42,  42,  42,  42,  42,  42,  67,  69,  78,  83, 
   79,  82,  69,  68,  42,  42,  42,  42,  42,  42, 
   42,  42, 125,   0
};

int main() 
{
    // unsigned char res[] = "zer0pts{********CENSORED********}";
    unsigned char flag[128] = "";
    for (int i = 0; i < sizeof(res) / sizeof(char); ++i) 
    {
        printf("res[%d]:%d values[%d]:%d ", i, res[i], i, values[i]);
        flag[i] = res[i] + values[i];
        printf("flag[%d]:%c \n", i, flag[i]);
    }
    cout << endl;
    printf("%s\n", flag);
}

调了半天, 意识到逐字节还原会丢失进位, 所以必须8字节为一组进行还原

[ACTF新生赛2020]Universe_final_answer

BUUCTF reverse wp 41 - 50_第6张图片

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  __int64 v4; // [rsp+0h] [rbp-A8h] BYREF
  char v5[104]; // [rsp+20h] [rbp-88h] BYREF
  unsigned __int64 v6; // [rsp+88h] [rbp-20h]

  v6 = __readfsqword(0x28u);
  __printf_chk(1LL, "Please give me the key string:", a3);
  scanf("%s", v5);
  if ( (unsigned __int8)sub_860(v5) )
  {
    sub_C50(v5, &v4);
    __printf_chk(1LL, "Judgement pass! flag is actf{%s_%s}\n", v5);
  }
  else
  {
    puts("False key!");
  }
  return 0LL;
}

bool __fastcall sub_860(char *a1)
{
  int v1; // ecx
  int v2; // esi
  int v3; // edx
  int v4; // r9d
  int v5; // r11d
  int v6; // ebp
  int v7; // ebx
  int v8; // r8d
  int v9; // r10d
  bool result; // al
  int v11; // [rsp+0h] [rbp-38h]

  v1 = a1[1];
  v2 = *a1;
  v3 = a1[2];
  v4 = a1[3];
  v5 = a1[4];
  v6 = a1[6];
  v7 = a1[5];
  v8 = a1[7];
  v9 = a1[8];
  result = 0;
  if ( -85 * v9 + 58 * v8 + 97 * v6 + v7 + -45 * v5 + 84 * v4 + 95 * v2 - 20 * v1 + 12 * v3 == 12613 )
  {
    v11 = a1[9];
    if ( 30 * v11 + -70 * v9 + -122 * v6 + -81 * v7 + -66 * v5 + -115 * v4 + -41 * v3 + -86 * v1 - 15 * v2 - 30 * v8 == -54400
      && -103 * v11 + 120 * v8 + 108 * v7 + 48 * v4 + -89 * v3 + 78 * v1 - 41 * v2 + 31 * v5 - (v6 << 6) - 120 * v9 == -10283
      && 71 * v6 + (v7 << 7) + 99 * v5 + -111 * v3 + 85 * v1 + 79 * v2 - 30 * v4 - 119 * v8 + 48 * v9 - 16 * v11 == 22855
      && 5 * v11 + 23 * v9 + 122 * v8 + -19 * v6 + 99 * v7 + -117 * v5 + -69 * v3 + 22 * v1 - 98 * v2 + 10 * v4 == -2944
      && -54 * v11 + -23 * v8 + -82 * v3 + -85 * v2 + 124 * v1 - 11 * v4 - 8 * v5 - 60 * v7 + 95 * v6 + 100 * v9 == -2222
      && -83 * v11 + -111 * v7 + -57 * v2 + 41 * v1 + 73 * v3 - 18 * v4 + 26 * v5 + 16 * v6 + 77 * v8 - 63 * v9 == -13258
      && 81 * v11 + -48 * v9 + 66 * v8 + -104 * v6 + -121 * v7 + 95 * v5 + 85 * v4 + 60 * v3 + -85 * v2 + 80 * v1 == -1559
      && 101 * v11 + -85 * v9 + 7 * v6 + 117 * v7 + -83 * v5 + -101 * v4 + 90 * v3 + -28 * v1 + 18 * v2 - v8 == 6308 )
    {
      return 99 * v11 + -28 * v9 + 5 * v8 + 93 * v6 + -18 * v7 + -127 * v5 + 6 * v4 + -9 * v3 + -93 * v1 + 58 * v2 == -1697;
    }
  }
  return result;
}

z3解方程组, 得到输入的key, 输入程序打印flag

from z3 import *

v1 = Int('v1')
v2 = Int('v2')
v3 = Int('v3')
v4 = Int('v4')
v5 = Int('v5')
v6 = Int('v6')
v7 = Int('v7')
v8 = Int('v8')
v9 = Int('v9')
v11 = Int('v11')
'''
if ( 30 * v11 + -70 * v9 + -122 * v6 + -81 * v7 + -66 * v5 + -115 * v4 + -41 * v3 + -86 * v1 - 15 * v2 - 30 * v8 == -54400
      && -103 * v11 + 120 * v8 + 108 * v7 + 48 * v4 + -89 * v3 + 78 * v1 - 41 * v2 + 31 * v5 - (v6 << 6) - 120 * v9 == -10283
      && 71 * v6 + (v7 << 7) + 99 * v5 + -111 * v3 + 85 * v1 + 79 * v2 - 30 * v4 - 119 * v8 + 48 * v9 - 16 * v11 == 22855
      && 5 * v11 + 23 * v9 + 122 * v8 + -19 * v6 + 99 * v7 + -117 * v5 + -69 * v3 + 22 * v1 - 98 * v2 + 10 * v4 == -2944
      && -54 * v11 + -23 * v8 + -82 * v3 + -85 * v2 + 124 * v1 - 11 * v4 - 8 * v5 - 60 * v7 + 95 * v6 + 100 * v9 == -2222
      && -83 * v11 + -111 * v7 + -57 * v2 + 41 * v1 + 73 * v3 - 18 * v4 + 26 * v5 + 16 * v6 + 77 * v8 - 63 * v9 == -13258
      && 81 * v11 + -48 * v9 + 66 * v8 + -104 * v6 + -121 * v7 + 95 * v5 + 85 * v4 + 60 * v3 + -85 * v2 + 80 * v1 == -1559
      && 101 * v11 + -85 * v9 + 7 * v6 + 117 * v7 + -83 * v5 + -101 * v4 + 90 * v3 + -28 * v1 + 18 * v2 - v8 == 6308 )
    {
      return 99 * v11 + -28 * v9 + 5 * v8 + 93 * v6 + -18 * v7 + -127 * v5 + 6 * v4 + -9 * v3 + -93 * v1 + 58 * v2 == -1697;
'''
s = Solver()
s.add(30 * v11 + -70 * v9 + -122 * v6 + -81 * v7 + -66 * v5 + -115 * v4 + -41 * v3 + -86 * v1 - 15 * v2 - 30 * v8 == -54400)
s.add(-103 * v11 + 120 * v8 + 108 * v7 + 48 * v4 + -89 * v3 + 78 * v1 - 41 * v2 + 31 * v5 - (v6 * 64) - 120 * v9 == -10283)
s.add(71 * v6 + (v7 * 128) + 99 * v5 + -111 * v3 + 85 * v1 + 79 * v2 - 30 * v4 - 119 * v8 + 48 * v9 - 16 * v11 == 22855)
s.add(5 * v11 + 23 * v9 + 122 * v8 + -19 * v6 + 99 * v7 + -117 * v5 + -69 * v3 + 22 * v1 - 98 * v2 + 10 * v4 == -2944)
s.add(-54 * v11 + -23 * v8 + -82 * v3 + -85 * v2 + 124 * v1 - 11 * v4 - 8 * v5 - 60 * v7 + 95 * v6 + 100 * v9 == -2222)
s.add(-83 * v11 + -111 * v7 + -57 * v2 + 41 * v1 + 73 * v3 - 18 * v4 + 26 * v5 + 16 * v6 + 77 * v8 - 63 * v9 == -13258)
s.add(81 * v11 + -48 * v9 + 66 * v8 + -104 * v6 + -121 * v7 + 95 * v5 + 85 * v4 + 60 * v3 + -85 * v2 + 80 * v1 == -1559)
s.add(101 * v11 + -85 * v9 + 7 * v6 + 117 * v7 + -83 * v5 + -101 * v4 + 90 * v3 + -28 * v1 + 18 * v2 - v8 == 6308)
s.add(99 * v11 + -28 * v9 + 5 * v8 + 93 * v6 + -18 * v7 + -127 * v5 + 6 * v4 + -9 * v3 + -93 * v1 + 58 * v2 == -1697)

if s.check() == sat:
    print(s.model())
else:
    print('no solution')

'''
[v1 = 48,
 v6 = 95,
 v2 = 70,
 v4 = 82,
 v11 = 64,
 v3 = 117,
 v5 = 84,
 v7 = 121,
 v9 = 119,
 v8 = 55]
'''

特殊的 BASE64

BUUCTF reverse wp 41 - 50_第7张图片

CPP逆向, C++写得多了, 大概会感觉比较亲切

int __cdecl main(int argc, const char **argv, const char **envp)
{
  std::ostream *v3; // rax
  std::ostream *v4; // rax
  std::string result; // [rsp+20h] [rbp-60h] BYREF
  std::string rightFlag; // [rsp+30h] [rbp-50h] BYREF
  std::string str; // [rsp+40h] [rbp-40h] BYREF
  char v9; // [rsp+4Fh] [rbp-31h] BYREF
  std::string v10; // [rsp+50h] [rbp-30h] BYREF

  _main();
  std::string::string(&str);
  std::allocator<char>::allocator(&v9);
  std::string::string(&rightFlag, "mTyqm7wjODkrNLcWl0eqO8K8gc1BPk1GNLgUpI==", &v9);
  std::allocator<char>::~allocator(&v9);
  v3 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "Please input your flag!!!!");
  refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v3);
  std::operator>><char>(refptr__ZSt3cin, &str);
  std::string::string(&v10, &str);
  base64Encode(&result);
  std::string::~string(&v10);
  if ( std::operator==<char>(&result, &rightFlag) )
    v4 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "The flag is right!!!!!!!!!");
  else
    v4 = (std::ostream *)std::operator<<<std::char_traits<char>>(refptr__ZSt4cout, "This is a wrong flag!!!!!!!!");
  refptr__ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v4);
  std::string::~string(&result);
  std::string::~string(&rightFlag);
  std::string::~string(&str);
  return 0;
}

std::string __cdecl base64Encode(std::string *p_decode)
{
  std::string *v1; // rdx
  char *v2; // rax
  int v3; // ebx
  char *v4; // rax
  int v5; // ebx
  char *v6; // rax
  _BYTE *v7; // rax
  char *v8; // rax
  _BYTE *v9; // rax
  char *v10; // rax
  int v11; // ebx
  char *v12; // rax
  _BYTE *v13; // rax
  __int64 v15; // [rsp+0h] [rbp-80h] BYREF
  char v16; // [rsp+2Fh] [rbp-51h] BYREF
  int pos_0; // [rsp+30h] [rbp-50h]
  int pos; // [rsp+34h] [rbp-4Ch]
  int len; // [rsp+38h] [rbp-48h]
  int i; // [rsp+3Ch] [rbp-44h]
  std::string *p_decodea; // [rsp+68h] [rbp-18h]

  p_decodea = v1;
  std::allocator<char>::allocator((char *)&v15 + 47);
  std::string::string(p_decode, &unk_489084, &v16);
  std::allocator<char>::~allocator(&v16);
  len = std::string::length(p_decodea);
  for ( i = 0; len / 3 > i; ++i )
  {
    v2 = (char *)std::string::operator[](p_decodea, 3 * i);
    std::string::operator[](&baseKey, *v2 >> 2);
    std::string::operator+=(p_decode);
    v3 = 16 * (*(_BYTE *)std::string::operator[](p_decodea, 3 * i) & 3);
    v4 = (char *)std::string::operator[](p_decodea, 3 * i + 1);
    std::string::operator[](&baseKey, v3 | (*v4 >> 4));
    std::string::operator+=(p_decode);
    v5 = 4 * (*(_BYTE *)std::string::operator[](p_decodea, 3 * i + 1) & 0xF);
    v6 = (char *)std::string::operator[](p_decodea, 3 * i + 2);
    std::string::operator[](&baseKey, v5 | (*v6 >> 6));
    std::string::operator+=(p_decode);
    v7 = (_BYTE *)std::string::operator[](p_decodea, 3 * i + 2);
    std::string::operator[](&baseKey, *v7 & 0x3F);
    std::string::operator+=(p_decode);
  }
  if ( len % 3 == 1 )
  {
    pos = 3 * (len / 3);
    v8 = (char *)std::string::operator[](p_decodea, pos);
    std::string::operator[](&baseKey, *v8 >> 2);
    std::string::operator+=(p_decode);
    v9 = (_BYTE *)std::string::operator[](p_decodea, pos);
    std::string::operator[](&baseKey, 16 * (*v9 & 3));
    std::string::operator+=(p_decode);
    std::string::operator+=(p_decode, "==");
  }
  if ( len % 3 == 2 )
  {
    pos_0 = 3 * (len / 3);
    v10 = (char *)std::string::operator[](p_decodea, pos_0);
    std::string::operator[](&baseKey, *v10 >> 2);
    std::string::operator+=(p_decode);
    v11 = 16 * (*(_BYTE *)std::string::operator[](p_decodea, pos_0) & 3);
    v12 = (char *)std::string::operator[](p_decodea, pos_0 + 1);
    std::string::operator[](&baseKey, v11 | (*v12 >> 4));
    std::string::operator+=(p_decode);
    v13 = (_BYTE *)std::string::operator[](p_decodea, pos_0 + 1);
    std::string::operator[](&baseKey, 4 * (*v13 & 0xF));
    std::string::operator+=(p_decode);
    std::string::operator+=(p_decode, "=");
  }
  return (std::string)p_decode;
}

换表base64

import base64

encodestr = "mTyqm7wjODkrNLcWl0eqO8K8gc1BPk1GNLgUpI=="

changebase64 = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0987654321/+"
originbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

trans_encodestr = encodestr.translate(str.maketrans(changebase64,originbase64))
flag = base64.b64decode(trans_encodestr)

print(flag)

[WUSTCTF2020]level4

BUUCTF reverse wp 41 - 50_第8张图片

int __cdecl main(int argc, const char **argv, const char **envp)
{
  puts("Practice my Data Structure code.....");
  puts("Typing....Struct.....char....*left....*right............emmmmm...OK!");
  init("Typing....Struct.....char....*left....*right............emmmmm...OK!", argv);
  puts("Traversal!");
  printf("Traversal type 1:");
  type1(&unk_601290);
  printf("\nTraversal type 2:");
  type2(&unk_601290);
  printf("\nTraversal type 3:");
  puts("    //type3(&x[22]);   No way!");
  puts(&byte_400A37);
  return 0;
}

unsigned __int64 init()
{
  int i; // [rsp+Ch] [rbp-34h]
  char v2[40]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v3; // [rsp+38h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  strcpy(v2, "I{_}Af2700ih_secTS2Et_wr");
  for ( i = 0; i <= 23; ++i )
    x[24 * i] = v2[i];
  qword_601298 = (__int64)&unk_6011E8;
  qword_6011F0 = (__int64)&unk_601260;
  qword_601268 = (__int64)&unk_6010F8;
  qword_601100 = (__int64)&unk_601110;
  qword_601108 = (__int64)&unk_601140;
  qword_601270 = (__int64)&unk_601230;
  qword_601238 = (__int64)&unk_601158;
  qword_601240 = (__int64)&unk_601098;
  qword_6010A0 = (__int64)&unk_601200;
  qword_6010A8 = (__int64)&unk_601188;
  qword_6011F8 = (__int64)&unk_601170;
  qword_601178 = (__int64)&unk_6011B8;
  qword_601180 = (__int64)&unk_6010B0;
  qword_6010B8 = (__int64)x;
  qword_6010C0 = (__int64)&unk_601218;
  qword_6012A0 = (__int64)&unk_601278;
  qword_601280 = (__int64)&unk_6010E0;
  qword_601288 = (__int64)&unk_6011A0;
  qword_6011B0 = (__int64)&unk_601128;
  qword_601130 = (__int64)&unk_6012A8;
  qword_601138 = (__int64)&unk_6011D0;
  qword_6011D8 = (__int64)&unk_601248;
  qword_6011E0 = (__int64)&unk_6010C8;
  return __readfsqword(0x28u) ^ v3;
}

__int64 __fastcall type1(char *a1)
{
  __int64 result; // rax

  if ( a1 )
  {
    type1(*((_QWORD *)a1 + 1));
    putchar(*a1);
    return type1(*((_QWORD *)a1 + 2));
  }
  return result;
}

int __fastcall type2(char *a1)
{
  int result; // eax

  if ( a1 )
  {
    type2(*((_QWORD *)a1 + 1));
    type2(*((_QWORD *)a1 + 2));
    return putchar(*a1);
  }
  return result;
}

估计是一颗树的遍历, type1是中序遍历, type2是后序遍历

Practice my Data Structure code.....
Typing....Struct.....char....*left....*right............emmmmm...OK!
Traversal!
Traversal type 1:2f0t02T{hcsiI_SwA__r7Ee}
Traversal type 2:20f0Th{2tsIS_icArE}e7__w
Traversal type 3:    //type3(&x[22]);   No way!

写个算法确定出先序遍历

class node:                          #定义节点结构
    def __init__(self, value = None, left = None, right=None):
        self.value = value
        self.left = left
        self.right = right
 
def GetTwoTree(str1, str2):          #str1为后序  str2为中序
    root = node(str1[-1])            #先给第一个值
    Index = str2.index(root.value)   #根在中序中的索引
 
    leftstr2 = str2[: Index]         #中序中的左半部分
    maxindex = -1
    for i in leftstr2:               # 分离后序序列
        tmpindex = str1.index(i)
        if maxindex < tmpindex:
            maxindex = tmpindex
    if len(leftstr2) == 1:           #如果只有一个元素
        root.left = node(leftstr2)   #直接赋值
    elif len(leftstr2) == 0:         #如果没有元素 
        root.left = None             #空
    else:                            #否则递归
        root.left = GetTwoTree(str1[:maxindex+1], leftstr2)   #递归构造左子树
 
    rightstr2 = str2[Index+1:]          #中序中的右半部分
    if len(rightstr2) == 1:
        root.right = node(rightstr2)
    elif len(rightstr2) == 0:
        root.right = None
    else:
        root.right = GetTwoTree(str1[maxindex+1:-1], rightstr2)   #递归构造右子树
    return root
 
def preTraverse(root):  #递归先序遍历
    if root != None:
        print(root.value, end='')
        preTraverse(root.left)
        preTraverse(root.right)
 
if __name__ == '__main__':
    str1 = '20f0Th{2tsIS_icArE}e7__w'                     #str1为后序结果  
    str2 = '2f0t02T{hcsiI_SwA__r7Ee}'                     #str2为中序结果
    root = GetTwoTree(str1, str2)        #构造二叉树
    preTraverse(root)                    #先序遍历输出

crackMe

BUUCTF reverse wp 41 - 50_第9张图片

int wmain()
{
  FILE *v0; // eax
  FILE *v1; // eax
  char v3; // [esp+3h] [ebp-405h]
  char v4[256]; // [esp+4h] [ebp-404h] BYREF
  char Format[256]; // [esp+104h] [ebp-304h] BYREF
  char v6[256]; // [esp+204h] [ebp-204h] BYREF
  char v7[256]; // [esp+304h] [ebp-104h] BYREF

  printf("Come one! Crack Me~~~\n");
  memset(v7, 0, sizeof(v7));
  memset(v6, 0, sizeof(v6));
  while ( 1 )
  {
    do
    {
      do
      {
        printf("user(6-16 letters or numbers):");
        scanf("%s", v7);
        v0 = (FILE *)sub_4024BE();
        fflush(v0);
      }
      while ( !(unsigned __int8)sub_401000(v7) );
      printf("password(6-16 letters or numbers):");
      scanf("%s", v6);
      v1 = (FILE *)sub_4024BE();
      fflush(v1);
    }
    while ( !(unsigned __int8)sub_401000(v6) );
    sub_401090(v7);
    memset(Format, 0, sizeof(Format));
    memset(v4, 0, sizeof(v4));
    v3 = ((int (__cdecl *)(char *, char *))loc_4011A0)(Format, v4);
    if ( (unsigned __int8)sub_401830(v7, v6) )
    {
      if ( v3 )
        break;
    }
    printf(v4);
  }
  printf(Format);
  return 0;
}

loc_4011A0里有个花指令, nop掉可以发现有字符串congratulations:)please try again
BUUCTF reverse wp 41 - 50_第10张图片
所以这里就是输出提示信息的函数, 下面的sub_00401830就是检验函数了, 逻辑比较复杂, 一点点分析写注释

bool __usercall checker@<al>(int a1@<ebx>, const char *user, const char *password)
{
  int v4; // [esp+18h] [ebp-22Ch]
  signed int v5; // [esp+1Ch] [ebp-228h]
  signed int v6; // [esp+28h] [ebp-21Ch]
  unsigned int passwd_cnt; // [esp+30h] [ebp-214h]
  char v8; // [esp+36h] [ebp-20Eh]
  char passwdval; // [esp+37h] [ebp-20Dh]
  char v10; // [esp+38h] [ebp-20Ch]
  unsigned __int8 v11; // [esp+39h] [ebp-20Bh]
  unsigned __int8 v12; // [esp+3Ah] [ebp-20Ah]
  char v13; // [esp+3Bh] [ebp-209h]
  unsigned int v14; // [esp+3Ch] [ebp-208h] BYREF
  char v15; // [esp+40h] [ebp-204h] BYREF
  char v16[255]; // [esp+41h] [ebp-203h] BYREF
  char xorresults[256]; // [esp+140h] [ebp-104h] BYREF

  v5 = 0;
  v6 = 0;
  v12 = 0;
  v11 = 0;
  memset(xorresults, 0, sizeof(xorresults));
  v15 = 0;
  memset(v16, 0, sizeof(v16));
  v10 = 0;
  passwd_cnt = 0;
  v4 = 0;
  while ( passwd_cnt < strlen(password) )
  {
    if ( isdigit(password[passwd_cnt]) )        // digit
    {
      passwdval = password[passwd_cnt] - '0';   // get value of num
    }
    else if ( isxdigit(password[passwd_cnt]) )  // hex
    {
      if ( *((_DWORD *)NtCurrentPeb()->ProcessHeap + 3) != 2 )// antidebug
        password[passwd_cnt] = '"';
      passwdval = (password[passwd_cnt] | 32) - 87;// convert to int
    }
    else                                        // char
    {
      passwdval = ((password[passwd_cnt] | 32) - 'a') % 6 + 10;// abcdef convert to 10 11 12 13 14 15 
    }
    __rdtsc();
    __rdtsc();
    v10 = passwdval + 16 * v10;                 // convert hex to value
    if ( !((int)(passwd_cnt + 1) % 2) )         // (passcnt + 1) % 2 == 0? two two as a group
    {
      v16[v4++ - 1] = v10;                      // value saved
      a1 = v4;
      v10 = 0;
    }
    ++passwd_cnt;
  }
  while ( v6 < 8 )
  {
    v11 += dataxor[++v12];
    v13 = dataxor[v12];
    v8 = dataxor[v11];
    dataxor[v11] = v13;
    dataxor[v12] = v8;
    if ( (NtCurrentPeb()->NtGlobalFlag & 0x70) != 0 )// antidebug
      v13 = v11 + v12;
    xorresults[v6] = dataxor[(unsigned __int8)(v8 + v13)] ^ v16[v5 - 1];
    if ( (unsigned __int8)*(_DWORD *)&NtCurrentPeb()->BeingDebugged )// antidebug
    {
      v11 = -83;
      v12 = 43;
    }
    sub_401710((int)xorresults, user, v6++);    // antidebug
    v5 = v6;
    if ( v6 >= (unsigned int)(&v16[strlen(&v15)] - v16) )
      v5 = 0;
  }
  v14 = 0;
  lastprocess(a1, xorresults, &v14);            // lastchar[] = "dbappsec"
  return v14 == 0xAB94;
}

输入的password转换成8个元素长的数组v16, 和dataxor数组进行乱序异或, 结果存放到xorresults数组里, 最后经过lastprocess的处理和判断

unsigned int *__usercall lastprocess@<eax>(int a1@<ebx>, _BYTE *xorresults, unsigned int *a3)
{
  char v5; // al
  unsigned int *result; // eax

  if ( *xorresults != 'd' )
    *a3 ^= 3u;
  else
    *a3 |= 4u;
  if ( xorresults[1] != 'b' )
  {
    *a3 &= 0x61u;
    _EAX = (unsigned int *)*a3;
  }
  else
  {
    _EAX = a3;
    *a3 |= 0x14u;
  }
  __asm { aam }
  if ( xorresults[2] != 'a' )
    *a3 &= 0xAu;
  else
    *a3 |= 0x84u;
  if ( xorresults[3] != 'p' )
    *a3 >>= 7;
  else
    *a3 |= 0x114u;
  if ( xorresults[4] != 'p' )
    *a3 *= 2;
  else
    *a3 |= 0x380u;
  if ( *((_DWORD *)NtCurrentPeb()->ProcessHeap + 3) != 2 )
  {
    if ( xorresults[5] != 'f' )
      *a3 |= 0x21u;
    else
      *a3 |= 0x2DCu;
  }
  if ( xorresults[5] != 's' )
  {
    v5 = (char)a3;
    *a3 ^= 0x1ADu;
  }
  else
  {
    *a3 |= 0xA04u;
    v5 = (char)a3;
  }
  _AL = v5 - (~(a1 >> 5) - 1);
  __asm { daa }
  if ( xorresults[6] != 'e' )
    *a3 |= 0x4Au;
  else
    *a3 |= 0x2310u;
  if ( xorresults[7] != 'c' )
  {
    *a3 &= 0x3A3u;
    return (unsigned int *)*a3;
  }
  else
  {
    result = a3;
    *a3 |= 0x8A10u;
  }
  return result;
}

所以目前已知信息: 题目给了user是welcomebeijing, 最后比较的字符串是dbappsec
需要动态调试得到乱序异或的dataxor数组(动态调试以略过分析下标顺序的过程, 以及数值生成过程), 然后xor回去得到password的value, 再转成字符串, 最后进行MD5的32位小写哈希

在OD里ctrl + s搜索指令序列

movzx ecx,byte ptr ss:[ebp-209]
xor eax,ecx

定位到关键代码处, 逐一调试出ecx的值, 注意要nop掉反调试代码, 否则调出来的值是被修改过的

import hashlib

testvalue = 'dbappsec'
dataxor = [0x2a, 0xd7, 0x92, 0xe9, 0x53, 0xe2, 0xc4, 0xcd] 
# anti debug values [0x7E, 0x98, 0xC9, 0x95, 0x10, 0x6D, 0xF3, 0x67]
keyval = []
for i in range(8):
    keyval.append(ord(testvalue[i]) ^ dataxor[i])

key = ''
for i in range(8):
    key += hex(keyval[i]).replace('0x', '')

print(key)
key = key.encode('utf-8')
m = hashlib.md5()
m.update(key)
print('flag{' + m.hexdigest() + '}')

[网鼎杯 2020 青龙组]singal

BUUCTF reverse wp 41 - 50_第11张图片

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4[117]; // [esp+18h] [ebp-1D4h] BYREF

  __main();
  qmemcpy(v4, &unk_403040, 0x1C8u);
  vm_operad(v4, 114);
  puts("good,The answer format is:flag {}");
  return 0;
}

int __cdecl vm_operad(int *arrs, int len_114)
{
  int result; // eax
  char Str[200]; // [esp+13h] [ebp-E5h] BYREF
  char v4; // [esp+DBh] [ebp-1Dh]
  int v5; // [esp+DCh] [ebp-1Ch]
  int v6; // [esp+E0h] [ebp-18h]
  int v7; // [esp+E4h] [ebp-14h]
  int v8; // [esp+E8h] [ebp-10h]
  int v9; // [esp+ECh] [ebp-Ch]

  v9 = 0;
  v8 = 0;
  v7 = 0;
  v6 = 0;
  v5 = 0;
  while ( 1 )
  {
    result = v9;
    if ( v9 >= len_114 )
      return result;
    switch ( arrs[v9] )
    {
      case 1:
        Str[v6 + 100] = v4;
        ++v9;
        ++v6;
        ++v8;
        break;
      case 2:
        v4 = arrs[v9 + 1] + Str[v8];
        v9 += 2;
        break;
      case 3:
        v4 = Str[v8] - LOBYTE(arrs[v9 + 1]);
        v9 += 2;
        break;
      case 4:
        v4 = arrs[v9 + 1] ^ Str[v8];
        v9 += 2;
        break;
      case 5:
        v4 = arrs[v9 + 1] * Str[v8];
        v9 += 2;
        break;
      case 6:
        ++v9;
        break;
      case 7:
        if ( Str[v7 + 100] != arrs[v9 + 1] )
        {
          printf("what a shame...");
          exit(0);
        }
        ++v7;
        v9 += 2;
        break;
      case 8:
        Str[v5] = v4;
        ++v9;
        ++v5;
        break;
      case 10:
        read(Str);
        ++v9;
        break;
      case 11:
        v4 = Str[v8] - 1;
        ++v9;
        break;
      case 12:
        v4 = Str[v8] + 1;
        ++v9;
        break;
      default:
        continue;
    }
  }
}

size_t __cdecl read(char *Str)
{
  size_t result; // eax

  printf("string:");
  scanf("%s", Str);
  result = strlen(Str);
  if ( result != 15 )
  {
    puts("WRONG!\n");
    exit(0);
  }
  return result;
}

VM逆向, 12种操作, 还原正向代码, 记录索引值序列和测试值数组

#include 
#include 

unsigned char arrs[] =
{
  0x0A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 
  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
  0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 
  0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
  0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 
  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
  0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 
  0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
  0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 
  0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 
  0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x21, 0x00, 
  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 
  0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x01, 0x00, 
  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 
  0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 
  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
  0x51, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 
  0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
  0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 
  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
  0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 
  0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
  0x02, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x08, 0x00, 
  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 
  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 
  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 
  0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 
  0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 
  0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 
  0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 
  0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 
  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
  0x41, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0C, 0x00, 
  0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
  0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3F, 0x00, 
  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 
  0x07, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 
  0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 
  0x33, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 
  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xA7, 0xFF, 0xFF, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 
  0x00, 0x00, 0xF1, 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 
  0x28, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x84, 0xFF, 
  0xFF, 0xFF, 0x07, 0x00, 0x00, 0x00, 0xC1, 0xFF, 0xFF, 0xFF, 
  0x07, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x00, 
  0x00, 0x00, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00
};
int *o = (int *)arrs;
char opseq[128] = {};
char testseq[128] = {};

int __cdecl vm_operad(int *opcode, int len_114)
{
    int result; // eax
    char flag[200]; // [esp+13h] [ebp-E5h] BYREF
    char v4; // [esp+DBh] [ebp-1Dh]
    int m; // [esp+DCh] [ebp-1Ch]
    int l; // [esp+E0h] [ebp-18h]
    int k; // [esp+E4h] [ebp-14h]
    int j; // [esp+E8h] [ebp-10h]
    int i; // [esp+ECh] [ebp-Ch]

    i = 0;
    j = 0;
    k = 0;
    l = 0;
    m = 0;
    int idx = 0, testcnt = 0;
    while ( 1 )
    {
        result = i;
        opseq[idx++] = i;
        if ( i >= len_114 )
            return result;

        switch ( opcode[i] )
        {
            case 1:                             
                flag[l + 100] = v4;
                ++i;
                ++l;
                ++j;
                break;
            case 2:                                   // +
                v4 = opcode[i + 1] + flag[j];
                i += 2;
                break;
            case 3:                                   // -
                v4 = flag[j] - opcode[i + 1];
                i += 2;
                break;
            case 4:                                   // xor
                v4 = opcode[i + 1] ^ flag[j];
                i += 2;
                break;
            case 5:                                   // *
                v4 = opcode[i + 1] * flag[j];
                i += 2;
                break;
            case 6:                                   // ++i
                ++i;
                break;
            case 7:                                
                // if ( flag[k + 100] != opcode[i + 1] )
                // {
                //   printf("what a shame...");
                //   exit(0);
                // }
                testseq[testcnt++] = opcode[i + 1];
                ++k;
                i += 2;
                break;
            case 8:                         
                flag[m] = v4;
                ++i;
                ++m;
                break;
            case 10:                                  // readstr
                // read(flag);
                // printf("input flag:\n");
                // scanf("%s", flag);
                ++i;
                break;
            case 11:                                  // str[i] - 1
                v4 = flag[j] - 1;
                ++i;
                break;
            case 12:                                  // str[i] + 1
                v4 = flag[j] + 1;
                ++i;
                break;
            default:
                continue;
        }
    }
}

int main() 
{
    vm_operad(o, 114);

    printf("opcode values sequence:\n");
    for (int i = 0; i < 128; ++i) 
        printf("%d, ", opseq[i]);
    
    printf("test values sequence:\n");
    for (int i = 0; i < 128; ++i) 
        printf("%#x, ", testseq[i]);    

    getchar();
    return 0;
}

REV, 根据已有的序列信息, 逆回去求flag

int vm_decode(int *opcode)
{
    char opseq[] = {1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 25, 26, 28, 29, 30, 31, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45, 46, 47, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 64, 66, 67, 69, 70, 72, 73, 75, 76, 78, 79, 81, 82, 83, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114};
    unsigned char testvalues[] = {0x22, 0x3f, 0x34, 0x32, 0x72, 0x33, 0x18, 0xffffffa7, 0x31, 0xfffffff1, 0x28, 0xffffff84, 0xffffffc1, 0x1e, 0x7a, 0x0};

    unsigned char flag[200] = {}; // [esp+13h] [ebp-E5h]
    int v4; // [esp+DBh] [ebp-1Dh]
    int m; // [esp+DCh] [ebp-1Ch]
    int l; // [esp+E0h] [ebp-18h]
    int j; // [esp+E8h] [ebp-10h]
    int i; // [esp+ECh] [ebp-Ch]
    j = 15;
    l = 15;
    m = 15;
    for(int k = sizeof(opseq) - 1; k >= 0 ; --k)//从后往前
    {
        i = opseq[k];
        switch ( opcode[i] )
        {
            case 1:
                --j;
                --l;
                v4 = testvalues[l];
                break;
            case 2:
                flag[j] = v4 - opcode[i + 1];
                break;
            case 3:
                flag[j] = v4 + opcode[i + 1];
                break;
            case 4:
                flag[j] = v4 ^ opcode[i + 1];
                break;
            case 5:
                flag[j] = v4 / opcode[i + 1];
                break;
            case 8:
                --m;
                v4 = flag[m];
                break;
            case 11:
                flag[j] = v4 + 1;
                break;
            case 12:
                flag[j] = v4 - 1;
                break;
            default:
                continue;
        }
    }

    printf("flag{%s}\n", flag);
}

[GUET-CTF2019]number_game

BUUCTF reverse wp 41 - 50_第12张图片

unsigned __int64 __fastcall main(int a1, char **a2, char **a3)
{
  __int64 v4; // [rsp+8h] [rbp-38h]
  __int64 v5; // [rsp+10h] [rbp-30h] BYREF
  __int16 v6; // [rsp+18h] [rbp-28h]
  __int64 v7; // [rsp+20h] [rbp-20h] BYREF
  __int16 v8; // [rsp+28h] [rbp-18h]
  char v9; // [rsp+2Ah] [rbp-16h]
  unsigned __int64 v10; // [rsp+38h] [rbp-8h]

  v10 = __readfsqword(0x28u);
  v5 = 0LL;
  v6 = 0;
  v7 = 0LL;
  v8 = 0;
  v9 = 0;
  __isoc99_scanf("%s", &v5);
  if ( (unsigned int)sub_4006D6(&v5) )
  {
    v4 = sub_400758(&v5, 0LL, 10LL);
    sub_400807(v4, &v7);
    v9 = 0;
    sub_400881(&v7);
    if ( (unsigned int)sub_400917() )
    {
      puts("TQL!");
      printf("flag{");
      printf("%s", (const char *)&v5);
      puts("}");
    }
    else
    {
      puts("your are cxk!!");
    }
  }
  return __readfsqword(0x28u) ^ v10;
}

__int64 __fastcall sub_4006D6(const char *a1)
{
  int i; // [rsp+1Ch] [rbp-4h]

  if ( strlen(a1) == 10 ) // length is 10
  {
    for ( i = 0; i <= 9; ++i )
    {
      if ( a1[i] > 52 || a1[i] <= 47 ) // 47 ~ 51
        goto failed;
    }
    return 1LL;
  }
  else
  {
failed:
    puts("Wrong!");
    return 0LL;
  }
}

_QWORD *__fastcall maketree(__int64 flag, int a2, signed int a3)
{
  char v5; // [rsp+1Fh] [rbp-11h]
  _QWORD *v6; // [rsp+28h] [rbp-8h]

  v5 = *(a2 + flag);
  if ( v5 == 32 || v5 == 10 || a2 >= a3 )
    return 0LL;
  v6 = malloc(0x18uLL);
  *v6 = v5;
  v6[1] = maketree(flag, 2 * a2 + 1, a3);
  v6[2] = maketree(flag, 2 * (a2 + 1), a3);
  return v6;
}

__int64 __fastcall sub_400807(__int64 treeptr, __int64 processed)
{
  __int64 result; // rax

  result = treeptr;
  if ( treeptr )
  {
    sub_400807(*(treeptr + 8), processed);      // lchild
    *(processed + cnt++) = *treeptr;
    return sub_400807(*(treeptr + 16), processed);// rchild
  }
  return result;
}

__int64 __fastcall sub_400881(char *a1)
{
  __int64 result; // rax

  byte_601062 = *a1;
  byte_601067 = a1[1];
  byte_601069 = a1[2];
  byte_60106B = a1[3];
  byte_60106E = a1[4];
  byte_60106F = a1[5];
  byte_601071 = a1[6];
  byte_601072 = a1[7];
  byte_601076 = a1[8];
  result = a1[9];
  byte_601077 = a1[9];
  return result;
}

__int64 sub_400917()
{
  unsigned int v1; // [rsp+0h] [rbp-10h]
  int i; // [rsp+4h] [rbp-Ch]
  int j; // [rsp+8h] [rbp-8h]
  int k; // [rsp+Ch] [rbp-4h]

  v1 = 1;
  for ( i = 0; i <= 4; ++i )
  {
    for ( j = 0; j <= 4; ++j )
    {
      for ( k = j + 1; k <= 4; ++k )
      {
        if ( *(&unk_601060 + 5 * i + j) == *(&unk_601060 + 5 * i + k) )
          v1 = 0;
        if ( *(&unk_601060 + 5 * j + i) == *(&unk_601060 + 5 * k + i) )
          v1 = 0;
      }
    }
  }
  return v1;
}

从后往前一步步梳理, 最后的校验函数是独特的格式, 可以看出来是比较行列元素不相等, 把unk_601060data拿出来5x5打印

for (int i = 0; i < 5; ++i) {
    for (int j = 0; j < 5; ++j) {
        printf("%c ", arrs[i * 5 + j]);
    }
    printf("\n");
}
    
/*
1 4 # 2 3
3 0 # 1 #
0 # 2 3 #
# 3 # # 0
4 2 # # 1
*/

可见是一个类似数独的谜题, 直接解出来得到

1 4 0 2 3
3 0 4 1 2
0 1 2 3 4
2 3 1 4 0
4 2 3 0 1

0421421430

再往前分析, 可以得知输入的flag会以二叉树的形式存储, 然后经过中序遍历后依次赋值给类数独游戏的#位置, 符合校验则通过, 所以需要找到一颗二叉树, 中序遍历的序列是0421421430, 其实只需要找到输入和经过二叉树处理后输出的置换关系即可, 输入0123456789查看输出的串即可得到置换关系, 不过需要patch掉输入格式校验函数
最后得到置换关系0123456789 → 7381940526
REV

#include 
#include 

int main()
{
    // 0123456789 → 7381940526
    char testvalues[] = "0421421430";
    int permutation[] = {7, 3, 8, 1, 9, 4, 0, 5, 2, 6};
    char flag[32] = {};
    for (int i = 0; i < 10; ++i)
        flag[permutation[i]] = testvalues[i];
    
    printf("flag{%s}\n", flag);
    return 0;
}

你可能感兴趣的:(逆向工程,逆向)