Accueil / Attaques pratiques

Dump d'une EEPROM 24LC256

Cas pratique pas à pas — repérer, câbler et extraire le contenu d'une EEPROM I2C 24LC256.

Complet #eeprom#i2c#dump#arduino

Reconnaissance

La 24LC256 est une EEPROM de 256 kbit (32 Ko) communiquant en I2C. On la repère sur la carte à sa référence sérigraphiée et à son boîtier (souvent SOIC-8 ou DIP-8).

Mémoire EEPROM

Attaque

Dump du contenu

Le contenu d’une EEPROM peut être dumpé à l’aide d’un composant tiers (Arduino, Raspberry Pi, programmateur).

Avant de procéder, il est préférable de connaître l’adresse I2C utilisée par le device. À partir de la référence de l’EEPROM, on détermine également le câblage à effectuer. Pour une 24LC256 :

Schéma de brochage

Câblage (wiring)

WP correspond à Write Protection (protection en écriture) : si cette broche est reliée à GND, l’écriture sur l’EEPROM est possible. Dans le cadre d’une lecture, son état n’a pas d’incidence.

Les broches A0/A1/A2 permettent de faire varier l’adresse I2C de l’équipement si elles sont reliées à VCC. Il est ainsi possible de placer jusqu’à 8 EEPROM en parallèle sur le même bus : chaque broche portée à 1 modifie un bit d’adresse, soit 2³ = 8 adresses possibles (0x50 à 0x57).

BrocheConnexion
VCC5 V (ou 3,3 V selon la cible)
GND (VSS)GND
WPGND ou rien
A0 / A1 / A2GND ou rien (adresse 0x50)
SDABroche I2C SDA
SCLBroche I2C SCL

Alimentation

Vérifiez la tension d'alimentation attendue par la puce (5 V ou 3,3 V) et la présence de résistances de pull-up sur SDA/SCL. Beaucoup de cartes Arduino/Raspberry en fournissent, mais pas toujours.

Arduino

Croquis complet qui lit toute l’EEPROM par blocs et affiche le contenu en hexadécimal sur le port série :

#include <Wire.h>

#define EEPROM_ADDR 0x50   // Adresse I2C par défaut de la 24LC256
#define EEPROM_SIZE 32768  // Taille totale en octets (32 Ko)
#define CHUNK_SIZE 32      // Lecture par petits blocs (meilleures performances)

void setup() {
  Wire.begin();
  Serial.begin(9600);

  Serial.println("Dumping EEPROM data...");
  dumpEEPROM();
}

void loop() {
  // Rien à faire ici
}

// Dump complet de l'EEPROM
void dumpEEPROM() {
  uint8_t buffer[CHUNK_SIZE]; // Tampon temporaire
  for (uint16_t address = 0; address < EEPROM_SIZE; address += CHUNK_SIZE) {
    readFromEEPROM(address, buffer, CHUNK_SIZE);
    printBuffer(address, buffer, CHUNK_SIZE);
  }
  Serial.println("Dump complete!");
}

// Lecture d'un bloc depuis l'EEPROM
void readFromEEPROM(uint16_t address, uint8_t* buffer, size_t length) {
  Wire.beginTransmission(EEPROM_ADDR);
  Wire.write((address >> 8) & 0xFF); // Octet de poids fort de l'adresse mémoire
  Wire.write(address & 0xFF);        // Octet de poids faible
  Wire.endTransmission();

  Wire.requestFrom(EEPROM_ADDR, length);
  for (size_t i = 0; i < length; i++) {
    if (Wire.available()) {
      buffer[i] = Wire.read();
    }
  }
}

// Affichage lisible du tampon (adresse + octets hexadécimaux)
void printBuffer(uint16_t address, uint8_t* buffer, size_t length) {
  Serial.print("0x");
  Serial.print(address, HEX);
  Serial.print(": ");
  for (size_t i = 0; i < length; i++) {
    if (buffer[i] < 16) Serial.print("0"); // Zéro de tête pour les valeurs sur un chiffre
    Serial.print(buffer[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

On récupère ensuite la sortie du moniteur série et on reconstitue le fichier binaire à partir du dump hexadécimal (script Python, ou capture puis conversion).

Raspberry Pi (i2c-tools)

Sur une Raspberry Pi, avec l’EEPROM sur le bus I2C et i2c-tools installé :

# Vérifier la présence de la puce (adresse attendue : 0x50)
i2cdetect -y 1

# Lire octet par octet et rediriger vers un fichier (exemple simplifié)
# En pratique, on scripte l'incrément d'adresse sur 16 bits.
i2cget -y 1 0x50 0x00 b

Pour un dump propre, un petit script Python via smbus2 gère l’adressage 16 bits et écrit un dump.bin exploitable.

Raspberry Pi Pico

Le RP2040 possède deux contrôleurs I2C. En MicroPython :

from machine import I2C, Pin

i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=100000)

EEPROM = 0x50
SIZE = 32768
CHUNK = 32

with open("dump.bin", "wb") as f:
    for addr in range(0, SIZE, CHUNK):
        # Adresse mémoire sur 2 octets (16 bits)
        i2c.writeto(EEPROM, bytes([(addr >> 8) & 0xFF, addr & 0xFF]))
        data = i2c.readfrom(EEPROM, CHUNK)
        f.write(data)

print("Dump terminé")

Analyse du dump

Une fois le binaire récupéré, on l’inspecte comme un firmware : chaînes de caractères (strings), structures de configuration, éventuels secrets.

strings -n 6 dump.bin | less

Protections

  • Ne pas stocker de secrets en clair dans l’EEPROM (chiffrer les données sensibles).
  • Activer la protection en écriture (WP) quand la persistance n’est pas requise.
  • Vérifier l’intégrité des données côté firmware.
  • Restreindre l’accès physique à la carte.

Ressources