Skip to content

Commit 5ec4a3b

Browse files
committed
addressing review comments, removing copyright notices
1 parent a2223ab commit 5ec4a3b

File tree

9 files changed

+43
-97
lines changed

9 files changed

+43
-97
lines changed

examples/hello_arm_blob_raw.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
##############################################################################
2-
# Added example for raw binary blob
3-
# Kelly Patterson - Cisco Talos
4-
# Copyright (C) 2025 Cisco Systems Inc
5-
# Licensed under the GNU General Public License v2.0 or later
2+
# This example is meant to demonstrate the modifications necessary
3+
# to enable code coverage when emulating small code snippets or bare-metal
4+
# code.
65
##############################################################################
76
from qiling import Qiling
87
from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE
98
from qiling.extensions.coverage import utils as cov_utils
109
from qiling.loader.loader import Image
10+
import os
1111

1212
BASE_ADDRESS = 0x10000000
1313
CHECKSUM_FUNC_ADDR = BASE_ADDRESS + 0x8
@@ -16,6 +16,8 @@
1616
STACK_ADDR = 0xb0000000 # Arbitrary address for stack
1717

1818
# Python implementation of the checksum function being emulated
19+
# This checksum function is intended to have different code paths based on the input
20+
# which is useful for observing code coverage
1921
def checksum_function(input_data_buffer: bytes):
2022
expected_checksum_python = 0
2123
input_data_len = len(input_data_buffer)
@@ -33,26 +35,34 @@ def checksum_function(input_data_buffer: bytes):
3335
expected_checksum_python &= 0xFF # Ensure it's a single byte
3436
return expected_checksum_python
3537

36-
def unmapped_handler(ql, type, addr, size, value):
38+
def unmapped_handler(ql: Qiling, type: int, addr: int, size: int, value: int) -> None:
39+
print(f"Unmapped Memory R/W, trying to access {size:d} bytes at {addr:#010x} from {ql.arch.regs.pc:#010x}")
3740

38-
print(f"Unmapped Memory R/W, trying to access {hex(size)} bytes at {hex(addr)} from {hex(ql.arch.regs.pc)}")
39-
40-
def emulate_checksum_function(input_data_buffer: bytes):
41+
def emulate_checksum_function(input_data_buffer: bytes) -> None:
4142
print(f"\n--- Testing with input: {input_data_buffer.hex()} ---")
4243

43-
with open("rootfs/blob/example_raw.bin", "rb") as f:
44-
raw_code = f.read()
44+
test_file = "rootfs/blob/example_raw.bin"
4545

46-
ql = Qiling(code=raw_code, archtype=QL_ARCH.ARM, ostype=QL_OS.BLOB, profile="blob_raw.ql", verbose=QL_VERBOSE.DEBUG, thumb=True)
46+
with open(test_file, "rb") as f:
47+
raw_code: bytes = f.read()
4748

48-
# monkeypatch - Correcting the loader image name, used for coverage collection
49-
# Remove all images with name 'blob_code' that were created by the blob loader
50-
ql.loader.images = [img for img in ql.loader.images if img.path != 'blob_code']
51-
# Add image back with correct info
52-
ql.loader.images.append(Image(ql.loader.load_address, ql.loader.load_address + ql.os.code_ram_size, 'example_raw.bin'))
49+
ql: Qiling = Qiling(
50+
code=raw_code,
51+
archtype=QL_ARCH.ARM,
52+
ostype=QL_OS.BLOB,
53+
profile="blob_raw.ql",
54+
verbose=QL_VERBOSE.DEBUG,
55+
thumb=True
56+
)
5357

58+
''' monkeypatch - Correcting the loader image name, used for coverage collection
59+
removing all images with name 'blob_code' that were created by the blob loader.
60+
This is necessary because some code coverage visualization tools require the
61+
module name to match that of the input file '''
62+
ql.loader.images = [img for img in ql.loader.images if img.path != 'blob_code']
63+
ql.loader.images.append(Image(ql.loader.load_address, ql.loader.load_address + ql.os.code_ram_size, os.path.basename(test_file)))
5464

55-
input_data_len = len(input_data_buffer)
65+
input_data_len: int = len(input_data_buffer)
5666

5767
# Map memory for the data and stack
5868
ql.mem.map(STACK_ADDR, 0x2000)
@@ -88,5 +98,4 @@ def emulate_checksum_function(input_data_buffer: bytes):
8898

8999
if __name__ == "__main__":
90100
data = b"\x01\x02\x03\x04\x05" # Example input data
91-
emulate_checksum_function(data)
92-
print(hex(checksum_function(data)))
101+
emulate_checksum_function(data)

examples/src/blob/Makefile

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
##############################################################################
2-
# Added example for raw binary blob
3-
# Kelly Patterson - Cisco Talos
4-
# Copyright (C) 2025 Cisco Systems Inc
5-
# Licensed under the GNU General Public License v2.0 or later
6-
##############################################################################
7-
# Makefile for Bare-Metal ARM Hash Calculator
1+
# Makefile for Bare-Metal ARM Checksum Calculator
82

93
# --- Toolchain Definitions ---
104
TOOLCHAIN_PREFIX = arm-none-eabi

examples/src/blob/example_raw.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
/*
2-
* Added example for raw binary blob
3-
* Kelly Patterson - Cisco Talos
4-
* Copyright (C) 2025 Cisco Systems Inc
5-
* Licensed under the GNU General Public License v2.0 or later
6-
*
7-
*/
1+
// example checksum algorithm to demonstrate raw binary code coverage in qiling
82
// example_raw.c
93

104
// Define some magic values

examples/src/blob/linker.ld

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
11
/* linker.ld */
2-
/*
3-
* Added example for raw binary blob
4-
* Kelly Patterson - Cisco Talos
5-
* Copyright (C) 2025 Cisco Systems Inc
6-
* Licensed under the GNU General Public License v2.0 or later
7-
*
8-
*/
92

103
ENTRY(_start) /* Define the entry point of our program */
114

examples/uboot_bin.ql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
ram_size = 0xa00000
33
load_address = 0x80800000
44
entry_point = 0x80800000
5+
heap_address = 0xa0000000
56
heap_size = 0x300000
67

78

qiling/loader/blob.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,9 @@
22
#
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
5-
# Heaps are optional for blobs
6-
# Kelly Patterson - Cisco Talos
7-
# Copyright (C) 2025 Cisco Systems Inc
8-
# Licensed under the GNU General Public License v2.0 or later
95

106
from qiling import Qiling
117
from qiling.loader.loader import QlLoader, Image
12-
from qiling.os.memory import QlMemoryHeap
13-
import configparser
148

159

1610
class QlLoaderBLOB(QlLoader):
@@ -33,15 +27,5 @@ def run(self):
3327
# allow image-related functionalities
3428
self.images.append(Image(code_begins, code_ends, 'blob_code'))
3529

36-
# FIXME: heap starts above end of ram??
37-
# FIXME: heap should be allocated by OS, not loader
38-
heap_base = code_ends
39-
# if heap_size is defined, create the heap
40-
try:
41-
heap_size = int(self.ql.os.profile.get("CODE", "heap_size"), 16)
42-
self.ql.os.heap = QlMemoryHeap(self.ql, heap_base, heap_base + heap_size)
43-
except (configparser.NoSectionError, configparser.NoOptionError):
44-
pass # heap_size is not required
45-
4630
# FIXME: stack pointer should be a configurable profile setting
4731
self.ql.arch.regs.arch_sp = code_ends - 0x1000

qiling/os/blob/blob.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from qiling.const import QL_ARCH, QL_OS
99
from qiling.os.fcall import QlFunctionCall
1010
from qiling.os.os import QlOs
11+
from qiling.os.memory import QlMemoryHeap
1112

1213

1314
class QlOsBlob(QlOs):
@@ -49,5 +50,11 @@ def run(self):
4950
# if exit point was set explicitly, override the default one
5051
if self.ql.exit_point is not None:
5152
self.exit_point = self.ql.exit_point
52-
53+
54+
# if heap info is provided in profile, create heap
55+
heap_base = self.profile.getint('CODE', 'heap_address', fallback=None)
56+
heap_size = self.profile.getint('CODE', 'heap_size', fallback=None)
57+
if heap_base is not None and heap_size is not None:
58+
self.heap = QlMemoryHeap(self.ql, heap_base, heap_base + heap_size)
59+
5360
self.ql.emu_start(self.entry_point, self.exit_point, self.ql.timeout, self.ql.count)

tests/profiles/uboot_bin.ql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
ram_size = 0xa00000
33
load_address = 0x80800000
44
entry_point = 0x80800000
5+
heap_address = 0xa0000000
56
heap_size = 0x300000
67

78

tests/test_blob.py

Lines changed: 3 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22
#
33
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
44
#
5-
# Added test for raw binary blob emulation
6-
# Kelly Patterson - Cisco Talos
7-
# Copyright (C) 2025 Cisco Systems Inc
8-
# Licensed under the GNU General Public License v2.0 or later
95

106
import unittest
117

@@ -87,7 +83,7 @@ def partial_run_init(ql: Qiling):
8783
del ql
8884

8985
@unittest.skip("Temporarily disabled")
90-
def test_blob_checksum_calculations(self):
86+
def test_blob_raw(self):
9187
def run_checksum_emu(input_data_buffer: bytes) -> int:
9288
"""
9389
Callable function that takes input data buffer and returns the checksum.
@@ -145,41 +141,8 @@ def calculate_expected_checksum(input_data_buffer: bytes) -> int:
145141

146142
return expected_checksum & 0xFF
147143

148-
# Test cases with descriptions
149-
test_cases = {
150-
"default_path": {
151-
"data": b"\x01\x02\x03\x04\x05",
152-
"description": "Default path - simple sum of all bytes"
153-
},
154-
"magic_value_1": {
155-
"data": b"\xDE\x01\x02\x03\x04\x05",
156-
"description": "Magic Value 1 path (0xDE at data[0]) - sum first 4 bytes + 0x10"
157-
},
158-
"magic_value_2": {
159-
"data": b"\x01\xAD\x02\x03\x04\x05",
160-
"description": "Magic Value 2 path (0xAD at data[1]) - XOR all bytes + 0x20"
161-
},
162-
"edge_magic1_short": {
163-
"data": b"\xDE\x01",
164-
"description": "Edge case: Magic Value 1, but short data (only 2 bytes)"
165-
},
166-
"edge_magic2_too_short": {
167-
"data": b"\xAD",
168-
"description": "Edge case: Magic Value 2, but too short (fallback to default)"
169-
},
170-
"both_magic_values": {
171-
"data": b"\xDE\xAD\x01\x02",
172-
"description": "Both magic values present, DE at [0] takes precedence"
173-
}
174-
}
175-
176-
# Assertions with descriptions - directly call functions with test data
177-
self.assertEqual(run_checksum_emu(test_cases["default_path"]["data"]), calculate_expected_checksum(test_cases["default_path"]["data"])) # Default path
178-
self.assertEqual(run_checksum_emu(test_cases["magic_value_1"]["data"]), calculate_expected_checksum(test_cases["magic_value_1"]["data"])) # Magic Value 1 path
179-
self.assertEqual(run_checksum_emu(test_cases["magic_value_2"]["data"]), calculate_expected_checksum(test_cases["magic_value_2"]["data"])) # Magic Value 2 path
180-
self.assertEqual(run_checksum_emu(test_cases["edge_magic1_short"]["data"]), calculate_expected_checksum(test_cases["edge_magic1_short"]["data"])) # Edge case: Magic Value 1, short data
181-
self.assertEqual(run_checksum_emu(test_cases["edge_magic2_too_short"]["data"]), calculate_expected_checksum(test_cases["edge_magic2_too_short"]["data"])) # Edge case: Magic Value 2, too short
182-
self.assertEqual(run_checksum_emu(test_cases["both_magic_values"]["data"]), calculate_expected_checksum(test_cases["both_magic_values"]["data"])) # Both magic values, DE takes precedence
144+
test_input = b"\x01\x02\x03\x04\x05"
145+
self.assertEqual(run_checksum_emu(test_input), calculate_expected_checksum(test_input))
183146

184147

185148
if __name__ == "__main__":

0 commit comments

Comments
 (0)