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 ; diff --git a/docs/modules/dotnet.rst b/docs/modules/dotnet.rst index 3f44acdc12..4a524a58ae 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 minor 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 metadata token for entrypoint. + .. c:type:: version The version string contained in the metadata root. @@ -54,15 +79,15 @@ Reference .. c:member:: name - Stream name. + Stream name .. c:member:: offset - Stream offset. + Stream offset .. c:member:: size - Stream size. + Stream size *Example: dotnet.streams[0].name == "#~"* @@ -168,6 +193,145 @@ 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_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_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_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_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_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_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/libyara/include/yara/dotnet.h b/libyara/include/yara/dotnet.h index f9e5948782..35d15ad3b2 100644 --- a/libyara/include/yara/dotnet.h +++ b/libyara/include/yara/dotnet.h @@ -28,6 +28,95 @@ 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_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_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_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_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_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_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 +228,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 +327,30 @@ typedef struct _ASSEMBLYREF_TABLE } Name; } ASSEMBLYREF_TABLE, *PASSEMBLYREF_TABLE; +// +// ImplMap 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 +371,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..fb89988c66 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,59 @@ 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; + + 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))); + + // Namespace has variable sized fields prior in struct + if (index_sizes.string == 4) + namespace = pe_get_dotnet_string( + pe, + string_offset, + yr_le32toh( + *(DWORD*) (typeref_ptr + index_size + index_sizes.string))); + else + namespace = pe_get_dotnet_string( + pe, + string_offset, + yr_le16toh( + *(WORD*) (typeref_ptr + index_size + index_sizes.string))); + + // Only require name or namespace to increment counter. + if (name || namespace) + { + 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(counter, pe->object, "number_of_typerefs"); + table_offset += row_size * num_rows; break; @@ -528,9 +586,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 +665,37 @@ 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++) + { + 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); + counter++; + } + + memberref_ptr += row_size; + } + + set_integer(counter, pe->object, "number_of_memberrefs"); + table_offset += row_size * num_rows; break; @@ -1057,16 +1185,60 @@ 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. 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) + 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 +1880,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 +1954,63 @@ 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_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_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_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_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_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_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 +2020,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 +2116,153 @@ 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_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_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_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_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_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_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; diff --git a/tests/test-dotnet.c b/tests/test-dotnet.c index f4d361b8b7..e93035722a 100644 --- a/tests/test-dotnet.c +++ b/tests/test-dotnet.c @@ -84,10 +84,48 @@ int main(int argc, char** argv) "tests/data/" "0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171"); + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + dotnet.is_dotnet and \ + dotnet.entry_point == 0 and \ + dotnet.flags & ( \ + dotnet.COMIMAGE_FLAGS_ILONLY & \ + dotnet.COMIMAGE_FLAGS_STRONGNAMESIGNED) == \ + dotnet.COMIMAGE_FLAGS_ILONLY & \ + dotnet.COMIMAGE_FLAGS_STRONGNAMESIGNED \ + }", + "tests/data/" + "0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171"); + + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + dotnet.is_dotnet and \ + for any typeref in dotnet.typerefs : ( \ + typeref.namespace == \"System.Reflection\" and \ + typeref.name == \"AssemblyTitleAttribute\") \ + }", + "tests/data/" + "0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171"); + + assert_true_rule_file( + "import \"dotnet\" \ + rule test { \ + condition: \ + dotnet.is_dotnet and \ + dotnet.number_of_memberrefs == 6 and \ + dotnet.memberrefs[1].name == \".ctor\" \ + }", + "tests/data/" + "0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171"); + yr_finalize(); YR_DEBUG_FPRINTF( 1, stderr, "} = %d // %s() in %s\n", result, __FUNCTION__, argv[0]); return result; -} +} \ No newline at end of file