During application assessments, I have stumbled upon several cases when I need to call out a specific function embedded in a .NET assembly (be it .exe or .dll extension). For example, an encrypted database password is found in a configuration file. Using .NET Decompiler, I am able to see and identify the function used to encrypt the database password. The encryption key appears to be static, so if I could call the corresponding decrypt function, I would be able to recover that password.
Classic solution: using Visual Studio to create new project, import encryption library, call out that function if it’s public or use .NET Reflection API if it’s private (or just copy the class to the new workspace, change method accessibility modifier to public and call out the function too if it is self-contained).
Alternative (and hopeful less-time consuming) solution: Powershell could be used in conjunction with .NET Reflection API to invoke methods directly from the imported assemblies, bypassing the need of an IDE and the grueling process of compiling source code.
Note that Powershell version 3 is used in the below examples, and the assembly is developed in C#.
Walkthrough
First, identify the fully qualified class name (typically in the form of Namespace.Classname ), method name, accessibility level, member modifier and method arguments. This can easily be done with any available .NET Decompiler (dotPeek, JustDecompile, Reflector)
Scenario 1: Public static class – Call public static method
namespace AesSample
{
public class AesLibStatic
{
...
public static string DecryptString(string cipherText)
{
return DecryptStringPrivate(StringToByteArray(cipherText));
}
This is the vanilla case, essentially in powershell you just need to call [Namespace].[Classname]::(params[]) And it only took 2 lines of code to do it:
Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}}
#Call public static method
[AesSample.AesLibStatic]::DecryptString("8E3C5A3088CEA26B634CFDA09D13A7DB")
Result:
Scenario 2: Public static class – Call private static method
Let’s say you want to call this private static method, assuming the method name is unique within the class
Private methods can’t be accessed directly from Powershell object, instead you will need to find it by name and correct binding flags. More information about binding flags could be found here: https://msdn.microsoft.com/en-us/library/4ek9c21e.aspx
#Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}}
#Only retrieve static private method
$BindingFlags= [Reflection.BindingFlags] "NonPublic,Static"
#Load method based on name
$PrivateMethod = [AesSample.AesLibStatic].GetMethod("DecryptStringSecret",$bindingFlags)
#Invoke
$PrivateMethod.Invoke($null,"8E3C5A3088CEA26B634CFDA09D13A7DB")
Scenario 2 Extension: Function Overloading: Public static class – Call private static method
In some cases, programmer takes advantage of function overloading feature of Object-Oriented languages – i.e multiple methods can have the same name as long as they have different argument list. For example:
Note that the two DecryptStringPrivate methods have the same name, but one takes a string as input, while another takes a bytearray as input. In this case, to look up the right method, you will need method name and method signature. The snippet below will invoke DecryptStringPrivate(byte[] cipherText)
#Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}}
#Search for private method based on name
$PrivateMethods = [AesSample.AesLibStatic].GetMethods($bindingFlags) | Where-Object Name -eq DecryptStringPrivate
$PrivateMethods | ForEach-Object{
$PrivateMethod=$_
$MethodParams=$PrivateMethod.GetParameters()
$MemberSignature = $MethodParams | Select -First 1 | Select-Object Member
#This will list all the method signatures
$MemberSignature.Member.ToString()
#Choose the correct method based on parameter list
If ($MemberSignature.Member.ToString() -eq "System.String DecryptStringPrivate(Byte[])"){
[byte[]]$Bytes =@(70,1,65,70,155,197,95,238,85,79,190,34,158,69,125,233,53,212,111,19,248,209,147,180,19,172,150,25,97,41,127,175)
[Object[]] $Params=@(,$Bytes)
#Call with the right arguments
$PrivateMethod.Invoke($null,$Params)
}
}
Scenario 3: Public class – Call nonstatic public method
If a class is not declared with “static” keyword, its methods can’t be invoked directly from the class itself but from an instance of the class with the following snippet:
Classname a = new Classname();
a.methodName(args[]);
For example:
namespace AesSample {
public class AesLib {...public string DecryptString(string cipherText) {
return DecryptStringPrivate(StringToByteArray(cipherText));
}
Sample solution:
#Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}}
#Call default constructor (no argument)
$AesSample= New-Object "AesSample.AesLib"
#Call constructor with arguments using this syntax: $AesSample= New-Object "AesSample.AesLib" ("a","b")
#Invoke public method
$AesSample.DecryptString("8E3C5A3088CEA26B634CFDA09D13A7DB")
Scenario 4: Public class: Function Overloading – Call nonstatic private method
This is very similar to Scenario 2: extension above. Again you will need both method name and argument list to call the right method.
#Load all .NET binaries in the folder
Get-ChildItem -recurse "D:DocumentsVisual Studio 2010ProjectsAesSampleAesSamplebinDebug"|Where-Object {($_.Extension -EQ ".dll") -or ($_.Extension -eq ".exe")} | ForEach-Object { $AssemblyName=$_.FullName; Try {[Reflection.Assembly]::LoadFile($AssemblyName)} Catch{ "***ERROR*** Not .NET assembly: " + $AssemblyName}}
#Call constructor
$Instance= New-Object "AesSample.AesLib" ("a","b")
# Find private nonstatic method. If you want to invoke static private method, replace Instance with Static
$BindingFlags= [Reflection.BindingFlags] "NonPublic,Instance"
$Instance.GetType().GetMethods($BindingFlags) | Where-Object Name -eq DecryptStringPrivate| ForEach-Object{
$PrivateMethod=$_
$MethodParams=$PrivateMethod.GetParameters()
$MemberSignature = $MethodParams | Select -First 1 | Select-Object Member
$MemberSignature.Member.ToString()
If ($MemberSignature.Member.ToString() -eq "System.String DecryptStringPrivate(Byte[])"){
[byte[]]$Bytes =@(70,1,65,70,155,197,95,238,85,79,190,34,158,69,125,233,53,212,111,19,248,209,147,180,19,172,150,25,97,41,127,175)
[Object[]] $Params=@(,$Bytes)
# You will need to pass the Instance here instead of $null
$PrivateMethod.Invoke($Instance,$Params)
}
}
Closing thoughts:
I didn’t include code to call out methods from private class in this post. Mainly because usually you can find a public class that reference to private class if it needs to use some methods of the private class, and then you can just invoke the calling method of the public class instead.
Those snippets work under assumption that all necessary .NET assemblies are located in the same folder. If other externally-linked .NET assemblies are required, add additional code to load them into memory.
Same with externally-linked native assemblies: either set them in your PATH environment variable, manually copy them to C:Windowssystem32 (not recommended) or load them with Powershell’s DllImport: https://blogs.msdn.com/b/mattbie/archive/2010/02/23/how-to-call-net-and-win32-methods-from-powershell-and-your-troubleshooting-packs.aspx
This method may also be useful in situations where you can’t decompile the application’s assemblies due to legal constraints. Consult with client or your contact before doing this, but it may be OK to list assembly’s methods and call them when necessary. This snippet will import all assemblies found in a folder and list all the constructors, methods along with argument list in a Powershell GridView (it’s kind of like mini-Excel so you have built-in search and filter features)
Necessary cookies help make a website usable by enabling basic functions like page navigation and access to secure areas of the website. The website cannot function properly without these cookies.
Name
Domain
Purpose
Expiry
Type
YSC
youtube.com
YouTube session cookie.
52 years
HTTP
Marketing cookies are used to track visitors across websites. The intention is to display ads that are relevant and engaging for the individual user and thereby more valuable for publishers and third party advertisers.
Name
Domain
Purpose
Expiry
Type
VISITOR_INFO1_LIVE
youtube.com
YouTube cookie.
6 months
HTTP
Test
test.com
Testing
7 days
HTTP
Analytics cookies help website owners to understand how visitors interact with websites by collecting and reporting information anonymously.
We do not use cookies of this type.
Preference cookies enable a website to remember information that changes the way the website behaves or looks, like your preferred language or the region that you are in.
We do not use cookies of this type.
Unclassified cookies are cookies that we are in the process of classifying, together with the providers of individual cookies.
We do not use cookies of this type.
Cookies are small text files that can be used by websites to make a user's experience more efficient. The law states that we can store cookies on your device if they are strictly necessary for the operation of this site. For all other types of cookies we need your permission. This site uses different types of cookies. Some cookies are placed by third party services that appear on our pages.
Cookie Settings
Discover how the NetSPI BAS solution helps organizations validate the efficacy of existing security controls and understand their Security Posture and Readiness.