This video introduces the fundamental architecture of .NET malware loaders, demonstrating how stage-1 loaders use reflection (Assembly.Load) to load and execute embedded payloads in memory. The presenter walks through a sample loader that includes anti-analysis checks (debugger detection, VM identification, process monitoring), mutex implementation to prevent multiple instances, and configuration data handling. The video explains how obfuscation techniques like ConfuserEx can disrupt analysis by renaming variables and functions, making it difficult to identify assembly loading points. Key analysis techniques include using dnSpy to examine decompiled code, setting breakpoints at Assembly.Load calls to capture payloads in memory, and bypassing anti-analysis checks to understand the malware's execution flow.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
[Workshop] Anatomy of a .NET Loader – Reflection & Assembly LoadingAdded:
All right, everyone. Welcome to this video. This is going to kick off a series talking about um obfuscation in.NET binaries. In particular, we're just going to use the uh you know, somewhat popular project ConfuserEx on GitHub, an open source, in order to take the sample programs here and just apply some of the obfuscation techniques that it has and look at the impact. Um not going to focus so much on reversing. We're going to talk a little bit about some tools that are available. Uh there hasn't been I I just from my perspective a ton of innovation in this space as of late. But um anyways, so a little bit more focus here on the offensive side so that we can see the impacts from our normal.NET binary. Let's get started here in this video, the first video. We're just going to go through a sample program and you see I'm going to try to set this up to be, you know, simple yet realistic. Uh so, we have uh what would be your initial stage. This is going to be more of a classic loader. Uh we'll talk about the configuration and the program flow in just a moment, but just to give you a sense of what's going on here.
Uh we have an assembly, which is going to be just the embedded bytes of a next stage, and that's really all this thing is designed to do. It It's designed to load using reflection to load that assembly, figure out where it wants to execute code in that assembly, so the entry point, and then invoke it. Uh so, that's all of what this code is doing. So, again, we'll come back to this in just a moment and go through it in a little bit more detail. It's very common to see a little bit of anti-analysis here. Um and this is going to be done in this function is being debugged that will then kick off uh whether or not it should proceed, which will then generate a mutex and do the reflective loading. Now, the next stage, also going to be very simple, but this is also something that is very common in that uh it's going to assume once it gets to this stage, you know, like this stage doesn't necessarily have anti-analysis.
Uh that's common, common enough anyway.
There's There's no right or wrong.
There's no typical flow that you're going to see here uh because every every malware author every loader that they use every obfuscator they use there's there's differences. You can find anti-analysis in every stage. You can find it just at the initial stages. It depends on a lot of variables. So, it's common. In this case, we have two programs their source and we're relying on another tool to obfuscate that post build. We're not putting a lot of the obfuscation in ourselves. If we were to look at this as like the developer perspective. So, here we have the run method. This is going to call check in.
Check in's going to have a URL. We're in a lab environment, so I'm just going to use FakeNet. You'll see FakeNet's already open.
FakeNet will be used to just handle this request. So, this really doesn't matter in this case. Going to create going to grab some information about the environment. So, the username, the operating system, name of the host, and a date time stamp, and then just wrap that manually as some JSON data and send it back. Nothing's actually consuming this. So, this is again just to be somewhat representative. Not using We're doing this manually just so we can avoid the use of any JSON libraries, but that certainly would be applicable or relevant here for building this. And then finally, you have HTTP client. So, just using plain old HTTP to post this information to the URL.
Okay. So, if we go back to the loader then, you can see that this has a pretty standard way of creating configuration data that is a class with a bunch of static properties. And in this case, if we're the authors, you you know, and depending on how we've decided to rely upon obfuscation, we might give these properties very clear names as we would as a normal developer. So, the name of the mutex, mutex name, and then the value itself.
We have this block list, this array of strings that we're going to use in order to query the processes and see if there's anything running to analyze.
Also embedding the raw assembly. This can happen in a number of different forms and in a wide wide variety of ways.
Often times these are going to be obfuscated and there's going to be logic that de-obfuscates them before loading.
So, we're kind of skipping that phase just to simplify things a little bit, but you can see here the 4D5A, these are the the first two magic bytes of a PE file. The only real requirement here is that as the authors, this is a.NET assembly and we know where our entry point is.
All right, that's what's happening right down here.
Um what happens when this gets running then? Well, we have the call to is being debugged.
This is going to first check if a debugger is attached.
Uh I commented this out because this was effective as simple as this is, this is another common very common technique been around for for years now and that is just to query information about the manufacturer using WMI and if it says VMware, well, we know we're in a VM or very likely in a VM. So, that can be part of the is being debugged or is being analyzed. So, a check like this maybe is being analyzed is a little bit more relevant here.
Uh finally, but this again this was just for demo purposes here. This was getting caught. Uh it was catching the environment I am I'm in cuz I am using VMware and I didn't want to have to deal with it. So, I just commented it out. Uh the final one here is just getting the process list, iterating through our array of um process names and then if it matches one, just one, then it returns true. And so, what this allows the program to do is say, "Okay, I'm being debugged and I'm being analyzed, so let's just bomb you know, bail out here of main and not continue."
Okay, the next thing is the mutex. The mutex is just there to help prevent the uh the program from running simultaneously to get multiple instances. So, when it's running it'll create this mutex, it'll use the mutex name, this will have a handle to itself and um and then during execution basically doesn't release it. It releases it when the process terminates.
So, if if you know, someone try to run the program quickly multiple times, there should only ever be one instance running.
Um of course, if it runs and then it terminates and then a few seconds later they try to run it again, it will run again. It's a mutex, it's only there to deconflict simultaneous execution, but very common.
Finally, we get into the reflexive loading. And so, this is where you can load an assembly. So, you can give this assembly.load the sequence of bytes of another.NET file, PE file, the raw bytes, and it'll load it into memory. And so, this is now avoiding having to write another payload to disk and execute it. This is this in-memory portion of how this attack works. Um so, this is also a key in determining this sort of logic uh because the way obfuscation you know, is leveraged typically giving nonsensical variable names, nonsensical function names, um you know, really disrupting the flow of the program, that can only be done to the symbols that are are uh controlled by the attacker. Um if we want to call assembly.load, that's not something that we control. So, it's harder to see that obfuscated. And so, you can, you know, you get this this binary in the real world, real world binary, in the wild binary, and it's got all this obfuscation, and it's multiple stages of assemblies. Well, you can typically focus in on those transition points from stage to stage by looking for you know, assembly.load events. And that can help you grep through uh a large amount of obfuscation. Once this is loaded into memory, this gets the type of the target class, so provider.fingerprint.
And if we go to our definition here, you see there's our fingerprint under the provider namespace.
And then finally, what method? So, now that we have the types, this can iterate through the methods to get run, that's the run method, and then invoke it. So, you can see here that this is the reflective part. Once it's in memory, it can inspect itself to understand about the different properties and the methods and then invoke them. So, that's how that stage is going to get executed. Uh to build this, I'm just going to use the command line.
So, we can use csc loader.cs.
Now, we can run the program. You'll see it uh terminated pretty quickly, and that knowing that it does some network connections and while it's all fast, there's still usually a little bit of a lag there. Um we can look at FakeNet, and if we scroll through the results here, you'll see there's no there's no request from our malware. And the reason why, again, simple check, I have dn dnspy open. So, we'll close that. Uh now we'll go back and run our loader.
You can see, okay, there was that little bit of extra lag, and here is our results in FakeNet. So, there's the request from loader. Here's our JSON data.
All right, so everything is in fact working.
Uh before I go too much further, let's just take a look at how to get this payload um into the file. Now, this is all very manual. I'm not going to take the time to build like an actual build pipeline here, uh but the the easiest way is to compile this and then convert it into the hex encoded sequence here that we can just paste right into our source.
So, uh here is the command. I I we don't need to go through all of this just because I've already done it, but using the C# compiler to create a library, we need a link to the appropriate libraries. So, this is using system.net.http.
So, we're going to make sure that we provide that for the linker. payload.dll is the output file, and then there's our source file. So, that that creates payload.dll.
And then from here, this was just some easy PowerShell to read the file, iterate over each byte, and then hex encode them, join them with a semicolon, and then generate the payload.text file.
And you can see here, this is then the beginning of that sequence. This is all on one line. So if we were to wrap this, you'll see of course it gets quite a bit larger because we have the entirety of our.NET file here, PE file.
Um now you can just take that and copy paste into the assembly right array here.
Right? And that's how that works. So when you compile it, it's all there ready to go. Of course, you know, you wouldn't want to have to do this if you were a red teamer or some someone doing this on a regular basis because this would be tedious and time-consuming. So uh of course lots of opportunities to to automate this and build frameworks. And that's what a lot of them do, um by the way. All right. So once we've got dnSpy open, we can just take our executable, drag and drop, and now we can select that. Typically, I just go to uh right click and to the entry point.
And what you'll see here is that our our decompiled results will look very much like our original. All right. There'll be some naming differences. Some of that gets lost just in the process of compilation, but um here's main. There's our being debugged. Here's the structure for the mutex, and then eventually the call to do the reflection and to load that assembly.
Being debugged looks pretty much identical. Uh and so everything looks, you know, relatively straightforward. And where we would run into kind of a stopping point with our analysis here, we'd have to transition to um well, one of two things, right? Uh we can see in this case there's really I mean the logic is is very clear. We we can follow this and within seconds of analyzing the code, you know that it's using reflection and it's invoking the method run from whatever this raw assembly is.
So we know that that's the next stage.
Um we can go to the assembly here and we can try to dump this using dnSpy. That can get a little bit clunky in order to do that. As you can see here, it's this mixture of uh well, it's it's base 10, but then you have this mixture of byte.MaxValue.
So, it can get a little bit clunky to get this data dumped out.
All right. So, now we can switch to debugging and we can just see this loaded into memory. And this is all often times a very helpful technique because um you know, again, as I mentioned earlier, a lot of times these assemblies you they're going to be obfuscated. They're not going to be just plain PE files ready to go.
If we observe when it's being loaded, if we detect that location, um this has to be a valid PE file. That's not to say that that layer is not obfuscated itself, but it has to be valid in in order to be loaded. And so, we can set a breakpoint here and now we can just capture it as it's loaded into memory and dump it from memory. Now, keep in mind that we're also dealing with the anti-analysis and because it's checking for dnSpy and now we're running in dn dnSpy, this simple check is going to be effective. So, we also have to handle that, which as you can see here, it just makes analysis a little bit more tedious because we'd either have to modify the IL to figure out a way to bypass this check or as we do our debugging, we have to manually go in here.
You can see that flag is true right down here because it caught the process list. So, now we have to modifly modif- manually modify that or you can set the instruction pointer. There's a number of different ways. But, we'll modify that local variable for now so that way we get to the assembly load and after that's loaded, if you go down here and you while you're debugging, you'll have your modules and make this a little bit larger.
Uh, there's our module now in memory.
There's payload. So, we could extract this from memory. We can double click and load it.
Uh, we know that now the next, and this is why identifying this the you know not just when it's loaded, but how it's going to transfer execution is important. We know that if we now go to provider namespace, the fingerprint fingerprint fingerprint class, we have the run method. Right? So, now we know the transition between the two layers. And now from here, we can continue to analyze. And again, you'll see of course there's no no obfuscation.
This is all pretty clean and in memory.
Okay, so that's that's the basics of our program and kind of the basic analysis that we would do. And this is what it would look like if there were no real obfuscation applied to this binary. So, let's take a look in the next video, ConfuserEx, and how that helps malware authors and red teamers to make this flow make the analysis a lot more difficult.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
🚀 BCS613C Compiler Design | Module 1 to 5 Schema Evaluation 🔥 | VTU 6th Sem 💯 #VTU #bcs613c #exam
Pranavaa-y4y
104 views•2026-06-02











