IKUN题
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动态搜
第一个还是假的, 第二个解出来是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'))
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;
}
整体逻辑:
逆
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()))
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;
}
看起来基本是函数名, 变量名的混淆, 逻辑不复杂, 从后往前分析
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)
给了汇编文件的一部分, 和对应的结果
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
计算flag的长度
call std::basic_string < char,std::char_traits
构建一个数组
这里是下标为奇数时^0x42
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)
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, 检测flag前5个字符"ACTF{", 二阶段是自修改出来的代码进行flag中第一部分字符的check和第二个SMC, 这里可以逐位cmp出来flag的第一部分yOu0y*
跟第二个SMC可以得到, flag的第二部分的处理代码和第三个SMC
三阶段继续跟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嵌套, 可以锻炼动调能力