From efaa0d12980d274f638d91a16aa8cbe35f57bf65 Mon Sep 17 00:00:00 2001 From: Paul Tarter Date: Thu, 31 Mar 2022 15:47:24 -0400 Subject: [PATCH 01/17] added Paul Tarter --- CONTRIBUTORS | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index e8a69cb213..ff4d7d07d8 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -33,6 +33,7 @@ Hilko Bengen Joachim Metz Karl Hiramoto Mike Wiacek +Paul Tarter ; Shane Huntley Stefan Buehlmann Victor M. Alvarez ; From d56cf7de95c6bc29eed893a2d15beb0756d14549 Mon Sep 17 00:00:00 2001 From: Paul Tarter Date: Thu, 31 Mar 2022 15:48:44 -0400 Subject: [PATCH 02/17] parse .NET directory and MetaData tables: Module, Typeref, Method, ImplMap --- libyara/include/yara/dotnet.h | 191 ++++++++++++++ libyara/modules/dotnet/dotnet.c | 455 +++++++++++++++++++++++++++++++- 2 files changed, 639 insertions(+), 7 deletions(-) diff --git a/libyara/include/yara/dotnet.h b/libyara/include/yara/dotnet.h index f9e5948782..f0a0773f10 100644 --- a/libyara/include/yara/dotnet.h +++ b/libyara/include/yara/dotnet.h @@ -28,6 +28,101 @@ typedef struct _CLI_HEADER #define NET_METADATA_MAGIC 0x424a5342 +// +// Runtime flags +// ECMA-335 Section II.25.3.3.1 +// +// COMIMAGE_FLAGS_IL_LIBRARY is not part of ECMA-335, but it is in Windows +// header files, to include winnt.h +#define COMIMAGE_FLAGS_ILONLY 0x00000001 +#define COMIMAGE_FLAGS_32BITREQUIRED 0x00000002 +#define COMIMAGE_FLAGS_IL_LIBRARY 0x00000004 +#define COMIMAGE_FLAGS_STRONGNAMESIGNED 0x00000008 +#define COMIMAGE_FLAGS_NATIVE_ENTRYPOINT 0x00000010 +#define COMIMAGE_FLAGS_TRACKDEBUGDATA 0x00010000 + +// +// Flags for methods [MethodAttributes] +// ECMA-335 Section II.23.1.10 +// +// These three bits contain one of the following values +#define METHOD_FLAGS_MEMBER_ACCESS_MASK 0x0007 +#define METHOD_FLAGS_COMPILER_CONTROLLED 0x0000 +#define METHOD_FLAGS_PRIVATE 0x0001 +#define METHOD_FLAGS_FAM_AND_ASSEM 0x0002 +#define METHOD_FLAGS_ASSEM 0x0003 +#define METHOD_FLAGS_FAMILY 0x0004 +#define METHOD_FLAGS_FAM_OR_ASSEM 0x0005 +#define METHOD_FLAGS_PUBLIC 0x0006 + +#define METHOD_FLAGS_STATIC 0x0010 +#define METHOD_FLAGS_FINAL 0x0020 +#define METHOD_FLAGS_VIRTUAL 0x0040 +#define METHOD_FLAGS_HIDE_BY_SIG 0x0080 + +// Use this mask to retrieve vtable attributes. This bit +// contains one of the following values +#define METHOD_FLAGS_VTABLE_LAYOUT_MASK 0x0100 +#define METHOD_FLAGS_REUSE_SLOT 0x0000 +#define METHOD_FLAGS_NEW_SLOT 0x0100 + +#define METHOD_FLAGS_STRICT 0x0200 +#define METHOD_FLAGS_ABSTRACT 0x0400 +#define METHOD_FLAGS_SPECIAL_NAME 0x0800 + +// Interop attributes +#define METHOD_FLAGS_PINVOKE_IMPL 0x2000 +#define METHOD_FLAGS_UNMANAGED_EXPORT 0x0008 + +// Additional flags +#define METHOD_FLAGS_RTS_SPECIAL_NAME 0x1000 +#define METHOD_FLAGS_HAS_SECURITY 0x4000 +#define METHOD_FLAGS_REQUIRE_SEC_OBJECT 0x8000 + +// +// Flags for methods [MethodImplAttributes] +// ECMA-335 Section II.23.1.11 +// + +// these two bits contain one of the follwing values +#define METHOD_IMPL_FLAGS_CODE_TYPE_MASK 0x0003 +#define METHOD_IMPL_FLAGS_IL 0x0000 +#define METHOD_IMPL_FLAGS_IS_NATIVE 0x0001 +#define METHOD_IMPL_FLAGS_OPTIL 0x0002 +#define METHOD_IMPL_FLAGS_RUNTIME 0x0003 + +// Flags specifying whether code is managed or unmanaged. +// This bit contains one of the following values +#define METHOD_IMPL_FLAGS_MANAGED_MASK 0x0004 +#define METHOD_IMPL_FLAGS_UNMANAGED 0x0004 +#define METHOD_IMPL_FLAGS_MANAGED 0x0000 + +// Implementation info and interop +#define METHOD_IMPL_FLAGS_FORWARD_REF 0x0010 +#define METHOD_IMPL_FLAGS_PRESERVE_SIG 0x0080 +#define METHOD_IMPL_FLAGS_INTERNAL_CALL 0x1000 +#define METHOD_IMPL_FLAGS_SYNCHRONIZED 0x0020 +#define METHOD_IMPL_FLAGS_NO_INLINING 0x0008 +#define METHOD_IMPL_FLAGS_NO_OPTIMIZATION 0x0040 + +// +// Flags for ImplMap [PInvokeAttributes] +// ECMA-335 Section II.23.1.8 +// +#define PINVOKE_FLAGS_NO_MANGLE 0x0001 +#define PINVOKE_FLAGS_CHAR_SET_MASK 0x0006 +#define PINVOKE_FLAGS_CHAR_SET_NOT_SPEC 0x0000 +#define PINVOKE_FLAGS_CHAR_SET_ANSI 0x0002 +#define PINVOKE_FLAGS_CHAR_SET_UNICODE 0x0004 +#define PINVOKE_FLAGS_CHAR_SET_AUTO 0x0006 +#define PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR 0x0040 +#define PINVOKE_FLAGS_CALL_CONV_MASK 0x0700 +#define PINVOKE_FLAGS_CALL_CONV_PLATFORM_API 0x0100 +#define PINVOKE_FLAGS_CALL_CONV_CDECL 0x0200 +#define PINVOKE_FLAGS_CALL_CONV_STDCALL 0x0300 +#define PINVOKE_FLAGS_CALL_CONV_THISCALL 0x0400 +#define PINVOKE_FLAGS_CALL_CONV_FASTCALL 0x0500 + // // CLI MetaData // ECMA-335 Section II.24.2.1 @@ -139,6 +234,29 @@ typedef struct _TILDE_HEADER // The string length of a typelib attribute is at most 0xFF. #define MAX_TYPELIB_SIZE 0xFF +// +// Module table +// ECMA-335 Section II.22.25 +// +typedef struct _MEMBERREF_TABLE +{ + union + { + WORD Class_Short; + DWORD Class_Long; + } Class; + union + { + WORD Name_Short; + DWORD Name_Long; + } Name; + union + { + WORD Signature_Short; + DWORD Signature_Long; + } Signature; +}MEMBERREF_TABLE, *PMEMBERREF_TABLE; + // // Module table // ECMA-335 Section II.22.30 @@ -215,6 +333,30 @@ typedef struct _ASSEMBLYREF_TABLE } Name; } ASSEMBLYREF_TABLE, *PASSEMBLYREF_TABLE; +// +// Manifest Resource Table +// ECMA-335 Section II.22.22 +// +typedef struct _IMPLMAP_TABLE +{ + WORD MappingFlags; + union + { + WORD MemberForwarded_Short; + DWORD MemberForwarded_Long; + } MemberForwarded; + union + { + WORD Name_Short; + DWORD Name_Long; + } ImportName; + union + { + WORD ImportScope_Short; + DWORD ImportScope_Long; + } ImportScope; +} IMPLMAP_TABLE, *PIMPLMAP_TABLE; + // // Manifest Resource Table // ECMA-335 Section II.22.24 @@ -235,6 +377,55 @@ typedef struct _MANIFESTRESOURCE_TABLE } Implementation; } MANIFESTRESOURCE_TABLE, *PMANIFESTRESOURCE_TABLE; +// +// TypeRef Table +// ECMA-335 Section II.22.38 +// +typedef struct _TYPEREF_TABLE +{ + union + { + WORD ResolutionScope_Short; + DWORD ResolutionScope_Long; + } ResolutionScope; + union + { + WORD Name_Short; + DWORD Name_Long; + } Name; + union + { + WORD Name_Short; + DWORD Name_Long; + } Namespace; +} TYPEREF_TABLE, *PTYPEREF_TABLE; + +// +// MethodDef Table +// ECMA-335 Section II.22.26 +// +typedef struct _METHODDEF_TABLE +{ + DWORD RVA; + WORD ImplFlags; + WORD Flags; + union + { + WORD Name_Short; + DWORD Name_Long; + } Name; + union + { + WORD Signature_Short; + DWORD Signature_Long; + } Signature; + union + { + WORD ParamList_Short; + DWORD ParamList_Long; + } ParamList; +} METHODDEF_TABLE, *PMETHODDEF_TABLE; + // // ModuleRef Table // ECMA-335 Section II.22.31 diff --git a/libyara/modules/dotnet/dotnet.c b/libyara/modules/dotnet/dotnet.c index 112e6fb092..5721f2c6fd 100644 --- a/libyara/modules/dotnet/dotnet.c +++ b/libyara/modules/dotnet/dotnet.c @@ -354,7 +354,11 @@ void dotnet_parse_tilde_2( PASSEMBLYREF_TABLE assemblyref_table; PFIELDRVA_TABLE fieldrva_table; PMANIFESTRESOURCE_TABLE manifestresource_table; + PMETHODDEF_TABLE methoddef_table; + PMEMBERREF_TABLE memberref_table; PMODULEREF_TABLE moduleref_table; + PTYPEREF_TABLE typeref_table; + PIMPLMAP_TABLE implmap_table; PCUSTOMATTRIBUTE_TABLE customattribute_table; PCONSTANT_TABLE constant_table; DWORD resource_size, implementation; @@ -397,6 +401,7 @@ void dotnet_parse_tilde_2( // CustomAttribute through MemberRef to TypeRef. uint8_t* typeref_ptr = NULL; + uint8_t* implmap_ptr = NULL; uint8_t* memberref_ptr = NULL; uint32_t typeref_row_size = 0; uint32_t memberref_row_size = 0; @@ -493,6 +498,53 @@ void dotnet_parse_tilde_2( row_size = (index_size + (index_sizes.string * 2)); typeref_row_size = row_size; typeref_ptr = table_offset; + for (i = 0; i < num_rows; i++) + { + typeref_table = (PTYPEREF_TABLE) typeref_ptr; + + if (!fits_in_pe(pe, typeref_table, row_size)) + break; + + // Name has variable sized fields prior in struct + if (index_sizes.string == 4) + name = pe_get_dotnet_string( + pe, + string_offset, + yr_le32toh(*(DWORD*) (typeref_ptr + index_size))); + else + name = pe_get_dotnet_string( + pe, + string_offset, + yr_le16toh(*(WORD*) (typeref_ptr + index_size))); + + if (name != NULL) + { + set_string(name, pe->object, "typerefs[%i].name", i); + } + + // Namespace has variable sized fields prior in struct + if (index_sizes.string == 4) + name = pe_get_dotnet_string( + pe, + string_offset, + yr_le32toh( + *(DWORD*) (typeref_ptr + index_size + index_sizes.string))); + else + name = pe_get_dotnet_string( + pe, + string_offset, + yr_le16toh( + *(WORD*) (typeref_ptr + index_size + index_sizes.string))); + if (name != NULL) + { + set_string(name, pe->object, "typerefs[%i].namespace", i); + } + + typeref_ptr += typeref_row_size; + } + + set_integer(i, pe->object, "number_of_typerefs"); + table_offset += row_size * num_rows; break; @@ -528,9 +580,48 @@ void dotnet_parse_tilde_2( break; case BIT_METHODDEF: - table_offset += (4 + 2 + 2 + index_sizes.string + index_sizes.blob + - index_sizes.param) * - num_rows; + row_size = + (4 + 2 + 2 + index_sizes.string + index_sizes.blob + + index_sizes.param); + + row_ptr = table_offset; + + for (i = 0; i < num_rows; i++) + { + methoddef_table = (PMETHODDEF_TABLE) row_ptr; + + if (!struct_fits_in_pe(pe, methoddef_table, METHODDEF_TABLE)) + break; + + set_integer( + yr_le32toh(methoddef_table->RVA), pe->object, "methods[%i].rva", i); + + set_integer( + yr_le32toh(methoddef_table->ImplFlags), + pe->object, + "methods[%i].impl_flags", + i); + + set_integer( + yr_le32toh(methoddef_table->Flags), + pe->object, + "methods[%i].flags", + i); + + name = pe_get_dotnet_string( + pe, string_offset, DOTNET_STRING_INDEX(methoddef_table->Name)); + + if (name != NULL) + { + set_string(name, pe->object, "methods[%i].name", i); + } + + row_ptr += row_size; + } + + set_integer(i, pe->object, "number_of_methods"); + + table_offset += row_size * num_rows; break; case BIT_PARAM: @@ -568,6 +659,35 @@ void dotnet_parse_tilde_2( row_size = (index_size + index_sizes.string + index_sizes.blob); memberref_row_size = row_size; memberref_ptr = table_offset; + + for (i = 0; i < num_rows; i++) + { + memberref_table = (PMEMBERREF_TABLE) memberref_ptr; + + if (!fits_in_pe(pe, memberref_table, row_size)) + break; + + if (index_sizes.string == 4) + name = pe_get_dotnet_string( + pe, + string_offset, + yr_le32toh(*(DWORD*) (memberref_ptr + index_size))); + else + name = pe_get_dotnet_string( + pe, + string_offset, + yr_le16toh(*(WORD*) (memberref_ptr + index_size))); + + if (name != NULL) + { + set_string(name, pe->object, "memberrefs[%i].name", i); + } + + memberref_ptr += row_size; + } + + set_integer(i, pe->object, "number_of_memberrefs"); + table_offset += row_size * num_rows; break; @@ -1057,16 +1177,59 @@ void dotnet_parse_tilde_2( case BIT_IMPLMAP: row_count = max_rows( - 2, yr_le32toh(rows.field), yr_le32toh(rows.methoddef)); + 3, + yr_le32toh(rows.field), + yr_le32toh(rows.methoddef), + yr_le32toh(rows.moduleref)); if (row_count > (0xFFFF >> 0x01)) index_size = 4; else index_size = 2; - table_offset += (2 + index_size + index_sizes.string + - index_sizes.moduleref) * - num_rows; + row_size = (2 + index_size + index_sizes.string + index_sizes.moduleref); + implmap_ptr = table_offset; + + for (i = 0; i < num_rows; i++) + { + implmap_table = (PIMPLMAP_TABLE) implmap_ptr; + + if (!fits_in_pe(pe, implmap_table, row_size)) + break; + + set_integer( + yr_le16toh(implmap_table->MappingFlags), + pe->object, + "impl_maps[%i].mapping_flags", + i); + + // Names can be NULL, but still add it to list. This will support + // tracing references to MemberForward and Import Scope. + // PInvoke doesn't have to fill in the name if the MemberForwad + // method is a native unmanaged method. This can be seen with + // implicit PInvoke examples. + if (index_sizes.string == 4) + name = pe_get_dotnet_string( + pe, + string_offset, + yr_le32toh(*(DWORD*) (implmap_ptr + 2 + index_size))); + else + name = pe_get_dotnet_string( + pe, + string_offset, + yr_le16toh(*(WORD*) (implmap_ptr + 2 + index_size))); + + if (name != NULL) + { + set_string(name, pe->object, "impl_maps[%i].import_name", i); + } + + implmap_ptr += row_size; + } + + set_integer(i, pe->object, "number_of_impl_maps"); + + table_offset += row_size * num_rows; break; case BIT_FIELDRVA: @@ -1708,6 +1871,21 @@ void dotnet_parse_com(PE* pe) cli_header = (PCLI_HEADER) (pe->data + offset); + set_integer(yr_le32toh(cli_header->Flags), pe->object, "flags"); + + set_integer( + yr_le16toh(cli_header->MajorRuntimeVersion), + pe->object, + "major_runtime_version"); + + set_integer( + yr_le16toh(cli_header->MinorRuntimeVersion), + pe->object, + "minor_runtime_version"); + + set_integer( + yr_le32toh(cli_header->EntryPointToken), pe->object, "entry_point"); + offset = metadata_root = pe_rva_to_offset( pe, yr_le32toh(cli_header->MetaData.VirtualAddress)); @@ -1767,6 +1945,69 @@ begin_declarations declare_integer("is_dotnet"); declare_string("version"); declare_string("module_name"); + declare_integer("COMIMAGE_FLAGS_ILONLY"); + declare_integer("COMIMAGE_FLAGS_32BITREQUIRED"); + declare_integer("COMIMAGE_FLAGS_IL_LIBRARY"); + declare_integer("COMIMAGE_FLAGS_STRONGNAMESIGNED"); + declare_integer("COMIMAGE_FLAGS_NATIVE_ENTRYPOINT"); + declare_integer("COMIMAGE_FLAGS_TRACKDEBUGDATA"); + + declare_integer("METHOD_FLAGS_MEMBER_ACCESS_MASK"); + declare_integer("METHOD_FLAGS_COMPILER_CONTROLLED"); + declare_integer("METHOD_FLAGS_FAM_AND_ASSEM"); + declare_integer("METHOD_FLAGS_ASSEM"); + declare_integer("METHOD_FLAGS_FAMILY"); + declare_integer("METHOD_FLAGS_FAM_OR_ASSEM"); + declare_integer("METHOD_FLAGS_PUBLIC"); + declare_integer("METHOD_FLAGS_STATIC"); + declare_integer("METHOD_FLAGS_FINAL"); + declare_integer("METHOD_FLAGS_VIRTUAL"); + declare_integer("METHOD_FLAGS_HIDE_BY_SIG"); + declare_integer("METHOD_FLAGS_VTABLE_LAYOUT_MASK"); + declare_integer("METHOD_FLAGS_REUSE_SLOT"); + declare_integer("METHOD_FLAGS_NEW_SLOT"); + declare_integer("METHOD_FLAGS_STRICT"); + declare_integer("METHOD_FLAGS_ABSTRACT"); + declare_integer("METHOD_FLAGS_SPECIAL_NAME"); + declare_integer("METHOD_FLAGS_PINVOKE_IMPL"); + declare_integer("METHOD_FLAGS_UNMANAGED_EXPORT"); + declare_integer("METHOD_FLAGS_RTS_SPECIAL_NAME"); + declare_integer("METHOD_FLAGS_HAS_SECURITY"); + declare_integer("METHOD_FLAGS_REQUIRE_SEC_OBJECT"); + + declare_integer("METHOD_IMPL_FLAGS_CODE_TYPE_MASK"); + declare_integer("METHOD_IMPL_FLAGS_IL"); + declare_integer("METHOD_IMPL_FLAGS_IS_NATIVE"); + declare_integer("METHOD_IMPL_FLAGS_OPTIL"); + declare_integer("METHOD_IMPL_FLAGS_RUNTIME"); + declare_integer("METHOD_IMPL_FLAGS_MANAGED_MASK"); + declare_integer("METHOD_IMPL_FLAGS_UNMANAGED"); + declare_integer("METHOD_IMPL_FLAGS_MANAGED"); + declare_integer("METHOD_IMPL_FLAGS_FORWARD_REF"); + declare_integer("METHOD_IMPL_FLAGS_PRESERVE_SIG"); + declare_integer("METHOD_IMPL_FLAGS_INTERNAL_CALL"); + declare_integer("METHOD_IMPL_FLAGS_SYNCHRONIZED"); + declare_integer("METHOD_IMPL_FLAGS_NO_INLINING"); + declare_integer("METHOD_IMPL_FLAGS_NO_OPTIMIZATION"); + + declare_integer("PINVOKE_FLAGS_NO_MANGLE"); + declare_integer("PINVOKE_FLAGS_CHAR_SET_MASK"); + declare_integer("PINVOKE_FLAGS_CHAR_SET_NOT_SPEC"); + declare_integer("PINVOKE_FLAGS_CHAR_SET_ANSI"); + declare_integer("PINVOKE_FLAGS_CHAR_SET_UNICODE"); + declare_integer("PINVOKE_FLAGS_CHAR_SET_AUTO"); + declare_integer("PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR"); + declare_integer("PINVOKE_FLAGS_CALL_CONV_MASK"); + declare_integer("PINVOKE_FLAGS_CALL_CONV_PLATFORM_API"); + declare_integer("PINVOKE_FLAGS_CALL_CONV_CDECL"); + declare_integer("PINVOKE_FLAGS_CALL_CONV_STDCALL"); + declare_integer("PINVOKE_FLAGS_CALL_CONV_THISCALL"); + declare_integer("PINVOKE_FLAGS_CALL_CONV_FASTCALL"); + + declare_integer("flags"); + declare_integer("major_runtime_version"); + declare_integer("minor_runtime_version"); + declare_integer("entry_point"); begin_struct_array("streams") declare_string("name"); @@ -1776,6 +2017,35 @@ begin_declarations declare_integer("number_of_streams"); + begin_struct_array("memberrefs") + declare_string("name"); + end_struct_array("memberrefs") + + declare_integer("number_of_memberrefs"); + + begin_struct_array("methods") + declare_integer("rva"); + declare_integer("impl_flags"); + declare_integer("flags"); + declare_string("name"); + end_struct_array("methods"); + + declare_integer("number_of_methods"); + + begin_struct_array("typerefs") + declare_string("name"); + declare_string("namespace"); + end_struct_array("typerefs"); + + declare_integer("number_of_typerefs"); + + begin_struct_array("impl_maps") + declare_integer("mapping_flags"); + declare_string("import_name"); + end_struct_array("impl_maps"); + + declare_integer("number_of_impl_maps"); + declare_string_array("guids"); declare_integer("number_of_guids"); @@ -1843,6 +2113,177 @@ int module_load( YR_MEMORY_BLOCK_ITERATOR* iterator = context->iterator; const uint8_t* block_data = NULL; + // Runtime Flags + set_integer(COMIMAGE_FLAGS_ILONLY, module_object, "COMIMAGE_FLAGS_ILONLY"); + set_integer( + COMIMAGE_FLAGS_32BITREQUIRED, module_object, "COMIMAGE_FLAGS_32BITREQUIRED"); + set_integer(COMIMAGE_FLAGS_IL_LIBRARY, module_object, "COMIMAGE_FLAGS_IL_LIBRARY"); + set_integer( + COMIMAGE_FLAGS_STRONGNAMESIGNED, + module_object, + "COMIMAGE_FLAGS_STRONGNAMESIGNED"); + set_integer( + COMIMAGE_FLAGS_NATIVE_ENTRYPOINT, + module_object, + "COMIMAGE_FLAGS_NATIVE_ENTRYPOINT"); + set_integer( + COMIMAGE_FLAGS_TRACKDEBUGDATA, + module_object, + "COMIMAGE_FLAGS_TRACKDEBUGDATA"); + + // Flags for methods [MethodAttributes] + set_integer( + METHOD_FLAGS_MEMBER_ACCESS_MASK, + module_object, + "METHOD_FLAGS_MEMBER_ACCESS_MASK"); + set_integer( + METHOD_FLAGS_COMPILER_CONTROLLED, + module_object, + "METHOD_FLAGS_COMPILER_CONTROLLED"); + set_integer(METHOD_FLAGS_PRIVATE, module_object, "METHOD_FLAGS_PRIVATE"); + set_integer( + METHOD_FLAGS_FAM_AND_ASSEM, module_object, "METHOD_FLAGS_FAM_AND_ASSEM"); + set_integer(METHOD_FLAGS_ASSEM, module_object, "METHOD_FLAGS_ASSEM"); + set_integer(METHOD_FLAGS_FAMILY, module_object, "METHOD_FLAGS_FAMILY"); + set_integer( + METHOD_FLAGS_FAM_OR_ASSEM, module_object, "METHOD_FLAGS_FAM_OR_ASSEM"); + set_integer(METHOD_FLAGS_PUBLIC, module_object, "METHOD_FLAGS_PUBLIC"); + set_integer(METHOD_FLAGS_STATIC, module_object, "METHOD_FLAGS_STATIC"); + set_integer(METHOD_FLAGS_FINAL, module_object, "METHOD_FLAGS_FINAL"); + set_integer(METHOD_FLAGS_VIRTUAL, module_object, "METHOD_FLAGS_VIRTUAL"); + set_integer( + METHOD_FLAGS_HIDE_BY_SIG, module_object, "METHOD_FLAGS_HIDE_BY_SIG"); + set_integer( + METHOD_FLAGS_VTABLE_LAYOUT_MASK, + module_object, + "METHOD_FLAGS_VTABLE_LAYOUT_MASK"); + set_integer( + METHOD_FLAGS_REUSE_SLOT, module_object, "METHOD_FLAGS_REUSE_SLOT"); + set_integer(METHOD_FLAGS_NEW_SLOT, module_object, "METHOD_FLAGS_NEW_SLOT"); + set_integer(METHOD_FLAGS_STRICT, module_object, "METHOD_FLAGS_STRICT"); + set_integer(METHOD_FLAGS_ABSTRACT, module_object, "METHOD_FLAGS_ABSTRACT"); + set_integer( + METHOD_FLAGS_SPECIAL_NAME, module_object, "METHOD_FLAGS_SPECIAL_NAME"); + set_integer( + METHOD_FLAGS_PINVOKE_IMPL, module_object, "METHOD_FLAGS_PINVOKE_IMPL"); + set_integer( + METHOD_FLAGS_UNMANAGED_EXPORT, + module_object, + "METHOD_FLAGS_UNMANAGED_EXPORT"); + set_integer( + METHOD_FLAGS_RTS_SPECIAL_NAME, + module_object, + "METHOD_FLAGS_RTS_SPECIAL_NAME"); + set_integer( + METHOD_FLAGS_HAS_SECURITY, module_object, "METHOD_FLAGS_HAS_SECURITY"); + set_integer( + METHOD_FLAGS_REQUIRE_SEC_OBJECT, + module_object, + "METHOD_FLAGS_REQUIRE_SEC_OBJECT"); + + // Flags for methods [MethodImplAttributes] + set_integer( + METHOD_IMPL_FLAGS_CODE_TYPE_MASK, + module_object, + "METHOD_IMPL_FLAGS_CODE_TYPE_MASK"); + set_integer(METHOD_IMPL_FLAGS_IL, module_object, "METHOD_IMPL_FLAGS_IL"); + set_integer( + METHOD_IMPL_FLAGS_IS_NATIVE, + module_object, + "METHOD_IMPL_FLAGS_IS_NATIVE"); + set_integer( + METHOD_IMPL_FLAGS_OPTIL, module_object, "METHOD_IMPL_FLAGS_OPTIL"); + set_integer( + METHOD_IMPL_FLAGS_RUNTIME, module_object, "METHOD_IMPL_FLAGS_RUNTIME"); + set_integer( + METHOD_IMPL_FLAGS_MANAGED_MASK, + module_object, + "METHOD_IMPL_FLAGS_MANAGED_MASK"); + set_integer( + METHOD_IMPL_FLAGS_UNMANAGED, + module_object, + "METHOD_IMPL_FLAGS_UNMANAGED"); + set_integer( + METHOD_IMPL_FLAGS_MANAGED, module_object, "METHOD_IMPL_FLAGS_MANAGED"); + set_integer( + METHOD_IMPL_FLAGS_FORWARD_REF, + module_object, + "METHOD_IMPL_FLAGS_FORWARD_REF"); + set_integer( + METHOD_IMPL_FLAGS_PRESERVE_SIG, + module_object, + "METHOD_IMPL_FLAGS_PRESERVE_SIG"); + set_integer( + METHOD_IMPL_FLAGS_INTERNAL_CALL, + module_object, + "METHOD_IMPL_FLAGS_INTERNAL_CALL"); + set_integer( + METHOD_IMPL_FLAGS_SYNCHRONIZED, + module_object, + "METHOD_IMPL_FLAGS_SYNCHRONIZED"); + set_integer( + METHOD_IMPL_FLAGS_NO_INLINING, + module_object, + "METHOD_IMPL_FLAGS_NO_INLINING"); + set_integer( + METHOD_IMPL_FLAGS_NO_OPTIMIZATION, + module_object, + "METHOD_IMPL_FLAGS_NO_OPTIMIZATION"); + + // ImplMap Flags + set_integer( + PINVOKE_FLAGS_NO_MANGLE, + module_object, + "PINVOKE_FLAGS_NO_MANGLE"); + set_integer( + PINVOKE_FLAGS_CHAR_SET_MASK, + module_object, + "PINVOKE_FLAGS_CHAR_SET_MASK"); + set_integer( + PINVOKE_FLAGS_CHAR_SET_NOT_SPEC, + module_object, + "PINVOKE_FLAGS_CHAR_SET_NOT_SPEC"); + set_integer( + PINVOKE_FLAGS_CHAR_SET_ANSI, + module_object, + "PINVOKE_FLAGS_CHAR_SET_ANSI"); + set_integer( + PINVOKE_FLAGS_CHAR_SET_UNICODE, + module_object, + "PINVOKE_FLAGS_CHAR_SET_UNICODE"); + set_integer( + PINVOKE_FLAGS_CHAR_SET_AUTO, + module_object, + "PINVOKE_FLAGS_CHAR_SET_AUTO"); + set_integer( + PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR, + module_object, + "PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR"); + set_integer( + PINVOKE_FLAGS_CALL_CONV_MASK, + module_object, + "PINVOKE_FLAGS_CALL_CONV_MASK"); + set_integer( + PINVOKE_FLAGS_CALL_CONV_PLATFORM_API, + module_object, + "PINVOKE_FLAGS_CALL_CONV_PLATFORM_API"); + set_integer( + PINVOKE_FLAGS_CALL_CONV_CDECL, + module_object, + "PINVOKE_FLAGS_CALL_CONV_CDECL"); + set_integer( + PINVOKE_FLAGS_CALL_CONV_STDCALL, + module_object, + "PINVOKE_FLAGS_CALL_CONV_STDCALL"); + set_integer( + PINVOKE_FLAGS_CALL_CONV_THISCALL, + module_object, + "PINVOKE_FLAGS_CALL_CONV_THISCALL"); + set_integer( + PINVOKE_FLAGS_CALL_CONV_FASTCALL, + module_object, + "PINVOKE_FLAGS_CALL_CONV_FASTCALL"); + foreach_memory_block(iterator, block) { PIMAGE_NT_HEADERS32 pe_header; From f802d38dc3f6db4e18bf8430cb47667e62dcf03b Mon Sep 17 00:00:00 2001 From: Paul Tarter Date: Thu, 31 Mar 2022 15:49:46 -0400 Subject: [PATCH 03/17] parse .NET directory and MetaData tables: Module, Typeref, Method, ImplMap --- docs/modules/dotnet.rst | 178 +++++++++++++++++++++++++++++++++++++++- tests/test-dotnet.c | 98 ++++++++++++++++++++++ 2 files changed, 273 insertions(+), 3 deletions(-) diff --git a/docs/modules/dotnet.rst b/docs/modules/dotnet.rst index 3f44acdc12..31e8c5663d 100644 --- a/docs/modules/dotnet.rst +++ b/docs/modules/dotnet.rst @@ -30,6 +30,31 @@ using attributes and features of the .NET file format. Let's see some examples: Reference --------- +.. c:type:: major_runtime_version + + The major version contained in the CLI header + +.. c:type:: minor_runtime_version + + The major version contained in the CLI header + +.. c:type:: flags + + CLI header runtime flags contains the following values + + .. c:type:: COMIMAGE_FLAGS_ILONLY + .. c:type:: COMIMAGE_FLAGS_32BITREQUIRED + .. c:type:: COMIMAGE_FLAGS_IL_LIBRARY + .. c:type:: COMIMAGE_FLAGS_STRONGNAMESIGNED + .. c:type:: COMIMAGE_FLAGS_NATIVE_ENTRYPOINT + .. c:type:: COMIMAGE_FLAGS_TRACKDEBUGDATA + +.. c:type:: entry_point + + If CORHEADER_NATIVE_ENTRYPOINT is set, entry_point represents an RVA + to a native entrypoint. If CORHEADER_NATIVE_ENTRYPOINT is not set, + entry_point represents a managed entrypoint. + .. c:type:: version The version string contained in the metadata root. @@ -53,12 +78,12 @@ Reference stream object has the following attributes: .. c:member:: name - - Stream name. + + Stream name .. c:member:: offset - Stream offset. + Stream offset .. c:member:: size @@ -168,6 +193,153 @@ Reference String containing the public key or token which identifies the author of this assembly. +.. c:type:: number_of_memberrefs + + the number of memberrefs in the file + +.. c:type:: memberrefs + + a zero-based array of memberrefs associating Methods to fields of a class. + Individual memberrefs can be access by using the [] operator. Each + memberref has the following attributes: + + .. c:member:: name + + memberref name + + *Example: dotnet.memberrefs[18].name == "CompareTo"* + + + +.. c:type:: number_of_methods + + the number of methods in the file + +.. c:type:: methods + + A zero-based array of methods associating operations with a type. Individual + methods can be accessed by using the [] operator. Each method has the + following attributes: + + .. c:member:: rva + + A relative virtual address of the method + + .. c:member:: impl_flags + + Integer representing method implementation attributes with one of the + following values: + + .. c:type:: METHOD_IMPL_FLAGS_CODE_TYPE_MASK + .. c:type:: METHOD_IMPL_FLAGS_IL + .. c:type:: METHOD_IMPL_FLAGS_IS_NATIVE + .. c:type:: METHOD_IMPL_FLAGS_OPTIL + .. c:type:: METHOD_IMPL_FLAGS_RUNTIME + .. c:type:: METHOD_IMPL_FLAGS_MANAGED_MASK + .. c:type:: METHOD_IMPL_FLAGS_UNMANAGED + .. c:type:: METHOD_IMPL_FLAGS_MANAGED + .. c:type:: METHOD_IMPL_FLAGS_FORWARD_REF + .. c:type:: METHOD_IMPL_FLAGS_PRESERVE_SIG + .. c:type:: METHOD_IMPL_FLAGS_INTERNAL_CALL + .. c:type:: METHOD_IMPL_FLAGS_SYNCHRONIZED + .. c:type:: METHOD_IMPL_FLAGS_NO_INLINING + .. c:type:: METHOD_IMPL_FLAGS_NO_OPTIMIZATION + + *Example: dotnet.methods[0].impl_flags & dotnet.METHOD_IMPL_FLAGS_IS_NATIVE* + + .. c:member:: flags + + .. c:type:: METHOD_FLAGS_MEMBER_ACCESS_MASK + .. c:type:: METHOD_FLAGS_COMPILER_CONTROLLED + .. c:type:: METHOD_FLAGS_PRIVATE + .. c:type:: METHOD_FLAGS_FAM_AND_ASSEM + .. c:type:: METHOD_FLAGS_ASSEM + .. c:type:: METHOD_FLAGS_FAMILY + .. c:type:: METHOD_FLAGS_FAM_OR_ASSEM + .. c:type:: METHOD_FLAGS_PUBLIC + .. c:type:: METHOD_FLAGS_STATIC + .. c:type:: METHOD_FLAGS_FINAL + .. c:type:: METHOD_FLAGS_VIRTUAL + .. c:type:: METHOD_FLAGS_HIDE_BY_SIG + .. c:type:: METHOD_FLAGS_VTABLE_LAYOUT_MASK + .. c:type:: METHOD_FLAGS_REUSE_SLOT + .. c:type:: METHOD_FLAGS_NEW_SLOT + .. c:type:: METHOD_FLAGS_STRICT + .. c:type:: METHOD_FLAGS_ABSTRACT + .. c:type:: METHOD_FLAGS_SPECIAL_NAME + .. c:type:: METHOD_FLAGS_PINVOKE_IMPL + .. c:type:: METHOD_FLAGS_UNMANAGED_EXPORT + .. c:type:: METHOD_FLAGS_RTS_SPECIAL_NAME + .. c:type:: METHOD_FLAGS_HAS_SECURITY + .. c:type:: METHOD_FLAGS_REQUIRE_SEC_OBJECT + + *Example: dotnet.methods[0].Flags & dotnet.METHOD_FLAGS_STATIC* + + .. c:member:: name + + method name + + *Example: dotnet.methods[0].name == "Foo"* + +.. c:type:: number_of_typerefs + + the number of type references in the file + +.. c:type:: typerefs + + A zero based array of type references, logical descriptions of user-defined + types that are referenced in the current module. Individual typerefs can + be access by using the [] operator. Each typeref has the following + attributes: + + .. c:member:: name + + typeref name + + *Example: dotnet.typerefs[0].name == "Decoder"* + + .. c:member:: nameSpace + + typeref namespace + + *Example: dotnet.typerefs[0].namespace == "System.Text"* + +.. c:type:: number_of_impl_maps + + The number of PInvoke implmaps in the file + +.. c:type:: impl_maps + + A zero based array of impl_map table row. Each entry holds information + about unmanaged methods that can be reached from managed code, using PInvoke + dispatch. A row is entered in the impl_map table for each parent method that + is defined with a .pinvokeimpl interoperation attribute. Individual + impl_maps can be accessed by using the [] operator.Each impl_map has the + following attributes. + + .. c:member:: import_name + + impl_map import name + + .. c:member:: mapping_flags + + Integer representing flags for the impl_map entry with one of the + following values: + + .. c:type:: PINVOKE_FLAGS_NO_MANGLE + .. c:type:: PINVOKE_FLAGS_CHAR_SET_MASK + .. c:type:: PINVOKE_FLAGS_CHAR_SET_NOT_SPEC + .. c:type:: PINVOKE_FLAGS_CHAR_SET_ANSI + .. c:type:: PINVOKE_FLAGS_CHAR_SET_UNICODE + .. c:type:: PINVOKE_FLAGS_CHAR_SET_AUTO + .. c:type:: PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR + .. c:type:: PINVOKE_FLAGS_CALL_CONV_MASK + .. c:type:: PINVOKE_FLAGS_CALL_CONV_PLATFORM_API + .. c:type:: PINVOKE_FLAGS_CALL_CONV_CDECL + .. c:type:: PINVOKE_FLAGS_CALL_CONV_STDCALL + .. c:type:: PINVOKE_FLAGS_CALL_CONV_THISCALL + .. c:type:: PINVOKE_FLAGS_CALL_CONV_FASTCALL + .. c:type:: number_of_user_strings The number of user strings in the file. diff --git a/tests/test-dotnet.c b/tests/test-dotnet.c index f4d361b8b7..c9c8d85b23 100644 --- a/tests/test-dotnet.c +++ b/tests/test-dotnet.c @@ -84,6 +84,104 @@ int main(int argc, char** argv) "tests/data/" "0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171"); + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + dotnet.number_of_guids == 2 and \ + dotnet.guids[0] == \"cb9aa69f-4951-49d2-98a1-18984dcfdb91\" and \ + dotnet.guids[1] == \"00000000-0000-0000-0000-000000000000\" \ + }", + "tests/data/" + "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); + + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + dotnet.user_strings[0] == \"F\\x00r\\x00e\\x00e\\x00D\\x00i\\x00s\\x00c\\x00B\\x00u\\x00r\\x00n\\x00e\\x00r\\x00.\\x00S\\x00t\\x00r\\x00i\\x00n\\x00g\\x00R\\x00e\\x00s\\x00o\\x00u\\x00r\\x00c\\x00e\\x00s\\x00\" \ + }", + "tests/data/" + "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); + + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + dotnet.entry_point == 0x600027A and \ + dotnet.flags & ( \ + dotnet.COMIMAGE_FLAGS_ILONLY & \ + dotnet.COMIMAGE_FLAGS_32BITREQUIRED) == \ + dotnet.COMIMAGE_FLAGS_ILONLY & \ + dotnet.COMIMAGE_FLAGS_32BITREQUIRED \ + }", + "tests/data/" + "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); + + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + for any method in dotnet.methods : ( \ + method.name == \"DoSetControlValues\" and \ + method.rva == 0x2830 and \ + method.impl_flags & ( \ + dotnet.METHOD_IMPL_FLAGS_IL & \ + dotnet.METHOD_IMPL_FLAGS_MANAGED & \ + dotnet.METHOD_IMPL_FLAGS_NO_INLINING) == \ + dotnet.METHOD_IMPL_FLAGS_IL & \ + dotnet.METHOD_IMPL_FLAGS_MANAGED & \ + dotnet.METHOD_IMPL_FLAGS_NO_INLINING and \ + method.flags & ( \ + dotnet.METHOD_FLAGS_FAMILY & \ + dotnet.METHOD_FLAGS_VIRTUAL & \ + dotnet.METHOD_FLAGS_HIDE_BY_SIG & \ + dotnet.METHOD_FLAGS_REUSE_SLOT) == \ + dotnet.METHOD_FLAGS_FAMILY & \ + dotnet.METHOD_FLAGS_VIRTUAL & \ + dotnet.METHOD_FLAGS_HIDE_BY_SIG & \ + dotnet.METHOD_FLAGS_REUSE_SLOT \ + ) \ + }", + "tests/data/" + "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); + + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + for any typeref in dotnet.typerefs : ( \ + typeref.namespace == \"DVDVideoSoft.Utils\" and \ + typeref.name == \"WindowUtils\") \ + }", + "tests/data/" + "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); + + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + for any i in (0..dotnet.number_of_memberrefs - 1): ( \ + dotnet.memberrefs[i].name == \"CompareTo\" and \ + dotnet.memberrefs[i+1].name == \"get_IsDirectory\" \ + ) \ + }", + "tests/data/" + "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); + + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + for any imap in dotnet.impl_maps : ( \ + imap.import_name == \"RtlZeroMemory\" and \ + imap.mapping_flags & \ + dotnet.PINVOKE_FLAGS_CALL_CONV_PLATFORM_API == \ + dotnet.PINVOKE_FLAGS_CALL_CONV_PLATFORM_API \ + ) \ + }", + "tests/data/" + "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); yr_finalize(); YR_DEBUG_FPRINTF( From e7dc73940d265d923f4e060a1ec1ca4be4de5e6e Mon Sep 17 00:00:00 2001 From: Paul Tarter Date: Thu, 31 Mar 2022 18:09:38 -0400 Subject: [PATCH 04/17] update tests to not use hash 33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b --- tests/test-dotnet.c | 88 ++++++++------------------------------------- 1 file changed, 14 insertions(+), 74 deletions(-) diff --git a/tests/test-dotnet.c b/tests/test-dotnet.c index c9c8d85b23..a3fe8706e4 100644 --- a/tests/test-dotnet.c +++ b/tests/test-dotnet.c @@ -88,104 +88,44 @@ int main(int argc, char** argv) "import \"dotnet\" \ rule test { \ condition: \ - dotnet.number_of_guids == 2 and \ - dotnet.guids[0] == \"cb9aa69f-4951-49d2-98a1-18984dcfdb91\" and \ - dotnet.guids[1] == \"00000000-0000-0000-0000-000000000000\" \ - }", - "tests/data/" - "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); - - assert_true_rule_file( - "import \"dotnet\" \ - rule test { \ - condition: \ - dotnet.user_strings[0] == \"F\\x00r\\x00e\\x00e\\x00D\\x00i\\x00s\\x00c\\x00B\\x00u\\x00r\\x00n\\x00e\\x00r\\x00.\\x00S\\x00t\\x00r\\x00i\\x00n\\x00g\\x00R\\x00e\\x00s\\x00o\\x00u\\x00r\\x00c\\x00e\\x00s\\x00\" \ - }", - "tests/data/" - "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); - - assert_true_rule_file( - "import \"dotnet\" \ - rule test { \ - condition: \ - dotnet.entry_point == 0x600027A and \ + dotnet.is_dotnet and \ + dotnet.entry_point == 0 and \ dotnet.flags & ( \ dotnet.COMIMAGE_FLAGS_ILONLY & \ - dotnet.COMIMAGE_FLAGS_32BITREQUIRED) == \ + dotnet.COMIMAGE_FLAGS_STRONGNAMESIGNED) == \ dotnet.COMIMAGE_FLAGS_ILONLY & \ - dotnet.COMIMAGE_FLAGS_32BITREQUIRED \ - }", - "tests/data/" - "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); - - assert_true_rule_file( - "import \"dotnet\" \ - rule test { \ - condition: \ - for any method in dotnet.methods : ( \ - method.name == \"DoSetControlValues\" and \ - method.rva == 0x2830 and \ - method.impl_flags & ( \ - dotnet.METHOD_IMPL_FLAGS_IL & \ - dotnet.METHOD_IMPL_FLAGS_MANAGED & \ - dotnet.METHOD_IMPL_FLAGS_NO_INLINING) == \ - dotnet.METHOD_IMPL_FLAGS_IL & \ - dotnet.METHOD_IMPL_FLAGS_MANAGED & \ - dotnet.METHOD_IMPL_FLAGS_NO_INLINING and \ - method.flags & ( \ - dotnet.METHOD_FLAGS_FAMILY & \ - dotnet.METHOD_FLAGS_VIRTUAL & \ - dotnet.METHOD_FLAGS_HIDE_BY_SIG & \ - dotnet.METHOD_FLAGS_REUSE_SLOT) == \ - dotnet.METHOD_FLAGS_FAMILY & \ - dotnet.METHOD_FLAGS_VIRTUAL & \ - dotnet.METHOD_FLAGS_HIDE_BY_SIG & \ - dotnet.METHOD_FLAGS_REUSE_SLOT \ - ) \ + dotnet.COMIMAGE_FLAGS_STRONGNAMESIGNED \ }", "tests/data/" - "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); + "0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171"); assert_true_rule_file( "import \"dotnet\" \ rule test { \ condition: \ + dotnet.is_dotnet and \ for any typeref in dotnet.typerefs : ( \ - typeref.namespace == \"DVDVideoSoft.Utils\" and \ - typeref.name == \"WindowUtils\") \ + typeref.namespace == \"System.Reflection\" and \ + typeref.name == \"AssemblyTitleAttribute\") \ }", "tests/data/" - "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); + "3b8b90159fa9b6048cc5410c5d53f116943564e4d05b04a843f9b3d0540d0c1c"); assert_true_rule_file( "import \"dotnet\" \ rule test { \ condition: \ - for any i in (0..dotnet.number_of_memberrefs - 1): ( \ - dotnet.memberrefs[i].name == \"CompareTo\" and \ - dotnet.memberrefs[i+1].name == \"get_IsDirectory\" \ - ) \ + dotnet.is_dotnet and \ + dotnet.number_of_memberrefs == 6 and \ + dotnet.memberrefs[1].name == \".ctor\" \ }", "tests/data/" - "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); + "0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171"); - assert_true_rule_file( - "import \"dotnet\" \ - rule test { \ - condition: \ - for any imap in dotnet.impl_maps : ( \ - imap.import_name == \"RtlZeroMemory\" and \ - imap.mapping_flags & \ - dotnet.PINVOKE_FLAGS_CALL_CONV_PLATFORM_API == \ - dotnet.PINVOKE_FLAGS_CALL_CONV_PLATFORM_API \ - ) \ - }", - "tests/data/" - "33fc70f99be6d2833ae48852d611c8048d0c053ed0b2c626db4dbe902832a08b"); yr_finalize(); YR_DEBUG_FPRINTF( 1, stderr, "} = %d // %s() in %s\n", result, __FUNCTION__, argv[0]); return result; -} +} \ No newline at end of file From f2947d77565e8837163b7a8514ad9ede36327ef4 Mon Sep 17 00:00:00 2001 From: Paul Tarter Date: Thu, 21 Apr 2022 07:17:43 -0400 Subject: [PATCH 05/17] corrected hash for dotnet-test --- tests/test-dotnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-dotnet.c b/tests/test-dotnet.c index a3fe8706e4..e93035722a 100644 --- a/tests/test-dotnet.c +++ b/tests/test-dotnet.c @@ -109,7 +109,7 @@ int main(int argc, char** argv) typeref.name == \"AssemblyTitleAttribute\") \ }", "tests/data/" - "3b8b90159fa9b6048cc5410c5d53f116943564e4d05b04a843f9b3d0540d0c1c"); + "0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171"); assert_true_rule_file( "import \"dotnet\" \ From 7a03749054a1a82977cfa78355ef26feef2a4cd8 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 21 Apr 2022 16:32:32 -0700 Subject: [PATCH 06/17] s/major/minor/ --- docs/modules/dotnet.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/dotnet.rst b/docs/modules/dotnet.rst index 31e8c5663d..d8410f6284 100644 --- a/docs/modules/dotnet.rst +++ b/docs/modules/dotnet.rst @@ -36,7 +36,7 @@ Reference .. c:type:: minor_runtime_version - The major version contained in the CLI header + The minor version contained in the CLI header .. c:type:: flags From b869c89459189b187c5bbfe2b8bf1f2acd727bcc Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 21 Apr 2022 16:46:56 -0700 Subject: [PATCH 07/17] specify entry_point cases When CORHEADER_NATIVE_ENTRYPOINT is not set it doesn't point to an RVA. I specified this better by stating `entry_point represents a metadata token`. Finding the RVA requires parsing the metadata tables for the specified token --- docs/modules/dotnet.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/dotnet.rst b/docs/modules/dotnet.rst index d8410f6284..4df6aa13d4 100644 --- a/docs/modules/dotnet.rst +++ b/docs/modules/dotnet.rst @@ -53,7 +53,7 @@ Reference If CORHEADER_NATIVE_ENTRYPOINT is set, entry_point represents an RVA to a native entrypoint. If CORHEADER_NATIVE_ENTRYPOINT is not set, - entry_point represents a managed entrypoint. + entry_point represents a metadata token for entrypoint. .. c:type:: version From 8b3e6a920f2f15f656fb9beb52f2c97bd2a360d1 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 21 Apr 2022 16:50:58 -0700 Subject: [PATCH 08/17] grammar and fix whitespace --- docs/modules/dotnet.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/dotnet.rst b/docs/modules/dotnet.rst index 4df6aa13d4..fb52cefb39 100644 --- a/docs/modules/dotnet.rst +++ b/docs/modules/dotnet.rst @@ -78,8 +78,8 @@ Reference stream object has the following attributes: .. c:member:: name - - Stream name + + Stream name. .. c:member:: offset From 82bca01ca2bd470f3591921c8bdd6d96bc72e351 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 21 Apr 2022 16:59:26 -0700 Subject: [PATCH 09/17] removed extra whitespace --- docs/modules/dotnet.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/modules/dotnet.rst b/docs/modules/dotnet.rst index fb52cefb39..802468b92f 100644 --- a/docs/modules/dotnet.rst +++ b/docs/modules/dotnet.rst @@ -79,7 +79,7 @@ Reference .. c:member:: name - Stream name. + Stream name .. c:member:: offset @@ -87,7 +87,7 @@ Reference .. c:member:: size - Stream size. + Stream size *Example: dotnet.streams[0].name == "#~"* @@ -209,8 +209,6 @@ Reference *Example: dotnet.memberrefs[18].name == "CompareTo"* - - .. c:type:: number_of_methods the number of methods in the file From d6758f52634b91eb082d29fce13a4ebe3849592b Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 21 Apr 2022 17:00:34 -0700 Subject: [PATCH 10/17] grammar fix Co-authored-by: Wesley Shields --- docs/modules/dotnet.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/dotnet.rst b/docs/modules/dotnet.rst index 802468b92f..15ee252a39 100644 --- a/docs/modules/dotnet.rst +++ b/docs/modules/dotnet.rst @@ -312,7 +312,7 @@ Reference about unmanaged methods that can be reached from managed code, using PInvoke dispatch. A row is entered in the impl_map table for each parent method that is defined with a .pinvokeimpl interoperation attribute. Individual - impl_maps can be accessed by using the [] operator.Each impl_map has the + impl_maps can be accessed by using the [] operator. Each impl_map has the following attributes. .. c:member:: import_name From 0c6f465a926f9d835316320c20d5c52cd102beb9 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 21 Apr 2022 17:05:10 -0700 Subject: [PATCH 11/17] removed unreferenced *_MASK #defines I had the same thoughts when adding them, I was mocking up ECMA as is, but I agree that if it isn't being used, doesn't need to be present. --- libyara/include/yara/dotnet.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libyara/include/yara/dotnet.h b/libyara/include/yara/dotnet.h index f0a0773f10..145767da79 100644 --- a/libyara/include/yara/dotnet.h +++ b/libyara/include/yara/dotnet.h @@ -46,7 +46,6 @@ typedef struct _CLI_HEADER // ECMA-335 Section II.23.1.10 // // These three bits contain one of the following values -#define METHOD_FLAGS_MEMBER_ACCESS_MASK 0x0007 #define METHOD_FLAGS_COMPILER_CONTROLLED 0x0000 #define METHOD_FLAGS_PRIVATE 0x0001 #define METHOD_FLAGS_FAM_AND_ASSEM 0x0002 @@ -62,7 +61,6 @@ typedef struct _CLI_HEADER // Use this mask to retrieve vtable attributes. This bit // contains one of the following values -#define METHOD_FLAGS_VTABLE_LAYOUT_MASK 0x0100 #define METHOD_FLAGS_REUSE_SLOT 0x0000 #define METHOD_FLAGS_NEW_SLOT 0x0100 @@ -85,7 +83,6 @@ typedef struct _CLI_HEADER // // these two bits contain one of the follwing values -#define METHOD_IMPL_FLAGS_CODE_TYPE_MASK 0x0003 #define METHOD_IMPL_FLAGS_IL 0x0000 #define METHOD_IMPL_FLAGS_IS_NATIVE 0x0001 #define METHOD_IMPL_FLAGS_OPTIL 0x0002 @@ -93,7 +90,6 @@ typedef struct _CLI_HEADER // Flags specifying whether code is managed or unmanaged. // This bit contains one of the following values -#define METHOD_IMPL_FLAGS_MANAGED_MASK 0x0004 #define METHOD_IMPL_FLAGS_UNMANAGED 0x0004 #define METHOD_IMPL_FLAGS_MANAGED 0x0000 @@ -110,13 +106,11 @@ typedef struct _CLI_HEADER // ECMA-335 Section II.23.1.8 // #define PINVOKE_FLAGS_NO_MANGLE 0x0001 -#define PINVOKE_FLAGS_CHAR_SET_MASK 0x0006 #define PINVOKE_FLAGS_CHAR_SET_NOT_SPEC 0x0000 #define PINVOKE_FLAGS_CHAR_SET_ANSI 0x0002 #define PINVOKE_FLAGS_CHAR_SET_UNICODE 0x0004 #define PINVOKE_FLAGS_CHAR_SET_AUTO 0x0006 #define PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR 0x0040 -#define PINVOKE_FLAGS_CALL_CONV_MASK 0x0700 #define PINVOKE_FLAGS_CALL_CONV_PLATFORM_API 0x0100 #define PINVOKE_FLAGS_CALL_CONV_CDECL 0x0200 #define PINVOKE_FLAGS_CALL_CONV_STDCALL 0x0300 From d521662ee82da0977fcb04e88e06d561ecee3f84 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 21 Apr 2022 17:06:21 -0700 Subject: [PATCH 12/17] typedef syntax format fix Co-authored-by: Wesley Shields --- libyara/include/yara/dotnet.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libyara/include/yara/dotnet.h b/libyara/include/yara/dotnet.h index 145767da79..d0e4301126 100644 --- a/libyara/include/yara/dotnet.h +++ b/libyara/include/yara/dotnet.h @@ -249,7 +249,7 @@ typedef struct _MEMBERREF_TABLE WORD Signature_Short; DWORD Signature_Long; } Signature; -}MEMBERREF_TABLE, *PMEMBERREF_TABLE; +} MEMBERREF_TABLE, *PMEMBERREF_TABLE; // // Module table From ce471164db8e7ce265b6fce059859ec304e74cbf Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 21 Apr 2022 17:10:16 -0700 Subject: [PATCH 13/17] fixed ECMA ImplMap comment --- libyara/include/yara/dotnet.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libyara/include/yara/dotnet.h b/libyara/include/yara/dotnet.h index d0e4301126..35d15ad3b2 100644 --- a/libyara/include/yara/dotnet.h +++ b/libyara/include/yara/dotnet.h @@ -328,7 +328,7 @@ typedef struct _ASSEMBLYREF_TABLE } ASSEMBLYREF_TABLE, *PASSEMBLYREF_TABLE; // -// Manifest Resource Table +// ImplMap Table // ECMA-335 Section II.22.22 // typedef struct _IMPLMAP_TABLE From 0d932a933877d5c7eb1c62aa3f80a620f24af833 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 21 Apr 2022 17:11:17 -0700 Subject: [PATCH 14/17] grammar fix Co-authored-by: Wesley Shields --- libyara/modules/dotnet/dotnet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libyara/modules/dotnet/dotnet.c b/libyara/modules/dotnet/dotnet.c index 5721f2c6fd..ddb7a0e047 100644 --- a/libyara/modules/dotnet/dotnet.c +++ b/libyara/modules/dotnet/dotnet.c @@ -1205,7 +1205,7 @@ void dotnet_parse_tilde_2( // Names can be NULL, but still add it to list. This will support // tracing references to MemberForward and Import Scope. - // PInvoke doesn't have to fill in the name if the MemberForwad + // PInvoke doesn't have to fill in the name if the MemberForward // method is a native unmanaged method. This can be seen with // implicit PInvoke examples. if (index_sizes.string == 4) From 6a8b5155743685ecafb2af9b92add445338200c8 Mon Sep 17 00:00:00 2001 From: Paul Tarter Date: Fri, 22 Apr 2022 07:50:05 -0400 Subject: [PATCH 15/17] remove *_MASK --- libyara/modules/dotnet/dotnet.c | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/libyara/modules/dotnet/dotnet.c b/libyara/modules/dotnet/dotnet.c index 5721f2c6fd..540ca4d858 100644 --- a/libyara/modules/dotnet/dotnet.c +++ b/libyara/modules/dotnet/dotnet.c @@ -1952,7 +1952,6 @@ begin_declarations declare_integer("COMIMAGE_FLAGS_NATIVE_ENTRYPOINT"); declare_integer("COMIMAGE_FLAGS_TRACKDEBUGDATA"); - declare_integer("METHOD_FLAGS_MEMBER_ACCESS_MASK"); declare_integer("METHOD_FLAGS_COMPILER_CONTROLLED"); declare_integer("METHOD_FLAGS_FAM_AND_ASSEM"); declare_integer("METHOD_FLAGS_ASSEM"); @@ -1963,7 +1962,6 @@ begin_declarations declare_integer("METHOD_FLAGS_FINAL"); declare_integer("METHOD_FLAGS_VIRTUAL"); declare_integer("METHOD_FLAGS_HIDE_BY_SIG"); - declare_integer("METHOD_FLAGS_VTABLE_LAYOUT_MASK"); declare_integer("METHOD_FLAGS_REUSE_SLOT"); declare_integer("METHOD_FLAGS_NEW_SLOT"); declare_integer("METHOD_FLAGS_STRICT"); @@ -1975,12 +1973,10 @@ begin_declarations declare_integer("METHOD_FLAGS_HAS_SECURITY"); declare_integer("METHOD_FLAGS_REQUIRE_SEC_OBJECT"); - declare_integer("METHOD_IMPL_FLAGS_CODE_TYPE_MASK"); declare_integer("METHOD_IMPL_FLAGS_IL"); declare_integer("METHOD_IMPL_FLAGS_IS_NATIVE"); declare_integer("METHOD_IMPL_FLAGS_OPTIL"); declare_integer("METHOD_IMPL_FLAGS_RUNTIME"); - declare_integer("METHOD_IMPL_FLAGS_MANAGED_MASK"); declare_integer("METHOD_IMPL_FLAGS_UNMANAGED"); declare_integer("METHOD_IMPL_FLAGS_MANAGED"); declare_integer("METHOD_IMPL_FLAGS_FORWARD_REF"); @@ -1991,13 +1987,11 @@ begin_declarations declare_integer("METHOD_IMPL_FLAGS_NO_OPTIMIZATION"); declare_integer("PINVOKE_FLAGS_NO_MANGLE"); - declare_integer("PINVOKE_FLAGS_CHAR_SET_MASK"); declare_integer("PINVOKE_FLAGS_CHAR_SET_NOT_SPEC"); declare_integer("PINVOKE_FLAGS_CHAR_SET_ANSI"); declare_integer("PINVOKE_FLAGS_CHAR_SET_UNICODE"); declare_integer("PINVOKE_FLAGS_CHAR_SET_AUTO"); declare_integer("PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR"); - declare_integer("PINVOKE_FLAGS_CALL_CONV_MASK"); declare_integer("PINVOKE_FLAGS_CALL_CONV_PLATFORM_API"); declare_integer("PINVOKE_FLAGS_CALL_CONV_CDECL"); declare_integer("PINVOKE_FLAGS_CALL_CONV_STDCALL"); @@ -2132,10 +2126,6 @@ int module_load( "COMIMAGE_FLAGS_TRACKDEBUGDATA"); // Flags for methods [MethodAttributes] - set_integer( - METHOD_FLAGS_MEMBER_ACCESS_MASK, - module_object, - "METHOD_FLAGS_MEMBER_ACCESS_MASK"); set_integer( METHOD_FLAGS_COMPILER_CONTROLLED, module_object, @@ -2153,10 +2143,6 @@ int module_load( set_integer(METHOD_FLAGS_VIRTUAL, module_object, "METHOD_FLAGS_VIRTUAL"); set_integer( METHOD_FLAGS_HIDE_BY_SIG, module_object, "METHOD_FLAGS_HIDE_BY_SIG"); - set_integer( - METHOD_FLAGS_VTABLE_LAYOUT_MASK, - module_object, - "METHOD_FLAGS_VTABLE_LAYOUT_MASK"); set_integer( METHOD_FLAGS_REUSE_SLOT, module_object, "METHOD_FLAGS_REUSE_SLOT"); set_integer(METHOD_FLAGS_NEW_SLOT, module_object, "METHOD_FLAGS_NEW_SLOT"); @@ -2182,10 +2168,6 @@ int module_load( "METHOD_FLAGS_REQUIRE_SEC_OBJECT"); // Flags for methods [MethodImplAttributes] - set_integer( - METHOD_IMPL_FLAGS_CODE_TYPE_MASK, - module_object, - "METHOD_IMPL_FLAGS_CODE_TYPE_MASK"); set_integer(METHOD_IMPL_FLAGS_IL, module_object, "METHOD_IMPL_FLAGS_IL"); set_integer( METHOD_IMPL_FLAGS_IS_NATIVE, @@ -2195,10 +2177,6 @@ int module_load( METHOD_IMPL_FLAGS_OPTIL, module_object, "METHOD_IMPL_FLAGS_OPTIL"); set_integer( METHOD_IMPL_FLAGS_RUNTIME, module_object, "METHOD_IMPL_FLAGS_RUNTIME"); - set_integer( - METHOD_IMPL_FLAGS_MANAGED_MASK, - module_object, - "METHOD_IMPL_FLAGS_MANAGED_MASK"); set_integer( METHOD_IMPL_FLAGS_UNMANAGED, module_object, @@ -2235,10 +2213,6 @@ int module_load( PINVOKE_FLAGS_NO_MANGLE, module_object, "PINVOKE_FLAGS_NO_MANGLE"); - set_integer( - PINVOKE_FLAGS_CHAR_SET_MASK, - module_object, - "PINVOKE_FLAGS_CHAR_SET_MASK"); set_integer( PINVOKE_FLAGS_CHAR_SET_NOT_SPEC, module_object, @@ -2259,10 +2233,6 @@ int module_load( PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR, module_object, "PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR"); - set_integer( - PINVOKE_FLAGS_CALL_CONV_MASK, - module_object, - "PINVOKE_FLAGS_CALL_CONV_MASK"); set_integer( PINVOKE_FLAGS_CALL_CONV_PLATFORM_API, module_object, From b980784849accdbc703fb3cd41d16d8a3cf410c0 Mon Sep 17 00:00:00 2001 From: Paul Tarter Date: Fri, 22 Apr 2022 07:51:54 -0400 Subject: [PATCH 16/17] remove *_MASK --- docs/modules/dotnet.rst | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/docs/modules/dotnet.rst b/docs/modules/dotnet.rst index 15ee252a39..4a524a58ae 100644 --- a/docs/modules/dotnet.rst +++ b/docs/modules/dotnet.rst @@ -227,13 +227,11 @@ Reference Integer representing method implementation attributes with one of the following values: - - .. c:type:: METHOD_IMPL_FLAGS_CODE_TYPE_MASK + .. c:type:: METHOD_IMPL_FLAGS_IL .. c:type:: METHOD_IMPL_FLAGS_IS_NATIVE .. c:type:: METHOD_IMPL_FLAGS_OPTIL - .. c:type:: METHOD_IMPL_FLAGS_RUNTIME - .. c:type:: METHOD_IMPL_FLAGS_MANAGED_MASK + .. c:type:: METHOD_IMPL_FLAGS_RUNTIME .. c:type:: METHOD_IMPL_FLAGS_UNMANAGED .. c:type:: METHOD_IMPL_FLAGS_MANAGED .. c:type:: METHOD_IMPL_FLAGS_FORWARD_REF @@ -247,7 +245,6 @@ Reference .. c:member:: flags - .. c:type:: METHOD_FLAGS_MEMBER_ACCESS_MASK .. c:type:: METHOD_FLAGS_COMPILER_CONTROLLED .. c:type:: METHOD_FLAGS_PRIVATE .. c:type:: METHOD_FLAGS_FAM_AND_ASSEM @@ -259,7 +256,6 @@ Reference .. c:type:: METHOD_FLAGS_FINAL .. c:type:: METHOD_FLAGS_VIRTUAL .. c:type:: METHOD_FLAGS_HIDE_BY_SIG - .. c:type:: METHOD_FLAGS_VTABLE_LAYOUT_MASK .. c:type:: METHOD_FLAGS_REUSE_SLOT .. c:type:: METHOD_FLAGS_NEW_SLOT .. c:type:: METHOD_FLAGS_STRICT @@ -325,13 +321,11 @@ Reference following values: .. c:type:: PINVOKE_FLAGS_NO_MANGLE - .. c:type:: PINVOKE_FLAGS_CHAR_SET_MASK .. c:type:: PINVOKE_FLAGS_CHAR_SET_NOT_SPEC .. c:type:: PINVOKE_FLAGS_CHAR_SET_ANSI .. c:type:: PINVOKE_FLAGS_CHAR_SET_UNICODE .. c:type:: PINVOKE_FLAGS_CHAR_SET_AUTO - .. c:type:: PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR - .. c:type:: PINVOKE_FLAGS_CALL_CONV_MASK + .. c:type:: PINVOKE_FLAGS_SUPPORT_GET_LAST_ERROR .. c:type:: PINVOKE_FLAGS_CALL_CONV_PLATFORM_API .. c:type:: PINVOKE_FLAGS_CALL_CONV_CDECL .. c:type:: PINVOKE_FLAGS_CALL_CONV_STDCALL From 97df9be2c905350c2b20ab53ab9899355fb9d0ce Mon Sep 17 00:00:00 2001 From: Paul Tarter Date: Fri, 22 Apr 2022 08:41:23 -0400 Subject: [PATCH 17/17] added counter for memberref and typeref --- libyara/modules/dotnet/dotnet.c | 37 ++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/libyara/modules/dotnet/dotnet.c b/libyara/modules/dotnet/dotnet.c index c4b9fa71de..fb89988c66 100644 --- a/libyara/modules/dotnet/dotnet.c +++ b/libyara/modules/dotnet/dotnet.c @@ -498,6 +498,9 @@ void dotnet_parse_tilde_2( row_size = (index_size + (index_sizes.string * 2)); typeref_row_size = row_size; typeref_ptr = table_offset; + counter = 0; + char* namespace; + for (i = 0; i < num_rows; i++) { typeref_table = (PTYPEREF_TABLE) typeref_ptr; @@ -517,33 +520,36 @@ void dotnet_parse_tilde_2( string_offset, yr_le16toh(*(WORD*) (typeref_ptr + index_size))); - if (name != NULL) - { - set_string(name, pe->object, "typerefs[%i].name", i); - } - // Namespace has variable sized fields prior in struct if (index_sizes.string == 4) - name = pe_get_dotnet_string( + namespace = pe_get_dotnet_string( pe, string_offset, yr_le32toh( *(DWORD*) (typeref_ptr + index_size + index_sizes.string))); else - name = pe_get_dotnet_string( + namespace = pe_get_dotnet_string( pe, string_offset, yr_le16toh( *(WORD*) (typeref_ptr + index_size + index_sizes.string))); - if (name != NULL) + + // Only require name or namespace to increment counter. + if (name || namespace) { - set_string(name, pe->object, "typerefs[%i].namespace", i); + counter++; + + if (name != NULL) + set_string(name, pe->object, "typerefs[%i].name", i); + + if (name != NULL) + set_string(namespace, pe->object, "typerefs[%i].namespace", i); } typeref_ptr += typeref_row_size; } - set_integer(i, pe->object, "number_of_typerefs"); + set_integer(counter, pe->object, "number_of_typerefs"); table_offset += row_size * num_rows; break; @@ -659,6 +665,7 @@ void dotnet_parse_tilde_2( row_size = (index_size + index_sizes.string + index_sizes.blob); memberref_row_size = row_size; memberref_ptr = table_offset; + counter = 0; for (i = 0; i < num_rows; i++) { @@ -681,12 +688,13 @@ void dotnet_parse_tilde_2( if (name != NULL) { set_string(name, pe->object, "memberrefs[%i].name", i); + counter++; } - + memberref_ptr += row_size; } - set_integer(i, pe->object, "number_of_memberrefs"); + set_integer(counter, pe->object, "number_of_memberrefs"); table_offset += row_size * num_rows; break; @@ -1204,8 +1212,9 @@ void dotnet_parse_tilde_2( i); // Names can be NULL, but still add it to list. This will support - // tracing references to MemberForward and Import Scope. - // PInvoke doesn't have to fill in the name if the MemberForward + // tracing references to MemberForward and Import Scope. Also + // a signature can be created off of a NULL name with specific + // flags. PInvoke doesn't have to fill in the name if the MemberForward // method is a native unmanaged method. This can be seen with // implicit PInvoke examples. if (index_sizes.string == 4)