Rétroingénierie sur un firmware

Introduction

Par simple curiosité, je voulais comprendre le fonctionnement de mon NAS Thecus N2310, et faire un peu de reverse engineering pour, pourquoi pas, mettre un jour un firmware alternatif.

Pour cela je suis partit du zip de mise à jour de la nand, mais j’aurai tout aussi bien pu dumper la nand avec les mtdtools.

Commençons les recherches sur le firmware

Récupérations des infos sur les partitions de la nand :
strings N2310_OS6.build_770.t2.bin > strings.txt
Recherche dans le fichier strings.txt de tailles de partitions.
Quelques données intéressantes :

partition@0,0
bNAND 256MiB 1,8V 08-bit
partition@0,1
bfirmware
partition@0c0000
benvironment
partition@100000
bkernel
partition@600000
bdevice-tree
partition@700000
bversion
partition@720000
bvalid
partition@820000
bramdisk
partition@1C00000
bos6disk

Pour plus d’information, il faut extraire la partition device tree qui semble être entre 0x600000 et 0x700000, donc utilisation de la commande :
dd if=N2310_OS6.build_770.t2.bin of=device-tree bs=1 skip=$((0x600000)) count=$((0x100000))

Extrations des données du device-tree

dtc -I dtb ./device-tree > dts
Ouverture avec un éditeur de texte du fichier dts, nous avons donc, entre autre, toutes les données de partitions :

				nand {
					#address-cells = <0x1>;
					#size-cells = <0x1>;

					partition@0,0 {
						label = "NAND 256MiB 1,8V 08-bit";
						reg = <0x0 0x10000000>;
					};

					partition@0,1 {
						label = "firmware";
						reg = <0x0 0xc0000>;
					};

					partition@0c0000 {
						label = "environment";
						reg = <0xc0000 0x40000>;
					};

					partition@100000 {
						label = "kernel";
						reg = <0x100000 0x500000>;
					};

					partition@600000 {
						label = "device-tree";
						reg = <0x600000 0x100000>;
					};

					partition@700000 {
						label = "version";
						reg = <0x700000 0x20000>;
					};

					partition@720000 {
						label = "valid";
						reg = <0x720000 0x100000>;
					};

					partition@820000 {
						label = "ramdisk";
						reg = <0x820000 0x27e0000>;
					};

					partition@1C00000 {
						label = "os6disk";
						reg = <0x3000000 0xd000000>;
					};
				};

Il est maintenant possible d’extraires les différentes partitions avec dd donc petit script :

#!/bin/sh
dd if=N2310_OS6.build_743.t2.bin of=firmware bs=1 skip=$((0x0)) count=$((0xc0000))
dd if=N2310_OS6.build_743.t2.bin of=environment bs=1 skip=$((0xc0000)) count=$((0x40000))
dd if=N2310_OS6.build_743.t2.bin of=kernel bs=1 skip=$((0x100000)) count=$((0x500000))
dd if=N2310_OS6.build_743.t2.bin of=device-tree bs=1 skip=$((0x600000)) count=$((0x100000))
dd if=N2310_OS6.build_743.t2.bin of=version bs=1 skip=$((0x700000)) count=$((0x20000))
dd if=N2310_OS6.build_743.t2.bin of=valid bs=1 skip=$((0x720000)) count=$((0x100000))
dd if=N2310_OS6.build_743.t2.bin of=ramdisk bs=1 skip=$((0x820000)) count=$((0x27e0000))
dd if=N2310_OS6.build_743.t2.bin of=os6disk bs=1 skip=$((0x3000000)) count=$((0xd000000))

L’outil file peut donner quelques informations sur les partitions :
file ramdisk
ramdisk: u-boot legacy uImage, InitRamFS 2.3.0-2.t2.ppc, Linux/PowerPC, RAMDisk Image (gzip), 15014381 bytes, Wed Jun 11 14:38:12 2014, Load Address: 0x00000000, Entry Point: 0x00000000, Header CRC: 0x7A5957CD, Data CRC: 0x67486288

C’est donc bien une partition InitRamFS.

file os6disk
os6disk: HIT archive data

En l’ouvrant avec ghex, il est possible de voir que les 3 premiers octets donne les caractères UBI, c’est donc une partition ubifs

Exploration de la partition InitRamFS

Il faut extraire le fichier gzip du ramdisk, pour cela il faut rechercher 00 00 1F 8B, avec une utilisation de ghex, on extrait tout ce qui est après 1F 8B inclu, donc 0x40 soit 64 :
dd if=ramdisk of=ramdisk.gz ibs=1 skip=64
Une petite vérification du fichier ramdisk.gz avec la commande file :
file ramdisk.gz
donne :
ramdisk.gz: gzip compressed data, from Unix, last modified: Tue Apr 15 18:24:42

Puis on extrait le ramdisk :
gunzip ramdisk.gz

On obtient un fichier cpio :
file ramdisk
qui renvoit :
ramdisk: ASCII cpio archive (SVR4 with no CRC)

On extrait le tout :
cpio -i -d -H newc -F ramdisk --no-absolute-filenames

Et voilà, un beau filesystem à explorer.

Exploration de la partition ubifs

Pour cela il faut simuler une nand, y copier la partition et monter le tout
sudo modprobe mtd
sudo modprobe nandsim first_id_byte=0x20 second_id_byte=0xaa third_id_byte=0x00 fourth_id_byte=0x15
sudo modprobe ubi
sudo dd if=os6disk of=/dev/mtd0 bs=2048
sudo ubiattach -m 0
sudo mount -t ubifs /dev/ubi0_0 partition/

La partition est maintenant montée sur le répertoire partition, il est possible d’en extraire les fichiers.

Astuces BIOS en vrac

Voici quelques astuces pour les bios, autres que les articles :
Modification d’un bios AMI pour y rajouter un microcode Intel
Modification d’un bios Award pour y rajouter un microcode Intel
Reprogrammer un bios de type SPI

Flasher le BIOS de backup d’une carte mère Gigabyte

Il faut pour cela un clavier connecté sur le port PS2 de la carte mère, un clavier USB ne fonctionnera pas, et il faut au démarrage appuyer sur les touches ALT+F10.

Astuces Eclipse en vrac

Voici quelques astuces pour Eclipse :

Afficher des variables statiques dans la fenêtre de debug d’Eclipse CDT

Il faut aller dans le menu Window -> Show View -> Expressions
Et ajouter ensuite la variable

Afficher des variables en hexadécimal dans la fenêtre de debug d’Eclipse CDT

Il faut aller dans le menu Window -> Preferences -> C/C++ -> Debug
Et modifier les « Default number format »

Astuces Windows en vrac

Cet article a pour but de répertorier quelques astuces qu’il m’arrive de rechercher.

Personnalisation de l’écran d’ouverture de session sous Windows 7

Il faut remplacer le fichier %windir%\System32\oobe\info\backgrounds\backgroundDefault.jpg par l’image de son choix.
Source

Comment faire pour activer la touche VERR. NUM pour l’écran d’ouverture de session

Pour activer VERR. NUM avant qu’un utilisateur ouvre une session, procédez comme suit.

Exécutez l’Éditeur du Registre (Regedt32.exe).
Recherchez la clé HKEY_USERS\.Default\Control Panel\Keyboard.
Remplacez la valeur 0 de InitialKeyboardIndicators par 2.
Source

Passer d’un clavier Qwerty à Azerty pour la saisie d’un mot de passe Windows

Mettre dans la clé HKEY_USERS\.DEFAULT\Keyboard Layout\Preload la valeur 0000040c
Source

Port série FTDI non associé à un composant mais à un port USB

Créer la clé binaire HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\UsbFlags\IgnoreHWSerNum04036001

Et y mettre la valeur 01
CF rubrique 7.1 Ignore Hardware Serial Number du document FTDI Application Note
AN_107 Advanced Driver Options

Passer un disque dur IDE en AHCI après installation

Il suffit de lancer le Microsoft Fix it 50470

Corriger un problème de port USB sous VirtualBox

Cette solution semble marcher :
1. Éditer la base de registre :
– Aller à HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Class\{36FC9E60-C465-11CF-8056-444553540000}
– Supprimer l’entrée UpperFilters

2. Installer le driver USB de VirtualBox manuellement :
– Aller dans C:\Program Files\Oracle\VirtualBox\drivers\USB\filter
– Clic droit sur VboxUSBMon.inf et sélectionner Install

3. Redémarrer

4. Débrancher le périphérique USB

5. Lancer VirtualBox puis le fermer

6. Brancher le périphérique USB

7. Lancer Virtualbox, ainsi que la machine virtuelle et sélectionner le périphérique USB.

Serveur Web Simple

TinyWeb est un petit serveur simple à configurer.
Exemple de script de lancement avec les fichiers dans le répertoire e:\www et sur le port 8000 :
tiny e:\www 8000
Exemple de script d’arrêt :
taskkill /F /IM tiny.exe

Corriger un problème périphérique usb dupliqué

Cela peut arriver si 2 périphériques ont le même numéro de série, et windows sort le code d’erreur 42 :

Windows cannot load the device driver for this
hardware because there is a duplicate device already running in the system. (Code 42) »

ou

Windows ne peut pas charger le pilote de périphérique de ce matériel car un périphérique identique est déjà activé dans le système. (Code 42)

La correction pour les VID 0x0483 et PID 0x5740 se fait avec regedit :
HKEY_LOCAL_MACHINE->SYSTEM->CurrentControlSet->Control->UsbFlags
Ajouter une valeur binaire : IgnoreHWSerNum04835740 et la mettre à la valeur 01

Libérer de la place en désactivant la mise en veille prolongée

Lancer la commande en administrateur :

powercfg -h off

Script bash de test d’une laison série

Voici un petit script qui permet de tester une liaison série (avec et sans bouchon)

#!/bin/bash

# connect.sh

# Usage:
# $ connect.sh <device> <port speed>
# Example: connect.sh /dev/ttyS0 9600

# Set up device
stty -F $1 $2 raw -echo

# Let cat read the device $1 in the background
cat $1 &

# Capture PID of background process so it's possible to terminate it when done
bgPid=$?

# Send a string to the serial link
sleep 0.5
echo "Loop OK !!!" > $1
sleep 0.5

read -p "Press any keys..."
# Terminate background read process
kill $bgPid

Accéder à un disque dur WD My Passport chiffré sous linux

Introduction

Certains disques dur comme les My Passport de Western Digital contiennent un chiffrement matériel et il faut donc un mot de passe pour y accéder.
Sous Windows il n’est possible d’y accéder qu’avec le logiciel WD Unlocker, aussi appelé WD Drive Unlock, mais rien d’officiel pour Linux.
J’ai donc cherché comment y accéder sous linux et voici la solution, qui n’est certes pas la plus simple mais fonctionne.

Récupération des différents logiciels

Les manipulations suivantes ont été faites sous Ubuntu 12.04.

Il faut récupérer le script python wdpassport-utils permettant de générer le mot de passe sur github :
git clone https://github.com/KenMacD/wdpassport-utils.git

puis installer les sg3-utils :
sudo apt-get install sg3-utils

Et enfin un petit bout de code qui permet de reseter le disque dur après avoir envoyé le mot de passe, à enregistrer sous usbreset.c par exemple :

/* usbreset -- send a USB port reset to a USB device */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>

#include <linux/usbdevice_fs.h>


int main(int argc, char **argv)
{
    const char *filename;
    int fd;
    int rc;

    if (argc != 2) {
        fprintf(stderr, "Usage: usbreset device-filename\n");
        return 1;
    }
    filename = argv[1];

    fd = open(filename, O_WRONLY);
    if (fd < 0) {
        perror("Error opening output file");
        return 1;
    }

    printf("Resetting USB device %s\n", filename);
#if 0
    rc = ioctl(fd, USBDEVFS_RESET, 0);
    
    if (rc < 0) {
        perror("Error in ioctl");
        return 1;
    }
#else
    //Work on WD My Passport
    struct usbdevfs_ioctl usb_ioctl;
    usb_ioctl.ifno = 0;
    usb_ioctl.ioctl_code = USBDEVFS_DISCONNECT;
    usb_ioctl.data = NULL;
    rc = ioctl(fd, USBDEVFS_IOCTL, &usb_ioctl);
    if (rc == -1 && errno != ENODATA) {
        perror("Error in ioctl (USBDEVFS_DISCONNECT)");
        return 1;
    }
    
    sleep(1);

    usb_ioctl.ifno = 0;
    usb_ioctl.ioctl_code = USBDEVFS_CONNECT;
    usb_ioctl.data = NULL;
    rc = ioctl(fd, USBDEVFS_IOCTL, &usb_ioctl);
    if (rc == -1 && errno != ENODATA) {
        perror("Error in ioctl (USBDEVFS_CONNECT)");
        return 1;
    }
#endif

    printf("Reset successful\n");

    close(fd);
    return 0;
}

et le compiler :
gcc usbreset.c -o usbreset

Utilisation des différents outils

Génération du mot de passe

Avec le script python qui va générer un fichier password.bin :
./cookpw.py MotDePasse > password.bin

Informations du disque

Pour trouver le disque dur il faut utiliser les commandes
dmesg |grep sg |grep "type 13"
qui nous donne
[ 3588.636411] ses 9:0:0:2: Attached scsi generic sg4 type 13
et
lsusb
qui nous donne
Bus 004 Device 005: ID 1058:0748 Western Digital Technologies, Inc.

Envois des commandes

Avec ces informations nous pouvons donc envoyer le mot de passe au disque dur :
sudo sg_raw -s 40 -i password.bin /dev/sg4 c1 e1 00 00 00 00 00 00 28 00
Puis le redémarrer :
sudo ./usbreset /dev/bus/usb/004/005

Normalement le disque dur se montera automatiquement.

Créer une disquette de boot MS-DOS 6.22 sous Linux

Introduction

Ceci est une méthode un peu bourrine pour créer une disquette bootable MS-DOS sous linux, en utilisant la commande dd pour modifier le Master Boot Record(MBR), pour plus d’informations sur le MBR des disquettes MS-DOS il suffit d’aller sur ce site.
Le but est de créer une image de disquette pouvant être utilisé dans VirtualBox.

Prérequis

Avoir récupéré MS-DOS 6.22 sur le site de microsoft :
Fichier fr_msdos622.exe
SHA1SUM :94d1d6dc7758999647e9ceaf0d502437e1556ccc
Avoir installé dosbox et wine :
sudo apt-get install dosbox wine1.4

Avoir récupéré dislite :
Exécutable
Source

Création de la disquette de boot MS-DOS 6.22

Création d’une disquette formatée en FAT12

Allocation de 1.44Mo de la disquette :
dd if=/dev/zero of=floppy144.img bs=1024 count=1440
Formatage de la disquette :
mkdosfs floppy144.img

Extraction des fichiers MS-DOS de l’exécutable Microsoft

Il suffit de lancer la commande :
wine fr_msdos622.exe
Et de choisir où extraire les fichiers, un répertoire MSDOS622 sera créé.

Extraire le MBR du fichier SYS.COM

Le fichier SYS.COM contient un MBR contenant le microprogramme permettant de booter, cet exécutable est compressé par pklite et doit donc être décompressé, pour cela nous allons utiliser le programme dislite avec dosbox.
Placer dans le même répertoire dislite.exe et le fichier SYS.COM extrait précédemment puis exécuter dosbox :
dosbox dislite.exe
dislite SYS.COM
exit

Nous avons donc maintenant un fichier SYS.COM décompressé, il faut l’ouvrir avec un éditeur hexadécimal pour trouver l’emplacement du MBR et rechercher la signature en hexadécimal 55AA, j’ai donc utilisé ghex :
Ghex SYS.COM
L’adresse de l’octet suivant 55AA est dans ce cas 0x3286, le MDR fait 512 Octet soit 0x200, il faut donc extraire le MBR à partir de l’adresse 0x3086 soit 12442, qui commence bien par EB3C90, pour cela nous utilisons la commande dd:
dd if=SYS.COM of=mbr.bin ibs=1 skip=12422 count=512

Merge du MBR Microsoft et de la disquette 1.44

Nous allons extraire l’entête et la fin du MBR extrait de SYS.COM et garder du MBR de la disquette son BIOS Parameter Block, son numéro de série(généré lors du formatage), son nom et l’ID du File System.

Extraction de l’entête du MBR :
dd if=mbr.bin of=top.bin ibs=1 count=11
Extraction de la fin du MBR à partir de 0x3e donc 62 :
dd if=mbr.bin of=bottom.bin ibs=1 skip=62
Extaction du reste sur la disquette 1.44 :
dd if=floppy144.img of=middle.bin ibs=1 skip=11 count=51

Merge du nouveau MBR :
cat top.bin > newmbr.bin
cat middle.bin >> newmbr.bin
cat bottom.bin >> newmbr.bin

Création de la nouvelle disquette bootable MS-DOS 6.22

Extraction du reste de la disquette :
dd if=floppy144.img of=floppy.with.no.mbr.bin ibs=1 skip=512
Concaténation du nouveau MBR et du reste de la disquette :
cat newmbr.bin > newfloppy.ima
cat floppy.with.no.mbr.bin >> newfloppy.ima

Il faut ensuite rajouter les fichiers IO.SYS, MSDOS.SYS et COMMAND.COM extraient précédemment :
Montage de la disquette :
mkdir floppymount
sudo mount -o loop newfloppy.ima floppymount
sudo cp MSDOS622/IO.SYS floppymount
sudo cp MSDOS622/MSDOS.SYS floppymount
sudo cp MSDOS622/COMMAND.COM floppymount
sudo umount floppymount

Ça y est la disquette est bootable.

Pour aller plus loin

Il est possible de désassembler le programme du MBR : en prenant le fichier mbr.bin extrait de SYS.COM et le désassemblant avec la commande :
objdump -D -b binary -mi386 -Maddr16,data1 mbr.bin
Nous pouvons voir que la première instructions est un jump vers 0x3e (début du programme) donc le bottom.bin, il est donc possible de le désassembler avec la commande :
objdump -D -b binary -mi386 -Maddr16,data1 bottom.bin
Attention, le bottom.bin contient aussi les messages d’erreur ainsi que les fichiers cherchés sur la disquette pour démarrer.

Ajouter une règle à l’extension HTTPS Everywhere pour Firefox

Il est possible de rajouter simplement une règle pour un site sur l’extension HTTPS Everywhere de Firefox en créant un fichier texte dans le répertoire .mozilla/firefox/xxx.default/HTTPSEverywhereUserRules.
Exemple pour le site zimbra.free.fr, le fichier créé se nomme zimbra.free.fr.xml :

<ruleset name="Zimbra.free.fr">
  <target host="zimbra.free.fr" />
  <rule from="^http://zimbra\.free\.fr/" to="https://zimbra.free.fr/"/>
</ruleset>

Western Digital Caviar Green et Timer d’idle

Le problème des disques Caviar Green est qu’ils se mettent en idle et parquent les têtes toutes les 8 secondes, ce qui peut entraîner une usure prématurée du disque dur.
Pour remédier à cela, il est possible de modifier le timer, il suffit de récupérer l’application idle3-tools

Il est ainsi possible de lire la valeur du timer avec la commande :
sudo ./idle3ctl -g105 /dev/sdb
Et de modifier la valeur :
sudo ./idle3ctl -s100 /dev/sdb

Utiliser ssh comme proxy pour firefox

Configuration de SSH

Sous linux

ssh -D 1080 esver@serveur.dedie

Sous Windows avec Putty

Putty Config Session

Putty Config Tunnel SSH

Configuration de Firefox

Configuration du proxy

Config Proxy Firefox

Configuration des DNS

Dans about:config, passer la valeur de network.proxy.socks_remote_dns à True