Skip to content

Commit ebadfdc

Browse files
authored
Enhance metadata checks and error handling in dotnetpe
Added checks for metadata presence and improved error handling when accessing tables in dotnetpe.
1 parent d0905e7 commit ebadfdc

1 file changed

Lines changed: 34 additions & 17 deletions

File tree

src/rat_king_parser/config_parser/utils/dotnetpe_payload.py

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ def __init__(
7373
self.dotnetpe = dnPE(data=self.data, clr_lazy_load=True)
7474
else:
7575
self.dotnetpe = dnPE(self.file_path, clr_lazy_load=True)
76+
if not self.dotnetpe.net or not self.dotnetpe.net.mdtables:
77+
raise ConfigParserException("Failed to load project as dotnet executable (missing Metadata)")
7678
except Exception:
7779
raise ConfigParserException("Failed to load project as dotnet executable")
7880

@@ -88,17 +90,19 @@ def __init__(
8890
self._tokens = [m.token for m in self._methods_by_token]
8991

9092
# Pre-compute FieldRva mapping for O(1) lookups
91-
self._field_rva_map = {
92-
row.struct.Field_Index: row.struct.Rva
93-
for row in self.dotnetpe.net.mdtables.FieldRva
94-
}
93+
self._field_rva_map = {}
94+
if getattr(self.dotnetpe.net.mdtables, "FieldRva", None):
95+
self._field_rva_map = {
96+
row.struct.Field_Index: row.struct.Rva
97+
for row in self.dotnetpe.net.mdtables.FieldRva
98+
}
9599

96100
# Given a byte array's size and RVA, translates the RVA to the offset of
97101
# the byte array and returns the bytes of the array as a byte string
98102
def byte_array_from_size_and_rva(self, arr_size: int, arr_rva: int) -> bytes:
99103
arr_field_rva = self.fieldrva_from_rva(arr_rva)
100104
arr_offset = self.offset_from_rva(arr_field_rva)
101-
return self.data[arr_offset : arr_offset + arr_size]
105+
return self.data[arr_offset: arr_offset + arr_size]
102106

103107
# Given an offset, and either a terminating offset or delimiter, extracts
104108
# the byte string
@@ -122,7 +126,10 @@ def byte_string_from_offset(
122126
# Given an RVA, derives the corresponding Field name
123127
def field_name_from_rva(self, rva: int) -> str:
124128
try:
125-
return self.dotnetpe.net.mdtables.Field.rows[
129+
field_table = getattr(self.dotnetpe.net.mdtables, "Field", None)
130+
if not field_table:
131+
raise ConfigParserException(f"Could not find Field table for RVA {rva}")
132+
return field_table.rows[
126133
(rva ^ MDT_FIELD_DEF) - 1
127134
].Name.value
128135
except Exception:
@@ -141,8 +148,11 @@ def _generate_method_list(
141148
self,
142149
) -> list[DotNetPEMethod]:
143150
method_objs = []
151+
method_def_table = getattr(self.dotnetpe.net.mdtables, "MethodDef", None)
152+
if not method_def_table:
153+
return method_objs
144154

145-
for idx, method in enumerate(self.dotnetpe.net.mdtables.MethodDef.rows):
155+
for idx, method in enumerate(method_def_table.rows):
146156
method_offset = self.offset_from_rva(method.Rva)
147157

148158
# Parse size from flags
@@ -152,7 +162,7 @@ def _generate_method_list(
152162
method_size = flags >> 2
153163
elif flags & 3 == 3: # Fat format (add 12-byte header)
154164
method_size = 12 + bytes_to_int(
155-
self.data[method_offset + 4 : method_offset + 8]
165+
self.data[method_offset + 4: method_offset + 8]
156166
)
157167

158168
method_objs.append(
@@ -252,21 +262,28 @@ def custom_attribute_from_type(self, typespacename: str, typename: str) -> dict:
252262
config = {}
253263
try:
254264
ca_map = {}
255-
for ca in self.dotnetpe.net.mdtables.CustomAttribute.rows:
256-
idx = ca.Parent.row_index
257-
if idx not in ca_map:
258-
ca_map[idx] = []
259-
ca_map[idx].append(ca)
265+
ca_table = getattr(self.dotnetpe.net.mdtables, "CustomAttribute", None)
266+
if ca_table:
267+
for ca in ca_table.rows:
268+
idx = ca.Parent.row_index
269+
if idx not in ca_map:
270+
ca_map[idx] = []
271+
ca_map[idx].append(ca)
260272

261-
for td in self.dotnetpe.net.mdtables.TypeDef.rows:
273+
td_table = getattr(self.dotnetpe.net.mdtables, "TypeDef", None)
274+
if not td_table:
275+
return config
276+
277+
for td in td_table.rows:
262278
if (
263279
td.TypeNamespace.value != typespacename
264280
and td.TypeName.value != typename
265281
):
266282
continue
267-
for pd_row_index, pd in enumerate(
268-
self.dotnetpe.net.mdtables.Property.rows
269-
):
283+
prop_table = getattr(self.dotnetpe.net.mdtables, "Property", None)
284+
if not prop_table:
285+
continue
286+
for pd_row_index, pd in enumerate(prop_table.rows):
270287
if pd.Name.value.startswith((
271288
"Boolean_",
272289
"BorderStyle_",

0 commit comments

Comments
 (0)