10 Feb 2025 by Jonas Rudloff
In the previous article we looked at the iRISC instruction set, and our analysis concluded that its a RISC instruction set similar to MIPS. We found some promising patterns, however we are missing a lot of knowledge about the instruction set to be able to make any sense of the firmware, in particular we only know a few instructions: st
, ld
, add
.
After looking around in the IRON_PREP_CODE
section to try to figure out more of the instruction set we found the following chunk of high entropy near the end of the section:
00015510 42 8a 2f 98 71 37 44 91 b5 c0 fb cf e9 b5 db a5 │B·/·│q7D·│····│····│
00015520 39 56 c2 5b 59 f1 11 f1 92 3f 82 a4 ab 1c 5e d5 │9V·[│Y···│·?··│··^·│
00015530 d8 07 aa 98 12 83 5b 01 24 31 85 be 55 0c 7d c3 │····│··[·│$1··│U·}·│
00015540 72 be 5d 74 80 de b1 fe 9b dc 06 a7 c1 9b f1 74 │r·]t│····│····│···t│
00015550 e4 9b 69 c1 ef be 47 86 0f c1 9d c6 24 0c a1 cc │··i·│··G·│····│$···│
00015560 2d e9 2c 6f 4a 74 84 aa 5c b0 a9 dc 76 f9 88 da │-·,o│Jt··│\···│v···│
00015570 98 3e 51 52 a8 31 c6 6d b0 03 27 c8 bf 59 7f c7 │·>QR│·1·m│··'·│·Y··│
00015580 c6 e0 0b f3 d5 a7 91 47 06 ca 63 51 14 29 29 67 │····│···G│··cQ│·))g│
00015590 27 b7 0a 85 2e 1b 21 38 4d 2c 6d fc 53 38 0d 13 │'···│.·!8│M,m·│S8··│
000155a0 65 0a 73 54 76 6a 0a bb 81 c2 c9 2e 92 72 2c 85 │e·sT│vj··│···.│·r,·│
000155b0 a2 bf e8 a1 a8 1a 66 4b c2 4b 8b 70 c7 6c 51 a3 │····│··fK│·K·p│·lQ·│
000155c0 d1 92 e8 19 d6 99 06 24 f4 0e 35 85 10 6a a0 70 │····│···$│··5·│·j·p│
000155d0 19 a4 c1 16 1e 37 6c 08 27 48 77 4c 34 b0 bc b5 │····│·7l·│'HwL│4···│
000155e0 39 1c 0c b3 4e d8 aa 4a 5b 9c ca 4f 68 2e 6f f3 │9···│N··J│[··O│h.o·│
000155f0 74 8f 82 ee 78 a5 63 6f 84 c8 78 14 8c c7 02 08 │t···│x·co│··x·│····│
00015600 90 be ff fa a4 50 6c eb be f9 a3 f7 c6 71 78 f2 │····│·Pl·│····│·qx·│
Googling the first 4 bytes 42 8a 2f 98
we figured out that this piece of data is the K
array from SHA256[1, 2]. This means that the firmware most likely has an SHA256 implementation.
Since the SHA256 algorithm is a well specified algorithm using many different operations this is great target for figuring out more of the instruction set.
Looking at open-source implementations of SHA256 we find that the sha256_init
function contains a lot of known constants:
void sha256_init(SHA256_CTX *ctx)
{
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
}
Searching through our disassembly we can find these constants in a function broken up into 16 bit chunks:
00013220: 480300bc unk.12 r0, r3, r0, 0x00bc
00013224: 6c201806 st.d r3, r1, 0x0006
00013228: 703f0ec2 st.d! r1, r1, 0xfec2
0001322c: 6c20b13e st.d r22, r1, 0x013e
00013230: 6c20b93a st.d r23, r1, 0x013a
00013234: fcd73008 unk.3f r6, r23, r6, 0x3008
00013238: fca62808 unk.3f r5, r6, r5, 0x2808
0001323c: fc852008 unk.3f r4, r5, r4, 0x2008
00013240: 2004ae85 unk.08 r0, r4, r21, 0xae85
00013244: 2484bb67 unk.09 r4, r4, r23, 0xbb67
00013248: 1c84e667 unk.07 r4, r4, r28, 0xe667
0001324c: 18846a09 unk.06 r4, r4, r13, 0x6a09
00013250: 7820211c unk.1e r1, r0, r4, 0x211c
00013254: 2004f53a unk.08 r0, r4, r30, 0xf53a
00013258: 2484a54f unk.09 r4, r4, r20, 0xa54f
0001325c: 1c84f372 unk.07 r4, r4, r30, 0xf372
00013260: 18843c6e unk.06 r4, r4, r7, 0x3c6e
00013264: 78202124 unk.1e r1, r0, r4, 0x2124
00013268: 2004688c unk.08 r0, r4, r13, 0x688c
0001326c: 24849b05 unk.09 r4, r4, r19, 0x9b05
00013270: 1c84527f unk.07 r4, r4, r10, 0x527f
00013274: 1884510e unk.06 r4, r4, r10, 0x510e
00013278: 7820212c unk.1e r1, r0, r4, 0x212c
0001327c: 2004cd19 unk.08 r0, r4, r25, 0xcd19
00013280: 24845be0 unk.09 r4, r4, r11, 0x5be0
00013284: 1c84d9ab unk.07 r4, r4, r27, 0xd9ab
00013288: 18841f83 unk.06 r4, r4, r3, 0x1f83
0001328c: 78202134 unk.1e r1, r0, r4, 0x2134
00013290: 78200114 unk.1e r1, r0, r0, 0x0114
00013294: 6c20010a st.d r0, r1, 0x010a
00013298: 00360008 add r22, r1, 8
0001329c: fec4b008 unk.3f r22, r4, r22, 0xb008
000132a0: 94fffeeb unk.25 r7, r31, r31, 0xfeeb
000132a4: fec4b008 unk.3f r22, r4, r22, 0xb008
000132a8: fee5b808 unk.3f r23, r5, r23, 0xb808
000132ac: 94ffff96 unk.25 r7, r31, r31, 0xff96
000132b0: 6437013a ld.d r23, r1, 0x13a
000132b4: 6436013e ld.d r22, r1, 0x13e
000132b8: 00210140 add r1, r1, 320
000132bc: 64230006 ld.d r3, r1, 0x006
000132c0: fd001825 unk.3f r8, r0, r3, 0x1825
From this we can learn:
opcode=0x06,0x07,0x08,0x09
is used for loading the SHA256 initialization constants into r4
.opcode=0x1e
might be a 64 bit store operation.opcode=0x25
might be a jump/call instruction. Both instances 94fffeeb
and 94ffff96
have 24bit signed constants in the instruction.Adding this knowledge to our assembler we get:
00013220: 480300bc unk.12 r0, r3, r0, 0x00bc
00013224: 6c201806 st.d r3, r1, 0x0006
00013228: 703f0ec2 st.d! r1, r1, -0x13e
0001322c: 6c20b13e st.d r22, r1, 0x013e
00013230: 6c20b93a st.d r23, r1, 0x013a
00013234: fcd73008 or r23, r6, r6
00013238: fca62808 or r6, r5, r5
0001323c: fc852008 or r5, r4, r4
00013240: 2004ae85 set2 r4, r0, 0xae85
00013244: 2484bb67 set3 r4, r4, 0xbb67
00013248: 1c84e667 set1 r4, r4, 0xe667
0001324c: 18846a09 set0 r4, r4, 0x6a09
00013250: 7820211c st.q r4, r1, 0x011c
00013254: 2004f53a set2 r4, r0, 0xf53a
00013258: 2484a54f set3 r4, r4, 0xa54f
0001325c: 1c84f372 set1 r4, r4, 0xf372
00013260: 18843c6e set0 r4, r4, 0x3c6e
00013264: 78202124 st.q r4, r1, 0x0124
00013268: 2004688c set2 r4, r0, 0x688c
0001326c: 24849b05 set3 r4, r4, 0x9b05
00013270: 1c84527f set1 r4, r4, 0x527f
00013274: 1884510e set0 r4, r4, 0x510e
00013278: 7820212c st.q r4, r1, 0x012c
0001327c: 2004cd19 set2 r4, r0, 0xcd19
00013280: 24845be0 set3 r4, r4, 0x5be0
00013284: 1c84d9ab set1 r4, r4, 0xd9ab
00013288: 18841f83 set0 r4, r4, 0x1f83
0001328c: 78202134 st.q r4, r1, 0x0134
00013290: 78200114 st.q r0, r1, 0x0114
00013294: 6c20010a st.d r0, r1, 0x010a
00013298: 00360008 add r22, r1, 8
0001329c: fec4b008 or r4, r22, r22
000132a0: 94fffeeb call 0x00012e4c
000132a4: fec4b008 or r4, r22, r22
000132a8: fee5b808 or r5, r23, r23
000132ac: 94ffff96 call 0x00013104
000132b0: 6437013a ld.d r23, r1, 0x13a
000132b4: 6436013e ld.d r22, r1, 0x13e
000132b8: 00210140 add r1, r1, 320
000132bc: 64230006 ld.d r3, r1, 0x006
000132c0: fd001825 alu.025 r8, r0, r3
Now we can see that there are calls to 0x00012e4c
and 0x00013104
, now it seem like we can’t learn much more from this function. In C this function looks like:
void sha256(void *r4_data, size_t r5_size, void *r6_hash) {
void *r23 = r6_hash;
size_t r6 = r5_size;
void *r5 = r4_data;
sha256_ctx ctx = {
... initialize sha256 with constants ...
};
void *r22 = &ctx
func_0x00012e4c(r22, r5, r6);
func_0x00013104(r22, r23);
}
But we can take a look at two functions that this function is calling, the first function seem to be sha256_update
and the other sha256_finalize
sha256_update
should have the following structure[2]:
void sha256_update(SHA256_CTX *ctx, const BYTE data[], size_t len)
{
WORD i;
for (i = 0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
sha256_transform(ctx, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
Judging by the structure of the code we should see a few jump both forward(if
) and backwards(for
), as well as a call to sha256_transform
.
00012e4c: 480300bc unk.12 r0, r3, r0, 0x00bc
00012e50: 6c201806 st.d r3, r1, 0x0006
00012e54: 703f0fea st.d! r1, r1, -0x016
00012e58: 6c20a816 st.d r21, r1, 0x0016
00012e5c: 6c20b012 st.d r22, r1, 0x0012
00012e60: 6c20b80e st.d r23, r1, 0x000e
... save argument registers to callee saved registers
... r21 = sha256_CTX
... r22 = data
... r23 = size
00012e64: fcd73008 or r23, r6, r6
00012e68: fcb62808 or r22, r5, r5
00012e6c: fc952008 or r21, r4, r4
00012e70: 16e40000 unk.05 r23, r4, r0, 0x0000
00012e74: a0000015 unk.28 r0, r0, r0, 0x0015
00012e78: 66a40102 ld.d r4, r21, 0x102
00012e7c: fea42000 alu.000 r21, r4, r4
00012e80: 62c50000 unk.18 r22, r5, r0, 0x0000
00012e84: 68802800 unk.1a r4, r0, r5, 0x2800
00012e88: 66a40102 ld.d r4, r21, 0x102
00012e8c: 00840001 add r4, r4, 1
00012e90: 6ea02102 st.d r4, r21, 0x0102
... this might be a compare and forward jump
00012e94: 14850040 unk.05 r4, r5, r0, 0x0040
00012e98: a4000008 unk.29 r0, r0, r0, 0x0008
... call sha256_transform(ctx) , data pointer is not passed as an argument
00012e9c: fea4a808 or r4, r21, r21
00012ea0: 94000010 call 0x00012ee0
... ctx->bitlen += 512
00012ea4: 5ea4010c unk.17 r21, r4, r0, 0x010c
00012ea8: 00840200 add r4, r4, 512
00012eac: 7aa0210c st.q r4, r21, 0x010c
... ctx->datalen = 0
00012eb0: 6ea00102 st.d r0, r21, 0x0102
00012eb4: 00040000 add r4, r0, 0
00012eb8: 02d60001 add r22, r22, 1
00012ebc: 02f7ffff add r23, r23, -1
... This might be a compare and backwards jump
00012ec0: 16e50000 unk.05 r23, r5, r0, 0x0000
00012ec4: a400ffee unk.29 r0, r0, r31, 0xffee
00012ec8: 6437000e ld.d r23, r1, 0x00e
00012ecc: 64360012 ld.d r22, r1, 0x012
00012ed0: 64350016 ld.d r21, r1, 0x016
00012ed4: 00210018 add r1, r1, 24
00012ed8: 64230006 ld.d r3, r1, 0x006
00012edc: fd001825 alu.025 r8, r0, r3
From this we can learn:
opcode = 0x05
: does some kind of comparison operation.opcode = 0x29
: is a conditional branch with 16bit offset.0x00012ee0
is most likely sha256_transform
.Now we will take a look at what we suspect is sha256_transform
and try to compare it to an actual implementation of SHA256:
00012ee0: 703f0fda st.d! r1, r1, -0x026
00012ee4: 6c208826 st.d r17, r1, 0x0026
00012ee8: 6c209022 st.d r18, r1, 0x0022
00012eec: 6c20981e st.d r19, r1, 0x001e
00012ef0: 6c20a01a st.d r20, r1, 0x001a
00012ef4: 6c20a816 st.d r21, r1, 0x0016
00012ef8: 6c20b012 st.d r22, r1, 0x0012
00012efc: 6c20b80e st.d r23, r1, 0x000e
00012f00: 00050000 add r5, r0, 0
00012f04: 64860002 ld.d r6, r4, 0x002
LOOP1:
00012f08: fc872800 alu.000 r4, r7, r5
00012f0c: 64e80006 ld.d r8, r7, 0x006
00012f10: fd09c881 alu.081 r8, r9, r25
00012f14: fd0a3883 alu.083 r8, r10, r7
00012f18: fd494808 or r9, r10, r9
00012f1c: fd0a7081 alu.081 r8, r10, r14
00012f20: fd0b9083 alu.083 r8, r11, r18
00012f24: fd6a5008 or r10, r11, r10
00012f28: fd0b1883 alu.083 r8, r11, r3
00012f2c: fd4a580e alu.00e r10, r10, r11
00012f30: fd49480e alu.00e r10, r9, r9
00012f34: 64ea003a ld.d r10, r7, 0x03a
00012f38: fd4b7881 alu.081 r10, r11, r15
00012f3c: fd4c8883 alu.083 r10, r12, r17
00012f40: fd8b5808 or r11, r12, r11
00012f44: fd4c6881 alu.081 r10, r12, r13
00012f48: fd429883 alu.083 r10, r2, r19
00012f4c: fc4c6008 or r12, r2, r12
00012f50: fd4a5083 alu.083 r10, r10, r10
00012f54: fd8a500e alu.00e r12, r10, r10
00012f58: fd4a580e alu.00e r10, r10, r11
00012f5c: 64eb0026 ld.d r11, r7, 0x026
00012f60: fcc65800 alu.000 r6, r6, r11
00012f64: fcc65000 alu.000 r6, r6, r10
00012f68: fcc64800 alu.000 r6, r6, r9
00012f6c: 6ce03042 st.d r6, r7, 0x0042
00012f70: 00a50004 add r5, r5, 4
00012f74: 14a600c0 cmp r6, r5, 0x00c0
00012f78: fd064008 or r6, r8, r8
00012f7c: a400ffe3 b.0.0 0x00012f08 LOOP1
00012f80: 00070000 add r7, r0, 0
00012f84: 6485012e ld.d r5, r4, 0x12e
00012f88: 6486012a ld.d r6, r4, 0x12a
00012f8c: 648c0126 ld.d r12, r4, 0x126
00012f90: 648b0122 ld.d r11, r4, 0x122
00012f94: 648a011e ld.d r10, r4, 0x11e
00012f98: 6489011a ld.d r9, r4, 0x11a
00012f9c: 64880116 ld.d r8, r4, 0x116
00012fa0: 64820112 ld.d r2, r4, 0x112
00012fa4: 001effff add r30, r0, -1
00012fa8: 00035510 add r3, r0, 21776
00012fac: 087b0072 unk.02 r3, r27, r0, 0x0072
00012fb0: fc551008 or r21, r2, r2
00012fb4: fd034008 or r3, r8, r8
00012fb8: fd3a4808 or r26, r9, r9
00012fbc: fcb62808 or r22, r5, r5
00012fc0: fcd33008 or r19, r6, r6
00012fc4: fd926008 or r18, r12, r12
00012fc8: fd745808 or r20, r11, r11
00012fcc: fd575008 or r23, r10, r10
LOOP2:
00012fd0: fe99a008 or r25, r20, r20
00012fd4: fe5c9008 or r28, r18, r18
00012fd8: fe7d9808 or r29, r19, r19
00012fdc: ff58d008 or r24, r26, r26
00012fe0: fc7a1808 or r26, r3, r3
00012fe4: fea3a808 or r3, r21, r21
00012fe8: ff35a881 alu.081 r25, r21, r21
00012fec: ff345883 alu.083 r25, r20, r11
00012ff0: fe95a808 or r21, r20, r21
00012ff4: ff34d081 alu.081 r25, r20, r26
00012ff8: ff333083 alu.083 r25, r19, r6
00012ffc: fe74a008 or r20, r19, r20
00013000: fe95a80e alu.00e r20, r21, r21
00013004: ff343881 alu.081 r25, r20, r7
00013008: ff33c883 alu.083 r25, r19, r25
0001300c: fe74a008 or r20, r19, r20
00013010: feb5a00e alu.00e r21, r21, r20
00013014: ff54c00a alu.00a r26, r20, r24
00013018: ff53c00e alu.00e r26, r19, r24
0001301c: ff92c80a alu.00a r28, r18, r25
00013020: ff31f00e alu.00e r25, r17, r30
00013024: ffb1880a alu.00a r29, r17, r17
00013028: fe32900e alu.00e r17, r18, r18
0001302c: feb6b000 alu.000 r21, r22, r22
00013030: fc75980a alu.00a r3, r21, r19
00013034: feb5a00e alu.00e r21, r21, r20
00013038: fc749881 alu.081 r3, r20, r19
0001303c: fc736883 alu.083 r3, r19, r13
00013040: fe74a008 or r20, r19, r20
00013044: fc73f081 alu.081 r3, r19, r30
00013048: fc711083 alu.083 r3, r17, r2
0001304c: fe339808 or r19, r17, r19
00013050: fe74a00e alu.00e r19, r20, r20
00013054: fc735081 alu.081 r3, r19, r10
00013058: fc71b083 alu.083 r3, r17, r22
0001305c: fe339808 or r19, r17, r19
00013060: fe94980e alu.00e r20, r20, r19
00013064: fe95a800 alu.000 r20, r21, r21
00013068: fed69000 alu.000 r22, r22, r18
0001306c: fcf4da19 alu.219 r7, r20, r27
00013070: fed6a000 alu.000 r22, r22, r20
00013074: fc943a19 alu.219 r4, r20, r7
00013078: fed6a000 alu.000 r22, r22, r20
0001307c: feb5b000 alu.000 r21, r21, r22
00013080: fed4b800 alu.000 r22, r20, r23
00013084: 00e70004 add r7, r7, 4
00013088: 14f70100 cmp r23, r7, 0x0100
0001308c: ffb6e808 or r22, r29, r29
00013090: ff93e008 or r19, r28, r28
00013094: ff32c808 or r18, r25, r25
00013098: ff17c008 or r23, r24, r24
0001309c: a400ffcd b.0.0 0x00012fd0 LOOP2
000130a0: ff276000 alu.000 r25, r7, r12
000130a4: fe8b5800 alu.000 r20, r11, r11
000130a8: ff0a5000 alu.000 r24, r10, r10
000130ac: ff494800 alu.000 r26, r9, r9
000130b0: feac1000 alu.000 r21, r12, r2
000130b4: fc684000 alu.000 r3, r8, r8
000130b8: 6c804116 st.d r8, r4, 0x0116
000130bc: 6c806112 st.d r12, r4, 0x0112
000130c0: 6c80491a st.d r9, r4, 0x011a
000130c4: 6c80511e st.d r10, r4, 0x011e
000130c8: 6c805922 st.d r11, r4, 0x0122
000130cc: 6c803926 st.d r7, r4, 0x0126
000130d0: ff863000 alu.000 r28, r6, r6
000130d4: 6c80312a st.d r6, r4, 0x012a
000130d8: ffa52800 alu.000 r29, r5, r5
000130dc: 6c80292e st.d r5, r4, 0x012e
000130e0: 6437000e ld.d r23, r1, 0x00e
000130e4: 64360012 ld.d r22, r1, 0x012
000130e8: 64350016 ld.d r21, r1, 0x016
000130ec: 6434001a ld.d r20, r1, 0x01a
000130f0: 6433001e ld.d r19, r1, 0x01e
000130f4: 64320022 ld.d r18, r1, 0x022
000130f8: 64310026 ld.d r17, r1, 0x026
000130fc: 00210028 add r1, r1, 40
00013100: fc00002d alu.02d r0, r0, r0
If we look at the first loop:
00012f0c: 64e80006 ld.d r8, r7, 0x006
00012f10: fd09c881 alu.081 r8, r9, r25
00012f14: fd0a3883 alu.083 r8, r10, r7
00012f18: fd494808 or r9, r10, r9
00012f1c: fd0a7081 alu.081 r8, r10, r14
00012f20: fd0b9083 alu.083 r8, r11, r18
00012f24: fd6a5008 or r10, r11, r10
00012f28: fd0b1883 alu.083 r8, r11, r3
00012f2c: fd4a580e alu.00e r10, r10, r11
00012f30: fd49480e alu.00e r10, r9, r9
00012f34: 64ea003a ld.d r10, r7, 0x03a
00012f38: fd4b7881 alu.081 r10, r11, r15
00012f3c: fd4c8883 alu.083 r10, r12, r17
00012f40: fd8b5808 or r11, r12, r11
00012f44: fd4c6881 alu.081 r10, r12, r13
00012f48: fd429883 alu.083 r10, r2, r19
00012f4c: fc4c6008 or r12, r2, r12
00012f50: fd4a5083 alu.083 r10, r10, r10
00012f54: fd8a500e alu.00e r12, r10, r10
00012f58: fd4a580e alu.00e r10, r10, r11
00012f5c: 64eb0026 ld.d r11, r7, 0x026
00012f60: fcc65800 alu.000 r6, r6, r11
00012f64: fcc65000 alu.000 r6, r6, r10
00012f68: fcc64800 alu.000 r6, r6, r9
00012f6c: 6ce03042 st.d r6, r7, 0x0042
This could very well correspond to the following code:
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
We make the following observations
alu.000
instructions, these could correspond to the 3 addition operation in SIG1(...) + m[...] + SIG0(...) + m[...]
alu.081
and alu.083
looks like shifting operations used to implement ROTRIGHT
due to the numbers incorrectly interpreted by our assembler as register: r7
, r25
, 7 + 25 = 32, r14
, r18
, 14 + 18 = 32.alu.00e
seems to be the xor operations in SIG0
and SIG1
or
(opcode=0x3f
, subop=0x008
) is actually or.Analysing the second loop:
00012fd0: fe99a008 or r25, r20, r20
00012fd4: fe5c9008 or r28, r18, r18
00012fd8: fe7d9808 or r29, r19, r19
00012fdc: ff58d008 or r24, r26, r26
00012fe0: fc7a1808 or r26, r3, r3
00012fe4: fea3a808 or r3, r21, r21
00012fe8: ff35a881 shr r21, r25, 21
00012fec: ff345883 shr r20, r25, 11
00012ff0: fe95a808 or r21, r20, r21
00012ff4: ff34d081 shr r20, r25, 26
00012ff8: ff333083 shr r19, r25, 6
00012ffc: fe74a008 or r20, r19, r20
00013000: fe95a80e xor r21, r20, r21
00013004: ff343881 shr r20, r25, 7
00013008: ff33c883 shr r19, r25, 25
0001300c: fe74a008 or r20, r19, r20
00013010: feb5a00e xor r21, r21, r20
00013014: ff54c00a alu.00a r26, r20, r24
00013018: ff53c00e xor r19, r26, r24
0001301c: ff92c80a alu.00a r28, r18, r25
00013020: ff31f00e xor r17, r25, r30
00013024: ffb1880a alu.00a r29, r17, r17
00013028: fe32900e xor r18, r17, r18
0001302c: feb6b000 add r22, r21, r22
00013030: fc75980a alu.00a r3, r21, r19
00013034: feb5a00e xor r21, r21, r20
00013038: fc749881 shr r20, r3, 19
0001303c: fc736883 shr r19, r3, 13
00013040: fe74a008 or r20, r19, r20
00013044: fc73f081 shr r19, r3, 30
00013048: fc711083 shr r17, r3, 2
0001304c: fe339808 or r19, r17, r19
00013050: fe74a00e xor r20, r19, r20
00013054: fc735081 shr r19, r3, 10
00013058: fc71b083 shr r17, r3, 22
0001305c: fe339808 or r19, r17, r19
00013060: fe94980e xor r20, r20, r19
00013064: fe95a800 add r21, r20, r21
00013068: fed69000 add r22, r22, r18
0001306c: fcf4da19 alu.219 r7, r20, r27
00013070: fed6a000 add r22, r22, r20
00013074: fc943a19 alu.219 r4, r20, r7
00013078: fed6a000 add r22, r22, r20
0001307c: feb5b000 add r21, r21, r22
00013080: fed4b800 add r20, r22, r23
00013084: 00e70004 add r7, r7, 4
00013088: 14f70100 cmp r23, r7, 0x0100
0001308c: ffb6e808 or r22, r29, r29
00013090: ff93e008 or r19, r28, r28
00013094: ff32c808 or r18, r25, r25
00013098: ff17c008 or r23, r24, r24
0001309c: a400ffcd b.0.0 0x00012fd0
Observations:
alu.00a
seems to be an and
instructions.alu.219
seems to be a load instruction with semantics similar to rd = mem[rs + rt]
.We are now able to understand many ALU operations and well as branches and calls.
This is our final disassembler:
#!/usr/bin/env python3
import sys
from collections import defaultdict
from pwnlib.util.misc import read
from pwnlib.util.lists import group
from pwnlib.util.packing import u32
def sx(bits, width):
return bits - (1 << width) if bits & (1 << (width - 1)) else bits
fields_decoders = {
"op": lambda a, w: (w >> 26) & 0x3f,
"rs": lambda a, w: (w >> 21) & 0x1f,
"rd": lambda a, w: (w >> 16) & 0x1f,
"rt": lambda a, w: (w >> 11) & 0x1f,
"shamt": lambda a, w: (w >> 11) & 0x1f,
"imm16": lambda a, w: w & 0xffff,
"simm16": lambda a, w: sx(w & 0xffff, 16),
"imm11": lambda a, w: w & 0x7ff,
"simm11": lambda a, w: sx(w & 0x7ff, 11),
"stoff16": lambda a, w: sx((((w >> 16) & 0x1f) << 11) | (w & 0x7ff), 16),
"subop": lambda a, w: w & 0x7ff,
"jmpop": lambda a, w: (w >> 24) & 0x3,
"jmpoff": lambda a, w: a + (sx(w & 0xffffff, 24) << 2),
"branchoff": lambda a, w: a + (sx(w & 0xffff, 16) << 2),
}
table = lambda table, field, default: lambda fs: table.get(fs[field], default)(fs)
opcodes = table(
table = {
0x00: lambda fs: "add r{rd}, r{rs}, {simm16}".format(**fs),
0x05: lambda fs: "cmp r{rd}, r{rs}, {imm16:#06x}".format(**fs),
0x06: lambda fs: "set0 r{rd}, r{rs}, {imm16:#06x}".format(**fs),
0x07: lambda fs: "set1 r{rd}, r{rs}, {imm16:#06x}".format(**fs),
0x08: lambda fs: "set2 r{rd}, r{rs}, {imm16:#06x}".format(**fs),
0x09: lambda fs: "set3 r{rd}, r{rs}, {imm16:#06x}".format(**fs),
0x19: lambda fs: "ld.d r{rd}, r{rs}, {imm11:#05x}".format(**fs),
0x1b: lambda fs: "st.d r{rt}, r{rs}, {stoff16:#06x}".format(**fs),
0x1c: lambda fs: "st.d! r{rt}, r{rs}, {stoff16:#06x}".format(**fs),
0x1e: lambda fs: "st.q r{rt}, r{rs}, {stoff16:#06x}".format(**fs),
0x25: table(
table = {
0x00: lambda fs: "call {jmpoff:#010x}".format(**fs),
},
field = "jmpop",
default = lambda fs: "jump.{jmpop} {jmpoff:#010x}".format(**fs),
),
0x29: lambda fs: "b.{rs}.{rd} {branchoff:#010x}".format(**fs),
0x3f: table(
table = {
0x000: lambda fs: "add r{rd}, r{rs}, r{rt}".format(**fs),
0x008: lambda fs: "or r{rd}, r{rs}, r{rt}".format(**fs),
0x00a: lambda fs: "and r{rd}, r{rs}, r{rt}".format(**fs),
0x00e: lambda fs: "xor r{rd}, r{rs}, r{rt}".format(**fs),
0x081: lambda fs: "shr r{rd}, r{rs}, {shamt}".format(**fs),
0x083: lambda fs: "shr r{rd}, r{rs}, {shamt}".format(**fs),
0x219: lambda fs: "ld.d r{rd}, r{rs}, r{rt}".format(**fs),
},
field = "subop",
default = lambda fs: "alu.{subop:03x} r{rs}, r{rd}, r{rt}".format(**fs)
),
},
field = "op",
default = lambda fs: "unk.{op:02x} r{rs}, r{rd}, r{rt}, {imm16:#06x}".format(**fs)
)
for i, word in enumerate(map(lambda d: u32(d, endian="big"), group(4, read(sys.argv[1])))):
address = i * 4
fields = {op: f(address, word) for op, f in fields_decoders.items()}
inst = opcodes(fields)
print(f"{address:08x}:\t{word:08x}\t{inst}")
[1] https://en.wikipedia.org/wiki/SHA-2
[2] https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c