mirror of
https://github.com/VirusTotal/yara.git
synced 2026-10-11 22:49:58 +00:00
Add parsing of .NET user types from .NET metadata stream (#1605)
* Add simple_str string implementation * Add ability to parse .NET user defined types to 'dotnet' module * Add copyright information * Unify comment style, define iter variable within for loop * Fix invalid handling of corrupted parameters * Remove duplicate test_dotnet in BUILD.bazel * Fix unaligned memory access. (#1) * Fix unaligned memory access. * Add missing comma in Bazel file. Co-authored-by: Victor M. Alvarez <[email protected]>
This commit is contained in:
co-authored by
Victor M. Alvarez
parent
77a57a1ba3
commit
15ec337e04
@@ -77,6 +77,111 @@ Reference
|
||||
|
||||
*Example: dotnet.guids[0] == "99c08ffd-f378-a891-10ab-c02fe11be6ef"*
|
||||
|
||||
.. c:type:: number_of_classes
|
||||
The number of classes in the file.
|
||||
|
||||
.. c:type:: classes
|
||||
An array of .NET classes stored in the metadata. Individual classes can be accessed
|
||||
using the [] operator. Each class object contains the following attributes:
|
||||
|
||||
.. c:member:: fullname
|
||||
Class full name.
|
||||
|
||||
.. c:member:: name
|
||||
Class name.
|
||||
|
||||
.. c:member:: namespace
|
||||
Class namespace.
|
||||
|
||||
.. c:member:: visibility
|
||||
Class visibility specifier, options are:
|
||||
|
||||
``private``
|
||||
``public``
|
||||
``protected``
|
||||
``internal``
|
||||
``private protected``
|
||||
``protected internal``
|
||||
|
||||
.. c:member:: type
|
||||
Type of the object, options are:
|
||||
|
||||
``class``
|
||||
``interface``
|
||||
|
||||
.. c:member:: abstract
|
||||
Boolean representing if class is abstract.
|
||||
|
||||
.. c:member:: sealed
|
||||
Boolean representing if class is sealed.
|
||||
|
||||
.. c:member:: number_of_generic_parameters
|
||||
Number of generic parameters.
|
||||
|
||||
.. c:member:: generic_parameters
|
||||
A zero-based array of generic parameters name. Individual parameters can be accessed using the [] operator.
|
||||
|
||||
.. c:member:: number_of_base_types
|
||||
Number of the base types.
|
||||
|
||||
.. c:member:: base_types
|
||||
A zero-based array of base types name. Individual base types can be accessed using the [] operator.
|
||||
|
||||
.. c:member:: number_of_methods
|
||||
Number of the methods.
|
||||
|
||||
.. c:member:: methods
|
||||
A zero-based array of method objects. Individual methods can be accessed by
|
||||
using the [] operator. Each object contains following attributes:
|
||||
|
||||
.. c:member:: name
|
||||
Method name.
|
||||
|
||||
.. c:member:: visibility
|
||||
Method visibility specifier, options are:
|
||||
|
||||
``private``
|
||||
``public``
|
||||
``protected``
|
||||
``internal``
|
||||
``private protected``
|
||||
``protected internal``
|
||||
|
||||
.. c:member:: static
|
||||
Boolean representing if method is static.
|
||||
|
||||
.. c:member:: virtual
|
||||
Boolean representing if method is virtual.
|
||||
|
||||
.. c:member:: final
|
||||
Boolean representing if method is final.
|
||||
|
||||
.. c:member:: abstract
|
||||
Boolean representing if method is abstract.
|
||||
|
||||
.. c:member:: return_type
|
||||
Method return type name.
|
||||
|
||||
.. c:member:: number_of_parameters
|
||||
Number of the method parameters.
|
||||
|
||||
.. c:member:: parameters
|
||||
A zero-based array of method parameters. Individual parameters can be accessed by using the [] operator.
|
||||
|
||||
.. c:member:: name
|
||||
Parameter name.
|
||||
|
||||
.. c:member:: type
|
||||
Parameter type.
|
||||
|
||||
.. c:member:: number_of_generic_parameters
|
||||
Number of the method generic parameters.
|
||||
|
||||
.. c:member:: generic_parameters
|
||||
A zero-based array of method generic parameters. Individual parameters can be accessed by using the [] operator.
|
||||
|
||||
*Example: dotnet.classes[0].fullname == "Launcher.Program"*
|
||||
|
||||
.. c:type:: number_of_resources
|
||||
|
||||
The number of resources in the .NET file. These are different from normal PE
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <yara/pe.h>
|
||||
#include <yara/pe_utils.h>
|
||||
#include <yara/types.h>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@@ -72,6 +73,10 @@ typedef struct _TILDE_HEADER
|
||||
ULONGLONG Sorted;
|
||||
} TILDE_HEADER, *PTILDE_HEADER;
|
||||
|
||||
// flag in HeapSizes that denotes extra 4 bytes after Rows
|
||||
#define HEAP_EXTRA_DATA 0x40
|
||||
#define SIG_FLAG_GENERIC 0x10
|
||||
|
||||
// These are the bit positions in Valid which will be set if the table
|
||||
// exists.
|
||||
#define BIT_MODULE 0x00
|
||||
@@ -129,16 +134,86 @@ typedef struct _TILDE_HEADER
|
||||
//#define BIT_IMPORTSCOPE 0x35
|
||||
//#define BIT_STATEMACHINEMETHOD 0x36
|
||||
|
||||
//
|
||||
// Element types. Note this is not a complete list as we aren't parsing all of
|
||||
// them. This only includes the ones we care about.
|
||||
// ECMA-335 Section II.23.1.16
|
||||
//
|
||||
#define ELEMENT_TYPE_STRING 0x0E
|
||||
|
||||
// The string length of a typelib attribute is at most 0xFF.
|
||||
#define MAX_TYPELIB_SIZE 0xFF
|
||||
|
||||
// Flags and Masks for .NET tables
|
||||
#define TYPE_ATTR_CLASS_SEMANTIC_MASK 0x20
|
||||
#define TYPE_ATTR_CLASS 0x0
|
||||
#define TYPE_ATTR_INTERFACE 0x20
|
||||
|
||||
#define TYPE_ATTR_VISIBILITY_MASK 0x7
|
||||
#define TYPE_ATTR_NOT_PUBLIC 0x0
|
||||
#define TYPE_ATTR_PUBLIC 0x1
|
||||
#define TYPE_ATTR_NESTED_PUBLIC 0x2
|
||||
#define TYPE_ATTR_NESTED_PRIVATE 0x3
|
||||
#define TYPE_ATTR_NESTED_FAMILY 0x4
|
||||
#define TYPE_ATTR_NESTED_ASSEMBLY 0x5
|
||||
#define TYPE_ATTR_NESTED_FAM_AND_ASSEM 0x6
|
||||
#define TYPE_ATTR_NESTED_FAM_OR_ASSEM 0x7
|
||||
|
||||
#define TYPE_ATTR_ABSTRACT 0x80
|
||||
#define TYPE_ATTR_SEALED 0x100
|
||||
|
||||
#define METHOD_ATTR_ACCESS_MASK 0x7
|
||||
#define METHOD_ATTR_PRIVATE 0x1
|
||||
#define METHOD_ATTR_FAM_AND_ASSEM 0x2
|
||||
#define METHOD_ATTR_ASSEM 0x3
|
||||
#define METHOD_ATTR_FAMILY 0x4
|
||||
#define METHOD_ATTR_FAM_OR_ASSEM 0x5
|
||||
#define METHOD_ATTR_PUBLIC 0x6
|
||||
|
||||
#define METHOD_ATTR_STATIC 0x10
|
||||
#define METHOD_ATTR_FINAL 0x20
|
||||
#define METHOD_ATTR_VIRTUAL 0x40
|
||||
#define METHOD_ATTR_ABSTRACT 0x400
|
||||
|
||||
// Element types ECMA-335 Section II.23.1.16
|
||||
#define TYPE_END 0x0
|
||||
#define TYPE_VOID 0x1
|
||||
#define TYPE_BOOL 0x2
|
||||
#define TYPE_CHAR 0x3
|
||||
#define TYPE_I1 0x4
|
||||
#define TYPE_U1 0x5
|
||||
#define TYPE_I2 0x6
|
||||
#define TYPE_U2 0x7
|
||||
#define TYPE_I4 0x8
|
||||
#define TYPE_U4 0x9
|
||||
#define TYPE_I8 0xa
|
||||
#define TYPE_U8 0xb
|
||||
#define TYPE_R4 0xc
|
||||
#define TYPE_R8 0xd
|
||||
#define TYPE_STRING 0xe
|
||||
#define TYPE_PTR 0xf
|
||||
#define TYPE_BYREF 0x10
|
||||
#define TYPE_VALUETYPE 0x11
|
||||
#define TYPE_CLASS 0x12
|
||||
#define TYPE_VAR 0x13
|
||||
#define TYPE_ARRAY 0x14
|
||||
#define TYPE_GENERICINST 0x15
|
||||
#define TYPE_TYPEDREF 0x16
|
||||
#define TYPE_I 0x18
|
||||
#define TYPE_U 0x19
|
||||
#define TYPE_FNPTR 0x1b
|
||||
#define TYPE_OBJECT 0x1c
|
||||
#define TYPE_SZARRAY 0x1d
|
||||
#define TYPE_MVAR 0x1e
|
||||
#define TYPE_CMOD_REQD 0x1f
|
||||
#define TYPE_CMOD_OPT 0x20
|
||||
#define TYPE_INTERNAL 0x21
|
||||
#define TYPE_MODIFIER 0x40
|
||||
#define TYPE_SENTINEL 0x41
|
||||
#define TYPE_PINNED 0x45
|
||||
|
||||
// Sane boundaries for invalid files
|
||||
#define MAX_ARRAY_RANK 50
|
||||
#define MAX_PARAM_COUNT 2000
|
||||
#define MAX_GEN_PARAM_COUNT 1000
|
||||
#define MAX_METHOD_COUNT 20000
|
||||
#define MAX_STRING_LENGTH 10000
|
||||
// Sanity check for loops in type parser
|
||||
#define MAX_TYPE_DEPTH 0x10
|
||||
|
||||
//
|
||||
// Module table
|
||||
// ECMA-335 Section II.22.30
|
||||
@@ -306,9 +381,84 @@ typedef struct _CONSTANT_TABLE
|
||||
} Value;
|
||||
} CONSTANT_TABLE, *PCONSTANT_TABLE;
|
||||
|
||||
// ECMA 335 - II.22.37
|
||||
typedef struct _TYPEDEF_ROW
|
||||
{
|
||||
uint32_t Flags;
|
||||
uint32_t Name;
|
||||
uint32_t Namespace;
|
||||
uint32_t Extends;
|
||||
uint32_t Field;
|
||||
uint32_t Method;
|
||||
} TYPEDEF_ROW, *PTYPEDEF_ROW;
|
||||
|
||||
// ECMA 335 - II.22.38
|
||||
typedef struct _TYPEREF_ROW
|
||||
{
|
||||
uint32_t ResolutionScope;
|
||||
uint32_t Name;
|
||||
uint32_t Namespace;
|
||||
} TYPEREF_ROW, *PTYPEREF_ROW;
|
||||
|
||||
// ECMA 335 - II.22.39
|
||||
typedef struct _TYPESPEC_ROW
|
||||
{
|
||||
uint32_t Signature;
|
||||
} TYPESPEC_ROW, *PTYPESPEC_ROW;
|
||||
|
||||
// ECMA 335 - II.22.23
|
||||
typedef struct _INTERFACEIMPL_ROW
|
||||
{
|
||||
uint32_t Class;
|
||||
uint32_t Interface;
|
||||
} INTERFACEIMPL_ROW, *PINTERFACEIMPL_ROW;
|
||||
|
||||
// ECMA 335 II.22.26
|
||||
typedef struct _METHODDEF_ROW
|
||||
{
|
||||
uint32_t Rva;
|
||||
uint16_t ImplFlags;
|
||||
uint16_t Flags;
|
||||
uint32_t Name;
|
||||
uint32_t Signature;
|
||||
uint32_t ParamList;
|
||||
} METHODDEF_ROW, *PMETHODDEF_ROW;
|
||||
|
||||
// ECMA 335 II.22.33
|
||||
typedef struct _PARAM_ROW
|
||||
{
|
||||
uint16_t Flags;
|
||||
uint16_t Sequence;
|
||||
uint32_t Name;
|
||||
} PARAM_ROW, *PPARAM_ROW;
|
||||
|
||||
// ECMA 335 II.22.20
|
||||
typedef struct _GENERICPARAM_ROW
|
||||
{
|
||||
uint16_t Number;
|
||||
uint16_t Flags;
|
||||
uint32_t Owner;
|
||||
uint32_t Name;
|
||||
} GENERICPARAM_ROW, *PGENERICPARAM_ROW;
|
||||
|
||||
// ECMA 335 II.22.32
|
||||
typedef struct _NESTEDCLASS_ROW
|
||||
{
|
||||
uint32_t NestedClass;
|
||||
uint32_t EnclosingClass;
|
||||
} NESTEDCLASS_ROW, *PNESTEDCLASS_ROW;
|
||||
|
||||
// For easy passing of gen param collection
|
||||
typedef struct _GENERIC_PARAMETERS
|
||||
{
|
||||
char **names;
|
||||
uint32_t len;
|
||||
} GENERIC_PARAMETERS, *PGENERIC_PARAMETERS;
|
||||
|
||||
// Used to return offsets to the various headers.
|
||||
typedef struct _STREAMS
|
||||
{
|
||||
int64_t metadata_root; // base from which are stream offsets relative
|
||||
PSTREAM_HEADER guid;
|
||||
PSTREAM_HEADER tilde;
|
||||
PSTREAM_HEADER string;
|
||||
@@ -321,9 +471,33 @@ typedef struct _STREAMS
|
||||
typedef struct _BLOB_PARSE_RESULT
|
||||
{
|
||||
uint8_t size; // Number of bytes parsed. This is the new offset.
|
||||
DWORD length; // Value of the bytes parsed. This is the blob length.
|
||||
uint32_t length; // Value of the bytes parsed. This is the blob length.
|
||||
} BLOB_PARSE_RESULT, *PBLOB_PARSE_RESULT;
|
||||
|
||||
typedef struct _TABLE_INFO
|
||||
{
|
||||
uint8_t *Offset;
|
||||
uint32_t RowCount;
|
||||
uint32_t RowSize;
|
||||
} TABLE_INFO, *PTABLE_INFO;
|
||||
|
||||
// Structure that stores table information for parsing
|
||||
typedef struct _TABLES
|
||||
{
|
||||
TABLE_INFO typedef_;
|
||||
TABLE_INFO typespec;
|
||||
TABLE_INFO typeref;
|
||||
TABLE_INFO methoddef;
|
||||
TABLE_INFO param;
|
||||
TABLE_INFO module;
|
||||
TABLE_INFO moduleref;
|
||||
TABLE_INFO assembly;
|
||||
TABLE_INFO assemblyref;
|
||||
TABLE_INFO intefaceimpl;
|
||||
TABLE_INFO genericparam;
|
||||
TABLE_INFO nestedclass;
|
||||
} TABLES, *PTABLES;
|
||||
|
||||
// Used to store the number of rows of each table.
|
||||
typedef struct _ROWS
|
||||
{
|
||||
@@ -359,16 +533,40 @@ typedef struct _INDEX_SIZES
|
||||
uint8_t blob;
|
||||
uint8_t field;
|
||||
uint8_t methoddef;
|
||||
uint8_t methodspec;
|
||||
uint8_t memberref;
|
||||
uint8_t param;
|
||||
uint8_t event;
|
||||
uint8_t typedef_;
|
||||
uint8_t typeref;
|
||||
uint8_t typespec;
|
||||
uint8_t interfaceimpl;
|
||||
uint8_t property;
|
||||
uint8_t moduleref;
|
||||
uint8_t module;
|
||||
uint8_t assemblyrefprocessor;
|
||||
uint8_t assemblyref;
|
||||
uint8_t assembly;
|
||||
uint8_t genericparam;
|
||||
} INDEX_SIZES, *PINDEX_SIZES;
|
||||
|
||||
typedef struct _CLASS_CONTEXT
|
||||
{
|
||||
PE* pe;
|
||||
TABLES* tables;
|
||||
INDEX_SIZES* index_sizes;
|
||||
const uint8_t* str_heap;
|
||||
uint32_t str_size;
|
||||
const uint8_t* blob_heap;
|
||||
uint32_t blob_size;
|
||||
} CLASS_CONTEXT, *PCLASS_CONTEXT;
|
||||
|
||||
typedef struct _PARAMETERS
|
||||
{
|
||||
char* name;
|
||||
char* type;
|
||||
bool alloc; // if name is allocated and needs to be free
|
||||
} PARAMETERS, *PPARAMETERS;
|
||||
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
+1761
-120
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,32 @@
|
||||
/*
|
||||
Copyright (c) 2022. The YARA Authors. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <yara/mem.h>
|
||||
|
||||
+4
-3
@@ -114,6 +114,7 @@ cc_test(
|
||||
"data/079a472d22290a94ebb212aa8015cdc8dd28a968c6b4d3b88acdd58ce2d3b885",
|
||||
"data/079a472d22290a94ebb212aa8015cdc8dd28a968c6b4d3b88acdd58ce2d3b885.upx",
|
||||
"data/3b8b90159fa9b6048cc5410c5d53f116943564e4d05b04a843f9b3d0540d0c1c",
|
||||
"data/ChipTune.efi",
|
||||
"data/ca21e1c32065352d352be6cde97f89c141d7737ea92434831f998080783d5386",
|
||||
"data/mtxex.dll",
|
||||
"data/mtxex_modified_rsrc_rva.dll",
|
||||
@@ -122,10 +123,9 @@ cc_test(
|
||||
"data/tiny",
|
||||
"data/tiny-idata-51ff",
|
||||
"data/tiny-idata-5200",
|
||||
"data/tiny-macho",
|
||||
"data/tiny-overlay",
|
||||
"data/weird_rich",
|
||||
"data/ChipTune.efi",
|
||||
"data/tiny-macho"
|
||||
],
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
@@ -239,9 +239,10 @@ cc_test(
|
||||
srcs = ["test-dotnet.c"],
|
||||
copts = COPTS,
|
||||
data = [
|
||||
"data/tiny",
|
||||
"data/0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171",
|
||||
"data/756684f4017ba7e931a26724ae61606b16b5f8cc84ed38a260a34e50c5016f59",
|
||||
"data/bad_dotnet_pe",
|
||||
"data/tiny",
|
||||
],
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
|
||||
Binary file not shown.
@@ -84,6 +84,54 @@ int main(int argc, char** argv)
|
||||
"tests/data/"
|
||||
"0ca09bde7602769120fadc4f7a4147347a7a97271370583586c9e587fd396171");
|
||||
|
||||
assert_true_rule_file(
|
||||
"import \"dotnet\" \
|
||||
rule test { \
|
||||
condition: \
|
||||
dotnet.classes[0].fullname == \"Autodesk.AutoCAD.Internal.Windows.MenuServices\" and \
|
||||
dotnet.classes[0].name == \"MenuServices\" and \
|
||||
dotnet.classes[0].namespace == \"Autodesk.AutoCAD.Internal.Windows\" and \
|
||||
dotnet.classes[0].visibility == \"public\" and \
|
||||
dotnet.classes[0].type == \"class\" and \
|
||||
dotnet.classes[0].abstract and \
|
||||
dotnet.classes[0].sealed and \
|
||||
dotnet.classes[0].number_of_generic_parameters == 0 and \
|
||||
dotnet.classes[0].number_of_base_types == 1 and \
|
||||
dotnet.classes[0].base_types[0] == \"System.Object\" and \
|
||||
dotnet.classes[0].number_of_methods == 20 and \
|
||||
dotnet.classes[0].methods[0].name == \"Initialize\" and \
|
||||
dotnet.classes[0].methods[0].visibility == \"public\" and \
|
||||
dotnet.classes[0].methods[0].static and \
|
||||
not dotnet.classes[0].methods[0].virtual and \
|
||||
not dotnet.classes[0].methods[0].final and \
|
||||
dotnet.classes[0].methods[0].return_type == \"void\" and \
|
||||
dotnet.classes[0].methods[0].parameters[0].name == \"productName\" and \
|
||||
dotnet.classes[0].methods[0].parameters[0].type == \"string\" and \
|
||||
dotnet.classes[0].methods[0].parameters[1].name == \"maxRecentFiles\" and \
|
||||
dotnet.classes[0].methods[0].parameters[1].type == \"int\" and \
|
||||
dotnet.classes[0].methods[0].number_of_generic_parameters == 0 and \
|
||||
dotnet.classes[156].fullname == \"Autodesk.AutoCAD.Ribbon.Point3dDoubleToStringConverter\" and \
|
||||
dotnet.classes[156].name == \"Point3dDoubleToStringConverter\" and \
|
||||
dotnet.classes[156].namespace == \"Autodesk.AutoCAD.Ribbon\" and \
|
||||
dotnet.classes[156].number_of_base_types == 2 and \
|
||||
dotnet.classes[156].base_types[0] == \"System.Object\" and \
|
||||
dotnet.classes[156].base_types[1] == \"System.Windows.Data.IValueConverter\" and \
|
||||
dotnet.classes[156].number_of_methods == 3 and \
|
||||
dotnet.classes[156].methods[0].name == \"Convert\" and \
|
||||
dotnet.classes[156].methods[0].return_type == \"object\" and \
|
||||
dotnet.classes[156].methods[0].number_of_parameters == 4 and \
|
||||
dotnet.classes[156].methods[0].parameters[0].name == \"value\" and \
|
||||
dotnet.classes[156].methods[0].parameters[0].type == \"object\" and \
|
||||
dotnet.classes[156].methods[0].parameters[1].name == \"targetType\" and \
|
||||
dotnet.classes[156].methods[0].parameters[1].type == \"System.Type\" and \
|
||||
dotnet.classes[156].methods[0].parameters[2].name == \"parameter\" and \
|
||||
dotnet.classes[156].methods[0].parameters[2].type == \"object\" and \
|
||||
dotnet.classes[156].methods[0].parameters[3].name == \"culture\" and \
|
||||
dotnet.classes[156].methods[0].parameters[3].type == \"System.Globalization.CultureInfo\" \
|
||||
}",
|
||||
"tests/data/"
|
||||
"756684f4017ba7e931a26724ae61606b16b5f8cc84ed38a260a34e50c5016f59");
|
||||
|
||||
assert_false_rule(
|
||||
"import \"dotnet\" \
|
||||
rule test { \
|
||||
|
||||
Reference in New Issue
Block a user