philpem boosted

Does anyone have a tutorial for reverse-engineering real-mode 80x86 ROM code (e.g. BIOSes) with IDA or Ghidra? I'm trying to R/E a Chips&Tech BIOS and a Polaroid Palette ROM (80386 and 80186 respectively). My main issue is loading the binary and setting up the segments.

philpem boosted


This bullshit about the right whining about LoTT being censored and not simply kicked off like she clearly should have been according to their ToS is basically more evidence that appeasing Nazis is ALWAYS the bad choice. They bent over backwards to try to accommodate letting fascists continue operating in blatant violation of their rules while doing little sneaky stuff on the back end to gaslight mainstream liberals into believing it wasn't THAT bad on right wing Twitter (while trans Twitter continues to scream into the void).

Instead, they got bought by a right wing billionaire who then exposed their sneaky appeasement, and now both the left AND the right hate them for being spineless slimy assholes with no conviction to uphold their own fucking policies.

If you don't want to be a Nazi Bar, KICK THE NAZIS OUT! Don't just give them a table in the back room where other patrons won't have to notice them. Eventually there's going to be a whole lot more of them and they're going to want the whole damn bar.

philpem boosted

Guess who's back!

Following our successful launch of the Fediverse™ campaign, we decided to release a new collection of peripherals for our #raspberrypi -- meet The Raspberry Spy! New technological possibilities and unlimited space for creativity*!

* We're not too sure ourselves what it actually does - but surely if it was created by a former surveillance officer, then it can do something interesting.

Image courtesy @selfagency

philpem boosted

The people going on strike at the moment are not enemies of the general public.

They are the general public, and they deserve to be paid enough to heat their homes as well as to put food on the table.

philpem boosted

@vampiress @danmac I wrote some useful utility for DOS in 1997 and distributed it via bulletin board. It was TeaspoonWare, which I made up. The license said if you like this please mail me a teaspoon because I lose them and mum gets mad. Every so often, we’d get a teaspoon in the mail without explanation. Drove mum insane.

philpem boosted

On Twitter it took us almost 5 years to reach to 50,000 followers.

Here at Mastodon we may be able to do it within one month.

Support our mission & amplify our voice.

#follow #Auschwitz #memory #museums #memory #history #fediverse #mastodon

philpem boosted

The fact that right wing reactionaries and fascists have taken language that was created by scholars of child and interpersonal abuse to describe ACTUAL tactics that abusers use to obtain control and then perpetrate sexual abuse (e.g., "grooming," and "groomers") and applied it to queer and trans people who are... just existing... just *talking about existing*... it makes me feel like I am living in a hall of mirrors that are also stabbing me. These people are truly despicable.

Show thread
philpem boosted

Trans people just want to fucking live. You know what I'm saying? We want to have a safe home, we want to eat in a restaurant on occasion, we want to hang out with friends, we want to fall in love and be loved back. We want to have fun and dress up sometimes and stay at home on our couches sometimes and have a life that is fulfilling and in which we aren't constantly in fear of murder or harassment. This is not new and it's not radical and it's not harming you or anyone else to ask for it.

philpem boosted

This one is kind of a big deal. The game has never been cracked, it was last imaged in the mid 1990's, and that image is nonfunctional because it didn't fully capture the disk's protection. It is also exceedingly rare; the Mac port did not sell well, and the game did not work on any Macs beyond the Mac Plus. It last showed up on eBay a decade ago. When it showed up earlier this year, a group of like-minded archivists pooled donations and were able to win the auction and preserve it properly.

Show thread
philpem boosted
philpem boosted

#dealingWithStrangers lesson 5:

Next time a stranger talks to you, look startled, and say “you can SEE me?!”

Show thread
philpem boosted

One of the best random bits of advice I've ever received: if the sun has gone down and everything seems / feels like shit, just go to bed.

Put it all down, get some food in you if you haven't already, and go the fuck to sleep.

Your brain isn't good at perspective when the light is dim, and it barely even matters how much of a night owl you are.

philpem boosted

In an unexpected turn, we've found ourselves blocking the official #RaspberryPi instance today, basically until they put an adult in charge of it.

If anyone really wants to learn how a relatively beloved and respected brand can burn a staggering amount of good will in record time, @aurynn has written up a very good case study of the event:

philpem boosted
philpem boosted
philpem boosted

long, research, reversing, raspberry pi, disassembler, undocumented microcontroller, figuring out an unknown instruction set 

So here's some interesting #RaspberryPi related #ReverseEngineering research.

Did you know that there's another undocumented microcontroller core in the BCM2708 SoC and its derivates?

Around 2019 or so, I found this set of slides :

The really fun stuff was redacted (I can only assume how they were convinced to remove the stuff related to keygenning the codec licensing :thinking: ), but that didn't matter. With some hardware experimentation, I figured out the majority of the remaining instruction set and coded a disassembler for the Broadcom Video Control Engine (VCE).

I never did figure out the entire instruction set, but hopefully others can build upon my research.

Yes, I coded a disassembler in PHP, it's something all Real Programmers should do, highly recommend.


// thanks synacktiv :)
// todo: figure out the full instruction set, eventually

$opTbl = [
0b000000 => 'end',
0b000001 => 'xor',
0b000010 => 'sendc', // set end code?
0b000011 => 'dmarun', // start dma? dmarun blank,blank,1 used in prerun/postrun
// 0b000100 => 'UNK', // rD not touched.
// 0b000101 => 'UNK', // rD not touched.
// 0b000110 => 'UNK', // rD not touched.
// 0b000111 => 'UNK', // rD not touched.
// load: op[0] = *(TYPE*)(op[1])
0b001000 => 'ldb',
0b001001 => 'ldw',
0b001010 => 'ldd',
0b001011 => 'ver', // << output reg gets 0x68323634 'h264'
// store: *(TYPE*)(op[0]) = op[2];
0b001100 => 'stb',
0b001101 => 'stw',
0b001110 => 'std',
// 0b001111 => 'UNK', // << unsure what this does. used by h264_code
0b010000 => 'dmafr', // set main memory addr to dma FROM? dmaf r1, <reg>, 0 used by prerun -- dest always at 0 of vce code/data?
0b010001 => 'dmato', // set main memory addr to dma TO? dmato r1, <reg>, 0 used by postrun; src always at 0?
0b010010 => 'dmatdl', // set length of copy to dma to DATA? mov r6, <len>;mov r7,0;dmadl r1, r7, 0 used by prerun
0b010011 => 'dmafdl', // set length of copy to dma from DATA?
// 0b010100 => 'UNK', // op[0] = (op[1] << op[2]) with maybe some additional bits set in low4
// 0b010101 => 'UNK', // op[0] = op[1] unk op[2], something bitwise? shl-related?
// 0b010110 => 'UNK', // rD not touched.
// 0b010111 => 'UNK', // rD not touched.
0b011000 => 'zero', // op[0] = 0
0b011001 => 'zero', // op[0] = 0
// 0b011010 => 'UNK', // rD not touched.
0b011011 => 'dmacl', // set length of copy to dma to CODE? mov r6, <len>;mov r7,0;dmacl r1, r7, 0 used by prerun
0b011100 => 'j',
0b011101 => 'ldiw', // << op[0] = *(u16*)(op[2]), if not aligned does the same thing as mem-operand
// 0b011110 => 'UNK', // << rD not touched.
// 0b011111 => 'UNK', // << rD not touched.
0b100000 => 'shl', // op[0]=op[1]<<op[2]
0b100001 => 'rshl', // op[0]=op[2]<<op[1]
0b100010 => 'shr',
0b100011 => 'mov', // << op[0]=op[1]
0b100100 => 'shr',
0b100101 => 'movi', // op[0] = op[2]
0b100110 => 'ror', // op[0] = op[1] ror op[2]
0b100111 => 'movi',
0b101000 => 'mulu', // op[0] = op[1] * op[2], all unsigned, 24-bit output?
// 0b101001 => 'UNK', // op[0] = op[1] <UNK> op[2], something bitwise?
0b101010 => 'muls', // op[0] = op[1] * op[2], all signed, 24-bit output?
// 0b101011 => 'UNK', // op[0] = op[1] <UNK> op[2], something bitwise?
0b101100 => 'add',
0b101101 => 'sub',
0b101110 => 'ldid', // op[0] = *(u32*)(op[2] & ~3)
0b101111 => 'rsub', // << op[0]=op[2]-op[1]
0b110000 => 'sub1', // op[0] = op[1] - 1 - op[2]
0b110001 => 'and',
0b110010 => 'bic', // op[0] = op[1] & ~op[2]
0b110011 => 'xorlim', // op[0] = (op[1] ^ op[2]) & mask(bnh(op[2]))
0b110100 => 'or', // op[0] = op[1] | op[2]
0b110101 => 'xor',
// 0b110110 => 'UNK', // op[0] = op[1] <UNK> op[2], some bitwise operation...
// 0b110111 => 'UNK', // op[0] = op[2] << unk(op[1])
0b111000 => 'signext', // op[0] = sign_extend(op[1] & mask(op[2]))
0b111001 => 'movi', // op[0] = op[2]
0b111010 => 'mov',
0b111011 => 'bnh', // op[0] = number of highest bit set in op[1], so bnh(0xffffffff)=31, bnh(0x7fffffff)=30 etc.
0b111100 => 'cmp',
// 0b111101 => 'UNK', // cmp variant? seen used before conditional instrs
// 0b111110 => 'UNK',
// 0b111111 => 'UNK'

$condTbl = [
0b00 => '',
// 0b01 =>
0b10 => 'eq',
0b11 => 'ne',

function registerParse($reg) {
if ($reg == 0) return 'last';
if ($reg == 63) return 'blank';
return sprintf('r%d', $reg);

function operandParse($imm) {
if (($imm >> 7) == 0b01101) {
// reg?
$reg = ($imm >> 3) & 0b1111;
return registerParse($reg);
if (($imm & 0x800) == 0x800) {
// (u32) data
return sprintf('(0x%x)', $imm & 0x7ff);
if ($imm > 32) return sprintf('0x%x', $imm);
return sprintf('%d', $imm);

function opCodeAsText($opcode) {
global $opTbl, $condTbl;
$ret = '';
if (in_array($opcode >> 2, array_keys($opTbl))) $ret = $opTbl[$opcode >> 2];
else {
$opBin = decbin($opcode >> 2);
if (strlen($opBin) < 6) $opBin = str_repeat('0',6 - strlen($opBin)) . $opBin;
$ret = 'unk_0b' . $opBin;
$cond = $opcode & 0b11;
if (in_array($cond, array_keys($condTbl))) $condTxt = $condTbl[$cond];
else {
$condBin = decbin($cond);
if (strlen($condBin) < 2) $condBin = str_repeat('0', 2 - strlen($condBin)) . $condBin;
$condTxt = 'unk_0b' . $condBin;
if ($condTxt != "") $ret .= '.' . $condTxt;
return $ret;

function unpackOp($op) {
// bits:
// 0-11: immediate
// 12-17: register operand 2
// 18-23: register operand 1
// 24-31: opcode
return (object) [
'opcode' => ( ($op >> 24) & 0b11111111 ),
'reg1' => ( ($op >> 18) & 0b111111 ),
'reg2' => ( ($op >> 12) & 0b111111 ),
'imm' => ( $op & 0b111111111111 ),
'imm_ex' => ( $op & 0b111111111111111111 )

function dis($bytes) {
$arr = unpack('V*', $bytes);
$off = 0;
foreach ($arr as $u32) {
$op = unpackOp($u32);
$reg1 = registerParse($op->reg1);
if ($reg1 != "") $reg1 .= ', ';
$reg2 = registerParse($op->reg2);
if ($reg2 != "") $reg2 .= ', ';
$operands = trim(sprintf("%s%s%s", $reg1, $reg2, operandParse($op->imm)), ",");
printf("%08x : %08x : %s %s\n",$off,$u32,opCodeAsText($op->opcode),$operands);

if ($argc == 0) die();

dis( file_get_contents( $argv[1] ) );
philpem boosted

(please boost to send this supposed "secret" across the fediverse) long, code. <=rpi3 codec licensing algorithm. replace the trigraphs (change ??= to # ) if your compiler doesn't like them. 

// #RaspberryPi codec licensing serial algo (<=RPi3)
// shoutouts to fabien perigaud/synacktiv. your beerump 2017 presentation slides started me on this journey.
// (sure you redacted the fun stuff, I just rediscovered it myself)
// also shoutouts to everyone involved in BCM2708 reversing!
// greetings to elites, fuckings to lamers (second category includes broadcom and rpi foundation)

??=include <stdint.h>
??=include <stdio.h>

typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;

u8 vce_data[] = {
0x54, 0x6f, 0x76, 0x6b, 0x94, 0xce, 0x1a, 0x57, 0x56, 0x51, 0x0c, 0xb2, 0x72, 0xc9, 0xc3, 0x12,
0x13, 0xbc, 0xe8, 0xd2, 0x5b, 0xa3, 0x2d, 0x2a, 0x5a, 0x62, 0x4d, 0xeb, 0x16, 0x40, 0x05, 0x87,
0xe0, 0x98, 0x39, 0xf7, 0xac, 0xc6, 0xab, 0x7c, 0xe9, 0xfb, 0x07, 0xaa, 0x29, 0xcd, 0x1d, 0x9b,
0xf6, 0x0e, 0x01, 0xbb, 0x5c, 0xfc, 0x15, 0xae, 0xd9, 0xfa, 0x9c, 0xef, 0xf1, 0x75, 0x8e, 0x70,
0x46, 0x8b, 0xb0, 0x89, 0x50, 0xaf, 0x6e, 0x67, 0x18, 0xda, 0xee, 0xd4, 0x32, 0xbe, 0x4e, 0x58,
0x5d, 0x1f, 0x4b, 0x73, 0x88, 0xc0, 0x79, 0x02, 0xde, 0x47, 0xa0, 0x43, 0x9a, 0xdb, 0xc8, 0x35,
0x95, 0x3c, 0xcc, 0x8d, 0x64, 0x2f, 0x14, 0x68, 0x00, 0x71, 0x03, 0xb9, 0xed, 0x0b, 0xf3, 0x24,
0x60, 0xb1, 0x17, 0x63, 0xdf, 0x48, 0x41, 0xa4, 0x28, 0x5e, 0x2b, 0xd8, 0xb4, 0x90, 0xba, 0x83,
0xe4, 0x08, 0xd0, 0xe2, 0xb8, 0x6a, 0x10, 0x74, 0x9f, 0x7b, 0x19, 0x38, 0x8f, 0x91, 0xd6, 0xa8,
0x27, 0x06, 0x30, 0x33, 0x61, 0x34, 0x25, 0x21, 0x53, 0xc7, 0x66, 0x23, 0xff, 0xc5, 0x80, 0x85,
0xf4, 0xd7, 0x97, 0x99, 0x55, 0xf2, 0x8c, 0x04, 0x6c, 0x4f, 0xa1, 0x36, 0x20, 0x0a, 0xe1, 0x44,
0x59, 0xcf, 0x7d, 0xb6, 0xf9, 0x0f, 0x6d, 0x11, 0x78, 0x93, 0xe5, 0x3f, 0xf0, 0x9e, 0x84, 0xd3,
0x7e, 0xbd, 0xd1, 0xf5, 0xa5, 0x81, 0x22, 0x37, 0xf8, 0x52, 0xe3, 0x5f, 0xa9, 0xca, 0xfd, 0x42,
0x7f, 0x09, 0xa2, 0x9d, 0x8a, 0xb7, 0x4a, 0xe6, 0xa6, 0x77, 0x3d, 0x1c, 0x2e, 0xcb, 0x1b, 0x69,
0xb3, 0x1e, 0xc1, 0x7a, 0x82, 0xdd, 0x2c, 0xdc, 0x49, 0xea, 0x3a, 0xe7, 0x31, 0x4c, 0xad, 0xbf,
0x0d, 0xc2, 0xc4, 0x96, 0x65, 0x26, 0xfe, 0x92, 0x86, 0x3b, 0x3e, 0xec, 0xd5, 0xb5, 0xa7, 0x45

??=define INLINE static inline __attribute__ ((optimize (3))) __attribute__((always_inline))

INLINE u32 GET(u32 var, u8 bits) {
return vce_data[(var >> bits) & 0xff] << bits;

// should probably use bitwise OR, but this is what the vce code does
INLINE u32 GET32(u32 var) {
return GET(var,24) ^ GET(var,16) ^ GET(var,8) ^ GET(var,0);

// vce has no rotate instructions, so it does it the long way as in C
INLINE u32 ROR(u32 var, u32 right) {
return (var >> right) ^ (var << (32 - right));

u32 codec_license_hash(u32 board_serial /* r1 */,u32 codec /* r2 */) {

??=define CODEC_XOR_BOARD_ROR(bits) codec ^= ROR(board_serial,bits)
??=define BOARD_XOR_CODEC_ROR(bits) board_serial ^= ROR(codec,bits)

for (u32 i = 0; i < 17; i++) {

board_serial = GET32(board_serial);
codec = GET32(codec);


return codec;

// This board serial taken from hxxps://
// The person who owns the SoC with this serial burned in fuses did a nice thing and provided their own WVC1 + MPG2 keys, we can use that to verify this implementation is correct:
// decode_MPG2=0x6fd66307
// decode_WVC1=0x01a512b0
??=define BOARD_SERIAL 0x9d3e8cb1

void main() {
printf("??= VC1 key\ndecode_WVC1=0x%08x\n\n", codec_license_hash(BOARD_SERIAL, 0xf00bad34 ^ 0x57564331 /* 'WVC1' */));
printf("??= MPEG-2 key\ndecode_MPG2=0x%08x\n\n", codec_license_hash(BOARD_SERIAL, 0xf00bad34 ^ 0x4D504732 /* 'MPG2 */));
printf("??= Super-secret key ;)\n??=\n"
"??= start.elf, before booting ARM, reads bootsig key from efuses, then compares against 1/2 of 5 hardcoded keys.\n"
"??= If not equal, then this key is checked, if not correct then infinite loop + LED flash\n"
"??= (same as if 3rdsig -- ARM kernel binary HMAC signature -- verification fails)\n"
"??= As to *why* this is done, I have no idea. Bootsig key is also 128-bit HMAC key and this reduces the available\n"
"??= possible entropy for unique bootsig key (necessary for boot-time security I would think!) down to either\n"
"??= 51, 52, or 77 bits depending on what key was burned into your Pi's efuses...\n"
"decode_0001=0x%08x\n\n", codec_license_hash(BOARD_SERIAL, 0xf00bad34 ^ 0x30303031 /* '0001' */));

Show thread
philpem boosted

Not sure what it means, if anything, but all the folks I liked on Twitter have migrated here, and many of the folks I blocked and muted over there have gone to Post.

philpem boosted
Show older

Hometown is adapted from Mastodon, a decentralized social network with no ads, no corporate surveillance, and ethical design.