capa
capa copied to clipboard
dotnet: detect OS
Research and implement if its possible to determine OS for .NET file; these should all be PEs so my best guess without further research is focusing on statically detecting the CLR
Maybe start with exploring TargetFrameworkAttribute?
we need to update the rule format documentation to describe OS_ANY, too:
https://github.com/mandiant/capa-rules/blob/b035bb8d90e556f412b6ee9ef738ce6c68bbd9cd/doc/format.md#os
we should definitely get (1) working as intended.
agree that we should do the research for (2). that's probably a #good-first-issue. then, once we know if it's possible and what to look for, we can tweak the behavior of the .NET feature extractor.
we need to update the rule format documentation to describe OS_ANY, too:
https://github.com/mandiant/capa-rules/blob/b035bb8d90e556f412b6ee9ef738ce6c68bbd9cd/doc/format.md#os
see #1324
Hello @mike-hunhoff @williballenthin, it's Colton, one of the FLARE interns from last summer! Do you mind if I take a crack at this one?
Hello @colton-gabertan! Absolutely, go for it! Please let us know if you have any questions
Thanks for the chance!
Off the bat, after looking into detecting the CLR statically, I think that for the purpose of purely detecting the OS via looking for the specific CLR's may not be the best route (at least while CAPA is statically analyzing the binaries ;) ). I say this because, yes the CLR's are platform-specific, but it's more or less the CLR's job to locate the assembly to be ran and not the other way around...at least to my understanding.
I did dig more into Attributes from there, and found something that may be pretty interesting. Microsoft released a platform compatibility analyzer that helps developers check whether or not their applications would be able to be ran cross-platform/OS. The way it does it is that specific .NET core libraries and api calls are now labeled with attributes that indicate what platform they are for.
These attributes may be seen as:
- OSPlatformAttribute
- ObsoletedOSPlatformAttribute
- SupportedOSPlatformAttribute
- SupportedOSPlatformGuardAttribute
- UnsupportedOSPlatformAttribute
- UnsupportedOSPlatformGuardAttribute
Example via documentation:
[SupportedOSPlatform("windows"),...]
public class apiClass
{
}
With this in mind, if we can figure out specifically which functions are labeled with which attributes, it could be one way to help detect the OS that the binaries were designed for. I can try to create a nursery rule for this as a Proof of Concept, but after looking at the CAPA repo, it might be more suited to go into the lib namespace if designed this way.
Any thoughts on this approach?
My reading:
- https://learn.microsoft.com/en-us/dotnet/api/system.runtime.versioning?view=net-7.0
- https://learn.microsoft.com/en-us/dotnet/standard/analyzers/platform-compat-analyzer
- https://learn.microsoft.com/en-us/dotnet/standard/class-libraries?source=recommendations
Thanks for all of your research @colton-gabertan! 🚀
Ideally we can identify a solution that works for all .NET files processed by capa.
My initial concern with your approach is that it is unclear if the attributes you describe are present in all .NET files. Do you have additional insight here? Also, capa does not process .NET attributes so there is no way presently to write a rule to detect use of specific attributes. This is a feature I've considered adding in the past but it may be a significant undertaking as a I do not believe dnfile supports attribute parsing, yet.
What are your thoughts on using TargetFrameworkAttribute to detect specific operating systems? I've come across this in the past but did not dig very deep. I'm interested to hear your thoughts based on the attribute research you've done here.
@mike-hunhoff
I've taken a deeper dive into TargetFrameworkAttribute
and it seems to only provide useful info for assemblies compiled against .NET 4+ in terms of the specific framework, anything below will return a general result i.e. 2, 3, or 3.5. However, this article, provides a bit of C# code that can be used as an extension method to extract this information. With framework info we can cross-check against OS's that support those versions; however, I still feel that this would allow us to only make educated guesses at best as multiple OS's may support the same versions.
The source code for the TargetFrameworkAttribute
class shows that the info is literally two string members of the class, but doesn't go into much detail as to how those strings are assigned when ran against an assembly. Based on how attributes work, they're an extension of a pefile's metadata. So, in this light, I'm hoping that the info is parse-able from somewhere within the metadata tables of the pefiles.
In the code from the article above, there is a call to GetCustomAttributes()
, which I found the source code for in order to see how it parses the file for it. However, the code itself is a bit ambiguous. If my theory is correct, then pulling version info should be relatively easy to integrate into CAPA, just using the pefile/dnfile module. I've also confirmed that the layout of the tables is currently undocumented in ECMA-335, unfortunately.
So, my solution for now would probably just to essentially pull any "unmanaged" imports and try cross-reference them with any from the Windows/Linux/MacOS apis to determine the OS. This task sounds very tedious, though.
did dig more into Attributes from there, and found something that may be pretty interesting. Microsoft released a platform compatibility analyzer that helps de
On that note, a wider solution would be if we see the .NET file try to dynamically import specifically a .dll we may be able to label it as Windows, if it tries to import a .so.* or a .dylib that may be indicative of a linux-based system. However, the downfalls are that CAPA will only even attempt this if the binary tries to import things, and any cross-platform-functional binaries will be labeled as working on all.
@mike-hunhoff
As per our email discussion, this enhancement is likely to evolve into a larger project. Unassigning myself from the issue for now.
I can't find any documentation stating whether the OS attributes (OSPlatformAttribute, ObsoletedOSPlatformAttribute, etc.) are in the method header, method body, or a MetaDataTable. Given the various string values I am seeing in examples, I suspect it is in neither a MetaDataTable nor the method header. If you know of some other .NET parsing program that is able to identify these guard conditions then let me know, either by creating an Issue on dnfile or just @ me in this thread.
I am working on method header parsing in a branch on dnfile, but it has turned into a lot more work than I initially anticipated