Thurler

Labyrinth 2 Bestiary Dump Documentation

Feb 21st, 2020 (edited)
173
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. First off, we need to find WHERE in the exe enemy data is stored. Thankfully, PD bosses have a lot of HP, and with very specific numbers too, so using a hex editor we can simply search for that HP value in the file, and we should be able to find the offset corresponding to that enemy's data. And since usually this kind of static data stays lumped together in the file, if we find one we should find almost all of them.
  2.  
  3. So let's take Shadow Iku - Heaven, for example. She has 302779499 HP, which converted to hex is 0x120C0C6B. Since we're using little endian, that value would be stored as 6B 0C 0C 12 in the game's exe. Searching for that value gets us only two matches, at offsets 0x274ADB and 0x274AF3. If we look around those addresses, we see that it's entirely surrounded by a wall of 0xCC values, with a bunch of stuff we don't currently understand between them.
  4.  
  5. Next let's take Shadow Suika - Heaven. She has 343749938 HP and is right next to Iku on the game's bestiary listing. This means she her data is likely adjacent to Iku's in the game's files, so let's search for her HP value in the exe. Converted to hex it is 0x147D3532, in little endian 32 35 7D 14. We also find exactly two matches, at offsets 0x275259 and 0x275271.
  6.  
  7. Some things to note here - each pair of offsets is separated by 18 bytes, showing that it is likely we have a common structure here to store those values, and they are very close in the code, their blocks of information are separated by a wall of 0xCC values. So we can assume that each enemy has its big structure to store its information, followed by a wall of 0xCC values. So now if we find the first enemy, we can just extract all the information sequentially!
  8.  
  9. Let's run Shadow Suika's data (0x2750F0 to 0x2756E0) through an online x86 disassembler to try and make sense of some of it: https://defuse.ca/online-x86-assembler.htm
  10.  
  11. If we search for our 0x147d3532 value, we see two similar instructions loading that value somewhere in memory. Scrolling down we see a lot of other things being loaded in memory with similar instructions, which could very well be the other stats we are looking for. Taking the bestiary entry in the wiki as a base, we can deduce what the other values are simply by comparing them (*1). Her level is listed at 1354, which in hex is 0x54A. Searching for that value we see the level is loaded just before the HP value. If we repeat this for other stats, we end up with the following order in which things are loaded:
  12.  
  13. Level - HP - HP again - ATK - DEF - MAG - MND - SPD - ACC - EVA - EXP - Money - FIR/CLD/WND/NTR/MYS/SPI/DRK/PHY/VOI affinities - PSN/PAR/HVY/SHK/SIL/TRR/DTH resistances - ATK/DEF/MAG/MND/SPD/ACC/EVA debuff resistances
  14.  
  15. So now that we know that, let's repeat this procedure for Shadow Iku and see if it all matches up. Taking the values from 0x274930 to 0x274F60 and putting them into the disassembler, we see that the code output is very similar to Suika's. At least the part where it loads values to memory, the part before that is very different. We can use this similarity to get where every enemy's offset is.
  16.  
  17. Specifically, the bit of code before the Level and the first HP load. It is the same between those two, namely:
  18. c7 40 20 <lv value> mov DWORD PTR [eax+0x20],<lv value>
  19. b8 08 00 00 00 mov eax,0x8
  20. 6b c8 00 imul ecx,eax,0x0
  21. 8b 55 ec mov edx,DWORD PTR [ebp-0x14]
  22. c7 84 0a c8 00 00 00 mov DWORD PTR [edx+ecx*1+0xc8],<hp value>
  23. 6b 0c 0c 12
  24. If we now take the b8080000006bc8008b55ecc7840ac8000000 sequence of values and look for those in the hex editor, we can check for every time the game is loading a level onto the memory, followed by a load of HP value. With some false positives since naturally these instructions can occur elsewhere in the loading stats process. The first offset we have when searching for that value is 0x134DA7, and if we check it out, it is loading a level 1 enemy with 0x58 HP, which is 88 in decimal. That is the first enemy in the bestiary, the Small Kedama! The other stats match up too, if you check them out.
  25.  
  26. Comparing the Small Kedama to the other two above, we see that there is a very big difference in their instructions after loading the Money amount. The Kedama has a bunch of instructions before loading its FIR affinity, which is what I assume to be item drop data. Since it's easier to just check those on the in-game bestiary anyway I don't even bother deciphering what it does. The differences stop when we reach the following instructions, when everything matches again:
  27. c7 81 bc 0b 00 00 00 mov DWORD PTR [ecx+0xbbc],0x0
  28. 00 00 00
  29. b8 08 00 00 00 mov eax,0x8
  30. 6b c8 0a imul ecx,eax,0xa
  31. 8b 55 ec mov edx,DWORD PTR [ebp-0x14]
  32. c7 84 0a c8 00 00 00 mov DWORD PTR [edx+ecx*1+0xc8],<fir affinity value>
  33. 42 00 00 00
  34.  
  35. So knowing all this, we can write a script that automatically reads enemy data starting from just before 0x134DA7, and dump them all into a file so we can analyze it. The script I wrote in python is in here: https://pastebin.com/4aR34fzG
  36.  
  37. (*1) If we did not know these values, we could try to change them in the exe with our hex editor and see what changes in game - if we bumped some value from 100 to 3000 and suddenly FIR attacks deal way less damage, we can assume that value is the FIR affinity.
RAW Paste Data