capa
capa copied to clipboard
dotnet: consider emitting references to types
methods interact with various types, including both primitive objects (u8) and classes. sometimes we see method/property access to the classes, which can be represented by things like API
(and maybe offset
???). we might also see direct references to class objects, such as casting instances from one class to another.
do we want to introduce a new feature to represent types/classes referenced within some scope?
e.g.
type: System.Net.FtpWebResponse
I vote we boot #982 to the next release. #982 ties in with some other .NET feature parsing I believe we will need more research and discussion on before implementing.
@mike-hunhoff
track CIL
instructions:
-
newobj
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.newobj?view=net-6.0 -
castclass
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.castclass?view=net-6.0 -
initobj
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.initobj?view=net-6.0 -
newarr
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.newarr?view=net-6.0 -
box
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.box?view=net-6.0 -
constrained
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.constrained?view=net-6.0 -
cpobj
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.cpobj?view=net-6.0 -
isinst
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.isinst?view=net-6.0 -
ldelem
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.ldelem?view=net-6.0 -
ldelema
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.ldelema?view=net-6.0 -
ldobj
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.ldobj?view=net-6.0 -
mkrefany
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.mkrefany?view=net-6.0 -
refanyval
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.refanyval?view=net-6.0 -
sizeof
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.sizeof?view=net-6.0 -
stelem
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.stelem?view=net-6.0 -
stobj
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.stobj?view=net-6.0 -
unbox
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.unbox?view=net-6.0 -
unbox.any
: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.unbox_any?view=net-6.0
we may be able to emit namespace
and class
features for type references, like we do for method calls e.g.
... newobj instance void [System]System.Uri::.ctor(string)
... newobj instance void [System]System.IO.Compression.GZipStream::.ctor(class [mscorlib]System.IO.Stream, valuetype [System]System.IO.Compression.CompressionMode, bool)
- namespace: System
- class: System.Uri
- namespace: System.IO.Compression
- class: System.IO.Compression.GZipStream
the proposal above does not allow us to capture object creation e.g.
... newobj instance void [mscorlib]System.Threading.Mutex::.ctor(bool, string, bool&)
we could emit this as a new type
feature, as Willi suggested, or maybe a new instance
feature e.g.
rule:
meta:
name: create mutex using .NET
...
features:
- or:
- instance: System.Threading.Mutex
...
I think I prefer instance
to better communicate the object has been created, versus type
which I think we can represent using the existing namespace
and class
features e.g. for the snippet above emit
- namespace: System.Threading
- class: System.Threading.Mutex
- instance: System.Threading.Mutex
unsure about the overlap of class
and instance
but I think this allows rule authors to write more intentional rules e.g. we can distinguish between "manipulate mutex using .NET" w/ -class: System.Threading.Mutex
and "create mutex using.NET" w/ -instance: System.Threading.Mutex
.
another use case for an instance
feature:
... newobj instance void [mscorlib]System.Reflection.Emit.DynamicMethod::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Type[], class [mscorlib]System.Type, bool)
- namespace: System.Reflection.Emit
- class: System.Reflection.Emit.DynamicMethod
- instance: System.Reflection.Emit.DynamicMethod
As a programmer, I get the difference between instance and class. But from a perspective of matching malware behavior, does it make enough difference to warrant a new feature?
Note also that the rule author must be competent at programming to differentiate the cases to construct accurate rules. Not sure if this is a strong or weak argument, though.
On Jul 28, 2022, at 1:43 PM, Mike Hunhoff @.***> wrote:
another use case for an instance feature:
... newobj instance void [mscorlib]System.Reflection.Emit.DynamicMethod::.ctor(string, class [mscorlib]System.Type, class [mscorlib]System.Type[], class [mscorlib]System.Type, bool)
- namespace: System.Reflection.Emit
- class: System.Reflection.Emit.DynamicMethod
- instance: System.Reflection.Emit.DynamicMethod — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.
Chatted with @adamstorek offline about the ability to distinguish object instantiation in capa rules. This is especially important when analyzing scripting languages e.g.
... new System.Threading.Mutex();
which we see as the following in .NET CIL:
... newobj System.Threading.Mutex::.ctor
We discussed the potential of emitting an object instantiation as an api
feature using the keyword ctor
:
- api: System.Threading.Mutex::ctor
This would allow us to capture the intended behavior without needing to add new features.