Finding SHA256

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:

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:

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

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:

Conclusion:

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}")

References:

[1] https://en.wikipedia.org/wiki/SHA-2

[2] https://github.com/B-Con/crypto-algorithms/blob/master/sha256.c