一些自认为典型的题

RE区

maze  GFSJ0497

接触到的第一道maze题
伪代码部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
signed __int64 i; // rbx
signed int chr; // eax
bool sign; // bp
bool sign1; // al
const char *v7; // rdi
__int64 matrix; // [rsp+0h] [rbp-28h]
matrix = 0LL;
puts("Input flag:");
scanf("%s", &input_flag_str, 0LL);
if ( strlen(&input_flag_str) != 24 || strncmp(&input_flag_str, "nctf{", 5uLL)
|| *(&byte_6010BF + 24) != '}' )
{
Wrong_jmp:
puts("Wrong flag!");
exit(-1);
}
i = 5LL;
if ( strlen(&input_flag_str) - 1 > 5 )
{
while ( 1 )
{
chr = *(&input_flag_str + i);
sign = 0;
if ( chr > 78 )
{
chr = (unsigned __int8)chr;
if ( (unsigned __int8)chr == 'O' )
{
sign1 = left((_DWORD *)&matrix + 1); // matrix 指针 + 1 就是旁边 的
dword 值 也就是 v9 的高8 位的值
goto LABEL_14;
}
if ( chr == 'o' )
{
// matrix 的低8位用来存储迷宫的行 高8位用来存储迷宫的列它是一个 __int64位的数据

方向函数matix
向左和向右操控的是高32位的值
sign1 = right((int *)&matrix + 1);
goto LABEL_14;
}
}
else
{
chr = (unsigned __int8)chr;
if ( (unsigned __int8)chr == '.' )
{
sign1 = up(&matrix);
goto LABEL_14;
}
if ( chr == '0' )
{
sign1 = down((int *)&matrix);
LABEL_14:
sign = sign1;
goto LABEL_15;
}
}
LABEL_15:
if ( !(unsigned __int8)sub_400690((__int64)maze_data, SHIDWORD(matrix),
matrix) )// 判断当前位置是否为0x20或0x23#不是则错误flag
goto Wrong_jmp;
if ( ++i >= strlen(&input_flag_str) - 1 ) // 当 长度 达到的时候
{
if ( sign )
break;
Wrong_Jmp1:
v7 = "Wrong flag!";
goto puts_wrong;
}
}
}
if ( maze_data[8 * (signed int)matrix + SHIDWORD(matrix)] != '#' )// 最后一层判断是否到达指定位置
goto Wrong_Jmp1;
v7 = "Congratulations!";
puts_wrong:
puts(v7);
return 0LL;
}

bool __fastcall left(_DWORD *a1)
{
}
int v1; // eax
v1 = (*a1)--;
return v1 > 0;
//对应 O
//高8 位-1迷宫向左移动一位
bool __fastcall right(int *a1) //对应 o
{
int v1; // eax
v1 = *a1 + 1;
*a1 = v1;
return v1 < 8;
}

bool __fastcall up(_DWORD *a1)
{
}
int v1; // eax
v1 = (*a1)--;
return v1 > 0;
//对应 .
bool __fastcall down(int *a1) //对应 0
{
int v1; // eax
v1 = *a1 + 1;
*a1 = v1;
return v1 < 8;
}

碰撞检测函数一眼就看得出来,不贴了
进去直接shift+F12查找字符串,找到迷宫数据
由于有64个字符,将其8*8分割画出迷宫
重点在于阅读移动函数,Oo0.确定上下左右
最后直接手写迷宫走出方法得wp

simple-unpack  NO.GFSJ0490

一道非常典型的UPX无魔改脱壳,可以留着作为upx范本文件一遍应付以后的魔改,也可以练习手动脱壳

方法1:upx脱壳软件一键脱壳,不多赘述

方法2:手动脱壳

打开x64dbg将文件拖入
找到文件开始行,在开头打上断点
开始动调,一步步往下直至有一大堆出栈行为的时候尝试脱壳
多次尝试后脱壳成功,拖入ida发现显示正常

getit  NO.GFSJ0495

一道经典的linux动调题
DIE查壳后用ida打开
进来先进入main函数扫一眼主要逻辑
看到关键函数fseek用来改变读写函数的位置指针
阅读代码逻辑可知 代码将flag赋值后remove掉
在remove上下断点动调发现输出一大堆
这些
号将原本应该输出的flag覆写
找到关键储存点t
在循环过程中关注t再次动调,发现flag

Valgrind  NO.GFSJ1148

分析文档写脚本
‘’’
s = “t1me_y0u_enj0y_wa5t1ng_wa5_not_wa5ted”
key = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”
flag = “”
for i in range(len(s)):
if(ord(s[i]) + 3 < 0x5a):
flag += chr(ord(s[i]) + 3 )
else:
flag += key[ (ord(s[i]) + 3 - 0x5a) % 0x1a -1 ]
print(flag)
‘’’

whats-the-hell-500  NO.GFSJ0124

有点意思
画了几个长方形和长方体
通过改代码,在每个等式后取值可得
p[0] + p[1] = 101
p[1] + p[2]= 143
p[0] * p[2] = 5035
p[3] + p[5] = 163
p[3] + p[4] = 226
p[4] * p[5] = 5814
p[7] + p[8] = 205
p[6] + p[8] = 173
p[6] * p[7] = 9744
p[9] + p[10] * p[11] = 5375
p[10] + p[9] * p[11] = 4670
p[9] + p[10] = 205
回到python用z3对等式求个解
就能求出所有p[]的值
最后可得flag:50_pr3TtYn_0

Android区

Android 2.0

入门Android逆向

用jadx打开apk,发现入口在

1744763232788

跟进,发现主要函数逻辑JNI在so层

用ida32打开lib中的so文件

直奔目标函数Java_com_example_test_ctf03_JNI_getResult

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
bool __fastcall Java_com_example_test_ctf03_JNI_getResult(int a1, int a2, int a3)
{
int v3; // r4
const char *v4; // r8
char *v5; // r6
char *v6; // r4
char *v7; // r5
int i; // r0
int j; // r0

v3 = 0;
v4 = (const char *)(*(int (__fastcall **)(int, int, _DWORD))(*(_DWORD *)a1 + 676))(a1, a3, 0);
if ( strlen(v4) == 15 )
{
v5 = (char *)malloc(1u);
v6 = (char *)malloc(1u);
v7 = (char *)malloc(1u);
Init(v5, v6, v7, v4, 15);
if ( !First(v5) )
return 0;
for ( i = 0; i != 4; ++i )
v6[i] ^= v5[i];
if ( !strcmp(v6, a5) )
{
for ( j = 0; j != 4; ++j )
v7[j] ^= v6[j];
return strcmp(v7, "AFBo}") == 0;
}
else
{
return 0;
}
}
return v3;
}

跟进Init函数

发现就是将整段字符串以3个字符为一次循环分给v5,v6,v7

分别跟进First,Second,Third

发现均为简单的单个字符逻辑运算

根据伪代码写出脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
a="LN^dl"
flag=""
for i in range(0,len(a)-1):
flag=flag + chr((ord(a[i]) ^ 0x80) // 2)
flag=flag+a[-1]
print(flag)

a5=[ord(' '),ord('5'),ord('-'),0x16,ord('a')]
v5="fgorl"
v6=""
for i in range(4):
v6=v6+chr(a5[i] ^ ord(a[i]))
v6=v6+'a'
print(v6)

v7=""
a7="AFBo}"
for i in range(0,len(a7)-1):
v7=v7+chr(ord(a7[i]) ^ a5[i])
v7=v7+a7[-1]
print(v7)

for i in range(0,len(a7)):
print(v5[i],end="")
print(v6[i],end="")
print(v7[i],end="")

运行可得flag{sosorryla}