n1vm, N1CTF 2025
n1vm
I have done this challenge with m1nds and Nardre.
Handout
1
2
3
I have been practicing human virtual machine reverse engineering
for two and a half years. But now, with the help of AI, I can complete
a virtual machine protection shell in just two and a half days.
We are also given this file:
1
2
$ file problem.exe
problem.exe: PE32+ executable (console) x86-64, for MS Windows, 6 sections
First analysis
Let’s first try to run the binary:
1
2
3
$ wine problem.exe
> hello
Wrong
Let’s open it in Ghidra.
We can see that the program is in C++, and that it takes 4 numbers as input. After that, it calls a function that I’ve renamed here vm_start, which seems to return a value. If this value is 0, this means that the input is wrong, otherwise it is correct.
Let’s have a look at the code in vm_start. From now, I will only show the code in asm, as the decompiled code is not very useful here.
We see that our parameters were stored in rcx, rdx, r8, r9. They are after pushed on the stack with some other values, and then in order to jump to another function, the program does a lea, push and ret. Therefore, when the ret is executed, it pops the address at the top of the stack (which is the address moved using lea) into the instruction pointer, and jumps to it. This is basically a way to do a jmp to an address computed at runtime.
Let’s continue the analysis by looking at the next code segment in 0x140001e8d:
We can see that it might use the values at [r8] and [r8+0x10] like registers, and it still uses the same method to jump to the next code segment. Let’s look at other segments to confirm this theory.
With these two segments, we can confirm that [r8 + XX] are used like registers, and that there seems to be some basic obfuscation inside some segments (like the one above where some operations seem irrelevant).
With that in mind, we need to find an efficient way to reverse this binary, and to do so, we decided to use Miasm’s Symbolic Execution engine to have a better understanding of the VM.
Symbolic Execution with Miasm
The base code I will be using here is taken from this repository, because I have used this video to learn how to reverse a VM and how to use Miasm for that.
This is the final script and I will explain it after:
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
#!/usr/bin/python3
import sys
from miasm.analysis.binary import Container
from miasm.analysis.machine import Machine
from miasm.core.locationdb import LocationDB
from miasm.expression.expression import *
from miasm.expression.simplifications import expr_simp
from miasm.ir.symbexec import SymbolicExecutionEngine
def get_register_value(sb, reg_name):
r8 = sb.symbols[ExprId("R8", 64)]
reg_name = reg_name[1:]
number_reg = int(reg_name)
address = expr_simp(r8 + ExprInt(0x8 * number_reg, 64))
constant = expr_simp(sb.symbols[ExprMem(address, 64)])
return constant
def get_r8_value(sb):
r8 = sb.symbols[ExprId("R8", 64)]
return r8
def get_memory_value(sb, address):
constant = expr_simp(sb.symbols[ExprMem(ExprInt(address, 64), 64)])
return constant
# hardcoded list of VM handlers taken from the binary
VM_HANDLERS = {
0x140001360: lambda sb, addr: print(f"{hex(int(addr))}: VM_INIT"),
0x140001e8d: lambda sb, addr: print(f"{hex(int(addr))}: [G0 + 0x8] = G2 ({get_register_value(sb, 'G2')}) (R8 = {get_r8_value(sb)})"),
0x14000146a: lambda sb, addr: print(f"{hex(int(addr))}: [G0 + 0x10] = G6 ({get_register_value(sb, 'G6')})"),
0x1400013d4: lambda sb, addr: print(f"{hex(int(addr))}: G10 = 0"),
# to check after
0x14000196c: lambda sb, addr: print(f"{hex(int(addr))}: G6 = [0x140005840] - 0x3ac0 ({expr_simp(get_memory_value(sb, 0x140005840) - ExprInt(0x3ac0, 64))})"),
0x1400015ad: lambda sb, addr: print(f"{hex(int(addr))}: G1 = G10 ({get_register_value(sb, 'G10')})"),
0x140001d21: lambda sb, addr: print(f"{hex(int(addr))}: G2 = G10 ({get_register_value(sb, 'G10')})"),
0x140001585: lambda sb, addr: print(f"{hex(int(addr))}: G11 = G10 ({get_register_value(sb, 'G10')})"),
0x140001cbd: lambda sb, addr: print(f"{hex(int(addr))}: G16 = flag(G3 & 1) (G3 = {get_register_value(sb, 'G3')})"),
0x140001a82: lambda sb, addr: print(f"{hex(int(addr))}: if JZ[flag(G16)]: goto 0x14000162f else goto 0x140001a9a"),
0x140001a9a: lambda sb, addr: print(f"{hex(int(addr))}: G1 = G1 + [G11 + G6 + 0x3ac0] ({get_register_value(sb, 'G1')} + [{get_register_value(sb, 'G11')} + {get_register_value(sb, 'G6')} + 0x3ac0]) "),
0x14000162f: lambda sb, addr: print(f"{hex(int(addr))}: G3 = G3 >> 1 (G3 = {get_register_value(sb, 'G3')} => {expr_simp(get_register_value(sb, 'G3') >> ExprInt(1, 64))})"),
0x14000167f: lambda sb, addr: print(f"{hex(int(addr))}: G11 = G11 + 0x8 ({get_register_value(sb, 'G11')} + 0x8 => {expr_simp(get_register_value(sb, 'G11') + ExprInt(0x8, 64))})"),
0x14000141c: lambda sb, addr: print(f"{hex(int(addr))}: G16 = flag(cmp G11 0x200) (G11 = {get_register_value(sb, 'G11')})"),
0x140001668: lambda sb, addr: print(f"{hex(int(addr))}: if JC[flag(G16)]: goto 0x140001cbd else goto 0x14000143b"),
0x140001482: lambda sb, addr: print(f"{hex(int(addr))}: G2 = G2 + [G11 + G6 + 0x32c0] ({get_register_value(sb, 'G2')} + [{get_register_value(sb, 'G11')} + {get_register_value(sb, 'G6')} + 0x32c0]) "),
0x140001884: lambda sb, addr: print(f"{hex(int(addr))}: G16 = flag(cmp G1 0x1770) (G1 = {get_register_value(sb, 'G1')})"),
0x140001a18: lambda sb, addr: print(f"{hex(int(addr))}: if JA[flag(G16)]: goto 0x140001cdb else goto 0x14000162f"),
0x140001cdb: lambda sb, addr: print(f"{hex(int(addr))}: G1 = 0"),
0x14000181b: lambda sb, addr: print(f"{hex(int(addr))}: G2 = [G0 + 0x8] (G0 = {get_register_value(sb, 'G0')})"),
0x140001c63: lambda sb, addr: print(f"{hex(int(addr))}: G6 = [G0 + 0x10] (G0 = {get_register_value(sb, 'G0')})"),
0x140001cb0: lambda sb, addr: print(f"{hex(int(addr))}: preparing end"),
0x1400015bf: lambda sb, addr: print(f"{hex(int(addr))}: RAX = G1 ({get_register_value(sb, 'G1')})"),
0x14000143b: lambda sb, addr: print(f"{hex(int(addr))}: G3 = G10 ({get_register_value(sb, 'G10')})"),
0x140001d65: lambda sb, addr: print(f"{hex(int(addr))}: G16 = flag(G4 & 1) (G4 = {get_register_value(sb, 'G4')})"),
}
def constraint_memory(address, num_of_bytes):
"""
Reads `num_of_bytes` from the binary at a given address
and builds symbolic formulas to pre-configure the symbolic
execution engine for concolinc execution.
"""
global container
# read bytes from binary
byte_stream = container.bin_stream.getbytes(address, num_of_bytes)
# build symbolic memory address
sym_address = ExprMem(ExprInt(address, 64), num_of_bytes * 8)
# build symbolic memory value
sym_value = ExprInt(int.from_bytes(
byte_stream, byteorder='little'), num_of_bytes * 8)
return sym_address, sym_value
def disassemble(sb, address):
"""
Callback to dump individual VM handler information,
execution context etc.
"""
# fetch concrete value of current virtual instruction pointer
#vip = sb.symbols[ExprId("RDX", 64)]
#if int(address) == 0x140001cbd:
# print("alerte")
if int(address) in VM_HANDLERS:
VM_HANDLERS[int(address)](sb, address)
else:
#print(f"{hex(int(address))}: Unknown VM handler.")
#r8 = sb.symbols[ExprId("R8", 64)]
#address_0x18 = expr_simp(r8 + ExprInt(0x18, 64))
#constant_0x18 = expr_simp(sb.symbols[ExprMem(address_0x18, 64)])
#address_0x80 = expr_simp(r8 + ExprInt(0x80, 64))
#constant_0x80 = expr_simp(sb.symbols[ExprMem(address_0x80, 64)])
print(f"{hex(int(address))}: Unknown VM handler.")
# parse file path
file_path = "problem.exe"
# address of vm entry
start_addr = 0x140001360
# init symbol table
loc_db = LocationDB()
# read binary file
container = Container.from_stream(open(file_path, 'rb'), loc_db)
# get CPU abstraction
machine = Machine(container.arch)
# disassembly engine
mdis = machine.dis_engine(container.bin_stream, loc_db=loc_db)
# initialize lifter to intermediate representation
lifter = machine.lifter_model_call(mdis.loc_db)
# disassemble the function at address
asm_cfg = mdis.dis_multiblock(start_addr)
# translate asm_cfg into ira_cfg
ira_cfg = lifter.new_ircfg_from_asmcfg(asm_cfg)
ALLOWED_START_ADDRS = {
0x140001360: ira_cfg,
}
# init SE engine
sb = SymbolicExecutionEngine(lifter)
# constraint bytecode -- start address and size (highest address - lowest address)
sym_address, sym_value = constraint_memory(0x140005040, 0x140006040 - 0x140005040)
sb.symbols[sym_address] = sym_value
# constraint VM input (rcx, first function argument). The value in `ExprInt` rerpesents the function's input value.
rcx = ExprId("RCX", 64)
sb.symbols[rcx] = ExprInt(2**63, 64)
#
#rdx = ExprId("RDX", 64)
#sb.symbols[rdx] = ExprInt(2, 64)
#
#r8 = ExprId("R8", 64)
#sb.symbols[r8] = ExprInt(3, 64)
#
#r9 = ExprId("R9", 64)
#sb.symbols[r9] = ExprInt(4, 64)
# init worklist
basic_block_worklist = [ExprInt(start_addr, 64)]
nb_to_run = 1000000000000
# worklist algorithm
while basic_block_worklist and nb_to_run > 0:
# get current block
current_block = basic_block_worklist.pop()
# print(f"current block: {current_block}")
# if current block is a VM handler, dump handler-specific knowledge
if current_block.is_int() and int(current_block):
disassemble(sb, current_block)
else:
print(f"current block: {current_block}")
if current_block.is_int() and int(current_block) in ALLOWED_START_ADDRS:
next_block = sb.run_block_at(ALLOWED_START_ADDRS[int(current_block)], current_block, step=False)
else:
asm_cfg_tmp = mdis.dis_multiblock(int(current_block))
ira_cfg_tmp = lifter.new_ircfg_from_asmcfg(asm_cfg_tmp)
ALLOWED_START_ADDRS[int(current_block)] = ira_cfg_tmp
next_block = sb.run_block_at(ira_cfg_tmp, current_block, step=False)
# print(f"next block: {next_block}")
#print(sb.symbols)
if next_block.is_int() and current_block.is_int() and int(current_block) == int(next_block):
print("Stuck in the same block, stopping execution to avoid infinite loop.")
break
# is next block is integer or label, continue execution
if next_block.is_int() or next_block.is_loc():
basic_block_worklist.append(next_block)
nb_to_run -= 1
print(f"next block: {next_block}")
print(f"RAX: {sb.symbols[ExprId('RAX', 64)]}")
print(f"nb blocks: {len(ALLOWED_START_ADDRS)}")
print(f"implemented: {len(VM_HANDLERS)}")
#print(sb.symbols)
# dump symbolic state
# sb.dump()
# dump VMs/functions' return value -- only works if SE runs until the end
# rax = ExprId("RAX", 64)
# value = sb.symbols[rax]
# print(f"VM return value: {value}")
The first thing we do is loading the binary and defining the start of the program (we will choose here the start of vm_start).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# parse file path
file_path = "problem.exe"
# address of vm entry
start_addr = 0x140001360
# init symbol table
loc_db = LocationDB()
# read binary file
container = Container.from_stream(open(file_path, 'rb'), loc_db)
# get CPU abstraction
machine = Machine(container.arch)
# disassembly engine
mdis = machine.dis_engine(container.bin_stream, loc_db=loc_db)
# initialize lifter to intermediate representation
lifter = machine.lifter_model_call(mdis.loc_db)
We then have to disassemble and tell Miasm that our code at the start address is executable:
1
2
3
4
# disassemble the function at address
asm_cfg = mdis.dis_multiblock(start_addr)
# translate asm_cfg into ira_cfg
ira_cfg = lifter.new_ircfg_from_asmcfg(asm_cfg)
Because of the jump obfuscation (the lea, push, ret trick), Miasm cannot automatically detect that it has to disassemble those segments, so we will be using a dict to do so. Each time our rip value is on a block that is not already disassembled, we will disassemble it and add it to the dict for future use.
1
2
3
4
5
6
7
8
9
10
11
ALLOWED_START_ADDRS = {
0x140001360: ira_cfg,
}
[...]
if current_block.is_int() and int(current_block) in ALLOWED_START_ADDRS:
next_block = sb.run_block_at(ALLOWED_START_ADDRS[int(current_block)], current_block, step=False)
else:
asm_cfg_tmp = mdis.dis_multiblock(int(current_block))
ira_cfg_tmp = lifter.new_ircfg_from_asmcfg(asm_cfg_tmp)
ALLOWED_START_ADDRS[int(current_block)] = ira_cfg_tmp
next_block = sb.run_block_at(ira_cfg_tmp, current_block, step=False)
We can now create our Symbolic Execution Engine and define some memory that the program will be using. As you will see afterwards, the VM will be using some data stored in the binary, and we need to tell Miasm to load this memory so the symbolic execution can use it. We then put it in the sb.symbols, which is a dictionary containing all the symbolic values, such as registers, stack, and memory.
1
2
3
4
5
6
# init SE engine
sb = SymbolicExecutionEngine(lifter)
# constraint bytecode -- start address and size (highest address - lowest address)
sym_address, sym_value = constraint_memory(0x140005040, 0x140006040 - 0x140005040)
sb.symbols[sym_address] = sym_value
We are now ready to start, we just need to define the input of the VM. As seen before, the different inputs are stored in rcx, rdx, r8, r9 registers, so we just need to define them in the sb.symbols dictionary. But we can also not define them in order to see where these registers are used, and what are the constraints on it.
1
2
3
4
5
6
7
8
9
10
11
12
# constraint VM input (rcx, first function argument). The value in `ExprInt` rerpesents the function's input value.
rcx = ExprId("RCX", 64)
sb.symbols[rcx] = ExprInt(2**63, 64)
#
#rdx = ExprId("RDX", 64)
#sb.symbols[rdx] = ExprInt(2, 64)
#
#r8 = ExprId("R8", 64)
#sb.symbols[r8] = ExprInt(3, 64)
#
#r9 = ExprId("R9", 64)
#sb.symbols[r9] = ExprInt(4, 64)
We can now start the symbolic execution at our start_addr. For each block, we will disassemble it (which is logging what the block does, we will talk about it later), then execute it using sb.run_block_at, and finally add the next block to the worklist. At the end of the execution, we need to check the value of RAX, which contains the return value of the VM (if it is 0, the input is wrong, otherwise it is correct). We’ve also implemented the nb_to_run variable to control the number of blocks we want to execute.
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
basic_block_worklist = [ExprInt(start_addr, 64)]
nb_to_run = 1000000000000
# worklist algorithm
while basic_block_worklist and nb_to_run > 0:
# get current block
current_block = basic_block_worklist.pop()
# print(f"current block: {current_block}")
# if current block is a VM handler, dump handler-specific knowledge
if current_block.is_int() and int(current_block):
disassemble(sb, current_block)
else:
print(f"current block: {current_block}")
if current_block.is_int() and int(current_block) in ALLOWED_START_ADDRS:
next_block = sb.run_block_at(ALLOWED_START_ADDRS[int(current_block)], current_block, step=False)
else:
asm_cfg_tmp = mdis.dis_multiblock(int(current_block))
ira_cfg_tmp = lifter.new_ircfg_from_asmcfg(asm_cfg_tmp)
ALLOWED_START_ADDRS[int(current_block)] = ira_cfg_tmp
next_block = sb.run_block_at(ira_cfg_tmp, current_block, step=False)
# print(f"next block: {next_block}")
#print(sb.symbols)
if next_block.is_int() and current_block.is_int() and int(current_block) == int(next_block):
print("Stuck in the same block, stopping execution to avoid infinite loop.")
break
# is next block is integer or label, continue execution
if next_block.is_int() or next_block.is_loc():
basic_block_worklist.append(next_block)
nb_to_run -= 1
print(f"next block: {next_block}")
print(f"RAX: {sb.symbols[ExprId('RAX', 64)]}")
print(f"nb blocks: {len(ALLOWED_START_ADDRS)}")
print(f"implemented: {len(VM_HANDLERS)}")
The main goal of this script is to understand at a higher level what each block does. To do so, we have created the disassemble function. For each block, it will log what it does after some manual deobfuscation and analysis of the code segment. With that, we will also be able to log the values in each virtual register (which are located at [r8 + XX]), which will be called here GX. G0 is at [r8 + 0x0], G1 at [r8 + 0x8], G2 at [r8 + 0x10], and so on.
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
def get_register_value(sb, reg_name):
r8 = sb.symbols[ExprId("R8", 64)]
reg_name = reg_name[1:]
number_reg = int(reg_name)
address = expr_simp(r8 + ExprInt(0x8 * number_reg, 64))
constant = expr_simp(sb.symbols[ExprMem(address, 64)])
return constant
def get_r8_value(sb):
r8 = sb.symbols[ExprId("R8", 64)]
return r8
def get_memory_value(sb, address):
constant = expr_simp(sb.symbols[ExprMem(ExprInt(address, 64), 64)])
return constant
# hardcoded list of VM handlers taken from the binary
VM_HANDLERS = {
0x140001360: lambda sb, addr: print(f"{hex(int(addr))}: VM_INIT"),
0x140001e8d: lambda sb, addr: print(f"{hex(int(addr))}: [G0 + 0x8] = G2 ({get_register_value(sb, 'G2')}) (R8 = {get_r8_value(sb)})"),
0x14000146a: lambda sb, addr: print(f"{hex(int(addr))}: [G0 + 0x10] = G6 ({get_register_value(sb, 'G6')})"),
0x1400013d4: lambda sb, addr: print(f"{hex(int(addr))}: G10 = 0"),
# to check after
0x14000196c: lambda sb, addr: print(f"{hex(int(addr))}: G6 = [0x140005840] - 0x3ac0 ({expr_simp(get_memory_value(sb, 0x140005840) - ExprInt(0x3ac0, 64))})"),
0x1400015ad: lambda sb, addr: print(f"{hex(int(addr))}: G1 = G10 ({get_register_value(sb, 'G10')})"),
0x140001d21: lambda sb, addr: print(f"{hex(int(addr))}: G2 = G10 ({get_register_value(sb, 'G10')})"),
0x140001585: lambda sb, addr: print(f"{hex(int(addr))}: G11 = G10 ({get_register_value(sb, 'G10')})"),
0x140001cbd: lambda sb, addr: print(f"{hex(int(addr))}: G16 = flag(G3 & 1) (G3 = {get_register_value(sb, 'G3')})"),
0x140001a82: lambda sb, addr: print(f"{hex(int(addr))}: if JZ[flag(G16)]: goto 0x14000162f else goto 0x140001a9a"),
0x140001a9a: lambda sb, addr: print(f"{hex(int(addr))}: G1 = G1 + [G11 + G6 + 0x3ac0] ({get_register_value(sb, 'G1')} + [{get_register_value(sb, 'G11')} + {get_register_value(sb, 'G6')} + 0x3ac0]) "),
0x14000162f: lambda sb, addr: print(f"{hex(int(addr))}: G3 = G3 >> 1 (G3 = {get_register_value(sb, 'G3')} => {expr_simp(get_register_value(sb, 'G3') >> ExprInt(1, 64))})"),
0x14000167f: lambda sb, addr: print(f"{hex(int(addr))}: G11 = G11 + 0x8 ({get_register_value(sb, 'G11')} + 0x8 => {expr_simp(get_register_value(sb, 'G11') + ExprInt(0x8, 64))})"),
0x14000141c: lambda sb, addr: print(f"{hex(int(addr))}: G16 = flag(cmp G11 0x200) (G11 = {get_register_value(sb, 'G11')})"),
0x140001668: lambda sb, addr: print(f"{hex(int(addr))}: if JC[flag(G16)]: goto 0x140001cbd else goto 0x14000143b"),
0x140001482: lambda sb, addr: print(f"{hex(int(addr))}: G2 = G2 + [G11 + G6 + 0x32c0] ({get_register_value(sb, 'G2')} + [{get_register_value(sb, 'G11')} + {get_register_value(sb, 'G6')} + 0x32c0]) "),
0x140001884: lambda sb, addr: print(f"{hex(int(addr))}: G16 = flag(cmp G1 0x1770) (G1 = {get_register_value(sb, 'G1')})"),
0x140001a18: lambda sb, addr: print(f"{hex(int(addr))}: if JA[flag(G16)]: goto 0x140001cdb else goto 0x14000162f"),
0x140001cdb: lambda sb, addr: print(f"{hex(int(addr))}: G1 = 0"),
0x14000181b: lambda sb, addr: print(f"{hex(int(addr))}: G2 = [G0 + 0x8] (G0 = {get_register_value(sb, 'G0')})"),
0x140001c63: lambda sb, addr: print(f"{hex(int(addr))}: G6 = [G0 + 0x10] (G0 = {get_register_value(sb, 'G0')})"),
0x140001cb0: lambda sb, addr: print(f"{hex(int(addr))}: preparing end"),
0x1400015bf: lambda sb, addr: print(f"{hex(int(addr))}: RAX = G1 ({get_register_value(sb, 'G1')})"),
0x14000143b: lambda sb, addr: print(f"{hex(int(addr))}: G3 = G10 ({get_register_value(sb, 'G10')})"),
0x140001d65: lambda sb, addr: print(f"{hex(int(addr))}: G16 = flag(G4 & 1) (G4 = {get_register_value(sb, 'G4')})"),
}
[...]
def disassemble(sb, address):
"""
Callback to dump individual VM handler information,
execution context etc.
"""
# fetch concrete value of current virtual instruction pointer
#vip = sb.symbols[ExprId("RDX", 64)]
#if int(address) == 0x140001cbd:
# print("alerte")
if int(address) in VM_HANDLERS:
VM_HANDLERS[int(address)](sb, address)
else:
#print(f"{hex(int(address))}: Unknown VM handler.")
#r8 = sb.symbols[ExprId("R8", 64)]
#address_0x18 = expr_simp(r8 + ExprInt(0x18, 64))
#constant_0x18 = expr_simp(sb.symbols[ExprMem(address_0x18, 64)])
#address_0x80 = expr_simp(r8 + ExprInt(0x80, 64))
#constant_0x80 = expr_simp(sb.symbols[ExprMem(address_0x80, 64)])
print(f"{hex(int(address))}: Unknown VM handler.")
For example let’s have a look at two of the segments:
Here we can see that [[R8] + 0x8] = [R8 + 0x10], and then there is the lea, push, ret trick to jump to the next segment. Therefore, as we defined G0 as [R8] and G2 as [R8 + 0x10], we can log that this segment does [G0 + 0x8] = G2.
In this segment, there is a bit of obfuscation, as some operations seem useless. We can rewrite this code as:
1
2
3
4
1400013dd 49 8b 50 50 MOV RDX,qword ptr [R8 + 0x50]
1400013ea 4d 8b 60 50 MOV R12,qword ptr [R8 + 0x50]
1400013fb 49 33 d4 XOR RDX,R12
14000140f 49 89 50 50 MOV qword ptr [R8 + 0x50],RDX
Which is basically [R8 + 0x50] = [R8 + 0x50] ^ [R8 + 0x50], which is 0. Therefore, we can log that this segment does G10 = 0 (as G10 is at [R8 + 0x50]).
We continued to deobfuscate and analyze each segment, and wrote the corresponding log in the VM_HANDLERS dictionary.
Understanding the algorithm
Let’s have a look at the logs we obtained when we do not define any input register:
1
2
3
4
5
6
7
8
9
10
11
12
python3 vm_disassembler_final.py
0x140001360: VM_INIT
0x140001e8d: [G0 + 0x8] = G2 (RBX) (R8 = 0x140006640)
0x14000146a: [G0 + 0x10] = G6 (RDI)
0x1400013d4: G10 = 0
0x14000196c: G6 = [0x140005840] - 0x3ac0 (0xFFFFFFFFFFFFC830)
0x1400015ad: G1 = G10 (0x0)
0x140001d21: G2 = G10 (0x0)
0x140001585: G11 = G10 (0x0)
0x140001cbd: G16 = flag(G3 & 1) (G3 = RCX)
0x140001a82: if JZ[flag(G16)]: goto 0x14000162f else goto 0x140001a9a
next block: (RCX & 0x1)?(0x140001A90,0x14000162F)
We can see that Miasm is blocked here, as it next rip value depends on the value of RCX & 0x1. We can clearly see here a JZ instruction that jumps depending on the value of the least significant bit of G3 (which is RCX). Therefore, the first input register used here is RCX. Let’s define it as 1 and rerun the script:
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
0x140001360: VM_INIT
0x140001e8d: [G0 + 0x8] = G2 (RBX) (R8 = 0x140006640)
0x14000146a: [G0 + 0x10] = G6 (RDI)
0x1400013d4: G10 = 0
0x14000196c: G6 = [0x140005840] - 0x3ac0 (0xFFFFFFFFFFFFC830)
0x1400015ad: G1 = G10 (0x0)
0x140001d21: G2 = G10 (0x0)
0x140001585: G11 = G10 (0x0)
0x140001cbd: G16 = flag(G3 & 1) (G3 = 0x1)
0x140001a82: if JZ[flag(G16)]: goto 0x14000162f else goto 0x140001a9a
0x140001a90: Unknown VM handler.
0x140001a9a: G1 = G1 + [G11 + G6 + 0x3ac0] (0x0 + [0x0 + 0x140001D80 + 0x3ac0])
0x140001482: G2 = G2 + [G11 + G6 + 0x32c0] (0x0 + [0x0 + 0x140001D80 + 0x32c0])
0x140001884: G16 = flag(cmp G1 0x1770) (G1 = 0x2F0)
0x140001a18: if JA[flag(G16)]: goto 0x140001cdb else goto 0x14000162f
0x140001a26: Unknown VM handler.
0x14000162f: G3 = G3 >> 1 (G3 = 0x1 => 0x0)
0x14000167f: G11 = G11 + 0x8 (0x0 + 0x8 => 0x8)
0x14000141c: G16 = flag(cmp G11 0x200) (G11 = 0x8)
0x140001668: if JC[flag(G16)]: goto 0x140001cbd else goto 0x14000143b
0x140001cbd: G16 = flag(G3 & 1) (G3 = 0x0)
0x140001a82: if JZ[flag(G16)]: goto 0x14000162f else goto 0x140001a9a
0x14000162f: G3 = G3 >> 1 (G3 = 0x0 => 0x0)
0x14000167f: G11 = G11 + 0x8 (0x8 + 0x8 => 0x10)
0x14000141c: G16 = flag(cmp G11 0x200) (G11 = 0x10)
0x140001668: if JC[flag(G16)]: goto 0x140001cbd else goto 0x14000143b
0x140001cbd: G16 = flag(G3 & 1) (G3 = 0x0)
0x140001a82: if JZ[flag(G16)]: goto 0x14000162f else goto 0x140001a9a
0x14000162f: G3 = G3 >> 1 (G3 = 0x0 => 0x0)
0x14000167f: G11 = G11 + 0x8 (0x10 + 0x8 => 0x18)
0x14000141c: G16 = flag(cmp G11 0x200) (G11 = 0x18)
0x140001668: if JC[flag(G16)]: goto 0x140001cbd else goto 0x14000143b
0x140001cbd: G16 = flag(G3 & 1) (G3 = 0x0)
[...]
0x140001cbd: G16 = flag(G3 & 1) (G3 = 0x0)
0x140001a82: if JZ[flag(G16)]: goto 0x14000162f else goto 0x140001a9a
0x14000162f: G3 = G3 >> 1 (G3 = 0x0 => 0x0)
0x14000167f: G11 = G11 + 0x8 (0x1F8 + 0x8 => 0x200)
0x14000141c: G16 = flag(cmp G11 0x200) (G11 = 0x200)
0x140001668: if JC[flag(G16)]: goto 0x140001cbd else goto 0x14000143b
0x140001676: Unknown VM handler.
0x14000143b: G3 = G10 (0x0)
0x140001d65: G16 = flag(G4 & 1) (G4 = RDX)
0x1400013bc: Unknown VM handler.
next block: (RDX & 0x1)?(0x1400013CA,0x140001A46)
RAX: 0x140001D80
Let’s have a look step by step at what happens here:
It checks the last bit of G3 and jumps to 0x14000162f if it is zero, or to 0x140001a9a if it is not. The Unknown VM handler here is just after the JZ, as this instructions actually splits the workflow in two blocks, but it’s not logged here as it is already logged in the code segment before.
1
2
3
0x140001cbd: G16 = flag(G3 & 1) (G3 = 0x1)
0x140001a82: if JZ[flag(G16)]: goto 0x14000162f else goto 0x140001a9a
0x140001a90: Unknown VM handler.
It increments G1 and G2 according to some values stored in memory at places depending on G11 and G6.
1
2
0x140001a9a: G1 = G1 + [G11 + G6 + 0x3ac0] (0x0 + [0x0 + 0x140001D80 + 0x3ac0])
0x140001482: G2 = G2 + [G11 + G6 + 0x32c0] (0x0 + [0x0 + 0x140001D80 + 0x32c0])
It then checks if G1 is above 0x1770 and jumps accordingly. We also have the Unknown VM handler for the same reason as before.
1
2
3
0x140001884: G16 = flag(cmp G1 0x1770) (G1 = 0x2F0)
0x140001a18: if JA[flag(G16)]: goto 0x140001cdb else goto 0x14000162f
0x140001a26: Unknown VM handler.
It then shifts G3 (where our first input is stored) to the right by one bit, effectively removing the least significant bit we just used. It also adds 8 to G11, which is used as an offset to read memory in the previous steps.
1
2
0x14000162f: G3 = G3 >> 1 (G3 = 0x1 => 0x0)
0x14000167f: G11 = G11 + 0x8 (0x0 + 0x8 => 0x8)
It then compares G11 with 0x200, and if it is below, it loops back to the beginning of the process (checking the least significant bit of G3).
1
2
3
0x14000141c: G16 = flag(cmp G11 0x200) (G11 = 0x8)
0x140001668: if JC[flag(G16)]: goto 0x140001cbd else goto 0x14000143b
0x140001cbd: G16 = flag(G3 & 1) (G3 = 0x0)
We can see now that if G3 is zero, the program will directly jump to 0x14000162f, which is where it shifts G3 to the right and adds 8 to G11.
1
2
3
4
0x140001cbd: G16 = flag(G3 & 1) (G3 = 0x0)
0x140001a82: if JZ[flag(G16)]: goto 0x14000162f else goto 0x140001a9a
0x14000162f: G3 = G3 >> 1 (G3 = 0x0 => 0x0)
0x14000167f: G11 = G11 + 0x8 (0x8 + 0x8 => 0x10)
Let’s now go to the end of the execution:
1
2
3
4
5
0x14000141c: G16 = flag(cmp G11 0x200) (G11 = 0x200)
0x140001668: if JC[flag(G16)]: goto 0x140001cbd else goto 0x14000143b
0x140001676: Unknown VM handler.
0x14000143b: G3 = G10 (0x0)
0x140001d65: G16 = flag(G4 & 1) (G4 = RDX)
We can see that G11 is now 0x200, so we exit the loop and go to 0x14000143b. Here, G3 is set to G10, which is 0, and then the program checks the least significant bit of G4 (which is RDX, the second input register).
Let’s try to write a pseudocode that simulates the algorithm apply on the first input register:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
G3 = 1 #RCX
G4 = 1 #RDX
G10 = 0
G6 = 0x140001D80
G1 = 0
G2 = 0
G11 = 0
do {
if G3 & 1 == 1:
G1 = G1 + [G11 + G6 + 0x3ac0]
G2 = G2 + [G11 + G6 + 0x32c0]
if G1 > 0x1770:
# 0x140001cdb
G3 = G3 >> 1
G11 = G11 + 0x8
} while G11 < 0x200
# 0x14000143b
G3 = G10
G16 = G4 & 1
...
So G3 is our first input (RCX), it is shift by one bit at each iteration. G11 is also incremented by 8 at each iteration and we exit the loop when it reaches 0x200. Therefore, we will do 0x200 / 0x8 = 64 iterations. As RCX is 64 bits long, it means that for each bit of RCX, we will either do nothing if the bit is not set, or increment G1 and G2 by some values in memory if the bit is set. We also notice that G11 is also one of the register used to compute the memory address to read, so we will assume that this register is also used as an index to read different values in memory at each iteration (as 64 bits value are read and G11 is incremented by 0x8, it also makes sense).
Let’s have a look at what happens if G1 > 0x1770. In order to try so, I will put RCX = 2**64 - 1, which will set all bits of RCX to 1, therefore maximizing the value of G1 and G2.
1
2
3
4
5
6
7
8
9
0x140001884: G16 = flag(cmp G1 0x1770) (G1 = 0x1794)
0x140001a18: if JA[flag(G16)]: goto 0x140001cdb else goto 0x14000162f
0x140001cdb: G1 = 0
0x14000181b: G2 = [G0 + 0x8] (G0 = RSP)
0x140001c63: G6 = [G0 + 0x10] (G0 = RSP)
0x140001cb0: preparing end
0x1400015bf: RAX = G1 (0x0)
next block: @64[RSP]
RAX: 0x0
We can see that our program ends, as RIP goes to @64[RSP], so the return address. Therefore, we actually here go back to when the vm_start function was called, but RAX is set to 0, meaning that the input is wrong. We can complete our pseudocode with this part:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
G3 = 1 #RCX
G4 = 1 #RDX
G10 = 0
G6 = 0x140001D80
G1 = 0
G2 = 0
G11 = 0
do {
if G3 & 1 == 1:
G1 = G1 + [G11 + G6 + 0x3ac0]
G2 = G2 + [G11 + G6 + 0x32c0]
if G1 > 0x1770:
BAD
EXIT
G3 = G3 >> 1
G11 = G11 + 0x8
} while G11 < 0x200
# 0x14000143b
G3 = G10
G16 = G4 & 1
As we already took some time to deobfuscate and analyze the different segments for the first input register, we decided to just look at the code segments for the second input register to see if it was doing the same operations. We think it may be similar as the first segment checks the least significant bit of RDX and jumps accordingly.
We have the comparison with the least significant bit (JZ):
If zero, we shift G4 to the right:
And then add 0x8 to G3:
Compares G3 with 0x200 and loops back if below:
If the first bit is not zero, G1 += [G3 + G6 + 0x3cc0]:
And G2 += [G3 + G6 + 0x34c0].
And then we have the comparison between G1 and 0x1770 again:
We notice that the offset when getting the values from memory is different: 0x3cc0 and 0x34c0 instead of 0x3ac0 and 0x32c0. This is actually logical, as we already passed 64 * 8 = 0x200 bit for the first input, so the next values to read are 0x200 bytes after.
With this piece of information on the second input register, we tried to guess the whole algorithm:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
input = first_number | (second_number << 64) | (third_number << 128) | (fourth_number << 192)
do_not_pass_0x1770 = 0
to_determine = 0
list_do_not_pass = 0x140005840 # 64 bit list
list_to_determine = 0x140005040 # 64 bit list
index = 0
while index < 0x200:
if (input >> index) & 1 == 1:
do_not_pass_0x1770 += list_do_not_pass[index]
to_determine += list_to_determine[index]
if do_not_pass_0x1770 > 0x1770:
EXIT BAD
index += 1
This is an assumption but it seems to work for the two first input. Let’s try in Ghidra to go do the end of the program to see if there is a check on to_determine at the end.
We here have a comparaison between G2 and 0x7b82:
And then a JNC just after:
Therefore we can also assume that we want to_determine >= 0x7b82 at the end of the program. We can now complete our pseudocode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
input = first_number | (second_number << 64) | (third_number << 128) | (fourth_number << 192)
do_not_pass_0x1770 = 0
to_determine = 0
list_do_not_pass = 0x140005840 # 64 bit list
list_to_determine = 0x140005040 # 64 bit list
index = 0
while index < 0x200:
if (input >> index) & 1 == 1:
do_not_pass_0x1770 += list_do_not_pass[index]
to_determine += list_to_determine[index]
if do_not_pass_0x1770 > 0x1770:
EXIT BAD
index += 1
if to_determine >= 0x7b82:
EXIT GOOD
else:
EXIT BAD
Solving the algorithm
The problem is the following:
- We have two lists of 256 values (as we have 4 inputs of 64 bits each, so 256 bits in total)
- We need to find a list of indexes
- If we choose an index
i, we need to addlist_do_not_pass[i]to a counter that must not exceed0x1770and we need to addlist_to_determine[i]to another counter that must be at least0x7b82at the end.
I will be using here a naive approach, by using a ratio. If list_success[i] / list_do_not_pass[i] is higher than the ratio, we will take the index, otherwise we will not take it.
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
list_do_not_pass = [ 0xf0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa2, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
list_success = [ 0x5e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
from Crypto.Util.number import long_to_bytes, bytes_to_long
list_do_not_pass = [bytes_to_long(bytes((list_do_not_pass[i:i+8])[::-1])) for i in range(0, len(list_do_not_pass), 8)]
list_success = [bytes_to_long(bytes((list_success[i:i+8])[::-1])) for i in range(0, len(list_success), 8)]
print(f"list_do_not_pass: {list_do_not_pass}")
print(f"list_success: {list_success}")
ratio = 0x7b82 / 0x1770
total_do_not_pass = 0
total_success = 0
assert len(list_do_not_pass) == len(list_success)
assert len(list_do_not_pass) == 256
for i in range(256):
if list_success[i] / list_do_not_pass[i] > ratio:
total_success += list_success[i]
total_do_not_pass += list_do_not_pass[i]
print(f"should be less than 0x1770 : {hex(total_do_not_pass)}")
print(f"should be greater or equal than 0x7b82 : {hex(total_success)}")
By doing so we got:
1
2
3
4
list_do_not_pass: [752, 808, 539, 914, 186, 881, 78, 153, 97, 896, 233, 499, 828, 24, 526, 51, 40, 170, 344, 392, 897, 817, 46, 64, 484, 17, 493, 481, 335, 516, 588, 479, 811, 463, 625, 685, 607, 191, 254, 774, 282, 410, 432, 921, 831, 241, 699, 250, 932, 901, 107, 356, 758, 127, 81, 547, 371, 299, 941, 134, 262, 637, 912, 513, 427, 439, 969, 771, 602, 689, 672, 648, 322, 176, 501, 114, 992, 895, 964, 645, 863, 659, 724, 680, 21, 246, 950, 843, 369, 707, 635, 653, 908, 311, 944, 94, 809, 613, 284, 157, 734, 36, 243, 847, 582, 614, 307, 58, 142, 627, 633, 830, 156, 760, 263, 431, 546, 419, 803, 767, 564, 687, 15, 506, 983, 288, 836, 968, 329, 605, 877, 26, 352, 545, 91, 117, 407, 629, 441, 798, 700, 844, 323, 976, 770, 259, 783, 888, 814, 443, 750, 742, 454, 182, 640, 840, 765, 947, 929, 460, 850, 296, 907, 341, 852, 451, 488, 578, 580, 313, 780, 470, 957, 18, 178, 572, 440, 764, 641, 469, 878, 119, 95, 986, 382, 92, 952, 756, 192, 171, 183, 970, 821, 736, 159, 778, 424, 367, 923, 604, 27, 261, 251, 915, 599, 548, 265, 203, 954, 612, 163, 781, 276, 999, 235, 197, 154, 429, 705, 76, 148, 718, 528, 816, 974, 448, 8, 618, 108, 686, 1, 342, 674, 668, 449, 464, 904, 527, 287, 868, 905, 104, 88, 286, 355, 883, 306, 662, 872, 69, 273, 93, 561, 360, 492, 423]
list_success: [862, 96, 515, 115, 574, 415, 761, 121, 934, 618, 840, 950, 69, 646, 254, 689, 561, 416, 557, 503, 892, 366, 993, 683, 34, 411, 90, 6, 401, 82, 899, 152, 142, 497, 412, 61, 533, 17, 824, 97, 136, 554, 277, 546, 548, 449, 2, 764, 427, 965, 207, 957, 890, 495, 474, 744, 221, 408, 522, 517, 129, 691, 701, 563, 371, 707, 478, 320, 324, 396, 244, 815, 216, 485, 76, 833, 639, 51, 529, 399, 710, 898, 138, 751, 737, 171, 669, 222, 225, 794, 912, 990, 458, 872, 630, 564, 306, 694, 269, 128, 962, 164, 986, 944, 542, 889, 120, 538, 973, 843, 900, 834, 516, 240, 414, 284, 217, 686, 972, 487, 116, 705, 135, 955, 47, 873, 523, 7, 882, 276, 780, 393, 697, 395, 922, 571, 295, 36, 87, 609, 999, 601, 725, 926, 419, 963, 762, 317, 177, 997, 638, 33, 738, 945, 820, 773, 267, 932, 161, 380, 637, 593, 391, 247, 891, 838, 465, 417, 384, 726, 318, 816, 724, 9, 971, 368, 185, 664, 110, 167, 510, 734, 605, 842, 158, 373, 147, 974, 782, 450, 739, 298, 45, 754, 745, 424, 316, 969, 141, 878, 636, 622, 823, 915, 640, 623, 235, 903, 289, 619, 387, 367, 101, 362, 146, 106, 879, 334, 508, 174, 361, 799, 398, 212, 661, 153, 331, 265, 308, 160, 237, 490, 729, 273, 819, 611, 742, 392, 85, 760, 279, 475, 431, 231, 662, 679, 753, 24, 340, 93, 382, 218, 681, 252, 205, 649]
should be less than 0x1770 : 0x669
should be greater or equal than 0x7b82 : 0x3d18
We can try to adjust the ratio value. For example, with ratio = (0x7b82 / 0x1770) - 2.58, we get:
1
2
3
4
list_do_not_pass: [752, 808, 539, 914, 186, 881, 78, 153, 97, 896, 233, 499, 828, 24, 526, 51, 40, 170, 344, 392, 897, 817, 46, 64, 484, 17, 493, 481, 335, 516, 588, 479, 811, 463, 625, 685, 607, 191, 254, 774, 282, 410, 432, 921, 831, 241, 699, 250, 932, 901, 107, 356, 758, 127, 81, 547, 371, 299, 941, 134, 262, 637, 912, 513, 427, 439, 969, 771, 602, 689, 672, 648, 322, 176, 501, 114, 992, 895, 964, 645, 863, 659, 724, 680, 21, 246, 950, 843, 369, 707, 635, 653, 908, 311, 944, 94, 809, 613, 284, 157, 734, 36, 243, 847, 582, 614, 307, 58, 142, 627, 633, 830, 156, 760, 263, 431, 546, 419, 803, 767, 564, 687, 15, 506, 983, 288, 836, 968, 329, 605, 877, 26, 352, 545, 91, 117, 407, 629, 441, 798, 700, 844, 323, 976, 770, 259, 783, 888, 814, 443, 750, 742, 454, 182, 640, 840, 765, 947, 929, 460, 850, 296, 907, 341, 852, 451, 488, 578, 580, 313, 780, 470, 957, 18, 178, 572, 440, 764, 641, 469, 878, 119, 95, 986, 382, 92, 952, 756, 192, 171, 183, 970, 821, 736, 159, 778, 424, 367, 923, 604, 27, 261, 251, 915, 599, 548, 265, 203, 954, 612, 163, 781, 276, 999, 235, 197, 154, 429, 705, 76, 148, 718, 528, 816, 974, 448, 8, 618, 108, 686, 1, 342, 674, 668, 449, 464, 904, 527, 287, 868, 905, 104, 88, 286, 355, 883, 306, 662, 872, 69, 273, 93, 561, 360, 492, 423]
list_success: [862, 96, 515, 115, 574, 415, 761, 121, 934, 618, 840, 950, 69, 646, 254, 689, 561, 416, 557, 503, 892, 366, 993, 683, 34, 411, 90, 6, 401, 82, 899, 152, 142, 497, 412, 61, 533, 17, 824, 97, 136, 554, 277, 546, 548, 449, 2, 764, 427, 965, 207, 957, 890, 495, 474, 744, 221, 408, 522, 517, 129, 691, 701, 563, 371, 707, 478, 320, 324, 396, 244, 815, 216, 485, 76, 833, 639, 51, 529, 399, 710, 898, 138, 751, 737, 171, 669, 222, 225, 794, 912, 990, 458, 872, 630, 564, 306, 694, 269, 128, 962, 164, 986, 944, 542, 889, 120, 538, 973, 843, 900, 834, 516, 240, 414, 284, 217, 686, 972, 487, 116, 705, 135, 955, 47, 873, 523, 7, 882, 276, 780, 393, 697, 395, 922, 571, 295, 36, 87, 609, 999, 601, 725, 926, 419, 963, 762, 317, 177, 997, 638, 33, 738, 945, 820, 773, 267, 932, 161, 380, 637, 593, 391, 247, 891, 838, 465, 417, 384, 726, 318, 816, 724, 9, 971, 368, 185, 664, 110, 167, 510, 734, 605, 842, 158, 373, 147, 974, 782, 450, 739, 298, 45, 754, 745, 424, 316, 969, 141, 878, 636, 622, 823, 915, 640, 623, 235, 903, 289, 619, 387, 367, 101, 362, 146, 106, 879, 334, 508, 174, 361, 799, 398, 212, 661, 153, 331, 265, 308, 160, 237, 490, 729, 273, 819, 611, 742, 392, 85, 760, 279, 475, 431, 231, 662, 679, 753, 24, 340, 93, 382, 218, 681, 252, 205, 649]
should be less than 0x1770 : 0x1755
should be greater or equal than 0x7b82 : 0x7b78
But if we take more values by decreasing the ratio further, we have too much in the total_do_not_pass. Let’s try to print the index we are taking, and the index that will be taken if we decrease the ratio by a small amount:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
index_using = []
second_ratio = (0x7b82 / 0x1770) - 2.59
index_using_second = []
for i in range(256):
if list_success[i] / list_do_not_pass[i] > ratio:
total_success += list_success[i]
total_do_not_pass += list_do_not_pass[i]
index_using.append(i)
elif list_success[i] / list_do_not_pass[i] > second_ratio:
index_using_second.append(i)
print(f"should be less than 0x1770 : {hex(total_do_not_pass)}")
print(f"should be greater or equal than 0x7b82 : {hex(total_success)}")
print(f"index_using: {index_using}")
print(f"index_using_second: {index_using_second}")
Which gives us:
1
2
3
4
5
6
list_do_not_pass: [752, 808, 539, 914, 186, 881, 78, 153, 97, 896, 233, 499, 828, 24, 526, 51, 40, 170, 344, 392, 897, 817, 46, 64, 484, 17, 493, 481, 335, 516, 588, 479, 811, 463, 625, 685, 607, 191, 254, 774, 282, 410, 432, 921, 831, 241, 699, 250, 932, 901, 107, 356, 758, 127, 81, 547, 371, 299, 941, 134, 262, 637, 912, 513, 427, 439, 969, 771, 602, 689, 672, 648, 322, 176, 501, 114, 992, 895, 964, 645, 863, 659, 724, 680, 21, 246, 950, 843, 369, 707, 635, 653, 908, 311, 944, 94, 809, 613, 284, 157, 734, 36, 243, 847, 582, 614, 307, 58, 142, 627, 633, 830, 156, 760, 263, 431, 546, 419, 803, 767, 564, 687, 15, 506, 983, 288, 836, 968, 329, 605, 877, 26, 352, 545, 91, 117, 407, 629, 441, 798, 700, 844, 323, 976, 770, 259, 783, 888, 814, 443, 750, 742, 454, 182, 640, 840, 765, 947, 929, 460, 850, 296, 907, 341, 852, 451, 488, 578, 580, 313, 780, 470, 957, 18, 178, 572, 440, 764, 641, 469, 878, 119, 95, 986, 382, 92, 952, 756, 192, 171, 183, 970, 821, 736, 159, 778, 424, 367, 923, 604, 27, 261, 251, 915, 599, 548, 265, 203, 954, 612, 163, 781, 276, 999, 235, 197, 154, 429, 705, 76, 148, 718, 528, 816, 974, 448, 8, 618, 108, 686, 1, 342, 674, 668, 449, 464, 904, 527, 287, 868, 905, 104, 88, 286, 355, 883, 306, 662, 872, 69, 273, 93, 561, 360, 492, 423]
list_success: [862, 96, 515, 115, 574, 415, 761, 121, 934, 618, 840, 950, 69, 646, 254, 689, 561, 416, 557, 503, 892, 366, 993, 683, 34, 411, 90, 6, 401, 82, 899, 152, 142, 497, 412, 61, 533, 17, 824, 97, 136, 554, 277, 546, 548, 449, 2, 764, 427, 965, 207, 957, 890, 495, 474, 744, 221, 408, 522, 517, 129, 691, 701, 563, 371, 707, 478, 320, 324, 396, 244, 815, 216, 485, 76, 833, 639, 51, 529, 399, 710, 898, 138, 751, 737, 171, 669, 222, 225, 794, 912, 990, 458, 872, 630, 564, 306, 694, 269, 128, 962, 164, 986, 944, 542, 889, 120, 538, 973, 843, 900, 834, 516, 240, 414, 284, 217, 686, 972, 487, 116, 705, 135, 955, 47, 873, 523, 7, 882, 276, 780, 393, 697, 395, 922, 571, 295, 36, 87, 609, 999, 601, 725, 926, 419, 963, 762, 317, 177, 997, 638, 33, 738, 945, 820, 773, 267, 932, 161, 380, 637, 593, 391, 247, 891, 838, 465, 417, 384, 726, 318, 816, 724, 9, 971, 368, 185, 664, 110, 167, 510, 734, 605, 842, 158, 373, 147, 974, 782, 450, 739, 298, 45, 754, 745, 424, 316, 969, 141, 878, 636, 622, 823, 915, 640, 623, 235, 903, 289, 619, 387, 367, 101, 362, 146, 106, 879, 334, 508, 174, 361, 799, 398, 212, 661, 153, 331, 265, 308, 160, 237, 490, 729, 273, 819, 611, 742, 392, 85, 760, 279, 475, 431, 231, 662, 679, 753, 24, 340, 93, 382, 218, 681, 252, 205, 649]
should be less than 0x1770 : 0x1755
should be greater or equal than 0x7b82 : 0x7b78
index_using: [4, 6, 8, 10, 13, 15, 16, 22, 23, 25, 38, 47, 53, 54, 59, 73, 75, 84, 93, 95, 101, 102, 107, 108, 112, 122, 125, 131, 134, 135, 145, 153, 174, 181, 182, 185, 188, 190, 194, 200, 202, 207, 216, 226, 228, 230, 241, 242]
index_using_second: [51, 128]
Let’s now try to brute-force by replacing each time one value from index_using with one from index_using_second:
1
2
3
4
5
6
7
8
9
10
11
for i in index_using_second:
for j in index_using:
tmp_index_using = index_using.copy()
tmp_index_using.append(i)
del tmp_index_using[tmp_index_using.index(j)]
tmp_total_success = sum([list_success[k] for k in tmp_index_using])
tmp_total_do_not_pass = sum([list_do_not_pass[k] for k in tmp_index_using])
if tmp_total_success >= 0x7b82 and tmp_total_do_not_pass <= 0x1770:
print(f"total do_not_pass: {hex(tmp_total_do_not_pass)}")
print(f"total success: {hex(tmp_total_success)}")
print(f"final index: {tmp_index_using}")
Which gives us:
1
2
3
total do_not_pass: 0x1767
total success: 0x7b82
final index: [4, 6, 8, 10, 13, 15, 16, 22, 23, 25, 38, 47, 53, 54, 59, 73, 75, 84, 95, 101, 102, 107, 108, 112, 122, 125, 131, 134, 135, 145, 153, 174, 181, 182, 185, 188, 190, 194, 200, 202, 207, 216, 226, 228, 230, 241, 242, 128]
This seems to work! Let’s now build the numbers from this list.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
first_number = [i for i in tmp_index_using if i < 64]
second_number = [i-64 for i in tmp_index_using if 64 <= i < 128]
third_number = [i-128 for i in tmp_index_using if 128 <= i < 192]
fourth_number = [i-192 for i in tmp_index_using if 192 <= i < 256]
first_number = sum([1 << i for i in first_number])
second_number = sum([1 << i for i in second_number])
third_number = sum([1 << i for i in third_number])
fourth_number = sum([1 << i for i in fourth_number])
print(f"first_number: {first_number}")
print(f"second_number: {second_number}")
print(f"third_number: {third_number}")
print(f"fourth_number: {fourth_number}")
print(str(first_number)+" " + str(second_number)+ " " + str(third_number)+ " " + str(fourth_number))
By running this code, we obtain:
1
2
3
4
5
first_number: 603623362480153936
second_number: 2594381663086578176
third_number: 5935814677652177097
fourth_number: 1689210654328068
603623362480153936 2594381663086578176 5935814677652177097 1689210654328068
1
2
3
$ wine problem.exe
> 603623362480153936 2594381663086578176 5935814677652177097 1689210654328068
Congratulations, the flag is n1ctf{2c61982082d1af5052664054030285cd}
Conclusion
I think we had a pretty good approach using symbolic execution in order to understand the problem, but next time I think it should be usefull to automatize the deobfuscation process of the code segment for example by using the symbolic execution engine directly on the segment we want to understand. Our naive approach while trying to find the good input worked here but it might not work every time, so maybe we should have take the time to look on the internet to see what problems it represents and how to solve it (it was here the Knapsack problem).













