Good approach to determine the PEFileKind of an assembly? - c#

In C# or VB.NET, I would like to know which would be the best approach to determine the PEFileKinds of an assembly loaded through Reflection. In other words, determine whether an assembly is a WinExe, Console application, or a Dynamic link library.
I found this solution (the other proposed solutions in that question are not effective), but If I'm not wrong I think it implies to assume that the file loaded is a .NET assembly, and, seems a little bit tidy to manually parse the PE header.
I also found this other solution but reading the comments it seem not effective in some circumstances.
For those reasons, I wonder if exists a truly safe, managed way, preferably through Reflection, to determine the PE file kind of a loaded assembly.
I'm sure the System.Reflection.Emit.PEFileKinds enumeration does not exists only for decorative purposes, if that enum exists then its logic to think that there could be a member/function that I missed inside the Reflection namespaces that internally use that enum to return the PE file kind of a Assembly object, however, I managed to look at the private members of the Assembly class through Reflection and other related classes and I found nothing relevant.

According to a search of the reference source, the PEFileKinds enum is only used in AssemblyBuilder and ModuleBuilder (and the non-public helper types for them). This enum and the classes are found in the System.Reflection.Emit namespace - e.g., they're intended for writing assemblies, not reading.
However, the official System.Reflection.Metadata NuGet package exposes the relevant values of an assembly's PE header in its System.Reflection.PortableExecutable namespace. You can use these headers to reverse engineer the equivalent PEFileKinds value. Here's an example in C#:
using (var stream = File.OpenRead(filenameAndExtension))
{
using (var peFile = new PEReader(stream))
{
var headers = peFile.PEHeaders;
Console.WriteLine($"Reading {filenameAndExtension} with System.Reflection.Metadata");
Console.WriteLine($" IsDll: {headers.IsDll}");
Console.WriteLine($" IsExe: {headers.IsExe}");
Console.WriteLine($" IsConsoleApplication: {headers.IsConsoleApplication}");
PEFileKinds reverseEngineeredKind;
// NOTE: the header values cause IsConsoleApplication to return
// true for DLLs, so we need to check IsDll first
if (headers.IsDll)
{
reverseEngineeredKind = PEFileKinds.Dll;
}
else if (headers.IsConsoleApplication)
{
reverseEngineeredKind = PEFileKinds.ConsoleApplication;
}
else
{
reverseEngineeredKind = PEFileKinds.WindowApplication;
}
Console.WriteLine($" Reverse-engineered kind: {reverseEngineeredKind}");
}
}
I ran this code on assemblies I generated with System.Reflection.Emit to ensure its accuracy. The full program is in this gist.
You can probably also get this information with third-party libraries, like Mono.Cecil or, as Lex Li mentioned, PeNet.

Related

Injecting and modifying C# executable

I would like to ask if it is possible to somehow inject C# code to an existing *.exe file that is also written in C# without decompiling it.
In other words, I'm trying to make an "extension" to an already existing C# program, but I would like to modify it without any manipulation with the "base" code (the .*exe file).
Is there any way to accomplish this? Or is the decompilation process required to modify base code's methods, classes and/or add extensions to it, etc. ?
you can achieve it by using frameworks like Mono.Cecil or Microsoft CCI project. These frameworks allows you to read & modify/inject IL. But it's not easy to learn those frameworks and IL codes usage.
Thought there's a library available FluentIL which is build on top of Mono.Cecil provides C# wrapper for IL Code. It doesn't Decompile the assembly rather it loads it, inject the assembly can writes/generates a new one with injected code.
Here's a sample that I used to inject "Null Checking code" in methods where arguments are marked with [NotNull] in project assembly post compilation.
var assembly = AssemblyDefinition.ReadAssembly(SourceAssemblyPath);
var module = assembly.MainModule;
var q = from type in module.Types
from method in type.Methods
from parameter in method.Parameters
where parameter.HasCustomAttributes
from attribute in parameter.CustomAttributes
where attribute.AttributeType.FullName == NotNullAttribute.FullName
select new { Method = method, Parameter = parameter };
foreach (var item in q)
{
item.Method.InsertBefore()
.Ldarg(item.Parameter.Name)
.IfNull()
.Throw<ArgumentNullException>()
.EndIf();
}
SourceAssemblyPath = SourceAssemblyPath.Replace("\\debug\\", "\\release\\");
assembly.Write(SourceAssemblyPath, new WriterParameters { WriteSymbols = false });

How to fetch Root namespace defined in a .NET Assembly using Reflection [duplicate]

Given an instance of System.Reflection.Assembly.
I have come across this dilemma plenty of times when I want to load a resource from the current assembly by its manifest resource stream.
The fact is that if you embed a file as a resource in your assembly using Visual Studio its manifest resource name will be derived from the default namespace of the assembly as defined in the Visual Studio project.
The best solution I've come up with (to avoid hardcoding the default namespace as a string somewhere) is to simply ensure your resource loading code is ALWAYS happening from inside a class that's also in the default namespace and then the following near-generic approach may be used.
This example is loading an embedded schema.
XmlSchema mySchema;
string resourceName = "MyEmbeddedSchema.xsd";
string resourcesFolderName = "Serialisation";
string manifestResourceName = string.Format("{0}.{1}.{2}",
this.GetType().Namespace, resourcesFolderName, resourceName);
using (Stream schemaStream = currentAssembly.GetManifestResourceStream(manifestResourceName))
mySchema = XmlSchema.Read(schemaStream, errorHandler);
See also: How to get Namespace of an Assembly?
Edit: Also noticed a very detailed answer to the question I'm answering at http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/3a469f5d-8f55-4b25-ac25-4778f260bb7e
Another edit in case people with same question come looking: Excellent idea to solve the resource-loading question here: How get the default namespace of project csproj (VS 2008)
Not possible. Nothing specifies a "Root" namespace. The default namespace in the options is a visual studio thing, not a .net thing
There could be any number of namespaces in a given assembly, and nothing requires them to all start from a common root. The best you could do would be to reflect over all the types in an assembly and build up a list of unique namespaces contained therein.
I just created an empty internal class called Root and put it in the project root (assuming this is your root namespace). Then I use this everywhere I need the root namespace:
typeof(Root).Namespace;
Sure I end up with an unused file, but it's clean.
Assemblies don't necessarily have a root namespace. Namespaces and Assemblies are orthogonal.
What you may be looking for instead, is to find a type within that Assembly, and then find out what its namespace is.
You should be able to accomplish this by using the GetExportedTypes() member and then using the Namespace property from one of the returned Type handles.
Again though, no guarantees all the types are in the same namespace (or even in the same namespace hierarchy).
I use typeof(App).Namespace in my WPF application.
App class is mandatory for any WPF application and it's located in root.
Get Types gives you a list of Type objects defined in the assembly. That object has a namespace property. Remember that an assembly can have multiple namespaces.
GetType(frm).Namespace
frm is the startup Form
Namespaces have nothing to do with assemblies - any mapping between a namespace and the classes in an assembly is purely due to a naming convention (or coincidence).
There actually is an indirect way to get it, by enumerating the names of the assembly's manifest resources. The name you want ends with the part of it that you know.
Rather than repeat the code here, please see get Default namespace name for Assembly.GetManifestResourceStream() method
The question I had that landed me here was, "If I call library code N methods deep and want the namespace of the Project - for example the MVC app that's actually running - how do I get that?"
A little hacky but you can just grab a stacktrace and filter:
public static string GetRootNamespace()
{
StackTrace stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames();
string ns = null;
foreach(var frame in stackFrames)
{
string _ns = frame.GetMethod().DeclaringType.Namespace;
int indexPeriod = _ns.IndexOf('.');
string rootNs = _ns;
if (indexPeriod > 0)
rootNs = _ns.Substring(0, indexPeriod);
if (rootNs == "System")
break;
ns = _ns;
}
return ns;
}
All this is doing is getting the stacktrace, running down the methods from most recently called to root, and filtering for System. Once it finds a System call it knows it's gone too far, and returns you the namespace immediately above it. Whether you're running a Unit Test, an MVC App, or a Service, the System container is going to be sitting 1 level deeper than the root namespace of your Project, so voila.
In some scenarios where System code is an intermediary (like System.Task) along the trace this is going to return the wrong answer. My goal was to take for example some startup code and let it easily find a class or Controller or whatever in the root Namespace, even if the code doing the work sits out in a library. This accomplishes that task.
I'm sure that can be improved - I'm sure this hacky way of doing things can be improved in many ways, and improvements are welcome.
Adding to all the other answers here, hopefully without repeating information, here is how I solved this using Linq. My situation is similar to Lisa's answer.
My solution comes with the following caveats:
You're using Visual Studio and have a Root Namespace defined for your project, which I assume is what you're asking for since you use the term "root namespace"
You're not embedding interop types from referenced assemblies
Dim baseNamespace = String.Join("."c,
Me.GetType().Assembly.ManifestModule.GetTypes().
Select(Function(type As Type)
Return type.Namespace.Split("."c)
End Function
).
Aggregate(Function(seed As String(), splitNamespace As String())
Return seed.Intersect(splitNamespace).ToArray()
End Function
)
)
Here as a rather simple way to get the root namespace for a website project.
''' <summary>
''' Returns the namespace of the currently running website
''' </summary>
Public Function GetWebsiteRootNamespace() As String
For Each Asm In AppDomain.CurrentDomain.GetAssemblies()
If Asm Is Nothing OrElse Asm.IsDynamic Then Continue For
For Each Typ In Asm.GetTypes
If Typ Is Nothing OrElse Typ.Name Is Nothing Then Continue For
If Typ.Name = "MyProject" Then Return Typ.Namespace.Split("."c)(0)
Next
Next
Return Nothing
End Function
This simply checks all the loaded assemblies for the "MyProject" type and returns the root namespace for that type. This is useful for logging when you have multiple web projects in a single solution sharing a log system. Hope this helps someone.
This solution works if you are trying to load an embedded resource.
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
string[] resourceNames = assembly.GetManifestResourceNames();
string resourceNameNoNamespace = $"Languages.{languageSupport.IsoCode}.Languages.xml";
var match = resourceNames.SingleOrDefault(rn => rn.EndsWith(resourceNameNoNamespace));
Dim applicationNamespace = TextBeforeFirst(Assembly.GetCallingAssembly().EntryPoint.DeclaringType.Namespace, ".")
Public Function TextBeforeFirst(value As String, expression As String) As String
If String.IsNullOrEmpty(value) Or String.IsNullOrEmpty(expression) Then Return Nothing
Dim index = value.IndexOf(expression)
If index = -1 Then Return Nothing
Dim length = index
Return value.Substring(0, length)
End Function

a correct way of forcing assembly load into current domain

I have a project that uses several class libraries that are part of my project, first AssemblyA is loaded, then AssemblyB is loaded. In AssemblyA there is code that does the following
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var assemblyB = assemblies
.Where(x=>x.GetName() == "AssemblyB")
.First();
var type = assemblyB.GetType("AssemblyB_Type");
Unfortunately when AssemblyA tries to do that, AssemblyB is not loaded yet into CurrentDomain, so to load that assembly I'm doing the following unnecessary thing:
var x = typeof(AssemblyB.AssemblyB_Type);
The compiler shows warning that this line is not needed, though I can't find words to explain it that otherwise it won't work, so the question would be, how do you correctly (in Feng Shui terms) force Assembly load into CurrentDomain without doing extra-unuseful plumbing
Your existing code is the best way to do that (AFAIK).
To get rid of the warning, change it to
typeof(AssemblyB.AssemblyB_Type).ToString();
If your referenced assemblies are deployed correctly, they should "just load" if you call one of its types. The .NET framework should take care of this for you.
Here's a good article explaining the way the framework searches for your referenced assemblies: http://msdn.microsoft.com/en-us/library/yx7xezcf(v=vs.71).aspx
I'm curious what you're doing that you need to load an assembly prematurely like this?
A hack to answer your direct question is to use Assembly.Load(string location) - though I would discourage this unless absolutely necessary. http://msdn.microsoft.com/en-us/library/ky3942xh.aspx
So, you could just load all the assemblies in your bin directory into the app domain. This should solve your problem.
var assemblies = Directory.GetFiles(containingDirectory, "*.dll")'
foreach (var assembly in assemblies)
{
Assembly.Load(AssemblyName.GetAssemblyName(assembly));
}
This is what I do:
public static class TypeExtensions {
public static void EnsureAssemblyLoads(this Type pType) {
// do nothing
}
}
...
typeof(SomeType).EnsureAssemblyLoads();

Is there a way to do a conditional check against whether your code is obfuscated in C#?

Is there a way to check whether your code base is obfuscated programmatically?
In my project, I'm using reflection to load classes from an outside DLL (which I control). The data for loading the information (assembly and class name) are stored in a resource file.
Once I obfuscate the project, I am unable to link the outside DLL into the output EXE (i.e. roll up all assemblies into a single output executable), because the assembly name in the resource file is no longer correct (the DLL has become part of the EXE). But I have to preserve the un-obfuscated functionality as well for debugging purposes.
What I'd like to do, is have the code check to see if it has been obfuscated at runtime. If it hasn't, use the assembly name in the resource file; if it has, use the name of the application. Is something like this possible?
Most Obfuscators, such as Dotfuscate, will put an assembly level Custom Attribute on the assembly. If that is the case of your obfuscator, check to see if the attribute is present, such as:
bool foundObfuscatationAttribute = false;
foreach (object attribute in attributes)
{
if (attribute.GetType().FullName == "DotfuscatorAttribute")
{
foundObfuscatationAttribute = true;
break;
}
}
//If found...
Since we don't want to reference the assembly that contains the attribute itself, we check by name.
Ask for the type info of a class you know will be obfuscated and check if the name is still the unobfuscated one. In code typeof(MyClass).Name == "MyClass" (may need include the namespace).
Set a compile flag or some kind of flag you can reach using Reflection to check if it is
Another way to check if the assembly(dll) is obfuscated from Dotfuscator, without need to the dependencies in the folder is:
public static bool IsDllOfuscated(string dirFile)
{
return Assembly.Load(File.ReadAllBytes(dirFile)).GetType("DotfuscatorAttribute") != null;
}

How to determine the code-file filename from a compiled application at runtime

Let's say I have an application with two files.
Console.cs and Business.cs
Console.cs has program Main class.
Business.cs has three classes named Customer, Order and Orderline.
Is there anyway in C# to determine at runtime (maybe with reflection) that the business objects are in a file named Business.cs?
The C# compiler does not emit this information into the DLL, so it's not available through reflection. However, as you'll be aware from debugging, the debugger can match up compiled locations to source code locations. It does this through PDB files. So it might be theoertically possible for you to ship your PDB files, and invoke the unmanaged debugger or diagnostic symbol store API (see General Reference > Unmanaged API Reference in MSDN) to determine where a given method was defined. You can't really do this for a class, though, because a class could be spread across multiple files using partial classes.
If you compile in debug mode you can probably use Cecil (part of Mono project) to extract the source filenames from the debug symbols. But when you compile in release mode this information probably gets lost.
However, if you need to do this, for other purposes than for example static analysis of your software, you are probably on the wrong track and should think of another solution.
If you put the classes in a Business namespace you could use reflection to find if an object comes from that namespace:
namespace Business {
class Customer {}
class Order {}
class OrderLine {}
}
var myObject = new Customer();
Console.WriteLine(myObject.GetType().Namespace); // writes "Business"
I believe the closest you'll get is typeof(Customer).Assembly.Location. However, this will only give you the DLL, not the location of the source code (which makes sense, since the source code would normally not be included with the binaries).
*.PDB (debug info files) files should have that information. Otherwise I see no way to get it, since code files is just an abstraction which compiled code should not care about.
not sure what your use case is, however if some one is calling you then you can add
compiler directives
[CallerFilePath] string file = "", [CallerLineNumber] int LineNo = 0
in your method.
if not than your best way of accessing this is by using the .pdb file that get's generated. The format is published and a C++ dll is available that can be used to access the file however the easiest way to read the file (and possible line number) if included in the pdb file is using stacktrace
You can access the stack in an exception, so if a class allows you to throw an exception by passing null where you should not than try catch it and you have your stack trace.
if you need the calling file but do not want to add the compiler directives as some one can simply overwrite it you can do something like:
StackTrace st = new StackTrace(new StackFrame(1));
st.GetFrame(1).GetFileName());
Assuming :
You have a project (probably technical with some extension methods etc) that all other projects in your solution reference (let's name it "NameSpaceGloballyVisibleByAllProjects")
You are using SDK-style csproj for your project (otherwise you'll have a little more work)
People in your team code without doing fancy things (ie: "class" / "struct"/ "enum" keywords are at the beginning of their own line in your .cs files).
It means that, by adding this class in "NameSpaceGloballyVisibleByAllProjects":
using System;
using System.Runtime.CompilerServices;
namespace NameSpaceGloballyVisibleByAllProjects
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum, AllowMultiple = true, Inherited = false)]
public class MemorizeFilePathAttribute : Attribute
{
public string Path() { return _filepath; }
public MemorizeFilePathAttribute([CallerFilePath] string filepath = "")
{
_filepath = filepath;
}
readonly string _filepath;
}
}
You can simply use it like this:
using System.Reflection;
using NameSpaceGloballyVisibleByAllProjects;
Type type = typeof(Program);
var files = type.GetCustomAttributes<MemorizeFilePathAttribute>(false).Select(att => att.Path).ToList();
Note: As you notice there are more than one file! This is because of "partial" keyword in C#. So it's up to you to use "files.Single()" or not...
We just need to add this attribute above all types now
We can do that in Visual Studio with Ctr-H (Find-and-Replace).
Select All Solution
Check options "regex" & "case sensitive"
Find: "^( *)([a-z][a-z ]*)? (class|struct|enum) "
(without double quotes, but with the final ' '!)
Replace by: "$1 [NameSpaceGloballyVisibleByAllProjects.MemorizeFilePath]\r\n$1$2 $3 "
(without double quotes, but with the final ' '!)
Be ready for this to take a little time (Go get a coffe... or tea)

Categories

Resources