Geek2023部分Reverse与Pwn

Re

点击就送的逆向题

汇编,链接得到可执行文件

幸运数字

第三位要得到C,就要异或94

最后一位也是94

但直接输94是不对的

shiftjmp

经典花指令

砍树

Loadlibrary和native想到去看so文件

得到dest数组要动调so文件

小丑了dest前面有整体复制

easymath

从0矩阵变成单位阵,last也就是matrix的逆矩阵

flag的每一位都从table表里取

table表

flag的每一位对应table,取出下标后转为字符存到position

输入aaaa,得到6666

最后的last为7777

输入asdz,得到7,8,9,10,说明是下标+1

大致功能是在table里面找到对应的值,并取下标然后储存到position里面,接着再用这个下标在number里面取值存到last里面

有约束,防止多解

下面这种写法最容易理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from z3 import *
s = Solver()
x = [BitVec(f'x[{i}]', 8) for i in range(25)]
matrix = [18, 29, 16, 19, 27, 8, 31, 8, 23, 30, 29, 3, 28, 10, 21, 18, 29, 8, 16, 28, 11, 30, 7, 20, 7]
v7 = [0] * 25
for i in range(5):
for j in range(5):
for k in range(5):
v7[5 * i + j] = (v7[5 * i + j] + x[5 * i + k] * matrix[5 * k + j]) & 0x1F
if i == j:
s.add(v7[5 * i + j] == 1)
if i != j:
s.add(v7[5 * i + j] == 0)
if s.check() == sat:
m = s.model()
#print(m)
number = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 19, 22, 26, 27, 28, 29, 31, 32, 50, 51, 52, 53, 54, 55, 56]
for i in range(25):
for j in range(len(number)):
if m[x[i]] == number[j]:
print('01234_asdzxcpoityumnbAOZWXGMY'[j],end='')

c++

一开始无法调试

把libstdc++-6.dll放到当前目录

调试发现+=10

rdx恒为0xa

先^10,再-10

re虽然可以只根据关键代码猜出flag但是平时还是要提升审计能力的

v21作为输入,经过encode函数编码(经调试发现值并没变化),一个个添加到字符向量v16中去

迭代器k和m都指向v16,std::vector::operator[](v19, v25)表示整数向量 v19 中索引为 v25 的元素

flower_tea

有花指令,经典jz和jnz同时存在

先按U

E9下一行按C,然后nopjz,jnz和E9

把黄色的按C修复

后面十个左右花指令也是如此

效果

tea算法

key

v8是len,相当于外层循环38/2=19次

nop到位数据更加完整,可以直接看到key和密文数组

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
#include <stdio.h>
#include <stdint.h>
void tea(unsigned int num, uint32_t v[2], uint32_t const key[4])
{
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], sum = 0x31415927 * num, delta = 0x31415927 ;
for (i = 0; i < num; i++)
{
sum -= delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]) ^ sum;
}
v[0] = v0;
v[1] = v1;
}
int main()
{
unsigned int r = 54;
unsigned int k[4] = {32, 27, 39, 44};
uint32_t v[2];
char arr3[40];
uint32_t arr2[40] = {
2600027723, 3289888926, 2987894547, 3376130536, 2499011662, 3050056373, 1146217516, 2055874714,
1405669384, 1846639433, 2617235348, 1593781753, 401024305, 3753744761, 2407996218, 1944634796,
2995155110, 1526113129, 754440740, 880502447, 3116911968, 2434699567, 3176804251, 3415634746,
3315165374, 2684359657, 3241103012, 3733338640, 2697254292, 1132501052, 2117039688, 3847085193,
1059563152, 3045929369, 1615521047, 2626697604, 4108338305, 1022684671};
for (int i = 0; i < 38 /2; i++)
{
v[0] = arr2[i*2];
v[1] = arr2[(i*2) + 1];
tea(r, v, k);
arr3[i] = v[0];
arr3[38 - i - 1] = v[1];
}
for (int i = 0; i < 38; i++)
{
printf("%c", arr3[i]);
}
return 0;
}

浪漫至死不渝

点完爱心也没让我输密码

附件给的一堆音频也没用,毕竟不是misc,那就看代码,两百多行,第一眼是拒绝的,后来静下心就开始了

第一眼看到这个字符串,还以为直接就是密码

看到后面有比较,那就能找到密文了

也去看了加密的过程

发现text1是由函数生成的,怎么看名字像栅栏密码

先试试,这密文,那还真是

也可以js调试获取text1

接下来就是简单逆向了

小黄鸭

一眼pyinstaller

发现倒数第三位有问题,说明在线反编译有问题,其实猜也可以猜到是dream

用uncompyle6出来是or

rainbow

这种一堆while循环,一个错了就得退出,看着就烦

密文

下标整除3的时候加18

异或i

要去混淆,wp说是控制流平坦化,新知识来了😏

这种流程图就很典型

用D-810插件去ollvvm混淆,注意提前用idapyswitch选择3.7的python,可以看以下链接

https://www.yuque.com/u34082223/swqzq3/qr5reox5g6k3q9m3

myself

魔改rc4?

VirtualProtect函数可以修改某个数据段的权限,j将开始的0x8c个地址内存属性设为可读可写可执行

再调用sub_401010(),再sub_4013B0地址开始的0x8c个地址内存属性改回来

一开始是这样的,就感觉怪怪的

将4013B0起始处一直到第一个retn的汇编全部U掉,再转换成代码,创建函数

变成tea了

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
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <iostream>
using namespace std;

void decrypt(unsigned int *v) {
unsigned int v0 = v[0], v1 = v[1], sum = 0, delta = 0x61C88647;
sum = -(delta * 32);
for (size_t i = 0; i < 32; i++) {
v1 -= ((v0 >> 5) + 4) ^ (16 * v0 + 3) ^ (sum + v0);
v0 -= ((v1 >> 5) + 2) ^ (16 * v1 + 2) ^ (sum + v1);
sum += delta;
}
v[0] = v0;
v[1] = v1;
}

unsigned char a[41] = { 0xF0, 0xF9, 0xBD, 0xBD, 0xC4, 0x94, 0x61, 0xE2, 0x25, 0x91,
0x79, 0x80, 0x19, 0xC2, 0x0F, 0x1F, 0x15, 0x18, 0x6A, 0xEB,
0xC5, 0x72, 0xF5, 0x84, 0x85, 0x3A, 0xCC, 0x40, 0xBB, 0x2A,
0xA3, 0xD2
};

//unsigned int key[] = {5,20,13,14};

signed main() {
unsigned int *t = (unsigned int *)a;
for (int i = 0; i < 7; i += 2) {
decrypt(t + i);

}
for (int i = 0; i < 8; i++) {
printf("%c%c%c%c", *((char *)&t[i] + 0), *((char *)&t[i] + 1), *((char *)&t[i] + 2), *((char *)&t[i] + 3));
}
}
// SYC{H0w_7o_R@te_YOurs31f_iNtRo?}

是男人就来扎针-1

好像挺多算法

blowfish

md5或者sha系列

crc

whirlpool

感觉复杂,看wp了

unity游戏逆向,C#,所以用dnSpy打开文件夹中的Assembly-CSharp.dll,分析GameManager

根据点击次数异或

扎了100次

求md5

这个大小写有点恶心,最后flag是大写

还有师傅用的CE,第一次CE用到题目上

寻找初音未来-1

rc4之后直接去和密文比较

伪c和汇编的不一样

这里伪c可能不准,算法里看不到key

ezAndroid-1

在mainActivity找到密文和main函数

搜string

根据题目提示,往上翻得到tea

长度为24,奇数位放到str1,偶数位放到str2

总体思路:str2->ointArray->uobyteArray^str1->密文

GDA分析有点问题

str2->ointArray->uobyteArray->密文1

密文1^数组->密文2

jadx的tea效果比较好

tea的密文和key

按位运算,实质上是bytes数组转换成了int数组iArr

下面是int逆变换到bytes,由此也可猜上面的功能

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void decrypt(int *v, int *k)
{
int v0 = v[0], v1 = v[2], v2 = v[1], sum = 0x9E3779B9 * 64, i;
/* set up */
int delta = 0x9E3779B9;
/* a key schedule constant */
int k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
/* cache key */
for (i = 0; i < 32; i++)
{ /* basic cycle start */
v1 -= (((v2 << 4) + k2) ^ (v2 + sum)) ^ ((v2 >> 5) + k3);
v2 -= (((v1 << 4) + k0) ^ (v1 + sum)) ^ ((v1 >> 5) + k1);
sum -= delta;
}
for (i = 0; i < 32; i++)
{ /* basic cycle start */
v1 -= (((v0 << 4) + k2) ^ (v0 + sum)) ^ ((v0 >> 5) + k3);
v0 -= (((v1 << 4) + k0) ^ (v1 + sum)) ^ ((v1 >> 5) + k1);
sum -= delta;
}
v[0] = v0;
v[1] = v1;
v[2] = v2;
}
int main()
{
char encode1[12] = {-91, -8, -110, -55, -49, 75, 115, 13, -76,
-113, 102, 80};
char encode2[12] = {-107, -106, -95, -115, -119, 127, 26, 121, -62, -20, 86, 9};
int key[4] = {2023708229, -158607964, -2120859654, 1167043672};
char temp;
for (int j = 0; j < 12; j++)
{
encode2[j] = encode1[j] ^ encode2[j];
}
for (int i = 0; i < 3; i++)
{
temp = encode1[4 * i];
encode1[4 * i] = encode1[4 * i + 3];
encode1[4 * i + 3] = temp;
temp = encode1[4 * i + 1];
encode1[4 * i + 1] = encode1[4 * i + 2];
encode1[4 * i + 2] = temp;
}
int *flag1 = (int *)encode1;
decrypt(flag1, key);
for (int i = 0; i < 3; i++)
{
temp = encode1[4 * i];
encode1[4 * i] = encode1[4 * i + 3];
encode1[4 * i + 3] = temp;
temp = encode1[4 * i + 1];
encode1[4 * i + 1] = encode1[4 * i + 2];
encode1[4 * i + 2] = temp;
}
for (int i = 0; i < 12; i++)
{
putchar(encode1[i]);
putchar(encode2[i]);
}
system("pause");
return 0;
}
// T00nV3tD3F34Tint0vict0rY

AES?AES!-1

密文

明显的s盒

一开始是轮密钥(和s和异或),后面行位移和列混淆,两次行位移针对同一个数组,v6只不过是v5+64,也可以认为只有针对全部的一次操作

异或s盒得到密钥(调试的时候输入aaaaa.aaaalaaaaaa0aaaaaaaaaaaaaa)

行位移和列混淆都简化了

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
S = [0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB,
0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C,
0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5,
0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80,
0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B,
0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A,
0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33,
0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D,
0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13,
0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81,
0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x6, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4,
0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65,
0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74,
0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35,
0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6,
0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]
# 字节代换S表
key = [110, 121, 105, -125, 121,
127, 105, 117, 121, 120,
-127, 105, 93, 99, 77, 73]
for i in range(16):
key[i] -= 10
if key[i] < 0:
key[i] += 256
key[i] = key[i] & 0xff
# 密钥:do_you_konw_SYC?
key1 = []
for i in range(16):
key1.append(key[i] ^ S[key[i]] & 0xff)
# 密钥扩展
enc = [0xe0, 0x05, 0x6e, 0xc2, 0x6e,
0x99, 0x68, 0x45, 0x7d, 0x1f,
0x3f, 0xf9, 0x97, 0x76, 0x3b,
0x92, 0x2f, 0x44, 0x06, 0x67,
0xa8, 0xeb, 0xec, 0x4a, 0x6f,
0xe8, 0x35, 0xf9, 0xac, 0xa7,
0x8c, 0x71]


# 逆向行位移
def re_shiftrow(flag): # 右移动
for i in range(0, 4):
for _ in range(i):
for k in range(3):
flag[4 * i + 3 - k], flag[4 * i + 3 - k - 1] = flag[4 * i + 3 - k - 1], flag[4 * i + 3 - k]
flag[16 + 4 * i + 3 - k], flag[16 + 4 * i + 3 - k - 1] = flag[16 + 4 * i + 3 - k - 1], flag[
16 + 4 * i + 3 - k]


def re_tansform(flag):
for i in range(32):
flag[i] = S.index(flag[i])
v = []
for i in flag:
v.append(i)
n = 0
for j in range(4):
for k in range(4):
flag[n] = v[4 * k + j]
flag[n + 16] = v[16 + 4 * k + j]
n += 1


def byte_xor(flag, key):
for i in range(32):
flag[i] ^= key[i % 0x10]


# 异或密钥
def byte_trans(flag):
for i in range(32):
flag[i] = S.index(flag[i])


# 字节代换

# 下面是主函数
byte_xor(enc, key1)
re_shiftrow(enc)
byte_trans(enc)
byte_xor(enc, key)
re_tansform(enc)
re_shiftrow(enc)
byte_trans(enc)
flag = ''
for i in range(32):
if i == 5:
enc[i] = 46
if i == 10:
enc[i] = 108
if i == 17:
enc[i] = 48
flag += chr(enc[i])
print(flag)

#SYC{0.o_Thls_1s_n0t_A3s_(q^_^p)}

Geek2023部分Reverse与Pwn
https://j1ya-22.github.io/2023/11/26/Geek2023部分Reverse与Pwn/
作者
j1ya
发布于
2023年11月26日
许可协议