NPCCTF 2025 randomXor

简单伪随机

打开看了下main,看起来是很简单的伪随机,但是随机数算法是出题人自制的,而且是arm架构题目,不能用frida hook,所以考虑用模拟执行获取rand的结果



我们在调用srand的代码块进入,然后随便找一个加密完的位置作为结束的位置
因为bn有非常方便的读取段数据的api,所以直接把所有段都读进去

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
from unicorn import *
from unicorn.arm64_const import *
from binaryninja import *


def hook_code(uc, address, size, user_data):
bv = user_data["bv"]
assert isinstance(bv, BinaryView)
if address == 0xbc8:
print("w0 = {} w1 ={}".format(uc.reg_read(
UC_ARM64_REG_W0), uc.reg_read(UC_ARM64_REG_W1)))
global rd
rd.append(uc.reg_read(UC_ARM64_REG_W0))
if address == 0xbdc:
print("addr = {}".format(uc.reg_read(UC_ARM64_REG_X0) +
uc.reg_read(UC_ARM64_REG_X1)))


CODE_BASE = 0x0
CODE_SIZE = 0x20000
STACK_BASE = 0x10000000
STACK_SIZE = 0x10000
uc = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
uc.mem_map(CODE_BASE, CODE_SIZE, UC_PROT_ALL)
uc.mem_map(STACK_BASE, STACK_SIZE, UC_PROT_ALL)
uc.hook_add(UC_HOOK_CODE, hook_code, user_data={"bv": bv})
rd = []
for segment in bv.segments:
if segment.readable:
start = segment.start
end = segment.end
size = end-start
print("[+] Mapping segment: [{}]".format(hex(segment.start)))
content = bv.read(start, size)
uc.mem_write(start, content)

addr = 0xb98
addrEnd = 0xc18

stack_top = STACK_BASE + STACK_SIZE - 0x100
uc.reg_write(UC_ARM64_REG_SP, stack_top)
uc.mem_write(stack_top, b"\x00\x00\x00\x00\x00\x00\x00\x00")
uc.emu_start(addr, addrEnd)
print(rd)
uc.emu_stop()


0xbc8执行的了xor操作,我们在这个位置设置hook,读取w0就能直接拿到随机数

之后直接解密即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
rd = [171, 171, 131, 225, 65, 75, 141, 216, 149, 238, 40, 235, 196, 132, 99, 176, 132, 203, 140, 159, 82, 45, 47, 112, 202, 233, 239, 208, 231, 132, 45, 46, 58, 242, 229, 224, 106, 121, 228, 112, 174, 107, 227, 40, 64, 239, 178, 108, 13, 68, 255, 143, 243, 74, 108, 95, 141, 203, 193, 122, 195, 218,
187, 40, 108, 174, 244, 32, 167, 107, 104, 52, 90, 201, 121, 99, 142, 99, 227, 128, 118, 224, 188, 142, 131, 33, 128, 109, 35, 105, 191, 19, 47, 225, 46, 183, 46, 200, 18, 38, 243, 17, 216, 185, 181, 68, 240, 165, 25, 104, 56, 165, 154, 91, 88, 2, 209, 171, 137, 112, 59, 9, 149, 238, 1, 40, 165, 243]

cipher = [0xCD, 0xC7, 0xE2, 0x86, 0x3A, 0x19, 0xB9, 0xB6, 0xF1, 0x81,
0x45, 0xB4, 0xB6, 0xE5, 0x0D, 0xD4, 0xB4, 0xA6, 0xD3, 0xF7,
0x33, 0x5D, 0x5F, 0x09, 0x95, 0xAF, 0x9A, 0xBE, 0x89, 0xEA,
0x54, 0x71, 0x68, 0xC6, 0x8B, 0x84, 0x05, 0x14, 0xBB, 0x41,
0xDD, 0x34, 0x91, 0x1B, 0x21, 0x83, 0xDE, 0x15, 0x52, 0x22,
0x8A, 0xE1, 0xBD, 0x33, 0x4D, 0x7E, 0xD2, 0xA3, 0xA9, 0x12,
0xF1, 0xE9, 0x88, 0x60, 0x24, 0xE6, 0xAB, 0x54, 0xCF, 0x02,
0x1B, 0x6B, 0x6B, 0xBA, 0x26, 0x09, 0xFB, 0x10, 0x97, 0xDF,
0x17, 0xBF, 0xCC, 0xE7, 0xB0, 0x42, 0xE5, 0x32, 0x4C, 0x0F,
0xE0, 0x60, 0x47, 0xD0, 0x5A, 0xE8, 0x48, 0xAE, 0x74, 0x4D,
0x98, 0x7A, 0xB3, 0xD2, 0xDE, 0x1B, 0x96, 0x91, 0x7A, 0x03,
0x67, 0xCF, 0xF0, 0x31, 0x32, 0x49, 0x9A, 0xE0, 0xC2, 0x3B,
0x51, 0x63, 0xFF, 0x84, 0x60, 0x5B, 0xC1, 0x8E]
print(len(rd))

for i in range(0, 128):
print(chr(cipher[i] ^ rd[i]), end='')

flag{R4ndom_rand0m_happy_Funnny_R4ndom_1s_r3ally_funNy!!_hhh233HHH_this_1s_just_a_pi3ce_of_sh1t_fffkkkkkk_f4ck_jjjjKKKKKjjjjasd}

Author

SGSG

Posted on

2025-04-01

Updated on

2025-04-18

Licensed under