Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Durante l'incontro 0x0A DC7831 DEF CON Nizhny Novgorod Il 16 febbraio abbiamo presentato un discorso sui principi di base dell'emulazione di codice binario e sul nostro sviluppo - l'emulatore di piattaforme hardware Kopycat.

Nell'articolo forniremo una descrizione dell'avvio del firmware del dispositivo nell'emulatore, dimostreremo l'interazione con il debugger e eseguiremo una piccola analisi dinamica del firmware.

Antefatti

Un tempo in una galassia lontana lontana

Qualche anno fa, nel nostro laboratorio si è reso necessario studiare il firmware di un dispositivo. Il firmware era compresso, veniva estratto dal bootloader. Lo faceva in modo piuttosto complesso, riposizionando più volte i dati in memoria. Inoltre, il firmware interagiva attivamente con le periferiche. E tutto questo su un nucleo MIPS.

Gli emulatori esistenti non ci soddisfacevano per motivi oggettivi, ma volevamo comunque eseguire il codice. Così abbiamo deciso di realizzare il nostro emulatore, che facesse il minimo necessario per estrarre il firmware principale. Abbiamo provato - e ci siamo riusciti. Abbiamo pensato, e se aggiungessimo le periferiche, in modo da eseguire anche il firmware principale. Non è stato molto complicato - e anche questo è riuscito. Abbiamo pensato di nuovo e abbiamo deciso di realizzare un emulatore completo.

Alla fine abbiamo ottenuto un emulatore di sistemi di calcolo Kopycat.

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat
Perché Kopycat?

Si tratta di un gioco di parole.

  1. copycat (inglese, sost. [ˈkɒpɪkæt]) - imitatore, copiato
  2. cat (inglese, sost. [ˈkæt]) - gatto, il tuo animale domestico preferito di uno dei creatori del progetto
  3. La lettera «K» - dal linguaggio di programmazione Kotlin

Kopycat

Quando è stato creato l'emulatore, sono stati stabiliti obiettivi ben precisi:

  • la possibilità di creare rapidamente una nuova periferica, modulo, nucleo di processore;
  • la possibilità di assemblare un dispositivo virtuale da vari moduli;
  • la possibilità di caricare in memoria del dispositivo virtuale qualsiasi dato binario (firmware);
  • la possibilità di lavorare con gli snapshot (istantanee dello stato del sistema);
  • la possibilità di interagire con l'emulatore tramite il debugger integrato;
  • un linguaggio moderno e piacevole per lo sviluppo.

Alla fine, per l'implementazione è stato scelto Kotlin, un'architettura a bus (quando i moduli si collegano tra loro tramite bus virtuali dati), e JSON - come formato di descrizione del dispositivo, e GDB RSP - come protocollo di interazione con il debugger.

Lo sviluppo è in corso da poco più di due anni e continua attivamente. Durante questo periodo sono stati realizzati i core del processore MIPS, x86, V850ES, ARM, PowerPC.

Il progetto sta crescendo, ed è giunto il momento di presentarlo al grande pubblico. Una descrizione dettagliata del progetto sarà fornita in seguito, per ora concentriamoci sull'utilizzo di Kopycat.

Per i più impazienti — la versione promozionale dell'emulatore può essere scaricata da link.

Rinoceronte nell'emulatore

Ricordiamo che in precedenza per la conferenza SMARTRHINO-2018 è stato creato un dispositivo di test "Rinoceronte" per insegnare abilità di reverse engineering. Il processo di analisi statica del firmware è stato descritto in questo articolo.

Ora cerchiamo di aggiungere un po' di "dinamismo" e avviamo il firmware nell'emulatore.

Avremo bisogno di:
1) Java 1.8
2) Python e il modulo Jep per utilizzare Python all'interno dell'emulatore. Il pacchetto WHL del modulo Jep per Windows può essere scaricata qui.

Per Windows:
1) com0com
2) PuTTY

Per Linux:
1) socat

Come client GDB, puoi utilizzare Eclipse, IDA Pro o radare2.

Come funziona?

Per eseguire il firmware nell'emulatore, è necessario "assemblare" un dispositivo virtuale che rappresenta un'analogia di un dispositivo reale.

Il dispositivo reale ("rinoceronte") può essere mostrato nello schema strutturale:

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

L'emulatore ha una struttura modulare e il dispositivo virtuale finale può essere descritto in un file JSON.

JSON su 105 righe

{
  "top": true,

  // Il nome del plugin dovrebbe essere lo stesso del nome del file (o del percorso completo a partire dalla libreria)
  "plugin": "rhino",

  // Directory in cui il plugin posiziona
  "library": "user",

  // Parametri del plugin (parametri del costruttore se versione jar-plugin)
  "params": [
    { "name": "tty_dbg", "type": "String"},
    { "name": "tty_bt", "type": "String"},
    { "name": "firmware", "type": "String", "default": "NUL"}
  ],

  // Porte esterne del plugin
  "ports": [  ],

  // Bus interni del plugin
  "buses": [
    { "name": "mem", "size": "BUS30" },
    { "name": "nand", "size": "4" },
    { "name": "gpio", "size": "BUS32" }
  ],

  // Componenti interni del plugin
  "modules": [
    {
      "name": "u1_stm32",
      "plugin": "STM32F042",
      "library": "mcu",
      "params": {
        "firmware:String": "params.firmware"
      }
    },
    {
      "name": "usart_debug",
      "plugin": "UartSerialTerminal",
      "library": "terminals",
      "params": {
        "tty": "params.tty_dbg"
      }
    },
    {
      "name": "term_bt",
      "plugin": "UartSerialTerminal",
      "library": "terminals",
      "params": {
        "tty": "params.tty_bt"
      }
    },
    {
      "name": "bluetooth",
      "plugin": "BT",
      "library": "mcu"
    },

    { "name": "led_0",  "plugin": "LED", "library": "mcu" },
    { "name": "led_1",  "plugin": "LED", "library": "mcu" },
    { "name": "led_2",  "plugin": "LED", "library": "mcu" },
    { "name": "led_3",  "plugin": "LED", "library": "mcu" },
    { "name": "led_4",  "plugin": "LED", "library": "mcu" },
    { "name": "led_5",  "plugin": "LED", "library": "mcu" },
    { "name": "led_6",  "plugin": "LED", "library": "mcu" },
    { "name": "led_7",  "plugin": "LED", "library": "mcu" },
    { "name": "led_8",  "plugin": "LED", "library": "mcu" },
    { "name": "led_9",  "plugin": "LED", "library": "mcu" },
    { "name": "led_10", "plugin": "LED", "library": "mcu" },
    { "name": "led_11", "plugin": "LED", "library": "mcu" },
    { "name": "led_12", "plugin": "LED", "library": "mcu" },
    { "name": "led_13", "plugin": "LED", "library": "mcu" },
    { "name": "led_14", "plugin": "LED", "library": "mcu" },
    { "name": "led_15", "plugin": "LED", "library": "mcu" }
  ],

  // Connessione del plugin tra componenti
  "connections": [
    [ "u1_stm32.ports.usart1_m", "usart_debug.ports.term_s"],
    [ "u1_stm32.ports.usart1_s", "usart_debug.ports.term_m"],

    [ "u1_stm32.ports.usart2_m", "bluetooth.ports.usart_m"],
    [ "u1_stm32.ports.usart2_s", "bluetooth.ports.usart_s"],

    [ "bluetooth.ports.bt_s", "term_bt.ports.term_m"],
    [ "bluetooth.ports.bt_m", "term_bt.ports.term_s"],

    [ "led_0.ports.pin",  "u1_stm32.buses.pin_output_a", "0x00"],
    [ "led_1.ports.pin",  "u1_stm32.buses.pin_output_a", "0x01"],
    [ "led_2.ports.pin",  "u1_stm32.buses.pin_output_a", "0x02"],
    [ "led_3.ports.pin",  "u1_stm32.buses.pin_output_a", "0x03"],
    [ "led_4.ports.pin",  "u1_stm32.buses.pin_output_a", "0x04"],
    [ "led_5.ports.pin",  "u1_stm32.buses.pin_output_a", "0x05"],
    [ "led_6.ports.pin",  "u1_stm32.buses.pin_output_a", "0x06"],
    [ "led_7.ports.pin",  "u1_stm32.buses.pin_output_a", "0x07"],
    [ "led_8.ports.pin",  "u1_stm32.buses.pin_output_a", "0x08"],
    [ "led_9.ports.pin",  "u1_stm32.buses.pin_output_a", "0x09"],
    [ "led_10.ports.pin", "u1_stm32.buses.pin_output_a", "0x0A"],
    [ "led_11.ports.pin", "u1_stm32.buses.pin_output_a", "0x0B"],
    [ "led_12.ports.pin", "u1_stm32.buses.pin_output_a", "0x0C"],
    [ "led_13.ports.pin", "u1_stm32.buses.pin_output_a", "0x0D"],
    [ "led_14.ports.pin", "u1_stm32.buses.pin_output_a", "0x0E"],
    [ "led_15.ports.pin", "u1_stm32.buses.pin_output_a", "0x0F"]
  ]
}

Fai attenzione al parametro firmware nella sezione params — è il nome del file che può essere caricato nel dispositivo virtuale come firmware.

Un dispositivo virtuale e la sua interazione con il sistema operativo principale possono essere rappresentati in questo modo:

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

L'attuale istanza di test dell'emulatore implica l'interazione con le porte COM del sistema operativo principale (UART di debug e UART per il modulo Bluetooth). Queste possono essere porte reali, a cui sono connessi i dispositivi, oppure porte COM virtuali (per questo serve esattamente com0com / socat).

Per interagire con l'emulatore dall'esterno, attualmente esistono due principali modalità:

  • il protocollo GDB RSP (pertanto, gli strumenti che supportano questo protocollo — Eclipse / IDA / radare2);
  • la riga di comando interna dell'emulatore (Argparse o Python).

Porte COM virtuali

Per interagire con l'UART del dispositivo virtuale sulla macchina locale tramite terminale, è necessario creare una coppia di porte COM virtuali collegate. Nel nostro caso, una porta è utilizzata dall'emulatore, e l'altra dal programma terminale (PuTTY o screen):

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Utilizzo di com0com

Le porte COM virtuali vengono configurate utilizzando l'utilità di setup del pacchetto com0com (versione console — C:Program Files (x86)com0comsetupс.exe, oppure la versione GUI — C:Program Files (x86)com0comsetupg.exe):

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

È necessario spuntare enable buffer overrun per tutte le porte virtuali create, altrimenti l'emulatore attenderà una risposta dalla porta COM.

Utilizzo di socat

Su sistemi UNIX, le porte COM virtuali vengono create automaticamente dall'emulatore utilizzando l'utilità socat, è sufficiente specificare il prefisso socat:.

Interfaccia interna della riga di comando (Argparse o Python)

Poiché Kopycat è un'applicazione console, per interagire con i propri oggetti e variabili, l'emulatore offre due opzioni di interfaccia della riga di comando: Argparse e Python.

Argparse è il CLI integrato in Kopycat, ed è sempre disponibile per tutti.

Il CLI alternativo è l'interprete Python. Per utilizzarlo, è necessario installare il modulo Python Jep e configurare l'emulatore per lavorare con Python (verrà utilizzato l'interprete Python installato nel sistema principale dell'utente).

Installazione del modulo Python Jep

Su Linux, Jep può essere installato tramite pip:

pip install jep

Per installare Jep su Windows, è necessario prima installare Windows SDK e il corrispondente Microsoft Visual Studio. Abbiamo semplificato un po' il vostro compito e abbiamo fatto pacchetti WHL JEP per le versioni attuali di Python per Windows, quindi il modulo può essere installato da file:

pip install jep-3.8.2-cp27-cp27m-win_amd64.whl

Per verificare l'installazione di Jep, è necessario eseguire nel prompt dei comandi:

python -c "import jep"

La risposta dovrebbe fornire il messaggio:

ImportError: Jep non è supportato in Python standalone, deve essere incorporato in Java.

Nel file di comando dell'emulatore per il tuo sistema (kopycat.bat — per Windows, kopycat — per Linux) aggiungi al elenco dei parametri DEFAULT_JVM_OPTS un parametro aggiuntivo Djava.library.path — deve contenere il percorso fino al modulo Jep installato.

Di conseguenza, per Windows dovrebbe risultare una stringa del tipo:

set DEFAULT_JVM_OPTS="-XX:MaxMetaspaceSize=256m" "-XX:+UseParallelGC" "-XX:SurvivorRatio=6" "-XX:-UseGCOverheadLimit" "-Djava.library.path=C:/Python27/Lib/site-packages/jep"

Esecuzione di Kopycat

L'emulatore è un'applicazione console JVM. L'avvio avviene tramite uno script della riga di comando del sistema operativo (sh/cmd).

Il comando per l'avvio su Windows:

binkopycat -g 23946 -n rhino -l user -y library -p firmware=firmwarerhino_pass.bin,tty_dbg=COM26,tty_bt=COM28

Il comando per l'avvio su Linux utilizzando l'utilità socat:

./bin/kopycat -g 23946 -n rhino -l user -y library -p firmware=./firmware/rhino_pass.bin, tty_dbg=socat:./COM26,tty_bt=socat:./COM28

  • -g 23646 — porta TCP che sarà aperta per l'accesso al server GDB;
  • -n rhino — nome del modulo principale del sistema (dispositivo assemblato);
  • -l user — nome della libreria per cercare il modulo principale;
  • -y library — percorso per cercare i moduli inclusi nel dispositivo;
  • firmwarerhino_pass.bin — percorso del file di firmware;
  • COM26 e COM28 — porte COM virtuali.

Di conseguenza, verrà mostrato un prompt Python > (o Argparse >):

18:07:59 INFO [eFactoryBuilder.create ]: Modulo top creato con successo come top
18:07:59 INFO [ Module.initializeAndRes]: Impostazione core su top.u1_stm32.cortexm0.arm per top
18:07:59 INFO [ Module.initializeAndRes]: Impostazione debugger su top.u1_stm32.dbg per top
18:07:59 WARN [ Module.initializeAndRes]: Tracer non trovato in top...
18:07:59 INFO [ Module.initializeAndRes]: Inizializzazione porte e bus...
18:07:59 WARN [ Module.initializePortsA]: ATTENZIONE: Alcune porte hanno avvisi, usa printModulesPortsWarnings per vederlo...
18:07:59 FINE [ ARMv6CPU.reset ]: Imposta l'indirizzo del punto di ingresso a 08006A75
18:07:59 INFO [ Module.initializeAndRes]: Modulo top inizializzato e ripristinato con successo come cellula top!
18:07:59 INFO [ Kopycat.open ]: Avvio della virtualizzazione della scheda top[rhino] con arm[ARMv6Core]
18:07:59 INFO [ GDBServer.debuggerModule ]: Imposta il nuovo modulo debugger top.u1_stm32.dbg per GDB_SERVER(port=23946,alive=true)
Python >

Interazione con IDA Pro

Come file sorgente per l'analisi in IDA per semplificare il testing, utilizziamo il firmware "Rhinoceros" in formato ELF-file (qui è salvata la meta-informazione).

Puoi anche utilizzare il firmware principale senza meta-informazioni.

Dopo aver avviato Kopycat in IDA Pro, nel menu Debugger andiamo su "Switch debugger…» e scegliamo «Debugger GDB remoto«. Successivamente configuriamo la connessione: menu Debugger — Opzioni processo…

Impostiamo i valori:

  • Applicazione — qualsiasi valore
  • Hostname: 127.0.0.1 (o IP dell macchina remota dove è in esecuzione Kopycat)
  • Porta: 23946

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Ora è disponibile il pulsante di avvio del debug (tasto F9):

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Facciamo clic su di esso — avviene la connessione al modulo debugger nell'emulatore. IDA entra in modalità di debug, e si aprono finestre aggiuntive: informazioni sui registri, sullo stack.

Ora possiamo utilizzare tutte le funzionalità standard del debugger:

  • esecuzione passo dopo passo delle istruzioni (Entra nel passo e Salta il passo — tasti F7 e F8, rispettivamente);
  • avvio e sospensione dell'esecuzione;
  • creazione di punti di interruzione sia su codice che su dati (tasto F2).

La connessione al debugger non significa l'avvio del codice del firmware. La posizione attuale per l'esecuzione deve essere l'indirizzo 0x08006A74 — inizio della funzione Reset_Handler. Scorrendo il listato più in basso, possiamo vedere la chiamata della funzione main. Possiamo posizionare il cursore su questa riga (indirizzo 0x08006ABE) ed eseguire l'operazione Esegui fino al cursore (tasto F4).

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Poi possiamo premere F7 per entrare nella funzione main.

Se eseguiamo il comando Continua processo (tasto F9), comparirà la finestra "Attendere prego" con il solo pulsante Sospendi:

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Premendo Sospendi l'esecuzione del codice del firmware viene sospesa e può essere ripresa dallo stesso indirizzo del codice dove è stata interrotta.

Se si continua l'esecuzione del codice, nei terminali collegati alle porte COM virtuali si possono vedere le seguenti righe:

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

La presenza della riga "state bypass" indica che il modulo Bluetooth virtuale è passato alla modalità di ricezione dei dati dalla porta COM dell'utente.

Ora nel terminale Bluetooth (nell'immagine — COM29) è possibile inserire comandi secondo il protocollo "Rinoceronte". Ad esempio, per il comando "MEOW" il terminale Bluetooth restituirà la stringa "mur-mur":

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Non emulami completamente

Nella costruzione dell'emulatore è possibile scegliere il grado di dettaglio/emulazione di un certo dispositivo. Ad esempio, il modulo Bluetooth può essere emulato in vari modi:

  • si emula completamente il dispositivo con un set completo di comandi;
  • si emulano i comandi AT, e il flusso di dati viene ricevuto dalla porta COM del sistema principale;
  • il dispositivo virtuale garantisce un completo reindirizzamento dei dati al dispositivo reale;
  • come un semplice stub, che restituisce sempre "OK".

Nell'attuale versione dell'emulatore viene utilizzato il secondo approccio: un modulo Bluetooth virtuale esegue la configurazione e poi passa alla modalità di "proxy" dei dati dalla porta COM del sistema principale alla porta UART dell'emulatore.

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Consideriamo la possibilità di una semplice strumentazione del codice nel caso in cui non sia stata realizzata qualche parte della periferia. Ad esempio, se non è stato creato un timer per controllare il trasferimento dei dati nel DMA (il controllo viene effettuato nella funzione ws2812b_wait, situata all'indirizzo 0x08006840), il firmware attenderà sempre il reset del flag busy, situato all'indirizzo 0x200004C4, che indica l'occupazione della linea dati del DMA:

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Possiamo ovviare a tale situazione eseguendo un reset "manuale" del flag busy subito dopo la sua impostazione. In IDA Pro è possibile creare una funzione Python e chiamarla in un breakpoint, collocando il breakpoint stesso nel codice dopo la scrittura del valore 1 nel flag busy.

Gestore del breakpoint

Iniziamo creando una funzione Python in IDA. Menu File — Script command…

Aggiungiamo un nuovo snippet nell'elenco a sinistra, dandogli un nome (ad esempio, BPT),
nella casella di testo a destra immettiamo il codice della funzione:

def skip_dma():
    print "Saltando l'attesa ws2812..."
    value = Byte(0x200004C4)
    if value == 1:
        PatchDbgByte(0x200004C4, 0)
return False

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Dopo di che premiamo Esegui e chiudiamo la finestra degli script.

Ora passiamo al codice all'indirizzo 0x0800688A, impostiamo un breakpoint (tasto F2), modifichiamolo (menu contestuale Modifica breakpoint…), non dimentichiamo di impostare il tipo di script – Python:

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat
Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Se il valore attuale del flag busy è 1, allora dobbiamo eseguire la funzione skip_dma nella riga degli script:

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Se avviamo l'esecuzione del firmware, possiamo vedere l'attivazione del codice del gestore del breakpoint in IDA nella finestra Output alla riga Saltando l'attesa ws2812.... Ora il firmware non attenderà il reset del flag busy.

Interazione con l'emulatore

L'emulazione fine a se stessa probabilmente non susciterà entusiasmo e gioia. È molto più interessante se l'emulatore aiuti il ricercatore a vedere i dati in memoria o stabilire interazioni tra i flussi.

Mostriamo come stabilire un'interazione dei task RTOS in dinamica. Prima di tutto, è necessario fermare l'esecuzione del codice, se è in esecuzione. Se si accede alla funzione bluetooth_task_entry nella sezione di gestione del comando "LED" (indirizzo 0x080057B8), si può notare che prima viene creato e poi inviato nella coda di sistema ledControlQueueHandle , un certo messaggio.

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Bisogna impostare un breakpoint sull'accesso alla variabile ledControlQueueHandle, situata all'indirizzo 0x20000624 e continuare l'esecuzione del codice:

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Di conseguenza, inizialmente ci sarà un'interruzione all'indirizzo 0x080057CA prima della chiamata della funzione osMailAlloc, poi — all'indirizzo 0x08005806 prima della chiamata della funzione osMailPut, quindi, dopo un po' di tempo — all'indirizzo 0x08005BD4 (prima della chiamata della funzione osMailGet), che appartiene alla funzione leds_task_entry (compito LED), cioè si è verificato uno switch dei task, e ora il controllo è passato al task LED.

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

In questo modo semplice è possibile stabilire come i task RTOS interagiscono tra di loro.

Certo, nella realtà, l'interazione tra i task può essere organizzata in modo più complesso, ma utilizzare un emulatore rende più semplice monitorare questa interazione.

Qui puoi guardare un breve video sull'avvio dell'emulatore e l'interazione con IDA Pro.

Avvio con Radare2

Non si può ignorare uno strumento così versatile come Radare2.

Per connettersi all'emulatore utilizzando r2, il comando sarà:

radare2 -A -a arm -b 16 -d gdb://localhost:23946 rhino_fw42k6.elf

Ora sono disponibili l'avvio (dc) e la pausa dell'esecuzione (Ctrl+C).

Sfortunatamente, attualmente in r2 ci sono problemi quando si utilizza un server gdb hardware e la mappatura della memoria, per questo motivo i punti di interruzione e i passi (comando ds) non funzionano. Speriamo che questo venga risolto a breve.

Avvio con Eclipse

Una delle opzioni per utilizzare l'emulatore è il debug del firmware del dispositivo in fase di sviluppo. Per essere più chiari, utilizzeremo anche il firmware "Rhinoceros". Puoi scaricare i sorgenti del firmware da qui.

Come IDE useremo Eclipse dal pacchetto System Workbench for STM32.

Per fare in modo che l'emulatore carichi il firmware direttamente compilato in Eclipse, è necessario aggiungere il parametro firmware=null al comando di avvio dell'emulatore:

binkopycat -g 23946 -n rhino -l user -y modules -p firmware=null,tty_dbg=COM26,tty_bt=COM28

Configurazione del debug

In Eclipse, seleziona il menu Esegui — Configurazioni di debug… Nella finestra che si apre, nella sezione GDB Hardware Debugging devi aggiungere una nuova configurazione, quindi nella scheda "Main" specifica il progetto corrente e l'applicazione per il debug:

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Nella scheda "Debugger" devi specificare il comando GDB:
${openstm32_compiler_path}arm-none-eabi-gdb

E inserire i parametri per la connessione al server GDB (host e porta):

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Nella scheda "Startup" è necessario specificare i seguenti parametri:

  • spunta la casella Load image (affinché il caricamento dell'immagine del firmware compilato venga eseguito nell'emulatore);
  • spunta la casella Load symbols;
  • aggiungi il comando di avvio: set $pc = *0x08000004 (impostare nel registro PC il valore dalla memoria all'indirizzo 0x08000004 — lì è memorizzato l'indirizzo ResetHandler'a).

Si prega di notare, se non desideri caricare il file di firmware da Eclipse, non è necessario specificare i parametri Load image e Eseguire comandi non è necessario.

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Dopo aver premuto Debug, puoi lavorare in modalità di debug:

  • esecuzione passo passo del codice
    Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat
  • interazione con i punti di interruzione
    Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

Nota. In Eclipse ci sono, hm… alcune peculiarità… e bisogna convivere con esse. Ad esempio, se durante l'avvio del debugger appare il messaggio «No source available for «0x0»», esegui il comando Step (F5)

Il rinoceronte dentro al gatto — lanciamo il firmware nell'emulatore Kopycat

In conclusione

L'emulazione del codice nativo è un'azione piuttosto interessante. Per il progettista di dispositivi, si presenta l'opportunità di fare debug del firmware senza un dispositivo reale. Per il ricercatore, vi è la possibilità di condurre un'analisi dinamica del codice, cosa non sempre possibile anche in presenza di un dispositivo.

Vogliamo fornire ai professionisti uno strumento che sia comodo, relativamente semplice e che non richieda troppo impegno e tempo per la sua configurazione e avvio.

Scrivi nei commenti la tua esperienza con gli emulatori hardware. Ti invitiamo a partecipare alla discussione e saremo lieti di rispondere alle domande.

Solo gli utenti registrati possono partecipare al sondaggio. Accedi, per favore.

Per cosa utilizzi l'emulatore?

  • sviluppo (debug) di firmware

  • esplorazione di firmware

  • esecuzione di giochi (Dendi, Sega, PSP)

  • qualcos'altro (scrivi nei commenti)

Hanno votato 7 utenti. Si sono astenuti 2 utenti.

Quale software utilizzi per l'emulazione del codice nativo?

  • QEMU

  • Motore Unicorn

  • Proteus

  • qualcos'altro (scrivi nei commenti)

Hanno votato 6 utenti. Si sono astenuti 2 utenti.

Cosa ti piacerebbe migliorare nell'emulatore utilizzato?

  • vorrei più velocità

  • vorrei una configurazione/avvio più comodi

  • vorrei più possibilità di interazione con l'emulatore (API, hook)

  • sono soddisfatto di tutto

  • qualcos'altro (scrivi nei commenti)

Hanno votato 8 utenti. Si è astenuto 1 utente.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster