巅峰极客2021逆向wp

本文最后更新于:2021年8月3日 下午

baby_maze

没有迷宫数据,一堆函数调用,得写脚本跑了,使用idapython。

1
2
我们可以找到最后提示成功的函数,然后通过交叉引用获取上层调用的函数,一直追溯到开始,跑出函数调用流程。
对于获取WASD方向,分析函数时发现在调用方向函数时有switch case xx 的注释,直接去获取注释,即可得到路径。

image-20210803155926749

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
import hashlib

start_addr = 0x54de35 #提示成功的函数地址
end_addr = 0x40187c #迷宫开始的函数地址
call_path = []
md5 = hashlib.md5()
def search(call_addr, call_list, maze_path="S"): #因为0x40187前边还有一个S,所以这里先给个S
if call_addr == end_addr: #追溯到最初的函数时,进行提取WASD方向,并且计算flag
print("search success")
for i in range(len(call_path)-1, -1, -1):
switch = GetCommentEx(int(call_path[i], 16)-5, True) #通过注释获取switch case
case_num = int(switch[-2:], 10)
maze_path += chr(case_num)
md5.update(maze_path.encode("utf-8"))
print("flag{" + md5.hexdigest() + "}")
return

for refs in CodeRefsTo(call_addr, 0): #获取交叉引用的地址
fun_name = GetFunctionName(refs)
fun_addr = LocByName(fun_name) #获取交叉引用的地址所在的函数,并且得到地址,进行下一次交叉引用
if hex(fun_addr) in call_list: #判断此路径可否继续
continue
call_list.append(hex(fun_addr))
call_path.append(hex(refs))
search(fun_addr, call_list)
call_list.remove(hex(fun_addr))
call_path.remove(hex(refs))
cl = []
search(start_addr, cl)

image-20210803160610738

medical_APP

反编译,java没什么东西,直接看native层。

image-20210731182247701

dump比较的数据,进行xxtea解密。

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
#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9F5776B6
#define MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ ((sum ^ y) + (key[(p & 3) ^ e] ^ z)))

void btea(uint32_t *v, int n, uint32_t const key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 6 + 52 / n;
sum = DELTA;
z = v[n - 1];
do
{
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++)
{
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n - 1] += MX;
//printf("%x\n", y);
sum -= 0x60A8894A;
} while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 6 + 52 / n;
sum = rounds * DELTA;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum += 0x60A8894A;
} while (--rounds);
}
}

int main()
{
// uint32_t v[9] = {0x87e25a01, 0x3c4364d2, 0x0ec3cc97, 0xd06cbb92, 0xb8411653, 0x43e7378d, 0x52947a3b, 0x1e5abac4, 0xd75382e7};
uint32_t v[9] = {0xc5268710, 0x6d7b0e5e, 0xc5d265c7, 0xda3a935f, 0xa0c5a950, 0x2daeb502, 0x228e3628, 0x1db6ceb5, 0xd5386a5};
uint32_t ss[9] = {
0x68E5973E, 0xC20C7367, 0x98AFD41B, 0xFE4B9DE2, 0x01A5B60B, 0x3D36D646, 0xDBCC7BAF, 0xA0414F00,
0x762CE71A};
uint32_t const k[4] = {1, 0x10, 0x100, 0x1000};
int n = 9; //n的绝对值表示v的长度,取正表示加密,取负表示解密
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为432位无符号整数,即密钥长度为128
// printf("加密前原始数据:%x %x %x %x %x %x %x %x\n", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
//btea(v, n, k);
// printf("加密后的数据:%x %x %x %x %x %x %x %x\n", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
btea(ss, -n, k);
printf("解密后的数据:%x %x %x %x %x %x %x %x %x\n", ss[0], ss[1], ss[2], ss[3], ss[4], ss[5], ss[6], ss[7], ss[8]);
//printf("加密前原始数据:%x %x %x %x %x %x %x %x %x\n", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]);
return 0;
}

然后进行rc4解密。

image-20210731182357172

so_get_sourcecode

人麻了,逆向狗做web,还好知道一句话木马。蚁剑连接。

image-20210731200056596

看见flag.php激动了,将文件都下载下来,全是乱码。

估计是被加密了,搜索了半天,使用dezend解密,也不对,然后搜到了php_screw,好像有点思路了。

image-20210731200153176

加强版的,再搜,搜到了源码,真不错。

https://github.com/del-xiong/screw-plus

image-20210731200331762

好吧,,大部分时间在搭建这个web环境。最后整好了,解密,还是乱码,估计魔改了吧,去分析题目中的php_screw_plus.so。

通过逆向与源码对比,发现一下几处需要修改或添加:

image-20210731202702111

image-20210731202737305

最后的异或数据怎么得到:

分析teg_yek得到返回的数据,也就是最后要进行异或的数据。

image-20210803161620817

而如果要修改源码的话,buf和path两个变量的顺序一定要弄对了,否则会得到不确定的值,解密肯定会失败。

image-20210803161845783

修改源码进行再次编译。

image-20210731204057750