BUUCTF reverse wp 91 - 95

[SCTF2019]Who is he

IKUN题
BUUCTF reverse wp 91 - 95_第1张图片
Unity逆向, dnSpy反编译Assembly-CSharp.dll, 搜索字符串定位到关键代码

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using UnityEngine.UI;

// Token: 0x02000005 RID: 5
public class TestClick : MonoBehaviour
{
	// Token: 0x0600000A RID: 10 RVA: 0x000020C4 File Offset: 0x000002C4
	private string Encrypt(string str)
	{
		string result;
		try
		{
			byte[] bytes = Encoding.Unicode.GetBytes(TestClick.encryptKey);
			byte[] bytes2 = Encoding.Unicode.GetBytes(str);
			DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider();
			MemoryStream memoryStream = new MemoryStream();
			CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateEncryptor(bytes, bytes), CryptoStreamMode.Write);
			cryptoStream.Write(bytes2, 0, bytes2.Length);
			cryptoStream.FlushFinalBlock();
			byte[] inArray = memoryStream.ToArray();
			cryptoStream.Close();
			memoryStream.Close();
			result = Convert.ToBase64String(inArray);
		}
		catch
		{
			result = str;
		}
		return result;
	}

	// Token: 0x0600000B RID: 11 RVA: 0x0000215C File Offset: 0x0000035C
	private string Decrypt(string str)
	{
		string result;
		try
		{
			byte[] bytes = Encoding.Unicode.GetBytes(TestClick.encryptKey);
			byte[] array = Convert.FromBase64String(str);
			DESCryptoServiceProvider descryptoServiceProvider = new DESCryptoServiceProvider();
			MemoryStream memoryStream = new MemoryStream();
			CryptoStream cryptoStream = new CryptoStream(memoryStream, descryptoServiceProvider.CreateDecryptor(bytes, bytes), CryptoStreamMode.Write);
			cryptoStream.Write(array, 0, array.Length);
			cryptoStream.FlushFinalBlock();
			byte[] bytes2 = memoryStream.ToArray();
			cryptoStream.Close();
			memoryStream.Close();
			result = Encoding.Unicode.GetString(bytes2);
		}
		catch
		{
			result = str;
		}
		return result;
	}

	// Token: 0x0600000C RID: 12 RVA: 0x000020C1 File Offset: 0x000002C1
	private void Start()
	{
	}

	// Token: 0x0600000D RID: 13 RVA: 0x000021F4 File Offset: 0x000003F4
	public void OnClick()
	{
		Debug.Log("Button Clicked. TestClick.");
		Debug.Log(this.Name.text);
		bool flag = this.Name.text.Equals(this.Decrypt(this.EncryptData));
		if (flag)
		{
			Debug.Log("Right");
			TestClick.Messagebox.MessageBox(IntPtr.Zero, "Haha, same as you!", "Info:", 0);
		}
		else
		{
			Debug.Log("Wrong");
			TestClick.Messagebox.MessageBox(IntPtr.Zero, "Emmmmm,I don't think so.", "Info:", 0);
		}
	}

	// Token: 0x04000003 RID: 3
	private static string encryptKey = "1234";

	// Token: 0x04000004 RID: 4
	private string EncryptData = "1Tsy0ZGotyMinSpxqYzVBWnfMdUcqCMLu0MA+22Jnp+MNwLHvYuFToxRQr0c+ONZc6Q7L0EAmzbycqobZHh4H23U4WDTNmmXwusW4E+SZjygsntGkO2sGA==";

	// Token: 0x04000005 RID: 5
	public Text Name;

	// Token: 0x02000006 RID: 6
	public class Messagebox
	{
		// Token: 0x06000010 RID: 16
		[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
		public static extern int MessageBox(IntPtr handle, string message, string title, int type);
	}
}

验证的密文b64解码后des解密然后和输入的串check, 但是这里的1Tsy0ZGotyMinSpxqYzVBWnfMdUcqCMLu0MA+22Jnp+MNwLHvYuFToxRQr0c+ONZc6Q7L0EAmzbycqobZHh4H23U4WDTNmmXwusW4E+SZjygsntGkO2sGA==是假的, 用CE动态搜

BUUCTF reverse wp 91 - 95_第2张图片

ctrl+B浏览相关内存区域
BUUCTF reverse wp 91 - 95_第3张图片

BUUCTF reverse wp 91 - 95_第4张图片

第一个还是假的, 第二个解出来是flag (注意, 在C#中,字符串默认是Unicode字符串,所以转成字节数组,在每个字符字节后都要加一个"\x00"

from pyDes import des,PAD_PKCS5,CBC
import base64

s2 = base64.b64decode('xZWDZaKEhWNMCbiGYPBIlY3+arozO9zonwrYLiVL4njSez2RYM2WwsGnsnjCDnHs7N43aFvNE54noSadP9F8eEpvTs5QPG+KL0TDE/40nbU=')
key2 = ''.join(['t','\x00','e','\x00','s','\x00','t','\x00'])
des_obj = des(key2,CBC,key2,padmode=PAD_PKCS5)
m = des_obj.decrypt(s2)
print(m.decode('UTF-16'))

[MRCTF2020]EasyCpp

BUUCTF reverse wp 91 - 95_第5张图片

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

  v31 = 0;
  std::vector<int>::vector(v20, argv, envp);
  std::vector<bool>::vector(v19);
  std::allocator<char>::allocator(&v21);
  std::string::basic_string(v18, &unk_500E, &v21);
  std::allocator<char>::~allocator(&v21);
  v3 = std::operator<<<std::char_traits<char>>(&std::cout, "give me your key!");
  std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
  for ( i = 0; i <= 8; ++i )
  {
    std::istream::operator>>(&std::cin, &keys[i]);
    std::to_string((std::__cxx11 *)v22, keys[i]);
    std::string::operator+=(v18, v22);
    std::string::~string(v22);
  }
  v28 = keys;
  v29 = keys;
  v27 = (int *)&unk_83E4;
  while ( v29 != v27 )
  {
    v17 = *v29;
    std::vector<int>::push_back(v20, &v17);
    ++v29;
  }
  v4 = std::vector<int>::end(v20);
  v5 = std::vector<int>::begin(v20);
  std::for_each<__gnu_cxx::__normal_iterator<int *,std::vector<int>>,main::{lambda(int &)#1}>(v5, v4);
  v26 = v20;
  v16 = std::vector<int>::begin(v20);
  v15 = std::vector<int>::end(v26);
  while ( (unsigned __int8)__gnu_cxx::operator!=<int *,std::vector<int>>(&v16, &v15) )
  {
    v25 = *(_DWORD *)__gnu_cxx::__normal_iterator<int *,std::vector<int>>::operator*(&v16);
    std::allocator<char>::allocator(&v23);
    std::string::basic_string(v14, &unk_500E, &v23);
    std::allocator<char>::~allocator(&v23);
    depart(v25, v14);
    {lambda(std::string &)#1}::operator()(&func, v14);
    std::string::basic_string(v24, v14);
    v6 = {lambda(std::string,int)#2}::operator()(&check, v24, v31) ^ 1;
    std::string::~string(v24);
    if ( (_BYTE)v6 )
    {
      v7 = std::operator<<<std::char_traits<char>>(&std::cout, "Wrong password!");
      std::ostream::operator<<(v7, &std::endl<char,std::char_traits<char>>);
      system("pause");
      exit(0);
    }
    ++v31;
    std::string::~string(v14);
    __gnu_cxx::__normal_iterator<int *,std::vector<int>>::operator++(&v16);
  }
  v8 = std::operator<<<std::char_traits<char>>(&std::cout, "right!");
  std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>);
  v9 = std::operator<<<std::char_traits<char>>(&std::cout, "flag:MRCTF{md5(");
  v10 = std::operator<<<char>(v9, v18);
  v11 = std::operator<<<std::char_traits<char>>(v10, ")}");
  std::ostream::operator<<(v11, &std::endl<char,std::char_traits<char>>);
  v12 = 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<<(v12, &std::endl<char,std::char_traits<char>>);
  system("pause");
  std::string::~string(v18);
  std::vector<bool>::~vector(v19);
  std::vector<int>::~vector(v20);
  return 0;
}

depart函数, 把一个数分解成素因子的乘积

__int64 __fastcall depart(int a1, __int64 a2)
{
  char v3[32]; // [rsp+20h] [rbp-60h] BYREF
  char v4[40]; // [rsp+40h] [rbp-40h] BYREF
  int i; // [rsp+68h] [rbp-18h]
  int v6; // [rsp+6Ch] [rbp-14h]

  v6 = a1;
  for ( i = 2; std::sqrt<int>((unsigned int)a1) >= (double)i; ++i )
  {
    if ( !(a1 % i) )
    {
      v6 = i;
      depart((unsigned int)(a1 / i), a2);
      break;
    }
  }
  std::to_string((std::__cxx11 *)v4, v6);
  std::operator+<char>(v3, &unk_500C, v4);
  std::string::operator+=(a2, v3);
  std::string::~string(v3);
  return std::string::~string(v4);
}

第一个lambda函数, 对每一项进行与1异或的操作

__int64 __fastcall std::for_each<__gnu_cxx::__normal_iterator<int *,std::vector<int>>,main::{lambda(int &)#1}>(
        __int64 a1,
        __int64 a2)
{
  unsigned int v2; // ebx
  __int64 v3; // rax
  char v5; // [rsp+Fh] [rbp-21h] BYREF
  __int64 v6; // [rsp+10h] [rbp-20h] BYREF
  __int64 v7[3]; // [rsp+18h] [rbp-18h] BYREF

  v7[0] = a1;
  v6 = a2;
  while ( (unsigned __int8)__gnu_cxx::operator!=<int *,std::vector<int>>(v7, &v6) )
  {
    v3 = __gnu_cxx::__normal_iterator<int *,std::vector<int>>::operator*(v7);
    main::{lambda(int &)#1}::operator()(&v5, v3);
    __gnu_cxx::__normal_iterator<int *,std::vector<int>>::operator++(v7);
  }
  return v2;
}

_DWORD *__fastcall main::{lambda(int &)#1}::operator()(__int64 a1, _DWORD *a2)
{
  _DWORD *result; // rax

  result = a2;
  *a2 ^= 1u;
  return result;
}

第二个lambda函数, 替换操作

__int64 __fastcall {lambda(std::string &)#1}::operator()(__int64 a1, __int64 a2)
{
  __int64 v2; // rbx
  __int64 v3; // rax
  __int64 v4; // rbx
  __int64 v5; // rax
  __int64 v6; // rbx
  __int64 v7; // rax
  __int64 v8; // rbx
  __int64 v9; // rax
  __int64 v10; // rbx
  __int64 v11; // rax
  __int64 v12; // rbx
  __int64 v13; // rax
  __int64 v14; // rbx
  __int64 v15; // rax
  __int64 v16; // rbx
  __int64 v17; // rax
  __int64 v18; // rbx
  __int64 v19; // rax
  __int64 v20; // rbx
  __int64 v21; // rax
  __int64 v22; // rbx
  __int64 v23; // rax
  char v25; // [rsp+1Ah] [rbp-26h] BYREF
  char v26; // [rsp+1Bh] [rbp-25h] BYREF
  char v27; // [rsp+1Ch] [rbp-24h] BYREF
  char v28; // [rsp+1Dh] [rbp-23h] BYREF
  char v29; // [rsp+1Eh] [rbp-22h] BYREF
  char v30; // [rsp+1Fh] [rbp-21h] BYREF
  char v31; // [rsp+20h] [rbp-20h] BYREF
  char v32; // [rsp+21h] [rbp-1Fh] BYREF
  char v33; // [rsp+22h] [rbp-1Eh] BYREF
  char v34; // [rsp+23h] [rbp-1Dh] BYREF
  char v35; // [rsp+24h] [rbp-1Ch] BYREF
  char v36; // [rsp+25h] [rbp-1Bh] BYREF
  char v37; // [rsp+26h] [rbp-1Ah] BYREF
  char v38; // [rsp+27h] [rbp-19h] BYREF
  char v39; // [rsp+28h] [rbp-18h] BYREF
  char v40; // [rsp+29h] [rbp-17h] BYREF
  char v41; // [rsp+2Ah] [rbp-16h] BYREF
  char v42; // [rsp+2Bh] [rbp-15h] BYREF
  char v43; // [rsp+2Ch] [rbp-14h] BYREF
  char v44; // [rsp+2Dh] [rbp-13h] BYREF
  char v45; // [rsp+2Eh] [rbp-12h] BYREF
  char v46[17]; // [rsp+2Fh] [rbp-11h] BYREF

  v25 = 79;
  v26 = 48;
  v2 = std::string::end(a2);
  v3 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v3, v2, &v26, &v25);
  v27 = 108;
  v28 = 49;
  v4 = std::string::end(a2);
  v5 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v5, v4, &v28, &v27);
  v29 = 122;
  v30 = 50;
  v6 = std::string::end(a2);
  v7 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v7, v6, &v30, &v29);
  v31 = 69;
  v32 = 51;
  v8 = std::string::end(a2);
  v9 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v9, v8, &v32, &v31);
  v33 = 65;
  v34 = 52;
  v10 = std::string::end(a2);
  v11 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v11, v10, &v34, &v33);
  v35 = 115;
  v36 = 53;
  v12 = std::string::end(a2);
  v13 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v13, v12, &v36, &v35);
  v37 = 71;
  v38 = 54;
  v14 = std::string::end(a2);
  v15 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v15, v14, &v38, &v37);
  v39 = 84;
  v40 = 55;
  v16 = std::string::end(a2);
  v17 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v17, v16, &v40, &v39);
  v41 = 66;
  v42 = 56;
  v18 = std::string::end(a2);
  v19 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v19, v18, &v42, &v41);
  v43 = 113;
  v44 = 57;
  v20 = std::string::end(a2);
  v21 = std::string::begin(a2);
  std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v21, v20, &v44, &v43);
  v45 = 61;
  v46[0] = 32;
  v22 = std::string::end(a2);
  v23 = std::string::begin(a2);
  return std::replace<__gnu_cxx::__normal_iterator<char *,std::string>,char>(v23, v22, v46, &v45);
}

第三个lambda函数, 加密后的字符串与一个已知字符串ans[abi:cxx11]做对比

_BOOL8 __fastcall {lambda(std::string,int)#2}::operator()(__int64 a1, __int64 a2, int a3)
{
  const char *v3; // rbx
  const char *v4; // rax

  v3 = (const char *)std::string::c_str((char *)&ans[abi:cxx11] + 32 * a3);
  v4 = (const char *)std::string::c_str(a2);
  return strcmp(v4, v3) == 0;
}

int __fastcall __static_initialization_and_destruction_0(int a1, int a2)
{
  int result; // eax
  char v3; // [rsp+17h] [rbp-29h] BYREF
  char v4; // [rsp+18h] [rbp-28h] BYREF
  char v5; // [rsp+19h] [rbp-27h] BYREF
  char v6; // [rsp+1Ah] [rbp-26h] BYREF
  char v7; // [rsp+1Bh] [rbp-25h] BYREF
  char v8; // [rsp+1Ch] [rbp-24h] BYREF
  char v9; // [rsp+1Dh] [rbp-23h] BYREF
  char v10; // [rsp+1Eh] [rbp-22h] BYREF
  char v11[33]; // [rsp+1Fh] [rbp-21h] BYREF

  if ( a1 == 1 && a2 == 0xFFFF )
  {
    std::ios_base::Init::Init((std::ios_base::Init *)&std::__ioinit);
    __cxa_atexit((void (__fastcall *)(void *))&std::ios_base::Init::~Init, &std::__ioinit, &_dso_handle);
    std::allocator<char>::allocator(&v3);
    std::string::basic_string(&ans[abi:cxx11], "=zqE=z=z=z", &v3);
    std::allocator<char>::~allocator(&v3);
    std::allocator<char>::allocator(&v4);
    std::string::basic_string((char *)&ans[abi:cxx11] + 32, "=lzzE", &v4);
    std::allocator<char>::~allocator(&v4);
    std::allocator<char>::allocator(&v5);
    std::string::basic_string((char *)&ans[abi:cxx11] + 64, "=ll=T=s=s=E", &v5);
    std::allocator<char>::~allocator(&v5);
    std::allocator<char>::allocator(&v6);
    std::string::basic_string((char *)&ans[abi:cxx11] + 96, "=zATT", &v6);
    std::allocator<char>::~allocator(&v6);
    std::allocator<char>::allocator(&v7);
    std::string::basic_string((char *)&ans[abi:cxx11] + 128, "=s=s=s=E=E=E", &v7);
    std::allocator<char>::~allocator(&v7);
    std::allocator<char>::allocator(&v8);
    std::string::basic_string((char *)&ans[abi:cxx11] + 160, "=EOll=E", &v8);
    std::allocator<char>::~allocator(&v8);
    std::allocator<char>::allocator(&v9);
    std::string::basic_string((char *)&ans[abi:cxx11] + 192, "=lE=T=E=E=E", &v9);
    std::allocator<char>::~allocator(&v9);
    std::allocator<char>::allocator(&v10);
    std::string::basic_string((char *)&ans[abi:cxx11] + 224, "=EsE=s=z", &v10);
    std::allocator<char>::~allocator(&v10);
    std::allocator<char>::allocator(v11);
    std::string::basic_string((char *)&ans[abi:cxx11] + 256, "=AT=lE=ll", v11);
    std::allocator<char>::~allocator(v11);
    return __cxa_atexit(_tcf_0, 0LL, &_dso_handle);
  }
  return result;
}

整体逻辑:

  • 输入9个数字, 与1异或
  • depart处理成素因数的字符串, 空格隔开
  • 替换
  • check

import hashlib

checklist = [
    "=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 replace_func(string):
    string = string.replace("O","0")
    string = string.replace("l","1")
    string = string.replace("z","2")
    string = string.replace("E","3")
    string = string.replace("A","4")
    string = string.replace("s","5")
    string = string.replace("G","6")
    string = string.replace("T","7")
    string = string.replace("B","8")
    string = string.replace("q","9")
    string = string.replace("="," ")
    return string

for i in range(len(checklist)):
    checklist[i] = replace_func(checklist[i])

print(checklist)
numbers = []
for eachstr in checklist:
    tmp = eachstr.split(' ')[1:]
    num = 1
    for n in tmp:
        tmpn = int(n)
        num *= tmpn
    numbers.append(num)

print(numbers)
flag = ''
for i in range(len(numbers)):
    flag += str(numbers[i] ^ 1)

md5obj = hashlib.md5()
md5obj.update(flag.encode('utf-8'))

print('flag{{{}}}'.format(md5obj.hexdigest()))

[NPUCTF2020]Baby Obfuscation

BUUCTF reverse wp 91 - 95_第6张图片

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  int v4; // ebx
  int v5; // esi
  int v6; // ebx
  int v7; // ebx
  int v8; // esi
  int v9; // ebx
  int v10; // ebx
  int v11; // ebx
  int v12; // esi
  int v13; // eax
  int v14; // ebx
  int v15; // esi
  int v16; // ebx
  int v17; // eax
  bool v18; // bl
  int v19; // eax
  int v20; // esi
  int v21; // ebx
  int v22; // ebx
  int v23; // eax
  int v24; // eax
  int v25; // eax
  int v26; // ebx
  int A0X3[65]; // [rsp+20h] [rbp-60h] BYREF
  char A0X2[1001]; // [rsp+130h] [rbp+B0h] BYREF
  int A0X1[1001]; // [rsp+520h] [rbp+4A0h] BYREF
  int A0X5[4]; // [rsp+14D0h] [rbp+1450h]
  int A0X4[4]; // [rsp+14E0h] [rbp+1460h]
  int length; // [rsp+14F0h] [rbp+1470h]
  int i_1; // [rsp+14F4h] [rbp+1474h]
  int i_0; // [rsp+14F8h] [rbp+1478h]
  int i; // [rsp+14FCh] [rbp+147Ch]

  _main();
  memset(A0X1, 0, sizeof(A0X1));
  memset(A0X3, 0, sizeof(A0X3));
  for ( i = 0; i <= 64; ++i )
    A0X3[i] = i + 1;
  A0X4[0] = 2;
  A0X4[1] = 3;
  A0X4[2] = 4;
  A0X4[3] = 5;
  A0X5[0] = 2;
  A0X5[1] = 3;
  A0X5[2] = 4;
  A0X5[3] = 5;
  puts("WHERE IS MY KEY!?");
  scanf("%32s", A0X2);
  length = strlen(A0X2);
  v3 = F0X1(A0X3[i_0], A0X3[i_0]);
  for ( i_0 = v3 / A0X3[i_0]; i_0 <= length; ++i_0 )
  {
    v4 = (A0X3[i_0] + A0X3[i_0 + 1]) * (A0X3[i_0] + A0X3[i_0 + 1]);
    if ( v4 >= F0X5(2, 2) * A0X3[i_0] * A0X3[i_0 + 1] )
    {
      v5 = ~A0X2[F0X4(i_0, 1)];
      v6 = F0X4(i_0, 1);
      A0X1[i_0] = ~(v5 + A0X4[v6 % F0X5(2, 2)]);
    }
    v7 = F0X1(A0X3[i_0], A0X3[i_0 + 1]);
    if ( v7 > F0X1(A0X3[i_0 + 1], ~(~A0X3[i_0 + 1] + A0X3[i_0])) )
    {
      v8 = A0X1[i_0];
      v9 = F0X4(i_0, 1);
      A0X1[i_0] = ~(~v8 + A0X3[v9 % F0X5(2, 2)]) * v8;
    }
    v10 = A0X3[i_0 + 1];
    v11 = F0X5(2, 1) * v10;
    v12 = A0X3[i_0];
    v13 = F0X5(2, 1);
    v14 = F0X1(v12 * v13, v11);
    v15 = F0X5(2, 1);
    if ( v14 == v15 * F0X1(A0X3[i_0], A0X3[i_0 + 1]) )
    {
      v16 = F0X4(i_0, 1);
      A0X1[i_0] ^= A0X4[v16 % F0X5(2, 2)];
    }
    v17 = F0X5(V0X3, A0X3[i_0]);
    v18 = v17 < A0X3[i_0] + 1;
    v19 = F0X5(2, 4);
    if ( F0X3(v19 >= i_0, v18) )
    {
      v20 = ~A0X2[F0X4(i_0, 1)];
      v21 = F0X4(i_0, 1);
      A0X1[i_0] ^= ~(v20 + A0X4[v21 % F0X5(2, 2)]);
    }
    v22 = F0X5(2, 3);
    v23 = F0X1(A0X3[i_0], A0X3[i_0]);
    A0X1[i_0] *= v22 + F0X5(2, v23 / A0X3[i_0]);
  }
  v24 = F0X5(2, 4);
  if ( F0X4(v24, 1) != length )
    goto LABEL_23;
  v25 = F0X1(A0X3[i_1], A0X3[i_1]);
  for ( i_1 = v25 / A0X3[i_1]; i_1 <= length; ++i_1 )
  {
    v26 = A0X1[i_1];
    if ( v26 == F0X4(A0X6[i_1], 1) / 10 )
      ++V0X2;
  }
  if ( V0X2 == length )
    puts("\nPASS");
  else
LABEL_23:
    puts("\nDENIED");
  return 0;
}

看起来基本是函数名, 变量名的混淆, 逻辑不复杂, 从后往前分析

BUUCTF reverse wp 91 - 95_第7张图片

BUUCTF reverse wp 91 - 95_第8张图片
抛去恒为假的分支, 保留关键处理逻辑, 可以直接逆回去

arr1 = [2, 3, 4, 5]

checklist = [
    0, 7801, 7801, 8501, 5901, 8001, 6401, 11501,
    4601, 9801, 9601, 11701, 5301, 9701, 10801, 12501
]

inputs = [0] * 16

for i in range(1, 16):
    checklist[i] = (checklist[i] - 1) // 10 // 10
    checklist[i] ^= arr1[(i - 1) % 4]
    inputs[i - 1] = (~(((~checklist[i]) & 0xFF) - arr1[(i - 1) % 4]) % 0xFF) + 1

print(inputs)

flag = ''
for i in range(len(inputs)):
    flag += chr(inputs[i])

print(flag)

[NPUCTF2020]BasicASM

给了汇编文件的一部分, 和对应的结果

00007FF7A8AC5A50  push        rbp  
00007FF7A8AC5A52  push        rdi  
00007FF7A8AC5A53  sub         rsp,238h  
00007FF7A8AC5A5A  lea         rbp,[rsp+20h]  
00007FF7A8AC5A5F  mov         rdi,rsp  
00007FF7A8AC5A62  mov         ecx,8Eh  
00007FF7A8AC5A67  mov         eax,0CCCCCCCCh  
00007FF7A8AC5A6C  rep stos    dword ptr [rdi]  
00007FF7A8AC5A6E  mov         rax,qword ptr [__security_cookie (07FF7A8AD3018h)]  
00007FF7A8AC5A75  xor         rax,rbp  
00007FF7A8AC5A78  mov         qword ptr [rbp+208h],rax  
00007FF7A8AC5A7F  lea         rcx,[__06A15900_ConsoleApplication@cpp (07FF7A8AD902Ah)]  
00007FF7A8AC5A86  call        __CheckForDebuggerJustMyCode (07FF7A8AC1122h)  
00007FF7A8AC5A8B  lea         rdx,[string "flag{this_is_a_fake_flag}" (07FF7A8ACF450h)]  
00007FF7A8AC5A92  lea         rcx,[flag]  
00007FF7A8AC5A96  call        std::basic_string,std::allocator >::basic_string,std::allocator > (07FF7A8AC15E1h)  
00007FF7A8AC5A9B  nop  
00007FF7A8AC5A9C  mov         dword ptr [p],0  
00007FF7A8AC5AA3  mov         dword ptr [rbp+64h],0  
00007FF7A8AC5AAA  jmp         main+64h (07FF7A8AC5AB4h)  
00007FF7A8AC5AAC  mov         eax,dword ptr [rbp+64h]  
00007FF7A8AC5AAF  inc         eax  
00007FF7A8AC5AB1  mov         dword ptr [rbp+64h],eax  
00007FF7A8AC5AB4  movsxd      rax,dword ptr [rbp+64h]  
00007FF7A8AC5AB8  mov         qword ptr [rbp+1F8h],rax  
00007FF7A8AC5ABF  lea         rcx,[flag]  
00007FF7A8AC5AC3  call        std::basic_string,std::allocator >::length (07FF7A8AC122Bh)  
00007FF7A8AC5AC8  mov         rcx,qword ptr [rbp+1F8h]  
00007FF7A8AC5ACF  cmp         rcx,rax  
00007FF7A8AC5AD2  jae         main+1B2h (07FF7A8AC5C02h)  
00007FF7A8AC5AD8  mov         eax,dword ptr [rbp+64h]  
00007FF7A8AC5ADB  and         eax,1  
00007FF7A8AC5ADE  cmp         eax,1  
00007FF7A8AC5AE1  jne         main+126h (07FF7A8AC5B76h)  
00007FF7A8AC5AE7  movsxd      rax,dword ptr [rbp+64h]  
00007FF7A8AC5AEB  mov         rdx,rax  
00007FF7A8AC5AEE  lea         rcx,[flag]  
00007FF7A8AC5AF2  call        std::basic_string,std::allocator >::operator[] (07FF7A8AC1442h)  
00007FF7A8AC5AF7  movsx       eax,byte ptr [rax]  
00007FF7A8AC5AFA  xor         eax,42h  
00007FF7A8AC5AFD  mov         dword ptr [p],eax  
00007FF7A8AC5B00  mov         dl,30h  
00007FF7A8AC5B02  lea         rcx,[rbp+144h]  
00007FF7A8AC5B09  call        std::setfill (07FF7A8AC1046h)  
00007FF7A8AC5B0E  mov         qword ptr [rbp+1F8h],rax  
00007FF7A8AC5B15  mov         edx,2  
00007FF7A8AC5B1A  lea         rcx,[rbp+168h]  
00007FF7A8AC5B21  call        std::setw (07FF7A8AC10D2h)  
00007FF7A8AC5B26  mov         qword ptr [rbp+200h],rax  
00007FF7A8AC5B2D  lea         rdx,[std::hex (07FF7A8AC1488h)]  
00007FF7A8AC5B34  mov         rcx,qword ptr [__imp_std::cout (07FF7A8AD71C0h)]  
00007FF7A8AC5B3B  call        qword ptr [__imp_std::basic_ostream >::operator<< (07FF7A8AD7160h)]  
00007FF7A8AC5B41  mov         rcx,qword ptr [rbp+200h]  
00007FF7A8AC5B48  mov         rdx,rcx  
00007FF7A8AC5B4B  mov         rcx,rax  
00007FF7A8AC5B4E  call        std::operator<<,__int64> (07FF7A8AC12F8h)  
00007FF7A8AC5B53  mov         rcx,qword ptr [rbp+1F8h]  
00007FF7A8AC5B5A  mov         rdx,rcx  
00007FF7A8AC5B5D  mov         rcx,rax  
00007FF7A8AC5B60  call        std::operator<<,char> (07FF7A8AC11A4h)  
00007FF7A8AC5B65  mov         edx,dword ptr [p]  
00007FF7A8AC5B68  mov         rcx,rax  
00007FF7A8AC5B6B  call        qword ptr [__imp_std::basic_ostream >::operator<< (07FF7A8AD7158h)]  
00007FF7A8AC5B71  jmp         main+1ADh (07FF7A8AC5BFDh)  
00007FF7A8AC5B76  movsxd      rax,dword ptr [rbp+64h]  
00007FF7A8AC5B7A  mov         rdx,rax  
00007FF7A8AC5B7D  lea         rcx,[flag]  
00007FF7A8AC5B81  call        std::basic_string,std::allocator >::operator[] (07FF7A8AC1442h)  
00007FF7A8AC5B86  movsx       eax,byte ptr [rax]  
00007FF7A8AC5B89  mov         dword ptr [p],eax  
00007FF7A8AC5B8C  mov         dl,30h  
00007FF7A8AC5B8E  lea         rcx,[rbp+194h]  
00007FF7A8AC5B95  call        std::setfill (07FF7A8AC1046h)  
00007FF7A8AC5B9A  mov         qword ptr [rbp+1F8h],rax  
00007FF7A8AC5BA1  mov         edx,2  
00007FF7A8AC5BA6  lea         rcx,[rbp+1B8h]  
00007FF7A8AC5BAD  call        std::setw (07FF7A8AC10D2h)  
00007FF7A8AC5BB2  mov         qword ptr [rbp+200h],rax  
00007FF7A8AC5BB9  lea         rdx,[std::hex (07FF7A8AC1488h)]  
00007FF7A8AC5BC0  mov         rcx,qword ptr [__imp_std::cout (07FF7A8AD71C0h)]  
00007FF7A8AC5BC7  call        qword ptr [__imp_std::basic_ostream >::operator<< (07FF7A8AD7160h)]  
00007FF7A8AC5BCD  mov         rcx,qword ptr [rbp+200h]  
00007FF7A8AC5BD4  mov         rdx,rcx  
00007FF7A8AC5BD7  mov         rcx,rax  
00007FF7A8AC5BDA  call        std::operator<<,__int64> (07FF7A8AC12F8h)  
00007FF7A8AC5BDF  mov         rcx,qword ptr [rbp+1F8h]  
00007FF7A8AC5BE6  mov         rdx,rcx  
00007FF7A8AC5BE9  mov         rcx,rax  
00007FF7A8AC5BEC  call        std::operator<<,char> (07FF7A8AC11A4h)  
00007FF7A8AC5BF1  mov         edx,dword ptr [p]  
00007FF7A8AC5BF4  mov         rcx,rax  
00007FF7A8AC5BF7  call        qword ptr [__imp_std::basic_ostream >::operator<< (07FF7A8AD7158h)]  
00007FF7A8AC5BFD  jmp         main+5Ch (07FF7A8AC5AACh)  
00007FF7A8AC5C02  mov         dword ptr [rbp+1E4h],0  
00007FF7A8AC5C0C  lea         rcx,[flag]  
00007FF7A8AC5C10  call        std::basic_string,std::allocator >::~basic_string,std::allocator > (07FF7A8AC1302h)  
00007FF7A8AC5C15  mov         eax,dword ptr [rbp+1E4h]  
00007FF7A8AC5C1B  mov         edi,eax  
00007FF7A8AC5C1D  lea         rcx,[rbp-20h]  
00007FF7A8AC5C21  lea         rdx,[__xt_z+540h (07FF7A8ACEFE0h)]  
00007FF7A8AC5C28  call        _RTC_CheckStackVars (07FF7A8AC1596h)  
00007FF7A8AC5C2D  mov         eax,edi  
00007FF7A8AC5C2F  mov         rcx,qword ptr [rbp+208h]  
00007FF7A8AC5C36  xor         rcx,rbp  
00007FF7A8AC5C39  call        __security_check_cookie (07FF7A8AC1190h)  
00007FF7A8AC5C3E  lea         rsp,[rbp+218h]  
00007FF7A8AC5C45  pop         rdi  
00007FF7A8AC5C46  pop         rbp  
00007FF7A8AC5C47  ret  

100来行, 直接读汇编就行
call std::basic_string < char,std::char_traits,std::allocator >::length (07FF7A8AC122Bh) 计算flag的长度
call std::basic_string < char,std::char_traits,std::allocator >::operator[] (07FF7A8AC1442h) 构建一个数组
这里是下标为奇数时^0x42

BUUCTF reverse wp 91 - 95_第9张图片
逻辑不复杂, 只有xor操作, 逆回去

s = '662e61257b26301d7972751d6b2c6f355f3a38742d74341d61776d7d7d'

flag = ''
odd = 0
for i in range(0, len(s), 2):
    intval = int(s[i:i + 2], 16)
    if odd % 2 == 1:
        intval ^= 0x42
    odd += 1
    flag += chr(intval)

print(flag)

[ACTF新生赛2020]Splendid_MineCraft

BUUCTF reverse wp 91 - 95_第10张图片

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *v3; // eax
  char *v4; // eax
  char v6; // [esp+0h] [ebp-68h]
  int i; // [esp+14h] [ebp-54h]
  char *v8; // [esp+18h] [ebp-50h]
  char v9; // [esp+20h] [ebp-48h]
  char Str1; // [esp+24h] [ebp-44h] BYREF
  _BYTE v11[3]; // [esp+25h] [ebp-43h] BYREF
  char v12; // [esp+3Dh] [ebp-2Bh]
  int v13; // [esp+44h] [ebp-24h]
  __int16 v14; // [esp+48h] [ebp-20h]
  char v15[4]; // [esp+4Ch] [ebp-1Ch]
  __int16 v16; // [esp+50h] [ebp-18h]
  int v17; // [esp+54h] [ebp-14h] BYREF
  __int16 v18; // [esp+58h] [ebp-10h]
  int v19; // [esp+5Ch] [ebp-Ch]
  __int16 v20; // [esp+60h] [ebp-8h]

  sub_401020("%s\n", (char)aWelcomeToActfS);
  sub_401050("%s", (char)&Str1);
  if ( &v11[strlen(&Str1)] - v11 == 26 && !strncmp(&Str1, "ACTF{", 5u) && v12 == 125 )
  {
    v12 = 0;
    v3 = strtok(&Str1, "_");
    v17 = *(_DWORD *)(v3 + 5);
    v18 = *(_WORD *)(v3 + 9);
    v19 = *(_DWORD *)(v3 + 5);
    v20 = *(_WORD *)(v3 + 9);
    v4 = strtok(0, "_");
    v13 = *(_DWORD *)v4;
    v14 = *((_WORD *)v4 + 2);
    v8 = strtok(0, "_");
    *(_DWORD *)v15 = *(_DWORD *)v8;
    v16 = *((_WORD *)v8 + 2);
    dword_403354 = (int)&unk_4051D8;
    if ( ((int (__cdecl *)(int *))unk_4051D8)(&v17) )
    {
      v9 = BYTE2(v19) ^ HIBYTE(v20) ^ v19 ^ HIBYTE(v19) ^ BYTE1(v19) ^ v20;
      for ( i = 256; i < 496; ++i )
        byte_405018[i] ^= v9;
      __asm { jmp     eax }
    }
  }
  sub_401020("Wrong\n", v6);
  return 0;
}

char *strtok(char *s, char *delim): 对字符串s进行操作, 以delim中的字符为分界符, 将s切分成一个个子串; 如果s为NULL, 则函数保存的指针SAVE_PTR在下一次调用中将作为起始位置.

这里有个SMC
BUUCTF reverse wp 91 - 95_第11张图片

这题基本就是动调, 一阶段是第一个SMC, 检测flag前5个字符"ACTF{", 二阶段是自修改出来的代码进行flag中第一部分字符的check和第二个SMC, 这里可以逐位cmp出来flag的第一部分yOu0y*
BUUCTF reverse wp 91 - 95_第12张图片

跟第二个SMC可以得到, flag的第二部分的处理代码和第三个SMC
BUUCTF reverse wp 91 - 95_第13张图片

三阶段继续跟SMC, 指令自修改后就是直接和5位字符比较, 得到第三部分flag为5mcsM<
二阶段的check代码是经过检索表处理, 动调拿到加密后的数据, 逆回去

table = [
	0xF6, 0xA3, 0x5B, 0x9D, 0xE0, 0x95, 0x98, 0x68, 0x8C, 0x65,
    0xBB, 0x76, 0x89, 0xD4, 0x09, 0xFD, 0xF3, 0x5C, 0x3C, 0x4C,
    0x36, 0x8E, 0x4D, 0xC4, 0x80, 0x44, 0xD6, 0xA9, 0x01, 0x32,
    0x77, 0x29, 0x90, 0xBC, 0xC0, 0xA8, 0xD8, 0xF9, 0xE1, 0x1D,
    0xE4, 0x67, 0x7D, 0x2A, 0x2C, 0x59, 0x9E, 0x3D, 0x7A, 0x34,
    0x11, 0x43, 0x74, 0xD1, 0x62, 0x60, 0x02, 0x4B, 0xAE, 0x99,
    0x57, 0xC6, 0x73, 0xB0, 0x33, 0x18, 0x2B, 0xFE, 0xB9, 0x85,
    0xB6, 0xD9, 0xDE, 0x7B, 0xCF, 0x4F, 0xB3, 0xD5, 0x08, 0x7C,
    0x0A, 0x71, 0x12, 0x06, 0x37, 0xFF, 0x7F, 0xB7, 0x46, 0x42,
    0x25, 0xC9, 0xD0, 0x50, 0x52, 0xCE, 0xBD, 0x6C, 0xE5, 0x6F,
    0xA5, 0x15, 0xED, 0x64, 0xF0, 0x23, 0x35, 0xE7, 0x0C, 0x61,
    0xA4, 0xD7, 0x51, 0x75, 0x9A, 0xF2, 0x1E, 0xEB, 0x58, 0xF1,
    0x94, 0xC3, 0x2F, 0x56, 0xF7, 0xE6, 0x86, 0x47, 0xFB, 0x83,
    0x5E, 0xCC, 0x21, 0x4A, 0x24, 0x07, 0x1C, 0x8A, 0x5A, 0x17,
    0x1B, 0xDA, 0xEC, 0x38, 0x0E, 0x7E, 0xB4, 0x48, 0x88, 0xF4,
    0xB8, 0x27, 0x91, 0x00, 0x13, 0x97, 0xBE, 0x53, 0xC2, 0xE8,
    0xEA, 0x1A, 0xE9, 0x2D, 0x14, 0x0B, 0xBF, 0xB5, 0x40, 0x79,
    0xD2, 0x3E, 0x19, 0x5D, 0xF8, 0x69, 0x39, 0x5F, 0xDB, 0xFA,
    0xB2, 0x8B, 0x6E, 0xA2, 0xDF, 0x16, 0xE2, 0x63, 0xB1, 0x20,
    0xCB, 0xBA, 0xEE, 0x8D, 0xAA, 0xC8, 0xC7, 0xC5, 0x05, 0x66,
    0x6D, 0x3A, 0x45, 0x72, 0x0D, 0xCA, 0x84, 0x4E, 0xF5, 0x31,
    0x6B, 0x92, 0xDC, 0xDD, 0x9C, 0x3F, 0x55, 0x96, 0xA1, 0x9F,
    0xCD, 0x9B, 0xE3, 0xA0, 0xA7, 0xFC, 0xC1, 0x78, 0x10, 0x2E,
    0x82, 0x8F, 0x30, 0x54, 0x04, 0xAC, 0x41, 0x93, 0xD3, 0x3B,
    0xEF, 0x03, 0x81, 0x70, 0xA6, 0x1F, 0x22, 0x26, 0x28, 0x6A,
    0xAB, 0x87, 0xAD, 0x49, 0x0F, 0xAF
]

m = [0x30,0x4,0x4,0x3,0x30,0x63]

flag = ''
for i in range(len(m)):
	flag+=chr(table.index(m[i])^(i+0x83))

print('flag{'+'yOu0y*_'+flag+'_5mcsM<}')

** 这个题出得挺好的, SMC嵌套, 可以锻炼动调能力

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