Spoofing a Character Device
In this guide, we will virtually spoof a radar sensor for a drone application. The software expects a device at /dev/radar, but we will provide it entirely through software.
The Target Application
Our C application attempts to open the radar and read its configuration.
certo_symbol_import_demo.h
struct RadarConfig {
int range;
int sweep_speed;
char status[16];
};
main.c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include "certo_symbol_import_demo.h"
int main() {
// 1. Attempt to connect to the physical hardware
int fd = open("/dev/radar", O_RDONLY);
if (fd < 0) {
printf("CRITICAL ERROR: Radar hardware not found!\n");
return -1;
}
// 2. Read the hardware's internal configuration
struct RadarConfig my_radar;
read(fd, &my_radar, sizeof(my_radar));
printf("Radar Online! Range: %d, Status: %s\n", my_radar.range, my_radar.status);
// 3. Teardown
close(fd);
return 0;
}
Step 1: Target and Schema
- Create a new Hardware Spec in Certo.
- Set the intercept target path to
/dev/radar. - Import
certo_symbol_import_demo.hto map theRadarConfigstruct.
Step 2: The open Hook
Intercept the initialization to tell the app the hardware is connected.
certo::logger "Intercepted attempt to open /dev/radar!"
# Initialize our virtual hardware state
set ::radar_is_healthy 1
# Bypass real OS and return a fake File Descriptor (e.g., 99)
certo_set_return_value 99
Step 3: The read Hook
Generate the structured data and write it to the app's memory.
::certo::logger info "Application requested Radar data."
# 1. Create a zeroed-out dictionary based on our C-Schema
set my_radar [::certo::create_struct "RadarConfig"]
# 2. Populate the dict based on virtual state
if {$::radar_is_healthy == 1} {
dict set my_radar range 10000
dict set my_radar sweep_speed 5
dict set my_radar status "ACTIVE"
} else {
dict set my_radar status "OFFLINE"
}
# 3. Convert to raw bytes and write to the app's pointer
set raw_bytes [::certo::dict_to_bytes "RadarConfig" $my_radar]
set buf_addr [lindex $certo::arguments 1]
::certo::write_memory $buf_addr $raw_bytes
# 4. Return the requested size to indicate success
set requested_size [lindex $certo::arguments 2]
certo_set_return_value $requested_size