首页
论坛
课程
招聘
强网杯: unicorn_like_a_pro
2021-6-14 21:28 10382

强网杯: unicorn_like_a_pro

2021-6-14 21:28
10382

强网杯: unicorn_like_a_pro

unicorn framework 是一个基于 qemu 的模拟执行框架

 

GitHub链接: https://github.com/unicorn-engine/unicorn

 

这道题目内部就调用了 unicorn 框架模拟执行一段 x64代码,最开始以为出题人魔改了 unicorn 框架,用 bindiff 分析了一段时间,发现并没有魔改 unicorn 代码

 

附件 原题 & 脚本 & idb:
可以去我博客文章页面下载附件:传送门

1. 符号还原

本题没有符号,逆向时比较困难,用 bindiff 可以直接还原。

 

在 ubuntu 上编译一份 unicorn 代码,载入 bindiff 插件即可完成大部分符号还原。

 

 

IDA 中的 bindiff 插件,载入另外一份 idb 后,按下 Ctrl + 6, 点击 如下按钮,设置好阀值后即可导入符号

 

2. main 函数分析

2.1 创建虚拟机

1
uc_open(4u, 8, &v14);                         // UC_ARCH_X86, UC_MODE_64

2.2 复制代码到虚拟机的 0x1000 地址

1
uc_mem_write(v14, 0x1000LL, &code, 0x1027LL);

2.3 设置回调

 

Unicorn 支持很多种回调类型,当 Unicorn 运行的代码满足特定的条件时,将触发对应的回调。

 

在回调中可以对虚拟机中环境上下文操作,类似调试器的调试回调。

 

本题借助 Unicorn 指令回调,实现指令即时解密,执行后重新加密,打乱控制流。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 虚拟机输入接口,虚拟机代码中的 in 指令
uc_hook_add(v14, &trace, 2, input + 1, 0LL, 1LL, 0LL, 0xDAu);// 2 == UC_HOOK_INSN
// 虚拟机输出接口,虚拟机中代码中的 out 指令处理
uc_hook_add(v14, &trace, 2, output, 0LL, 1LL, 0LL, 0x1F4u);// 2 = UC_HOOK_INSN
// 虚拟机中 syscall 指令处理,设置 rax 寄存器的值为 time(0)
uc_hook_add(v14, &trace, 2, syscall_time, 0LL, 1LL, 0LL, 0x2BBu);// 2 = UC_HOOK_INSN
// 虚拟机中 fs 内存访问处理,改变 fs:0 的值,关键算法部分很重要
uc_hook_add(v14, &trace, 1024, changeKey, 0LL, 0x66660000LL, 0x66661000LL, v4);// UC_HOOK_MEM_READ
// 代码解密回调
uc_hook_add(v14, &trace, 8, decrypt, &v21, 1LL, 0LL, v5);// UC_HOOK_BLOCK
// 代码控制流控制回调1
uc_hook_add(v14, &trace, 0x4000,  ControlFlow1, &v21, 1LL, 0LL, v6);// UC_HOOK_INSN_INVALID
// 代码控制流控制回调2
uc_hook_add(v14, &trace, 4,  ControlFlow2, &v21, 0x10A3LL, 0x10A4LL, v7);// UC_HOOK_CODE

注意控制流有两个控制回调,第二个控制回调只在 0x10A3 地址处有效,就是特殊处理的地址。

3. 代码解密分析

代码解密的主要逻辑在 decrypt 函数,该函数解密当前即将执行的基本块,加密上一个执行完的基本块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
v9 = miniDec(lastKey, entry_rip);
for ( i = 0; i <= 85; ++i )
{
  if ( v9 == *&size_table[8 * i] )
  {
    size[0] = *&size_table[8 * i + 4];        // getlen
    v12 = malloc(size[0]);
    uc_mem_read(v5, addr, v12, size[0]);
    for ( j = 0; size[0] > j; ++j )
      ;
    dec1(v12, size[0], lastKey);
    uc_mem_write(v5, addr, v12, size[0]);
    for ( k = 0; size[0] > k; ++k )
      ;
    free(v12);
    *(*&size[1] + 4LL) = addr;
    *(*&size[1] + 12LL) = **&size[1];
    *(*&size[1] + 8LL) = size[0];
    *(*&size[1] + 16LL) = addr;
    uc_reg_write(v5, 41, &addr);              // UC_X86_REG_RIP
  }
}

基本块密钥用 miniDec 函数计算,参数为上一个基本块的入口密钥 lastKey 与当前基本块入口 rip, minidec 函数如下

1
2
3
4
__int64 __fastcall miniDec(int a1, int a2)
{
  return a2 ^ a1 ^ (a2 * a1) ^ (a1 + a2);
}

size_table 是一个数组,该数组保存了基本块密钥与基本块大小的关系,元素结构如下

1
2
dd key
dd size
1
size_table = [0x02F73020, 0x00000015, 0x09D3473A, 0x00000051, 0x0EF87B55, 0x0000000D, 0x147CB028, 0x00000023, 0x15F833AA, 0x00000030, 0x17086780, 0x00000018, 0x1733A9D4, 0x00000014, 0x17D61EE8, 0x00000051, 0x1D52F19E, 0x00000011, 0x1F732DE0, 0x0000000D, 0x1FBECFAD, 0x0000001B, 0x245BD7C8, 0x00000055, 0x25E7ABEE, 0x00000009, 0x2882C190, 0x000000A2, 0x2A2084A0, 0x00000075, 0x326AA6AE, 0x00000036, 0x33074A36, 0x00000024, 0x3440BD69, 0x0000002C, 0x362A1FC3, 0x0000002C, 0x3C0450D0, 0x0000000D, 0x3CB575FD, 0x00000011, 0x41B3B26E, 0x0000004E, 0x46005120, 0x00000011, 0x465A72CF, 0x00000002, 0x492145A0, 0x0000000D, 0x49AA4CE0, 0x0000002D, 0x4BD63647, 0x0000004E, 0x4BF84A87, 0x0000000D, 0x4D102445, 0x00000033, 0x4D4D3C55, 0x0000001B, 0x53723232, 0x0000000A, 0x5809B5CB, 0x000000A2, 0x5B12FFCE, 0x00000015, 0x5B1F3000, 0x00000051, 0x5D9FBD20, 0x00000027, 0x6219EED9, 0x0000008A, 0x65D82D17, 0x0000004C, 0x67F5671A, 0x00000063, 0x6CE2CBC1, 0x00000033, 0x718A739C, 0x0000000B, 0x71A62DD7, 0x00000015, 0x7693A1F6, 0x00000014, 0x7A473FB0, 0x00000047, 0x7AEFEDDC, 0x00000011, 0x7AF2CF90, 0x0000004F, 0x7BE0B8B0, 0x0000001B, 0x80EB3E88, 0x0000000A, 0x8213506A, 0x0000000C, 0x82468114, 0x00000011, 0x86B872A2, 0x0000001C, 0x87FBD296, 0x00000019, 0x88719339, 0x00000016, 0x89E2630A, 0x00000024, 0x8CB6536E, 0x0000004E, 0x92316E00, 0x00000015, 0x9415A51E, 0x0000004F, 0x94D658E0, 0x0000002B, 0x97E8DFCD, 0x00000036, 0x992E3874, 0x0000002A, 0x9B06958D, 0x00000030, 0x9B36B480, 0x0000000D, 0xA03CEFAD, 0x0000005A, 0xA39F47E6, 0x0000004E, 0xA946DEC4, 0x000000B4, 0xAE6173DC, 0x00000051, 0xB044A68D, 0x0000008C, 0xB29E36A8, 0x0000000B, 0xB82781F4, 0x0000000D, 0xC14DFAF8, 0x00000011, 0xC3F42E20, 0x0000001E, 0xC5E0065E, 0x00000067, 0xCAD68B21, 0x00000039, 0xCBF29AC7, 0x00000011, 0xCE8729BC, 0x0000001B, 0xD2A85A94, 0x00000004, 0xD34FA4F3, 0x00000011, 0xD64611B0, 0x00000058, 0xD814FD56, 0x00000018, 0xDD386A80, 0x0000000A, 0xDE82DFAC, 0x00000011, 0xEC68D16F, 0x0000001B, 0xEEDE845B, 0x0000003F, 0xF235F260, 0x0000008D, 0xF9AA1F0B, 0x00000087, 0xFC200887, 0x00000011, 0xFED657A3, 0x0000000C, 0x00000000]

奇数下标数据为key,偶数为基本块字节的长度。

 

用 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
def fuck(prev_key, rip):
    return rip ^ prev_key ^ ((rip * prev_key) & 0xffffffff) ^ (prev_key + rip)
 
def deXor(data, key):
    key = p32(key)
    data = bytearray(data)
    for i in range(len(data)):
        data[i] ^=  key[i % 4]
    return data
 
 
def decrypt_block(key, rip):
    key2 = fuck(key, rip)
    blockSize = get_size(key2)
    if blockSize is None:
        print("Not found1: rip:%x key:%x" % (rip, key2))
        return None, None, None
    offset = rip - 0x1000
    code_data = code_bin[offset: offset + blockSize]
    code_data = deXor(code_data, key)
    next_rip = rip + blockSize - 2
    key2 = fuck(key, next_rip)
    jmps = get_jmps(key2)
    return code_data, jmps, next_rip

这里的部分代码还涉及控制流重建,后面会提到。

4. 控制流分析

ControlFlow1 回调,执行到无效指令会被调用,用于切换程序中的控制流。

 

该题用 3f 0f作为基本块的结尾(无效指令)触发 ControlFlow1 回调,切换控制流。

 

ControlFlow1 回调函数根据结尾 rip 与 当前基本块的 key 计算另外一个 key,用于索引当前基本块的后继基本块的信息。

 

 

flowInfo 是一个数组,每一个元素有如下5个字段

1
2
3
4
5
dd key
dd zf_0_jmp  当基本块结尾 zf 标志寄存器为 0 的跳转偏移,下面同理
dd zf_0_key
dd zf_1_jmp
dd zf_1_key

根据 zf 标志位跳转

 

 

注意 v9 保存的是上一个基本块的 key,此处做的 += 运算,即上一个基本块的 key 与 下一个基本块的 key 有关联。

 

由此可见,基本块的 key 与控制流的路径有关!写解密脚本的时候要考虑路径问题。

 

另外,当虚拟机中程序运行到 0x10A3 时将调整控制流并更改 key

 

 

解密后的基本块,很多都是以读取 fs 寄存器并判断结尾

 

 

r15 的值来源于 fs:xxx ,最后再与 fs:xxx 内存的值比较,很明显最后的 zf = 1。

 

其实并不是,这道题对 fs 寄存器指向的那段内存做了内存读回调,回调如下

 

 

每次读取 fs 指向的内存,该内存的值都会被改写。所以 mov 与 cmp 对 fs 内存访问出的结果是不同的,自然 zf = 0,走 zf = 0 的分支。

 

在控制流重建的时候,需要考虑以读取 fs 内存结尾的基本块,将其看作是无条件跳转,而不是 jz/jnz。

5. 控制流重建

重建思路:

 

以 bfs 遍历顺序,从入口基本块开始解密,解密后再查询分支信息表获取后继基本块的相对偏移与key,最后将新基本块的信息加入到队列,等待分析。遍历时注意维护路径上的 key 累计值。

 

所有基本块解密完成后,可以得到每个基本块的后继基本块的相对偏移。

 

要在基本块的结尾插入跳转指令,这将改变代码布局,使得原始相对偏移不可用,所以我采取重编译来解决这个问题,重编译之前将原始基本块的入口地址作为基本的符号名,基本块结尾用 jmp/jz 等指令连接。

 

code.bin 文件时 dump 出来的原始 code 数据,输出 1.bin 可以直接在 ida 中反编译。

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
import ctypes
from capstone import *
from keystone import *
from pwn import *
 
context.arch = 'amd64'
 
from pwn import *
fuckTable = [0x00412F5E, 0xFFFFFA22, 0x14252652, 0xFFFFF9AC, 0x66CEF8EC, 0x0251D934, 0x0000009F, 0xC56FBF59, 0xFFFFFF61, 0xAA4D5B7C, 0x02745896, 0xFFFFFB7F, 0x34B6D31E, 0xFFFFFBB0, 0x302CC828, 0x02AC5992, 0xFFFFF524, 0x67CC4064, 0xFFFFF483, 0x8A5D9B26, 0x046254D0, 0xFFFFFC37, 0x074AB936, 0xFFFFFC7F, 0xB8EA37F7, 0x0CACD9FE, 0x0000007F, 0x6112F222, 0x00000002, 0x47A72561, 0x0F0FE6EB, 0xFFFFFBAE, 0x0A1411E7, 0xFFFFFC85, 0x3BE88B46, 0x0FC59DC2, 0xFFFFF72F, 0x7D12A5EF, 0xFFFFF691, 0xE67393D6, 0x10B1EBCA, 0x000001CF, 0x473A1295, 0x0000022E, 0x7BC15385, 0x1565D41D, 0xFFFFFDC4, 0x05D337BE, 0xFFFFFE7E, 0xE12982E4, 0x18909E40, 0x000005EB, 0xAE2337AF, 0x000005B1, 0x8E0AB2ED, 0x1AE7593A, 0xFFFFF3BC, 0x23E9058D, 0xFFFFF40B, 0xDFA6CF3E, 0x1B47DA81, 0xFFFFF8C3, 0x349CC616, 0xFFFFF7E9, 0x70C290D0, 0x1D816435, 0x00000002, 0x43F999C9, 0xFFFFFFD8, 0xAB0BCA16, 0x1DACC905, 0xFFFFFF54, 0x5C129962, 0xFFFFFD06, 0xE4515A41, 0x1E03B13C, 0xFFFFFF80, 0x7E763806, 0xFFFFF36A, 0xA25F3D93, 0x22FEFC06, 0xFFFFFCDD, 0xB94E0C2F, 0xFFFFFCB6, 0xF023033D, 0x26B1E690, 0xFFFFFDAB, 0xD0C7ED0C, 0xFFFFFE9B, 0xD49872C6, 0x2A652084, 0x000001EA, 0xDF9B65EE, 0x00000051, 0x5CC5AB90, 0x2FBEBD25, 0x0000048F, 0x60A4E9F2, 0x000009AF, 0x42FE8B0D, 0x34F12D90, 0x000004C0, 0xF6257D94, 0x00000480, 0x5227DE21, 0x35F591D0, 0xFFFFFCA1, 0xDA83E113, 0xFFFFF998, 0x805C7ECB, 0x37EB0B72, 0xFFFFF3EC, 0x7480201A, 0xFFFFF903, 0xAC977E11, 0x389A58A8, 0x00000189, 0xE4005CD7, 0xFFFFFDEC, 0xB043695F, 0x3CB24155, 0x0000084C, 0x8ACB6FF1, 0x00000899, 0xACB471A5, 0x3DCBCDE3, 0x000007A8, 0xA84E3072, 0x00000384, 0xB2624259, 0x3F5290DE, 0xFFFFFE25, 0x8AC11F92, 0xFFFFFD8A, 0x44ACCD78, 0x47FF9B7E, 0x00000A81, 0x9833BF9C, 0x00000B35, 0x9B7199CD, 0x4C7867E6, 0x0000011C, 0x68BB4F80, 0x0000002E, 0x75B675CD, 0x53ADCD80, 0x000004E8, 0x6AA4F705, 0x00000452, 0xBA7C314B, 0x566E1640, 0x00000C8E, 0x203E3737, 0x00000C38, 0xF9367ED9, 0x5EDBB130, 0x000004FF, 0xD4F71A40, 0x000002AA, 0x35DC4141, 0x6C29C83A, 0x00000013, 0xBEAD8A76, 0xFFFFFFB5, 0x7A8A43EF, 0x6E036C9C, 0x00000BD5, 0x225F81E0, 0x00000D89, 0x3C25944D, 0x6FDCCE50, 0x00000605, 0xD3126740, 0x000003D5, 0xA3DA544C, 0x7132D345, 0x0000064E, 0x00915A5A, 0x000006DD, 0x5BCB6B22, 0x720DBD5C, 0x000008C3, 0x64DCFDF6, 0x00000858, 0x190B20BB, 0x7A035AD4, 0x00000424, 0x4DD955FB, 0x000004BF, 0xF65150B5, 0x7CBAED22, 0x00000AA1, 0x62CC154B, 0xFFFFFC58, 0x8DD5CEDB, 0x7EBF8EA8, 0x00000458, 0xCE844A0E, 0xFFFFF734, 0x9079D6BA, 0x804885CD, 0x000007BB, 0x89A8DA66, 0x00000136, 0x7185B813, 0x82190F37, 0xFFFFF58C, 0x013FA7D4, 0xFFFFF4AB, 0x7518093D, 0x83F7826A, 0x00000917, 0x2F33C3DD, 0xFFFFFBF0, 0x02A289B1, 0x8481BFD5, 0xFFFFF927, 0x72EED2D1, 0xFFFFF80A, 0xF46FD351, 0x85A69D6E, 0x000000B4, 0x27A3BB0F, 0x00000181, 0x49235BC0, 0x85F73150, 0x00000259, 0xA300692F, 0x000009BD, 0x5A3E46A9, 0x86E2497A, 0xFFFFFB53, 0xE7614707, 0xFFFFFBB3, 0xFA190B2A, 0x8B261F60, 0xFFFFF323, 0x97B9CC33, 0xFFFFFAB7, 0x2CB73BF0, 0x8B42B00C, 0x00000871, 0xA57A2DE3, 0x00000797, 0xA73082D6, 0x8E4C5C94, 0x000000FE, 0xEE4B594B, 0xFFFFF999, 0xDCE3B74D, 0x913A9FDB, 0xFFFFFE1C, 0x1BFFA329, 0xFFFFFD31, 0x49B21C95, 0x922BFB96, 0xFFFFF61B, 0x4FAFD829, 0xFFFFFBBA, 0x6BD5D317, 0x9F4B8702, 0xFFFFFEC1, 0xB691AD49, 0xFFFFFEF2, 0xCE6C6FE9, 0xA2CEAAA6, 0xFFFFFD89, 0x60E52701, 0xFFFFFCB2, 0x25AD9A9D, 0xAA970D72, 0xFFFFF2BB, 0xC1F58CAC, 0xFFFFF2AB, 0x20B8FE22, 0xABC02B72, 0xFFFFF94B, 0xFF6EA5A6, 0xFFFFFA6A, 0x1CD46647, 0xAE535E9E, 0x000003EC, 0x31246F6B, 0x0000035B, 0x50E2A20A, 0xB7337941, 0xFFFFF856, 0xD1A79AD7, 0xFFFFF955, 0x14673B75, 0xBB8DB95E, 0xFFFFFEEB, 0x6A7F1E5A, 0xFFFFF3B3, 0x1EF2F3AA, 0xBC1EDA22, 0xFFFFFB90, 0xE247955F, 0xFFFFFCE6, 0xA0351A85, 0xBCD91FE8, 0x0000008C, 0x71A348B9, 0x00000030, 0x821754EF, 0xBD38E305, 0xFFFFFF59, 0xE694333F, 0xFFFFFEF9, 0x436B1A45, 0xBE1AA65A, 0xFFFFF93D, 0x8761A810, 0xFFFFFEEB, 0xB2DB19FA, 0xC052453C, 0x000009B5, 0xB05027D7, 0x000009C5, 0xBCA91679, 0xC4A2D780, 0x000008B9, 0xE42FD068, 0x000007C1, 0x9F8B2B83, 0xC6A236BA, 0xFFFFFDBB, 0x20649A12, 0xFFFFFD09, 0x5F73FD94, 0xC6BB5160, 0xFFFFFE90, 0x0ED42674, 0xFFFFFF4B, 0xA76699CC, 0xCB74E940, 0x000003E3, 0x7DA194FF, 0xFFFFFCDA, 0xB23E5B15, 0xD027B387, 0xFFFFF701, 0x880BCC4F, 0xFFFFF785, 0xFEA3D685, 0xD1127D6B, 0xFFFFFAC0, 0xDF3D499A, 0x00000362, 0x84B7777D, 0xD6F5F913, 0xFFFFFCCD, 0xA5D89DB8, 0xFFFFFCAB, 0xF69BAE29, 0xDD04F828, 0xFFFFF705, 0xE18F3BA0, 0xFFFFF64D, 0xEBC799B0, 0xDDF22CB8, 0x0000075D, 0x47F7B857, 0x000001B3, 0x5C1CDEA9, 0xDF34D0A8, 0x0000014D, 0xBFE2CAD5, 0x00000201, 0x1F0C8A89, 0xE146EA40, 0x0000046D, 0x189EB8F9, 0xFFFFF6FB, 0x4CA1090D, 0xE231C560, 0x00000710, 0x2E586529, 0xFFFFFF17, 0x0E9AA776, 0xE2FC6838, 0x00000733, 0xB73DDD7A, 0x00000753, 0x14A1BDE4, 0xE44AE35D, 0x000002C8, 0x46B1F3D1, 0xFFFFFA2D, 0xD2295816, 0xE5AF4AB1, 0x00000DB0, 0x0AFF4FF9, 0x00000D91, 0xB17A4340, 0xE7E3CF21, 0x00000656, 0x9FC50924, 0x00000658, 0x31615022, 0xE8815965, 0x00000BCB, 0x6F51A655, 0x00000C0A, 0x72F5680C, 0xEBDF0F14, 0xFFFFF2B1, 0xD36EC5D4, 0xFFFFF239, 0x3B711343, 0xEC12E59B, 0x00000270, 0x3A38D2E8, 0x0000023D, 0x68D07674, 0xF4013920, 0x00000703, 0xD83CCFAA, 0x000007BA, 0x46891EEB, 0xF6847EC1, 0xFFFFFE62, 0x6D4BAAFC, 0xFFFFFD92, 0x5E6F5A94]
 
 
size_table = [0x02F73020, 0x00000015, 0x09D3473A, 0x00000051, 0x0EF87B55, 0x0000000D, 0x147CB028, 0x00000023, 0x15F833AA, 0x00000030, 0x17086780, 0x00000018, 0x1733A9D4, 0x00000014, 0x17D61EE8, 0x00000051, 0x1D52F19E, 0x00000011, 0x1F732DE0, 0x0000000D, 0x1FBECFAD, 0x0000001B, 0x245BD7C8, 0x00000055, 0x25E7ABEE, 0x00000009, 0x2882C190, 0x000000A2, 0x2A2084A0, 0x00000075, 0x326AA6AE, 0x00000036, 0x33074A36, 0x00000024, 0x3440BD69, 0x0000002C, 0x362A1FC3, 0x0000002C, 0x3C0450D0, 0x0000000D, 0x3CB575FD, 0x00000011, 0x41B3B26E, 0x0000004E, 0x46005120, 0x00000011, 0x465A72CF, 0x00000002, 0x492145A0, 0x0000000D, 0x49AA4CE0, 0x0000002D, 0x4BD63647, 0x0000004E, 0x4BF84A87, 0x0000000D, 0x4D102445, 0x00000033, 0x4D4D3C55, 0x0000001B, 0x53723232, 0x0000000A, 0x5809B5CB, 0x000000A2, 0x5B12FFCE, 0x00000015, 0x5B1F3000, 0x00000051, 0x5D9FBD20, 0x00000027, 0x6219EED9, 0x0000008A, 0x65D82D17, 0x0000004C, 0x67F5671A, 0x00000063, 0x6CE2CBC1, 0x00000033, 0x718A739C, 0x0000000B, 0x71A62DD7, 0x00000015, 0x7693A1F6, 0x00000014, 0x7A473FB0, 0x00000047, 0x7AEFEDDC, 0x00000011, 0x7AF2CF90, 0x0000004F, 0x7BE0B8B0, 0x0000001B, 0x80EB3E88, 0x0000000A, 0x8213506A, 0x0000000C, 0x82468114, 0x00000011, 0x86B872A2, 0x0000001C, 0x87FBD296, 0x00000019, 0x88719339, 0x00000016, 0x89E2630A, 0x00000024, 0x8CB6536E, 0x0000004E, 0x92316E00, 0x00000015, 0x9415A51E, 0x0000004F, 0x94D658E0, 0x0000002B, 0x97E8DFCD, 0x00000036, 0x992E3874, 0x0000002A, 0x9B06958D, 0x00000030, 0x9B36B480, 0x0000000D, 0xA03CEFAD, 0x0000005A, 0xA39F47E6, 0x0000004E, 0xA946DEC4, 0x000000B4, 0xAE6173DC, 0x00000051, 0xB044A68D, 0x0000008C, 0xB29E36A8, 0x0000000B, 0xB82781F4, 0x0000000D, 0xC14DFAF8, 0x00000011, 0xC3F42E20, 0x0000001E, 0xC5E0065E, 0x00000067, 0xCAD68B21, 0x00000039, 0xCBF29AC7, 0x00000011, 0xCE8729BC, 0x0000001B, 0xD2A85A94, 0x00000004, 0xD34FA4F3, 0x00000011, 0xD64611B0, 0x00000058, 0xD814FD56, 0x00000018, 0xDD386A80, 0x0000000A, 0xDE82DFAC, 0x00000011, 0xEC68D16F, 0x0000001B, 0xEEDE845B, 0x0000003F, 0xF235F260, 0x0000008D, 0xF9AA1F0B, 0x00000087, 0xFC200887, 0x00000011, 0xFED657A3, 0x0000000C, 0x00000000]
zf_0_jmp = 0
zf_0_key = 1
zf_1_jmp = 2
zf_1_key = 3
 
 
code_bin = open("code.bin", "rb").read()
print("code size: ", hex(len(code_bin)))
 
def get_size(key):
    for i in range(85):
        if size_table[i * 2] == key:
            return  size_table[i * 2 + 1]
    return None
 
def get_jmps(key):
    for i in range(85):
        base = i * 5
        if fuckTable[base] == key:
            # zf_0_jmp, zf_0_key, zf_1_jmp, zf_1_key
            return fuckTable[base + 1: base + 5]
    print("not found2: ", hex(key))
    return None
 
def fuck(prev_key, rip):
    return rip ^ prev_key ^ ((rip * prev_key) & 0xffffffff) ^ (prev_key + rip)
 
def deXor(data, key):
    key = p32(key)
    data = bytearray(data)
    for i in range(len(data)):
        data[i] ^=  key[i % 4]
    return data
 
 
def decrypt_block(key, rip):
    key2 = fuck(key, rip)
    blockSize = get_size(key2)
 
    if blockSize is None:
        print("Not found1: rip:%x key:%x" % (rip, key2))
        return None, None, None
 
    offset = rip - 0x1000
    code_data = code_bin[offset: offset + blockSize]
    code_data = deXor(code_data, key)
    next_rip = rip + blockSize - 2
    key2 = fuck(key, next_rip)
 
    jmps = get_jmps(key2)
 
    return code_data, jmps, next_rip
 
class Node:
    def __init__(self, data, rip):
        self.code_data = data
        self.child1 = 0
        self.child2 = 0
        self.end_rip = None
        self.rip = rip
 
 
def disasm(data, baseaddr):
    md = Cs(CS_ARCH_X86, CS_MODE_64)
    ins = ''
    for i in md.disasm(data, baseaddr):
        asm_code = "%s\t%s" % (i.mnemonic, i.op_str)
        ins += asm_code + "\n"
    return ins
 
def buildNode(key_, rip_):
    work_queue = [(key_, rip_)]
    log_map = {}
    while len(work_queue) > 0:
        T = work_queue[0]
        work_queue.remove(T)
        key, rip = T
 
 
        if rip in log_map:
            continue
 
        if rip == 0x10A3:
            key -= 0x2B09B990
            rip = 0x1EEC
 
        code_data, jmps, next_rip = decrypt_block(key, rip)
 
        if code_data is None:
            continue
 
        node_cur = Node(code_data, rip)
 
        node_cur.end_rip = next_rip
        log_map[rip] = node_cur
 
        if jmps is None:
            continue
 
        asm_text = disasm(node_cur.code_data, rip)
 
 
        newrip = next_rip + ctypes.c_int32(jmps[zf_0_jmp]).value
        node_cur.child1 = newrip
        if newrip not in log_map:
            work_queue.append(((key + jmps[zf_0_key]) & 0xffffffff, newrip))
 
        if 'qword ptr fs:[' in asm_text.splitlines()[-1]:
            continue
 
 
        newrip = next_rip + ctypes.c_int32(jmps[zf_1_jmp]).value
        node_cur.child2 = newrip
        if newrip not in log_map:
            work_queue.append(((key + jmps[zf_1_key]) & 0xffffffff, newrip))
 
 
    jmptables = {}
    for i in sorted(log_map.keys()):
        if log_map[i].child1 is None:
            log_map[i].child1 = 0
 
        if log_map[i].child2 is None:
            log_map[i].child2 = 0
 
        jmptables[hex(log_map[i].end_rip)] = (hex(log_map[i].rip), hex(log_map[i].child1), hex(log_map[i].child2))
    print("len:", len(jmptables))
    print(jmptables)
 
    all_asm = ''
    for i in sorted(log_map.keys()):
        print(hex(i))
        node = log_map[i]
        if i == 0x1EEC:
            all_asm += "_0x10a3:\n"
 
        all_asm += "_" + hex(i) + ":\n"
        all_asm += disasm(node.code_data, i)
 
        if node.child1 != 0 and node.child2 != 0:
            jmp_code = "jz _" + hex(node.child2) + "\n"
            jmp_code += "jmp _" + hex(node.child1) + "\n"
 
        elif node.child1 == 0 and node.child2 != 0:
            jmp_code = "jmp _" + hex(node.child2) + "\n"
 
        elif node.child2 == 0 and node.child1 != 0:
            jmp_code = "jmp _" + hex(node.child1) + "\n"
        else:
            jmp_code = '\n'
 
        all_asm += jmp_code
 
    all_asm = all_asm.replace("endbr64", "nop\n" * 4)
    code_bin = asm(all_asm)
    open('1.bin', 'wb').write(code_bin)
    print(all_asm)
    print("all nodes: ", len(log_map))
 
buildNode(0x3265B1F5, 0x1000)

6. 提取出来的代码分析

重建控制流,输出 bin 后,代码比较清晰了。

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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// rsp = 0x7777F000
void __noreturn sub_4()
{
  unsigned __int8 v0; // al
  int v1; // eax
  __int64 v2; // rax
  __int64 xorKey[4]; // [rsp+0h] [rbp-2C0h]
  __int128 v4; // [rsp+21h] [rbp-29Fh] BYREF
  char v5[14]; // [rsp+31h] [rbp-28Fh] BYREF
  char v6[17]; // [rsp+3Fh] [rbp-281h] BYREF
  __int64 compare[5]; // [rsp+50h] [rbp-270h] BYREF
  __int64 v8; // [rsp+78h] [rbp-248h]
  __int64 FlagInData[8]; // [rsp+80h] [rbp-240h] BYREF
  unsigned __int8 v10; // [rsp+C2h] [rbp-1FEh]
  unsigned __int8 v11; // [rsp+C3h] [rbp-1FDh]
  int kk; // [rsp+C4h] [rbp-1FCh]
  __int64 v13; // [rsp+C8h] [rbp-1F8h]
  __int128 *v14; // [rsp+D0h] [rbp-1F0h]
  unsigned __int8 v15; // [rsp+DAh] [rbp-1E6h]
  unsigned __int8 v16; // [rsp+DBh] [rbp-1E5h]
  int mm; // [rsp+DCh] [rbp-1E4h]
  __int64 v18; // [rsp+E0h] [rbp-1E0h]
  __int64 v19; // [rsp+E8h] [rbp-1D8h]
  unsigned __int8 v20; // [rsp+F3h] [rbp-1CDh]
  int jj; // [rsp+F4h] [rbp-1CCh]
  __int64 v22; // [rsp+F8h] [rbp-1C8h]
  __int64 *v23; // [rsp+100h] [rbp-1C0h]
  __int64 *v24; // [rsp+108h] [rbp-1B8h]
  int ii; // [rsp+110h] [rbp-1B0h]
  unsigned int v26; // [rsp+114h] [rbp-1ACh]
  int v27; // [rsp+118h] [rbp-1A8h]
  unsigned int v28; // [rsp+11Ch] [rbp-1A4h]
  unsigned int *v29; // [rsp+120h] [rbp-1A0h]
  int n; // [rsp+12Ch] [rbp-194h]
  unsigned __int64 v31; // [rsp+130h] [rbp-190h]
  unsigned __int64 v32; // [rsp+138h] [rbp-188h]
  unsigned __int64 v33; // [rsp+140h] [rbp-180h]
  unsigned __int64 data2; // [rsp+148h] [rbp-178h]
  int m; // [rsp+154h] [rbp-16Ch]
  unsigned __int64 v36; // [rsp+158h] [rbp-168h]
  unsigned __int64 data1; // [rsp+160h] [rbp-160h]
  int i_0; // [rsp+16Ch] [rbp-154h]
  __int64 v39; // [rsp+170h] [rbp-150h]
  unsigned __int64 from_t0; // [rsp+178h] [rbp-148h]
  __int64 const_32; // [rsp+180h] [rbp-140h]
  __int64 *flag_ptr; // [rsp+188h] [rbp-138h]
  unsigned __int64 v43; // [rsp+190h] [rbp-130h]
  __int64 v44; // [rsp+198h] [rbp-128h]
  __int64 *v45; // [rsp+1A0h] [rbp-120h]
  unsigned __int8 v46; // [rsp+202h] [rbp-BEh]
  unsigned __int8 v47; // [rsp+203h] [rbp-BDh]
  int nn; // [rsp+204h] [rbp-BCh]
  __int64 v49; // [rsp+208h] [rbp-B8h]
  char *v50; // [rsp+210h] [rbp-B0h]
  __int64 flagLen; // [rsp+218h] [rbp-A8h]
  __int64 *v52; // [rsp+220h] [rbp-A0h]
  unsigned __int8 v53; // [rsp+22Ah] [rbp-96h]
  unsigned __int8 v54; // [rsp+22Bh] [rbp-95h]
  int i1; // [rsp+22Ch] [rbp-94h]
  __int64 v56; // [rsp+230h] [rbp-90h]
  char *v57; // [rsp+238h] [rbp-88h]
  __int64 v58; // [rsp+240h] [rbp-80h]
  __int64 time0; // [rsp+248h] [rbp-78h]
  __int64 v60; // [rsp+250h] [rbp-70h]
  __int64 d2; // [rsp+258h] [rbp-68h]
  __int64 v62; // [rsp+260h] [rbp-60h]
  __int64 d1; // [rsp+268h] [rbp-58h]
  int i; // [rsp+274h] [rbp-4Ch]
  __int64 data0; // [rsp+278h] [rbp-48h]
  unsigned __int8 v66; // [rsp+282h] [rbp-3Eh]
  unsigned __int8 v67; // [rsp+283h] [rbp-3Dh]
  int j; // [rsp+284h] [rbp-3Ch]
  __int64 v69; // [rsp+288h] [rbp-38h]
  char *v70; // [rsp+290h] [rbp-30h]
  unsigned __int8 v71; // [rsp+29Ah] [rbp-26h]
  unsigned __int8 v72; // [rsp+29Bh] [rbp-25h]
  int k; // [rsp+29Ch] [rbp-24h]
  __int64 v74; // [rsp+2A0h] [rbp-20h]
  __int64 *flagIn; // [rsp+2A8h] [rbp-18h]
  __int64 v76; // [rsp+2B0h] [rbp-10h]
  unsigned __int64 time0_1; // [rsp+2B8h] [rbp-8h]
 
  v58 = 0x7177625F32303231i64;
  __writefsqword(0, 0x7177625F32303231ui64);
  __asm { syscall; Low latency system call }
  time0 = MEMORY[0x1337];                       // time(0)
  time0_1 = MEMORY[0x1337];
  v2 = MEMORY[0x1337] / 0xE10ui64;
  data0 = MEMORY[0x1337] / 0xE10ui64;
  for ( i = 0; i != 256; ++i )
  {
    d1 = 0i64;
    d1 = *(_QWORD *)v2;
    v62 = d1;
    d2 = 0i64;
    d2 = *(_QWORD *)(d1 + 1);
    v60 = d2;
    data0 = __ROL8__((data0 ^ d1) + d2 + 33 * data0 + 1, 13);
    if ( (i & 1) != 0 )
      data0 = v60 ^ (v62 + data0);
    if ( (i & 2) != 0 )
      data0 ^= v62 + v60;
    if ( (i & 4) != 0 )
      data0 ^= v60 ^ v62;
    v2 = i & 8;
    if ( (i & 8) != 0 )
    {
      v2 = data0 + v62 + v60;
      data0 = v2;
    }
  }
  v76 = data0;
  strcpy(v6, "input flag:\n");
  v70 = v6;
  v69 = 12i64;
  for ( j = 0; v69 != j; ++j )
  {
    v67 = v70[j];
    v66 = v67;
    __outbyte(1u, v67);                         // putchar
  }
  memset(FlagInData, 0, sizeof(FlagInData));
  flagIn = FlagInData;
  v74 = 0x40i64;
  for ( k = 0; ; ++k )
  {
    if ( v74 == k )
      goto LABEL_3;
    v0 = __inbyte(0);                           // get_char
    v72 = v0;
    v71 = v0;
    if ( v0 == '\n' )
      break;
    *((_BYTE *)flagIn + k) = v71;
  }
  *((_BYTE *)flagIn + k) = 0;
LABEL_3:
  if ( v76 == 0x1C986C3B22EA63E5i64 )
  {
    v52 = FlagInData;
    for ( flagLen = 0i64; *((_BYTE *)v52 + flagLen); ++flagLen )
      ;
    v8 = flagLen;
    if ( flagLen == 32 )
    {
      v45 = FlagInData;
      v44 = 32i64;
      v43 = time0_1 / 0xE10;
      flag_ptr = FlagInData;
      const_32 = 32i64;
      from_t0 = time0_1 / 0xE10;
      v39 = 0x5249415452455451i64;
      __writefsqword(0, 0x5249415452455451ui64);
      for ( i_0 = 0; const_32 != i_0; ++i_0 )
      {
        data1 = __readfsqword(0);               // 0x5249415452455451
        v36 = i_0;
        for ( m = 0; m != 256; ++m )
        {
          data2 = __readfsqword(0);
          v33 = data2;
          v32 = data2;
          v31 = data2;
          v36 = (v36 ^ data2) + data2 + 0x21 * v36 + 1;
          v36 = __ROL8__(v36, 13);
          if ( (m & 1) != 0 )
            v36 = v31 ^ (v33 + v36);
          if ( (m & 2) != 0 )
            v36 ^= v33 + v31;
          if ( (m & 4) != 0 )
            v36 ^= v31 ^ v33;
          if ( (m & 8) != 0 )
            v36 += v33 + v31;
        }
        *((_BYTE *)flag_ptr + i_0) ^= (_BYTE)data1 + (_BYTE)v36;
      }
      for ( n = 0; const_32 != n; n += 4 )      // 4字节一组
      {
        v29 = (unsigned int *)((char *)flag_ptr + n);
        v28 = *v29;
        v27 = 0;
        v26 = v28;
        v28 = from_t0 + _mm_crc32_u32(0, v28);
        *v29 = v28;
      }
      xorKey[0] = 0x178DEC4F232DDB6Ei64;
      xorKey[1] = 0xC2AAB7D6D2A167C3ui64;
      xorKey[2] = 0xF1AB91F72761A80Fui64;
      xorKey[3] = 0x3DCEDC28076C41Ai64;
      for ( ii = 0; v44 != ii; ++ii )
        *((_BYTE *)v45 + ii) ^= *((_BYTE *)xorKey + ii);
      compare[0] = 0x3EC81D9432CEF584i64;
      compare[1] = 0xB649A4DCD6BD24FEui64;
      compare[2] = 0xC5927F0B767A787Dui64;
      compare[3] = 0x1F245B7F751BB52Ei64;
      v24 = FlagInData;
      v23 = compare;
      v22 = v8;
      for ( jj = 0; ; ++jj )
      {
        if ( v22 == jj )
        {
          v1 = 0;
          goto LABEL_47;
        }
        v20 = *((_BYTE *)v24 + jj) - *((_BYTE *)v23 + jj);
        if ( v20 )
          break;
      }
      v1 = v20;
LABEL_47:
      if ( v1 )
      {
        strcpy((char *)&v4, "wrong\n");
        v14 = &v4;
        v13 = 6i64;
        for ( kk = 0; v13 != kk; ++kk )
        {
          v11 = *((_BYTE *)v14 + kk);
          v10 = v11;
          __outbyte(1u, v11);
        }
      }
      else
      {
        strcpy((char *)&v4 + 7, "correct\n");
        v19 = (__int64)&v4 + 7;
        v18 = 8i64;
        for ( mm = 0; v18 != mm; ++mm )
        {
          v16 = *(_BYTE *)(mm + v19);
          v15 = v16;
          __outbyte(1u, v16);
        }
      }
    }
    else
    {
      strcpy(v5, "wrong\n");
      v50 = v5;
      v49 = 6i64;
      for ( nn = 0; v49 != nn; ++nn )
      {
        v47 = v50[nn];
        v46 = v47;
        __outbyte(1u, v47);
      }
    }
  }
  else
  {
    *(_DWORD *)&v5[7] = 'norw';
    *(_WORD *)&v5[11] = '\ng';
    v5[13] = 0;
    v57 = &v5[7];
    v56 = 6i64;
    for ( i1 = 0; v56 != i1; ++i1 )
    {
      v54 = v57[i1];
      v53 = v54;
      __outbyte(1u, v54);
    }
  }
  __halt();
}

程序入口调用 syscall,由 unicorn 回调处理获取 time(0) 的值,并根据该值计算一个数 0x1C986C3B22EA63E5

 

 

为了屏蔽 ida 的优化,方便分析,我做了一些小 patch

  • syscall 的 unicorn 回调会修改 rax 寄存器,但是 ida 认为 rax 的值是一个可计算的常数,于是后面与 rax 有关的表达式都被优化。
  • for 循环中读取了两次 fs:0 , 有unicorn回调,每次读取的值肯定不一样,ida 认为两次读取的值一样,于是优化成一次访问。

手动 patch ,即可解决这些问题。

 

有两种爆破思路:

  • 直接爆破 time(0)
  • 根据 flag 信息反向爆破

可以用 flag 开头来爆破 time(0) 时间常数

 

from_t0 = time_0 / 0xE10;

 

 

由于 4字节一组,qwb{QWB{flagFLAG 都是已知的 4 个字节并且 v28 可以非常轻松的获得

 

通过爆破开头也可以反推 time(0)

 

爆破出 time(0) 后的做法就是非常简单的计算任务了

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
#include <iostream>
#include "ida.h"
#include <x86intrin.h>
 
 
static uint64  fs_0;
uint64 getFS0() {
    // v7[0] = 8461816625668189699LL * v7[0] + 841540768324766462LL;
    fs_0 = 0x756E69636F726E03 * fs_0 + 0xBADC0DEC001CAFE;
    return fs_0;
}
void setFSO(int64_t val) {
    fs_0 = val;
}
 
uint64 test_time(uint64 time) {
    uint64  v35;
    setFSO(0x7177625F32303231);
 
    uint64 v2 = time ;
    uint64  data0 = time ;
    uint64 d1, d2,v62, v60;
 
    for (int i = 0; i != 256; ++i )
    {
        d1 = 0;
        d1 = getFS0();
        v62 = d1;
        d2 = getFS0();
        v60 = d2;
        data0 = __ROL8__((data0 ^ d1) + d2 + 33 * data0 + 1, 13);
        if ( (i & 1) != 0 )
            data0 = v60 ^ (v62 + data0);
        if ( (i & 2) != 0 )
            data0 ^= v62 + v60;
        if ( (i & 4) != 0 )
            data0 ^= v60 ^ v62;
        v2 = i & 8;
        if ( (i & 8) != 0 )
        {
            v2 = data0 + v62 + v60;
            data0 = v2;
        }
    }
    printf("%p ==\n", data0);
    return data0;
}
 
int main() {
    std::cout << "Hello, World!" << std::endl;
    unsigned __int64 compare[4];
    unsigned __int64 xorKey[4];
    unsigned int flags[] = {0x67616c66, 0x47414c46, 0x7b627771, 0x7b425751};
    unsigned char xorkey0[32] = {0};
    uint32  * xorkey0_4 = (uint32  *)xorkey0;
    compare[0] = 0x3EC81D9432CEF584; // flag, FLAG, qwb{ ,QWB{
    compare[1] = 0xB649A4DCD6BD24FE;
    compare[2] = 0xC5927F0B767A787D;
    compare[3] = 0x1F245B7F751BB52E;
    xorKey[0] = 0x178DEC4F232DDB6E;
    xorKey[1] = 0xC2AAB7D6D2A167C3;
    xorKey[2] = 0xF1AB91F72761A80F;
    xorKey[3] = 0x3DCEDC28076C41A;
 
    unsigned int * compare_4 = (unsigned int *)compare;
 
 
    unsigned int fs;
    uint64 v35, v36, v33,v32, v31, v30;
    setFSO(0x5249415452455451);
    for (int i_0 = 0; 32 != i_0; ++i_0 )
    {
        uint64 data0 = getFS0();               // 0x5249415452455451
        v35 = i_0;
        for (int m = 0; m != 256; ++m )
        {
            uint64 data1 = getFS0();
            uint64 data2 = getFS0();
            v35 = (v35 ^ data1) + data2 + 0x21 * v35 + 1;
 
            v35 = __ROL8__(v35, 13);
            if ( (m & 1) != 0 )
                v35 = data2 ^ (data1 + v35);
            if ( (m & 2) != 0 )
                v35 ^= data2 + data1;
            if ( (m & 4) != 0 )
                v35 ^= data2 ^ data1;
            if ( (m & 8) != 0 )
                v35 += data2 + data1;
        }
        xorkey0[i_0] =  (_BYTE)data0 + (_BYTE)v35;
    }
 
    for(int k = 0; k < 4; k++) {
        unsigned char * data = (unsigned  char *)&flags[k];
        for (int i = 0 ; i < 4; i++) {
            data[i] ^= xorkey0[i];
        }
       // printf("%x\n", flags[k]);
    }
 
    for (int ii = 0; 32 != ii; ++ii )
        *((_BYTE *)compare + ii) ^= *((_BYTE *)xorKey + ii);
 
 
    uint64 targetTT = 0;
    for (int i = 0; i < 4; i++)
    {
        // v27 = from_t0 + _mm_crc32_u32(0, v27);
      //  unsigned int from_t0 = compare_4[0] - _mm_crc32_u32(0, flags[i]);
        uint64 tt = compare_4[0] - _mm_crc32_u32(0, flags[i]);
        uint64 rr = test_time(tt);
        if (rr == 0x1c986c3b22ea63e5) {
            targetTT = tt;
            printf("val:%p\n", tt);
        }
    }
 
    uint32 flag_arr[8];
    for (int i = 0; i < 8; ++i) { // 4 * 8
        for (uint32 val = 0; val != 0xffffffff; ++val) {
            if (compare_4[i] - targetTT == _mm_crc32_u32(0, val)) {
                flag_arr[i] = val;
                break;
            }
        }
    }
    for (int i = 0; i < 8; ++i) {
        flag_arr[i] ^= xorkey0_4[i];
    }
    printf("%s", (char *)flag_arr);
 
    return 0;
}

2021 KCTF 秋季赛 防守篇-征题倒计时(11月14日截止)!

收藏
点赞7
打赏
分享
最新回复 (16)
雪    币: 15488
活跃值: 活跃值 (20571)
能力值: (RANK:75 )
在线值:
发帖
回帖
粉丝
Editor 活跃值 2021-6-14 21:32
2
0
感谢分享~
雪    币:
活跃值: 活跃值 (148)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_rhynjqzk 活跃值 2021-6-14 22:02
3
0
无名侠爷爷tql!!!所以除了unicorn还有其它re的wp吗,比如Longtimeago
雪    币: 2608
活跃值: 活跃值 (1804)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
YenKoc 活跃值 2021-6-14 22:07
4
0
666,tql
雪    币: 9919
活跃值: 活跃值 (11537)
能力值: (RANK:650 )
在线值:
发帖
回帖
粉丝
ScUpax0s 活跃值 11 2021-6-14 22:12
5
0
太强了
雪    币: 59
活跃值: 活跃值 (451)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zbzb 活跃值 2021-6-14 22:23
6
0
厉害啊!
雪    币: 3551
活跃值: 活跃值 (510)
能力值: ( LV5,RANK:63 )
在线值:
发帖
回帖
粉丝
Minhal 活跃值 2021-6-14 22:45
7
0

无名爷爷!

最后于 2021-6-14 22:46 被Minhal编辑 ,原因:
雪    币: 553
活跃值: 活跃值 (1568)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
葫芦娃 活跃值 1 2021-6-14 23:09
8
0
无名哥哥我爱你 [打call][打call][打call]
雪    币: 1033
活跃值: 活跃值 (1117)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
77pray 活跃值 2021-6-15 00:15
9
0
无名哥哥我爱你 [打call][打call][打call] 
雪    币: 2136
活跃值: 活跃值 (402)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
zhouws 活跃值 2 2021-6-15 11:44
10
0
倒是学了个符号还原技能
雪    币: 3227
活跃值: 活跃值 (1675)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
Jev0n 活跃值 2021-6-15 14:47
11
0
太强了
雪    币: 5499
活跃值: 活跃值 (1272)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
alphc 活跃值 2021-6-15 23:29
12
0
牛逼
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
CHOLASLEE 活跃值 2021-6-16 15:52
13
0
想请教下楼主是怎么控制编译方式和参数的,我编译出来的和题目匹配不上
雪    币: 7160
活跃值: 活跃值 (4167)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
34r7hm4n 活跃值 5 2021-6-16 15:54
14
0
爷爷!
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
大史 4.0 活跃值 2021-6-21 22:31
15
0
想问下最后的头文件"ida.h"是包含在crypto++包中的还是idasdk的呢?用g++ 带头文件指定路径-I ./ida.h_path都保存编译不通过诶
雪    币: 2879
活跃值: 活跃值 (2956)
能力值: ( LV15,RANK:685 )
在线值:
发帖
回帖
粉丝
无名侠 活跃值 11 2021-6-22 23:46
16
0
CHOLASLEE 想请教下楼主是怎么控制编译方式和参数的,我编译出来的和题目匹配不上[em_67]
不能完全识别,ubuntu 20 编译,similarity 最低 0.5
雪    币: 2879
活跃值: 活跃值 (2956)
能力值: ( LV15,RANK:685 )
在线值:
发帖
回帖
粉丝
无名侠 活跃值 11 2021-6-22 23:47
17
0
大史 4.0 想问下最后的头文件"ida.h"是包含在crypto++包中的还是idasdk的呢?用g++ 带头文件指定路径-I ./ida.h_path都保存编译不通过诶
ida.h 就是 idasdk 里的文件,可以直接编译。
游客
登录 | 注册 方可回帖
返回