Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

În cadrul întâlnirii 0x0A DC7831 DEF CON Nizhniy Novgorod Pe 16 februarie, am prezentat o comunicare despre principiile de bază ale emulării codului binar și dezvoltarea noastră proprie — emulatorul platformelor hardware Kopycat.

În articol vom descrie cum să lansăm firmware-ul dispozitivului în emulator, vom demonstra interacțiunea cu debugger-ul și vom efectua o analiză dinamică a firmware-ului.

Povestea

A long time ago in a galaxy far far away

Acum câțiva ani, în laboratorul nostru a apărut necesitatea de a studia firmware-ul unui dispozitiv. Firmware-ul era comprimat, desfăcându-se cu bootloader-ul. Se ocupa de acest lucru într-un mod destul de complicat, mutând repetat datele în memorie. Iar firmware-ul interacționa activ cu perifericele. Și toate acestea pe un nucleu MIPS.

Emulatoarele existente, din motive obiective, nu ne-au satisfăcut, iar noi doream totuși să lansăm codul. Atunci am decis să creăm un emulator propriu, care să facă minimul necesar și să permită desfăcarea firmware-ului principal. Am încercat — a reușit. Ne-am gândit, dar ce ar fi dacă am adăuga periferia, astfel încât să putem rula și firmware-ul principal. Nu a fost prea dureros — și a funcționat și asta. Din nou ne-am gândit și am decis să facem un emulator complet.

În final, am obținut un emulator de sisteme computaționale Kopycat.

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat
De ce Kopycat?

Este vorba despre un joc de cuvinte.

  1. copycat (engleză, substantiv [ˈkɒpɪkæt]) — imitator, imitator
  2. cat (engleză, substantiv [ˈkæt]) — pisică, motan — animalul de companie preferat al unuia dintre creatorii proiectului
  3. Litera „K” — de la limbajul de programare Kotlin

Kopycat

Câteva obiective clare au fost stabilite la crearea emulatorului:

  • posibilitatea de a crea destul de rapid o nouă periferie, modul, nucleu de procesor;
  • posibilitatea de a asambla un dispozitiv virtual din module diverse;
  • posibilitatea de a încărca în memoria dispozitivului virtual orice date binare (firmware);
  • posibilitatea de a lucra cu snapshot-uri (fotografii ale stării sistemului);
  • posibilitatea de interacțiune cu emulatorul prin intermediul debugger-ului încorporat;
  • un limbaj plăcut și modern pentru dezvoltare.

În cele din urmă, pentru implementare s-a ales Kotlin, arhitectura de tip bus (când modulele se conectează între ele prin intermediul unor autobuze virtuale de date), JSON — ca format de descriere a dispozitivului, și GDB RSP — ca protocol de interacțiune cu debugger-ul.

Dezvoltarea a durat puțin peste doi ani și continuă activ. În acest timp, au fost realizate nucleele de procesor MIPS, x86, V850ES, ARM, PowerPC.

Proiectul crește și a venit vremea să-l prezentăm publicului larg. O descriere detaliată a proiectului va fi realizată mai târziu, iar acum să ne concentrăm pe utilizarea Kopycat.

Pentru cei mai nerăbdători - versiunea promoțională a emulatorului poate fi descărcată de la linkul.

Rinocer în emulator

Amintim că, anterior, pentru conferința SMARTRHINO-2018 a fost creat un dispozitiv de testare „Rinocer” pentru a învăța abilități de inginerie inversă. Procesul de analiză statică a firmware-ului a fost descris în această articole.

Acum să încercăm să adăugăm „dinamică” și să lansăm firmware-ul în emulator.

Ne vor trebui:
1) Java 1.8
2) Python și modulul Jep pentru utilizarea Python în emulator. Pachetul WHL al modulului Jep pentru Windows poate fi descărcat aici.

Pentru Windows:
1) com0com
2) PuTTY

Pentru Linux:
1) socat

Ca client GDB, se pot folosi Eclipse, IDA Pro sau radare2.

Cum funcționează?

Pentru a executa firmware-ul în emulator, este necesar să „construim” un dispozitiv virtual, care reprezintă un analog al dispozitivului real.

Dispozitivul real („rinocerul”) poate fi arătat pe schema structurală:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Emulatorul are o structură modulară, iar dispozitivul virtual final poate fi descris într-un fișier JSON.

JSON de 105 linii

{
  "top": true,

  // Numele pluginului ar trebui să fie același cu numele fișierului (sau calea completă de la începutul bibliotecii)
  "plugin": "rhino",

  // Directorul în care pluginul plasează
  "library": "user",

  // Parametrii pluginului (parametrii constructorului dacă este versiunea jar-plugin)
  "params": [
    { "name": "tty_dbg", "type": "String"},
    { "name": "tty_bt", "type": "String"},
    { "name": "firmware", "type": "String", "default": "NUL"}
  ],

  // Porturile externe ale pluginului
  "ports": [  ],

  // Busele interne ale pluginului
  "buses": [
    { "name": "mem", "size": "BUS30" },
    { "name": "nand", "size": "4" },
    { "name": "gpio", "size": "BUS32" }
  ],

  // Componentele interne ale pluginului
  "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" }
  ],

  // Conexiunea pluginului între componente
  "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"]
  ]
}

Atenție la parametrul firmware în secțiunea params — este numele fișierului care poate fi încărcat pe un dispozitiv virtual ca firmware.

Dispozitivul virtual și interacțiunea acestuia cu sistemul de operare principal pot fi reprezentate prin următorul schematic:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Exemplarul curent al emulatorului implică interacțiunea cu porturile COM ale sistemului de operare principal (UART-ul de depanare și UART-ul pentru modulul Bluetooth). Acestea pot fi porturi reale, la care sunt conectate dispozitive sau porturi COM virtuale (pentru care este nevoie de com0com / socat).

Pentru a interacționa cu emulatorul din exterior, în prezent există două modalități principale:

  • protocolul GDB RSP (respectiv, uneltele care suportă acest protocol — Eclipse / IDA / radare2);
  • linia de comandă internă a emulatorului (Argparse sau Python).

Porturi COM virtuale

Pentru a interacționa cu UART-ul dispozitivului virtual pe o mașină locală prin terminal, este necesară crearea unei perechi de porturi COM virtuale legate. În cazul nostru, un port este utilizat de emulator, iar celălalt — de programul-terminal (PuTTY sau screen):

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Utilizarea com0com

Porturile COM virtuale sunt configurate cu ajutorul utilitarului setup din pachetul com0com (versiunea de consolă — C:Program Files (x86)com0comsetupс.exe, sau versiunea GUI — C:Program Files (x86)com0comsetupg.exe):

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Trebuie să bifezi opțiunile enable buffer overrun pentru toate porturile virtuale create, altfel emulatorul va aștepta un răspuns de la portul COM.

Utilizarea socat

Pe sistemele UNIX, porturile COM virtuale sunt create automat de emulator cu ajutorul utilitarului socat; pentru aceasta, este suficient să specifici prefixul socat:.

Interfața internă a liniei de comandă (Argparse sau Python)

Dat fiind că Kopycat este o aplicație de consolă, pentru interacțiunea cu obiectele și variabilele sale, emulatorul oferă două opțiuni de interfață pentru linia de comandă: Argparse și Python.

Argparse — este CLI-ul integrat în Kopycat, disponibil întotdeauna și tuturor.

CLI-ul alternativ — interpretorul Python. Pentru utilizarea acestuia, este necesară instalarea modulului Python Jep și configurarea emulatorului pentru a lucra cu Python (va fi utilizat interpretorul Python instalat în sistemul principal al utilizatorului).

Instalarea modulului Python Jep

Pe Linux, Jep poate fi instalat prin pip:

pip install jep

Pentru instalarea Jep pe Windows este necesară instalarea prealabilă a Windows SDK și a Microsoft Visual Studio corespunzătoare. Am simplificat puțin sarcina și am realizat pachete WHL JEP pentru versiunile actuale de Python pe Windows, astfel că modulul poate fi instalat din fișier:

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

Pentru a verifica instalarea Jep, trebuie să executați în linia de comandă:

python -c "import jep"

Răspunsul ar trebui să fie mesajul:

ImportError: Jep nu este suportat în Python autonom, trebuie să fie încapsulat în Java.

În fișierul de comandă al emulatorului pentru sistemul dumneavoastră (kopycat.bat — pentru Windows, kopycat — pentru Linux) la lista de parametri DEFAULT_JVM_OPTS adăugați un parametru suplimentar Djava.library.path — acesta trebuie să conțină calea către modulul Jep instalat.

În rezultat, pentru Windows ar trebui să obțineți un format de linie similar cu următorul:

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

Pornirea Kopycat

Emulatorul este o aplicație JVM de tip consolă. Pornirea se realizează printr-un script de linie de comandă al sistemului de operare (sh/cmd).

Comanda pentru pornirea pe Windows:

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

Comanda pentru pornirea pe Linux utilizând utilitarul 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 — TCP-portul care va fi deschis pentru acces la serverul GDB;
  • -n rhino — numele modulului principal al sistemului (dispozitivul asamblat);
  • -l user — numele bibliotecii pentru căutarea modulului principal;
  • -y library — calea pentru a căuta modulele care fac parte din dispozitiv;
  • firmwarerhino_pass.bin — calea către fișierul de firmware;
  • COM26 și COM28 — porturi COM virtuale.

În rezultat, va fi afișat un prompt Python > (sau Argparse >):

18:07:59 INFO [eFactoryBuilder.create]: Modulul top a fost creat cu succes ca top
18:07:59 INFO [Module.initializeAndRes]: Configurarea nucleului pentru top.u1_stm32.cortexm0.arm pentru top
18:07:59 INFO [Module.initializeAndRes]: Configurarea debuggerului pentru top.u1_stm32.dbg pentru top
18:07:59 WARN [Module.initializeAndRes]: Tracer nu a fost găsit în top...
18:07:59 INFO [Module.initializeAndRes]: Inițializarea porturilor și busurilor...
18:07:59 WARN [Module.initializePortsA]: ATENȚIE: Unele porturi au avertizări, utilizați printModulesPortsWarnings pentru a le vedea...
18:07:59 FINE [ARMv6CPU.reset]: Setarea adresei punctului de intrare la 08006A75
18:07:59 INFO [Module.initializeAndRes]: Modulul top este inițializat și resetat cu succes ca celulă principală!
18:07:59 INFO [Kopycat.open]: Începerea virtualizării plăcii top[rhino] cu arm[ARMv6Core]
18:07:59 INFO [GDBServer.debuggerModule]: Setarea unui nou modul de debugger top.u1_stm32.dbg pentru GDB_SERVER(port=23946,alive=true)
Python >

Interacțiunea cu IDA Pro

Ca fișier sursă pentru analiză în IDA, pentru a facilita testarea, utilizăm firmware-ul „Rhinoceros” sub formă de fișier ELF (acolo este salvată meta-informația).

De asemenea, puteți utiliza firmware-ul principal fără meta-informație.

După pornirea Kopycat în IDA Pro, în meniul Debugger, mergem la opțiunea „Switch debugger…” și alegem „Depurator GDB la distanță«. Configurăm conexiunea: meniul Depurator — Opțiuni pentru proces…

Setăm valorile:

  • Aplicație — orice valoare
  • Hostname: 127.0.0.1 (sau adresa IP a mașinii de la distanță, unde este pornit Kopycat)
  • Port: 23946

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Acum devine disponibil butonul de pornire a depurării (tasta F9):

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Apăsăm acest buton — se realizează conexiunea cu modul depurator în emulator. IDA trece în modul de depurare, devin disponibile feronine suplimentare: informații despre registre, despre stivă.

Acum putem folosi toate funcționalitățile standard ale depuratorului:

  • execuția pas cu pas a instrucțiunilor (Intrați în și Săriți peste — tastele F7 și F8, respectiv);
  • pornirea și suspendarea execuției;
  • crearea punctelor de oprire atât pentru cod, cât și pentru date (tasta F2).

Conectarea la depurator nu înseamnă pornirea codului firmware-ului. Poziția curentă pentru execuție trebuie să fie adresa 0x08006A74 — începutul funcției Reset_Handler. Dacă derulăm lista mai jos, putem vedea apelul funcției main. Putem plasa cursorul pe această linie (adresa 0x08006ABE) și executa operația Executare până la cursor (tasta F4).

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Apoi putem apăsa F7 pentru a intra în funcție main.

Dacă executăm comanda Continuare proces (tasta F9), va apărea o fereastră «Vă rugăm să așteptați» cu un singur buton Suspendare:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

La apăsarea acesteia, Suspendare execuția codului firmware-ului este suspendată și poate fi reluată de la aceeași adresă în cod, unde a fost oprită.

Dacă continuăm execuția codului, atunci în terminalele conectate la porturi COM virtuale pot apărea următoarele linii:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Prezența liniei «state bypass» indică faptul că modulul Bluetooth virtual a trecut în modul de receptare a datelor de la portul COM al utilizatorului.

Acum în terminalul Bluetooth (în imagine — COM29) putem introduce comenzi conform protocolului «Rhinoceros». De exemplu, în urma comenzii «MEOW», terminalul Bluetooth va returna linia «mur-mur»:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Emulează-mă complet

Când construim emulatorul, putem alege gradul de detaliere/emulare al unui anumit dispozitiv. De exemplu, modulul Bluetooth poate fi emulat în diferite moduri:

  • se emulează complet dispozitivul cu un set complet de comenzi;
  • se emulează comenzi AT, iar fluxul de date este primit de la portul COM al sistemului principal;
  • dispozitivul virtual asigură redirecționarea completă a datelor către dispozitivul real;
  • sub formă de o simplă măsură care întotdeauna returnează „OK”.

În versiunea curentă a emulatorului, este folosită a doua abordare – un modul Bluetooth virtual configurează, după care trece în modul de „proxy” pentru datele din portul COM al sistemului principal în portul UART al emulatorului.

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Să examinăm posibilitatea unei instrumentări simple a codului în cazul în care nu este implementată vreo parte a periferiei. De exemplu, dacă nu este creat un timer care să se ocupe de controlul transmiterii datelor în DMA (verificarea se face în funcția ws2812b_wait, situată la adresa 0x08006840), firmware-ul va aștepta întotdeauna resetarea flagului busy, situat la adresa 0x200004C4, care arată ocuparea liniei de date DMA:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Putem evita această situație prin „resetarea manuală” a flagului busy imediat după ce a fost setat. În IDA Pro putem crea o funcție Python și o putem apela în breakpoint, punând break point-ul în cod după ce am scris valoarea 1 în flag. busy.

Breakpoint-Handler

Mai întâi, să creăm o funcție Python în IDA. Meniul File – Script command...

Adăugăm un nou snippet în lista din stânga, îi dăm un nume (de exemplu, BPT),
în câmpul de text din dreapta introducem codul funcției:

def skip_dma():
    print "Skipping wait ws2812..."
    value = Byte(0x200004C4)
    if value == 1:
        PatchDbgByte(0x200004C4, 0)
return False

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

După aceasta, facem click pe Run și închidem fereastra scripturilor.

Acum să ne îndreptăm către codul de la adresa 0x0800688A, setăm breakpoint (tasta F2), îi edităm (meniul contextual Edit breakpoint...), nu uitați să setați tipul scriptului – Python:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat
Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Dacă valoarea curentă a flagului busy este egală cu 1, atunci trebuie să executăm funcția skip_dma în linia scripturilor:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Dacă pornim firmware-ul pentru execuție, activarea codului breakpoint-handler-ului poate fi observată în IDA în fereastra Registrul direcției, registrul de ieșire. În acest proiect, nu ne vor fi necesare. la linia Skipping wait ws2812.... Acum firmware-ul nu va aștepta resetarea flagului. busy.

Interacțiunea cu emulatorul

Emularea doar de dragul emulării nu va provoca entuziasm sau bucurie. Mult mai interesant este dacă emulatorul ajută cercetătorul să vizualizeze datele din memorie sau să stabilească interacțiunea firelor.

Să arătăm cum se poate stabili interacțiunea RTOS-tasks în dinamică. Este necesar să suspendăm executarea codului, dacă este deja pornit. Dacă ne îndreptăm spre funcția bluetooth_task_entry în ramura de gestionare a comenzii „LED” (adresa 0x080057B8), putem observa că mai întâi se creează și apoi se trimite într-o coadă de sistem ledControlQueueHandle un anumit mesaj.

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Este necesar să stabilim un breakpoint la accesarea variabilei ledControlQueueHandle, situată la adresa 0x20000624 și să continuăm executarea codului:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Ca urmare, întâi va avea loc o oprire la adresa 0x080057CA înainte de apelarea funcției osMailAlloc, apoi — la adresa 0x08005806 înainte de apelarea funcției osMailPut, apoi, după un timp — la adresa 0x08005BD4 (înainte de apelarea funcției osMailGet), care aparține funcției leds_task_entry (task LED), adică a avut loc o schimbare a task-urilor, iar acum controlul a fost preluat de task-ul LED.

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

În acest mod simplu se poate stabili cum interacționează task-urile RTOS între ele.

Desigur, în realitate, interacțiunea task-urilor poate fi mai complexă, dar utilizând emulatorul, urmărirea acestei interacțiuni devine mai puțin laborios.

Aici se poate viziona un scurt videoclip despre lansarea emulatorului și interacțiunea cu IDA Pro.

Lansare cu Radare2

Nu se poate să nu menționăm un astfel de instrument versatil ca Radare2.

Pentru a te conecta la emulator folosind r2, comanda va arăta astfel:

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

Acum sunt disponibile lansarea (dc) și suspendarea execuției (Ctrl+C).

Din păcate, în prezent, în r2 există probleme la lucrul cu serverul gdb hardware și cu maparea memoriei, din această cauză nu funcționează punctele de oprire și pașii (comanda ds). Sperăm că, în curând, acest lucru va fi rezolvat.

Lansare cu Eclipse

Una dintre variantele de utilizare a emulatorului este depanarea firmware-ului dispozitivului în dezvoltare. Pentru a fi mai clar, vom folosi de asemenea firmware-ul „Rhinoceros”. Poți descărca sursele firmware-ului de aici.

Ca IDE, vom folosi Eclipse din pachetul System Workbench for STM32.

Pentru ca firmware-ul să fie încărcat în emulator direct din Eclipse, trebuie adăugat parametrul firmware=null în comanda de lansare a emulatorului:

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

Configurarea configurației debug

În Eclipse, alegem meniul Run — Debug Configurations… În fereastra deschisă, în secțiunea GDB Hardware Debugging trebuie să adăugăm o nouă configurație, după care, pe tab-ul „Main”, să indicăm proiectul curent și aplicația pentru depanare:

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Pe tab-ul „Debugger” trebuie să indicăm comanda GDB:
${openstm32_compiler_path}arm-none-eabi-gdb

De asemenea, trebuie introduse parametrii pentru conectarea la serverul GDB (host și port):

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Pe tab-ul „Startup” trebuie să indicăm următorii parametrii:

  • să bifezi căsuța Load image (pentru a permite încărcarea în emulator a imaginii firmware-ului compilate);
  • să bifezi căsuța Load symbols;
  • să adaugăm comanda de lansare: set $pc = *0x08000004 (afisează în registrul PC valoarea din memorie la adresa 0x08000004 — acolo este stocat adresa ResetHandler-ului).

Vă rugăm să observați, dacă nu doriți să încărcați fișierul de firmware din Eclipse, atunci parametrii Load image și Comenzi de rulare nu trebuie specificate.

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

După apăsarea pe Debug, puteți lucra în modul de depanare:

  • execuția pas cu pas a codului
    Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat
  • interacțiunea cu punctele de oprire
    Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

Notă. În Eclipse există, hmmm... unele particularități... și trebuie să trăim cu ele. De exemplu, dacă la pornirea debugger-ului apare mesajul „No source available for «0x0»”, atunci executați comanda Step (F5)

Rinocerul din interiorul pisicii — lansăm firmware-ul în emulatorul Kopycat

În concluzie

Emularea codului nativ este o activitate destul de interesantă. Pentru dezvoltatorul de dispozitive, oferă posibilitatea de a debuga firmware-ul fără dispozitivul real. Pentru cercetător — oportunitatea de a efectua analiza dinamică a codului, ceea ce nu este întotdeauna posibil chiar și în prezența unui dispozitiv.

Dorim să oferim specialiștilor un instrument care să fie convenabil, în mod rezonabil simplu și să nu consume mult timp și efort pentru configurare și pornire.

Scrieți în comentarii despre experiența dumneavoastră cu emulatorii hardware. Vă invităm la discuții și vom fi bucuroși să răspundem la întrebări.

Numai utilizatorii înregistrați pot participa la sondaj. Conectați-vă, vă rugăm.

Pentru ce folosiți emulatorul?

  • dezvolt firmware (depanare)

  • cercetez firmware

  • lansez jocuri (Dendi, Sega, PSP)

  • altceva (scrieți în comentarii)

7 utilizatori au votat. 2 utilizatori s-au abținut.

Ce software folosiți pentru emularea codului nativ?

  • QEMU

  • Unicorn engine

  • Proteus

  • altceva (scrieți în comentarii)

6 utilizatori au votat. 2 utilizatori s-au abținut.

Ce ați dori să îmbunătățiți în emulatorul pe care îl folosiți?

  • aș dori viteză

  • aș dori să fie mai ușor de configurat/înlansat

  • aș dori mai multe funcționalități de interacțiune cu emulatorul (API, hook-uri)

  • sunt mulțumit de tot

  • altceva (scrieți în comentarii)

8 utilizatori au votat. 1 utilizator s-a abținut.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster