- Not known if vulnerable to laser glitching like 87C51FA
- Don't have a known fuse location like 8751H
- Not familiar with the XOR encryption scheme
So we procured some sample chips, this time literally marked SAMPLE.
Sample decapped
After a few masking tests, we discover the security fuses are in the location marked above. This makes the project interesting because its rather close to the EPROM. However, we are able to apply masks reasonably precisely, so didn't worry about this too much.
Here is the final mask on C055. Note that the mask was applied pretty heavily to try to minimize edge leakage.
00000000 ec e1 45 b3 09 23 a2 dc fd bf 76 65 8d 61 20 a3 |..E..#....ve.a .|
00000010 21 54 fc 76 da ef 54 32 44 da bc 30 54 33 35 61 |!T.v..T2D..0T35a|
00000020 12 32 45 83 f4 5d a2 dc fd bf 76 55 fa c8 12 9e |.2E..]....vU....|
00000030 51 de b3 b3 66 a0 a3 b8 2b e5 10 92 5b 8f 5a a9 |Q...f...+...[.Z.|
00000040 98 44 ab c4 87 7f 28 a9 13 35 01 16 fa d8 02 28 |.D....(..5.....(|
...
This yields the ROM above!
However, this is encrypted, so we now need to address cracking the XOR table. The basic idea is that there are 0x20 XOR encryption key bytes that are linearly applied, modulo the address. However, since the default key of 0xFF should not change the contents, the result is also inverted. This yields something like this:
for address, pt_byte in enumerate(plaintext):
encrypted[i] = pt_byte ^ key[address % len(key)] ^ 0xFF
Now with this in mind, note that the key cannot be read out, even if the chip is unprotected. Some options to deal with this:
- Reprogram the table and XOR out the key from the new ROM readout
- Guess the key
Guessing the key is probably not too hard as, for example, usually firmware starts with LJMP (0x02). More on this later.
We started by looking at reprogramming the XOR table as a direct extraction technique. Unfortunately, our primary programmer (BP Microsystems) doesn't allow directly programming the table. However, the commercial minipro software did:
We set the key to 0 which yielded this:
00000000 fe d3 00 fd fd 7e 00 00 00 00 00 fd fd fe cd 00 |.....~..........|
00000010 00 00 00 cd 00 00 00 00 00 00 00 cd 00 00 00 00 |................|
00000020 00 00 00 cd 00 00 00 00 00 00 00 cd 8a 57 ff 3d |.............W.=|
00000030 70 8a 4f 08 bc 4f f7 8a 6f 3f ac 6f 0f bc 6f c8 |p.O..O..o?.o..o.|
00000040 8a 76 ee 8a 73 22 8a 75 ee 8a 77 8e 8a 47 ef 8b |.v..s".u..w..G..|
Now XOR'ing the two dumps:
00000000 12 32 45 4e f4 5d a2 dc fd bf 76 98 70 9f ed a3 |.2EN.]....v.p...|
00000010 21 54 fc bb da ef 54 32 44 da bc fd 54 33 35 61 |!T....T2D...T35a|
00000020 12 32 45 4e f4 5d a2 dc fd bf 76 98 70 9f ed a3 |.2EN.]....v.p...|
00000030 21 54 fc bb da ef 54 32 44 da bc fd 54 33 35 61 |!T....T2D...T35a|
00000040 12 32 45 4e f4 5d a2 dc fd bf 76 98 70 9f ed a3 |.2EN.]....v.p...|
Which means the encryption key is:
00000000 12 32 45 4e f4 5d a2 dc fd bf 76 98 70 9f ed a3 |.2EN.]....v.p...|
00000010 21 54 fc bb da ef 54 32 44 da bc fd 54 33 35 61 |!T....T2D...T35a|
Applying the key now to the original dump:
00000000 01 2c ff 02 02 81 ff ff ff ff ff 02 02 01 32 ff |.,............2.|
00000010 ff ff ff 32 ff ff ff ff ff ff ff 32 ff ff ff ff |...2.......2....|
00000020 ff ff ff 32 ff ff ff ff ff ff ff 32 75 a8 00 c2 |...2.......2u...|
00000030 8f 75 b0 f7 43 b0 08 75 90 c0 53 90 f0 43 90 37 |.u..C..u..S..C.7|
00000040 75 89 11 75 8c dd 75 8a 11 75 88 71 75 b8 10 74 |u..u..u..u.qu..t|
However, this is suspicious. Usually the first mcs51 instruction is 0x02 (LJMP). However, popping into Ghidra:
Aha! They've just used AJMP instead of LJMP. Additionally we see clean disassembly and familiar register initialization. We have a dump!
Finally, what if we tried guessing the key? Well, we probably undersold just how bad this scheme is. One major flaw is that often people don't use the entire chip and its partly left unprogrammed (ie 0xFF filled). Here's the end of the encrypted dump:
00000fa0 ae cd bc bd f5 82 66 23 04 4c 77 47 ba 60 14 50 |......f#.LwG.`.P|
00000fb0 20 8b 2c 44 23 1c 55 cd bb 25 43 02 ab cc ca 9e | .,D#.U..%C.....|
00000fc0 ed cd ba b1 0b a2 5d 23 02 40 89 67 8f 60 12 5c |......]#.@.g.`.\|
00000fd0 de ab 03 44 25 10 ab cd bb 25 43 02 ab cc ca 9e |...D%....%C.....|
00000fe0 ed cd ba b1 0b a2 5d 23 02 40 89 67 8f 60 12 5c |......]#.@.g.`.\|
00000ff0 de ab 03 44 25 10 ab cd bb 25 43 02 ab cc ca 9e |...D%....%C.....|
Where near the end we clearly see a pattern repeated every 0x20 bytes, the telltale sign of filling with 0xFF. So yeah...pretty weak encryption as this is simply inverted to extract the key.
We also recently received a bunch more chips, including a number of 87C5X. So hopefully there will be a follow up soon.
Enjoy this post? Please support us on Patreon! Note: with the Indiegogo campaign over we unfortunately don't currently have a way to accept one time donations.