D3CTF 2023 RE Writeup

本文最后更新于 2024年1月4日 凌晨

D3CTF 2023 Reverse 题解

d3RC4

涉及知识

  • 子进程调试
  • RC4
  • 管道读写

分析

通过对比算法,得到 main 函数的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int i; // [rsp+8h] [rbp-8h]
int j; // [rsp+Ch] [rbp-4h]

pipe(pipedes);
__isoc99_scanf(&format, input);
input_len = strlen(input);
RC4_init(::a1);
RC4_init0(::a1, ::a2, ::a3);
RC4_crypt(::a1, input_len, xor_data);
for ( i = 0; i < input_len; ++i )
input[i] ^= xor_data[i];
for ( j = 0; j < input_len; ++j )
{
if ( input[j] != cmp_data_0[j] )
exit(1);
}
return 0LL;
}

实际调试过程中,发现main 函数执行之后,又会执行其他函数

1
2
3
4
5
_init_array和_fini_array中的函数分别会在main函数之前和之后被调用执行。

_init_array里sub_1A20函数做了一些变量的初始化和字符串的解密。

_fini_array里sub_16C5函数是题目主要逻辑

函数 sub_16c5 里面用了子进程进行了最后的加密和检验

如果只看加密操作,那基本就全是 Xor 操作

调试子进程求解

因为加密的操作基本都是固定值加密,所以可以尝试提取数据,然后进行异或还原
这里的难点就是进行子进程调试。

详细记录一下子进程调试的过程 首先,在第一个 fork 函数处打上断点

断下来之后,在子进程第一个代码块上patch 一个死循环

call RC4_init0 patch 为 jmp 0x55CBB4614875 ,即始终跳转到第一条指令
反调试得到的代码也出现了 while(1)
\

然后直接 F9 ,让程序一直跑,此时Debugger -> Detach The process
然后在刚刚我们修改的地方打上断点,然后再 Attach 上进程

断下来后,将指令改回去

此时就可以调试子进程了 提取出数据之后,逆向异或就可以得到 flag 了

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
#include <iostream>
#include <iomanip>
using namespace std;
#define LEN 36
void de_xor(unsigned char (&arr)[LEN],const unsigned char (&key)[LEN]){
int i,k;
for(i=LEN-2; i>=0; i -= 2){
arr[i+1] = arr[i] - (key[i+1] ^ arr[i+1]);
arr[i] = (arr[i] ^ key[i]) - arr[i+1];
}

}
void en_xor(unsigned char (&arr)[LEN], const unsigned char (&key)[LEN]){
for(int j=0; j<LEN; j += 2){
arr[j] = (arr[j] + arr[j + 1]) ^ key[j];
arr[j + 1] = key[j + 1] ^ (arr[j] - arr[j + 1]);
}
}
void xor_de(unsigned char (&arr)[LEN], unsigned char (&key)[LEN]){
for(int i=0; i< LEN ; i++){
arr[i] ^= key[i];
}
}
void print_state(unsigned char* arr, int len)
{
for(int i=0; i<len; i++){
// cout << setfill('0') << setw(2) << hex << (int)*(arr+i) << " ";
cout << *(arr+i);
}
cout << endl;
}

int main(){
unsigned char en_data[] = {0x75, 0xF5, 0x67, 0x75, 0x65, 0x2C, 0x74, 0x21, 0x1C, 0x5A, 0x02, 0x80, 0x3F, 0x94, 0x5A, 0x9A, 0x19, 0x04, 0xBA, 0xA2, 0x3D, 0x73, 0xBE, 0xC1, 0xFC, 0x09, 0x34, 0xD0, 0x70, 0xF3, 0x0D, 0x7B, 0x84, 0x1B, 0xBC, 0x83};
const unsigned char key[] = {0x35, 0x4B, 0xA0, 0x60, 0x08, 0x50, 0xA5, 0xF1, 0x33, 0x97, 0xB2, 0x13, 0xCB, 0x4C, 0x0D, 0xCF, 0xA3, 0x7C, 0x57, 0x53, 0xE2, 0xA9, 0x65, 0x4E, 0x0E, 0xC7, 0x7A, 0x0F, 0xFD, 0xB5, 0x9E, 0xB4, 0x33, 0xF9, 0x61, 0xD3};
unsigned char de_data_0[] = {0xF7, 0x5F, 0xE7, 0xB0, 0x9A, 0xB4, 0xE0, 0xE7, 0x9E, 0x05, 0xFE, 0xD8, 0x35, 0x5C, 0x72, 0xE0, 0x86, 0xDE, 0x73, 0x9F, 0x9A, 0xF6, 0x0D, 0xDC, 0xC8, 0x4F, 0xC2, 0xA4, 0x7A, 0xB5, 0xE3, 0xCD, 0x60, 0x9D, 0x04, 0x1F};

de_xor(de_data_0, key);


unsigned char input[] = {0x89, 0xB7, 0x75, 0x52, 0x84, 0xE9, 0x2D, 0xA4, 0xE0, 0x4F, 0x41, 0x6F, 0x8D, 0x67, 0x52, 0x05, 0x19, 0xA1, 0x24, 0xC9, 0x7C, 0x63, 0xAC, 0x2F, 0xC4, 0x2E, 0xF9, 0x55, 0x63, 0x2A, 0x55, 0x3E, 0x15, 0xA2, 0x71, 0x6C};
unsigned char key_1[] = {0xB8, 0x86, 0x44, 0x63, 0xB5, 0xD8, 0x1C, 0x95, 0xD1, 0x7E, 0x70, 0x5E, 0xBC, 0x56, 0x63, 0x34, 0x28, 0x90, 0x15, 0xF8, 0x4D, 0x52, 0x9D, 0x1E, 0xF5, 0x1F, 0xC8, 0x64, 0x52, 0x1B, 0x64, 0x0F, 0x24, 0x93, 0x40, 0x5D};
xor_de(de_data_0, key_1);
print_state(de_data_0, 36);


return 0;
}

爆破求解

这是官方wp
给出的解法,前提是在看懂算法的情况下还原加密逻辑,省去素数筛部分代码,爆破可见字符

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char enc[] = {247, 95, 231, 176, 154, 180, 224, 231, 158, 5, 254, 216, 53, 92, 114, 224, 134, 222, 115, 159, 154, 246, 13, 220, 200, 79, 194, 164, 122, 181, 227, 205, 96, 157, 4, 31};
unsigned char rc4_s[256];
unsigned char rc4_key[] = "We1c0m3_t0_d^3ctf";

void rc4_init_s(unsigned char *s) {
for (int i = 0; i < 256; i++) {
s[i] = i;
}
}

void rc4_shuffle(unsigned char *s, unsigned char *key, int key_len) {
int j = 0;
for (int i = 0; i < 256; i++) {
j = (j + s[i] + key[i%key_len])%256;
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}

void rc4_gen_keystream(unsigned char *s, int len, unsigned char *key_stream) {
int i = 0, j = 0, cnt = -1;
while (len) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
int tmp = s[i];
s[i] = s[j];
s[j] = tmp;
key_stream[++cnt] = s[(s[i] + s[j]) % 256];
len -= 1;
}
}

int main() {
unsigned char keystream1[50];
unsigned char keystream[50];
rc4_init_s(rc4_s);
rc4_shuffle(rc4_s, rc4_key, 17);
rc4_gen_keystream(rc4_s, 36, keystream1);
// keystream1: 184, 134, 68, 99, 181, 216, 28, 149, 209, 126, 112, 94, 188, 86, 99, 52, 40, 144, 21, 248, 77, 82, 157, 30, 245, 31, 200, 100, 82, 27, 100, 15, 36, 147, 64, 93
unsigned char primes[] = {3, 5, 7, 11, 13, 17, 19, 23, 29, 31};
memcpy(rc4_key+17, primes, 10);
rc4_shuffle(rc4_s, rc4_key, 27);
for (int i = 0; i < 17; i++) {
rc4_gen_keystream(rc4_s, 36, keystream);
}
// keystream: 53, 75, 160, 96, 8, 80, 165, 241, 51, 151, 178, 19, 203, 76, 13, 207, 163, 124, 87, 83, 226, 169, 101, 78, 14, 199, 122, 15, 253, 181, 158, 180, 51, 249, 97, 211
for (int i = 0; i < 36; i += 2) {
for (unsigned char a1 = 0; a1 < 0xff; a1++) {
for (unsigned char a2 = 0; a2 < 0xff; a2++) {
unsigned char a10 = a1;
unsigned char a20 = a2;
a1 = a1 ^ keystream1[i];
a2 = a2 ^ keystream1[i+1];
a1 = (a1 + a2) ^ keystream[i];
a2 = (a1 - a2) ^ keystream[i+1];
if ( a1 == enc[i] && a2 == enc[i+1]) {
printf("%c%c", a10, a20);
}
a1 = a10;
a2 = a20;
}
}
}

}

d3syscall

涉及知识

  • syscall
  • 虚拟机
  • shell 命令

分析

这道题同样也在 init_array 处进行了修改
断在
sub_1830 的最后,查看寄存器地址,发现了一些路径字符串

程序首先从/proc/kallsyms中获取了系统调用表的地址,通过参数传递到内核模块中
我们将 my_module 复制过来

1
cp /tmp/my_module /mnt/d/CTF/d^3ctf/d3syscall_attachment2/my_module

在这里面找到了一些调用号相关的

如果只看这个的话,还是有点抽象了
我们可以通过Linux 自带命令 strace 打印出syscall 调用情况: 先运行程序

1
sudo ./d3syscall

查看进程,发现有三个

1
ps -ef

strace 查看 ./d3syscall

1
sudo strace -p 1467 -o 1.txt

得到

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
read(0, "11111111111111111111111111\n", 1024) = 27
syscall_0x14f(0x1, 0, 0x3131313131313131, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x3131313131313131, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0x1, 0x3131313131313131, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x2, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x4, 0x2, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x51e7647e, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x2, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x2, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0xe0b4140a, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0xe6978f27, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x152(0x1, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x1, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0x1, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x2, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x6, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x4, 0x2, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x53a35337, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x2, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x5, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x2, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x9840294d, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x5eae4751, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x1, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x152(0, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x153(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x3131313131313131, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x3131, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0x1, 0x3131, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x2, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x4, 0x2, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x51e7647e, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x2, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x2, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0xe0b4140a, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0xe6978f27, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x152(0x1, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x1, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0x1, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x2, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x6, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x4, 0x2, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x53a35337, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x2, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x5, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x2, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x9840294d, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x5eae4751, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x1, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x152(0, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x153(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0x1, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x2, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x4, 0x2, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x51e7647e, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x2, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x2, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0xe0b4140a, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0x1, 0xe6978f27, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x152(0x1, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x1, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0x1, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x2, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x6, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x4, 0x2, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x53a35337, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x2, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x5, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x2, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x9840294d, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0, 0x3, 0x1, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x14f(0x1, 0, 0x5eae4751, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x1, 0x3, 0, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0x3, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x152(0, 0x2, 0x3, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x150(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x151(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x153(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
syscall_0x154(0, 0, 0x2, 0xffffffffffffff80, 0, 0x55c3d6f28890) = -1 ENOSYS (Function not implemented)
newfstatat(1, "", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0xb), ...}, AT_EMPTY_PATH) = 0
unlink("/tmp/my_module") = -1 ENOENT (No such file or directory)
delete_module("my_module", O_NONBLOCK) = -1 ENOENT (No such file or directory)
write(1, "Congratulations!", 16) = 16
lseek(0, -1, SEEK_CUR) = -1 ESPIPE (Illegal seek)
exit_group(0) = ?
+++ exited with 0 +++

这样就得到了一个完整的记录 结合上面,分析这几个调用号所代表的含义。

既然是个虚拟机,至少得有栈和寄存器 我们以此来分析 首先通过特折最明显reset 来确定 寄存器

1
2
3
4
5
6
7
8
9
10
11
__int64 reset()
{
__int64 result; // rax

result = _fentry__();
reg[0] = 0LL;
reg[1] = 0LL;
reg[2] = 0LL;
reg[3] = 0LL;
return result;
}

随后通过 check 函数确定 stack

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
void __fastcall check()
{
__int64 v0; // rbx
unsigned __int64 v1; // rsi
__int64 v2; // r12
unsigned __int64 v3; // [rsp-50h] [rbp-50h]
__int64 v4; // [rsp-48h] [rbp-48h]
__int64 v5; // [rsp-40h] [rbp-40h]
unsigned __int64 v6; // [rsp-38h] [rbp-38h]
__int64 v7; // [rsp-30h] [rbp-30h]
__int64 v8; // [rsp-28h] [rbp-28h]
unsigned __int64 v9; // [rsp-20h] [rbp-20h]
__int64 v10; // [rsp-8h] [rbp-8h] BYREF

_fentry__();
v0 = 1LL;
v9 = __readgsqword(0x28u);
v3 = 0xB0800699CB89CC89LL;
v4 = 0x4764FD523FA00B19LL;
v5 = 0x396A7E6DF099D700LL;
v6 = 0xB115D56BCDEAF50ALL;
v7 = 0x2521513C985791F4LL;
v8 = 0xB03C06AF93AD0BELL;
while ( 1 )
{
v1 = (int)v0 - 1;
if ( v1 > 5 )
_ubsan_handle_out_of_bounds(&off_1880, v1);
v2 = *(&v10 + v0 - 10);
if ( (unsigned __int64)(int)v0 > 0x27 )
_ubsan_handle_out_of_bounds(&off_1860, (int)v0);
if ( v2 != stack[v0] ) // 比较数据累加时,不可能是对寄存器操作,所以应该是 stack
break;
if ( ++v0 == 7 )
{
reg[0] = 0LL;
reg[1] = 0LL;
reg[2] = 0LL;
reg[3] = 0LL;
reg[5] = 0LL;
return;
}
}
}

逐条分析之后得到

1
2
3
4
5
6
::v4[0x14F] = mov;
v4[0x150] = alu; // 运算器
v4[0x151] = push;
v4[0x152] = pop;
v4[0x153] = reset;
v4[0x154] = check;

写出对应的函数 这里用 python
写出这个过程呢,不太一定能一次成功,因为代码量不太多,我们可以尝试先不直接还原代码,而是打印出每个指令,然后逆向分析

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# 全局变量
reg = [0, 0, 0, 0, 0, 0]
stack = [0 for i in range(1000)]

def syscall_mov(a1, a2, a3):
if a1 == 1:
print(f'mov reg[{a2}], {a3}' )
else:
print(f'mov reg[{a2}], reg[{a3}]' )


def syscall_alu(a1, a2, a3):
if a1 == 1:
print(f'sub reg[{a2}], reg[{a3}] ')
elif a1 == 2:
print(f'mul reg[{a2}], reg[{a3}] ')

elif a1 == 3:
print(f'xor reg[{a2}], reg[{a3}]')
elif a1 == 4:
print(f'shl reg[{a2}], reg[{a3}]')
elif a1 == 5:
print(f'shr reg[{a2}], reg[{a3}]')
else:
print(f'add reg[{a2}], reg[{a3}]')

def syscall_push(a1, a2, a3):
if a1:
print(f'push reg[{a2}]')
else:
print(f'push {a2}')

def syscall_pop(a1, a2, a3):
print(f'pop reg[{a1}]')

def syscall_reset(a1, a2, a3):
print('reset')
for i in range(4):
reg[i] = 0

def syscall_check(a1, a2, a3):
print('check')
cmp_data = [0xB0800699CB89CC89, 0x4764FD523FA00B19, 0x396A7E6DF099D700, 0xB115D56BCDEAF50A, 0x2521513C985791F4, 0xB03C06AF93AD0BE]
for i in range(6):
if(cmp_data[i] == stack[i]):
break
syscall_reset(a1, a2, a3)

def main():
syscall_mov(0x1, 0, 0x3837363534333231)
syscall_mov(0x1, 0x1, 0x6867666564636261)
syscall_push(0, 0x1, 0x6867666564636261)
syscall_mov(0, 0x2, 0)
syscall_mov(0x1, 0x1, 0x3)
syscall_alu(0x4, 0x2, 0x1)
syscall_mov(0x1, 0x1, 0x51e7647e)
syscall_alu(0, 0x2, 0x1)
syscall_mov(0, 0x3, 0)
syscall_mov(0x1, 0x1, 0x3)
syscall_alu(0x2, 0x3, 0x1)
syscall_mov(0x1, 0x1, 0xe0b4140a)
syscall_alu(0, 0x3, 0x1)
syscall_alu(0x3, 0x2, 0x3)
syscall_mov(0, 0x3, 0)
syscall_mov(0x1, 0x1, 0xe6978f27)
syscall_alu(0, 0x3, 0x1)
syscall_alu(0x3, 0x2, 0x3)
syscall_pop(0x1, 0x2, 0x3)
syscall_alu(0, 0x1, 0x2)
syscall_push(0, 0x1, 0x2)
syscall_push(0, 0, 0x2)
syscall_mov(0, 0x2, 0x1)
syscall_mov(0x1, 0, 0x6)
syscall_alu(0x4, 0x2, 0)
syscall_mov(0x1, 0, 0x53a35337)
syscall_alu(0, 0x2, 0)
syscall_mov(0, 0x3, 0x1)
syscall_mov(0x1, 0, 0x5)
syscall_alu(0x2, 0x3, 0)
syscall_mov(0x1, 0, 0x9840294d)
syscall_alu(0, 0x3, 0)
syscall_alu(0x3, 0x2, 0x3)
syscall_mov(0, 0x3, 0x1)
syscall_mov(0x1, 0, 0x5eae4751)
syscall_alu(0x1, 0x3, 0)
syscall_alu(0x3, 0x2, 0x3)
syscall_pop(0, 0x2, 0x3)
syscall_alu(0, 0, 0x2)
syscall_push(0, 0, 0x2)
syscall_reset(0, 0, 0x2)
syscall_mov(0x1, 0, 0x3132333435363738)
syscall_mov(0x1, 0x1, 0x6162636465666768)
syscall_push(0, 0x1, 0x6162636465666768)
syscall_mov(0, 0x2, 0)
syscall_mov(0x1, 0x1, 0x3)
syscall_alu(0x4, 0x2, 0x1)
syscall_mov(0x1, 0x1, 0x51e7647e)
syscall_alu(0, 0x2, 0x1)
syscall_mov(0, 0x3, 0)
syscall_mov(0x1, 0x1, 0x3)
syscall_alu(0x2, 0x3, 0x1)
syscall_mov(0x1, 0x1, 0xe0b4140a)
syscall_alu(0, 0x3, 0x1)
syscall_alu(0x3, 0x2, 0x3)
syscall_mov(0, 0x3, 0)
syscall_mov(0x1, 0x1, 0xe6978f27)
syscall_alu(0, 0x3, 0x1)
syscall_alu(0x3, 0x2, 0x3)
syscall_pop(0x1, 0x2, 0x3)
syscall_alu(0, 0x1, 0x2)
syscall_push(0, 0x1, 0x2)
syscall_push(0, 0, 0x2)
syscall_mov(0, 0x2, 0x1)
syscall_mov(0x1, 0, 0x6)
syscall_alu(0x4, 0x2, 0)
syscall_mov(0x1, 0, 0x53a35337)
syscall_alu(0, 0x2, 0)
syscall_mov(0, 0x3, 0x1)
syscall_mov(0x1, 0, 0x5)
syscall_alu(0x2, 0x3, 0)
syscall_mov(0x1, 0, 0x9840294d)
syscall_alu(0, 0x3, 0)
syscall_alu(0x3, 0x2, 0x3)
syscall_mov(0, 0x3, 0x1)
syscall_mov(0x1, 0, 0x5eae4751)
syscall_alu(0x1, 0x3, 0)
syscall_alu(0x3, 0x2, 0x3)
syscall_pop(0, 0x2, 0x3)
syscall_alu(0, 0, 0x2)
syscall_push(0, 0, 0x2)
syscall_reset(0, 0, 0x2)
syscall_mov(0x1, 0, 0x4847464544434241)
syscall_mov(0x1, 0x1, 0x4142434445464847)
syscall_push(0, 0x1, 0x4142434445464847)
syscall_mov(0, 0x2, 0)
syscall_mov(0x1, 0x1, 0x3)
syscall_alu(0x4, 0x2, 0x1)
syscall_mov(0x1, 0x1, 0x51e7647e)
syscall_alu(0, 0x2, 0x1)
syscall_mov(0, 0x3, 0)
syscall_mov(0x1, 0x1, 0x3)
syscall_alu(0x2, 0x3, 0x1)
syscall_mov(0x1, 0x1, 0xe0b4140a)
syscall_alu(0, 0x3, 0x1)
syscall_alu(0x3, 0x2, 0x3)
syscall_mov(0, 0x3, 0)
syscall_mov(0x1, 0x1, 0xe6978f27)
syscall_alu(0, 0x3, 0x1)
syscall_alu(0x3, 0x2, 0x3)
syscall_pop(0x1, 0x2, 0x3)
syscall_alu(0, 0x1, 0x2)
syscall_push(0, 0x1, 0x2)
syscall_push(0, 0, 0x2)
syscall_mov(0, 0x2, 0x1)
syscall_mov(0x1, 0, 0x6)
syscall_alu(0x4, 0x2, 0)
syscall_mov(0x1, 0, 0x53a35337)
syscall_alu(0, 0x2, 0)
syscall_mov(0, 0x3, 0x1)
syscall_mov(0x1, 0, 0x5)
syscall_alu(0x2, 0x3, 0)
syscall_mov(0x1, 0, 0x9840294d)
syscall_alu(0, 0x3, 0)
syscall_alu(0x3, 0x2, 0x3)
syscall_mov(0, 0x3, 0x1)
syscall_mov(0x1, 0, 0x5eae4751)
syscall_alu(0x1, 0x3, 0)
syscall_alu(0x3, 0x2, 0x3)
syscall_pop(0, 0x2, 0x3)
syscall_alu(0, 0, 0x2)
syscall_push(0, 0, 0x2)
syscall_reset(0, 0, 0x2)
syscall_check(0, 0, 0x2)

if __name__ == '__main__':
main()

得到

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
mov reg[0], 4050765991979987505
mov reg[1], 7523094288207667809
push 1
mov reg[2], reg[0]
mov reg[1], 3
shl reg[2], reg[1]
mov reg[1], 1374119038
add reg[2], reg[1]
mov reg[3], reg[0]
mov reg[1], 3
mul reg[3], reg[1]
mov reg[1], 3769897994
add reg[3], reg[1]
xor reg[2], reg[3]
mov reg[3], reg[0]
mov reg[1], 3868692263
add reg[3], reg[1]
xor reg[2], reg[3]
pop reg[1]
add reg[1], reg[2]
push 1
push 0
mov reg[2], reg[1]
mov reg[0], 6
shl reg[2], reg[0]
mov reg[0], 1403212599
add reg[2], reg[0]
mov reg[3], reg[1]
mov reg[0], 5
mul reg[3], reg[0]
mov reg[0], 2554341709
add reg[3], reg[0]
xor reg[2], reg[3]
mov reg[3], reg[1]
mov reg[0], 1588479825
sub reg[3], reg[0]
xor reg[2], reg[3]
pop reg[0]
add reg[0], reg[2]
push 0
reset
mov reg[0], 3544952156018063160
mov reg[1], 7017280452245743464
push 1
mov reg[2], reg[0]
mov reg[1], 3
shl reg[2], reg[1]
mov reg[1], 1374119038
add reg[2], reg[1]
mov reg[3], reg[0]
mov reg[1], 3
mul reg[3], reg[1]
mov reg[1], 3769897994
add reg[3], reg[1]
xor reg[2], reg[3]
mov reg[3], reg[0]
mov reg[1], 3868692263
add reg[3], reg[1]
xor reg[2], reg[3]
pop reg[1]
add reg[1], reg[2]
push 1
push 0
mov reg[2], reg[1]
mov reg[0], 6
shl reg[2], reg[0]
mov reg[0], 1403212599
add reg[2], reg[0]
mov reg[3], reg[1]
mov reg[0], 5
mul reg[3], reg[0]
mov reg[0], 2554341709
add reg[3], reg[0]
xor reg[2], reg[3]
mov reg[3], reg[1]
mov reg[0], 1588479825
sub reg[3], reg[0]
xor reg[2], reg[3]
pop reg[0]
add reg[0], reg[2]
push 0
reset
mov reg[0], 5208208757389214273
mov reg[1], 4702394921427290183
push 1
mov reg[2], reg[0]
mov reg[1], 3
shl reg[2], reg[1]
mov reg[1], 1374119038
add reg[2], reg[1]
reset
check
reset

分析后,每次加密是这样的

1
2
b += ((a << 3) + 1374119038) ^ (a * 3 + 3769897994) ^ (a + 3868692263)
a += ((b << 6) + 1403212599) ^ (b * 5 + 2554341709) ^ (b - 1588479825)

注意这里的 a b 并不是按顺序来的,而是传参顺序,也就是 b对应 arr[i],
a对应arr[i+1]

解密

因为参与 a 加密的b是已经加密的结果,所以解密只需要简单的调换顺序,加号变减号就行了

用 C++ 会比较好

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;
void decode(uint64_t &a, uint64_t &b){
a -= ((b << 6) + 1403212599) ^ (b * 5 + 2554341709) ^ (b - 1588479825);
b -= ((a << 3) + 1374119038) ^ (a * 3 + 3769897994) ^ (a + 3868692263);

printf("%.8s%.8s", &a, &b);

}
int main(){
uint64_t cmp_data[] = {0xB0800699CB89CC89, 0x4764FD523FA00B19, 0x396A7E6DF099D700, 0xB115D56BCDEAF50A, 0x2521513C985791F4, 0xB03C06AF93AD0BE};
for(int i=0; i<6; i+=2){
decode(cmp_data[i+1], cmp_data[i]);
}
return 0;
}

得到 flag

1
d3ctf{cef9b994-2547-4844-ac0d-a097b75806a0}

还有其他师傅是直接还原整个逻辑,然后用z3进行解题的

d3recover

涉及知识

  • 符号恢复
  • Bindiff

分析

给了两个附件 分别用 ida 打开,发现 1.0 是去掉了符号的,而 2.0 保留了符号
用 Bindiff 恢复 1.0 的符号 恢复之后,通过字符串关键字 check ,可以找到check 函数

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    Py_XDECREF(Item);
Py_XDECREF(v16);
Py_XDECREF(v17);
_Pyx_AddTraceback("d3recover_ver1.check", v7, v6, v18);
v11 = 0LL;
goto LABEL_61;
}
if ( v19 == 32 )
{
Item = _Pyx_PyObject_CallNoArg(&unk_A7B7A0);
if ( !Item )
{
v18 = str_d3recover_ver1_py;
v6 = 32;
v7 = 2109;
goto LABEL_60;
}
v9 = Item;
Item = 0LL;
for ( i = 0LL; i <= 31; ++i )
{
Item = _Pyx_PyInt_From_long(i);
if ( !Item )
{
v18 = str_d3recover_ver1_py;
v6 = 33;
v7 = 2122;
goto LABEL_60;
}
v23 = v10;
v10 = Item;
Py_XDECREF(v23);
Item = _Pyx_PyObject_GetItem(a2, Item);
if ( !Item )
{
v18 = str_d3recover_ver1_py;
v6 = 34;
v7 = 2134;
goto LABEL_60;
}
if ( (unsigned int)PyType_HasFeature(*(_QWORD *)(Item + 8), 0x10000000LL) )
v2 = (unsigned int)sub_5A374B(Item);
else
v2 = sub_5A3D44(Item);
v24 = v2;
if ( v2 == 0xFFFFFFFFLL )
{
v18 = str_d3recover_ver1_py;
v6 = 34;
v7 = 2136;
goto LABEL_60;
}
Py_DECREF(Item);
Item = 0LL;
if ( (unsigned int)_Pyx_PyByteArray_Append(v9, v24 ^ 0x23u) == -1 )
{
v18 = str_d3recover_ver1_py;
v6 = 34;
v7 = 2138;
goto LABEL_60;
}
}
for ( j = 0LL; j <= 29; ++j )
{
Item = _Pyx_PyInt_From_long(j);
if ( !Item )
{
v18 = str_d3recover_ver1_py;
v6 = 35;
v7 = 2149;
goto LABEL_60;
}
v22 = v10;
v10 = Item;
Py_XDECREF(v22);
Item = _Pyx_PyObject_GetItem(v9, Item);
if ( !Item )
{
v18 = str_d3recover_ver1_py;
v6 = 36;
v7 = 2161;
goto LABEL_60;
}
v16 = _Pyx_PyInt_AddObjC(v10, qword_ABC1E8, 2LL, 0LL, 0LL);
if ( !v16 )
{
v18 = str_d3recover_ver1_py;
v6 = 36;
v7 = 2163;
goto LABEL_60;
}
v17 = _Pyx_PyObject_GetItem(v9, v16);
if ( !v17 )
{
v18 = str_d3recover_ver1_py;
v6 = 36;
v7 = 2165;
goto LABEL_60;
}
Py_DECREF(v16);
v16 = sub_4E0BB0(Item, v17);
if ( !v16 )
{
v18 = str_d3recover_ver1_py;
v6 = 36;
v7 = 2168;
goto LABEL_60;
}
Py_DECREF(Item);
Item = 0LL;
Py_DECREF(v17);
v17 = _Pyx_PyInt_AndObjC(v16, qword_ABC220, 255LL, 0LL, 0LL);
if ( !v17 )
{
v18 = str_d3recover_ver1_py;
v6 = 36;
v7 = 2172;
goto LABEL_60;
}
Py_DECREF(v16);
v16 = _Pyx_PyInt_XorObjC(v17, qword_ABC218, 84LL, 0LL, 0LL);
if ( !v16 )
{
v18 = str_d3recover_ver1_py;
v6 = 36;
v7 = 2175;
goto LABEL_60;
}
Py_DECREF(v17);
v17 = 0LL;
if ( (int)PyObject_SetItem(v9, v10, v16) < 0 )
{
v18 = str_d3recover_ver1_py;
v6 = 36;
v7 = 2178;
goto LABEL_60;
}
Py_DECREF(v16);
v16 = 0LL;
}
if ( *(_QWORD *)(qword_ABC050 + 24) == qword_ABC2A0 )
{
if ( qword_ABC2A8 )
{
Py_INCREF(qword_ABC2A8);
BuiltinName = qword_ABC2A8;
}
else
{
BuiltinName = _Pyx_GetBuiltinName(qword_ABC0E0);
}
}
else
{
BuiltinName = _Pyx__GetModuleGlobalName(qword_ABC0E0, &qword_ABC2A0, &qword_ABC2A8);
}
v17 = BuiltinName;
if ( !BuiltinName )
{
v18 = str_d3recover_ver1_py;
v6 = 37;
v7 = 2189;
goto LABEL_60;
}
v13 = 0LL;
if ( (unsigned int)Py_IS_TYPE(BuiltinName, &unk_A7D100) )
{
v13 = *(_QWORD *)(v17 + 24);
if ( v13 )
{
v20 = *(_QWORD *)(v17 + 16);
Py_INCREF(v13);
Py_INCREF(v20);
v21 = v17;
v17 = v20;
Py_DECREF(v21);
}
}
if ( v13 )
v4 = _Pyx_PyObject_Call2Args(v17, v13, v9);
else
v4 = _Pyx_PyObject_CallOneArg(v17, v9);
v16 = v4;
Py_XDECREF(v13);
Item = 0LL;
if ( !v16 )
{
v18 = str_d3recover_ver1_py;
v6 = 37;
v7 = 2203;
goto LABEL_60;
}
Py_DECREF(v17);
v17 = 0LL;
v8 = _Pyx_PyBytes_Equals(v16, qword_ABC0D0, 2LL);
if ( v8 < 0 )
{
v18 = str_d3recover_ver1_py;
v6 = 37;
v7 = 2206;
goto LABEL_60;
}
Py_DECREF(v16);
Py_XDECREF(0LL);
if ( v8 )
{
Py_INCREF(&qword_A7AEA0);
v11 = &qword_A7AEA0;
}
else
{
Py_INCREF(&qword_A7AEC0);
v11 = &qword_A7AEC0;
}
}
else
{
Py_XDECREF(0LL);
Py_INCREF(&qword_A7AEC0);
v11 = &qword_A7AEC0;
}
LABEL_61:
Py_XDECREF(v9);
Py_XDECREF(v10);
return v11;
}

看起来有点抽象,但是仔细看会发现,操作基本都以符号名的形式呈现了

但是具体形式还是不容易弄清楚,动调一下

求解

加密后的正确flag以 base64 的形式存在
转化后为

1
d3 c7 ce ca 3f 84 db b3 b6 b9 80 ea d0 cd 72 fc d8 30 95 db e2 d8 92 08 c1 c6 c5 f4 07 ec 02 5e

z3 脚本

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
from z3 import *
import base64
def en(arr):
length = 32
for i in range(32):
arr[i] = arr[i] ^ 0x23
for i in range(30):
arr[i] = ((arr[i] + arr[i+2]) & 0xff) ^ 0x54

def de(arr):
flag = [BitVec('flag[%d]' % i, 8) for i in range(32)]
s = Solver()
en(flag)
for i in range(32):
s.add(flag[i] == arr[i])
if(s.check() == sat):
print("Solver!")
result = s.model()
print(result)

else:
print("No Solver!!")
def main():
enflag = b'08fOyj+E27O2uYDq0M1y/Ngwldvi2JIIwcbF9AfsAl4='
dec = base64.b64decode(enflag)
de(dec)

return 0

if __name__ == '__main__':
main()
# flag{y0U_RE_Ma5t3r_0f_R3vocery!}

d3sky

涉及知识点

  • 反调试
  • RC4
  • 虚拟机
  • idapython

分析

Tls 回调里面有反调试

1
2
3
4
5
6
7
8
9
10
void __stdcall isDebugger__()
{
unsigned int len_key; // eax

if ( !IsDebuggerPresent() )
aYunzh1junalkai[5] = 49;
len_key = strlen("YunZhiJun");
RC4_init(sbox, "YunZhiJun", len_key);
rc4_crypt(sbox, &data, 74u);
}

没有调试的情况下,会更改字符串,而调试的状态下不会更改。
然后进行了RC4加密 并且还有除零异常
可以通过
attach 绕过

回调里面的函数加密的结果然后再进行解密 main 函数

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int len; // [esp+0h] [ebp-24h]
int v5; // [esp+Ch] [ebp-18h]
unsigned __int16 index_3; // [esp+14h] [ebp-10h]
unsigned __int16 index_1; // [esp+18h] [ebp-Ch]
unsigned __int16 index_2; // [esp+1Ch] [ebp-8h]
unsigned __int16 index_0; // [esp+20h] [ebp-4h]

v5 = 0;
puts("Welcome to D^3CTF~");
while ( code[0] != 0xFFFF )
{
if ( code[2] == 1 )
{
code[2] = 0;
print("%c", code[3]);
}
if ( code[7] == 1 )
{
code[7] = 0;
scanf("%c", &input);
len = v5++;
if ( len == 36 && code[8] != 126 )
{
puts("Wrong!");
return 0;
}
}
if ( code[19] )
{
puts("Wrong!");
return 0;
}
index_0 = code[0];
rc4_crypt(sbox, &code[code[0]], 3u);
index_1 = code[index_0];
index_2 = word_22401A[index_0];
index_3 = word_22401C[index_0];
code[0] = index_0 + 3;
rc4_crypt(sbox, &code[index_0], 3u);
code[index_3] = ~(code[index_1] & code[index_2]);
}
puts("Right! Your flag is antd3ctf{your input}");
return 0;
}

这里的 sbox 都是来自回调函数,我们先通过调试得到正确的key,然后得到加密后的数据 RC4 加密

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
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
// 初始化 S 和 T
void RC4_init(unsigned char* S, unsigned char* key, unsigned int len)
{
int i, j=0;
unsigned char T[256] = { 0 };
unsigned char temp = 0;
for (i = 0; i < 256; i++)
{
// 初始化 S
*(S + i) = i;
// 密钥轮换
*(T + i) = *(key + (i%len)) % 256;
}
for (i = 0; i < 256; i++)
{
j = (j + *(S + i) + *(T + i)) % 256;
// 进行交换
temp = *(S + i);
*(S + i) = *(S + j);
*(S + j) = temp;
}
}
// 加密明文
void RC4_encrypt(unsigned char* S, unsigned char* data, unsigned int len)
{
int i = 0, j = 0, t = 0;
unsigned int k;
unsigned char temp = 0;
for (k = 0; k < len; k++)
{
// 固定方式生成
i = (i + 1) % 256;
j = (j + *(S + i)) % 256;
// 交换
temp = *(S + i);
*(S + i) = *(S + j);
*(S + j) = temp;
// 固定方式生成的 t
t = (*(S + i) + *(S + j)) % 256;
// 异或
*(data + k) ^= *(S + t);
}
}
void numout(unsigned char* data, unsigned int len)
{
int i;
for (i = 0; i < len; i++)
{
printf("0x%02X, ", *(data + i));
}
printf("\n");
}
int main(int argc, char **argv)
{
// 初始化向量
unsigned char S[256] = { 0 };
// 密钥
unsigned char key[256] = "YunZh1JunAlkaid";
// 明文
unsigned char data_en[512] = { 0x009E, 0x0028, 0x00F5, 0x0075, 0x0073, 0x0073, 0x0030, 0x007E, 0x0048, 0x0048, 0x00F2, 0x002F, 0x003D, 0x00EC, 0x0001, 0x0026, 0x003E, 0x00CD, 0x0082, 0x00AD, 0x00B1, 0x00D1, 0x0036, 0x00D2, 0x00B4, 0x00E5, 0x00E8, 0x004C, 0x003D, 0x000C, 0x0073, 0x00FD, 0x0059, 0x00A7, 0x0048, 0x0093, 0x00FD, 0x0006, 0x00E0, 0x0044, 0x0048, 0x0071, 0x0094, 0x004A, 0x008E, 0x00A4, 0x0036, 0x0091, 0x0023, 0x00EE, 0x0068, 0x00C1, 0x005D, 0x000B, 0x004D, 0x001A, 0x0074, 0x0083, 0x0051, 0x0052, 0x00EE, 0x00FE, 0x0011, 0x00A2, 0x00A1, 0x0064, 0x00BD, 0x0098, 0x004D, 0x00B9, 0x0097, 0x0045, 0x00E6, 0x00F7 };
// 明文长度
// unsigned int len_en = strlen(data_en);
unsigned int len_en = 74;
// 密钥长度
unsigned int len_k = 15;
// unsigned int len_k = strlen(key);
// 加密
RC4_init(S, (unsigned char*)key, len_k);
RC4_encrypt(S, (unsigned char*)data_en, len_en);
numout((unsigned char*)data_en, len_en);
return 0;
}

得到

1
2
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, 0x24, 0x0B, 0x6D, 0x0F, 0x03, 0x32, 0x42, 0x1D, 0x2B, 0x43, 0x78, 0x43, 0x73, 0x30, 0x2B, 0x4E, 0x63, 0x48, 0x77, 0x2E, 0x32, 0x39, 0x1A, 0x12, 0x71, 0x7A, 0x42, 0x17, 0x45, 0x72, 0x56, 0x0C, 0x5C, 0x4A, 0x62, 0x53, 0x33
length =

尝试复现这个加密,发现有一些数据莫名其妙的不对,并且能够调试,于是尝试用idapython 来进行这个打桩log 的事

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
import idc
import ida_dbg
import idaapi
# 断点
def bpt(arr):
for i in range(len(arr)):
idc.add_bpt(arr[i])

def read_var(addr, reg):
# 运行到 addr 处
idc.run_to(addr)
idc.wait_for_next_event(ida_dbg.WFNE_SUSP, -1)

# 得到 reg 的值
return idc.get_reg_value(reg) & 0xffff

def get_var(addr, reg):
idc.run_to(addr)
idc.wait_for_next_event(ida_dbg.WFNE_SUSP, -1)
return idc.get_reg_value(reg)

def bin_log(base_addr):
index_0 = read_var(base_addr + 0x15A0, 'eax')
index_1 = read_var(base_addr + 0x15CB, 'ecx')
index_2 = read_var(base_addr + 0x15DB, 'eax')
index_3 = read_var(base_addr + 0x15EB, 'edx')
var_0 = read_var(base_addr + 0x1638, 'eax')
var_1 = idc.get_reg_value('edx') & 0xffff
var_2 = read_var(base_addr + 0x163c, 'eax')
print(hex(index_0) + ': ' + 'mem[' + hex(index_3) +'] = ~' + ' (mem[' + hex(index_1) + '] & mem[' + hex(index_2) + '])' )
print('\t ' + hex(var_2) + ' = ~(' + hex(var_0) + ' & ' + hex(var_1) + ')')

def main():
# 获取基址
base_addr = idaapi.get_imagebase()
print('base_addr= ' + hex(base_addr))
# 打上断点
bpt_arr= [base_addr+0x1578, base_addr + 0x15A0, base_addr + 0x15CB, base_addr + 0x15DB, base_addr + 0x15EB, base_addr + 0x1638, base_addr + 0x163c]
bpt(bpt_arr)
flag = get_var(base_addr + 0x1578, 'eax')
while(flag == 0):
bin_log(base_addr)
flag = get_var(base_addr + 0x1578, 'eax')


if __name__ == '__main__':
main()

得到

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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// 1
0x63: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x66: mem[0xad4] = ~ mem[0x7] & mem[0x7]
0x69: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x6c: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 2
0x6f: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x72: mem[0xad5] = ~ mem[0x7] & mem[0x7]
0x75: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x78: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 3
0x7b: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x7e: mem[0xad6] = ~ mem[0x7] & mem[0x7]
0x81: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x84: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 4
0x87: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x8a: mem[0xad7] = ~ mem[0x7] & mem[0x7]
0x8d: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x90: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 5
0x93: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x96: mem[0xad8] = ~ mem[0x7] & mem[0x7]
0x99: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x9c: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 6
0x9f: mem[0x7] = ~ mem[0x8] & mem[0x8]
0xa2: mem[0xad9] = ~ mem[0x7] & mem[0x7]
0xa5: mem[0xb] = ~ mem[0x14] & mem[0x14]
0xa8: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 7
0xab: mem[0x7] = ~ mem[0x8] & mem[0x8]
0xae: mem[0xada] = ~ mem[0x7] & mem[0x7]
0xb1: mem[0xb] = ~ mem[0x14] & mem[0x14]
0xb4: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 8
0xb7: mem[0x7] = ~ mem[0x8] & mem[0x8]
0xba: mem[0xadb] = ~ mem[0x7] & mem[0x7]
0xbd: mem[0xb] = ~ mem[0x14] & mem[0x14]
0xc0: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 9
0xc3: mem[0x7] = ~ mem[0x8] & mem[0x8]
0xc6: mem[0xadc] = ~ mem[0x7] & mem[0x7]
0xc9: mem[0xb] = ~ mem[0x14] & mem[0x14]
0xcc: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 9
0xcf: mem[0x7] = ~ mem[0x8] & mem[0x8]
0xd2: mem[0xadd] = ~ mem[0x7] & mem[0x7]
0xd5: mem[0xb] = ~ mem[0x14] & mem[0x14]
0xd8: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 10
0xdb: mem[0x7] = ~ mem[0x8] & mem[0x8]
0xde: mem[0xade] = ~ mem[0x7] & mem[0x7]
0xe1: mem[0xb] = ~ mem[0x14] & mem[0x14]
0xe4: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 11
0xe7: mem[0x7] = ~ mem[0x8] & mem[0x8]
0xea: mem[0xadf] = ~ mem[0x7] & mem[0x7]
0xed: mem[0xb] = ~ mem[0x14] & mem[0x14]
0xf0: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 12
0xf3: mem[0x7] = ~ mem[0x8] & mem[0x8]
0xf6: mem[0xae0] = ~ mem[0x7] & mem[0x7]
0xf9: mem[0xb] = ~ mem[0x14] & mem[0x14]
0xfc: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 13
0xff: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x102: mem[0xae1] = ~ mem[0x7] & mem[0x7]
0x105: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x108: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 14
0x10b: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x10e: mem[0xae2] = ~ mem[0x7] & mem[0x7]
0x111: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x114: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 15
0x117: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x11a: mem[0xae3] = ~ mem[0x7] & mem[0x7]
0x11d: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x120: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 16
0x123: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x126: mem[0xae4] = ~ mem[0x7] & mem[0x7]
0x129: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x12c: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 17
0x12f: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x132: mem[0xae5] = ~ mem[0x7] & mem[0x7]
0x135: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x138: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 18
0x13b: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x13e: mem[0xae6] = ~ mem[0x7] & mem[0x7]
0x141: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x144: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 19
0x147: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x14a: mem[0xae7] = ~ mem[0x7] & mem[0x7]
0x14d: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x150: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 20
0x153: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x156: mem[0xae8] = ~ mem[0x7] & mem[0x7]
0x159: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x15c: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 21
0x15f: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x162: mem[0xae9] = ~ mem[0x7] & mem[0x7]
0x165: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x168: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 22
0x16b: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x16e: mem[0xaea] = ~ mem[0x7] & mem[0x7]
0x171: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x174: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 23
0x177: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x17a: mem[0xaeb] = ~ mem[0x7] & mem[0x7]
0x17d: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x180: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 24
0x183: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x186: mem[0xaec] = ~ mem[0x7] & mem[0x7]
0x189: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x18c: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 25
0x18f: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x192: mem[0xaed] = ~ mem[0x7] & mem[0x7]
0x195: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x198: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 26
0x19b: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x19e: mem[0xaee] = ~ mem[0x7] & mem[0x7]
0x1a1: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x1a4: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 27
0x1a7: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x1aa: mem[0xaef] = ~ mem[0x7] & mem[0x7]
0x1ad: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x1b0: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 28
0x1b3: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x1b6: mem[0xaf0] = ~ mem[0x7] & mem[0x7]
0x1b9: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x1bc: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 29
0x1bf: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x1c2: mem[0xaf1] = ~ mem[0x7] & mem[0x7]
0x1c5: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x1c8: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 30
0x1cb: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x1ce: mem[0xaf2] = ~ mem[0x7] & mem[0x7]
0x1d1: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x1d4: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 31
0x1d7: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x1da: mem[0xaf3] = ~ mem[0x7] & mem[0x7]
0x1dd: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x1e0: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 32
0x1e3: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x1e6: mem[0xaf4] = ~ mem[0x7] & mem[0x7]
0x1e9: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x1ec: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 33
0x1ef: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x1f2: mem[0xaf5] = ~ mem[0x7] & mem[0x7]
0x1f5: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x1f8: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 34
0x1fb: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x1fe: mem[0xaf6] = ~ mem[0x7] & mem[0x7]
0x201: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x204: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 35
0x207: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x20a: mem[0xaf7] = ~ mem[0x7] & mem[0x7]
0x20d: mem[0xb] = ~ mem[0x14] & mem[0x14]
0x210: mem[0x7] = ~ mem[0xb] & mem[0xb]

// 36
0x213: mem[0x7] = ~ mem[0x8] & mem[0x8]
0x216: mem[0xaf8] = ~ mem[0x7] & mem[0x7]

//
0x219: mem[0xb] = ~ mem[0xad4] & mem[0xad4]
0x21c: mem[0xb] = ~ mem[0xb] & mem[0xad5]
0x21f: mem[0xc] = ~ mem[0xad5] & mem[0xad5]
0x222: mem[0xc] = ~ mem[0xc] & mem[0xad4]
0x225: mem[0x11] = ~ mem[0xb] & mem[0xc]

0x228: mem[0xb] = ~ mem[0xad6] & mem[0xad6]
0x22b: mem[0xb] = ~ mem[0xb] & mem[0xad7]
0x22e: mem[0xc] = ~ mem[0xad7] & mem[0xad7]
0x231: mem[0xc] = ~ mem[0xc] & mem[0xad6]
0x234: mem[0x12] = ~ mem[0xb] & mem[0xc]
0x237: mem[0xb] = ~ mem[0x11] & mem[0x11]
0x23a: mem[0xb] = ~ mem[0xb] & mem[0x12]
0x23d: mem[0xc] = ~ mem[0x12] & mem[0x12]
0x240: mem[0xc] = ~ mem[0xc] & mem[0x11]
0x243: mem[0x12] = ~ mem[0xb] & mem[0xc]
0x246: mem[0xb] = ~ mem[0xaf9] & mem[0xaf9]
0x249: mem[0xb] = ~ mem[0xb] & mem[0x12]
0x24c: mem[0xc] = ~ mem[0x12] & mem[0x12]
0x24f: mem[0xc] = ~ mem[0xc] & mem[0xaf9]
0x252: mem[0x13] = ~ mem[0xb] & mem[0xc]

最后这段就是加密了,但是不完整,因为这里有一个验证,我们并没有通过验证。

1
2
3
4
5
0x219:   mem[0xb] = ~ mem[0xad4] & mem[0xad4]
0x21c: mem[0xb] = ~ mem[0xb] & mem[0xad5]
0x21f: mem[0xc] = ~ mem[0xad5] & mem[0xad5]
0x222: mem[0xc] = ~ mem[0xc] & mem[0xad4]
0x225: mem[0x11] = ~ mem[0xb] & mem[0xc]

加密基本上都是这样的形式,略加分析,这其实实现的就是一个异或操作,上述等价于

1
mem[0x11] = mem[0xad4] ^ mem[0xad5]

多试几次,就可以得到正向加密

1
2
3
4
5
delta = [0x24, 0x0B, 0x6D, 0x0F, 0x03, 0x32, 0x42, 0x1D, 0x2B, 0x43, 0x78, 0x43, 0x73, 0x30, 0x2B, 0x4E, 0x63, 0x48, 0x77, 0x2E, 0x32, 0x39, 0x1A, 0x12, 0x71, 0x7A, 0x42, 0x17, 0x45, 0x72, 0x56, 0x0C, 0x5C, 0x4A, 0x62, 0x53, 0x33]
for i in range(0, len(flag)):
m = flag[i % 37] ^ flag[(i+1) % 37]
n = flag[(i+2) % 37] ^ flag[(i+3) % 37]
s.add((m ^ n) == delta[i])

其中 delta 为 RC4 加密后的结果(除去所有0的结果) 其中 第37个字符确定为~

1
if ( len == 36 && code[8] != 126 )

求解

正向基本明确了,现在就可以正向解密了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from z3 import *
flag = [BitVec('flag%i' % i, 8) for i in range(37)]
s = Solver()
for i in range(len(flag)):
s.add(flag[i] >= 33)
s.add(flag[i] <= 126)
s.add(flag[36] == 126)
delta = [0x24, 0x0B, 0x6D, 0x0F, 0x03, 0x32, 0x42, 0x1D, 0x2B, 0x43, 0x78, 0x43, 0x73, 0x30, 0x2B, 0x4E, 0x63, 0x48, 0x77, 0x2E, 0x32, 0x39, 0x1A, 0x12, 0x71, 0x7A, 0x42, 0x17, 0x45, 0x72, 0x56, 0x0C, 0x5C, 0x4A, 0x62, 0x53, 0x33]
for i in range(0, len(flag)):
m = flag[i % 37] ^ flag[(i+1) % 37]
n = flag[(i+2) % 37] ^ flag[(i+3) % 37]
s.add((m ^ n) == delta[i])

if(s.check() == sat):
print("Solver!")
result = s.model()
res = [chr(result[flag[i]].as_long()) for i in range(37)]
print(''.join(res))
else:
print("No Solver!!")

D3CTF 2023 RE Writeup
https://l3isu7e.github.io/2023/05/30/D3CTF2023/
作者
L3iSu7e
发布于
2023年5月30日
更新于
2024年1月4日
许可协议