1+ ##############################################################################
2+ # Added example for raw binary blob
3+ # Kelly Patterson - Cisco Talos
4+ # Copyright (C) 2025 Cisco Systems Inc
5+ ##############################################################################
6+ from qiling import Qiling
7+ from qiling .const import QL_ARCH , QL_OS , QL_VERBOSE
8+ from qiling .extensions .coverage import utils as cov_utils
9+
10+ BASE_ADDRESS = 0x10000000
11+ CHECKSUM_FUNC_ADDR = BASE_ADDRESS + 0x8
12+ END_ADDRESS = 0x100000ba
13+ DATA_ADDR = 0xa0000000 # Arbitrary address for data
14+ STACK_ADDR = 0xb0000000 # Arbitrary address for stack
15+
16+ # Python implementation of the checksum function being emulated
17+ def checksum_function (input_data_buffer : bytes ):
18+ expected_checksum_python = 0
19+ input_data_len = len (input_data_buffer )
20+ if input_data_len >= 1 and input_data_buffer [0 ] == 0xDE : # MAGIC_VALUE_1
21+ for i in range (min (input_data_len , 4 )):
22+ expected_checksum_python += input_data_buffer [i ]
23+ expected_checksum_python += 0x10
24+ elif input_data_len >= 2 and input_data_buffer [1 ] == 0xAD : # MAGIC_VALUE_2
25+ for i in range (input_data_len ):
26+ expected_checksum_python ^= input_data_buffer [i ]
27+ expected_checksum_python += 0x20
28+ else :
29+ for i in range (input_data_len ):
30+ expected_checksum_python += input_data_buffer [i ]
31+ expected_checksum_python &= 0xFF # Ensure it's a single byte
32+
33+ def unmapped_handler (ql , type , addr , size , value ):
34+
35+ print (f"Unmapped Memory R/W, trying to access { hex (size )} bytes at { hex (addr )} from { hex (ql .arch .regs .pc )} " )
36+
37+ def emulate_checksum_function (input_data_buffer : bytes ):
38+ print (f"\n --- Testing with input: { input_data_buffer .hex ()} ---" )
39+
40+ ql = Qiling (archtype = QL_ARCH .ARM , ostype = QL_OS .BLOB , profile = "blob_raw.ql" , verbose = QL_VERBOSE .DEBUG , thumb = True )
41+
42+ input_data_len = len (input_data_buffer )
43+
44+ # Map memory for the binary, data and stack
45+ ql .mem .map (BASE_ADDRESS , 0x10000 )
46+ ql .mem .map (STACK_ADDR , 0x2000 )
47+ ql .mem .map (DATA_ADDR , ql .mem .align_up (input_data_len + 0x100 )) # Map enough space for data
48+
49+ # Write the binary into memory
50+ ql .mem .write (BASE_ADDRESS , open ("rootfs/blob/example_raw.bin" , "rb" ).read ())
51+
52+ # Write input data
53+ ql .mem .write (DATA_ADDR , input_data_buffer )
54+
55+ # Set up the stack pointer
56+ ql .arch .regs .sp = STACK_ADDR + 0x2000 - 4
57+ # Set up argument registers
58+ ql .arch .regs .r0 = DATA_ADDR
59+ ql .arch .regs .r1 = input_data_len
60+
61+ # Set the program counter to the function's entry point
62+ ql .arch .regs .pc = CHECKSUM_FUNC_ADDR
63+
64+ # Set the return address (LR) to a dummy address.
65+ ql .arch .regs .lr = 0xbebebebe
66+
67+ ql .hook_mem_unmapped (unmapped_handler )
68+ #ql.debugger="gdb:127.0.0.1:9999"
69+
70+ # Start emulation
71+ print (f"Starting emulation at PC: { hex (ql .arch .regs .pc )} " )
72+ try :
73+ ql .run (begin = CHECKSUM_FUNC_ADDR , end = END_ADDRESS )
74+ except Exception as e :
75+ print (f"Emulation error: { e } " )
76+
77+ print (f"Emulated checksum: { hex (ql .arch .regs .r0 )} " )
78+
79+ if __name__ == "__main__" :
80+ data = b"\x01 \x02 \x03 \x04 \x05 " # Example input data
81+ emulate_checksum_function (data )
0 commit comments