Shadow of War research

Memory scanning, code injection, debugger internals and other gamemodding related discussion
Post Reply
1b0d6fe5
Noobzor
Noobzor
Posts: 6
Joined: Thu Oct 26, 2017 5:14 pm
Reputation: 1

Shadow of War research

Post by 1b0d6fe5 »

Starting this thread for anything useful related to Shadow of War, including, but not limited to:

- game engine
- game's server API
- telemetry server API
- format of files, scripts used by the game
- interesting functions/snippets from CE or IDA

If you have info that meets any of the above - post it! I don't have all the answers and I'm pretty bad at reversing so..the more the merrier!

For starters, links to previous discussions:

- SunBeam - engine goodies, includes in-game console info: viewtopic.php?f=19&t=5146
- seikur0 - CE table for modifying uruks, forcing new spawns as legendary + more. Includes code that handles reading gamedb (maybe stringdb is same way): fearlessrevolution.com/viewtopic.php?f=4&t=5132
- gregkwaste - .arch05 unpacker - used to understand .arch06 format: [Link]

Disclaimer: I'm not skilled at RE, so this may be a painful read/experience to people who actually know what they're doing.

--------------------------------

Section: game engine

Game seems to use a modified LithTech engine. I expected to find some references to certain things that older games have used. The only thing that seems common is GameClientShell. DeadlineHF did some reversing of one of the engines back in 2012: https://www.fearlessrevolution.com/forum/gene ... ersal.html

In the code (offline disassembly), I've found a bunch of functions that are from Apache Avro. Also have found references to Google's protobuf in-memory when the game is running (but not found anywhere offline). Probably need to dump the EXE while it's running to get a better picture.

--------------------------------

Section: game's server API

This is where I've spent most of my time. Client (game) sends the server requests, gets responses. Simple enough.
The content-type of these requests is "x-ag-binary", which is fairly simple most of the time:

Code: Select all

type_string = 0x30
type_date_uint32 = 0x40
type_date_uint64 = 0x17
type_map = 0x60
type_array = 0x50
type_unknown_int = 0x11 // single byte
type_unknown_int32 = 0x14 // probably uint32
type_unknown_int32_2 = 0x15 // probably uint32
type_unknown_2byte = 0x13
type_unknown_8byte = 0x21 // probably an in-game hash, can't remember where it's used
type_null = 0x01
type_bool_true = 0x02
type_bool_false = 0x03
Example of response data - some redacted becuz reasons: [Link]

The part where the game knows how many "items" to allocate from this response, dumped to be readable:

Code: Select all

"server_data": {
   "contents": {
    "2": {
     "item": "con-depl",
     "amount": {
     00000000  01                                                |.|
    },
     "content_type": "item"
   },
    "1": {
     "content_type": "uruk",
     "level_relative": true,
     "rarity": "common",
     "builder_record": "None",
     "unique_id": "XXXX",
     "element": "undefined",
     "tribe": "undefined",
     "level": {
     00000000  ff                                                |.|
    },
     "trait": "None",
     "advance_class": "undefined",
     "type": "undefined",
     "friend": true
   },
    "0": {
     "trait": "None",
     "unique_id": "XXXX",
     "type": "undefined",
     "friend": true,
     "level_relative": true,
     "tribe": "undefined",
     "advance_class": "undefined",
     "rarity": "epic",
     "builder_record": "None",
     "content_type": "uruk",
     "element": "undefined",
     "level": {
     00000000  fe                                                |.|
    }
   }
  }
 }
So the item itself (training orders as they are in game) is chosen by the server, but uruks in silver chests aren't defined - it lets the game generate it randomly. So all "undefined" fields allow the game to roll for what it will end up being.

Note that there _are_ some responses that include, say, "tribe". I did a test buy of one of the specials, and as it was a terror-only box, that's what was in the field rather than undefined.

Decoding the requests/responses is easy enough, just start at the beginning of the response. Read a byte, then read the value. May need to recurse (in the case of MAP or ARRAY). My code is extremely ugly so I haven't put it up yet. When encountering a single-byte type (eg null/bool), treat the type as the value and skip to the next.

There are an absolute ton of requests/responses to go through, but I have most of the useful ones mapped out.

One response in particular that is not understood is the one that comes back after an online invasion is complete. It does not match the spec above but still advertises x-ag-binary. I believe this is encrypted or encoded in a way that's not obvious, but seikur0 and I weren't able to figure this out yet.

---------------------

Section: game archives / format / script

I don't understand _all_ of this just yet, so bear with me. It _is_ possible to unpack .ARCH06 files, and I have a few unpacked. Within you will find some subfolders with unpacked textures/materials/etc. Some files are still packed, named ".embb". This is basically another archive.
Most times I find scripts are in .embb files.

The ".script" files you can find have a few bytes as a header - but they are plain text. Delete the bytes before the initial comment ("--") and save as a new file.

I will fill this section in more later when I have the files in front of me, but it appears that the game uses lua with some custom modifications; I see references to, say, setmetatable but also a weird keyword/func "hmake" that I am not familiar with.

Seems that these ".script" files have gone through some pre-processing step to concatenate them together, as well. There are references in comments to paths that don't seem to exist anywhere in archives, right before code, so I'm guessing their preprocessor just inserts code where it's used.

-------------

Section: Random

This will take a while to piece everything together, but if you have found anything neat, post it here, and I'll keep this thread updated with stuff as I go along.

TODO: release decoder/encoder/file unpacker
Last edited by 1b0d6fe5 on Fri Nov 03, 2017 10:08 pm, edited 1 time in total.

1b0d6fe5
Noobzor
Noobzor
Posts: 6
Joined: Thu Oct 26, 2017 5:14 pm
Reputation: 1

Re: Shadow of War research

Post by 1b0d6fe5 »

Not much to update - still figuring out the invasion format.

That being said, the response is of a special type in ag-binary.

For example, see: [Link]
First image is the first few bytes of `ssc/invasion_publish`. Second is the first few bytes from `invasion_calc_final_score`.

In both cases, type is 0x67 followed by 1-byte length and then the inner type is 0x34, followed by 2-byte length. I was thinking it was xor'd and tried bruteforcing that, but came up with nada.

Example of ssc/invasion_publish call response (there's probably some identifiable info in here, but whatever):

Code: Select all

{
  "InvasionFaction": {
   "0": {
   00000000  78 da ed 9d 67 40 13 4b  17 86 a9 d2 05 c4 01 01  |x...g@.K........|
   00000010  51 6c d8 50 43 17 af 8d  22 bd 89 08 56 30 40 02  |Ql.PC..."...V0@.|
.... snipped because it's 21161 bytes long ....
   00005280  d7 fc ef af 44 6a 57 1b  64 24 23 80 c6 7e 8e e6  |....DjW.d$#..~..|
   00005290  44 29 51 f3 43 21 ef ca  7e e4 b2 87 3f 19 b5 98  |D)Q.C!..~...?...|
   000052a0  dc 08 dc f9 1f 52 11 1c  58                       |.....R..X|
  }
 },
  "Overlord": {
   "is_severed": false,
   "boss_faction_id": 4294967295,
   "encounter_previous_index": {
   00000000  20                                                | |
  },
   "is_player_presented": true,
   "npc_profile_guid": "835c746a4fa1bbf131fb36aa5a868404_NPC_51",
   "role_name": "Role_Dragon",
   "interrogation_level": {
   00000000  02                                                |.|
  },
   "is_dead": false,
   "personality_record": 3559274028,
   "faction_col": {
   00000000  00                                                |.|
  },
   "player_kills": {
   00000000  00                                                |.|
  },
   "preset_record": {
   00000000  00                                                |.|
  },
   "unpack_product_slug": "",
   "is_warchief": false,
   "menace_level": {
   00000000  3b                                                |;|
  },
   "purpose_string_id": {
   00000000  00                                                |.|
  },
   "resurrect_applied_scartype_record": 2082198200,
   "Inventory": {
    "fmi_equipment_list": {
     "7": {
      "ID": 4294967295,
      "UnpackSlug": "",
      "WeaponData": {
      00000000  00                                                |.|
     },
      "iUpg": {
      00000000  00                                                |.|
     },
      "Affixes": {
     },
      "GUID64B": 0-snipped,
      "Sockets": {
     },
      "Source": {
      00000000  03                                                |.|
     },
      "iLvl": {
      00000000  01                                                |.|
     },
      "iNgUpgLvl": {
      00000000  00                                                |.|
     },
      "ArmorData": 601812608,
      "GUID64A": 0-snipped,
      "IsNemesisGear": false,
      "Item": 2522550989
    },
     "8": {
      "iLvl": {
      00000000  01                                                |.|
     },
      "GUID64A": 0-snipped,
      "Sockets": {
     },
      "iNgUpgLvl": {
      00000000  00                                                |.|
     },
      "iUpg": {
      00000000  00                                                |.|
     },
      "ArmorData": 1142978977,
      "GUID64B": 0-snipped,
      "ID": 4294967295,
      "Item": 2617228636,
      "Source": {
      00000000  03                                                |.|
     },
      "Affixes": {
     },
      "IsNemesisGear": false,
      "UnpackSlug": "",
      "WeaponData": {
      00000000  00                                                |.|
     }
    },
     "9": {
      "ArmorData": 2058997806,
      "GUID64B": 0-snipped,
      "Source": {
      00000000  02                                                |.|
     },
      "WeaponData": {
      00000000  00                                                |.|
     },
      "iUpg": {
      00000000  00                                                |.|
     },
      "UnpackSlug": "",
      "iLvl": {
      00000000  01                                                |.|
     },
      "Affixes": {
     },
      "IsNemesisGear": false,
      "Item": 111138598,
      "GUID64A": 0-snipped,
      "ID": 4294967295,
      "Sockets": {
     },
      "iNgUpgLvl": {
      00000000  00                                                |.|
     }
    },
     "4": {
      "GUID64B": 0-snipped,
      "IsNemesisGear": false,
      "Sockets": {
     },
      "UnpackSlug": "",
      "iLvl": {
      00000000  01                                                |.|
     },
      "iNgUpgLvl": {
      00000000  00                                                |.|
     },
      "ArmorData": 4129984516,
      "Affixes": {
     },
      "ID": 4294967295,
      "Item": 3934832671,
      "Source": {
      00000000  09                                                |.|
     },
      "GUID64A": 0-snipped,
      "iUpg": {
      00000000  00                                                |.|
     },
      "WeaponData": {
      00000000  00                                                |.|
     }
    },
     "5": {
      "UnpackSlug": "",
      "iLvl": {
      00000000  01                                                |.|
     },
      "ArmorData": 2537051847,
      "GUID64B": 0-snipped,
      "ID": 4294967295,
      "GUID64A": 0-snipped,
      "WeaponData": {
      00000000  00                                                |.|
     },
      "Sockets": {
     },
      "Source": {
      00000000  05                                                |.|
     },
      "iNgUpgLvl": {
      00000000  00                                                |.|
     },
      "iUpg": {
      00000000  00                                                |.|
     },
      "Affixes": {
     },
      "IsNemesisGear": false,
      "Item": 12386160
    },
     "6": {
      "WeaponData": {
      00000000  00                                                |.|
     },
      "iUpg": {
      00000000  00                                                |.|
     },
      "Affixes": {
     },
      "GUID64A": 0-snipped,
      "ID": 4294967295,
      "Item": 3877214803,
      "IsNemesisGear": false,
      "Sockets": {
     },
      "Source": {
      00000000  09                                                |.|
     },
      "iLvl": {
      00000000  01                                                |.|
     },
      "iNgUpgLvl": {
      00000000  00                                                |.|
     },
      "ArmorData": 576103638,
      "GUID64B": 0-snipped,
      "UnpackSlug": ""
    },
     "0": {
      "UnpackSlug": "",
      "WeaponData": 266625617,
      "iNgUpgLvl": {
      00000000  00                                                |.|
     },
      "iUpg": {
      00000000  00                                                |.|
     },
      "IsNemesisGear": false,
      "iLvl": {
      00000000  01                                                |.|
     },
      "GUID64B": 0-snipped,
      "Sockets": {
     },
      "Source": {
      00000000  02                                                |.|
     },
      "Affixes": {
     },
      "ArmorData": {
      00000000  00                                                |.|
     },
      "GUID64A": 0-snipped,
      "ID": 4294967295,
      "Item": 4123042115
    },
     "1": {
      "iLvl": {
      00000000  01                                                |.|
     },
      "iNgUpgLvl": {
      00000000  00                                                |.|
     },
      "ArmorData": {
      00000000  00                                                |.|
     },
      "Source": {
      00000000  02                                                |.|
     },
      "UnpackSlug": "",
      "IsNemesisGear": false,
      "Sockets": {
     },
      "WeaponData": 1844883171,
      "iUpg": {
      00000000  00                                                |.|
     },
      "Affixes": {
     },
      "GUID64B": 0-snipped,
      "ID": 4294967295,
      "GUID64A": 0-snipped,
      "Item": 1844883171
    },
     "2": {
      "Affixes": {
     },
      "WeaponData": 910020656,
      "iLvl": {
      00000000  01                                                |.|
     },
      "GUID64A": 0-snipped,
      "GUID64B": 0-snipped,
      "iNgUpgLvl": {
      00000000  00                                                |.|
     },
      "Item": 910020656,
      "Sockets": {
     },
      "UnpackSlug": "",
      "iUpg": {
      00000000  00                                                |.|
     },
      "ArmorData": {
      00000000  00                                                |.|
     },
      "ID": 4294967295,
      "IsNemesisGear": false,
      "Source": {
      00000000  08                                                |.|
     }
    },
     "3": {
      "GUID64B": 0-snipped,
      "Item": 1260666426,
      "ArmorData": 4004892529,
      "Sockets": {
     },
      "Source": {
      00000000  05                                                |.|
     },
      "GUID64A": 0-snipped,
      "IsNemesisGear": false,
      "iLvl": {
      00000000  01                                                |.|
     },
      "iUpg": {
      00000000  00                                                |.|
     },
      "Affixes": {
     },
      "UnpackSlug": "",
      "WeaponData": {
      00000000  00                                                |.|
     },
      "iNgUpgLvl": {
      00000000  00                                                |.|
     },
      "ID": 4294967295
    }
   },
    "smc_flaircolor_list": {
   },
    "smc_nonequipment_record_list": {
     "0": 3745640686,
     "1": 433459081,
     "2": 3209780763
   }
  },
   "is_resurrected": false,
   "levelchange_reward_list": {
    "1": 1151425910,
    "2": 3948727328,
    "0": 4225212017
  },
   "location_name": "",
   "purpose_record": {
   00000000  00                                                |.|
  },
   "random_seed": 9211279571599491072,
   "relationship_list": {
  },
   "faction_name": "Faction_volcano",
   "purpose_timeout": {
   00000000  00                                                |.|
  },
   "revengetype_record": {
   00000000  00                                                |.|
  },
   "is_mockdead": false,
   "purpose_levelremap_record": 2733249899,
   "title": "",
   "can_interrogate_about": true,
   "can_resurrect": false,
   "character_record": 1461117272,
   "last_deathtype_record": {
   00000000  00                                                |.|
  },
   "location_record": {
   00000000  00                                                |.|
  },
   "resurrect_scartype_record": {
   00000000  00                                                |.|
  },
   "trait_marker_list": {
    "20": 1865648148,
    "0": 4069624417,
    "1": 234192561,
    "3": 2548214877,
    "6": 849562412,
    "9": 1696253148,
    "18": 1386176202,
    "19": 4027762002,
    "5": 2919624496,
    "7": 2312689329,
    "8": 2892198045,
    "17": 1364491165,
    "2": 3743442058,
    "15": 1534413219,
    "4": 1879253697,
    "10": 4095116103,
    "11": 1517250837,
    "12": 1951162197,
    "13": 853232054,
    "14": 2235431975,
    "16": 1865648148
  },
   "SMCStorage": {
    "smc_storage": {
     "smc_headaccessory1_piece_record": {
     00000000  00                                                |.|
    },
     "smc_headscar_piece_record": {
     00000000  00                                                |.|
    },
     "smc_legs_piece_record": 2714542610,
     "smc_trim_color": {
     00000000  00                                                |.|
    },
     "smc_armor2_color": {
     00000000  00                                                |.|
    },
     "smc_arms_piece_record": 3690379789,
     "smc_factionmetal_color": {
     00000000  00                                                |.|
    },
     "smc_factiontrim_color": {
     00000000  00                                                |.|
    },
     "smc_helmet_piece_record": 1089417413,
     "smc_lowlod_piece_record": 2571925135,
     "smc_factioncloth_color": {
     00000000  00                                                |.|
    },
     "smc_harr_color": 4286085240,
     "smc_headModel_record": 2103969100,
     "smc_shoulder_piece_record": 2115239317,
     "smc_bodyscar_piece_record": {
     00000000  00                                                |.|
    },
     "smc_clothing1_color": {
     00000000  00                                                |.|
    },
     "smc_eye_color": 4288401144,
     "smc_factionleather_color": {
     00000000  00                                                |.|
    },
     "smc_warpaint_color": {
     00000000  00                                                |.|
    },
     "smc_accessory1_piece_record": {
     00000000  00                                                |.|
    },
     "smc_accessory2_piece_record": 714694449,
     "smc_body_piece_record": 2937841496,
     "smc_chest_piece_record": 522306648,
     "smc_pants_piece_record": 1759779879,
     "smc_armor1_color": {
     00000000  00                                                |.|
    },
     "smc_bodymodel_record": 2726823285,
     "smc_hair_piece_record": 119459683,
     "smc_head_piece_record": 2103969100,
     "smc_tattoo_color": {
     00000000  00                                                |.|
    },
     "BodyType": {
     00000000  05                                                |.|
    },
     "smc_bodyfair_piece_record": {
     00000000  00                                                |.|
    },
     "smc_clothing2_color2": {
     00000000  00                                                |.|
    },
     "smc_factionbone_color": {
     00000000  00                                                |.|
    },
     "smc_skin_color": 4290947450,
     "smc_storage_appearancetags": {
      "1": 1905260391,
      "2": 3397703289,
      "3": 3397703289,
      "4": 3397703289,
      "5": 3760787029,
      "0": 1905260391
    }
   }
  },
   "encounter_current_index": {
   00000000  20                                                | |
  },
   "is_menu_presented": true,
   "role_record": 2236231475,
   "tribe_name": "TribeDef_Sorcerous",
   "combat_tree_name": "AI_Olog_Infantry",
   "faction_id": {
   00000000  bb                                                |.|
  },
   "is_total": {
   00000000  01 4a                                             |.J|
  },
   "resurrect_count": {
   00000000  00                                                |.|
  },
   "was_ever_preset": false,
   "has_vow": false,
   "killed_by_player": false,
   "personality_name": "Olog_BlackSpeech1",
   "trait_level": {
   00000000  3b                                                |;|
  },
   "trait_picker_list": {
    "1": 3125643875,
    "24": 3816248675,
    "33": 4099751083,
    "32": 873541420,
    "2": 3107817071,
    "10": 1081335689,
    "11": 196841539,
    "14": 266214309,
    "17": 3424455350,
    "19": 564098968,
    "0": 34650999,
    "3": 422696737,
    "7": 3440649570,
    "18": 322747468,
    "29": 492727905,
    "31": 590526540,
    "4": 3440419082,
    "6": 1146543044,
    "13": 2033375197,
    "16": 12426745,
    "20": 2685642093,
    "21": 3399567032,
    "34": 3738741785,
    "9": 1657957701,
    "27": 3251978480,
    "26": 3228452947,
    "5": 2673953632,
    "12": 1410609994,
    "22": 3733170652,
    "23": 726942136,
    "28": 115361462,
    "30": 82464385,
    "8": 894047086,
    "15": 2323056476,
    "25": 2585622754
  },
   "combat_tree_record": 831844024,
   "is_revengetarget": false,
   "is_spy": false,
   "trait_picker_level_remap": 2733249899,
   "is_player_follower": true,
   "name": "snipped",
   "tribe_record": 3421778612,
   "unpack_guid": "",
   "faction_event_list": {
    "2": 2390132817,
    "6": 2390132817,
    "8": 484314232,
    "17": 2967111803,
    "25": 3339886815,
    "26": 4073141026,
    "29": 3527621889,
    "7": 4119891205,
    "16": 1742857148,
    "19": 4286371869,
    "18": 3355915467,
    "23": 1565009894,
    "20": 484314232,
    "24": 1673299765,
    "11": 222665716,
    "14": 2390132817,
    "27": 3355915467,
    "30": 1121411322,
    "0": 1469126043,
    "1": 1449785269,
    "3": 58551332,
    "4": 2390132817,
    "5": 58551332,
    "9": 2427729487,
    "12": 1673299765,
    "13": 1469126043,
    "22": 1565009894,
    "28": 3329515217,
    "31": 1121411322,
    "10": 1565009894,
    "15": 2905012611,
    "21": 1304980966
  },
   "faction_record": 430193800,
   "faction_row": {
   00000000  00                                                |.|
  },
   "name_string_id_hash": 3270444918,
   "trait_base": 2178316201
 }
}
Anyway, until this special data is decoded, it's unlikely I'll be able to write a complete server emulator.

kranebrain
What is cheating?
What is cheating?
Posts: 2
Joined: Sat Nov 04, 2017 3:28 am
Reputation: 0

Re: Shadow of War research

Post by kranebrain »

Has anyone been able to attach / debug shadow of war? I'm unable to attach. I'm a noob when it comes to anti-debugging techniques

User avatar
seikur0
Code Alchemist
Code Alchemist
Posts: 440
Joined: Sat Aug 26, 2017 10:48 am
Reputation: 339

Re: Shadow of War research

Post by seikur0 »

You'll have to use the "veh debugger" in cheat engine.

So let me add some stuff to this research thread:

There is a game_database, that consists of a header followed by 2434 themed database_lists, for example the list "Inventory/Items". Each of these database lists has a certain length and contains objects of the same type, let's call it base_object.

So these base objects are like this:

Code: Select all

base_object: (length 28 bytes)
+0: (4 bytes) integer, that encodes the list type (example 2625 means Inventory/Items)
+4: (4 bytes) hash for the object (these are hashes of their string description, so they're unique within a list but not unique for the object)
+8: (8 bytes p) pointer to another object (no clue what kind of object that is, it either consists of 4 (4 byte)-values.)
+10: (8 bytes p) pointer to data object of the base_object, these can be small lists themselves, or huge objects or float values, really anything.
+18: (8 bytes p) pointer to database_list that contains this base_object
+20: (8 bytes p) pointer to string_name of base_object (this is very useful as it gives you a good clue, what it is)
after that at +28 the next base_object in the list will start.
Now for the database_list:

Code: Select all

database_list: (length 58 bytes)
+0: (8 bytes p) pointer to string_name of database_list (very useful, together with the string_name of a base_object, you'll know what it's for)
+8: (8 bytes p) pointer to string_name_struct of database_list
+10: (8 bytes p) pointer to string_path of database_list (might be useful, when you're compiling game files)
+18: (8 bytes p) pointer to game_database header (in the header you'll find the pointer to the first database_list at +50)
+20: (8 bytes p) pointer to another object (no clue)
+28: (4 bytes) length of the list
+2c: (4 bytes) index of the list in game_database
+30: (4 bytes) always 0
+34: (4 bytes) always 0
+38: (8 bytes p) pointer to first base_object in list
+40: (4 bytes) no clue, mostly 0
+44: (4 bytes) always 0
+48: (8 bytes p) repetition of +38, if the +40 number was 0, otherwise a pointer to another object (no clue)
+50: (8 bytes p) pointer to another object (no clue, seems to be a list of 4 byte values)
And here's the uruk_object:

Code: Select all

uruk_object: (length 0x510?)
+0 to +47: several 8 byte pointers, 2 to unknown objects, 7 to their own location or a very close one (->no actual data)
--
+50: (8 bytes eo pointer) equipment left hand
--
+60: (8 bytes eo pointer) equipment right hand
+68: (8 bytes eo pointer) equipment two-handed
--
+90: (8 bytes eo pointer) equipment helmet
+98: (8 bytes eo pointer) equipment shoulders
+a0: (8 bytes eo pointer) equipment chest
+a8: (8 bytes eo pointer) equipment arms
+b0: (8 bytes eo pointer) equipment pants
+b8: (8 bytes eo pointer) equipment legs
+c0: (8 bytes eo pointer) equipment quiver
+c8: (8 bytes eo pointer) equipment accessory
+d0: (8 bytes eo pointer) equipment body
--
+e0: (8 bytes eo pointer) equipment special body
+e8: (8 bytes eo pointer) equipment special head

+f8: (8 bytes pointer) pointer to list of ?
+100: (8 bytes pointer) pointer after end of list
+104: (4 bytes) max list length
+108: (4 bytes) lowest byte 1 for existing list, otherwise 0

+130: (8 bytes pointer) pointer to pointer to faction (1)
+138: (8 bytes pointer) pointer to some faction object?

+158: (8 bytes bo pointer) faction (2)
+160: (8 bytes bo pointer) faction (3)
+168: (8 bytes bo pointer) AI
--
+178: (8 bytes pointer) pointer to list of visual abilities
+180: (8 bytes pointer) pointer after end of list
+188: (4 bytes) max list length
+18c: (4 bytes) lowest byte 1 for existing list, otherwise 0
+190: (8 bytes pointer) pointer to list of marker abilities
+198: (8 bytes pointer) pointer after end of list
+1a0: (4 bytes) max list length
+1a4: (4 bytes) lowest byte 1 for existing list, otherwise 0
+1a8 to +1bf: one more of these lists
+1c0: (8 bytes pointer) pointer to list of picker abilites
+1c8: (8 bytes pointer) pointer after end of list
+1d0: (4 bytes) max list length
+1d4: (4 bytes) lowest byte 1 for existing list, otherwise 0
+1d8: (8 bytes pointer) pointer to list of kill rewards
+1e0: (8 bytes pointer) pointer after end of list
+1e8: (4 bytes) max list length
+1ec: (4 bytes) lowest byte 1 for existing list, otherwise 0
+1f0 to +237: three more of these lists
--
+248: (8 bytes bo pointer) army row
+250: (8 bytes bo pointer) personality
+258: (8 bytes bo pointer) class
+260: (8 bytes bo pointer) trait level offset
--
+278: (8 bytes bo pointer) faction (4)

+2a8: (8 bytes bo pointer) faction (5)
+2b0: (always 0xFFFFFFFF?)
+2b8: (8 bytes mo pointer) models

+2f8:  (8 bytes bo pointer) role

+308: (8 bytes bo pointer) tribe
+310: (8 bytes bo pointer) patrol location (1)
+318: (8 bytes bo pointer) patrol location (2)

+328: (8 bytes bo pointer) wound

+370: (8 bytes bo pointer) rarity


+478: (8 bytes string) name
+480 to +497: filled with 0x80
+498: (8 bytes)level
+4a0: (8 bytes) copy of level (used for what?)

+4ac-4af: filled with 0x80
+4b0: (8 byte pointer) ??? (no clue)

+4e8: (4 byte bitmask) status (dominated/bodyguard/dead/removed flags in there)
+4ec: (4 byte bitmask) status
+4f0: (4 byte bitmask) status (name/strenghts/weaknesses known flags in there)
+4f4: (4 byte bitmask) status (always 0xFFFFFFFF?)
+4f8: (4 byte bitmask) status (either strengths or weaknesses known permanent flags in there)
+4fc: (4 byte bitmask) status
So the interesting part is, that any of these base_objects can be found in memory by using their database_list index and their own index in the list, instead of their own index you could use the hash as well. If needed you could brute force the list as well with just the hash, but at that point an aobscan for the hash would probably be faster.

And also the hashes aren't unique, since there might be objects with the same name in multiple lists. As example the Immune_Beasts base_objects, there's one in "Faction/Traits/Definitions", one in "Faction/Rewards/Definitions" and one in "Interface/Movies". These are all different, every object is only in one of the database_lists.

I dumped the whole game_database (just the strings), I'll attach that.
Attachments
game_db.7z
(1.77 MiB) Downloaded 70 times

Post Reply

Who is online

Users browsing this forum: No registered users