Skip to content

Parsing Mono

Roadmap

This is the hardest part of this whole guide. Get ready for a long and tedious process. Here is a roadmap:

  1. Get the pointer to mono root domain
  2. Parse MonoDomain struct and get domain_assemblies filed
  3. Parse MonoAssembly struct and get image filed
  4. Parse MonoImage struct and get MonoInternalHashTable field
  5. Parse MonoInternalHashTable struct and get table field
  6. Parse MonoClassDef
  7. Parse MonoClassField

By the end of this page you should have definition for all classes of the game. Mono works in such way that the runtime always have the full information about all objects. That's why mono is so "easy" to parse

Parsing the instruction

In the pervious part we got the mono_get_root_domain function that returns a pointer

c
mono_get_root_domain (void)
{
  return mono_root_domain;
}

When reading the next 8 bytes and disassembling them we get this:

hex
# 0: 48 8b 05 fc 11 44 00   mov rax, qword ptr [rip + 0x4411fc]
# 7: c3                     ret

Then we extract the offset from the instruction fc 11 44 00

relativeOffset is 0x4411fc (note that it is backwards because of the little endian)

This is a relative offset and the instruction is 7 bytes long, so

mono_root_domain is mono_get_root_domain + 7 + relativeOffset

This is the only instruction we will ever disassemble. The rest of this project is just reading C structs.

Go to mono_root_domain

MonoDomain

You are looking at _MonoDomain struct.

By the way

Get used to reading the mono source code! I will leave all the links here so that you will know where to look at.

To keep the text compact I will not copy paste C source code but I will paste my ASCII tables for the structs.

┌────────────────────────────────────────────────────────────────────┐
│ _MonoDomain                                                        │
│ Size: ??? bytes, Alignment: 8 bytes                                │
├────────────────────────────────────────────────────────────────────┤
│   0- 47 │ MonoCoopMutex   │ lock                │ 48 bytes  │      │
│  48- 55 │ MonoAppDomain*  │ domain              │ 8 bytes   │      │
│  56- 63 │ MonoAppContext* │ default_context     │ 8 bytes   │      │
│  64- 71 │ MonoException*  │ out_of_memory_ex    │ 8 bytes   │      │
│  72- 79 │ MonoException*  │ null_reference_ex   │ 8 bytes   │      │
│  80- 87 │ MonoException*  │ stack_overflow_ex   │ 8 bytes   │      │
│  88- 95 │ MonoObject*     │ typeof_void         │ 8 bytes   │      │
│  96-103 │ MonoObject*     │ ephemeron_tombstone │ 8 bytes   │      │
│ 104-111 │ MonoArray*      │ empty_types         │ 8 bytes   │      │
│ 112-119 │ MonoString*     │ empty_string        │ 8 bytes   │      │
│ 120-127 │ MonoGHashTable* │ env                 │ 8 bytes   │      │
│ 128-135 │ MonoGHashTable* │ ldstr_table         │ 8 bytes   │      │
│ 136-139 │ guint32         │ state               │ 4 bytes   │      │
│ 140-143 │ gint32          │ domain_id           │ 4 bytes   │      │
│ 144-147 │ gint32          │ shadow_serial       │ 4 bytes   │      │
│ 148-151 │                 │ [padding]           │ 4 bytes   │      │
│ 152-159 │ GSList*         │ domain_assemblies   │ 8 bytes   │ <--  │
│ 160-167 │ MonoAssembly*   │ entry_assembly      │ 8 bytes   │      │
│ 168-175 │ char*           │ friendly_name       │ 8 bytes   │ <--  │
│ ... and other fields                                               │
└────────────────────────────────────────────────────────────────────┘

Each Mono application has its own MonoDomain. It contains Mono assemblies, static variables and heap.

Go to char* friendly_name. Read ZT string. Strings are your best friends in this project. If you are reading a string and it comes out as readable text, it means that your offsets are correct and you're doing everything right

Go to GSList* domain_assemblies

GSList

You are looking at a GSList

GSList is a linked list.

 ┌────────────────────────────────────────────────────────────────────┐
 │ _GSList                                                            │
 │ Size: 16 bytes, Alignment: 8 bytes                                 │
 ├────────────────────────────────────────────────────────────────────┤
 │   0-  7 │ gpointer*       │ data    │ 8 bytes   │ <--              │
 │   8- 15 │ GSList*         │ next    │ 8 bytes   │ <--              │
 └────────────────────────────────────────────────────────────────────┘

Read gpointer* data. Save it. It is a general pointer with no way to know what it is pointing to (: cool, right? It points to _MonoAssembly

Goto GSList* next. If it is zero, you have reached the end of the list.

Repeat until you reach the end.

Goto each gpointer* data

MonoAssembly

You are looking at MonoAssembly

MonoAssembly is a in-memory representation of a .NET dll. If you open any .NET dll with dotPeek or any other decompiler you will see something like these

a

These are just 4 random assemblies from the game. Core being the most important one

Assemblies can be quite large. So instead of parsing all of them, let's first get the name of each one and only parse the one we need.

 ┌────────────────────────────────────────────────────────────────────────────────────────┐
 │ _MonoAssembly                                                                          │
 │ Size: 128 bytes, Alignment: 8 bytes                                                    │
 ├────────────────────────────────────────────────────────────────────────────────────────┤
 │   0-  3 │ gint32               │ ref_count                        │ 4 bytes   │        │
 │   4-  7 │                      │ [padding]                        │ 4 bytes   │        │
 │   8- 15 │ char*                │ basedir                          │ 8 bytes   │        │
 │  16- 95 │ MonoAssemblyName     │ aname                            │ 80 bytes  │ <--    │
 │  96-103 │ MonoImage*           │ image                            │ 8 bytes   │ <--    │
 │ 104-111 │ GSList*              │ friend_assembly_names            │ 8 bytes   │        │
 │ 112-112 │ guint8               │ friend_assembly_names_inited     │ 1 byte    │        │
 │ 113-113 │ guint8               │ in_gac                           │ 1 byte    │        │
 │ 114-114 │ guint8               │ dynamic                          │ 1 byte    │        │
 │ 115-115 │ guint8               │ corlib_internal                  │ 1 byte    │        │
 │ 116-119 │ MonoAssemblyContext  │ context                          │ 4 bytes   │        │
 │ 120-120 │ guint8               │ wrap_non_exception_throws        │ 1 byte    │        │
 │ 121-121 │ guint8               │ wrap_non_exception_throws_inited │ 1 byte    │        │
 │ 122-122 │ guint8               │ jit_optimizer_disabled           │ 1 byte    │        │
 │ 123-123 │ guint8               │ jit_optimizer_disabled_inited    │ 1 byte    │        │
 │ 124-127 │ guint32              │ flags                            │ 4 bytes   │        │
 └────────────────────────────────────────────────────────────────────────────────────────┘
 ┌────────────────────────────────────────────────────────────────────────────────────────┐
 │ MonoAssemblyName                                                                       │
 │ Size: 80 bytes, Alignment: 8 bytes                                                     │
 ├────────────────────────────────────────────────────────────────────────────────────────┤
 │   0-  7 │ char*                │ name                     │ 8 bytes   │ <--            │
 │   8- 15 │ char*                │ culture                  │ 8 bytes   │                │
 │  16- 23 │ char*                │ hash_value               │ 8 bytes   │                │
 │  24- 31 │ mono_byte*           │ public_key               │ 8 bytes   │                │
 │  32- 48 │ mono_byte            │ public_key_token         │ 17 bytes  │                │
 │  49- 51 │                      │ [padding]                │ 3 bytes   │                │
 │  52- 55 │ uint32_t             │ hash_alg                 │ 4 bytes   │                │
 │  56- 59 │ uint32_t             │ hash_len                 │ 4 bytes   │                │
 │  60- 63 │ uint32_t             │ flags                    │ 4 bytes   │                │
 │  64- 65 │ uint16_t             │ major                    │ 2 bytes   │                │
 │  66- 67 │ uint16_t             │ minor                    │ 2 bytes   │                │
 │  68- 69 │ uint16_t             │ build                    │ 2 bytes   │                │
 │  70- 71 │ uint16_t             │ revision                 │ 2 bytes   │                │
 │  72- 73 │ uint16_t             │ arch                     │ 2 bytes   │                │
 │  74- 74 │ MonoBoolean          │ without_version          │ 1 byte    │                │
 │  75- 75 │ MonoBoolean          │ without_culture          │ 1 byte    │                │
 │  76- 76 │ MonoBoolean          │ without_public_key_token │ 1 byte    │                │
 │  77- 79 │                      │ [padding]                │ 3 bytes   │                │
 └────────────────────────────────────────────────────────────────────────────────────────┘

TIP

MonoAssemblyName aname is a struct, not a pointer. It is inlined.

Goto MonoAssemblyName aname. Read a ZT string.

We are only interested an assembly with a name Core.

Goto MonoImage* image

MonoImage

You are looking at MonoImage

Mono assembly is just a container for Mono image. It describes the structures of all classes and methods

 ┌───────────────────────────────────────────────────────────────────────────────────┐
 │ _MonoImage                                                                        │
 │ Size: 1272 bytes, Alignment: 8 bytes                                              │
 ├───────────────────────────────────────────────────────────────────────────────────┤
 │    0-   3 │ int                       │ ref_count              │ 4 bytes   │      │
 │    4-   7 │                           │ [padding]              │ 4 bytes   │      │
 │    8-  15 │ MonoImageStorage*         │ storage                │ 8 bytes   │      │
 │   16-  23 │ char*                     │ raw_data               │ 8 bytes   │      │
 │   24-  27 │ guint32                   │ raw_data_len           │ 4 bytes   │      │
 │   28-  28 │ guint8                    │ dynamic                │ 1 byte    │      │
 │   29-  29 │ guint8                    │ ref_only               │ 1 byte    │      │
 │   30-  30 │ guint8                    │ uncompressed_metadata  │ 1 byte    │      │
 │   31-  31 │ guint8                    │ metadata_only          │ 1 byte    │      │
 │   32-  32 │ guint8                    │ load_from_context      │ 1 byte    │      │
 │   33-  33 │ guint8                    │ checked_module_cctor   │ 1 byte    │      │
 │   34-  34 │ guint8                    │ has_module_cctor       │ 1 byte    │      │
 │   35-  35 │ guint8                    │ idx_string_wide        │ 1 byte    │      │
 │   36-  36 │ guint8                    │ idx_guid_wide          │ 1 byte    │      │
 │   37-  37 │ guint8                    │ idx_blob_wide          │ 1 byte    │      │
 │   38-  38 │ guint8                    │ core_clr_platform_code │ 1 byte    │      │
 │   39-  39 │ guint8                    │ minimal_delta          │ 1 byte    │      │
 │   40-  47 │ char*                     │ name                   │ 8 bytes   │      │
 │   48-  55 │ char*                     │ filename               │ 8 bytes   │      │
 │   56-  63 │ char*                     │ assembly_name          │ 8 bytes   │      │
 │   64-  71 │ char*                     │ module_name            │ 8 bytes   │      │
 │   72-  75 │ guint32                   │ time_date_stamp        │ 4 bytes   │      │
 │   76-  79 │                           │ [padding]              │ 4 bytes   │      │
 │   80-  87 │ char*                     │ version                │ 8 bytes   │      │
 │   88-  89 │ gint16                    │ md_version_major       │ 2 bytes   │      │
 │   90-  91 │ gint16                    │ md_version_minor       │ 2 bytes   │      │
 │   92-  95 │                           │ [padding]              │ 4 bytes   │      │
 │   96- 103 │ char*                     │ guid                   │ 8 bytes   │      │
 │  104- 111 │ MonoCLIImageInfo*         │ image_info             │ 8 bytes   │      │
 │  112- 119 │ MonoMemPool*              │ mempool                │ 8 bytes   │      │
 │  120- 127 │ char*                     │ raw_metadata           │ 8 bytes   │      │
 │  128- 143 │ MonoStreamHeader          │ heap_strings           │ 16 bytes  │      │
 │  144- 159 │ MonoStreamHeader          │ heap_us                │ 16 bytes  │      │
 │  160- 175 │ MonoStreamHeader          │ heap_blob              │ 16 bytes  │      │
 │  176- 191 │ MonoStreamHeader          │ heap_guid              │ 16 bytes  │      │
 │  192- 207 │ MonoStreamHeader          │ heap_tables            │ 16 bytes  │      │
 │  208- 223 │ MonoStreamHeader          │ heap_pdb               │ 16 bytes  │      │
 │  224- 231 │ char*                     │ tables_base            │ 8 bytes   │      │
 │  232- 239 │ guint64                   │ referenced_tables      │ 8 bytes   │      │
 │  240- 247 │ int*                      │ referenced_table_rows  │ 8 bytes   │      │
 │  248-1127 │ MonoTableInfo             │ tables                 │ 880 bytes │      │
 │ 1128-1135 │ MonoAssembly**            │ references             │ 8 bytes   │      │
 │ 1136-1139 │ int                       │ nreferences            │ 4 bytes   │      │
 │ 1140-1143 │                           │ [padding]              │ 4 bytes   │      │
 │ 1144-1151 │ MonoImage**               │ modules                │ 8 bytes   │      │
 │ 1152-1155 │ guint32                   │ module_count           │ 4 bytes   │      │
 │ 1156-1159 │                           │ [padding]              │ 4 bytes   │      │
 │ 1160-1167 │ gboolean*                 │ modules_loaded         │ 8 bytes   │      │
 │ 1168-1175 │ MonoImage**               │ files                  │ 8 bytes   │      │
 │ 1176-1179 │ guint32                   │ file_count             │ 4 bytes   │      │
 │ 1180-1183 │                           │ [padding]              │ 4 bytes   │      │
 │ 1184-1191 │ MonoAotModule*            │ aot_module             │ 8 bytes   │      │
 │ 1192-1207 │ guint8                    │ aotid                  │ 16 bytes  │      │
 │ 1208-1215 │ MonoAssembly*             │ assembly               │ 8 bytes   │      │
 │ 1216-1223 │ MonoAssemblyLoadContext*  │ alc                    │ 8 bytes   │      │
 │ 1224-1231 │ GHashTable*               │ method_cache           │ 8 bytes   │      │
 │ 1232-1271 │ MonoInternalHashTable     │ class_cache            │ 40 bytes  │ <--  │
 │ ... and other fields                                                              │
 └───────────────────────────────────────────────────────────────────────────────────┘
 ┌───────────────────────────────────────────────────────────────────────────────────┐
 │ _MonoInternalHashTable                                                            │
 │ Size: 40 bytes, Alignment: 8 bytes                                                │
 ├───────────────────────────────────────────────────────────────────────────────────┤
 │    0-   7 │ GHashFunc*                      │ hash_func   │ 8 bytes   │           │
 │    8-  15 │ MonoInternalHashKeyExtractFunc* │ key_extract │ 8 bytes   │           │
 │   16-  23 │ MonoInternalHashNextValueFunc*  │ next_value  │ 8 bytes   │           │
 │   24-  27 │ gint                            │ size        │ 4 bytes   │ <--       │
 │   28-  31 │ gint                            │ num_entries │ 4 bytes   │ <--       │
 │   32-  39 │ gpointer*                       │ table       │ 8 bytes   │ <--       │
 └───────────────────────────────────────────────────────────────────────────────────┘

We are interested in MonoInternalHashTable

Unsurprisingly, it is a hash table.

Read gint size. Number of bytes that takes the array at gpointer* table.

num_lines is gint size / 8. How many elements are in gpointer* table

Read gint num_entries. (optional) Number of elements in the entire hash table

Read gpointer* table. Pointer to an array of pointers to MonoClassDef

Go to gpointer* table and read num_lines pointers

You now have an array of pointers to MonoClassDef

Go to each pointer

MonoClassDef

You are looking at MonoClassDef

And also you are looking at MonoClass, because it is right at the start of the struct

 ┌──────────────────────────────────────────────────────────────┐
 │ _MonoClassDef                                                │
 │ Size: 264 bytes, Alignment: 8 bytes                          │
 ├──────────────────────────────────────────────────────────────┤
 │    0- 231 │ MonoClass  │ klass            │ 232 bytes │ <--  │
 │  232- 235 │ guint32    │ flags            │ 4 bytes   │      │
 │  236- 239 │ guint32    │ first_method_idx │ 4 bytes   │      │
 │  240- 243 │ guint32    │ first_field_idx  │ 4 bytes   │      │
 │  244- 247 │ guint32    │ method_count     │ 4 bytes   │      │
 │  248- 251 │ guint32    │ field_count      │ 4 bytes   │ <--  │
 │  252- 255 │            │ [padding]        │ 4 bytes   │      │
 │  256- 263 │ MonoClass* │ next_class_cache │ 8 bytes   │ <--  │
 └──────────────────────────────────────────────────────────────┘

Read MonoClass* next_class_cache. It points to the next MonoClassDef. If it is 0 you have reached the end

Read guint32 field_count. It is the number of fields in this MonoClass

Process MonoClass klass as described in the next section

Go to MonoClass* next_class_cache

Repeat until the end

MonoClass

You are looking at MonoClass

Mono class is exactly what it sounds like. We have reached the actual class definition.

 ┌───────────────────────────────────────────────────────────────────────────────────┐
 │ _MonoClass                                                                        │
 │ Size: 232 bytes, Alignment: 8 bytes                                               │
 ├───────────────────────────────────────────────────────────────────────────────────┤
 │    0-   7 │ MonoClass*            │ element_class            │ 8 bytes   │ <--    │
 │    8-  15 │ MonoClass*            │ cast_class               │ 8 bytes   │        │
 │   16-  23 │ MonoClass*            │ supertypes               │ 8 bytes   │        │
 │   24-  25 │ guint16               │ idepth                   │ 2 bytes   │        │
 │   26-  26 │ guint8                │ rank                     │ 1 byte    │        │
 │   27-  27 │ guint8                │ class_kind               │ 1 byte    │        │
 │   28-  31 │ guint                 │ bitfields1               │ 4 bytes   │ <--    │
 │   32-  32 │ guint8                │ min_align                │ 1 byte    │        │
 │   33-  33 │                       │ bitfields2               │ 1 byte    │        │
 │   34-  34 │                       │ bitfields3               │ 1 byte    │        │
 │   35-  35 │                       │ bitfields4               │ 1 byte    │        │
 │   36-  39 │                       │ [padding]                │ 4 bytes   │        │
 │   40-  47 │ MonoClass*            │ parent                   │ 8 bytes   │ <--    │
 │   48-  55 │ MonoClass*            │ nested_in                │ 8 bytes   │        │
 │   56-  63 │ MonoImage*            │ image                    │ 8 bytes   │        │
 │   64-  71 │ const char*           │ name                     │ 8 bytes   │ <--    │
 │   72-  79 │ const char*           │ name_space               │ 8 bytes   │ <--    │
 │   80-  83 │ guint32               │ type_token               │ 4 bytes   │        │
 │   84-  87 │ int                   │ vtable_size              │ 4 bytes   │        │
 │   88-  89 │ guint16               │ interface_count          │ 2 bytes   │        │
 │   90-  91 │                       │ [padding]                │ 2 bytes   │        │
 │   92-  95 │ guint32               │ interface_id             │ 4 bytes   │        │
 │   96-  99 │ guint32               │ max_interface_id         │ 4 bytes   │        │
 │  100- 101 │ guint16               │ interface_offsets_count  │ 2 bytes   │        │
 │  102- 103 │                       │ [padding]                │ 2 bytes   │        │
 │  104- 111 │ MonoClass*            │ interfaces_packed        │ 8 bytes   │        │
 │  112- 119 │ guint16*              │ interface_offsets_packed │ 8 bytes   │        │
 │  120- 127 │ guint8*               │ interface_bitmap         │ 8 bytes   │        │
 │  128- 135 │ MonoClass*            │ interfaces               │ 8 bytes   │        │
 │  136- 139 │ union _MonoClassSizes │ sizes                    │ 4 bytes   │ <--    │
 │  140- 143 │                       │ [padding]                │ 4 bytes   │        │
 │  144- 151 │ MonoClassField*       │ fields                   │ 8 bytes   │ <--    │
 │  152- 159 │ MonoMethod*           │ methods                  │ 8 bytes   │        │
 │  160- 175 │ MonoType              │ this_arg                 │ 16 bytes  │ <--    │
 │  176- 191 │ MonoType              │ _byval_arg               │ 16 bytes  │        │
 │  192- 199 │ MonoGCDescriptor*     │ gc_descr                 │ 8 bytes   │        │
 │  200- 207 │ MonoClassRuntimeInfo* │ runtime_info             │ 8 bytes   │ <--    │
 │  208- 215 │ MonoMethod*           │ vtable                   │ 8 bytes   │        │
 │  216- 223 │ MonoPropertyBag*      │ infrequent_data          │ 8 bytes   │        │
 │  224- 231 │ void*                 │ unity_user_data          │ 8 bytes   │        │
 └───────────────────────────────────────────────────────────────────────────────────┘

Read MonoClass* element_class. Only used for arrays and enums. If you'll have a someType[] then element_class will be a pointer to a MonoClass of someType

Read MonoClass* parent. It is a pointer to a parent class definition

Go to char* name. Read ZT String. it is a name of the class

Go to char* name_space. Read ZT String. it is a namespace in which the class is located

Read union _MonoClassSizes sizes. It is an int32 value contains the size of the struct that can be created from this MonoClass

Go to the start of MonoType this_arg. Continue reading MonoType

Go to MonoClassRuntimeInfo* runtime_info. Continue reading MonoClassRuntimeInfo

Go to MonoClassField* fields. Continue reading MonoClassField

MonoType

You are looking at a MonoType

┌───────────────────────────────────────────────────────────────┐
│ MonoType                                                      │
│ Size: 16 bytes, Alignment: 8 bytes                            │
├───────────────────────────────────────────────────────────────┤
│    0-   7 │ Union MonoClass* │ klass     │ 8 bytes   │ <--    │
│    8-  11 │ unsigned int     │ bitfields │ 4 bytes   │ <--    │
│   12-  15 │                  │ [padding] │ 4 bytes   │        │
└───────────────────────────────────────────────────────────────┘
c
struct _MonoType {
 union {
  MonoClass *klass; /* for VALUETYPE and CLASS */
  MonoType *type;   /* for PTR */
  MonoArrayType *array; /* for ARRAY */
  MonoMethodSignature *method;
  MonoGenericParam *generic_param; /* for VAR and MVAR */
  MonoGenericClass *generic_class; /* for GENERICINST */
 } data;
 unsigned int attrs     : 16; /* param attributes or field flags */
 MonoTypeEnum type      : 8;
 unsigned int has_cmods : 1;
 unsigned int byref     : 1;
 unsigned int pinned    : 1;  /* valid when included in a local var signature */
};

Read MonoClass* klass. It is a pointer to a type of a field

Read bitfields. Use these bit shifts to get isStatic, isConstant, typeCode

isStatic = (bitfields & 0x10) == 0x10
isConstant = (bitfields & 0x40) == 0x40
typeCode = 0xff & (bitfields >> 16)

TypeCode is exactly what it sounds like. It is a type of a value. Look into the source code

MonoClassRuntimeInfo

You are looking at MonoClassRuntimeInfo

┌───────────────────────────────────────────────────────────────┐
│ MonoClassRuntimeInfo                                          │
│ Size: 16 bytes, Alignment: 8 bytes                            │
├───────────────────────────────────────────────────────────────┤
│    0-   1 │ guint16      │ max_domain    │ 2 bytes   │        │
│    2-   7 │              │ [padding]     │ 6 bytes   │        │
│    8-  15 │ MonoVTable*  │ domain_vtables│ 8 bytes   │ <--    │
└───────────────────────────────────────────────────────────────┘

Read MonoVTable *domain_vtables. We can later use this value to find objects of this class in heap memory.

MonoClassField

You are looking at an array of MonoClassField

Earlier in MonoClassDef you've read field_count. It is a length of this array.

┌───────────────────────────────────────────────────────────────┐
│ _MonoClassField                                               │
│ Size: 32 bytes, Alignment: 8 bytes                            │
├───────────────────────────────────────────────────────────────┤
│    0-   7 │ MonoType*   │ type      │ 8 bytes   │ <--         │
│    8-  15 │ char*       │ name      │ 8 bytes   │ <--         │
│   16-  23 │ MonoClass*  │ parent    │ 8 bytes   │ <--         │
│   24-  27 │ int         │ offset    │ 4 bytes   │ <--         │
│   28-  31 │             │ [padding] │ 4 bytes   │             │
└───────────────────────────────────────────────────────────────┘

Go to MonoType* type. Continue reading MonoType. You already read it before for the class but now you need to do it for each field of the class

Go to char* name. Read ZT String. It is a name of the class field.

Read MonoClass* parent. (Optional) Pointer to the parent class. Can read to double check yourself.

Read int offset. It is an offset from the start of the object. The field will be located in memory at objectPtr+offset. Will be relevant in next page of the guide.

Conclusion

After traversing all of these structs you should now have the following data

  • Core Assembly. (Or even all assemblies).
  • Each assembly has Classes
  • Each class has fields
  • Each field has a type and an offset

Using this information you can now parse actual structs in memory. But we need to find them first.