
In questa sessione del workshop, estrarremo il firmware da un caricatore per veicoli elettrici, analizzeremo il firmware e, infine, lo emuleremo per poter interagire con i servizi in tempo reale.
Unisciti a noi in questa demo pratica su Unblob, il flessibile estrattore di firmware. Durante questa sessione di workshop, estrarremo il firmware da un caricabatterie per veicoli elettrici, esploreremo il firmware e, infine, lo emuleremo per poter interagire con i servizi in tempo reale. Unblob funziona sia su versioni hardware che su versioni scaricabili di firmware, quindi abbiamo un ambiente ricco di obiettivi. Non è richiesta alcuna esperienza precedente: questa sessione è adatta a tutti i livelli di competenza e non vediamo l'ora di vederti lì.
Il nostro obiettivo è un controller di stazione di ricarica per veicoli elettrici di Phoenix Contact. Puoi trovare maggiori dettagli qui.
CHARX control modular, controller di ricarica AC, con sistema Linux embedded, IEC 61851-1, modalità operativa: Stand-Alone, Client, Server,
Interfacce:
- Ethernet (2x)
- Comunicazione cellulare (4G/2G)
- Bus di sistema CHARX control modular
- MICRO-USB tipo C
Protocolli di comunicazione:
- OCPP 1.6J
- Modbus/TCP
- MQTT
Dispositivi periferici collegabili:
- Contatore di energia
- RFID
- Rilevamento corrente residua DC
- Montaggio su guida DIN
Ci sono alcuni strumenti che ci servono in questo workshop. Puoi installarli
eseguendo lo script install-prerequisites in questo modo:```sh
./install-prerequisites
## Ottenimento del firmware
Il firmware può essere ottenuto dal sito web del vendor. In questo repository è presente uno script denominato
`download-firmware` che puoi usare per scaricare il firmware
senza dover aprire un browser.
La nostra attenzione oggi è sul firmware fornito dal vendor, poiché contiene tutto
ciò di cui abbiamo bisogno. Ma un flusso di lavoro simile può essere applicato a un dump di memoria estratto da
un dispositivo reale. La cosa interessante è che possiamo estrarre, esplorare ed
emulare senza nemmeno aver bisogno di un dispositivo reale.
## Estrazione con Unblob
Iniziamo assicurandoci che tutte le dipendenze siano disponibili:```
unblob --show-external-dependencies
The following executables found installed, which are needed by unblob:
7z ✓
debugfs ✓
jefferson ✓
lz4 ✓
lziprecover ✓
lzop ✓
sasquatch ✓
sasquatch-v4be ✓
simg2img ✓
ubireader_extract_files ✓
ubireader_extract_images ✓
unar ✓
zstd ✓
Ora possiamo estrarre il firmware con unblob:``` unblob CHARXSEC3XXXSoftwareBundleV190.raucb
L'estrazione richiede circa 3 minuti su un laptop decente. Dovresti vedere una barra di avanzamento che avanza:

Una volta completata l'estrazione, dovrebbe essere visibile una directory denominata
`CHARXSEC3XXXSoftwareBundleV190.raucb_extract`. Puoi entrarci
ed elencarne il contenuto.
### Chunk, Chunk Sconosciuti
Unblob funziona identificando chunk di dati all'interno dei file. Se un chunk è un
flusso compresso, viene decompresso. Se è un filesystem o un archivio, viene
estratto. Se l'estrazione o la decompressione ha successo, il chunk
che è stato scritto su disco viene eliminato per recuperare spazio.
Qui, un chunk SquashFS versione 4 little-endian è stato scritto su disco, estratto
ed eliminato. I file (e quindi le directory di estrazione) sono nominati con
la nomenclatura `{start_offset}-{end_offset}.{type}`.
Possiamo vedere che 11KB di chunk "unknown" compaiono dopo il filesystem squashfs.```
./0-132173824.squashfs_v4_le_extract
./132173824-132184833.unknown
Puoi eseguire binwalk su di esso per vedere cosa contiene:```
binwalk 132173824-132184833.unknown
0 0x0 Object signature in DER format (PKCS header length: 4, sequence length: 10997 58 0x3A Certificate in DER format (x509 v3), header length: 4, sequence length: 4372 4434 0x1152 Certificate in DER format (x509 v3), header length: 4, sequence length: 4387
Puoi controllare i certificati con openssl:```
dd if=132173824-132184833.unknown bs=1 skip=58 | openssl x509 -in /dev/stdin -inform der -noout -text
dd if=132173824-132184833.unknown bs=1 skip=4434 | openssl x509 -in /dev/stdin -inform der -noout -text
Questo significa che i firmware sono probabilmente firmati con la chiave privata del vendor, così i dispositivi possono assicurarsi che i firmware siano autentici.
Questo è uno dei vantaggi di unblob: trasformare le incognite sconosciute in incognite note che possono essere investigate.
Diamo un'occhiata al contenuto del nostro filesystem squashfs:``` ls -al 0-132173824.squashfs_v4_le_extract total 460532 drwxrwxr-x 4 kali kali 4096 dec 5 09:51 . drwxrwxr-x 3 kali kali 4096 dec 5 09:51 .. -rw-rw-r-- 1 kali kali 20971520 sep 8 09:59 bootimg.vfat drwxrwxr-x 3 kali kali 4096 dec 5 09:51 bootimg.vfat_extract -rwxrwxr-x 1 kali kali 2654 sep 19 2022 hook -rw-rw-r-- 1 kali kali 442 sep 8 09:59 manifest.raucm -rw-rw-r-- 1 kali kali 450584576 sep 8 09:59 root.ext4 drwxrwxr-x 22 kali kali 4096 sep 8 09:57 root.ext4_extract
Possiamo vedere un manifest in chiaro, uno script shell, un MBR e un filesystem EXT4:```
find -maxdepth 1 -type f -exec file {} \;
./manifest.raucm: ASCII text
./hook: a /usr/bin/env sh script, ASCII text executable
./bootimg.vfat: DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, reserved sectors 4, root entries 512, sectors 40960 (volumes <=32 MB), Media descriptor 0xf8, sectors/FAT 40, sectors/track 63, heads 255, hidden sectors 163158016, reserved 0x1, serial number 0xd09aad9c, label: "KERNEL ", FAT (16 bit)
./root.ext4: Linux rev 1.0 ext4 filesystem data, UUID=8ed19606-02c4-42e7-9cfb-1a2839f93ec4 (extents) (large files) (huge files)
Sia bootimg.vfat che root.ext4 sono stati gestiti ed estratti da unblob. La
partizione VFAT contiene tutto ciò che riguarda boot e sistema operativo (kernel Linux, DTB, TEE):```
oftree: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756
tee.bin: data
zImage: Linux kernel ARM boot executable zImage (little-endian)
zImage-imx6ul-ksp0632.dtb: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756
Vedrai che unblob è un po' avido ed estrarrà un file ELF e un archivio CPIO
dal kernel Linux (`zImage`), questi corrispondono al kernel minimale
e al ramdisk.
Il filesystem EXT4 contiene il filesystem root che viene montato dal kernel
Linux all'avvio:```
ls -alh root.ext4_extract
total 88K
drwxrwxr-x 22 kali kali 4,0K sep 8 09:57 .
drwxrwxr-x 4 kali kali 4,0K dec 5 09:51 ..
drwxrwxr-x 2 kali kali 4,0K dec 5 09:51 bin
drwxrwxr-x 3 kali kali 4,0K dec 5 09:51 boot
drwxrwxr-x 16 kali kali 4,0K sep 8 09:56 data
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 dev
drwxrwxr-x 53 kali kali 4,0K dec 5 09:51 etc
drwxrwxr-x 18 kali kali 4,0K sep 8 09:56 home
drwxrwxr-x 2 kali kali 4,0K jul 18 03:13 identity
drwxrwxr-x 9 kali kali 4,0K dec 5 09:51 lib
drwxrwxr-x 2 kali kali 4,0K jul 18 03:14 log
drwxrwxr-x 2 kali kali 4,0K sep 8 09:57 lost+found
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 media
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 mnt
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 proc
drwxrwxr-x 2 kali kali 4,0K sep 8 09:57 run
drwxrwxr-x 2 kali kali 4,0K dec 5 09:51 sbin
drwxrwxr-x 2 kali kali 4,0K jul 18 03:14 sdcard
drwxrwxr-x 2 kali kali 4,0K jul 18 00:09 sys
drwxrwxrwx 2 kali kali 4,0K jul 18 00:09 tmp
drwxrwxr-x 11 kali kali 4,0K sep 8 09:56 usr
drwxrwxr-x 11 kali kali 4,0K dec 5 09:51 var
Facciamo un po' di esplorazione utilizzando un diverso set di opzioni di unblob:```
unblob -e /tmp/out -f -k -d 3 --report /tmp/report.json
--log /tmp/unblob.log CHARXSEC3XXXSoftwareBundleV190.raucb
Qui continuiamo a estrarre (`-e`) in `/tmp/out` ma forziamo (`-f`) la sovrascrittura
mantenendo (`-k`) i chunk estratti ma limitando la profondità di ricorsione (`-d`) a
3. Scriviamo un report dettagliato (`--report`) in `/tmp/report.json` e il file di log
(`--log`) in `/tmp/unblob.log`.
Dai un'occhiata al file di log: vedrai il funzionamento interno di unblob.
Il file di report contiene informazioni dettagliate sui file analizzati (dimensione, tipo di file,
percorso, magic, mime-type, hash MD5/SHA1/SHA256), sui chunk (dimensione, offset,
distribuzione dell'entropia) e sulle attività (estrazione, decompressione, carving). È
possibile generare belle visualizzazioni da questi file di report con un po'
di Python.
Puoi crearle tu stesso con lo script `diagram.py` disponibile in
questo repository:```
python3 diagram.py /tmp/report.json sunburst
python3 diagram.py /tmp/report.json treemap
These commands will open up the browser to a page that contains a plotly based visualization like the ones below:


Now that we have a better sense of what's inside, it's time to list what we need to perform proper emulation of the device.
Ideally, we need to gather these pieces of information:
To get some details about the platform, CPU, and architecture, we can look into the device tree blobs embedded in the firmware.
In the VFAT partition, we have these DTBs:``` oftree: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756 zImage-imx6ul-ksp0632.dtb: Device Tree Blob version 17, size=27469, boot CPU=0, string block size=1657, DT structure block size=25756
Questi file sono una rappresentazione binaria dei device tree. Possiamo recuperare la loro sorgente in testo semplice usando `device-tree-compiler`:```
dtc -I dtb -o zImage-imx6ul-ksp0632.dts zImage-imx6ul-ksp0632.dtb
dtc -I dtb -o oftree.dts oftree
Dai un'occhiata al DTS e presto troverai dettagli interessanti come il modello:``` /dts-v1/;
/ { #address-cells = <0x01>; #size-cells = <0x01>; model = "Phytec phyBOARD-Segin i.MX6 UltraLite"; <----- right here compatible = "phytec,imx6ul-pbacd-10\0phytec,imx6ul-pcl063\0fsl,imx6ul";
La CPU:```
cpus {
#address-cells = <0x01>;
#size-cells = <0x00>;
cpu@0 {
compatible = "arm,cortex-a7"; <---- here
device_type = "cpu";
reg = <0x00>;
clock-latency = <0xee6c>;
operating-points = <0xa9ec0 0x137478 0x80e80 0x11edd8 0x60ae0 0xfa3e8 0x30570 0xe7ef0>;
fsl,soc-operating-points = <0xa9ec0 0x137478 0x80e80 0x11edd8 0x60ae0 0x11edd8 0x30570 0x11edd8>;
clocks = <0x01 0x5d 0x01 0x1a 0x01 0x26 0x01 0xdb 0x01 0x38 0x01 0x39 0x01 0x19>;
clock-names = "arm\0pll2_bus\0pll2_pfd2_396m\0secondary_sel\0step\0pll1_sw\0pll1_sys";
arm-supply = <0x02>;
soc-supply = <0x03>;
dc-supply = <0x04>;
};
};
O anche periferiche:``` --snip-- ethernet@2188000 { compatible = "fsl,imx6ul-fec\0fsl,imx6q-fec"; reg = <0x2188000 0x4000>; interrupts = <0x00 0x76 0x04 0x00 0x77 0x04>; clocks = <0x01 0x90 0x01 0x91 0x01 0x30 0x01 0x2c 0x01 0x2c>; clock-names = "ipg\0ahb\0ptp\0enet_clk_ref\0enet_out"; fsl,num-tx-queues = <0x01>; fsl,num-rx-queues = <0x01>; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <0x23>; phy-mode = "rmii"; phy-handle = <0x24>;
mdio {
#address-cells = <0x01>;
#size-cells = <0x00>;
ethernet-phy@1 {
reg = <0x01>;
interrupt-parent = <0x0b>;
interrupts = <0x02 0x08>;
micrel,led-mode = <0x01>;
clocks = <0x01 0x2c>;
clock-names = "rmii-ref";
status = "okay";
linux,phandle = <0x24>;
phandle = <0x24>;
};
ethernet-phy@2 {
reg = <0x03>;
micrel,led-mode = <0x01>;
clocks = <0x01 0x2d>;
clock-names = "rmii-ref";
status = "okay";
linux,phandle = <0x13>;
phandle = <0x13>;
};
};
};
--snip-- flexcan@2090000 { compatible = "fsl,imx6ul-flexcan\0fsl,imx6q-flexcan"; reg = <0x2090000 0x4000>; interrupts = <0x00 0x6e 0x04>; clocks = <0x01 0x94 0x01 0x95>; clock-names = "ipg\0per"; status = "okay"; pinctrl-names = "default"; pinctrl-0 = <0x0f>; xceiver-supply = <0x10>; };
flexcan@2094000 { compatible = "fsl,imx6ul-flexcan\0fsl,imx6q-flexcan"; reg = <0x2094000 0x4000>; interrupts = <0x00 0x6f 0x04>; clocks = <0x01 0x96 0x01 0x97>; clock-names = "ipg\0per"; status = "disabled"; };
### Informazioni sulla versione del kernel Linux
Possiamo identificare la versione del kernel Linux eseguendo grep all'interno della partizione VFAT che contiene il kernel compresso:```
grep 'Linux version' . -ra
./zImage_extract/7296-6371487.lzo_extract/7296-6371487:
Linux version 5.15.195 (oe-user@oe-host) (gcc version 8.3.0 (GCC)) #1 SMP PREEMPT
./zImage_extract/7296-6371487.lzo_extract/7296-6371487:
Linux version %s (%s)Bluetooth subsystem version %u.%uHCI socket registration failed
Un altro modo è guardare i moduli del kernel all'interno del filesystem root EXT4:```
modinfo ./CHARXSEC3XXXSoftwareBundleV190.raucb_extract/0-138014720.squashfs_v4_le_extract/root.ext4_extract/lib/modules/5.15.195/kernel/net/bluetooth/bnep/bnep.ko.xz
filename: ./CHARXSEC3XXXSoftwareBundleV190.raucb_extract/0-138014720.squashfs_v4_le_extract/root.ext4_extract/lib/modules/5.15.195/kernel/net/bluetooth/bnep/bnep.ko.xz
alias: bt-proto-4
license: GPL
version: 1.3
description: Bluetooth BNEP ver 1.3
author: Marcel Holtmann [email protected]
srcversion: 86266D360814678CE0C94E9
depends:
intree: Y
name: bnep
vermagic: 5.15.195 preempt mod_unload modversions ARMv7 thumb2 p2v8
parm: compress_src:Compress sources headers (bool)
parm: compress_dst:Compress destination headers (bool)
## Emulazione
Potremmo già avere un kernel compilato all'interno del pacchetto firmware, ma questo
kernel è compilato specificamente per una particolare macchina (la Phytec
phyBOARD-Segin i.MX6 UltraLite).
Per usare correttamente questo kernel, dovremmo essere in grado di eseguirlo su
un'emulazione dell'esatta macchina per cui è stato compilato. Questa operazione
richiede molto tempo se non è già presente nell'elenco delle macchine QEMU.
Nota: una macchina con scheda di valutazione è disponibile in QEMU
(`mcimx6ul-evk - Freescale i.MX6UL Evaluation Kit (Cortex-A7)`) ma non corrisponde
esattamente.
In alternativa, in teoria, possiamo scegliere una macchina QEMU e usare vari
metadati che troviamo nell'immagine del firmware per configurare e compilare un
kernel per quella macchina, che sarebbe anche in grado di eseguire tutto ciò che
è nel nostro filesystem, il più vicino possibile all'originale.
Da qui, abbiamo alcune opzioni:
- *emulazione dello spazio utente*: potremmo avviare un nostro ramfs/rootfs personalizzato, quindi
caricare il rootfs del firmware target ed eseguire chroot al suo interno per emularlo.
- *emulazione di sistema completo*: potremmo provare ad avviare direttamente il rootfs del firmware target
(passandolo direttamente alla macchina QEMU).
L'emulazione dello spazio utente è di solito limitante, ma è un ottimo modo per
analizzare, eseguire il debug e sfruttare binari specifici. Ti consigliamo
vivamente di dare un'occhiata a [EMUX](https://github.com/therealsaumil/emux)
di Saumil Shah per tutte le tue esigenze di emulazione dello spazio utente.
In ogni caso, abbiamo comunque bisogno di un kernel che si avvii all'interno di una
macchina QEMU e che corrisponda il più possibile a ciò che il firmware target
si aspetta.
### Macchine QEMU
Ci sono solo pochi candidati tra le macchine generiche che offrono flessibilità.
Dopo parecchi esperimenti, `virt`
(https://qemu.readthedocs.io/en/latest/system/arm/virt.html) sembra avere un
buon rapporto flessibilità/potenza per i nostri scopi.
Quando si compila il kernel per una determinata macchina QEMU, probabilmente è
meglio assicurarsi di poter usare il dispositivo virtio generico fornito con QEMU.
Nella configurazione, questi potrebbero significare uno o più dei seguenti:```
CONFIG_VIRTIO=y
CONFIG_SCSI_VIRTIO=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BLK=y
E molto altro! Questo elenco è incompleto.
Per noi è vantaggioso usare un kernel che abbia una stringa vermagic identica (o almeno molto simile). Tutti i tipi di componenti all'interno di un sistema potrebbero controllare il vermagic del kernel e fallire se è diverso da quello atteso. Questo è molto comune nei moduli del kernel - un kernel di solito rifiuta di caricare un modulo che non ha un vermagic corrispondente al proprio. Anche se possiamo patchare il kernel per ignorare questo a livello di kernel, abbiamo comunque bisogno che la parte iniziale “kernel release” della stringa corrisponda alla stringa di rilascio dei moduli del kernel, poiché viene usata come percorso di ricerca per modules.dep.
Nel firmware Phoenix Contact, il vermagic è 5.15.195 preempt mod_unload modversions ARMv7 thumb2 p2v8.
La stringa vermagic è in un formato simile a (da include/linux/vermagic.h):```c
#define VERMAGIC_STRING
UTS_RELEASE " "
MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT
MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_MODVERSIONS
MODULE_ARCH_VERMAGIC
- Kernel release = la versione del kernel + la stringa `CONFIG_LOCALVERSION`.
- SMP = `CONFIG_SMP`
- PREEMPT = `CONFIG_PREEMPT`
- mod_unload = `CONFIG_MODULE_UNLOAD`
- modversions = `CONFIG_MODVERSIONS`
- ARMv7 thumb2 p2v8 = `MODULE_ARCH_VERMAGIC` (relativo all'architettura per cui il kernel è compilato, quindi legato all'opzione compilatore/arch passata.)
Una volta ottenuto il sorgente del kernel estratto, possiamo modificarlo affinché non sia così brutale nel confrontare le stringhe vermagic. In kernel/module.c, possiamo semplicemente commentare return -ENOEXEC:```diff
} else if (!same_magic(modmagic, vermagic, info->index.vers)) {
pr_err("%s: version magic '%s' should be '%s'\n", info->name, modmagic, vermagic);
- return -ENOEXEC;
+ // return -ENOEXEC;
}
if (!get_modinfo(info, "intree")) {
Potrebbe non essere necessariamente utile a lungo termine, ma è utile per i test, finché ci sono lievi discrepanze tra il vermagic del nostro kernel e il vermagic del modulo. I moduli (il più delle volte) si caricheranno comunque.
NOTA: qui forniamo un kernel già compilato che soddisfa i requisiti del target, così non devi compilarne uno tu stesso. È stato compilato con uno script interno che:
multi_v7_defconfig per impostare la configurazione inizialekernel/module.cVIRTIO e sottosistemi specifici come
USB o CANBUSVediamo i diversi parametri del nostro comando qemu-system-arm. Forniamo il kernel in questo modo:```sh
qemu-system-arm -M virt,highmem=off
-m ${AVAILABLE_MEM_GB}G -smp ${CPU_CORES} -cpu cortex-a15
-kernel zImage
L'immagine del filesystem EXT4 è allegata come disco SCSI:```sh
-device virtio-scsi-device \
-device scsi-hd,drive=SystemDisk \
-drive file=${FIRMWARE_IMAGE},format=raw,if=none,id=SystemDisk
Impostiamo un output console adeguato in questo modo:```sh
-append "${BOOT_PARAMS}"
-no-reboot
-nographic
-serial mon:stdio \
I parametri `BOOT_PARAMS` sono impostati in `config.ini` e corrispondono all'effettivo bootcmd del kernel, con due piccole adattamenti (percorso della console e percorso del rootfs).
### Rete
Ora che abbiamo un sistema emulato funzionante, è ora di configurare la rete. Il target dispone di quanto segue:
- due interfacce Ethernet (`eth0` e `eth1`)
- un'interfaccia CANbus (`can0`)
- un'interfaccia USB che può fungere da Ethernet over USB (`usb0`)
- un modem cellulare Qualcomm High Sierra (`ppp0`)
Emulare il modem cellulare e le interfacce USB è una seccatura con QEMU, e non è
realmente necessario per il funzionamento del dispositivo poiché quelle interfacce sono "opzionali". L'
interfaccia CAN è presente per consentire al controller di comunicare con altri controller o
stazioni di ricarica. L'interfaccia `eth0` fornisce connettività verso l'alto
richiedendo un lease DHCP per impostazione predefinita, mentre `eth1` è impostata su 192.168.4.1 ed è
presente se si desidera collegare in cascata più controller.
Le interfacce ethernet sono configurate come interfacce TAP e collegate in questo modo:```
-netdev tap,id=tap0net,ifname=${ETH_1},script=no,downscript=no \
-device virtio-net-device,netdev=tap0net,mac=${ETH_1_MAC} \
-netdev tap,id=tap1net,ifname=${ETH_0},script=no,downscript=no \
-device virtio-net-device,netdev=tap1net,mac=${ETH_0_MAC} \
L'interfaccia CANBUS è semplicemente un'interfaccia PCI, collegata in questo modo:```
-object can-bus,id=canbus0
-device kvaser_pci,canbus=canbus0
-object can-host-socketcan,id=canhost0,if=can0,canbus=canbus0 \
Il diagramma seguente mostra com'è configurata la rete:

Se volessi provare la comunicazione tra controller collegandoli in serie (daisy-chain) come consigliato da Phoenix Contact, potresti usare qualcosa del genere:

## Pronti ? Partenza. Lancio !
Ora che tutto è in ordine, è il momento di avviare il tutto !
Per prima cosa, devi configurare tutte le interfacce di rete in questo modo:```
sudo ./ifup.sh
Assicurati che la tua interfaccia upstream sia impostata correttamente in config.ini:```
OUT_IF="eth0"
Puoi quindi avviare l'emulatore:```
sudo ./launch.sh
Vedrai gli indirizzi ottenuti nei log:``` Dec 5 10:07:46 ev3000 daemon.info avahi-daemon[1047]: Registering new address record for 192.168.4.1 on eth1.IPv4. Dec 5 10:07:46 ev3000 daemon.info avahi-daemon[1047]: Registering new address record for 192.168.88.181 on eth0.IPv4.
### Accesso via SSH
Puoi quindi accedere tramite SSH al dispositivo emulato utilizzando l'utente `user-app`:```sh
ssh [email protected]
La password è "user". Dovrai cambiarla al primo accesso:```sh ssh [email protected] The authenticity of host '192.168.88.181 (192.168.88.181)' can't be established. ED25519 key fingerprint is SHA256:qMupzEehNFpx6eaGZ4d3AY5Jlms3Pmxh3/yg9OGA28o. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '192.168.88.181' (ED25519) to the list of known hosts. [email protected]'s password: WARNING: Your password has expired. You must change your password now and login again! Changing password for user-app Old password: Enter the new password (minimum of 5 characters) Please use a combination of upper and lower case letters and numbers. New password: Re-enter new password: passwd: password changed. Connection to 192.168.88.181 closed.
### Interfaccia Web
Puoi accedere all'interfaccia web all'indirizzo http://192.168.4.1. Potrebbe mostrare un messaggio di errore
mentre il dispositivo si avvia. Una volta che tutto è operativo,
dovresti vedere questo:

Puoi accedere con i seguenti account:
| Nome utente | Password |
|----------|----------|
| manufacturer | manufacturer |
| operator | operator |
### Traffico CAN
Quando tutto è operativo, puoi catturare il traffico CAN emesso dal
controller:```
candump -i can0
can0 701 [1] 00000101
can0 701 [1] 00000101
can0 701 [1] 00000101
can0 701 [1] 00000101
can0 701 [1] 00000101
can0 701 [1] 00000101
NOTE: sembra che la versione 8.x di QEMU abbia alcune difficoltà a collegare il controller CAN per qualche motivo.