Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

W ramach spotkania 0x0A DC7831 DEF CON Niżny Nowogród 16 lutego przedstawiliśmy referat na temat podstawowych zasad emulacji kodu binarnego oraz naszej własnej produkcji — emulatora platform sprzętowych Kopycat.

W artykule przedstawimy opis uruchamiania oprogramowania urządzenia w emulatorze, zademonstrujemy interakcję z debugerem i przeprowadzimy niewielką analizę dynamiczną oprogramowania.

Tło

Dawno temu w odległej galaktyce

Kilka lat temu w naszej laboratorium pojawiła się potrzeba zbadania oprogramowania urządzenia. Oprogramowanie było skompresowane, rozpakowywane przez bootloadera. Robił to w dość skomplikowany sposób, kilkakrotnie przestawiając dane w pamięci. A samo oprogramowanie aktywnie współdziałało z peryferiami. A wszystko to na jądrze MIPS.

Istniejące emulatory z obiektywnych powodów nam nie odpowiadały, ale chcieliśmy uruchomić kod. Wtedy postanowiliśmy stworzyć własny emulator, który zrobi minimum i pozwoli rozpakować główne oprogramowanie. Spróbowaliśmy — udało się. Pomyśleliśmy, a co jeśli dodać peryferie, aby także wykonywać główne oprogramowanie. Nie było to zbyt bolesne — i też się udało. Znowu pomyśleliśmy i postanowiliśmy zbudować pełnoprawny emulator.

Ostatecznie powstał emulator systemów obliczeniowych Kopycat.

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat
Dlaczego Kopycat?

Mamy do czynienia z grą słów.

  1. copycat (ang., rzecz. [ˈkɒpɪkæt]) — naśladowca, imitator
  2. cat (ang., rzecz. [ˈkæt]) — kot, kotka — ulubione zwierzę jednego z twórców projektu
  3. Litera „K” — od języka programowania Kotlin

Kopycat

Podczas tworzenia emulatora postawiono całkowicie określone cele:

  • możliwość dość szybkiego stworzenia nowej peryferii, modułu, rdzenia procesora;
  • możliwość zbudowania wirtualnego urządzenia z różnych modułów;
  • możliwość załadowania do pamięci wirtualnego urządzenia dowolnych danych binarnych (oprogramowania);
  • możliwość pracy ze snapshotami (zdjęcia stanu systemu);
  • możliwość interakcji z emulatorem przez wbudowany debuger;
  • przyjemny nowoczesny język do programowania.

Ostatecznie do realizacji wybrano Kotlin, architekturę szynową (to wtedy moduły łączą się między sobą przez wirtualne szyny danych), JSON jako format opisu urządzenia oraz GDB RSP jako protokół interakcji z debugerem.

Prace trwają już od ponad dwóch lat i ciągle się rozwijają. W tym czasie zrealizowano rdzenie procesorów MIPS, x86, V850ES, ARM, PowerPC.

Projekt rośnie, a nadszedł czas, aby zaprezentować go szerszej publiczności. Szczegółowy opis projektu przygotujemy później, a teraz skupmy się na wykorzystaniu Kopycat.

Dla najbardziej niecierpliwych - wersję promocyjną emulatora można pobrać pod linkiem.

Nosorożec w emulatorze

Przypominamy, że wcześniej na konferencję SMARTRHINO-2018 stworzono urządzenie testowe „Nosorożec” do nauki umiejętności reverse engineering. Proces analizy statycznej oprogramowania był opisany w w tym artykule.

Teraz spróbujemy dodać „dynamikę” i uruchomimy oprogramowanie w emulatorze.

Będziemy potrzebować:
1) Java 1.8
2) Python oraz moduł Jep do użycia Pythona wewnątrz emulatora. Kompilację WHL modułu Jep na Windows można pobrać tutaj.

Dla Windows:
1) com0com
2) PuTTY

Dla Linux:
1) socat

Jako klienta GDB można użyć Eclipse, IDA Pro lub radare2.

Jak to działa?

Aby przeprowadzić oprogramowanie w emulatorze, należy „zbudować” wirtualne urządzenie, które jest analogiem rzeczywistego urządzenia.

Rzeczywiste urządzenie („nosorożec”) można przedstawić na schemacie strukturalnym:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Emulator ma modułową strukturę, a końcowe wirtualne urządzenie można opisać w pliku JSON.

JSON w 105 linijkach

{
  "top": true,

  // Nazwa wtyczki powinna być taka sama jak nazwa pliku (lub pełna ścieżka od początku biblioteki)
  "plugin": "rhino",

  // Katalog, w którym umieszczana jest wtyczka
  "library": "user",

  // Parametry wtyczki (parametry konstruktora, jeśli wersja jest jar-plugin)
  "params": [
    { "name": "tty_dbg", "type": "String"},
    { "name": "tty_bt", "type": "String"},
    { "name": "firmware", "type": "String", "default": "NUL"}
  ],

  // Zewnętrzne porty wtyczki
  "ports": [  ],

  // Wewnętrzne szyny wtyczki
  "buses": [
    { "name": "mem", "size": "BUS30" },
    { "name": "nand", "size": "4" },
    { "name": "gpio", "size": "BUS32" }
  ],

  // Wewnętrzne komponenty wtyczki
  "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" }
  ],

  // Połączenia wtyczki między komponentami
  "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"]
  ]
}

Zwróć uwagę na parametr firmware w sekcji parametry — to nazwa pliku, który można wczytać do wirtualnego urządzenia jako firmware.

Wirtualne urządzenie i jego interakcje z głównym systemem operacyjnym można przedstawić w takiej schemacie:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Bieżący testowy egzemplarz emulatory zakłada interakcję z portami COM głównego systemu operacyjnego (port UART do debugowania oraz UART dla modułu Bluetooth). Mogą to być rzeczywiste porty, do których podłączone są urządzenia lub wirtualne porty COM (do tego właśnie potrzebny jest com0com / socat).

Obecnie istnieją dwa główne sposoby interakcji z emulatorem z zewnątrz:

  • protokół GDB RSP (odpowiednio, narzędzia wspierające ten protokół to — Eclipse / IDA / radare2);
  • wewnętrzna linia poleceń emulatora (Argparse lub Python).

Wirtualne porty COM

Aby w interactować z UART-em wirtualnego urządzenia na lokalnej maszynie za pomocą terminala, należy stworzyć parę powiązanych wirtualnych portów COM. W naszym przypadku jeden port wykorzystuje emulator, a drugi — program terminalowy (PuTTY lub screen):

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Wykorzystanie com0com

Wirtualne porty COM są konfigurowane za pomocą narzędzia setup z zestawu com0com (wersja konsolowa — C:Program Files (x86)com0comsetupс.exe, lub wersja GUI — C:Program Files (x86)com0comsetupg.exe):

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Należy zaznaczyć opcje enable buffer overrun dla wszystkich utworzonych wirtualnych portów, inaczej emulator będzie oczekiwał odpowiedzi z portu COM.

Wykorzystanie socat

Na systemach UNIX wirtualne porty COM są automatycznie tworzone przez emulator za pomocą narzędzia socat, wystarczy przy uruchamianiu emulatora użyć prefiksu w nazwie portu socat:.

Wewnętrzny interfejs linii poleceń (Argparse lub Python)

Ponieważ Kopycat jest aplikacją konsolową, aby interagować z jego obiektami i zmiennymi, emulator udostępnia dwa warianty interfejsu linii poleceń: Argparse i Python.

Argparse — to CLI wbudowane w Kopycat, dostępne zawsze i dla wszystkich.

Alternatywne CLI — interpreter Python. Aby go używać, należy zainstalować moduł Python Jep i skonfigurować emulator do pracy z Pythonem (będzie używany interpreter Python zainstalowany w głównym systemie użytkownika).

Instalacja modułu Python Jep

Pod Linux Jep można zainstalować przez pip:

pip install jep

Aby zainstalować Jep na Windowsie, należy najpierw zainstalować Windows SDK oraz odpowiednią wersję Microsoft Visual Studio. Nieco uprościliśmy Wam zadanie i zrobiliśmy WHL-paczki JEP dla aktualnych wersji Pythona na Windows, dlatego moduł można zainstalować z pliku:

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

Aby sprawdzić instalację Jep, należy wykonać w wierszu poleceń:

python -c "import jep"

W odpowiedzi powinno pojawić się wiadomość:

ImportError: Jep nie jest obsługiwany w samodzielnym Pythonie, musi być osadzony w Javie.

W pliku skryptu emulatora dla Twojego systemu (kopycat.bat — dla Windows, kopycat — dla Linux) do listy parametrów DEFAULT_JVM_OPTS dodaj dodatkowy parametr Djava.library.path — powinien zawierać ścieżkę do zainstalowanego modułu Jep.

W rezultacie dla Windows powinna to być następująca linia:

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

Uruchamianie Kopycat

Emulator to konsolowa aplikacja JVM. Uruchamianie odbywa się poprzez skrypt wiersza poleceń systemu operacyjnego (sh/cmd).

Polecenie uruchomienia w Windows:

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

Polecenie uruchomienia w Linux z wykorzystaniem narzędzia 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 — port TCP, który będzie otwarty dla dostępu do serwera GDB;
  • -n rhino — nazwa głównego modułu systemu (urządzenie w zestawie);
  • -l user — nazwa biblioteki dla wyszukiwania głównego modułu;
  • -y library — ścieżka do wyszukiwania modułów wchodzących w skład urządzenia;
  • firmwarerhino_pass.bin — ścieżka do pliku oprogramowania układowego;
  • COM26 i COM28 — wirtualne porty COM.

W rezultacie pojawi się komunikat Python > (lub Argparse >):

18:07:59 INFO [eFactoryBuilder.create]: Moduł top został pomyślnie utworzony jako top
18:07:59 INFO [Module.initializeAndRes]: Ustawiono rdzeń na top.u1_stm32.cortexm0.arm dla top
18:07:59 INFO [Module.initializeAndRes]: Ustawiono debugger na top.u1_stm32.dbg dla top
18:07:59 WARN [Module.initializeAndRes]: Tracer nie został znaleziony w top...
18:07:59 INFO [Module.initializeAndRes]: Inicjalizacja portów i szyn...
18:07:59 WARN [Module.initializePortsA]: UWAGA: Niektóre porty mają ostrzeżenie, użyj printModulesPortsWarnings, aby je zobaczyć...
18:07:59 FINE [ARMv6CPU.reset]: Ustawiam adres punktu wejścia na 08006A75
18:07:59 INFO [Module.initializeAndRes]: Moduł top został pomyślnie zainicjowany i zresetowany jako komórka główna!
18:07:59 INFO [Kopycat.open]: Rozpoczęcie wirtualizacji płyty top[rhino] z arm[ARMv6Core]
18:07:59 INFO [GDBServer.debuggerModule]: Ustawiono nowy moduł debuggera top.u1_stm32.dbg dla GDB_SERVER(port=23946,alive=true)
Python >

Interakcja z IDA Pro

Jako plik źródłowy do analizy w IDA do uproszczenia testowania używamy oprogramowania układowego "Nosorożec" w postaci pliku ELF (zawiera zachowaną metainformację).

Możesz również użyć głównego oprogramowania układowego bez metainformacji.

Po uruchomieniu Kopycat w IDA Pro w menu Debugger przechodzimy do opcji „Switch debugger…” i wybieramy „Zdalny debugger GDB«. Następnie konfigurujemy połączenie: menu Debugger — Opcje procesu…

Ustawiamy wartości:

  • Aplikacja — dowolna wartość
  • Nazwa hosta: 127.0.0.1 (lub adres IP zdalnej maszyny, na której działa Kopycat)
  • Port: 23946

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Teraz dostępny jest przycisk uruchamiania debuggera (klawisz F9):

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Naciskamy go — następuje połączenie z modułem debuggera w emulatorze. IDA przechodzi w tryb debugowania, odblokowują się dodatkowe okna: informacje o rejestrach, o stosie.

Teraz możemy korzystać ze wszystkich standardowych funkcji pracy z debuggerem:

  • krokowe wykonywanie instrukcji (Przejdź do i Pomiń — klawisze F7 i F8, odpowiednio);
  • uruchamianie i wstrzymywanie wykonania;
  • tworzenie punktów przerwania zarówno dla kodu, jak i danych (klawisz F2).

Połączenie z debuggerem nie oznacza uruchomienia kodu oprogramowania. Bieżąca pozycja do wykonania powinna być adresem 0x08006A74 — początek funkcji Reset_Handler. Jeśli przewiniesz listing w dół, możesz zobaczyć wywołanie funkcji main. Możesz ustawić kursor na tym wierszu (adres 0x08006ABE) i wykonać operację Uruchom do kursora (klawisz F4).

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Następnie możesz nacisnąć F7, aby wejść w funkcję main.

Jeśli wykonasz polecenie Kontynuuj proces (klawisz F9), pojawi się okno „Proszę czekać” z jedynym przyciskiem Wstrzymaj:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Po naciśnięciu Wstrzymaj wykonywanie kodu oprogramowania jest wstrzymywane i może być kontynuowane z tej samej pozycji w kodzie, w której zostało przerwane.

Jeśli kontynuujesz wykonanie kodu, w terminalach podłączonych do wirtualnych portów COM można zobaczyć następujące linie:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Obecność linii „state bypass” wskazuje, że wirtualny moduł Bluetooth przeszedł w tryb odbierania danych z portu COM użytkownika.

Teraz w terminalu Bluetooth (na rysunku — COM29) możesz wprowadzać polecenia zgodnie z protokołem „Nosorożca”. Na przykład, na polecenie „MEOW” do terminala Bluetooth wróci linia „mur-mur”:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Nie emuluj mnie całkowicie

Podczas budowy emulatora można wybierać stopień szczegółowości/emulacji danego urządzenia. Na przykład moduł Bluetooth można emulować na różne sposoby:

  • emuluje się całe urządzenie z pełnym zestawem poleceń;
  • emulowane są polecenia AT, a strumień danych jest odbierany z portu COM głównego systemu;
  • wirtualne urządzenie zapewnia pełne przekierowanie danych do rzeczywistego urządzenia;
  • w formie prostej nakładki, która zawsze zwraca „OK”.

W bieżącej wersji emulatora zastosowano drugie podejście — wirtualny moduł Bluetooth przeprowadza konfigurację, a następnie przechodzi w tryb „proxy” danych z portu COM głównego systemu do portu UART emulatora.

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Rozważmy możliwość prostego instrumentowania kodu w przypadku, gdy jakaś część peryferyjna nie jest zrealizowana. Na przykład, jeśli nie został stworzony timer, który odpowiada za kontrolę przesyłania danych w DMA (sprawdzane w funkcji ws2812b_wait, znajdującej się pod adresem 0x08006840), to oprogramowanie będzie zawsze czekać na zresetowanie flagi busy, znajdującej się pod adresem 0x200004C4, która pokazuje zajętość linii danych DMA:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Możemy obejść tę sytuację poprzez „ręczne” zresetowanie flagi busy zaraz po jej ustawieniu. W IDA Pro można stworzyć funkcję w Pythonie i wywołać ją w punkcie przerwania, a sam punkt przerwania ustawić w kodzie po zapisaniu wartości 1 w flagę busy.

Handler punktu przerwania

Najpierw stworzymy funkcję w Pythonie w IDA. Menu Plik — Komenda skryptu…

Dodajemy nowy fragment na liście po lewej, nadając mu nazwę (na przykład, BPT),
w polu tekstowym po prawej wpisujemy kod funkcji:

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

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Po tym klikamy Run i zamykamy okno skryptów.

Teraz przejdźmy do kodu pod adresem 0x0800688A, ustawmy punkt przerwania (klawisz F2), edytujemy go (menu kontekstowe Edytuj punkt przerwania…), nie zapomnijmy ustawić typu skryptu – Python:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat
Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Jeśli bieżąca wartość flagi busy wynosi 1, należy wykonać funkcję skip_dma w linii skryptu:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Jeśli uruchomić oprogramowanie do wykonania, to wykonanie kodu obsługi punktu przerwania można zobaczyć w IDA w oknie Output pod linią Pomijam czekanie ws2812.... Teraz oprogramowanie nie będzie oczekiwać na reset flagi. busy.

Interakcja z emulatorem

Emulacja tylko w celu emulacji raczej nie wywoła entuzjazmu ani radości. O wiele ciekawiej, gdy emulator pomoże badaczowi zobaczyć dane w pamięci lub ustanowić interakcję pomiędzy wątkami.

Pokażemy, jak w dynamiczny sposób ustanowić interakcję zadań RTOS. Wcześniej należy wstrzymać wykonanie kodu, jeśli jest już uruchomione. Jeśli przejdziesz do funkcji bluetooth_task_entry w gałęzi obsługi komendy „LED” (adres 0x080057B8), to można zobaczyć, że najpierw tworzone jest, a potem wysyłane do systemowej kolejki ledControlQueueHandle pewne komunikaty.

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Należy ustawić punkt przerwania na odwołanie do zmiennej ledControlQueueHandle, znajdującej się pod adresem 0x20000624 i kontynuować wykonanie kodu:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

W rezultacie najpierw nastąpi zatrzymanie pod adresem 0x080057CA przed wywołaniem funkcji osMailAlloc, następnie - pod adresem 0x08005806 przed wywołaniem funkcji osMailPut, potem po pewnym czasie - pod adresem 0x08005BD4 (przed wywołaniem funkcji osMailGet), który należy do funkcji leds_task_entry (LED-task), co oznacza, że doszło do przełączenia zadań, a teraz kontrola przeszła do LED-task.

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

W ten prosty sposób można ustalić, jak zadania RTOS współdziałają ze sobą.

Oczywiście w rzeczywistości interakcja zadań może być bardziej złożona, ale korzystając z emulatora, śledzenie tej interakcji staje się mniej czasochłonne.

Tutaj można zobaczyć krótki filmik dotyczący uruchamiania emulatora i interakcji z IDA Pro.

Uruchomienie z Radare2

Nie można pominąć tak wszechstronnego narzędzia jak Radare2.

Aby połączyć się z emulatorem za pomocą r2, komenda będzie wyglądać tak:

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

Obecnie dostępne są uruchomienie (dc) i wstrzymanie wykonania (Ctrl+C).

Niestety, w tej chwili w r2 występują problemy podczas pracy z serwerem gdb oraz podziałem pamięci; w związku z tym punkty zatrzymania i kroki (komenda ds) nie działają. Mamy nadzieję, że wkrótce zostanie to naprawione.

Uruchomienie z Eclipse

Jedną z możliwości wykorzystania emulatora jest debugowanie oprogramowania układowego rozwijanego urządzenia. Dla jasności będziemy również korzystać z oprogramowania 'Nosorożec'. Źródła oprogramowania można pobrać stąd.

Jako IDE będziemy używać Eclipse z zestawu System Workbench for STM32.

Aby w emulatorze ładowano oprogramowanie bezpośrednio zbudowane w Eclipse, należy dodać parametr firmware=null do komendy uruchomienia emulatora:

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

Konfiguracja debugowania

W Eclipse wybieramy menu Run — Debug Configurations… W otwartym oknie w sekcji GDB Hardware Debugging należy dodać nową konfigurację, po czym na zakładce 'Main' wskazać aktualny projekt i aplikację do debugowania:

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Na zakładce 'Debugger' należy wskazać komendę GDB:
${openstm32_compiler_path}arm-none-eabi-gdb

A także wprowadzić parametry do połączenia z serwerem GDB (host i port):

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Na zakładce 'Startup' należy podać następujące parametry:

  • zaznaczyć pole Load image (aby załadować zbudowany obraz oprogramowania do emulatora);
  • zaznaczyć pole Load symbols;
  • dodać komendę uruchomienia: set $pc = *0x08000004 (ustaw wartość PC w rejestrze z pamięci pod adresem 0x08000004 — tam jest zapisany adres ResetHandler’a).

Zwróć uwagę, jeśli nie chcesz załadować pliku firmware z Eclipse, to parametry Load image i Uruchom polecenia nie musisz podawać.

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Po naciśnięciu Debug można pracować w trybie debuggera:

  • krokowe wykonywanie kodu
    Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat
  • interakcja z punktami przerwania
    Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Uwaga. W Eclipse są, hmm… pewne specyficzne cechy… i trzeba z nimi żyć. Na przykład, jeśli podczas uruchamiania debuggera pojawi się komunikat „Brak dostępnego źródła dla „0x0″”, to wykonaj polecenie Step (F5)

Nosorożec w środku kota — uruchamiamy oprogramowanie w emulatorze Kopycat

Zamiast zakończenia

Emulacja natywnego kodu to bardzo interesująca sprawa. Dla dewelopera urządzeń stwarza możliwość debugowania firmware bez rzeczywistego urządzenia. Dla badacza — możliwość przeprowadzenia dynamicznej analizy kodu, czego nie zawsze można dokonać nawet przy posiadaniu urządzenia.

Chcemy dostarczyć specjalistom narzędzie, które byłoby wygodne, w miarę proste i nie zabierało dużo siły i czasu na swoją konfigurację i uruchomienie.

Podziel się w komentarzach swoimi doświadczeniami z emulatorami sprzętowymi. Zapraszamy do dyskusji i z przyjemnością odpowiemy na pytania.

Tylko zarejestrowani użytkownicy mogą brać udział w ankiecie. Zaloguj się, proszę.

Do czego używasz emulatora?

  • opracowuję (debuguję) firmware

  • badam firmware

  • uruchamiam gry (Dendi, Sega, PSP)

  • coś innego (napisz w komentarzu)

7 użytkowników zagłosowało. 2 użytkowników wstrzymało się.

Jakiego oprogramowania używasz do emulacji natywnego kodu?

  • QEMU

  • Unicorn engine

  • Proteus

  • coś innego (napisz w komentarzu)

Zagłosowało 6 użytkowników. 2 wstrzymało się.

Co chciałbyś poprawić w używanym emulatorze?

  • chciałbym szybkości

  • chciałbym wygody konfiguracji/uruchamiania

  • chciałbym więcej możliwości interakcji z emulatorem (API, hooki)

  • wszystko mi odpowiada

  • coś innego (napisz w komentarzu)

8 użytkowników zagłosowało. 1 użytkownik wstrzymał się od głosu.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster