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
__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
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进制
__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
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;
}
__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字节为一组进行还原
__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]
'''
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)
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) #先序遍历输出
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
所以这里就是输出提示信息的函数, 下面的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() + '}')
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);
}
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_601060
data拿出来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;
}