Skip to content

Commit cba07ec

Browse files
authored
Potential native rsz name (#783)
* add order index to reflection_property * guess potential native type name
1 parent 0c333b9 commit cba07ec

File tree

2 files changed

+270
-7
lines changed

2 files changed

+270
-7
lines changed

reversing/rsz/non-native-dumper.py

Lines changed: 268 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ def als(align, size):
2727
"C16": als(2, 2),
2828
"S16": als(2, 2),
2929
"U16": als(2, 2),
30+
"F16": als(2, 2),
3031

3132
"S32": als(4, 4),
3233
"U32": als(4, 4),
@@ -41,19 +42,230 @@ def als(align, size):
4142
"Resource": als(4, 4),
4243
"String": als(4, 4),
4344
"RuntimeType": als(4, 4),
45+
46+
"Quaternion": als(16, 16),
47+
"Guid": als(8, 16),
48+
"GameObjectRef": als(8, 16),
49+
"Color": als(4, 4),
50+
"DateTime": als(8, 8),
51+
# Enum could have variable size and alignment, so we fallback to its base type and never use it.
52+
53+
"Uint2": als(4, 8),
54+
"Uint3": als(4, 12),
55+
"Uint4": als(4, 16),
56+
"Int2": als(4, 8),
57+
"Int3": als(4, 12),
58+
"Int4": als(4, 16),
59+
"Float2": als(4, 8),
60+
"Float3": als(4, 12),
61+
"Float4": als(4, 16),
62+
"Mat4": als(16, 64),
63+
"Vec2": als(16, 16),
64+
"Vec3": als(16, 16),
65+
"Vec4": als(16, 16),
66+
67+
"AABB": als(16, 32),
68+
"Capsule": als(16, 48),
69+
"Cone": als(16, 32),
70+
"LineSegment": als(16, 32),
71+
"OBB": als(16, 80),
72+
"Plane": als(16, 16),
73+
"Point": als(4, 8),
74+
"Range": als(4, 8),
75+
"RangeI": als(4, 8),
76+
"Size": als(4, 8),
77+
"Sphere": als(16, 16),
78+
"Triangle": als(16, 48),
79+
"Cylinder": als(16, 48),
80+
"Area": als(16, 48),
81+
"Rect": als(4, 16),
82+
"Frustum": als(16, 96),
83+
"KeyFrame": als(16, 16),
84+
85+
"Sfix": als(4, 4),
86+
"Sfix2": als(4, 8),
87+
"Sfix3": als(4, 12),
88+
"Sfix4": als(4, 16),
89+
}
90+
91+
hardcoded_native_type_to_TypeCode = {
92+
'float': 'F32',
93+
'int': 'S32',
94+
'size_t': 'U32',
95+
96+
'via.GameObject': 'Object',
97+
98+
'System.Boolean': 'Bool',
99+
'System.Char': 'C8',
100+
'System.SByte': 'S8',
101+
'System.Byte': 'U8',
102+
'System.Int16': 'S16',
103+
'System.UInt16': 'U16',
104+
'System.Int32': 'S32',
105+
'System.UInt32': 'U32',
106+
'System.Int64': 'S64',
107+
'System.UInt64': 'U64',
108+
'System.Single': 'F32',
109+
'System.Double': 'F64',
44110
}
45111

46-
def generate_native_name(element):
112+
TypeCode = [
113+
# "Undefined",
114+
"Object",
115+
"Action",
116+
"Struct",
117+
"NativeObject",
118+
"Resource",
119+
"UserData",
120+
"Bool",
121+
"C8",
122+
"C16",
123+
"S8",
124+
"U8",
125+
"S16",
126+
"U16",
127+
"S32",
128+
"U32",
129+
"S64",
130+
"U64",
131+
"F32",
132+
"F64",
133+
"String",
134+
"MBString",
135+
"Enum",
136+
"Uint2",
137+
"Uint3",
138+
"Uint4",
139+
"Int2",
140+
"Int3",
141+
"Int4",
142+
"Float2",
143+
"Float3",
144+
"Float4",
145+
"Float3x3",
146+
"Float3x4",
147+
"Float4x3",
148+
"Float4x4",
149+
"Half2",
150+
"Half4",
151+
"Mat3",
152+
"Mat4",
153+
"Vec2",
154+
"Vec3",
155+
"Vec4",
156+
"VecU4",
157+
"Quaternion",
158+
"Guid",
159+
"Color",
160+
"DateTime",
161+
"AABB",
162+
"Capsule",
163+
"TaperedCapsule",
164+
"Cone",
165+
"Line",
166+
"LineSegment",
167+
"OBB",
168+
"Plane",
169+
"PlaneXZ",
170+
"Point",
171+
"Range",
172+
"RangeI",
173+
"Ray",
174+
"RayY",
175+
"Segment",
176+
"Size",
177+
"Sphere",
178+
"Triangle",
179+
"Cylinder",
180+
"Ellipsoid",
181+
"Area",
182+
"Torus",
183+
"Rect",
184+
"Rect3D",
185+
"Frustum",
186+
"KeyFrame",
187+
"Uri",
188+
"GameObjectRef",
189+
"RuntimeType",
190+
"Sfix",
191+
"Sfix2",
192+
"Sfix3",
193+
"Sfix4",
194+
"Position",
195+
"F16",
196+
"Decimal",
197+
# "End",
198+
]
199+
200+
TypeCodeSearch = dict([(k.lower(),v) for k,v in hardcoded_native_type_to_TypeCode.items()] + [(a.lower(), a) for a in TypeCode] + [("via."+a.lower(), a) for a in TypeCode] + [("system."+a.lower(), a) for a in TypeCode])
201+
# print(TypeCodeSearch)
202+
203+
def generate_native_name(element, use_potential_name, reflection_property, il2cpp_dump={}):
47204
if element is None:
48205
os.system("Error")
49206

50207
if element["string"] == True:
208+
if use_potential_name:
209+
property_type = reflection_property["type"]
210+
type_code = TypeCodeSearch.get(property_type.lower(), "Data")
211+
212+
if type_code == "Data" and property_type.startswith("via."):
213+
native_element = il2cpp_dump.get(property_type, None)
214+
215+
if native_element is None:
216+
if (property_type.endswith("ResourceHandle") or property_type.endswith("ResorceHandle")) and property_type.startswith("via."):
217+
property_type = property_type.replace("ResourceHandle", "ResourceHolder")
218+
property_type = property_type.replace("ResorceHandle", "ResorceHolder") # arrrrrrrrrr
219+
native_element = il2cpp_dump.get(property_type, None)
220+
chain = native_element.get('deserializer_chain', None)
221+
222+
if "via.ResourceHolder" in [a['name'] for a in chain]: # ResourcePath
223+
return "Resource"
224+
else:
225+
if type_code in ["C16","C8","String"]:
226+
return "String"
227+
228+
return type_code
51229
return "String"
52230
elif element["list"] == True:
53-
return generate_native_name(element["element"])
54-
231+
return generate_native_name(element["element"], use_potential_name, reflection_property, il2cpp_dump)
232+
elif use_potential_name and reflection_property is not None:
233+
property_type = reflection_property["type"]
234+
type_code = TypeCodeSearch.get(property_type.lower(), "Data")
235+
236+
if type_code == "Data" and property_type.startswith("via."):
237+
native_element = il2cpp_dump.get(property_type, None)
238+
239+
if native_element is None:
240+
return type_code
241+
242+
parent = native_element.get('parent', None)
243+
if parent is not None:
244+
parent_type_code = TypeCodeSearch.get(parent.lower(), "Data")
245+
if parent_type_code != 'Data':
246+
return parent_type_code
247+
248+
chain = native_element.get('deserializer_chain', None)
249+
if chain is not None:
250+
for chain_i in reversed(chain):
251+
chain_type_code = TypeCodeSearch.get(chain_i['name'].lower(), "Data")
252+
if chain_type_code != 'Data':
253+
return chain_type_code
254+
255+
return type_code
55256
return "Data"
56257

258+
def enum_fallback(reflection_property, il2cpp_dump={}):
259+
native_element = il2cpp_dump.get(reflection_property["type"], None)
260+
# Enum type should have and only have one "RSZ" field. These check are just for safety.
261+
if native_element is None:
262+
return "Enum"
263+
if "RSZ" not in native_element:
264+
return "Enum"
265+
if len(native_element["RSZ"]) != 1:
266+
return "Enum"
267+
return native_element["RSZ"][0]["code"]
268+
57269
def generate_field_entries(il2cpp_dump, natives, key, il2cpp_entry, use_typedefs, prefix = "", i=0, struct_i=0):
58270
e = il2cpp_entry
59271
parent_name = key
@@ -85,14 +297,64 @@ def generate_field_entries(il2cpp_dump, natives, key, il2cpp_entry, use_typedefs
85297
struct_str = struct_str + "// " + chain["name"] + " BEGIN\n"
86298

87299
layout = chain["layout"]
88-
for field in layout:
89-
native_type_name = generate_native_name(field)
300+
301+
# Get reflection_properties for guessing native type name.
302+
reflection_properties = il2cpp_dump[chain["name"]].get("reflection_properties", None)
303+
append_potential_name = False
304+
305+
# If len not match, we give-up
306+
if len(layout) == len(reflection_properties):
307+
append_potential_name = True
308+
309+
# sort reflection_properties by its native order
310+
order_rp = [(int(v["order"]), (k,v)) for k, v in reflection_properties.items()]
311+
reflection_properties = dict([v for _, v in sorted(order_rp)])
312+
313+
# check align and size to increase accuracy
314+
for (property_name, property_value), field in zip(reflection_properties.items(), layout):
315+
property_type_code = generate_native_name(field, True, property_value, il2cpp_dump)
316+
317+
if property_type_code == "Enum":
318+
property_type_code = enum_fallback(property_value, il2cpp_dump)
319+
320+
reflection_properties[property_name]["TypeCode"] = property_type_code
321+
322+
if property_type_code == "Data":
323+
continue
324+
if "element" in field and "list" in field and field["list"] == True:
325+
field_align = field["element"]["align"]
326+
field_size = field["element"]["size"]
327+
else:
328+
field_align = field["align"]
329+
field_size = field["size"]
330+
331+
property_align = hardcoded_align_sizes[property_type_code]["align"]
332+
property_size = hardcoded_align_sizes[property_type_code]["size"]
333+
334+
if property_align != field_align or property_size != field_size:
335+
append_potential_name = False
336+
337+
if append_potential_name:
338+
rp_names = list(reflection_properties.keys())
339+
rp_values = list(reflection_properties.values())
340+
341+
for rp_idx, field in enumerate(layout):
90342
native_field_name = "v" + str(i)
343+
if not append_potential_name:
344+
native_type_name = generate_native_name(field, False, None)
345+
native_org_type_name = ""
346+
else:
347+
native_type_name = rp_values[rp_idx]["TypeCode"]
348+
native_field_name += "_" + rp_names[rp_idx]
349+
# native_field_name = rp_names[rp_idx] # without start with v_
350+
native_org_type_name = rp_values[rp_idx]['type']
351+
if native_type_name != "Data" and not native_org_type_name.startswith("via"):
352+
native_org_type_name = "" # those would be sth like "bool" "s32"
91353

92354
new_entry = {
93355
"type": native_type_name,
94356
"name": native_field_name,
95-
"original_type": "",
357+
"original_type": native_org_type_name,
96358
"align": field["align"],
97359
"size": field["size"],
98360
"native": True

src/mods/tools/ObjectExplorer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1920,7 +1920,7 @@ void ObjectExplorer::generate_sdk() {
19201920
// Generate Properties
19211921
if (fields->variables != nullptr && fields->variables != nullptr && fields->variables->data != nullptr) {
19221922
auto descriptors = fields->variables->data->descriptors;
1923-
1923+
auto reflection_property_index = 0;
19241924
for (auto i = descriptors; i != descriptors + fields->variables->num; ++i) {
19251925
auto variable = *i;
19261926

@@ -1967,6 +1967,7 @@ void ObjectExplorer::generate_sdk() {
19671967
prop_entry = {
19681968
{"getter", (std::stringstream{} << "0x" << std::hex << get_original_va(variable->function)).str()},
19691969
{"type", field_t_name},
1970+
{"order", reflection_property_index++},
19701971
};
19711972
#endif
19721973

0 commit comments

Comments
 (0)