Close

Python on Beaglebone

A project log for Hacking a Supervisor Password - With a Beagle Bone

I found myself being intrigued with the low level safety features of my X201. I experimented with the I2C bus and it got interesting...

timo-birnscheinTimo Birnschein 02/14/2021 at 22:480 Comments

The only time I used Python in the past was an attempt to scrape data from web-shops websites to buy a graphics card when available check the weather. So my experience is extremely limited and I have to look up pretty much every single function or import or even if-statements when I wanted to use them for the first time. Python is great and powerful but if you are used to C++ it's a bit of a mystery.

I must emphasize that Adafruit has deprecated their libraries and none of them function at this point. It appears, Adafruit has abandoned the Beaglebone support completely as this information isn't even available on their website. Only old and very promising looking tutorials that are simply a waste of time to read!

For ease of use, I use cloud9 - Cloud9 as my Beaglebone (link only works if your Beaglebone has a fresh install and is connected to your PC via the Mini-USB cable). It looks like a full blown Python IDE and has all sorts of nice features like system shell, python shell, debugger and I'm sure a whole lotta other things I haven't used, yet. Even some basic type of code completion.

After successful tests on the console reading and writing to my I2C EEPROM, I wanted to recreate some of these functions in python to automate things. SMBus is the library of choice.

from smbus import SMBus
bus = SMBus(2) # select I2C bus 2, default pins are SCL:19; SDA: 20

 First, I wanted to read from the eeprom, so I wrote myself a little function

# Read consecutive bytes from the eeprom
def read_from_eeprom_8(bus, address, size=256):
    binary = [0] * size
    
    for i in range(int(size)):
        # To ensure we can actually read all 256 bytes from the EEPROM,
        # some memories like the 24RF08 require setting multiple page addresses.
        # The 24RF08 is organized in 128 byte pages that must be accessed individually
        # or the page will simply loop.
        # The 24C02 isn't. But it doesn't hurt to do it regardless.
        if i % 0x80 == 0:
            # print("setting new page at ", i)
            bus.write_byte(address, i) # write the new page address to the address counter
            sleep(0.01) # wait a bit to let the new address settle
            
        result = bus.read_byte(address)
        binary[i] = result
    return binary

The above function is extremely simple. When called, you have to provide the bus object, an address to read and the number of bytes you wish to extract from that device address beginning at 0x00. If the bus and address can be accessed, it will return a byte array then we can then work with.

I then wanted to write dump this to a file so I created another function

def write_binary_to_file(data, filename = "binary.bin", append = 0):
    if append == 0:
        print("\nWriting binary to file... ", filename)
    elif append == 1:
        print("Appending binary to file... ", filename)
    # Open file to dump the EEPROM data into
    if append == 0:
        file = open(filename, "wb")
    elif append == 1:
        file = open(filename, "ab")
        
    for i in data:
        file.write(i.to_bytes(1, 'big'))
    file.close()

This function takes the byte array, a file name, and whether you want to append the data to the file or rewrite the file. This is important if we have 8-bit addressed eeproms with multiple internal device addresses like the 24RF08.

Now, with that done, we can simply dump the entire eeprom of a Lenovo Thinkpad X201 Tablet using six lines of code (IF YOU DON'T HAVE AN OSCOLLOSCOPE ATTACHED TO YOUR I2C BUS AND YOU DON' T KNOW WHEN THE LAPTOP IS ACCESSING THE BUS, DO NOT DO THIS OR TURN THE LAPTOP OFF WITH THE POWER SUPPLY STILL ATTACHED. SUSPEND OR SLEEP WON'T CUT IT!!)

eepromDump = eeprom.read_from_eeprom_8(bus, 0x54, 256)
eeprom.write_binary_to_file(eepromDump, "eeprom.bin", 0)
eepromDump = eeprom.read_from_eeprom_8(bus, 0x55, 256)
eeprom.write_binary_to_file(eepromDump, "eeprom.bin", 1)
eepromDump = eeprom.read_from_eeprom_8(bus, 0x56, 256)
eeprom.write_binary_to_file(eepromDump, "eeprom.bin", 1)
eepromDump = eeprom.read_from_eeprom_8(bus, 0x57, 256)
eeprom.write_binary_to_file(eepromDump, "eeprom.bin", 1)

Here, I walk through the four addresses of the 24RF08 and write every byte to my binary file. Note, that the last three sections are appended to the original file as indicated by the trailing '1' instead of '0'. This is the full 1Kbyte of data or 8kbit (according to the 08 at the end of 24RF08). If you just plan on reading the 24C02, you can only read one device address and only get 256 bytes. Now, we have a complete EEPROM dump and can play with it.   

Discussions