mas_4
mas_4
com
1. Introduction
Welcome to the fourth article of MAS (Malware Analysis Series). After I have posted three articles that,
hopefully, provided you with relevant concepts, techniques and some new knowledge on malware
analysis, so let’s move forward to learn new and interesting aspects of other well-known malicious
Windows binaries available for downloading from public sandboxes such as Malware Bazaar, Triage,
Polyswarm, Malshare, Hybrid Analysis, Virus Total and other ones.
Just in case you haven’t read the previous articles, you can download them from:
▪ MAS_1: https://exploitreversing.com/2021/12/03/malware-analysis-series-mas-article-1/
▪ MAS_2: https://exploitreversing.com/2022/02/03/malware-analysis-series-mas-article-2/
▪ MAS_3: https://exploitreversing.com/2022/05/05/malware-analysis-series-mas-article-3/
Throughout this text I will refresh concepts explained in previous articles, but I don’t have any plan for
getting into details, so it’s recommended to read them once again just in case you need it. Of course, in
practical terms and along the time, many explained techniques, approaches and concepts will be repeated
over and over again to provide you with further experience about proposed topics.
In this fourth part of this series, we’ll scratch the surface of .NET malware analysis, which sometimes
might present difficulties for analysts due to several and different techniques and tricks. We have excellent
tools available for helping us such as dnSpy and ILSpy, which make an excellent job in decompiling code to
MSIL (Microsoft Intermediate Language) and offering an approximate code to the original in high-level
.NET language, but in some cases isn’t still enough due to customized encoding and encrypted data, which
force us to use different techniques to be able to proceed and tackle the binary.
I’ll try to provide a minimal theory about the subject to ensure you understand the basic information
required while reversing .NET code. No doubts, .NET malware analysis a quite extensive topic and we will
return to this subject in future articles of this series.
As you’ll during all analysis of managed code threats, most of the time will came up additional stages also
written in .NET, and some of them are protected with a packer, obfuscator or even a modern protector. At
end of day, our mission is handling each of these stages, decrypting them and moving forward to the next
one, until being able to find the final payload, which could not be so easy to get it.
Like binary malware threats, in .NET malware analysis we also search for persistence techniques, C2
communication, evasion techniques, data exfiltration, clear text URLs, credentials and all sort of IOCs
that might help us to identify similar threats. Certainly we will encounter a wide spectrum of challenges
1|Page
https://exploitreversing.com
and obstacles to analyze managed code (.NET code), and this task might be harder yet than native code
because it’s necessary to have much of knowledge learned from native binary analysis and know specific
concepts about .NET architecture and manage several issues (obfuscation and cryptography, as usual ) to
get good results from the analysis. As you will see, .NET malware threats are in everywhere and are
heavily used in many threat campaigns nowadays.
Now we’re ready to proceed to setup a lab environment and refresh key concepts.
2. Lab Setup
We’ll be using the following environment during this article and future articles focused on .NET reversing
and, this time, I’m going to focus only on .NET related tools: :
▪ DnSpy: it’s a .NET assembly editor and debugger, but this project was archived, unfortunately. You
can download/clone it from: https://github.com/dnSpy/dnSpy.
▪ DnSpyEx: This is the revival of the original dnSpy project and has been constantly updated:
https://github.com/dnSpyEx/dnSpy
▪ De4dot: it’s a .NET deobfuscator and unpacker. You can download/clone it from:
https://github.com/de4dot/de4dot. It’ uses dnlib (below) to read and write assemblies.
Additionally, de4dot is also available in many Linux distributions and to install it execute: apt get
install de4dot.
▪ dnlib: it’s a module used to manipulate (read/write) .NET assemblies. Clone it: git clone
https://github.com/0xd4d/dnlib
▪ ILSpy: It’s an open-source .NET assembly browser and decompiler. It can be downloaded/cloned
from: https://github.com/icsharpcode/ILSpy
We won’t use all of the mentioned tools in this article, but it would be recommended to install them on
their Windows virtual machines for future binary analysis. To any external de-obfuscator necessary during
the analysis, so I’m going to indicate the proper URL to download it.
3. .NET Concepts
Definitely learning programming in several languages such as C, C++ and C# is not quite critical to perform
reverse engineering, but certainly this knowledge takes you up to a next level and helps to acquire a better
understanding of the code before taking decisions during any analysis.
Thus, and based on this premise, I’ll review key concepts related to .NET programming in this section. Of
course, I won’t explain how to program any code, but I will only expose relevant concepts about .NET for
helping readers to become a bit more comfortable while analyzing .NET malware samples.
2|Page
https://exploitreversing.com
Probably we’ll find malware samples written in .NET Framework and .NET Core and, as you probably
already know, .NET code is a managed code, which needs a .NET runtime
(https://github.com/dotnet/runtime) to be executed. These. NET binaries are basically composed by MSIL
(Microsoft Intermediate Language) instructions and metadata. Of course, probably you rarely handle IL
(Intermediate Language) instructions (though it is required in some obfuscated samples) and, if you want,
you can list all .NET runtimes and SDKs by executing: dotnet --list-runtimes / dotnet --list-sdks.
While malware samples compiled in .NET Framework assemblies, which also contains metadata
(manifest), can be either .dll or .exe file, .NET Core samples are always compiled as a .dll file (usually
compiled using: dotnet <assembly>.dll). Another subtle difference is that .NET Core doesn’t use the GAC
(Global Assembly Cache) like .NET Framework used as a common installation directory for framework
libraries.
If you already analyzed .NET threats previously, so probably you also found encrypted payloads in
embedded .NET resources, which can be unpacked using distinguished approaches as dumping the
unpacked resource (a .NET module, for example) from the memory using common tools like dnSpy or
specific programs to accomplish the same task.
Similar to any native binary, a .NET malware threat might also unpack another .NET malware (a .dll module
or .exe file) or a native code to be injected into a running process, and this injected malicious binary could
be a downloader to the next stage, which can download a native or managed code and start the real
infection. Even worse, some .NET malicious payload are able to attack the own .NET runtime and
compromise the entire environment.
In a daily malware analysis job, you probably will find .NET malware samples obfuscated using well-known
obfuscators such ConfuserEx, .NET Reactor, Dotfuscator, babelfor.NET, Agile, and so on, or even a
customized protectors, so it could demand some time to unpack and de-obfuscate such sample due the
existence of so many distinguished approaches. Depending on used obfuscating techniques, you can wait
for different tricks such as:
▪ Methods signatures, fields and metadata renaming.
▪ Encrypted strings.
▪ Junk code
▪ Control Flow obfuscation.
▪ Cross-Reference obfuscation
▪ Obfuscated Implementation methods.
▪ Obfuscated/hidden cross references
Any .NET code (included malware binaries, of course) can interact with the system using class from
System.Diagnostics namespace such as Process, ProcessModule, ProcessThread,
ProcessThreadCollection, ProcessStartInfo, and so on. Furthermore, there’re different methods such as
Start( ), Kill( ), GetProcesses( ), GetCurrentProcess( ), GetProcessById( ) etc, which are applied to the
Process type mentioned in this paragraph and interact directly with a running system. As a programming
concepts, remember that to compile assemblies with System.Diagnostics namespace, programmers will
need System.Linq namespace, so that’s an additional clue about what readers should expect for.
.NET applications (composed by one or more assemblies) are hosted within an application domain, which
can be accessed using AppDomain.CurrentDomain static property. These assemblies can be accessed
3|Page
https://exploitreversing.com
using System.Reflection namespace and this is a critical stuff for malware analysts to learn because we’ll
find .NET Reflection methods being use in the most of the .NET malware samples.
A very short list of well-known methods from System, System.Reflection and also other namespaces,
which could be used by .NET malware threats, follows below and, as you’ll learn, these methods are
interesting targets to set up a breakpoint during dynamic analysis:
▪ Activator.CreateInstance: this method is used to create an instance of a specified type by using a
technique named “late binding”, which provides the possibility of creating an instance of a given
type and, better, invoking any of its member at runtime without having any pre-determined
reference to the member of given an external assembly in the code.
▪ Assembly.CreateInstance: this methods locates a type from this assembly and creates an instance.
▪ Assembly.GetExecutingAssembly: this method gets the assembly that contains the code that’s
currently executing.
▪ Assembly.GetEntryAssembly: this method gets the process executable in the default application
domain.
▪ Assembly. GetFile: this method returns a FileStream for the specified file in the file table of the
manifest of this assembly.
▪ Assembly.GetModule: this method gets the specified module in the given assembly.
▪ Assembly.GetType: this method gets the type given a string, for example.
▪ Assembly.Load: this method loads an assembly.
▪ Assembly.LoadFile: this method loads the content of an assembly file.
▪ Assembly.LoadFrom: this method loads the content of an assembly file.
▪ Assembly.LoadModule: this method loads the module internal to the given assembly.
▪ Assembly.GetLoadedModules: this method gets all the loaded modules that make part of the given
assembly.
▪ AssemblyDependencyResolver.ResolveAssemblyToPath: this method resolves a path to an
assembly given an assembly’s name.
▪ AppDomain.GetAssemblies: this method gets assemblies that have been loaded into the
application domain context.
▪ ConstructorInfo.Invoke: this method invokes the constructor given by the instance.
▪ System.Reflection.AssemblyName GetAssemblyName: this method gets the AssemblyName for a
given file.
▪ Module.GetField: this method returns a specified field.
▪ Module.GetFields: this method returns the global fields on a given module.
▪ Module.GetMethod: this method returns a method given a string name.
▪ Module.GetMethods: this method returns the global methods defined on the module.
▪ Module.IsResource: this method determines whether the given object is a resource or not.
▪ MethodBase.Invoke: this method invokes the method or constructor.
▪ ResourceManager class: it represents a resource manager, which offers access to culture
resources.
▪ Module.GetMethodImpl: this method returns an implementation of a method.
A .NET malware binary contains the following structure:
▪ File header
4|Page
https://exploitreversing.com
5|Page
https://exploitreversing.com
DOS Header
PE Header
PE Header
Data Directories
(size and location of CLR header)
CLR Header
Section Headers
.text
CLR Data (includes MSIL and metadata)
(ILcode, metadata,
managed resources) .idata
.data
Native Code /
Data Remaining sections
4. General Procedure
Certainly one of most common questions from professionals while examining .NET malware threats is:
what details and clues should I take note while analyzing a .NET sample?
Of course, there aren’t fixed rules here and some considerations should be taken:
▪ Determine whether the malware code is really a .NET code.
7|Page
https://exploitreversing.com
▪ Try to identify whether the malware is packed. Even the presence of embedded resources are a
fair indication that there might be some malicious code hidden (and obfuscated).
▪ Discover the real Entry Point (pay attention to .cctor and .ctor constructors).
▪ Examine the code and try to identify possible obfuscator’s presence.
▪ Tools such as de4dot (better editing capabilities when executed on PowerShell) and other
customized ones will help you to de-obfuscate the code.
▪ How do you plan to unpack it? You should consider a mix of static and dynamic approach.
▪ Most .NET malware are really large, so don’t try to analyze all of them line-by-line. Most of time, it
isn’t worth, though in few cases you don’t have another alternative (knowing C# could help you).
▪ If you use dynamic analysis (probably also using dnSpy), so try to set up breakpoints on critical
methods listed previously.
▪ While analyzing methods, pay attention to non-used parameters.
▪ While using dnSpy, debugger’s tabs such Local, Call Stack and Modules are incredibly useful.
▪ Remember that malicious modules are loaded anytime and you always can dump them from
memory.
▪ There’re .NET malware samples that result to a final .NET malware and other ones that result to a
native malicious binary. Therefore, don’t make any conclusion in advance.
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscorlib.dll
C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.PowerShell.ConsoleHost\v4.0_3.0.0.0__31bf
3856ad364e35\Microsoft.PowerShell.ConsoleHost.dll
C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\Syste
m.Core.dll
C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3
856ad364e35\System.Management.Automation.dll
C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.Management.Infrastructure\v4.0_1.0.0.0__3
1bf3856ad364e35\Microsoft.Management.Infrastructure.dll
C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.Management\v4.0_4.0.0.0__b03f5f7f11d50a3a
\System.Management.dll
C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System.DirectoryServices\v4.0_4.0.0.0__b03f5f7f11d50
a3a\System.DirectoryServices.dll
MDStreamVersion : 131072
FullyQualifiedName : C:\Users\Administrator\Desktop\MAS\MAS_4\malware_dotnet.bin
ModuleVersionId : 53d49999-e4ad-4b0b-be7a-8497530feeda
MetadataToken :1
ScopeName : WaitCallb.exe
Name : malware_dotnet.bin
Assembly : WaitCallb, Version=1.7.3.0, Culture=neutral, PublicKeyToken=null
CustomAttributes : {}
ModuleHandle : System.ModuleHandle
MDStreamVersion : 131072
FullyQualifiedName : C:\Users\Administrator\Desktop\MAS\MAS_4\malware_dotnet.bin
ModuleVersionId : 53d49999-e4ad-4b0b-be7a-8497530feeda
MetadataToken :1
ScopeName : WaitCallb.exe
Name : malware_dotnet.bin
Assembly : WaitCallb, Version=1.7.3.0, Culture=neutral, PublicKeyToken=null
CustomAttributes : {}
ModuleHandle : System.ModuleHandle
Name : MapVisitor
DeclaringType : WaitCallb.Filter.GlobalValueFilter
ReflectedType : WaitCallb.Filter.GlobalValueFilter
MemberType : Method
MetadataToken : 100663315
Module : WaitCallb.exe
IsSecurityCritical : True
IsSecuritySafeCritical : False
IsSecurityTransparent : False
MethodHandle : System.RuntimeMethodHandle
Attributes : PrivateScope, Private, Static, HideBySig
CallingConvention : Standard
ReturnType : System.Void
ReturnTypeCustomAttributes : Void
ReturnParameter : Void
IsGenericMethod : False
…
# List all classes of the Assembly.
PS C:\ > $Malware_Assembly.GetModules().gettypes()|?{$_.isPublic -AND $_.isClass}
WaitCallb.g.resources
WaitCallb.States.ReponseListState.resources
WaitCallb.Filter.MappingValueFilter.resources
aR3nbf8dQp2feLmk31.lSfgApatkdxsVcGcrktoFd.resources
Tourield.Properties.Resources.resources
CanRead : True
CanSeek : True
CanWrite : False
Length : 5650
Capacity : 5650
Position :0
PositionPointer :
CanTimeout : False
ReadTimeout :
Version Name
------- --------------------------------
4.0.0.0 mscorlib
4.0.0.0 PresentationFramework
4.0.0.0 System.Windows.Forms
4.0.0.0 System
4.0.0.0 System.Drawing
4.0.0.0 PresentationCore
4.0.0.0 System.Xaml
4.0.0.0 WindowsBase
4.0.0.0 System.Core
Name : InsertProcess
Name : RunProcess
Name
--------
Equals
GetHashCode
GetType
ToString
Name
----
Finalize
MemberwiseClone
Equals
GetHashCode
GetType
12 | P a g e
https://exploitreversing.com
ToString
Finalize
MemberwiseClone
InsertProcess
RunProcess
We’re also able to invoke any method of a .NET malware during our analysis, but we’re going to return to
this topic in next articles.
During .NET malware analysis we will encounter Dynamic Assemblies, which concept is quite different
from Static Assemblies. The latter are loaded from a file on disk while dynamic assemblies are created on
memory (at runtime) using a special naming space named System.Relfection.Emit that offers the
possibility of creating assemblies, modules, performing CIL implementation, etc, during runtime.
This System.Relfection.Emit namespace has several members such as:
▪ AssemblyBuilder: this class is used to create an assembly at runtime.
▪ TypeBuilder: this class to control the creation of interfaces, delegates, structures and, of course,
classes in a module.
▪ ModuleBuilder: this class is used to define a module within a given assembly.
▪ MethodBuilder: this class defines and represents a method/constructor.
▪ EnumBuilder: this class is used to create a .NET enumeration type.
It’s required to use ILGenerator class and its associated methods such as Emit, EmitCall, BeginScope,
DeclaredLocal and so on to emit raw CIL opcodes and, dynamically, make the entire assembly.
13 | P a g e
https://exploitreversing.com
Although this article isn’t about programming, further details that could help readers interested in learning
a bit more about the topic follow:
▪ System.Reflection.Emit NuGet package should be installed.
15 | P a g e
https://exploitreversing.com
6. Threat information
The sample that will be analyzing in this article is SHA 256:
▪ 7cb92356a0170028fabc20f0cb9736b149efab01824ab1173b3277340a6a2ec4
You can download the sample from Malware Bazaar:
16 | P a g e
https://exploitreversing.com
17 | P a g e
https://exploitreversing.com
[Figure 9] Gathering information about the sample from Malware Bazaar (continuation)
18 | P a g e
https://exploitreversing.com
[Figure 10] Gathering information about the sample from Virus Total
There’s good information from Figures 7, 8, 9 and 10 that we could consider about this sample:
▪ Its “original name” seems to be tup.exe.
▪ Likely it performs code injection (WriteProcessMemory + SetThreadContext).
▪ It seems to “escalate privileges” during the execution (AdjustPrivilegeToken).
▪ It apparently uses hooking technique (SetWindowsHookEx).
▪ It enumerates processes (EnumeratesProcess) for, maybe, picking up one to inject code.
▪ WMI is used by the malware. Infinite probabilities: anti-vm, anti-debugging, and so on.
▪ A new process is launched, which might be a native one.
▪ A file is created.
19 | P a g e
https://exploitreversing.com
▪ The sample is the AgentTesla (or one of its variants) and written in .NET (mscoree.dll).
▪ The .text section entropy is too high (7.91), so maybe hiding or “packing” something. However,
remember: on .NET, the embedded resources make part of the .text section, so the high entropy
could be reflecting possible embedded resources.
It’s relevant to underscore that all considerations above are only possibilities and first information.
Remember that the malware is likely packed/obfuscated, so there’re many artifacts to be discovered.
To check possible existence of packers/obfuscators in a .NET malware, readers could use Exeinfo PE
(https://github.com/ExeinfoASL/ASL) or DiE (https://github.com/horsicq/Detect-It-Easy), which are great
tools to check existence of packers and obfuscators:
[Figure 11] Checking packers through Exeinfo PE and Detect It Easy (DiE)
20 | P a g e
https://exploitreversing.com
Both tools tell us a possible existence of .NET Reactor, though we need to confirm whether there is a
packer or not by analyzing the code.
A last tool that’s always recommended while analyzing .NET samples is pestudio
(https://www.winitor.com/download/). I’m using the free version of pestudio and the paid one has much
more features:
7. Analysis
That’s the start point of our analysis and comprehensive understanding of the threat. As you’ll remember
about .NET analysis, most of samples have embedded resources (managed resources), which might be a
binary (managed module or binary) to be unpacked in real time. From those ones, few of them work as a
simple downloader of an external resource that is the real malicious payload to be executed.
Nonetheless, that’s the crucial point. There’re three well-known approaches to unpack a .NET malware:
a. using an specialized debugger and assembly editor for .NET such as dnSpy / dnSpyEx and
proceeding manually doing the analysis.
b. using a native debugger and some associated tricks to do it semi-automatically.
c. using a specialized tool to accomplish this task automatically.
Actually, using the term “unpacking” could be imprecise in some cases because resource could be only
encoded (or even in plain text), but certainly we can continue using the term without any lost of meaning.
Due to motivation in highlighting few concepts presented in previous sections, we’re taking the first
approach and, in next articles, we’ll try the other two possibilities.
Although readers already know, remember that over any debugging session (even a managed one) the
system can and likely will be infected, so don’t forget to disable networking communications, disable
shared folder and, mainly, take a snapshot.
Thus, open the malware (mas_4.bin) on dnSpy and let’s make some notes about the sample:
22 | P a g e
https://exploitreversing.com
23 | P a g e
https://exploitreversing.com
24 | P a g e
https://exploitreversing.com
As readers can verify, this method is using two arguments: text, which receives exactly the Assembly
Location (line 994) and 101. Going into this method, we have:
25 | P a g e
https://exploitreversing.com
Once again, we have a kind of state variable (num) that determines which piece of code will be executed
and, initially, it’s set to 6, so next methods to be invoked are RecordParam.SelectConfig( ) and
ReponseListState.PostProcess( ).
Before proceeding, we’re able to see several methods being called inside a for-loop:
▪ RecordParam.SelectConfig()
▪ ReponseListState.PostProcess( )
▪ Invoke(obj, parameters)
▪ GetMethod("InvalidCast")
▪ CompareVisitor( )
Anyway, as num variable has been set to 6, so the next methods to be executed are:
▪ RecordParam.SelectConfig (line 34)
▪ ReponseListState.PostProcess (line 36)
▪ And, num is will be set to 2 (line 35), and the execution will jump to IL_0C label.
Method SelectConfig( ) doesn’t do anything and PostProcess( ) only returns “false”, so the “continue”
instruction (line 40) executes and the code flows to IL_0C label anyway. Therefore, the next method to be
executed will be CompareVisitor( ), though an instance constructor (.ctor) is executed right before of it. If
the reader go inside CompareVisitor( ), there is a long switch case (17 cases) with many graphic-related
methods being executed and, apparently, there isn’t anything strange. However, the first impression is
wrong! The trigger to the second stage (another .NET module) is hidden exactly inside of this method
because, soon after it, there’s the instruction: this.Text = “Form 1” (line 258). The “Text” property is
associated to an accessor/mutator , which is overridden by other accessor/mutator on line 292:
[Figure 18] ResetVisitor( ) method being called within on overriding accessor (getter/setter)
27 | P a g e
https://exploitreversing.com
If readers are not used to working with dnSpy, it’s possible to get a list of methods that overrides, are
overridden, have dependencies (Uses) and dependents (Used by) through right clicking on any method
and choosing Analyze (CTRL+SHIFT+R). In this case, I showed the view from overriding mutator, but we
could have done the same analysis from the overwritten mutator’s point of view, as shown below:
28 | P a g e
https://exploitreversing.com
[Figure 20] ResetVisitor method and the decoder of Vargo managed resource.
Of course, we can easily write a Python / PowerShell script to decode manually this managed resource, but
it isn’t worth because there could be many encrypted resources. Thus, let’s set up a breakpoint on line 323
(for example) and following a dynamic approach using a debugger, which is best approach to save time.
If you don’t know about hotkeys on dnSpy, the most important ones are:
▪ F11 for stepping-in
▪ F10 for stepping over
▪ SHIFT+F11 for stepping out
▪ F9 to set / clear a breakpoint
If you don’t want to use the hotkeys, so you can access the Debug menu and have access to the same
commands. Therefore, set the breakpoint on line 323 and start the debugging process. The debugger is
going to stop the execution exactly on line 323 before the managed resource being decoded, so it’s time to
wait a minute. Within this same method (ResetVisitor( )), there’s a critical instruction on line 370 that
really loads the Vargo managed resource:
▪ ReponseListState.DefineVisitor(Assembly.Load(array), 11);
We’ve listed the Assembly.Load( ) method on page 4 and at this point we can imagine that the Load
method will load the decoded resource (Vargo) and it will use methods from this new module. Therefore,
set up a breakpoint on the Load( ) method above and resume the execution. Just in case your dnSpy
environment doesn’t show the Modules window, so go to Debug → Windows → Modules as explained
below:
29 | P a g e
https://exploitreversing.com
[Figure 22] Decoded array: pay attention to 0x4D, 0x5A bytes (MZ)
30 | P a g e
https://exploitreversing.com
Below I show you the list of modules before and after the new module (SharpStructures) being loaded:
32 | P a g e
https://exploitreversing.com
No doubts, we are able to de-obfuscate this code and there’re several available techniques and tools that
can be used accomplish this task, though the de4dot (https://github.com/de4dot/de4dot) is one of the
most recommended tools. Of course, de4dot is able to de-obfuscate / unpack many different types of .NET
malware samples, but not all of them and, in some cases, we need to search for a specific unpacker,
though is not a hard task. Anyway, let’s try to de-obfuscate the extracted module:
33 | P a g e
https://exploitreversing.com
Returning to the malicious code, if we continue debugging after having extracted the second stage (a .NET
module) from memory, soon the MapVisitor( ) will be called and, so afterwards, it will call
ReponseListState( ) constructor from ResponseListState class. If you check the Stack windows, it confirms
our statement:
34 | P a g e
https://exploitreversing.com
A well-known approach to manage cases like that is replacing the content of obfuscated module on
memory, before it being loaded, by our de-obfuscated one. It’s seems weird, but provide us good and
practical results because debugging it becomes easier than handling obfuscation issues. How can we do it?
There’re many options and, probably, it’s a matter of taste: some professionals prefer using a hexadecimal
editor + Notepad++ and other ones prefer using CyberChef. Personally, I prefer the latter one. Thus, we
need to stop the debug session (because the module was already loaded) and set up a breakpoint on the
instruction responsible for loading the second stage module that, in our case, it’s the one from Figure 22,
and on the first instruction calling a method from the second stage:
▪ ReponseListState.DefineVisitor(Assembly.Load(array), 11); (from ResetVisitor( ) method)
35 | P a g e
https://exploitreversing.com
36 | P a g e
https://exploitreversing.com
37 | P a g e
https://exploitreversing.com
Readers could also are asking how to find the right InvalidCast method because there’re two methods with
the same name, but that belong to different classes:
▪ SharpStructures.Main.SortHelper class
▪ SharpStructures.Sorting.SortHelper class
If you’re continue debugging (F10 – step over), the answer comes automatically in the FullName property:
38 | P a g e
https://exploitreversing.com
39 | P a g e
https://exploitreversing.com
40 | P a g e
https://exploitreversing.com
▪ Taking a snapshot of the virtual machine after having done this setup because you might want to
be able to repeat this procedure if it’s necessary.
Of course, it wouldn’t be necessary to set up four breakpoints and only executing the code using F10
(step-over) would be enough. Anyway, you can decide the best approach for you.
Therefore, we have the following breakpoints setup:
43 | P a g e
https://exploitreversing.com
For now, right click the _byte array → Save… . Choose a name (stage_3.bin, but we’re going to rename it
later) and save it. Use the Exeinfo PE or Die to check possible obfuscators/packers, as shown below:
44 | P a g e
https://exploitreversing.com
[Figure 46] Method from third stage being called for the second stage
There’re many classes (not shown in this figure above), but each one has a respective .cctor( ) method.
Additionally, the XcuCxUwDbNNwbx89AI class has its own class constructor and an instance constructor
that calls the .ctor( ) constructor. Additionally, the function being called (RrRUhxJmfM) from the
InvalidCast( ) is also obfuscated and has several switch cases (not showed above).
Now we have some useful information, we can try to de-obfuscate the extracted module (the third stage)
to replace the obfuscated module loaded on memory by this one. Once again, we can try to use de4dot to
accomplish this job:
If everything goes smoothly, the execution will hit the breakpoint in .cctor( ). Welcome to the stage 3,
whose the first method being called has the content shown below:
47 | P a g e
https://exploitreversing.com
48 | P a g e
https://exploitreversing.com
▪ About delegates in .NET, a delegate type is sort of object (data structure / class) that provides a
reference (as a pointer) to a method or list of methods that can be invoked anytime. Actually,
delegate type can be interpreted as a structure because it holds the address of a method (similar
a function pointer), its respective parameters and return type. Therefore, we could create a
delegate type to any function accepting two strings as arguments and returning another string, for
example. Furthermore, when we use delegate keyword to define a delegate type, we are creating a
class (data structure) to hold all necessary information to the delegate.
▪ Delegate types can be used to send notifications (as a callback) to the invoking function whether
any specific condition is triggered, but it is not the main purpose of the malware code.
▪ In our case, GetDelegateForFunctionPointer( ) is used for marshaling a pointer to a native function
into a delegate type that can be invoked inside the .NET code.
▪ Malware is performing code injection because the usage, through delegating, of native functions
such as VirtualAllocEx, WriteProcessMemory, SetThreadContext and ResumeThread.
▪ As readers know, CreateProcessA (via delegate) is being used to create a process, but we need to
get additional information about it.
▪ In fact, .cctor( ) in this sample is being used only to create delegates (references) to native
functions because, according to page 46, the stage 2 is really calling the smethod_10, which calls
many methods and many of them using these mentioned delegates.
Therefore, the recommended approach would be to:
▪ set up breakpoints on key functions / methods inside the smethod_10 (not within .cctor( )).
▪ filter relevant methods by using Analyze feature, which bring us methods being used by our
analyzed method and methods that use the analyzed method.
The .cctor uses Class12, which has 9 delegates, and you get them by using the Analyze feature:
50 | P a g e
https://exploitreversing.com
▪ Class12.delegate0_0 → "ResumeThread"
▪ Class12.delegate1_0 → "Wow64SetThreadContext"
▪ Class12.delegate2_0 → "SetThreadContext"
▪ Class12.delegate3_0 → "Wow64GetThreadContext"
▪ Class12.delegate4_0 → "GetThreadContext"
▪ Class12.delegate5_0 → "VirtualAllocEx"
▪ Class12.delegate6_0 → “WriteProcessMemory"
▪ Class12.delegate7_0 → "ReadProcessMemory"
▪ Class12.delegate8_0 → "ZwUnmapViewOfSection"
▪ Class12.delegate9_0 → "CreateProcessA"
And we have a good surprise: all of delegates are being used in smethod_9, as shown below:
It’s great! The smethod_9( ) is responsible for using several delegates related to native functions, but the
smethod_9 is not called directly by smethod_10 (the first method being executed after .cctor( )). Once
again, we should use Analyze feature to find out the sequence of calls:
52 | P a g e
https://exploitreversing.com
Therefore, let’s do a quick analysis of each smethod_#, one by one. Starting in smethod_0( ), we have:
53 | P a g e
https://exploitreversing.com
The method HeGwfEiyF( ) is called several times and its strings, used as argument, tell us that its purpose is
virtual machine detection.
VMWARE:
▪ bool flag3 = Class1.HeGwfEiyF("SOFTWARE\\VMware, Inc.\\VMware Tools",
"InstallPath").ToUpper().Contains("C:\\PROGRAM FILES\\VMWARE\\VMWARE TOOLS\\");
▪ bool flag5 = Operators.CompareString(Class1.HeGwfEiyF("SOFTWARE\\VMware, Inc.\\VMware
Tools", ""), "noValueButYesKey", false) == 0
▪ bool flag6 = Class1.HeGwfEiyF("HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 0\\Scsi Bus 0\\Target
Id 0\\Logical Unit Id 0", "Identifier").ToUpper().Contains("VMWARE");
▪ bool flag7 = Class1.HeGwfEiyF("SYSTEM\\ControlSet001\\Control\\Class\\{4D36E968-E325-11CE-
BFC1-08002BE10318}\\0000\\Settings", "Device Description").ToUpper().Contains("VMWARE");
▪ bool flag8 = Class1.HeGwfEiyF("HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 1\\Scsi Bus 0\\Target
Id 0\\Logical Unit Id 0", "Identifier").ToUpper().Contains("VMWARE");
▪ bool flag12 = Class1.HeGwfEiyF("SYSTEM\\ControlSet001\\Control\\Class\\{4D36E968-E325-
11CE-BFC1-08002BE10318}\\0000", "DriverDesc").ToUpper().Contains("VMWARE");
▪ bool flag13 = Class1.HeGwfEiyF("HARDWARE\\DEVICEMAP\\Scsi\\Scsi Port 2\\Scsi Bus 0\\Target
Id 0\\Logical Unit Id 0", "Identifier").ToUpper().Contains("VMWARE");
▪ num = (Class1.HeGwfEiyF("SYSTEM\\ControlSet001\\Services\\Disk\\Enum",
"0").ToUpper().Contains("vmware".ToUpper()) ? 4010111179U : 2868294220U);
▪ num4 = ((Operators.CompareString(managementObject["Description"].ToString(), "VMware
SVGA II", false) == 0)
VIRTUALBOX:
54 | P a g e
https://exploitreversing.com
WMI queries are involved in gathering system information to be able to check all details related to virtual
machines. Anyway, we can conclude that the main purpose of smethod_1( ) is detecting virtual machine
environments, so we might nullify any instruction invoking it. Nonetheless, you’ll see that it isn’t necessary
in this sample.
Next method, smethod_2( ), is very simple and only starts a thread given by smethod_3( ) by using the
instruction:
▪ new Thread(new ThreadStart(Class12.smethod_3));
Therefore, both are related to each other and there’s none additional facts about them.
The smethod_4( ) and smethod_5( ) manage ACLs through APIs such as:
▪ DirectorySecurity
▪ SetAccessControl
▪ SetAccessRuleProtection
▪ setAttributes
▪ FileSystemAccessRule
▪ AddAccessRule
The smethod_6 is a bit more interesting because it handles tasks using schtasks.exe and even temporary
file creation on disk to support it. The base64 string below represents only a XML template to define and
control an application using tags such as RunLevel, Triggers, Settings, StartWhenAvailable,
AllowStartOnDemand and so on, and it’s used by schtasks.exe during the scheduling of a task:
[Figure 56] smethod_6: base64 string used for persistence with schtasks.exe
55 | P a g e
https://exploitreversing.com
57 | P a g e
https://exploitreversing.com
The smethod_12( ) is a proxy method for the smethod_13( ), which invokes a member of the new loaded
assembly, but also provides the following lines of code (and strings) for our analysis:
▪ string text = Path.Combine(path, "RegSvcs.exe");
▪ string text = Path.Combine(path, "MSBuild.exe");
▪ string text = Path.Combine(path, "vbc.exe");
[Figure 63] smethod_12 and smethod_13: operation related to the new loaded module
There, as a summary of methods, we have:
▪ smethod_0: sandbox detection
▪ smethod_1: virtual machine detection
▪ smethod_2: starts a thread
▪ smethod_3: provides the application to be started as a thread
▪ smethod_4 and smethod_5: manages ACLs
▪ smethod_6: schedules new tasks with schtasks.exe
▪ smethod_7: supposedly downloads a file from the Internet
▪ smethod_8: resolves native API addresses
▪ smethod_9: involved with native API calls.
▪ smethod_10: the main method (dispatcher).
▪ smethod_11: loads a new assembly.
▪ smethod_12 and smethod_13: operations related method invocation.
We have to set up some breakpoints, and a list of few possible lines follows below:
▪ smethod_1: (line 488) Start of the loop
▪ smethod_13:
o (line 1617) string path =
(string)typeof(RuntimeEnvironment).InvokeMember("GetRuntimeDirectory",
BindingFlags.InvokeMethod, null, null, null);
o (line 1633) string text = Path.Combine(path, "RegSvcs.exe");
o (line 1654) string text = Path.Combine(path, "MSBuild.exe");
o (line 1664) string text = Path.Combine(path, "vbc.exe");
▪ smethod_9:
o (line 776 / WriteProcessMemory) num6 = (((!Class12.delegate6_0(struct2.intptr_0, num10
+ num11, array, array.Length, ref num4)) ? 1777126585U : 974911055U) ^ num3 *
3593627777U)
o (line 803 / WriteProcessMemory) bool flag5 = !Class12.delegate6_0(struct2.intptr_0,
num13 + 8, bytes, 4, ref num4)
o (line 859 / VirtualAllocEx) int num10 = Class12.delegate5_0(struct2.intptr_0, num14,
length, 12288, 64)
o (line 867 / CreateProcessA) bool flag10 = !Class12.delegate9_0(string_11, string.Empty,
IntPtr.Zero, IntPtr.Zero, false, 134217732U, IntPtr.Zero, null, ref @struct, ref struct2)
o (line 880 / WriteProcessMemory) num6 = ((!Class12.delegate6_0(struct2.intptr_0, num10,
byte_1, bufferSize, ref num4)) ? 1884772482U : 172468949U);
o (line 895 / GetThreadContext) num6 = ((Class12.delegate4_0(struct2.intptr_1, array2) ?
1127022864U : 23477936U) ^ num3 * 3000738847U);
o (line 921 / ReadProcessMemory) bool flag6 = !Class12.delegate7_0(struct2.intptr_0, num13
+ 8, ref num16, 4, ref num4);
o (line 929 / Wow64GetThreadContext) bool flag11 = !Class12.delegate3_0(struct2.intptr_1,
array2)
o (line 941 / ZwUnmapViewOfSection) num6 = (((Class12.delegate8_0(struct2.intptr_0,
num16) != 0) ? 3120432759U : 2659671650U) ^ num3 * 1247483263U);
o (line 984 / SetThreadContext) bool flag13 = !Class12.delegate2_0(struct2.intptr_1, array2);
o (line 1035 / Wow64SetThreadContext) bool flag4 = !Class12.delegate1_0(struct2.intptr_1,
array2);
o (line 1045 / ResumeThread) bool flag12 = Class12.delegate0_0(struct2.intptr_1) == -1;
After setting the mentioned breakpoints readers should take a snapshot of the virtual machine just in case
to be necessary to start over.
Resuming the execution, few breakpoints will be hit and other ones don’t:
▪ smethod_13:
o (line 1617) @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\"
o (line 1633) @"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegSvcs.exe"
▪ smethod_9:
o (line 867 / CreateProcess):
▪ lpApplicationName:
@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegSvcs.exe"
59 | P a g e
https://exploitreversing.com
I tried making things easier and wrote down some parameters (as shown above) during the debugging
execution for helping you to understand what’s happening over the stage_3.bin’s instructions.
Additionally, I left some API parameter as support stuff and, as you could notice, many breakpoints haven’t
been hit as we expected (nor not), and it looks like good:
60 | P a g e
https://exploitreversing.com
Based on information collected from the debugging session through those breakpoints, we can make some
considerations:
▪ The malware execute GetRuntimeDirectory( ) to find the current .NET Runtime directory.
▪ Depending on the result of GetRuntimeDirectory( ), which is related to .NET runtime version, the
malware loads one of available and legal applications. In my environment, It’s loaded RegSvcs.exe,
which is an installation tool for .NET services.
▪ The malware injects a malicious code into the loaded module (RegSvcs.exe). However, it doesn’t
do it at once to include the entire malicious code, but it does a section-by-section copy.
▪ Due to the fact that the malicious code is injected section-by-section, it isn’t practical to use dnSpy
to save each part of the code being injected because we would need to concatenate everything
later, and it isn’t worth to spend time doing it.
▪ The most recommended approach is to visualize memory addresses of the process (RegSvcs.exe)
and search for a RWX section, which likely starts at 0x400000. These both information can be
confirmed using collected parameters on line 859 (VirtualAllocEx) of page 60.
To save a memory region from Process Hacker tool, double-click the region, which confirms it’s an PE
executable and click on “Save…” button:
[Figure 67] Process Hacker: identify and save the injected code
If you open the saved binary in PE Bear to check Imports, so you’ll find everything messed up and,
apparently, there isn’t any useful information.
62 | P a g e
https://exploitreversing.com
The reason is that we dumped the binary from memory, so it’s in mapped format and we need to convert
it to unmapped format:
▪ At Section Hdrs tab, for each section, copy the Virtual Address to the Raw Address.
▪ Calculate the size of each section by subtracting the address of next section from the current one
and alters the Raw Size using the result.
▪ After you have changed the Raw Size, copy the Raw Size value to the Virtual Size field.
▪ Save the binary by right-clicking on the binary’s name (top-left) and provide it a new name.
64 | P a g e
https://exploitreversing.com
Once the saved binary has been fixed, search for possible packers/obfuscators using DiE and Exeinfo PE:
65 | P a g e
https://exploitreversing.com
new stage because, apparently, it tries to communicate via network, according to \Device\Afd handle
name:
66 | P a g e
https://exploitreversing.com
According to the entry-point, namespaces, class names and methods, this stage seems to be also
obfuscated and, as we learned from Die and Exeinfo PE, apparently the packer is Obfuscar.
Readers can navigate to Entry Point or by clicking on last “A” on line 4 from last figure or right-clicking on
the Assembly name and choosing “Go to Entry Point”:
Anyway, a method C.A( ) is called and, afterwards, an Application.Run( ) method is called. Going into the
A( ) method, we have:
68 | P a g e
https://exploitreversing.com
The routine, partially shown in the figure above, contains a class containing a main method (private static
string <<EMPTY_NAME>>(int A_0, int A_1, int A_2)) and several methods calling a decryption routine.
Apparently, the malicious code dynamically decodes and build up a string table with 767 strings and, once
they are decoded then the malware picks up the string from there according to the given index. All this
process occurs in the .cctor( ), where is a long sequence of elements (11566 elements) and, at end, a for-
loop reading each one and decoding them using the own element index and a value (170).
Our first step is using de4dot, which doesn’t offer support for Obfuscar, to try de-obfuscate all possible
symbols:
69 | P a g e
https://exploitreversing.com
To decrypt strings we have two possible paths: we can use another de-obfuscator tool or try to do it using
other available options from de4dot. A working de-obfuscator for Obfuscar is
https://github.com/DarkObb/DeObfuscar-Static.
To use, reader should clone and compile it using Visual Studio 2019 or Visual Studio 2022, and building the
solution is clean and direct:
[Figure 83] De-obfuscating the fourth stage (already cleaned by de4dot) with DeObfuscar-Static
Opening stage_4_decrypted-Dec.exe on dnSpy, we have:
Readers could ask about reasons of namespaces, classes and method haven’t been recovered neither using
de4dot nor DeObfuscar-Static tool. The cause is that, during the obfuscation process, all information
about names of namespace, classes, methods, and so on, were lost. However, it isn’t an issue for us
because everything else is present within the sample. Additionally, the whole
<PrivateImplementationDetails>{A78A1E33-EFB4-4B39-84DB-A2C18EC95E34} namespace could be
deleted without any problem because the malware won’t need it anymore, but it’s a personal decision.
Another approach would be use the own de4dot to de-obfuscate strings from this sample, but using non-
conventional options that usually works very well for several unknown obfuscators.
To understand what will do here, return to Figure 78 and pay attention to the following:
▪ 4AE7E02E-291A-4676-9641-A6E499CD2831.aw()
From this instruction, we have:
▪ 4AE7E02E-291A-4676-9641-A6E499CD2831 ➔ class
▪ aw() ➔ method
Therefore, as we mentioned previously, this class contains all methods used to decrypt scripts and, if we
can dynamic use them, so decrypting strings issue is solved. Checking the method above, we have:
There’re many decrypting methods and the most important part for us are their respective tokens, where
the first one is 0x060001F8 and the last one is 0x060004F6 (please, check the code).
The de4dot options we are looking for are reported in its help:
▪ --strtyp TYPE String decrypter type
▪ --strtok METHOD String decrypter method token or [type::][name][(args,...)]
In few words, de4dot provides us with options to dynamically call all decrypting methods by referring to
their respective tokens. Thus, the syntax to decrypt all strings is:
▪ de4dot --strtyp delegate –strtok <method token> –strtok <method token> --strtok…
The only issue is that there’re too many tokens (and methods associated) because, as we mentioned
previously, there’re 767 strings and, of course, the command line will be very long, but we can manage it.
Using Python + Jupyter Notebook, I wrote few line of code to generate our command line:
72 | P a g e
https://exploitreversing.com
As readers are able to see, the script only puts several parts of the necessary command together and
generates an output including all required tokens and options. As the Python range( ) function excludes
the last element, so I added one to include it. You should copy the whole command to a PowerShell
terminal and execute it there as shown below (I’m sorry for the dark background, please):
It has worked perfectly, again. There’re some comments that, eventually, could be useful here:
▪ Remember that de4dot is able to run Windows and Linux (apt install de4dot) and you could test
the command on these systems.
▪ Usually I prefer run commands and tools for .NET in recent version of Windows (10 or 11) to avoid
encountering any unexpected surprise. Once again, it’s a matter of personal preference.
▪ It’s recommended to compile your own version of de4dot because, usually, it will include updated
components.
▪ Prefer using PowerShell window because its editing capabilities are much better than Command
Prompt.
▪ If you have any problem while using de4dot to run the produced long command then you should
try a newer version of Windows system using your own compiled version.
From this point onward, finally there isn’t further obfuscation in the binary and it’s only a task of reading
code, analyzing APIs and structures, though you’ll find some encrypted data yet. I’m going to leave only
three pieces of code here, but readers really must parse several methods (there’re a lot of them) to learn
all capabilities offered by AgentTesla malware.
One of the possible approaches, mainly while analyzing obfuscated codes, would be to examine the Table
Streams to locate interesting functions, mainly native APIs, which provides an idea of some characteristics
of the malware. Of course, there’re other tables, but ImplMap table might help you here:
74 | P a g e
https://exploitreversing.com
[Figure 91] Contacting an external website to upload information and/or download tools
75 | P a g e
https://exploitreversing.com
Finally, a question remains: can we use IDA Pro, which it’s used for analyzing native binaries, shellcodes,
raw files and UEFI firmware, to analyze a .NET (managed) malicious code? Of course, we can.
IDA Pro doesn’t show the high-level representation of the binary, but its IL (Intermediate Language)
interpretation, which already helped me understanding what was happening in the code over many
situations and, additionally, it has the well-known graph representation that makes easier to navigate
through the MSIL code:
[Figure 93] IDA Pro: view of the final .NET payload (AgentTesla)
Initially, you could think it wouldn’t be appropriate using IDA Pro to analyze managed code (.NET code)
because MSIL representation doesn’t seems too easy, but I’ve used it in many cases:
▪ To understand eventual obfuscation tricks.
▪ To quickly find all called natived APIs.
▪ To figure out the sequence of called functions using the graph mode.
Additionally, I have used IDA Pro to analyze final payloads and get quick directions of executed actions by
observing the function list, following code through the graph-mode and, as we’ve used in dnSpy,
performing text searches through ALT+T and CTRL+T. If you don’t know about MSIL then, once again, I
recommend you reading my slides from DEF CON USA 2019.
At the end of day, it’s a personal choice using tools and different approaches to analyze .NET malware
samples, but it’s always recommended to use any available tool that to make things clearer and faster.
76 | P a g e
https://exploitreversing.com
8. Conclusion
As I already mentioned previously, there’re dozens (or hundreds) of methods and functions to be analyzed,
which certainly would take many additional pages. We could, for example, have tracked a more complete
malware profile by:
▪ searching for other mechanisms of persistence
▪ collecting information from system
▪ studying hooks and keyloggers
▪ analyzing all network communications
My goal keep being to offer a review of malware analysis and, if it’s possible, helping reverse engineers to
learn something new, providing a guideline to follow and search for something when it’s necessary.
I could have chosen a more complex malware sample, but it wasn’t not the idea. The general context is to
explain key concepts, strategies, techniques and approaches used during malware analysis of different
threats and, in this scenario, proposing hard examples wouldn’t help anyone and it would be useless, in my
opinion.
This article certainly will have typos and errors, but it isn’t big deal. Soon I find them, I’ll release a new
revision of this document.
9. Acknowledgments
I’d like to publicly thank Ilfak Guilfanov (@ilfak) and Hex-Rays (@HexRaysSA) for supporting this project
by providing me with a personal license of the IDA Pro.
Although I haven’t used IDA Pro in this specific article, it doesn’t change anything because without having
the support from Ilfak and HexRays certainly I wouldn’t be able to write this series of articles.
As I promised him, I will keep writing this series of articles in the next months and years. Certainly, my
gratitude for his help is endless.
Once again: thank you for everything, Ilfak.
77 | P a g e