← Back to list

BSides CPH 2024 Writeup: DIY Trojan horse or: How to get your malware past EDR

TL;DR — This post is a written version of the presentation given at BSides Copenhagen 2024

0x0vid · 2024-11-11 16:57 · 5 claps · 14.4 min read
#bsides #edr-evasion #malware #cybersecurity #pentesting
Open on Medium ↗
Wiki topics: 🔒 · Cybersecurity 🐾 · Pets & Animals 🛠️ · Crafts & DIY

BSides CPH 2024 Writeup: DIY Trojan horse or: How to get your malware past EDR

TL;DR — This post is a written version of the presentation given at BSides Copenhagen 2024

Obligatory disclaimer: All of the information presented here is for research purposes and should only be used in a legitimate and legal manner, the author will not be held responsible for any misdoings or illegal activities.

The following is a write-up of my presentation at BSides Copenhagen 2024. The aim is to document the talk and provide some additional details that were cut from the talk as well as serve as a point of reference if needed for the ones who attended the talk.

— [ 0x0 — Introduction

A short introduction to myself. My name is Mark and I have been doing offensive security for the last 3–4 years. Within the last year or two, I got tired of my tools getting caught and removed by AV and EDR. This coincided with the growth in the ability of EDR software to detect and mitigate threats automatically. This sent me down the path of malware development! This talk is a basic walkthrough of how userland malware can evade EDR. The goal is for us to be able to run our tools. More advanced evasion like completely evading detection and teletry will be left for another time!

— [ 0x1 — Structure

For this talk, we will go through how to evade modern anti-virus (AV) and Endpoint Detection and Response (EDR) software(From here on I’ll just refer to these as EDR).

We will start off by talking about the purpose of the presentation and then talk a bit about the different aspects of analysis. I have chosen the methodology of separating these into different stages, this was based on [001]. We will be separating analysis into three different stages, each of which uses a different set of tools and techniques to detect malware at different points in its execution:

  • The first is static analysis where the binary is scanned for static signatures indicating malicious intent
  • The second is sandboxing — here the malware is run in a dedicated analysis sandbox to see if it does anything malicious
  • Third and lastly is runtime analysis — here the ongoing behaviour of the application is scrutinized for indicators of malicious behaviour.

Next up we will dive into a plan of how we are going to be putting all this together to get a final product that can evade EDR. Here I'll also briefly get into how you can get started, and what to expect.

After that, I will be releasing my packer called “farsidePacker”. As of writing (Oct. 2024) this is able to bypass most EDR. The project is meant to serve as inspiration for how something like this can be made, other examples are listed in the references at the end of this post. The tool allows for different configurations for evasion features, and can be used both by offensive and defensive teams to play around with these! I fully expect this tool to be fingerprinted and blocked pretty quickly after the release, but enjoy it while it works.

In the end, we will go through a bit of how this tool and similar applications can be detected and blocked!

— [ 0x2 — Purpose

So what's the purpose? why are we here? Well, I have narrowed it down to three distinct points.

  • Firstly I want to give an introduction to how evasion works for different security controls.
  • Next, I want to show you how you can get started.
  • And finally, I will provide an example of how I have done it.

— [ 0x3 — What is a trojan horse?

When talking about a “Trojan” in terms of malware, it is a piece of software that looks legitimate but is malicious. More specifically for our user case, it is a piece of software that looks legit when analyzed by EDR projects. So for our purposes, we will narrow down this definition even further: Create legitimate-looking software [002] that can run malicious software.

But before we get that far let's have a short look at the defensive measures employed by EDR.

— [ 0x4 — Stages of Analysis

In general, there are three different stages of analysis [001] that a binary goes through when running on a system. In short, these are:

  • Static analysis — this is when you download something and it is immediately flagged and removed.
  • Sandbox analysis — this often is the short break from running the binary to the binary actually starting to execute.
  • Runtime — this is when the binary has been executed and is running on the system.

A little trick to figuring out which part of the analysis a binary is getting caught on is just to include a simple print statement at the start of execution. If this is not triggered then you know that you never got to actually execute on host.

— [ 0x5 — Evading Static Analysis (AV)

The first topic we will deal with is static analysis. Static analysis is the oldest and most widespread type of analysis done by defensive countermeasures. In short, it looks through files for known Indicators of Compromise (IOCs). These can be everything from the hash of the file to byte sequences, strings, or filenames. This is why your malware gets flagged and deleted the second you download it. Take a vanilla compilation of mimikatz as an example, its hash is probably known by every EDR and AV product out there. The low resource requirements to perform a check like this mean that this is done pretty much by every security product on the market.

So how do we get around this? First let's understand our objective: to remove known signatures. There are two main ways of doing this:

  • Obfuscation [003]: in this step, we simply go through the binary, and remove or modify known IoCs like strings. An example of this is just going through mimikatz and changing strings. This method is simple, it does not modify behaviour and can be done by more or less everyone. It does require access to the source code and can be quite time-intensive if done manually.
  • Encryption[004] — the next option is to encrypt our binary and execute it in memory. This method is a lot more complex and demands specialized software. This method requires that the binary be reflectively injected into memory and executed (PE injection, RunPE etc. [005], [006], [007]). The benefit of this method is that the binary with the IoCs is completely transformed. Where obfuscation might leave byte patterns or other IoCs behind, this method has none of those drawbacks. The software used for this is often called packers or crypters, the most famous example of this is probably UPX.

The second method also has the benefit of completely retaining the original functionality. It also has the benefit that we won't need the original source code for the binary! This is useful for stuff like cobaltStrike where the source code for implants is not easily available to us. This is desired if we want to retain functionality that might be heavily flagged as IoCs such as help menus and strings used to track execution. Therefore this will be our preferred method.

— [ 0x6 — Evading Sandbox Analysis

Next up is sandbox analysis. Sandbox analysis is simply moving the binary to a place where the binary can be executed. Then the actions it performs can be tracked. And an evaluation of whether or not it is malicious can be made by the system. Common examples of sandboxes for malware include but are not limited to:

The strategy for evasion of sandbox analysis is quite simple. We either try to detect whether our malware is running in a sandbox. or we simply wait for long enough that the sandbox has stopped running (this is possible due to the resource constraints placed on online sandboxes).

The first of these can be done by checking for the attributes of the machine we are running:

  • The amount of RAM [011].
  • The presence of physical memory.
  • Time elapsed since the start — this works since sandboxes often remove sleep functionality from binaries to speed up analysis, thus giving away their presence [012].

Many more methods exist but I trust you get the idea

— [ 0x7 — Evading Runtime Analysis (EDR)

Lastly, the newest addition to the capabilities of modern EDR systems is the monitoring of real-time actions performed by malware. This can come in many forms but the two most popular are:

  • Hooking of system calls via the Win32 API or lower-level API functions — This is where a program replaces an API call with a JMP instruction to some form of monitoring functionality [013].
  • The other is listening to system events either from Event Tracing for Windows (EWT)[014] or the kernel level ETW Threat Intelligence[015] (ETW—TI) also known as “Microsoft Threat Intelligence Drivers (ETW-TI) [016]”, here the EDR is listening to system-generated events (similar to Sysmon [017]) and using these to determine if a program is malicious.

So how do we get around this? We either blind defences or we use some API call or technique that is not monitored. To demonstrate I have chosen the two approaches listed above:

  • Patch ETW [018] — this one is simple we just patch the function responsible for creating ETW events for our process to stop collection. No collection = no telemetry.
  • Function unhooking/circumvent — here we eitherfully remove the hooks placed by EDR. Or we avoid calling the hooked functions by calling either a similar function or a lower-level version of the function(direct syscalls [019]) i.e. using NtAllocateVirtualMemory instead of VirtualAlloc.

Many more techniques exist! Some of the more interesting include blocking network communications of the EDR agent [020], and installing a rootkit to filter out telemetry on the kernel level… imagination is the only limit here!

— [ 0x8 — That’s cool, but what is the plan?

So now that we have a decent overview of the different telemetry an EDR relies on to catch our malware. What is the plan?

Well, we will create a build system to create a packer which encrypts our target payload and adds evasion features. Why a build system? Because this allows us to add and remove features at will and experiment with what works, and what doesn't. It will also allow for customizable payloads depending on the EDR/AV we are going up against … and I think it was more useful for learning!

Pro tip: If this starts to get flagged by EDR, then it's likely just the stub (part of the packer responsible for loading the malware into memory) or some of the evasion features added to the stub. To get around this just change up the techniques and the code a bit, and it should work again!

— [ 0x9 — But How do I get started?

Now you are probably sitting there…. a bit more tired than when you came… and wondering: How do I get started? Luckily for you, the answer is pretty simple: You go look at stuff on Git Hub, see how other people do stuff, and then create something yourself (I'll help with the first part shortly)[021], [022], [023], [024], [025], [026], [027].

To do this, you will need to know how to program. Since our malware targets Windows you will need a language with support for the Win32 API, or the competencies to implement this yourself!

Then you will need to know how to program with the Win32 API. A short rant on the Win32 API: It is a mess, it is awful nothing makes sense, nothing is standardised, and the documentation is outdated and messy… if you are programming in a language that cares about types, you will find yourself casting types to other types to even more different types… Here are some examples:

Nim: Converting a pointer to a byte to a ulonglong to add it to a DWORD from a struct from an object to convert it to a pointer function pointer

Nim: Converting a pointer to a byte to a ulonglong to add it to a DWORD from a struct from an object to convert it to a pointer function pointer

Golang: Take the address of the first byte in an array, cast to an unsafe pointer, cast that to a uintptr

Golang: Take the address of the first byte in an array, cast to an unsafe pointer, cast that to a uintptr

It's a mess and it's just something you need to work around …

So in short, to create malware for a Windows system you need a language that supports the Win32 API, has reasonable support for Windows structs and objects, and lastly can be compiled or run on Windows systems.

— [ 0xA — Release: farsidePacker

Now for the exciting part! putting it all together! and for this occasion, I have created the “farsidePacker” project which is available on my GitHub! The project shows how all of the above techniques can be put together to create a piece of malware that as of writing can bypass most EDR/AV, at least when using mimikatz!

The intention of this project is to provide a PoC that you can use to learn how to create your own malware!

[embed]GitHub - 0xOvid/farsidePacker: Packer for demonstrating various evasion techniques Packer for demonstrating various evasion techniques - 0xOvid/farsidePackergithub.com

— [ 0xB — Detection And Prevention

Now that we have gone through how to evade EDR and I have shown how this can be done, let's have a talk about how this can be prevented and detected.

Detection:

To detect the techniques mentioned here, defenders have a few broad options:

  • Suspicious API calls — this is already present in some EDR solutions and more or less just consists of the software detecting potentially malicious API calls. A classic example of this is using direct syscalls instead of more conventional calls, such as: using NtAllocateVirutalMemoryinstead of VirtualAlloc to allocate memory for our payload
  • Loading NtDll twice or overwriting its memory space — most programs likely will not write to the memory space of NtDll or load it twice, therefore it might be a decent IOC for unhooking NtDll
  • Compound detections — no matter how many fancy evasion techniques we add to our packer, the packed program will eventually have to do something. If that something can then be detected then this will mitigate the evasion our packer just did. A classic example is mimikatz getting a handle to LSASS or CobaltStrike allocating its config on the heap.

Prevention:

Prevention of an attacker's ability to evade defences comes down to one simple strategy:

Don't let attackers run code in your environment!

To achieve this tools like AppLocker can be really helpful to defend against the blunt of most modern attacks by simply preventing execution. Combining this with tools like Attack Surface Reduction (ASR) many techniques become nullified. This is not a cure-all but will get defenders much of the way towards greater defensive posture.

Attack Surface Reduction Rules[028]:

#Attack Surface Reduction Rules JSON File
$URL = "https://raw.githubusercontent.com/Kaidja/Defender-for-Endpoint/main/AttackSurfaceReductionRules.json"
#Convert ASR Rules from JSON
$ASRRules = (Invoke-WebRequest -Uri $URL -UseBasicParsing).Content | ConvertFrom-Json
foreach($Rule in $ASRRules){

    $ASRRuleName = $Rule.Name
    $ASRRuleGUID = $Rule.GUID

    Write-Output -InputObject "Working on $ASRRuleName. Setting the rule to Audit Mode"
    Add-MpPreference -AttackSurfaceReductionRules_Ids $Rule.GUID -AttackSurfaceReductionRules_Actions AuditMode

}

Applocker:

for the recommended configuration of AppLocker please refer to the MS guidelines [029], [030]. Also, please just block all execution from the downloads folder!

— [ 0xC — Conclusion

In conclusion, it's not that hard to create malware, it takes a bunch of time and there are challenges to overcome. But if you break them down into their components and are not afraid to get your hands dirty and do some research, it is quite fun! and it is really cool seeing your malware run on an EDR-protected system for the first time!

— [ 0xD — Q&A

Summary of questions from the audience:

  • Q: What does Beep() do? — A: This is a WinAPI function which takes two arguments, frequency and duration — which basically makes it a nice alternative to Sleep() [031].
  • Q: Do you use any of the EDRSilencer [032] features in this packer? — A: Nope EDRSilencer uses the Windows Filtering Platform (WFP) to intercept EDR telemetry and avoid detection. What I'm doing with this packer is not to avoid detection but to enable execution.
  • Q: Will there be a Russian and Chinese language version? — A: Maybe it could be fun.
  • Q: Any cool and weird techniques? — A: My favourite one is for sure the “Low Entropy” (entropy being a way of measuring the randomness of data). Which is my way of bypassing Crowdstrike’s detection of encrypted data (high entropy) in files. Many clever approaches exist for this [033] [034]. I liked the first of these, although in my opinion using multiple English words was a way to try hard so I just added 1.000.000 “A”s to a string in the file and got an entropy of like 2, which does the trick.
  • Q: Can I use Code Caves instead? — A: Sure codecaves (spaces in an .exe where there is no live code) can be used to hide your functionality or shellcode loader. Just remember that this will change the hash and signature of the file, leading to more scrutiny by detection products.

There were many other great questions, but these were the ones I can remember off the top of my head.

If you have any additional questions please feel free to post them in the responses to this article or send me a message and I'll do my best to answer them.

— [ 0xD — References

Other references:


메타데이터
post_id
0e5ed2196ccd
slug
bsides-cph-2024-writeup-diy-trojan-horse-or-how-to-get-your-malware-past-edr-0e5ed2196ccd
url
https://medium.com/@0x0vid/bsides-cph-2024-writeup-diy-trojan-horse-or-how-to-get-your-malware-past-edr-0e5ed2196ccd
canonical_url
https://medium.com/@0x0vid/bsides-cph-2024-writeup-diy-trojan-horse-or-how-to-get-your-malware-past-edr-0e5ed2196ccd
author_url
https://medium.com/@0x0vid
status
ok
fetched_at
2026-06-27 07:40:21