Log: Reverse Engineering Human Resource Machine

July 3rd 2024

I’ve been wanting to build a small assembler, and I think for a while I was considering transpiling the instruction set exposed by Human Resource Machine into x86or something. Maybe wasm.

The save file

On my box Human Resource machine keeps its data in .local/share/Tomorrow Corporation/Human Resource Machine. Here’s what that looks like:

λ  ls
profiles.bin   settings.txt   steam_autocloud.vdf

both settings.txt and steam_autocloud.vdf contain some information about cloud saves and fullscreen settings etc. The really interesting file is profiles.bin. Which is where I will show HRM is keeping all of its state.

To start off I’ll remove the file completely:

λ  rm profiles.bin

And start the game:

Choose Profile Page
Chosen Profile
Level Zero

Now that that’s done, I can close the game and examine profiles.bin:

λ  la profiles.bin 
.rw-rw-r-- kingsfoil kingsfoil 14 MB Wed Jul  3 22:41:35 2024  profiles.bin

λ  hexyl profiles.bin 
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ b0 1b b6 b9 05 00 00 00 ┊ 18 f9 8c 24 62 3e 16 ec │ו×ו⋄⋄⋄┊•××$b>•×│
│00000010│ 50 d1 99 7e d6 15 f1 f3 ┊ 01 00 00 00 31 6c 72 67 │P××~ו××┊•⋄⋄⋄1lrg│
│00000020│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│*       │                         ┊                         │        ┊        │
│00e4bb80│ 00 00 00 00 00 00 00 00 ┊                         │⋄⋄⋄⋄⋄⋄⋄⋄┊        │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘

λ  cp profiles.bin level0.profiles.bin
'profiles.bin' -> 'level0.profiles.bin'

λ  sha256sum level0.profiles.bin 
2ef459accf8188a4a38981fd3ee74b2f5be5453652899a76badb5742ccdb3785  level0.profiles.bin

I’m making a note of that checksum to keep an easy at-a-glance indicator of the save file changing.

Next I start the game up again, I can begin playing level 1:

Empty Level 1

Then, I can add a single INBOX instruction:

Single INBOX instruction

Check the profile:

λ  hexyl profiles.bin 
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ 7d 4a 0c 63 05 00 00 00 ┊ 18 f9 8c 24 62 3e 16 ec │}J_c•⋄⋄⋄┊•××$b>•×│
│00000010│ 50 d1 99 7e d6 15 f1 f3 ┊ 01 00 00 00 31 6c 72 67 │P××~ו××┊•⋄⋄⋄1lrg│
│00000020│ 01 00 00 00 c9 bb c5 30 ┊ f6 48 10 1a 54 d3 b6 a2 │•⋄⋄⋄×××0┊×H••T×××│
│00000030│ f8 1c bd 8d 00 00 00 00 ┊ 00 00 00 00 ff ff ff ff │ו××⋄⋄⋄⋄┊⋄⋄⋄⋄××××│
│00000040│ ff ff ff ff 00 00 00 00 ┊ 00 00 00 00 01 00 00 00 │××××⋄⋄⋄⋄┊⋄⋄⋄⋄•⋄⋄⋄│
│00000050│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│*       │                         ┊                         │        ┊        │
│00e4bb80│ 00 00 00 00 00 00 00 00 ┊                         │⋄⋄⋄⋄⋄⋄⋄⋄┊        │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘

For good measure, I’ll add an additional INBOX instruction to the first level and save that state as level1_two_inbox_instr.profiles.bin, just to see if I can find a repeated pattern:

λ  ls level*.bin
level0.profiles.bin   level1_single_inbox_instr.profiles.bin   level1_two_inbox_instr.profiles.bin

share/Tomorrow Corporation/Human Resource Machine on  (us-west-2) took 9s 
λ  ls level*.bin | xargs sha256sum
2ef459accf8188a4a38981fd3ee74b2f5be5453652899a76badb5742ccdb3785  level0.profiles.bin
d622078b0cdce3bec853e16f033ac2c0a325aa6dacbb74bf9e29d24d41624e04  level1_single_inbox_instr.profiles.bin
03dffae90a971bbc6fa2b4c98fa4b14c60f088851093ffb329cb337a9c8ea7f8  level1_two_inbox_instr.profiles.bin

Dumping those all as hex with hexyl I get the following:

λ  ls level0.hex level1_single_inbox_instr.profiles.hex level1_two_inbox_instr.profiles.hex | xargs sha256sum
fd46030c4695f628eb41c87747b96f4b8fcff226364f88bcc00aff31c64a756f  level0.hex
2ce84cbebe58c2023c11429aca9a8976e6669fdacd8523201a1a42d4395910e7  level1_single_inbox_instr.profiles.hex
2d8bff4dce8a1d51c8c8a3d6a397d8e0635d171c9cc543b8fa9648ec05f8e2bb  level1_two_inbox_instr.profiles.hex

λ  bat level0.hex level1_single_inbox_instr.profiles.hex level1_two_inbox_instr.profiles.hex
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ b0 1b b6 b9 05 00 00 00 ┊ 18 f9 8c 24 62 3e 16 ec │ו×ו⋄⋄⋄┊•××$b>•×│
│00000010│ 50 d1 99 7e d6 15 f1 f3 ┊ 01 00 00 00 31 6c 72 67 │P××~ו××┊•⋄⋄⋄1lrg│
│00000020│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│*       │                         ┊                         │        ┊        │
│00e4bb80│ 00 00 00 00 00 00 00 00 ┊                         │⋄⋄⋄⋄⋄⋄⋄⋄┊        │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ 7d 4a 0c 63 05 00 00 00 ┊ 18 f9 8c 24 62 3e 16 ec │}J_c•⋄⋄⋄┊•××$b>•×│
│00000010│ 50 d1 99 7e d6 15 f1 f3 ┊ 01 00 00 00 31 6c 72 67 │P××~ו××┊•⋄⋄⋄1lrg│
│00000020│ 01 00 00 00 c9 bb c5 30 ┊ f6 48 10 1a 54 d3 b6 a2 │•⋄⋄⋄×××0┊×H••T×××│
│00000030│ f8 1c bd 8d 00 00 00 00 ┊ 00 00 00 00 ff ff ff ff │ו××⋄⋄⋄⋄┊⋄⋄⋄⋄××××│
│00000040│ ff ff ff ff 00 00 00 00 ┊ 00 00 00 00 01 00 00 00 │××××⋄⋄⋄⋄┊⋄⋄⋄⋄•⋄⋄⋄│
│00000050│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│*       │                         ┊                         │        ┊        │
│00e4bb80│ 00 00 00 00 00 00 00 00 ┊                         │⋄⋄⋄⋄⋄⋄⋄⋄┊        │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ 4d 4a 0c 63 05 00 00 00 ┊ 18 f9 8c 24 62 3e 16 ec │MJ_c•⋄⋄⋄┊•××$b>•×│
│00000010│ 50 d1 99 7e d6 15 f1 f3 ┊ 01 00 00 00 31 6c 72 67 │P××~ו××┊•⋄⋄⋄1lrg│
│00000020│ 01 00 00 00 c9 bb c5 30 ┊ f6 48 10 1a 54 d3 b6 a2 │•⋄⋄⋄×××0┊×H••T×××│
│00000030│ f8 1c bd 8d 00 00 00 00 ┊ 00 00 00 00 ff ff ff ff │ו××⋄⋄⋄⋄┊⋄⋄⋄⋄××××│
│00000040│ ff ff ff ff 00 00 00 00 ┊ 00 00 00 00 02 00 00 00 │××××⋄⋄⋄⋄┊⋄⋄⋄⋄•⋄⋄⋄│
│00000050│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│*       │                         ┊                         │        ┊        │
│00e4bb80│ 00 00 00 00 00 00 00 00 ┊                         │⋄⋄⋄⋄⋄⋄⋄⋄┊        │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘

And with any luck a diff of the files will reveal the change in instructions:

Hexadecimal Diff of Level 0 and Level 1 (single INBOX instruction)
Hexadecimal Diff of Level 1 (single INBOX instruction) and Level 1 (two INBOX instructions)

Presumably the b0 1b b6 b9 becoming 7d 4a 0c 63 on row 20 has something to do with the game initializing the first level, and