-
Notifications
You must be signed in to change notification settings - Fork 778
Raw binary blob support #1583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Raw binary blob support #1583
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
d3cc47d
adding support for raw binary blobs
technikelly 81c2a39
minimizing blob changes
technikelly 6d697b5
updating copyright statements with license info
technikelly a2223ab
update description
technikelly 5ec4a3b
addressing review comments, removing copyright notices
technikelly 04236d7
enabling test and updating rootfs submodule
technikelly File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| [CODE] | ||
| load_address = 0x10000000 | ||
| entry_point = 0x10000008 | ||
| ram_size = 0xa00000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| ############################################################################## | ||
| # This example is meant to demonstrate the modifications necessary | ||
| # to enable code coverage when emulating small code snippets or bare-metal | ||
| # code. | ||
| ############################################################################## | ||
| from qiling import Qiling | ||
| from qiling.const import QL_ARCH, QL_OS, QL_VERBOSE | ||
| from qiling.extensions.coverage import utils as cov_utils | ||
| from qiling.loader.loader import Image | ||
| import os | ||
|
|
||
| BASE_ADDRESS = 0x10000000 | ||
| CHECKSUM_FUNC_ADDR = BASE_ADDRESS + 0x8 | ||
| END_ADDRESS = 0x100000ba | ||
| DATA_ADDR = 0xa0000000 # Arbitrary address for data | ||
| STACK_ADDR = 0xb0000000 # Arbitrary address for stack | ||
|
|
||
| # Python implementation of the checksum function being emulated | ||
| # This checksum function is intended to have different code paths based on the input | ||
| # which is useful for observing code coverage | ||
| def checksum_function(input_data_buffer: bytes): | ||
| expected_checksum_python = 0 | ||
| input_data_len = len(input_data_buffer) | ||
| if input_data_len >= 1 and input_data_buffer[0] == 0xDE: # MAGIC_VALUE_1 | ||
| for i in range(min(input_data_len, 4)): | ||
| expected_checksum_python += input_data_buffer[i] | ||
| expected_checksum_python += 0x10 | ||
| elif input_data_len >= 2 and input_data_buffer[1] == 0xAD: # MAGIC_VALUE_2 | ||
| for i in range(input_data_len): | ||
| expected_checksum_python ^= input_data_buffer[i] | ||
| expected_checksum_python += 0x20 | ||
| else: | ||
| for i in range(input_data_len): | ||
| expected_checksum_python += input_data_buffer[i] | ||
| expected_checksum_python &= 0xFF # Ensure it's a single byte | ||
| return expected_checksum_python | ||
|
|
||
| def unmapped_handler(ql: Qiling, type: int, addr: int, size: int, value: int) -> None: | ||
| print(f"Unmapped Memory R/W, trying to access {size:d} bytes at {addr:#010x} from {ql.arch.regs.pc:#010x}") | ||
|
|
||
| def emulate_checksum_function(input_data_buffer: bytes) -> None: | ||
| print(f"\n--- Testing with input: {input_data_buffer.hex()} ---") | ||
|
|
||
| test_file = "rootfs/blob/example_raw.bin" | ||
|
|
||
| with open(test_file, "rb") as f: | ||
| raw_code: bytes = f.read() | ||
|
|
||
| ql: Qiling = Qiling( | ||
| code=raw_code, | ||
| archtype=QL_ARCH.ARM, | ||
| ostype=QL_OS.BLOB, | ||
| profile="blob_raw.ql", | ||
| verbose=QL_VERBOSE.DEBUG, | ||
| thumb=True | ||
| ) | ||
|
|
||
| ''' monkeypatch - Correcting the loader image name, used for coverage collection | ||
| removing all images with name 'blob_code' that were created by the blob loader. | ||
| This is necessary because some code coverage visualization tools require the | ||
| module name to match that of the input file ''' | ||
| ql.loader.images = [img for img in ql.loader.images if img.path != 'blob_code'] | ||
| ql.loader.images.append(Image(ql.loader.load_address, ql.loader.load_address + ql.os.code_ram_size, os.path.basename(test_file))) | ||
|
|
||
| input_data_len: int = len(input_data_buffer) | ||
|
|
||
| # Map memory for the data and stack | ||
| ql.mem.map(STACK_ADDR, 0x2000) | ||
| ql.mem.map(DATA_ADDR, ql.mem.align_up(input_data_len + 0x100)) # Map enough space for data | ||
|
|
||
| # Write input data | ||
| ql.mem.write(DATA_ADDR, input_data_buffer) | ||
|
|
||
| # Set up the stack pointer | ||
| ql.arch.regs.sp = STACK_ADDR + 0x2000 - 4 | ||
| # Set up argument registers | ||
| ql.arch.regs.r0 = DATA_ADDR | ||
| ql.arch.regs.r1 = input_data_len | ||
|
|
||
| # Set the program counter to the function's entry point | ||
| ql.arch.regs.pc = CHECKSUM_FUNC_ADDR | ||
|
|
||
| # Set the return address (LR) to a dummy address. | ||
| ql.arch.regs.lr = 0xbebebebe | ||
|
|
||
| ql.hook_mem_unmapped(unmapped_handler) | ||
| #ql.debugger="gdb:127.0.0.1:9999" | ||
|
|
||
| # Start emulation | ||
| print(f"Starting emulation at PC: {hex(ql.arch.regs.pc)}") | ||
| try: | ||
| with cov_utils.collect_coverage(ql, 'drcov', 'output.cov'): | ||
| ql.run(begin=CHECKSUM_FUNC_ADDR, end=END_ADDRESS) | ||
| except Exception as e: | ||
| print(f"Emulation error: {e}") | ||
|
|
||
| print(f"Emulated checksum: {hex(ql.arch.regs.r0)}") | ||
|
|
||
| if __name__ == "__main__": | ||
| data = b"\x01\x02\x03\x04\x05" # Example input data | ||
| emulate_checksum_function(data) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # Makefile for Bare-Metal ARM Checksum Calculator | ||
|
|
||
| # --- Toolchain Definitions --- | ||
| TOOLCHAIN_PREFIX = arm-none-eabi | ||
|
|
||
| # Compiler, Linker, and Objcopy executables | ||
| CC = $(TOOLCHAIN_PREFIX)-gcc | ||
| LD = $(TOOLCHAIN_PREFIX)-gcc | ||
| OBJCOPY = $(TOOLCHAIN_PREFIX)-objcopy | ||
|
|
||
| # --- Source and Output Files --- | ||
| SRCS = example_raw.c | ||
| OBJS = $(SRCS:.c=.o) # Convert .c to .o | ||
| ELF = example_raw.elf | ||
| BIN = example_raw.bin | ||
|
|
||
| # --- Linker Script --- | ||
| LDSCRIPT = linker.ld | ||
|
|
||
| # --- Compiler Flags --- | ||
| CFLAGS = -c -O0 -mcpu=cortex-a7 -mthumb -ffreestanding -nostdlib | ||
|
|
||
| # --- Linker Flags --- | ||
| LDFLAGS = -T $(LDSCRIPT) -nostdlib | ||
|
|
||
| # --- Objcopy Flags --- | ||
| OBJCOPYFLAGS = -O binary | ||
|
|
||
| # --- Default Target --- | ||
| .PHONY: all clean | ||
|
|
||
| all: $(BIN) | ||
|
|
||
| # Rule to build the raw binary (.bin) from the ELF file | ||
| $(BIN): $(ELF) | ||
| $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ | ||
| @echo "Successfully created $(BIN)" | ||
|
|
||
| # Rule to link the object file into an ELF executable | ||
| $(ELF): $(OBJS) $(LDSCRIPT) | ||
| $(LD) $(LDFLAGS) $(OBJS) -o $@ | ||
| @echo "Successfully linked $(ELF)" | ||
|
|
||
| # Rule to compile the C source file into an object file | ||
| %.o: %.c | ||
| $(CC) $(CFLAGS) $< -o $@ | ||
| @echo "Successfully compiled $<" | ||
|
|
||
| # --- Clean Rule --- | ||
| clean: | ||
| rm -f $(OBJS) $(ELF) $(BIN) | ||
| @echo "Cleaned build artifacts." |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| // example checksum algorithm to demonstrate raw binary code coverage in qiling | ||
| // example_raw.c | ||
|
|
||
| // Define some magic values | ||
| #define MAGIC_VALUE_1 0xDE | ||
| #define MAGIC_VALUE_2 0xAD | ||
|
|
||
| // This function calculates a checksum with branches based on input data | ||
| // It takes a pointer to data and its length | ||
| // Returns the checksum (unsigned char to fit in a byte) | ||
| unsigned char calculate_checksum(const unsigned char *data, unsigned int length) { | ||
| unsigned char checksum = 0; | ||
|
|
||
| // Branch 1: Check for MAGIC_VALUE_1 at the start | ||
| if (length >= 1 && data[0] == MAGIC_VALUE_1) { | ||
| // If first byte is MAGIC_VALUE_1, do a simple sum of first 4 bytes | ||
| // (or up to length if less than 4) | ||
| for (unsigned int i = 0; i < length && i < 4; i++) { | ||
| checksum += data[i]; | ||
| } | ||
| // Add a fixed offset to make this path distinct | ||
| checksum += 0x10; | ||
| } | ||
| // Branch 2: Check for MAGIC_VALUE_2 at the second byte | ||
| else if (length >= 2 && data[1] == MAGIC_VALUE_2) { | ||
| // If second byte is MAGIC_VALUE_2, do a XOR sum of all bytes | ||
| for (unsigned int i = 0; i < length; i++) { | ||
| checksum ^= data[i]; | ||
| } | ||
| // Add a fixed offset to make this path distinct | ||
| checksum += 0x20; | ||
| } | ||
| // Default Branch: Standard byte sum checksum | ||
| else { | ||
| for (unsigned int i = 0; i < length; i++) { | ||
| checksum += data[i]; | ||
| } | ||
| } | ||
|
|
||
| return checksum; | ||
| } | ||
|
|
||
| // Minimal entry point for bare-metal. | ||
| // This function will not be called directly during Qiling emulation, | ||
| // but it's needed for the linker to have an entry point. | ||
| __attribute__((section(".text.startup"))) | ||
| void _start() { | ||
| // In a real bare-metal application, this would initialize hardware, | ||
| // set up stacks, etc. For this example, it's just a placeholder. | ||
| // We'll call calculate_checksum directly from our Qiling script. | ||
|
|
||
| while (1) { | ||
| // Do nothing, or perhaps put the CPU to sleep | ||
| asm volatile ("wfi"); // Wait For Interrupt (ARM instruction) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| /* linker.ld */ | ||
|
|
||
| ENTRY(_start) /* Define the entry point of our program */ | ||
|
|
||
| /* Define memory regions - simple RAM region for this example */ | ||
| MEMORY | ||
| { | ||
| ram (rwx) : ORIGIN = 0x10000000, LENGTH = 64K /* 64KB of RAM for our program */ | ||
| } | ||
|
|
||
| SECTIONS | ||
| { | ||
| /* Define the start of our program in memory. | ||
| */ | ||
| . = 0x10000000; | ||
|
|
||
| .text : { | ||
| KEEP(*(.text.startup)) /* Keep the _start function */ | ||
| *(.text) /* All other code */ | ||
| *(.text.*) | ||
| *(.rodata) /* Read-only data */ | ||
| *(.rodata.*) | ||
| . = ALIGN(4); | ||
| } > ram /* Place .text section in the 'ram' region */ | ||
|
|
||
| .data : { | ||
| . = ALIGN(4); | ||
| *(.data) /* Initialized data */ | ||
| *(.data.*) | ||
| . = ALIGN(4); | ||
| } > ram | ||
|
|
||
| .bss : { | ||
| . = ALIGN(4); | ||
| *(.bss) | ||
| *(.bss.*) | ||
| . = ALIGN(4); | ||
| } > ram | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| [CODE] | ||
| load_address = 0x10000000 | ||
| entry_point = 0x10000008 | ||
| ram_size = 0xa00000 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.