RISC 8bit CPU
Writing an emulator / disassembler

Description

The SFT0 CPU is a secure processor designed to store encryption key. Find out how the processor works and get the key.
manual.pdf
109KB
PDF
manual.pdf
rom.bin
5KB
Binary
rom.bin

Solution

We're given the specifications for this custom processor. This one is pretty simple - there are 3 registers (A, B and C), a program counter (PC) and a 1-bit flag register.
We're told that the address space is from 0x0000 to 0xFFFF. Furthermore, the PC starts from 0x1000:
We're given the ROM to be loaded at 0x0000, and we need to write an emulator that parses and executes the following instructions.
We can simply represent the memory space as an array, access 4 bytes at a time, and parse the instructions based on the specification above. Initially, I ran into some errors because I forgot to always take the lower 8 bits after an arithmetic operation. The rest is just a bunch of if-else statements!
1
ROM = "40 18 2C ... 09 09 09"
2
​
3
registers = [0 for _ in range(3)]
4
​
5
pc = 0x1000 # Program Counter
6
fr = 0 # Flag Register
7
​
8
rom = [int(x, 16) for x in ROM.split()]
9
memory = rom + [0 for _ in range(0xffff + 1 - len(rom))]
10
​
11
done = False
12
while not done:
13
​
14
curr_instruction = memory[pc:pc+4]
15
pc += 4
16
​
17
if curr_instruction[0] == 0:
18
# print(f"ADD R{curr_instruction[1]}, {curr_instruction[3]}")
19
​
20
registers[curr_instruction[1]] += curr_instruction[3]
21
​
22
elif curr_instruction[0] == 1:
23
# print(f"XOR R{curr_instruction[1]}, {curr_instruction[3]}")
24
​
25
registers[curr_instruction[1]] ^= curr_instruction[3]
26
27
elif curr_instruction[0] == 2:
28
# print(f"AND R{curr_instruction[1]}, {curr_instruction[3]}")
29
​
30
registers[curr_instruction[1]] &= curr_instruction[3]
31
32
elif curr_instruction[0] == 3:
33
# print(f"OR R{curr_instruction[1]}, {curr_instruction[3]}")
34
​
35
registers[curr_instruction[1]] |= curr_instruction[3]
36
​
37
elif curr_instruction[0] == 4:
38
# print(f"LD R{curr_instruction[1]}, {curr_instruction[3]}")
39
​
40
registers[curr_instruction[1]] = curr_instruction[3]
41
42
elif curr_instruction[0] == 5:
43
# print(f"MOV R{curr_instruction[1]}, R{curr_instruction[3]}")
44
​
45
registers[curr_instruction[1]] = registers[curr_instruction[3]]
46
​
47
elif curr_instruction[0] == 6:
48
​
49
addr = 256 * curr_instruction[2] + curr_instruction[3]
50
​
51
# print(f"LDR R{curr_instruction[1]}, {addr}")
52
​
53
registers[curr_instruction[1]] = memory[addr]
54
​
55
elif curr_instruction[0] == 7:
56
# print(f"LDR R{curr_instruction[1]}")
57
​
58
addr = 256 * registers[1] + registers[2]
59
registers[curr_instruction[1]] = memory[addr]
60
61
elif curr_instruction[0] == 8:
62
63
addr = 256 * curr_instruction[2] + curr_instruction[3]
64
​
65
# print(f"STR R{curr_instruction[1]}, {addr}")
66
​
67
memory[addr] = registers[curr_instruction[1]]
68
​
69
elif curr_instruction[0] == 9:
70
# print(f"STR R{curr_instruction[1]}")
71
​
72
addr = 256 * registers[1] + registers[2]
73
memory[addr] = registers[curr_instruction[1]]
74
​
75
elif curr_instruction[0] == 0x0A:
76
# print(f"PUT R{curr_instruction[1]}")
77
​
78
print(chr(registers[curr_instruction[1]]), end='')
79
80
elif curr_instruction[0] == 0x0B:
81
82
addr = 256 * curr_instruction[2] + curr_instruction[3]
83
​
84
# print(f"JMP {addr}")
85
​
86
pc = addr
87
​
88
elif curr_instruction[0] == 0x0C:
89
​
90
addr = 256 * curr_instruction[2] + curr_instruction[3]
91
​
92
# print(f"JNZ {addr}")
93
​
94
if fr == 0:
95
pc = addr + 4
96
97
elif curr_instruction[0] == 0x0D:
98
99
addr = 256 * curr_instruction[2] + curr_instruction[3]
100
​
101
# print(f"JZ {addr}")
102
​
103
if fr == 1:
104
pc = addr + 4
105
​
106
elif curr_instruction[0] == 0x0E:
107
# print(f"CMPEQ R{curr_instruction[1]}, {curr_instruction[3]}")
108
​
109
if registers[curr_instruction[1]] == curr_instruction[3]:
110
fr = 1
111
112
else:
113
fr = 0
114
115
elif curr_instruction[1] == 0x44:
116
# print("HLT")
117
​
118
done = True
119
120
elif curr_instruction[1] == 0x33:
121
# print("NOP")
122
pass
123
​
124
else:
125
raise ValueError(f"Unrecognized instruction {curr_instruction}")
126
127
# 8-bit
128
for i in range(len(registers)):
129
if registers[i] >= 256:
130
registers[i] -= 256
131
132
# 16-bit
133
if pc >= 65536:
134
pc -= 65536
Copied!
The flag is YauzaCTF{s0_s3cr3t_y3t_s0_fr33}.
Last modified 3mo ago
Copy link