This document contains notes about the reverse engineering efforts against the firmware of the ET-312B Electrostimulation Device, including what is currently known about the firmware, and different attack vectors. The goal is to provide an unencrypted version of the ET-312B firmware that can be modified and upgraded.
This will hopefully be updated as progress continues, mainly so I don’t have to repeat myself over IRC/Twitter/Telegram/Etc.
There’s also a good chance we’re missing something obvious, so if you see something here we’ve missed, please file a github issue and let us know!
For those that are just curious what we’re up to and what we’re running into:
We want an unencrypted version of the firmware for the ET-312B, which has an ATMega16 in it.
We have:
- An ET-312B Box
- 2 Firmware upgrade files for the box, available here
These files are somehow obfuscated or encrypted, and the bootloader on the ATMega16 undoes that encryption when we upload the firmware to the chip. Due to fuses being set on the chip, we can’t access the flash or bootloader through JTAG or other hardware debugging methods. Due to the chip being a harvard architecture, we can’t screw with the stack and inject instructions ‘cause we don’t have access to code space. While we know that the flash will contain AVR assembly, strings, etc, we aren’t sure what order the upgrade file is in, or where those things might be in it.
The ET-312B runs on an ATMega16A chip. There is no external RAM/EEPROM/etc, everything exists in memory on the chip.
All fuses are set on the chip, locking out JTAG access or the ability to read out the flash or bootloader.
Two versions of the firmware, for v1.5 and v1.6, are available via the firmware upgrade website:
http://blog.erostek.com/2012/08/27/et-312-firmware-upgrade-1/
These files (312-15.upg and 312-16.upg), are also available in the Erosoutsider Repo.
Some assumptions about the upgrade files:
- Neither file is a plaintext flash image. They’ve been at least obfuscated, if not fully encrypted, and possibly rearranged. Since we don’t have access to the bootloader code, there’s no telling what they could be. We just know that somewhere in here is the code to run the ET312.
- Both firmware files are 15872 bytes, which is 16384 - 512. Since the bootloader takes up 512 bytes of the Flash, there’s a good chance the upgrade files could just be images of the rest of the flash.
- It is assumed that these files are encrypted via some sort of stream cipher, mainly due to the patterns that emerge when comparing them (see below). The serial protocol used a simple XOR cipher (more information on this is available in the serial protocol documentation), so there’s a chance this could be similarly simple.
To upgrade the firmware on the box, the upgrade file is simply transferred via the XMODEM protocol. Full instructions for upgrading are listed in the Reference section of this document.
Use either hardware debuggers or screwing with the stack in RAM to get at the flash
No luck here.
JTAG or hardware debugging in general is dead from the start despite there being a JTAG header on the board, due to the fuses being set.
Screwing with the stack doesn’t do use much good because this is a harvard architecture chip, so we can’t really inject instructions in a useful manner since all of the code sits in another address space anyways. The best we might be able to do is play with return addresses to figure out where things are in flash and try to match that to the upgrade file in order to produce plaintext.
The basics of the Serial Protocol is already reverse engineered. It provides a peek/poke interface on top of a weird virtual memory like system, able to access parts of the ROM, RAM, and EEPROM.
More information on the serial protocol is available at
https://github.com/metafetish/erosoutsider/wiki/Serial-Protocol
This is probably the best vector for retrieving the firmware. The RAM address space contains all of the processor registers, IO registers, and the stack. All of those areas are writable, giving us a lot of freedom in what we can do.
For instance, using the erosoutsider-py library, we can run the following code (eo refers to an ErosOutsider object):
e = ErosOutsiderSerial("/dev/ttyUSB0")
e.perform_handshake()
eo.write_sync(0x4014, 0x09)
eo.write_sync(0x4015, 0x04)
eo.write_sync(0x4016, 0x03)
eo.write_sync(0x4017, 0x24)
This block overwrites r14-r17, causing the box to error and display a “Shut Down Power!!” message on the LCD screen. If we then hit the “Up” button, we are taken to the mode menu, but the string offset is wrong, so instead of showing the mode name, we get random parts of other strings.
Assuming the “Up” button is pressed enough times, we start getting gibberish on the LCD screen, meaning we’ve jumped over the string boundaries and are in program space.
The CPU is most likely talking I2C or SPI to the LCD controller board, so assuming we can come up with a script that can glitch this correctly and play with the string offset, we could use a logic analyzer to dump the firmware via the LCD, and reassemble it on the host machine.
Interesting facts from playing with memory using the protocol:
- Reading from the EEPROM, there’s strings stored in 8 byte chunks, with spaces around them to buffer up to 8 characters if they aren’t already, and no null terminators. This may be a common way to storing strings in the system, as for instance the pattern mode names are all <=8 characters.
Armed with a spec sheet, knowledge of AVR assembly and binary tools, pick at the upgrade files until either something makes sense or the heat death of the universe consumes us all.
While entropy tests run against the files using the Dieharder Test Suite show that the files themselves are fairly random, comparing the files to each other shows some patterns. For instance, here is the first 256 bytes of each file:
312-15.upg
00000000: ed78 3723 9920 5637 af04 4e2b 4e73 9382 .x7#. V7..N+Ns.. 00000010: 2984 f9ec 0ba5 a382 e9ad 4828 c45f 25e2 ).........H(._%. 00000020: d0f1 4359 35a3 f574 24e2 4b1c 6d1b b5e6 ..CY5..t$.K.m... 00000030: 53cc 5e99 d249 e453 c6b6 984d fc1e f530 S.^..I.S...M...0 00000040: ffe2 4f81 6d1f 75e4 57c0 5c95 124b e85f ..O.m.u.W.\..K._ 00000050: c4ba 984d bc39 6669 4774 deba 5b2a 6428 ...M.9fiGt..[*d( 00000060: 62d1 acab 92d2 1dbe 4d51 3132 00e0 a335 b.......MQ12...5 00000070: 81e0 a729 6ba3 b669 7dec 496e 903a 0129 ...)k..i}.In.:.) 00000080: c36b 46d3 08ba f630 f5b5 d899 9085 7d46 .kF....0......}F 00000090: c506 6a6c 12c7 0ac6 e14f 7fad 92de 86bf ..jl.....O...... 000000a0: 99bc d2df 10c5 9118 1888 b1da 64a6 36f0 ............d.6. 000000b0: 0509 2947 4f93 31cb 1895 6f31 360c df11 ..)GO.1...o16... 000000c0: 4869 33ee eabf 080a 143a dc99 5f79 0aef Hi3......:.._y.. 000000d0: 791d 2523 3c4c 96cf 2fb4 551f af73 fa7d y.%#<L../.U..s.} 000000e0: 5395 0736 7734 1f92 846c cc8b 697e 2c43 S..6w4...l..i~,C 000000f0: 02ad 65ef aff1 f32b 71a3 2c58 4286 24a1 ..e....+q.,XB.$.
312-16.upg
00000000: ed78 5f23 9948 5637 c704 4e43 4e73 9382 .x_#.HV7..NCNs.. 00000010: 2984 11ec 0bfd 2582 31c5 4870 425f ed8a ).....%.1.HpB_.. 00000020: d0b9 4359 eda3 f52c 24e2 961c 6d44 d4e6 ..CY...,$...mD.. 00000030: 8eda 36c2 b321 d145 aebd f925 f108 f53f ..6..!.E...%...? 00000040: 9ee2 aa97 6d78 92e4 b2be 34fe f523 e521 ....mx....4..#.! 00000050: acb1 f925 b12f 0e62 261c d7ac 335d 0540 ...%./.b&...3].@ 00000060: 97c7 d4dc f3aa 14a8 055e 507a 09f6 eb32 .........^Pz...2 00000070: e0a8 a23f 23a4 d721 44fa 0151 f172 383f ...?#..!D..Q.r8? 00000080: 8b50 279b 2dac be17 94fd f98f d8aa 1c0e .P'.-........... 00000090: e410 224f 738f 2bd0 a96c 1ee5 b3c8 ce9c .."Os.+..l...... 000000a0: f8f4 f3c9 58ea f050 319e f9ed 05ee 03e6 ....X..P1....... 000000b0: 4d3a 480f 7e85 79f8 79dd 5e27 7e3f be59 M:H.~.y.y.^'~?.Y 000000c0: 757f 7bcd 8bf7 251c 5c11 bdd1 766f 42c4 u.{...%.\...voB. 000000d0: 1855 0035 746b f787 0aa2 1d38 ce3b df6b .U.5tk.....8.;.k 000000e0: 1bbe 667e 5e22 57b5 e524 e59d 2151 4d0b ..f~^"W..$..!QM. 000000f0: 2fbb 2dc0 ceb9 de3d 398c 4d10 6f90 6c8a /.-....=9.M.o.l.
However, XORing the two files together, interesting patterns emerge:
00000000: 0000 6800 0068 0000 6800 0068 0000 0000 ..h..h..h..h.... 00000010: 0000 e800 0058 8600 d868 0058 8600 c868 .....X...h.X...h 00000020: 0048 0000 d800 0058 0000 dd00 005f 6100 .H.....X....._a. 00000030: dd16 685b 6168 3516 680b 6168 0d16 000f ..h[ah5.h.ah.... 00000040: 6100 e516 0067 e700 e57e 686b e768 0d7e a....g...~hk.h.~ 00000050: 680b 6168 0d16 680b 6168 0916 6877 6168 h.ah..h.ah..hwah 00000060: f516 7877 6178 0916 480f 6148 0916 4807 ..xwax..H.aH..H. 00000070: 6148 0516 4807 6148 3916 483f 6148 3916 aH..H.aH9.H?aH9. 00000080: 483b 6148 2516 4827 6148 2116 482f 6148 H;aH%.H'aH!.H/aH 00000090: 2116 4823 6148 2116 4823 6148 2116 4823 !.H#aH!.H#aH!.H# 000000a0: 6148 2116 482f 6148 2916 4837 6148 3516 aH!.H/aH).H7aH5. 000000b0: 4833 6148 3116 4833 6148 3116 4833 6148 H3aH1.H3aH1.H3aH 000000c0: 3d16 4823 6148 2d16 482b 6148 2916 482b =.H#aH-.H+aH).H+ 000000d0: 6148 2516 4827 6148 2516 4827 6148 2516 aH%.H'aH%.H'aH%. 000000e0: 482b 6148 2916 4827 6148 2916 482f 6148 H+aH).H'aH).H/aH 000000f0: 2d16 482f 6148 2d16 482f 6148 2d16 482b -.H/aH-.H/aH-.H+
If we format the XOR output into blocks of 6 bytes each, some repetition starts to show up:
6800 0068 0000 0000 6800 0068 0000 0000 0000 e800 0058 8600 d868 0058 8600 c868 0048 0000 d800 0058 0000 dd00 005f 6100 dd16 685b 6168 3516 680b 6168 0d16 000f 6100 e516 0067 e700 e57e 686b e768 0d7e 680b 6168 0d16 680b 6168 0916 6877 6168 f516 7877 6178 0916 480f 6148 0916 4807 6148 0516 4807 6148 3916 483f 6148 3916 483b 6148 2516 4827 6148 2116 482f 6148 2116 4823 6148 2116 4823 6148 2116 4823 6148 2116 482f 6148 2916 4837 6148 3516 4833 6148 3116 4833 6148 3116 4833 6148 3d16 4823 6148 2d16 482b 6148 2916 482b 6148 2516 4827 6148 2516 4827 6148 2516 482b 6148 2916 4827 6148 2916 482f 6148 2d16 482f 6148 2d16 482f 6148 2d16 482b 6148
There are also blocks of the XOR’d files where things turn to randomess:
000010a0: 6446 ee64 c6ee 6442 ee64 c2ee 644e ee64 dF.d..dB.d..dN.d 000010b0: ceee 644e ee64 c2ee 6442 ee64 c2ee 6442 ..dN.d..dB.d..dB 000010c0: ee64 c2ee 644e ee64 c2ee 6442 ee64 c6ee .d..dN.d..dB.d.. 000010d0: 6442 ee64 ceee 644e ee64 f2ee 6472 ee64 dB.d..dN.d..dr.d 000010e0: f2ee 6472 ee64 f2ee 6472 fe15 0f24 7d47 ..dr.d..dr...$}G 000010f0: cf93 990e 94b2 90b7 5f7b cf4c 60fd 3f0a ........_{.L`.?. 00001100: 9708 7021 4b21 535c 0431 2663 7125 53b1 ..p!K!S\.1&cq%S. 00001110: fc23 e831 4d54 3188 5b1b 2a99 01d9 aa27 .#.1MT1.[.*....' 00001120: 5dd2 5395 df5b 52fc e545 6462 7a6e a191 ].S..[R..Edbzn.. 00001130: 67ec 6883 c796 9443 d004 35a0 1459 db38 g.h....C..5..Y.8 00001140: 4e17 3cc9 7139 d387 4533 47d1 ce81 5540 N.<.q9..E3G...U@ 00001150: f0c6 4551 4bea e24b 1647 cf42 8c70 dd8a ..EQK..K.G.B.p..
Though the patterns start up against a bit later:
00001c20: bb19 bf61 04b5 2dc0 e83f e9fe e7da ff6e ...a..-..?.....n 00001c30: 78ad 30e6 f7c1 1231 d5ad a7ca 8358 4e38 x.0....1.....XN8 00001c40: 58c2 8358 4238 58c2 8358 5e38 58de 8358 X..XB8X..X^8X..X 00001c50: 5e38 58a2 8358 a638 58ba 8358 be38 58b2 ^8X..X.8X..X.8X. 00001c60: 8358 f3c7 a704 8358 65c7 a796 8358 97c7 .X.....Xe....X.. 00001c70: 5891 7c58 97c7 5899 7c58 9bc7 5899 7c58 X.|X..X.|X..X.|X
And then back to randomness a little later, until the end of the XOR file:
000021a0: 7f7e 0ef7 7e0e 7f7e 0ef7 7e12 7f7e 1ef7 .~..~..~..~..~.. 000021b0: 7e1e 7f7e 1ef7 7e1e 7f7e 1af7 7e1a 7f7e ~..~..~..~..~..~ 000021c0: 1af7 7e16 7f7e 2af7 7ad3 6dab 66d7 bb50 ..~..~*.z.m.f..P 000021d0: 0b0d 2746 c850 2e5c a52b bed2 ee31 fb33 ..'F.P.\.+...1.3 000021e0: 15e6 f6c8 d8b3 3bc4 54d9 cb38 b2d7 a9f3 ......;.T..8.... 000021f0: a8d4 4496 6ef7 7217 9c25 b590 3a92 1a76 ..D.n.r..%..:..v
It’s doubtful that the actual firmware is 100% valid data, so there’s a good chance that whatever utility was used to build the upgrade file might just be filling it with randomness.
There’s also assumptions that could be made about the order of the firmware. For instance, usually the AVR IVT is at the top of the flash address space, so there’s a chance that the matching portions of the first sections of the 2 files are the IVTs, which probably don’t change much. However, this idea hasn’t gotten very far in practice.
More a mapping technique than an attack, but by changing every Nth byte by a known value, we may be able to map parts of the upgrade file as we see strings change in the UI on the box.
For instance, we can increase every 10th byte in a block of the firmware by a value of 1. Assuming the firmware runs, we can watch for misspelled/changed strings around the box UI.
This is still perilous at best. Flash only has a certain number of guaranteed writes (yes it’s in the 1000s but let’s assume we’re really bad at this and also the fact that…), and we’ve only got 1 box, so if that chip gets ruined before we figure this out, we have a problem (and no warranty).
The last 13 bytes of the firmware can be set to any value, and the box will still boot. Changing any other values will cause the box to boot directly into firmware upgrade mode, meaning there’s probably a CRC check in the bootloader that’s checking the integrity of the bits and not jumping if it finds an error.
Complete guess, but it’s probably a CRC-16 that’s the last 2 bytes. However, if those bytes are also encrypted, we’re out of luck for changing much.
From step 12 of the “Upgrade Instructions” in the References section:
- Click Send and the file transfer should begin. The Ch A and Ch B lights will flash randomly as the data is transferred to the ET-312. DO NOT interrupt this process in any way.
Nothing ever happens randomly.
Mapped LED A to be controlled by Pin 20 of the ATMega16, attached to a logic analyzer. During firmware upload, there’s a signal that happens on this pin between packet upload and ACK response in the XMODEM protocol. The signal is repeatable between uploads. Further analysis required, but doubtful this is going anywhere.
The fuuuuuuuuuuuuuuuuuture! While now feasible with projects like ChipWhisperer, not sure if it’s all that applicable here.
That said, if we could write one XMODEM packet then possibly see what’s happening in the chip that way? Sure. But it’s magic to us at the moment.
No real direction with this, require advice of grown up and/or magic person.
Ship the chip and $800 or so somewhere and have them pop the top off and do magic to it.
What fun is that? :(
Put on a nice outfit. Knock politely on the front door.
What fun is that? :(
This is a copy of the text from the Eroslink ET-312 Upgrade Instructions PDF, available at
http://media.erostek.com.s3.amazonaws.com/support/312-16_firmware_upgrade.pdf
Firmware Upgrade Instructions: ET-312 Version 1.6
- Connect the ErosLink cable to an unused Serial port on your PC.
- With the ET-312 off, connect the ErosLink cable to the Link jack of the ET-312.
- Go to the Start, Programs, Accessories, menu in Windows and find Hyperterminal. It may be under Communications depending on which version of windows you have.
- When Hyperterminal starts, wait for the welcome screen to go away and then enter any name in the New Connection box such as “ET312” and click OK.
- In the Connect To box, select the serial port used in Step 1 from the Connect Using pull down menu. This will usually be COM1 - COM4. Then click OK.
- In the Properties box, select the following options: Bits per second=19200, Data bits=8, Parity=None, Stop bits=1, Flow control=None and click OK.
- Hold down the Menu and Up buttons on the ET-312 at the same time, then turn on the ET-312 while keeping them held down. The display should be blank and the Ch A and Ch B LEDs should blink slowly. If the ET-312 powers up normally, you did not hold down the buttons correctly as try again.
- In Hyperterminal you should see a string of “C” characters appear at about 1 per second. If you don’t see anything or you see different characters, Hyperterminal is not configured correctly or there is a problem with the serial port. Shut down Hyperterminal and try again selecting other available COM ports and make sure the properties in Step 6 are correct.
- When you see the string of “C” characters in Hyperterminal, select the Transfer menu and Send file. If you wait too long, you’ll have to power the ET-312 off and try again (the LEDs will stop blinking).
- In the Send File box, make sure you select Xmodem as the protocol (NOT Zmodem or 1k Xmodem).
- After Xmodem is selected, enter or Browse to the filename of the new firmware. For example, the version 1.6 upgrade file is called “312-16.upg”.
- Click Send and the file transfer should begin. The Ch A and Ch B lights will flash randomly as the data is transferred to the ET-312. DO NOT interrupt this process in any way.
- When the transfer is completed, the ET-312 will power up normally and the display should show the new version of the software. If anything goes wrong, try again starting over from Step 1. If you still can’t make it work, contact ErosTek or SexTek for further assistance.
- Once the transfer is complete, you can turn the ET-312 off, unplug the cable, and close Hyperterminal (you do not need to save the Hyperterminal session).
Link to Serial Protocol Documentation
This is a partial list of strings found just playing around with the UI. Yes, we realize this makes us the human version of the “strings” utility.
UI Strings:
- Eros Tek ET312-B
- SelfTest OK v1.6
- (c) ‘04 Eros Tek
- Press Any Key…
- Ramp:
- Battery:
- Selects Mode
(There’s way more of these, will enter more later)
Mode Names, in order of appearance while pressing “up” button:
- Waves
- Stroke
- Climb
- Combo
- Intense
- Rhythm
- Audio 1
- Audio 2
- Audio 3
- Split
- Random1
- Random2
- Toggle
- Orgasm
- Torment
- Phase 1
- Phase 2
- Phase 3