Skills · learning

AV and EDR Defence Evasion

Table of Contents

AV and EDR Defence Evasion

Quick references: task-first command sheet · detailed command reference · exam navigator

Authorized-lab note: use these concepts only within an explicitly scoped red-team engagement or your own isolated home lab. “Evasion” here means understanding and measuring defensive visibility - not disabling security controls or applying these techniques to systems without permission.

Quick reference: what to remember next time

The central rule

For a defensive review, start with:

What exact artifact or behavior triggered the alert, which control observed it, and what evidence supports that conclusion?

AV/EDR detection is a moving target. A payload that is clean today may be detected tomorrow, and a payload that passes a static scan may still be detected when it executes.

The four visibility layers

  1. File and reputation: filename, hash, publisher, prevalence, and reputation.
  2. Static content: PE headers, sections, imports, strings, resources, entropy, and recognizable code or byte patterns.
  3. Runtime behavior: process creation, script execution, memory allocation, injection, module loading, network activity, and the sequence of events.
  4. OS and security telemetry: process/thread callbacks, image loads, file and registry activity, network telemetry, AMSI, ETW, and correlated EDR events.
Artifact arrives
      │
      ├─ reputation / signature / static inspection
      │
      ▼
Execution allowed?
      │
      ▼
Runtime monitoring
      │
      ├─ process and thread behavior
      ├─ memory and module mapping
      ├─ scripts and command lines
      ├─ file, registry, and network activity
      └─ security-provider telemetry
      │
      ▼
Behavioral correlation → alert, block, or allow

Cobalt Strike-specific map

Area What it changes What it does not guarantee
Artifact Kit Compiled EXE/DLL artifact templates and their loading behavior A clean artifact after one scan
Resource Kit Script artifacts such as PowerShell templates That decoded or executed content will be clean
Malleable C2 stage How Beacon is represented and loaded in memory That memory is invisible to EDR
Malleable C2 process-inject Allocation, transformation, and execution choices for injected content and BOFs That injection becomes benign
Malleable C2 post-ex Some post-exploitation process, pipe, and cleanup behavior That a legitimate-looking process makes the behavior legitimate
Command choice The implementation path and observable child processes That a Beacon command hides its underlying Windows actions

Four customization layers and when they matter

Layer What it changes What defenders may observe
Artifact Kit Compiled EXE/DLL templates that package and start Beacon content. File reputation and static features, followed by the template's runtime behavior.
Resource Kit Script templates used by Cobalt Strike workflows, including PowerShell and other script formats. Script text, files written to disk, content submitted through AMSI, and the script host's behavior.
Malleable C2 profile Beacon's network representation and selected stage, injection, and post-execution characteristics. Network patterns, memory and process activity, and related security telemetry.
Beacon command implementation The host-side path a particular feature uses: client-side action, Beacon API, BOF, post-exploitation job, process, or service. The processes, APIs, tokens, memory, threads, scripts, pipes, and services involved in that path.

These layers solve different problems and can be used together. A custom Artifact Kit does not customize PowerShell templates; a Resource Kit does not change Beacon's injection settings; a Malleable C2 profile does not make every command invisible.

Do not apply a profile change just because a command has an OPSEC consideration. First identify that command's implementation path and the behavior the lab asks you to observe. process-inject is relevant to injected content and BOF memory; post-ex is relevant to supported post-exploitation jobs. Network-profile options address a different layer. Use the installed-version documentation for exact command support.

Beacon command behavior: exam classification

Command class Mental model Main defensive observations
Housekeeping Some actions affect only the client UI; others queue work for Beacon. Distinguish a local console action from a queued task, network check-in, or target-side action.
API-only Beacon performs an operation using Windows APIs without necessarily starting a child process. API effects can still produce file, token, process, network, registry, or security telemetry.
Inline BOF A compiled object runs inside the Beacon process and uses Beacon's internal APIs. No separate process is implied, but memory allocation/protection changes and the BOF's own API behavior remain observable. Don't assume a BOF can never create a thread.
Fork-and-run / explicit post-ex A post-exploitation capability runs in a temporary process or a selected existing process; results may return through a pipe. Process ancestry, injection, memory writes/protection changes, threads, image loads, and pipe activity. post-ex and process-inject influence different parts of this path.
External process / service A command may start a program or create/use a service. Parent/child relationships, command lines, service installation/start events, identity, and resulting network or file activity.

Exam prompt: name the implementation path, the process and security context involved, and the telemetry a defender could correlate. The command name by itself does not tell the whole story; behavior can vary by feature and Cobalt Strike version.

Token reminder: an access token represents a Windows security context. Using or impersonating a token does not grant arbitrary rights; the account, token privileges, logon context, and target authorization still matter. Confirm the effective identity and permissions rather than inferring them from a command's success message.

The practical workflow

  1. Identify whether the alert concerns file reputation, static content, AMSI/script content, memory, process behavior, network activity, or correlated events.
  2. Reproduce or review it only in the authorized, isolated lab, using the lab's approved test input.
  3. Preserve the alert, timestamps, exact file hash or script identity, process tree, and relevant Defender/EDR events.
  4. Separate file scanning from execution telemetry and record whether the product blocked, quarantined, alerted, or allowed the test.
  5. Compare the evidence across visibility layers; an alert may be triggered by a sequence rather than one file or API.
  6. Treat “ThreatCheck clean” as not detected by that test at that stage, not as proof of operational safety or invisibility.

The most important memory and process ideas

  • RWX memory can be unusual because many ordinary applications do not need pages that are simultaneously readable, writable, and executable. Changing to RW and later RX may alter one signal, but it does not remove all memory telemetry.
  • PE headers help a loader map an image, but their presence in an in-memory Beacon region can make that region easier to recognize. Removing headers changes one memory characteristic; it does not make the code invisible.
  • Module stomping can make a memory region appear associated with a legitimate module, but defenders can compare memory with the image on disk or inspect other inconsistencies.
  • Process injection is a chain: obtain a process handle → allocate memory → write content → arrange execution. Every step can be observable.
  • BOFs execute inside Beacon and are not automatically “free” from detection. Their allocator, memory reuse, and execution path are influenced by process-inject settings and by the BOF itself.
  • Fork and run usually means a temporary or sacrificial process, injected capability, and a return channel such as a named pipe. More mechanisms mean more telemetry and more opportunities for detection.
  • PPID spoofing and spawnto are not the same: one changes the apparent parent relationship for a created process; the other selects a process used for execution or injection. Neither makes an implausible process tree legitimate.
  • Service execution can produce high-integrity execution, but service creation, the service binary, its parent/child relationships, and its command line remain observable.
  • AMSI is an interface, not the detector: an AMSI-aware application submits content to an antimalware provider, which makes the detection decision.
  • Static script scanning is not execution scanning: PowerShell may decode, decompress, or transform content and expose intermediate representations during execution.
  • A clean result is scoped: clean from a particular scanner, at a particular stage, with a particular artifact, on a particular date.

What not to memorize

Do not memorize a fixed list of commands, filenames, bypasses, or “safe” settings. Cobalt Strike versions, endpoint products, policies, and detections change. Memorize the reasoning pattern:

Technique → implementation path → Windows observations → defender telemetry → test result

Detailed notes

The sections below preserve the original explanations, diagrams, lab notes, screenshots, and unresolved questions. They are now grouped by the defensive layer they help explain.

1. AV and EDR mental model

Antivirus and endpoint detection response: defensive evasion is a tactic where adversaries attempt to avoid detection during an operation. It is not something done only at the beginning or end; it affects decisions throughout the operation. Defensive evasion is not something done only at the start or end; it is a consideration throughout the operation.

Most antivirus products use two broad detection strategies.

The first is static analysis: signatures and other rules inspect known or recognizable portions of a payload.

For the Cobalt Strike ecosystem, this can include raw Beacon content, the prepended loader, and compiled artifacts that contain or deliver them.

The second is dynamic or behavioral analysis: the product observes execution and applies heuristics or behavioral rules.

Examples include running shell commands, creating unusual child processes, remote process injection, and running third-party post-exploitation tools.

This raises the practical question: does a red-team operator still need to understand how to modify payloads and post-exploitation behavior to avoid these detections?

The goal for this chapter is to understand and test those detection surfaces: remove or change known indicators in an authorized lab, and understand how post-exploitation behavior changes what AV/EDR can observe.

  • The Artifact Kit to remove known indicators from the compiled artifacts (the .exe and .dll).

  • The Resource Kit to remove known indicators from the script artifacts (the .ps1).

  • Malleable C2 to modify how the prepended loader loads Beacon into memory.

  • Malleable C2 to modify post-exploitation behaviours.

A major caveat for this defensive-evasion chapter is that antivirus and EDR are moving targets. Vendors continuously update signatures, models, and behavioral detections.

What works today may not work tomorrow.

The durable skill is the methodology: identify the detection surface, test it, and understand what changed.

This way you can investigate future detections on your own.

This section gives a mental model of how endpoint defenses observe a program from arrival through execution.

Use the four visibility layers above as a simplified model; products can combine them and their exact behavior varies.

A product may assess reputation and file content before execution, apply policy checks, then observe process behavior and operating-system telemetry. The stages can overlap; a static pass does not guarantee that later execution will be allowed.

Modern endpoint protection is not just a database of known file hashes; it can combine reputation, static inspection, behavior monitoring, and OS telemetry.

Detection model separating static payload inspection, execution behavior, and AV/EDR visibility.
Fig. 1. Detection model separating static payload inspection, execution behavior, and AV/EDR visibility.

The four-layer summary is a study model, not a claim that every product uses the same pipeline.

When reviewing endpoint defenses, identify the observed signal and the layer that produced it before drawing a conclusion. don't just ask how does this loader work

also ask what does the window observe while this loader runs and which of those observations could an A or endpoint detection response used to recognize malicious behavior

Use this model to connect a red-team action to the defensive evidence it may create.

At the highest level, modern endpoint security is roughly:

                Something enters the machine
                         │
                         ▼
              ┌─────────────────────┐
              │ File / Payload      │
              └──────────┬──────────┘
                         │
          ┌──────────────┼──────────────┐
          ▼              ▼              ▼
     Static analysis  Reputation    ML / heuristics
     signatures       prevalence    suspicious traits
          │              │              │
          └──────────────┼──────────────┘
                         ▼
                  Execution allowed
                         │
                         ▼
              ┌─────────────────────┐
              │ Runtime monitoring  │
              └──────────┬──────────┘
                         │
       ┌─────────────────┼─────────────────┐
       ▼                 ▼                 ▼
   Processes          Memory            System
   & threads          activity          activity
       │                 │                 │
       │          suspicious memory       ├─ files
       │          regions/modules         ├─ registry
       │                                   └─ network
       └─────────────────┬─────────────────┘
                         ▼
                 Behavior correlation
                         │
                  "Does this look
                    malicious?"
                    /          \
                  YES           NO
                   │             │
                   ▼             ▼
             block / alert     continue

The important realization is that antivirus isn't simply a database of malware hashes anymore.

Suppose malware called evil.exe appears.

1.1 Known-file detection

The easiest case is something the vendor already knows.

evil.exe
   ↓
SHA-256 / signatures / reputation
   ↓
Known malicious?
   ↓
BLOCK

This is why simply downloading a well-known malware sample will often get caught immediately.

But attackers can modify binaries, so defenders need more.

1.2 Static analysis

Before executing the program, security software can inspect properties of it.

Think:

evil.exe
│
├── PE headers
├── sections
├── imports
├── strings
├── embedded resources
├── entropy
├── digital signature
└── suspicious code characteristics

For example, a program containing suspicious combinations of capabilities may receive a higher risk score.

This is where concepts you've been studying such as PE files, loaders, packing and shellcode start becoming relevant.

1.3 Runtime behavior

This is arguably the most important concept for understanding modern EDR.

Imagine a previously unseen program:

unknown.exe

Its hash isn't known and its static appearance doesn't trigger a block.

It executes.

Now endpoint telemetry might observe a chain such as:

Word
  │
  └── launches PowerShell
             │
             └── unusual script activity
                        │
                        └── accesses another process
                                   │
                                   └── suspicious memory activity
                                              │
                                              └── network connection

Each individual event might have a legitimate explanation.

The sequence and context can be much more informative.

That leads to an important distinction:

AV tends to answer: "Is this artifact malicious?"
EDR additionally tries to answer: "Is this endpoint behaving like it is being attacked?"

The boundary isn't absolute - modern AV products incorporate behavioral detection too - but it's a useful mental model.

1.4 OS telemetry

Modern endpoint products can obtain information from several places in the operating system.

On Windows, you'll eventually want to understand:

Windows
│
├── Process creation
├── Thread creation
├── Image/module loading
├── File operations
├── Registry operations
├── Network activity
├── Script execution
│
├── AMSI
├── ETW
└── Windows security telemetry

This explains something important about the process-injection material you've been studying.

You were recently looking at:

VirtualAlloc
WriteProcessMemory
CreateRemoteThread

From the attacker's perspective:

allocate → write → execute

From the defender's perspective:

Process A
   │
   ├── interacts with Process B
   │
   ├── causes memory changes
   │
   └── execution appears in unusual memory
                    │
                    ▼
            suspicious telemetry

Same event, completely different mental model.

That's the perspective I recommend learning.

1.5 Learning path

Rather than studying "antivirus bypass" as one giant subject, build these concepts in order:

  1. How classic antivirus works - hashes, signatures, YARA-like pattern matching, reputation and static PE analysis.

  2. How Windows executes programs - PE loading, virtual memory, processes, threads, DLLs and permissions.

  3. How modern EDR observes Windows - process trees, memory events, ETW, AMSI, callbacks and behavioral telemetry.

  4. How detections are constructed - individual indicators versus sequences of behavior, behavioral rules and correlation.

  5. Then revisit offensive techniques - process injection, reflective loading, shellcode and C2 frameworks, but ask what observable artifacts does each technique create?

That last question is extremely valuable.

For example, when you next study a Cobalt Strike loader, don't only ask:

"How does this loader work?"

Also ask:

"What does Windows observe while this loader runs, and which of those observations could an AV/EDR use to recognize malicious behavior?"

That connects your red-team knowledge directly to blue-team knowledge.

A particularly useful next lesson would be to take one completely ordinary Windows executable from double-click → PE loading → process creation → memory → execution, and mark every point where Defender/EDR can potentially observe it. Once that model clicks, things like AMSI, ETW, process injection detection, reflective loading and Cobalt Strike become substantially easier to understand.

2. Artifact Kit: compiled artifacts

The Artifact Kit is a source framework for generating EXE and DLL templates that host or load Beacon content. It is not the Beacon payload itself.

Beacon is the payload. The Artifact Kit is a source framework for generating executable and DLL artifacts that host or load that payload. It is not the Beacon itself.

The Artifact Kit contains stage-zero artifact templates and supporting source code. The templates are not merely inert wrappers: they include the selected loading, allocation, and execution logic used to start the Beacon content.

When an artifact is generated, Cobalt Strike places the selected Beacon shellcode into a template. The template supplies the loader and execution logic.

The templates take Beacon shellcode and arrange for it to be loaded or executed in memory. Their behavior can include allocation, decoding, cleanup, and selected environment checks, so their observable behavior matters as much as their static bytes.

Repeated template logic and byte patterns can be recognized by static scanners, especially when the same kit version is reused.

A matching signature identifies a known pattern; it does not establish how every version or deployment will be detected.

The kit source can be changed for a controlled lab comparison, but a change is not a detection bypass guarantee and may break the artifact.

The kit includes editable source templates, which helps explain how the generated artifact behaves.

Operators can modify source portions that are known to be recognized by a particular antivirus product, but this is a version- and vendor-specific experiment - not a general bypass guarantee.

Diagram distinguishing the Beacon implant from the compiled wrapper produced by the Artifact Kit.
Fig. 2. Diagram distinguishing the Beacon implant from the compiled wrapper produced by the Artifact Kit.

A layout of the kit can be overwhelming if you're not fluent in C but it's actually simple

This is the layer of the artifact kit

Artifact Kit directory layout showing source folders and bypass implementations.
Fig. 3. Artifact Kit directory layout showing source folders and bypass implementations.

The easiest way to about this layout is to stop thinking it of it is a pile of C files instead think about as who is responsible for what

The artifact kit is essentially building a wrapper around the a payload

Artifact Kit source map showing where startup and execution behavior are implemented.
Fig. 4. Artifact Kit source map showing where startup and execution behavior are implemented.

You can see here that this their source It's not it's actually just three different doors into the same machinery It's three different entry points

2.1 main.c, svcmain.c, dllmain.c - "How did Windows start me?"

Windows programs can be launched in different ways, so the Artifact Kit needs different entry points.

Think of these as three different front doors into essentially the same machinery.

Normal EXE
   │
   ▼
 main.c ─────┐

Windows      │
Service      │
   │         │
   ▼         ├──► common Artifact Kit logic
svcmain.c ───┤
             │
DLL loaded   │
   │         │
   ▼         │
dllmain.c ───┘

If you build:

artifact.exe

Windows starts the normal executable entry path represented by main.c.

If you build something intended to run as a Windows service:

artifact.svc.exe

the service-oriented entry path uses svcmain.c.

And if you're building:

artifact.dll

the DLL's entry path is represented by dllmain.c.

So don't think:

"Why are there three different versions of the malware?"

Think:

"There are three different ways Windows might enter this program."

2.2 bypass-*.c - "Should I continue running?"

And then there's the there's the bypass.C -- This is the logic the answers should I continue running It basically checks which environments it's in and checks if the environment looks suitable or unsuitable for one

you have seen in the previous picture there's different kinds of bypasses The reason for this is you wanna make it modular instead of having an entire bypass file that describes all the different bypasses

These implement environment/sandbox checks.

Conceptually:

Program starts
     │
     ▼
Environment check
     │
     ├── environment looks unsuitable
     │         ↓
     │        stop
     │
     └── continue
              ↓
        payload logic

The important architectural point is that they're modular.

Instead of putting all of that code inside main.c, the project separates it:

src-common/
    bypass-A.c
    bypass-B.c
    bypass-C.c

The build configuration can select the implementation used by a particular template.

And then there's a third part which is the patch dot C This is the one that actually contains the Shelfwood injection

You can think of it as patch C is the main payload execution machinery

Then you can think of injection.C and start thread.C as just helper functions too do the shelter injection

putting the whole thing together it looks like this

Source-layout diagram distinguishing normal executable startup from the selected bypass implementation.
Fig. 5. Source-layout diagram distinguishing normal executable startup from the selected bypass implementation.

to build a new set of templates this is the code you need to run

The syntax is: ./build <techniques> <allocator> <stage size> <rdll size> <include resource file> <stack spoof> <syscalls> <output directory>.

This is an example of a basic artifact using the bypass mail slot bypass template

./build.sh mailslot VirtualAlloc 344564 0 false false none /mnt/c/Tools/cobaltstrike/custom-artifacts

Uh this is the meaning of the flags

  • Techniques is a space separated list of bypass templates that you want to build.

  • Allocator sets which API is used to allocate memory for the shellcode.  The default options are HeapAlloc, VirtualAlloc, and MapViewOfFile.

  • Stage Size is used to set the reserved space needed for the Beacon shellcode.

  • RDLL Size is used to validate the stage size.  When not using a custom loader, keep this set to 0.

  • When set to true, the Resource File is used to change properties of the artifact, such as the CompanyName, FileDescription, ProductName, etc.  This information is defined in src-main/resource.rc.

  • When set to true, Stack Spoof enables a stack spoofing technique to hide the fact the shellcode is executing from an unbacked region of memory.

  • Syscalls sets the system call method.  Valid options are none, embedded, indirect, and indirect_randomized.

  • Output Directory is the directory to save the generated artifacts.

After you've created the stage your new artifacts will look like this

PowerShell directory listing of the compiled custom artifacts used in the course example.
Fig. 6. PowerShell directory listing of the compiled custom artifacts used in the course example.

Before plugging this new template into Cobalt it's useful to How do you stand up against antivirus before any weaponized shell code is patched into them

This is so that your templates I first checked and they don't trigger any signatures for the static checks

It's not ideal to recommend your templates to Virus Total because you're just giving away your artifacts to antivirus for for antivi virus vendors to analyze instead

you should check within your own sandbox

Tools such as ThreatCheck can help localize a static detection by testing portions of a file and reporting the smallest region that still triggers the selected scanner. This is a diagnostic result for that file and scanner, not proof that the behavior is safe or that the detection has been defeated.

ThreatCheck run identifying a detection boundary in the selected compiled artifact.
Fig. 7. ThreatCheck run identifying a detection boundary in the selected compiled artifact.

First analyze which part of the program I was actually seen as malicious you got to check it out in in ghidra so use to find out which assembly program it's It's called is being detected as malicious

https://github.com/NationalSecurityAgency/ghidra

The steps Where is Gidra you'll be able to see the decompiled function in instead of reading assembly language which is almost It's very hard to read

First student wants to navigate to What if the section was seen as malicious

To find the offending code, we can use ghidra to jump to the offset given by ThreatCheck.  Select Navigation > Go To and enter file(0x9ce) (or whatever offset ThreatCheck gave), and click OK.  This will jump us to an 'unknown' function called FUN_140001585.  To narrow down the search a bit more, we can go back to ThreatCheck's output and start looking at the specific byte sequences that it reported.  In this particular example, the last line of output were the hex values 83 E2 07 8A 54 15 00 32 14 07 88 14 03 48 FF C0, and we can match these exactly in Ghidra.

Highlighting these bytes in the assembly (on the left) will also highlight the corresponding lines in the decompilation (on the right).

Disassembly view used to inspect the machine-code region associated with the detection.
Fig. 8. Disassembly view used to inspect the machine-code region associated with the detection.

Then after this you go back into the actual to the artifact source code defined by the loop the loop exist

Now we can see that this byte sequence relates to a for loop.

The next step is to go back to the artifact source code and find where this loop exists.  We can clearly see its within a function that takes three parameters, and contains calls to VirtualProtect and CreateThread.  This turns out to be the spawn function in patch.c, and based on the comments, is responsible for decoding the Beacon shellcode and copying it into memory.  The loop itself is on lines 115-117.

Source-code excerpt showing the payload-copy loop under examination.
Fig. 9. Source-code excerpt showing the payload-copy loop under examination.

The course then compares source changes with static-scanner results. Treat it as an experiment about one signature, not as a way to make execution invisible.

One way to test a static signature is to modify the source so that it compiles to different machine code while preserving the intended lab functionality. This may change one signature without changing the runtime behavior that an EDR observes.

Simply changing variable names is usually insufficient for compiled code because source names are often not retained in the release binary. The generated machine code and surrounding structure are what matter to the static signature.

Changing the variable names May may change will change the source representation but executable it's still the same so we probably detected by the A

The lesson's alternate loop form is an example of a source change that can alter compiled bytes while preserving the intended function. Runtime behavior can still be detected.

In this way it still runs the same code both in a different way

Revised payload-copy code retaining the earlier implementation for comparison.
Fig. 10. Revised payload-copy code retaining the earlier implementation for comparison.

Once you've made your change go and build the script again and then and then check if the template is still detected as a malicious

ThreatCheck output after the course's artifact-source change.
Fig. 11. ThreatCheck output after the course's artifact-source change.

Once you are sure these templates are no longer seen as malicious You can load them so that this new template will be used -- This is just you hooking the new templates into Cobalt Strike

There's a nice demo of how to use artifact kits here but you can also just find it online

It basically just runs through what we've just covered

https://www.zeropointsecurity.co.uk/path-player?courseid=red-team-ops&unit=696e32554ceb5e67d90ae795Unit

3. Resource Kit, AMSI, and script content

The Resource Kit changes script templates used by Cobalt Strike workflows. It is separate from the Artifact Kit's compiled EXE/DLL templates and from Malleable C2's Beacon memory/injection settings. A custom script template can change the generated script, but it does not disable the AMSI interface or guarantee that later PowerShell content or behavior will be allowed. The installed kit's README identifies which workflows use each template.

In this lab, compress.ps1 is described as a helper used to package PowerShell content for a delivery workflow. Treat its source file, any generated/downloaded script, and content PowerShell processes while executing as separate inspection points. Confirm the helper's exact role against the README for the kit version in the lab.

Oh so the artifact kit is used to modify the compiled templates compiled templates meaning like EXE DLL does been a files those kind of things

while Resourcekit is used to modify script templates

AMSI (Antimalware Scan Interface) is especially relevant to PowerShell because PowerShell can submit content to an antimalware provider while it is being interpreted. AMSI is not itself the detection engine and is not limited to scripts that are already “running in memory.”

What is AMS and how does it work

It's basically made by Windows and is a standard that allows application and services to integrate with the antivirus product on the machine That means it's not just Windows Defender that can access AMSI

Any 3rd party developer can submit and scan requests from the application which is done using the AMSI DLL

AMSI is essentially the bridge between the application and the security product. Oh

This is how the AMSI architecture looks like

AMSI architecture showing PowerShell, the scanning interface, and the antimalware service.
Fig. 12. AMSI architecture showing PowerShell, the scanning interface, and the antimalware service.

Native Windows components that are amsi aware --- What does it mean to be AMS I aware

  • components like User Account Control
  • Powershell scripts
  • Windows Script Host (wscript.exe and cscript.exe)
  • Javascript
  • VBS script
  • and VBA might macros

Note that the AMSI is not the one that determines whether or not the data is malicious It's the antivirus product itself that determines whether the AMSI is malicious

AMSI flow showing a script host submitting content for an antimalware scan.
Fig. 13. AMSI flow showing a script host submitting content for an antimalware scan.

AMSI is simply a vehicle which data can be submitted to an antivirus for analysis AMSI is an interface for submitting content to a registered antimalware provider; the provider, rather than the interface itself, evaluates that content.

The phrase “bypass AMSI” can refer to two different ideas and should not blur them together:

  • interfering with the AMSI submission path or its result; or
  • changing the content so that the antimalware provider does not recognize it.

The first category can itself be detected and can leave indicators. The second is better described as content or representation evasion, and a clean result from one scan does not establish that execution is safe. In a controlled lab, analyze PowerShell content the same way as compiled artifacts: identify what is detected, change one variable, and rescan and execute only within scope.

This is typically the the command to build resource kit

./build.sh /mnt/c/Tools/cobaltstrike/custom-resources

and you can see how the templates are made with this

Directory listing showing the custom Resource Kit files used in the demonstration.
Fig. 14. Directory listing showing the custom Resource Kit files used in the demonstration.

The same thing with your architect and the resource kit you use threat check to to find out which part gets detected

  • Know know the interchange you can also uh enable which antivirus or which kind of analysis you want to do with the E flag

ThreatCheck.exe -f .\template.x64.ps1 -e AMSI -t Script

When investigating a content-based AMSI detection in a lab, possible changes include:

  • renaming functions and variables
  • refactoring to break it down to into multiple sub steps
  • using classical Powershell obfuscation techniques
  • my suggestion is to start with simple ones and saving the changes and rescanning threat check as you go and move up to more complex changes if needed

You can see here it's flag It's flagging this as malicious

ThreatCheck output identifying a detection boundary in the script resource.
Fig. 15. ThreatCheck output identifying a detection boundary in the script resource.

and we've determined that it's because of the word system.Dll So you simply just use Trinkon caffeination to change it

Script excerpt associated with the offending line reported by ThreatCheck.
Fig. 16. Script excerpt associated with the offending line reported by ThreatCheck.

then after that you rescan it again to see if you have a different result and and we did And if there is you have to manually change all of this to bypass all of the changes

Another one that was found is this this is found to be malicious the marshall copy method from the net library

Byte-level output showing the region identified as the end of the detected content.
Fig. 17. Byte-level output showing the region identified as the end of the detected content.

The course compares API paths in a controlled lab. Calling a different API does not change the underlying memory-write behavior or guarantee a different runtime verdict.

We were able to use write process memory API to do the same task

$var_wpm = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((func_get_proc_address kernel32.dll WriteProcessMemory), (func_get_delegate_type @([IntPtr], [IntPtr], [Byte[]], [UInt32], [IntPtr]) ([Bool]))) $ok = $var_wpm.Invoke([IntPtr]::New(-1), $var_buffer, $v_code, $v_code.Count, [IntPtr]::Zero)

does this process of changing it and using threat check to do it until there's no more threat found

Once your artifact kit is ready you need to load the resources.cna as the new road resources so that it will be used

Compressed PowerShell example: the course includes a resource named compressed.ps1 to illustrate how a script can be packaged for a delivery feature.

The example compresses and Base64-encodes PowerShell text. This changes its on-disk representation; it does not remove the script behavior or prevent later inspection.

  • It would basically take a ps1 fikle and then compress it with G zip and then base 64 encodes it and then patches it into compressed PS1
ThreatCheck result after revising the script resource in the course example.
Fig. 18. ThreatCheck result after revising the script resource in the course example.

In the course comparison, the static ThreatCheck scan did not flag the compressed representation, while execution produced a detection. This is a lesson about different inspection points, not a general result.

The run-time result is shown in the following course screenshot.

PowerShell download-and-execute attempt and the response shown in the demonstration.
Fig. 19. PowerShell download-and-execute attempt and the response shown in the demonstration.

PowerShell can submit content to AMSI at different points as scripts are parsed, transformed, and evaluated. The antimalware provider may therefore see content that was not apparent in the original file.

For example, PowerShell can evaluate one representation and submit content to AMSI before later decoding or constructing another representation.

Separate evaluation stages can produce separate observations or alerts. Keep the static file scan and the execution-time inspection as separate questions.

ThreatCheck tests supplied content through a selected scanning path; it does not necessarily reproduce the entire behavior of PowerShell executing and transforming that content.

If encoded text is decoded during execution, a later scan may receive the decoded content. A clean result for the original representation does not predict the result at a later stage.

AMSI content inspection is one layer; process, memory, file, and network telemetry can provide additional evidence.

Yes. The important distinction is scanning a fixed piece of text versus watching PowerShell progressively transform that text while executing it.

Think about a simplified, benign example where a script contains encoded data:

$encoded = "SGVsbG8="
$decoded = [Convert]::FromBase64String($encoded)
$stream = New-Object IO.MemoryStream(,$decoded)

The source file contains:

Layer 0  -  original script
        ↓
"SGVsbG8="
        ↓ Base64 decoding
Layer 1  -  decoded bytes
        ↓
MemoryStream
        ↓ processing
Layer 2  -  another representation

PowerShell delivery: where inspection can occur

This diagram shows the observation path, not a payload-generation procedure. Scripted Web Delivery can host a PowerShell script that PowerShell downloads and evaluates; each transformation or execution stage may expose different evidence.

flowchart LR A[Operator selects a PowerShell workflow] --> B[Resource Kit template shapes generated script] B --> C[Cobalt Strike web server hosts script] C --> D[PowerShell host downloads and evaluates content] D --> E[Content may be decoded or decompressed] E --> F[AMSI-aware application submits content to provider] D --> G[Defender/EDR observes process, memory, network, and child activity] F --> H[Provider decision: allow, alert, or block] G --> I[Correlated endpoint decision] H --> I
Diagram source
flowchart LR
    A[Operator selects a PowerShell workflow] --> B[Resource Kit template shapes generated script]
    B --> C[Cobalt Strike web server hosts script]
    C --> D[PowerShell host downloads and evaluates content]
    D --> E[Content may be decoded or decompressed]
    E --> F[AMSI-aware application submits content to provider]
    D --> G[Defender/EDR observes process, memory, network, and child activity]
    F --> H[Provider decision: allow, alert, or block]
    G --> I[Correlated endpoint decision]
    H --> I

Keep the checkpoints separate: a static scan of a script, an AMSI inspection of content during evaluation, and runtime behavior are different observations. A result at one checkpoint does not predict the result at the next.

What ThreatCheck is doing in your example

When you give ThreatCheck:

compress.ps1

it's testing content from that supplied artifact against the selected scanning interface.

Very roughly:

compress.ps1
     │
     ▼
ThreatCheck
     │
     ▼
AMSI scan
     │
     ▼
No detection

The important limitation is:

ThreatCheck isn't PowerShell actually executing the entire script.

Therefore it doesn't necessarily reproduce every intermediate representation PowerShell will generate during real execution.


What happens during actual PowerShell execution

PowerShell is an interpreter/runtime. It starts evaluating expressions.

Suppose the original script effectively contains:

encoded content

Initially AMSI might see something corresponding to that representation.

Then PowerShell evaluates:

[Convert]::FromBase64String(...)

Now something new exists:

Base64 text
     │
     ▼
Base64 decoder
     │
     ▼
decoded content

PowerShell can expose content for antimalware inspection at relevant points as processing continues.

So conceptually you can end up with:

               PowerShell execution

Original script ───────────────► AMSI scan #1
      │
      ▼
Base64 decode
      │
      ▼
Decoded representation ────────► AMSI scan #2
      │
      ▼
Decompression/transformation
      │
      ▼
Resulting content ──────────────► AMSI scan #3
      │
      ▼
Further execution

Any one of those representations may expose something detectable.

That's what the author means by "different parts of code evaluation."

Why that's important

Imagine, purely illustratively, the AV knows the pattern:

MALICIOUS_PATTERN

But the source contains it encoded:

TU...==

Scanning only the original source might produce:

TU...==
   ↓
No recognizable pattern

But when the interpreter evaluates the decoding operation:

TU...==
   ↓ decode
MALICIOUS_PATTERN
   ↓
AMSI
   ↓
DETECTED

So you can have the seemingly confusing result:

ThreatCheck(compress.ps1)
        ↓
      CLEAN

         BUT

PowerShell(compress.ps1)
        ↓
     decode
        ↓
   intermediate content
        ↓
      AMSI
        ↓
    DETECTED

There's no contradiction. The AV was effectively presented with different content in the two situations.

That's the bigger lesson from this example: when testing AMSI detections, "does the source file scan clean?" and "does the complete PowerShell execution remain undetected?" are fundamentally different questions. An interpreter can progressively reveal content that wasn't plainly visible in the original artifact.

The precise distinction is between the AMSI interface, the provider's content verdict, and other runtime telemetry.

AMSI provides a content-inspection interface; the registered antimalware provider decides whether submitted content matches a detection.

With an obfuscation or refactoring technique, the representation may change enough that a particular static or content rule does not match. That does not imply that the resulting execution will evade behavioral or memory detections.

Provider rules and product versions change over time, so a previous scan result is not a lasting guarantee.

PowerShell commands loading Invoke-Obfuscation for the course's script-content example.
Fig. 20. PowerShell commands loading Invoke-Obfuscation for the course's script-content example.

A robust defensive view should correlate script content with process, memory, and network behavior rather than depend on one literal string. they should be they should be looking at script telemetry process behavior memory activity correlated events and decoded content

In short, when studying AMSI-related detection, distinguish the interface from the provider's decision: the experiment may change the representation of PowerShell content so that a particular provider rule does not recognize it, but the interface and other defensive sensors still exist.

AMSI is an interface that applications can use to submit content to an antimalware provider. PowerShell is a common caller, but AMSI is not limited to PowerShell.

An application can submit a buffer or string for scanning; the provider makes the detection decision.

Diagram separating an application's AMSI request from the antimalware provider's scan decision.
Fig. 21. Diagram separating an application's AMSI request from the antimalware provider's scan decision.

4. Beacon memory and in-memory visibility

Beacon may be delivered through an executable, DLL, or script, depending on the selected artifact. A loader prepares code and data in a process and transfers control to it. Security products can inspect memory after loading, so a clean file scan is not proof that run-time behavior will go unnoticed.

Microsoft Defender detection alert identifying Cobalt Strike-related behavior in the example.
Fig. 22. Microsoft Defender detection alert identifying Cobalt Strike-related behavior in the example.

Memory scans can be performed as a routine thing or it can be triggered by suspicious activities

The default loader behavior and the exact memory layout depend on the Cobalt Strike version and selected allocator. A Beacon stage may produce memory with read, write, and execute permissions during part of its loading process. Broad RWX regions can attract attention because many ordinary applications do not need them, although legitimate runtimes can also use dynamic executable memory.

Process-memory properties used to examine the Beacon process's mapped regions.
Fig. 23. Process-memory properties used to examine the Beacon process's mapped regions.

Setting stage.userwx to false asks the loader to avoid leaving the Beacon stage with writable-and-executable final permissions. The exact allocation and protection transitions depend on the loader and allocator; do not reduce this setting to “it allocates RW only.” The resulting behavior still needs to be checked in the target version.

The following course screenshot illustrates one view of Beacon-related memory properties; interpret it as a point-in-time example.

Second process-memory view illustrating the Beacon process's memory layout.
Fig. 24. Second process-memory view illustrating the Beacon process's memory layout.

Note that when we talk about malleable C2 it's just the Cobalt or the command controls configuration er profile system

A PE image includes metadata as well as executable code.

To understand what deal headers are is to understand what happens when Windows loads a normal EXE or DLL file

A Portable Executable contains headers and section information that describe the image to the loader; it is not only a block of code.

Think of the headers as construction manual describing the portable executable rather than the main logic of the program

The headers describe architecture, sections, and other loading information. The .text section commonly contains code, but section names and layout can vary.

A PE file is more than just executable code

A Windows .exe or .dll has a structure roughly like:

PE FILE
┌──────────────────────────┐
│ DOS Header               │  ← "MZ..."
├──────────────────────────┤
│ DOS Stub                 │
├──────────────────────────┤
│ NT / PE Headers          │  ← "PE..."
│                          │
│ architecture             │
│ entry point              │
│ section information      │
│ sizes / offsets          │
│ etc.                     │
├──────────────────────────┤
│ Section Table            │
├──────────────────────────┤
│ .text                    │  ← executable code
├──────────────────────────┤
│ .data                    │  ← writable data
├──────────────────────────┤
│ .rdata / other sections  │
└──────────────────────────┘

Think of the headers as the instruction manual describing the PE, rather than the program's main executable logic.

For example, they help a loader determine things such as:

Where is .text? How large is it? Where should execution begin? What architecture is this binary? What sections exist?

Why does the loader need them The loader needs the meta meta data to use it to construct the appropriate in memory representation of of so DLL headers are useful because they have the metadata for the executable O the headers are useful for loading the achievable code

PE-memory diagram separating headers, executable code, and other sections.
Fig. 25. PE-memory diagram separating headers, executable code, and other sections.

Once the relevant parts have been mapped and initialization is complete the CP primarily cares about the executable instructions and the data those it operates on it doesn't need it doesn't need the headers anymore

When the prepended loader loads Beacon into memory, it may copy Beacon's PE headers by default. The headers help describe the image during loading but are generally not needed for the Beacon code's normal runtime behavior. Their presence can make a PE-like memory region easier for an analyst or security product to recognize.

Copied PE headers are one possible memory clue. Changing whether they are copied removes only that characteristic; it does not make the memory image unidentifiable.

The following screenshot compares the header region shown in the course example.

Process-memory inspection showing the region associated with the Beacon's PE representation.
Fig. 26. Process-memory inspection showing the region associated with the Beacon's PE representation.

The course profile sets stage.copy_pe_header to alse to change this loader behavior. Treat it as a version-specific lab setting, not an exam recommendation.

This changes the copied-header behavior; it does not mean that only .text and .data exist in memory. Other sections and loader-created structures may still be present.

Setting stage.copy_pe_header to false asks the loader not to copy the PE headers to the final Beacon memory location. This changes one recognizable characteristic; it does not make the image unidentifiable or remove all metadata.

Additional memory-region view used to compare the Beacon's mapped image and private memory.
Fig. 27. Additional memory-region view used to compare the Beacon's mapped image and private memory.

Essentially your portable executable will look like this

Comparison of an in-memory PE representation with and without its original headers.
Fig. 28. Comparison of an in-memory PE representation with and without its original headers.

The next example discusses module stomping, also called module overloading in the course material.

A memory image may contain executable regions that are not backed by a conventional file mapping. That mismatch can be a useful defensive signal, but it is not conclusive by itself.

  • So this is another thing that can stand out

Thus we actually need to provide some kind of module in these regions so that it looks like it's real

The course profile setting selects a module for the loader to use as a backing image. The exact option name and behavior depend on the Cobalt Strike version.

In the illustrated technique, a module is mapped and its memory is then changed. That can make memory differ from the file on disk; comparing the two creates another detection opportunity.

The selected module must be large enough for the content in the example, and its suitability depends on the exact process and environment.

The module must be large enough for the Beacon payload. The vendor guidance describes choosing a module roughly twice the size of the payload; a fixed “512 KB” rule is not universal.

Note that the module must be large enough to accommodate Beacon, and the selected DLL must not be needed by the process in which it is loaded. For example, set module_x64 "Hydrogen.dll"; configures the x64 module-stomping target; the exact path and suitability depend on the target system and profile.

Most of the original portable executable will remain but the beacon will be mapped somewhere over the various sections

Process-memory properties used to inspect the changed mapping after the course configuration change.
Fig. 29. Process-memory properties used to inspect the changed mapping after the course configuration change.

just to go deeper into model stomping

You need to go back to how a legitimate application is loaded from this

And then understand that typical legitimate applications have modules that are associated with That's why we have to act as if we are a typical normal file back module

then of course a new defense opportunity rises here which is if you used that DLL it looked very different from the normal DLL so that will be seen as malicious

4.1 What normally happens

Suppose a legitimate application loads example.dll from disk.

DISK                              PROCESS MEMORY

C:\...\example.dll
        │
        │ Windows loads it
        ▼
                               ┌──────────────┐
                               │ example.dll  │
                               │ .text   RX   │
                               │ .data   RW   │
                               └──────────────┘
                                      │
                                      ▼
                              backed by:
                              example.dll

If a tool such as System Informer examines that RX region, Windows can associate it with the DLL that was mapped there.

That's normal:

Executable memory
      ↓
Which module owns it?
      ↓
C:\...\example.dll

4.2 Why an in-memory Beacon can look unusual

Beacon can be loaded without Windows loading a corresponding Beacon DLL from disk in the normal way.

You can therefore get something conceptually like:

PROCESS MEMORY

0x10000000
┌─────────────────────┐
│ Beacon code         │ RX
│                     │
│ machine instructions│
└─────────────────────┘
          │
          ▼
Backing module?

      NONE

That doesn't automatically mean malicious - JIT runtimes and other legitimate software can create executable memory too - but it's an interesting anomaly.

A defender might ask:

"Why is there executable code here when there isn't a normal file-backed module associated with it?"


4.3 Module stomping changes that appearance

Instead of creating an obviously separate memory-resident image, the technique starts with a legitimate module mapping.

Conceptually:

Step 1

Hydrogen.dll on disk
        │
        ▼
Windows maps it
        │
        ▼
┌─────────────────────┐
│ Hydrogen.dll        │
│                     │
│ original code       │
└─────────────────────┘

So Windows has legitimate bookkeeping saying:

this memory region
      ↓
Hydrogen.dll

Then comes the "stomping" part.

Some of the mapped module's in-memory contents are overwritten:

BEFORE

Hydrogen.dll mapping
┌──────────────────────┐
│ Hydrogen code        │
│ Hydrogen code        │
│ Hydrogen code        │
└──────────────────────┘


AFTER

Hydrogen.dll mapping
┌──────────────────────┐
│ some original data   │
├──────────────────────┤
│ Beacon-related code  │ ← overwritten memory
│ Beacon-related code  │
├──────────────────────┤
│ other original data  │
└──────────────────────┘

But the important part is that the memory mapping may still be associated with:

C:\Windows\System32\Hydrogen.dll

Hence the name module stomping: content belonging to a mapped module has effectively been stomped over.


4.4 Why the course says "Beacon appears backed by a legitimate module"

Without module stomping:

Executable memory
      │
      ▼
Beacon-like code
      │
      ▼
No ordinary backing DLL

With module stomping:

Executable memory
      │
      ▼
Beacon-like code
      │
      ▼
mapping associated with
Hydrogen.dll

So a simplistic defensive check like:

IF executable_memory
AND no_backing_module
THEN suspicious

becomes less useful.

But importantly, this doesn't make the code invisible.


4.5 The new anomaly: memory does not match the mapped module

A defender can instead ask:

"Does the memory actually contain what the DLL on disk says it should contain?"

Imagine:

ON DISK
Hydrogen.dll

0x1000  AA BB CC DD EE FF ...


IN MEMORY
"Hydrogen.dll"

0x1000  AA BB CC DD EE FF ...
0x2000  48 89 5C ...          ← different
0x3000  ...

If portions of executable memory differ unexpectedly from the corresponding mapped image, that's another potentially useful detection signal.

So you're seeing a recurring theme in this chapter:

Detection:
"Executable memory isn't file-backed"

             ↓

Technique:
Use a legitimate module mapping

             ↓

New detection opportunity:
"Why doesn't this module's memory
match what should be there?"

That's a much better way to study these techniques than thinking of them as magic invisibility tricks.

A memory scanner may inspect readable strings and other recognizable byte patterns inside a process. Distinctive strings can contribute to a detection, especially when combined with code bytes, constants, and surrounding structure. A string may remain visible after a payload is loaded into memory, depending on how the loader transforms it. This matters because memory inspection can see information that is not obvious from the name or appearance of the process. When relevant strings are present in a mapped image, a scanner may observe them in process memory. A string match can be a signal for further analysis; it is not, by itself, proof of malicious behavior. that will highlight it as malicious or at least trigger some kind of detection

Illustration of distinctive code and strings that may remain visible in a process-memory region.
Fig. 30. Illustration of distinctive code and strings that may remain visible in a process-memory region.

Strings are only one feature. A scanner may correlate constants, code bytes, memory layout, and surrounding structure.

But sufficiently distinctive combinations of constants, strings, code bytes, and surrounding structure can contribute to identifying a known implementation.

The course then uses an Aggressor Script helper to inspect the original Beacon DLL for study.

The helper extracts or exposes the original Beacon DLL so its recognizable content can be examined offline.

The key idea is simple: strings and other distinctive bytes can be visible in memory and can contribute to a detection.

It's really just saying that the strings can be culprits for detection

The lesson author is showing how analysts can inspect a Beacon image to understand which strings or byte patterns may be recognizable.

Cobalt Strike does not necessarily expose the exact in-memory DLL as a convenient file, so the lesson includes a helper to study the source image.

The loaded memory image may differ from the original DLL on disk, so an offline string listing is only a starting point for understanding what may be present at run time.

The helper provides a way to examine the original DLL content used in the lesson; its role is supporting analysis, not the main concept to memorize.

The Aggressor Script is supporting lab tooling. The concept to remember is that memory can expose recognizable content even when the original DLL is not present as a normal file.

Memory-detection model explaining why a running Beacon can remain identifiable after file-level changes.
Fig. 31. Memory-detection model explaining why a running Beacon can remain identifiable after file-level changes.

The script is not the main lesson; it is a means to inspect the artifact for defensive analysis.

Summary diagram connecting Beacon memory indicators with the detection surfaces discussed in the lesson.
Fig. 32. Summary diagram connecting Beacon memory indicators with the detection surfaces discussed in the lesson.

This is the actual lesson that we need to learn from strings

Recall: Beacon can contain recognizable data in memory. Studying the original image helps explain one possible detection signal, but changing bytes does not guarantee a clean result and may break the program.

"Beacon contains recognizable data in memory. Extract the original DLL so you can study those features, understand which ones contribute to detections, and recognize that changing binary content can also break the program."

5. Beacon command behavior

Beacon is Cobalt Strike's post-exploitation agent. The built-in command set and loaded extensions can vary by version. Memorize the execution categories and the evidence each can create; use the installed `help` output and the exam rules for a specific command.
Beacon command model separating API-only, BOF, and fork-and-run execution paths.
Fig. 33. Beacon command model separating API-only, BOF, and fork-and-run execution paths.

House-keeping commands

These commands generally exist to set a configuration option Beacon or perform other house-keeping tasks.  Common ones include:

  • help displays command help text.

  • checkin instructs Beacon to send its metadata.

  • sleep changes Beacon's sleep interval and jitter %.

  • clear clears the current Beacon console.

  • downloads shows downloads in progress.

  • cancel stops a download.

  • jobs shows running post-exploitation jobs.

  • note sets a custom note about the current Beacon.

  • powershell-import imports a PowerShell script into Beacon.

  • ppid sets an alternate parent for supported created processes; it does not affect every Beacon command or execution path.

  • spawnto changes the temporary process used for supported post-exploitation jobs.

Some of them (checkin, sleep, cancel, powershell-import, spawnto, and ppid) work by sending a task to Beacon to carry out; whilst others (help, clear, downloads, jobs, and note) do not, and are handled client-side instead.

API-only commands

These commands are built into Beacon and only rely on native Windows APIs to function.  Common ones include:

  • pwd prints Beacon's current working directory.

  • cd changes Beacon's current working directory.

  • download transfers a file from the target to the team server.

  • upload transfers a file from the attacker's machine to the target.

  • ls list files and directories.

  • getuid gets the username of the current user.

  • make_token creates and impersonates an access token.

  • steal_token duplicates and impersonates an access token from another process.

  • rev2self drops token impersonation.

  • kill terminates a target process.

  • exit instructs Beacon to terminate.

These are someone new to me with our inline commands

clipboard monitors the user's clipboard content gets system use OK

Inline commands

These commands are implemented as Beacon Object Files (BOFs), which are compiled C programs that execute within the Beacon session. The BOF and command arguments are sent to Beacon as tasking data. Cobalt Strike cleans up the BOF capability after it finishes where the implementation permits, but “cleared” should not be treated as a guarantee that no memory or telemetry remains. Common commands that are implemented as BOFs include:

Or did the beacon object falls which means it's uh commands that actually exist in the

  • clipboard monitors a user's clipboard content.

  • getsystem elevates the Beacon session to SYSTEM privileges.

  • jump psexec is a lateral movement technique.

  • kerberos_ticket_use imports a Kerberos ticket into the Beacon session.

  • reg queries the registry.

  • runasadmin uac-cmstplua is a UAC bypass technique.

BOFs are compiled object files that execute inside the Beacon process and use Beacon's internal APIs. They are a popular way to add custom commands, but they are not ordinary external programs. This differs from larger post-exploitation DLL features, which can run in a temporary or selected process: process-inject controls that injection step, while post-ex controls behavior specific to those features. A BOF's implementation determines its own memory and thread behavior. TrustedSec's Situational Awareness BOF is an example.

Thread correction: executing a BOF inside Beacon does not by itself imply a new process. It also does not prove that no new thread or other observable behavior can occur; the BOF's implementation matters. Review process, memory, thread, and API telemetry for the actual feature rather than assuming all BOFs behave alike.

6. Fork and run commands

  • Many of Beacon's post-exploitation features are implemented as Windows DLLs.  To execute these DLLs, they are appended to a loader (much like Beacon is) to produce a shellcode package, which is then injected into a target process.  Output is provided to Beacon over an SMB named pipe.  There are two sub-categories to this pattern, called 'explicit' and 'spawn'.

  • Explicit injects the post-ex capability into a target process that already exists.

  • Spawn starts a new process and injects the post-ex capability into it.

Some fork & run commands support both variants, while some only support one or the other.

Comparison of explicit injection into an existing process and spawning a new process.
Fig. 34. Comparison of explicit injection into an existing process and spawning a new process.
  • Spawn only

    • execute-assembly runs a .NET (Framework) assembly in memory.

    • powerpick runs PowerShell via an unmanaged runspace.

  • Explicit only

    • psinject is same functionality as powerpick.
  • Both

    • portscan scans open ports and fingerprints services on the network.

    • keylogger logs the keystrokes within the desktop session it's injected into.

    • printscreen takes a screenshot of the desktop session it's injected into.

    • desktop injects a full VNC session.

    • mimikatz requires no explanation 🙂

OPSEC considerations

The OPSEC question isn't simply:

“Which executable should I use?”

The deeper question is:

“Does the resulting process behavior make sense?”

These commands carry the heaviest OPSEC burden because they must inject shellcode, start a new thread, and start a new named pipe.  The spawn variant must also start a new sacrificial process.  Malleable C2's process-inject block can influence how this shellcode is injected. It does not make the action invisible or inherently safer.

Fork-and-run diagram showing injection, a new thread, and the named-pipe communication path.
Fig. 35. Fork-and-run diagram showing injection, a new thread, and the named-pipe communication path.

This is the key idea:

More mechanisms = more opportunities for detection.

A defender doesn't necessarily need to recognize “Cobalt Strike.”

They can potentially recognize the behavioral chain produced by the technique.

OPSEC diagram mapping an operation across multiple telemetry and detection surfaces.
Fig. 36. OPSEC diagram mapping an operation across multiple telemetry and detection surfaces.

Process execution commands

There are several commands that are used to run an arbitrary program on disk.  These include:

  • execute runs a program without returning output.

  • run executes a program but does return output.

  • runas executes a program using alternate credentials.

  • runu is like run but attempts to spoof its parent PID.

  • shell passes the provided arguments via cmd.exe.

  • powershell passes the provided arguments via powershell.exe.  Other commands also rely on this, including jump winrm and remote-exec winrm.

Service creations

The following Beacon commands create a service (either on the current machine or a remote one) to run a command or Beacon.

  • elevate svc-exe is used to elevate from high-integrity to SYSTEM privileges.

  • jump psexec, psexec64, & psexec_psh are lateral movement techniques.

  • remote-exec psexec runs an arbitrary command.'

The built-in service executable uses rundll32.exe as its default temporary process in the documented behavior; treat this as version- and implementation-specific rather than a universal rule for every service-based payload.

tghghe main lessonm here is that even though services are run with high priviletes --- this does not mean that they cannjot be tagged as malicious

context and behaviour of where you run things matters

Using a legitimate Windows executable doesn't automatically make activity inconspicuous. Context and behavior matter.

this will still be tagged as malcviisiou

Process-chain example showing a service-launched process and behavior that may warrant investigation.
Fig. 37. Process-chain example showing a service-launched process and behavior that may warrant investigation.

the main thing here is that the AK settigns in tghe artifact kid provides a comamnds that calles the AK settings which allow syou to send the spawn tto an expliocit path instead

the service binary will use the post.ex spaw to directin in the confdig --- but we need to change that as the win dire is not valid in system context --- thus we need to change in in the Ak SETTINGS

THE MAIN THING TO TKA WAWY HERE IIS THAT --

DIFFERENT BEACION EXUCTUION MECHANSIM, HAVE DIFF CONFIG PATHJS

  • THJE SPAWN TO SEETIGN THAT AFFECTS the oridinary odfrk and run does not necessarity affect the service based payload

From an OPSEC perspective, reason backward from what Windows and the blue team can observe. The relevant question is always: what telemetry does this execution path create?

Decision model connecting an operator command to the Windows mechanism and observable behavior it creates.
Fig. 38. Decision model connecting an operator command to the Windows mechanism and observable behavior it creates.

7. Blending post-exploitation behavior

here we will learnn how to blend post explootation techniquies that spawn new priocess in tot he surrounding environment

its good pratice to have your egresss(going otu data) ebacon to br running inside a process that c2 channel ebuign used!

for exampelsl, -=-- For example in HTTP beacon should run in a process that legitimately makes a bond HDB request It doesn't make sense to put it in a process that does DNS

you can see in the image below that we have attached an HTTP beacon into Microsoft Edge application

Cobalt Strike session table used while examining post-exploitation process context.
Fig. 39. Cobalt Strike session table used while examining post-exploitation process context.

This is how it will look like when we run commands or post exploitation commands in those in the legitimate process

you can see that it will be seen as a children of those process

Process view showing the multiple msedge.exe processes used as a parent-process example.
Fig. 40. Process view showing the multiple msedge.exe processes used as a parent-process example.

PPID and spawnto: two different process settings

Cobalt Strike documents ppid as the alternate parent process for certain programs run by Beacon. spawnto selects the executable used as a temporary process for post-exploitation jobs. The settings affect different parts of process creation:

Setting What it selects What it does not establish
ppid Parent relationship used for supported child processes A new user, privilege, authorization, or an invisible process
spawnto Executable image used for supported temporary jobs A believable parent relationship or the identity of a user

Use ps or the process browser to inspect the process list and obtain a PID when the course demonstration asks for one. The actual effect depends on the command and the installed Cobalt Strike version. Process ancestry, image, command line, token, memory behavior, and network activity remain separate evidence. The course describes the settings as a way to blend process activity; for exam preparation, treat them as observable behavior and apply the live OPSEC rules before any such change.

The screenshots show the parent-process setting, the process tree, and its relationship to fork-and-run:

System Informer process view used to examine candidate parent processes and their context.
Fig. 41. System Informer process view used to examine candidate parent processes and their context.
Beacon commands setting a spoofed parent PID before creating the example process.
Fig. 42. Beacon commands setting a spoofed parent PID before creating the example process.
Beacon output resetting the parent-process setting and inspecting the process-spawn context.
Fig. 43. Beacon output resetting the parent-process setting and inspecting the process-spawn context.

8. Command-line and process-creation detections

As we know from the beacon human behavior lesson we know that many of the commands work by running a new process

Some Beacon commands eventually ask Windows to create a process. The command name alone does not show every API or policy check involved.

The following course screenshots show process-creation attempts that returned Access denied. Record the command, current identity, target, and exact error; the error alone does not identify which policy or control denied the operation.

Pass-the-Hash example ending in access denied; credential values in the command and output are redacted.
Fig. 44. Pass-the-Hash example ending in access denied; credential values in the command and output are redacted.
Diagram expanding the Pass-the-Hash command into its underlying credential and process operations.
Fig. 45. Diagram expanding the Pass-the-Hash command into its underlying credential and process operations.

A second course example also returns Access denied through a different Cobalt Strike path. Treat it as a separate observation, not proof of the same underlying cause.

Its purpose is to elevate from medium integrity sessions to high integrity sessions

The visible result is Access denied; further evidence is needed to identify the denying layer.

Reading the kids aggressor script is a good place to understand what's happening under the field here

Fortunately the author has already given us what's actually happening in using the aggressor script

The accompanying script example shows one implementation detail; the error output alone does not identify which layer denied process creation.

Beacon task invoking the scheduled-task UAC technique in the course example.
Fig. 46. Beacon task invoking the scheduled-task UAC technique in the course example.
Process and mechanism diagram expanding the scheduled-task UAC technique beyond its short Beacon command.
Fig. 47. Process and mechanism diagram expanding the scheduled-task UAC technique beyond its short Beacon command.

Interpreting an Access denied result

Access denied does not, by itself, prove that Defender blocked the operation. It may come from Windows access checks, token or privilege limits, application policy, or a security product.

The result is not automatically evidence that Defender blocked the command. Windows and security products can observe process creation through kernel-supported callbacks and other telemetry. For example,

PsSetCreateProcessNotifyRoutineEx that allow drivers to register a callback routine when events of interest occur, such as a process being started.

PsSetCreateProcessNotifyRoutineEx registers a driver callback for process creation and exit notifications. The callback provides visibility; the API itself is not a general-purpose explanation for an Access denied result.

Are there bypasses for this? User-mode code should not assume it can remove or disable security-driver callbacks. Whether a process is allowed to run depends on privileges, policy, security products, and the operation being attempted. Kernel tampering is outside the scope of this note and is not required to understand the defensive lesson.

Do not respond to a denial by switching to a quieter-looking execution path. First identify the failed operation and denying control, then follow the live scope and OPSEC rules.

A Beacon-level error can originate in a lower Windows API or policy layer. Trace the failure to the operation that returned the error before drawing a conclusion.

Takeaway: reason about the underlying behavior and its observable events, not just the Beacon command label.

when a commander is located what are the different things that gets done after it What is observable

Decision diagram comparing alternative procedures and the distinct process evidence each may produce.
Fig. 48. Decision diagram comparing alternative procedures and the distinct process evidence each may produce.

From a defense perspective this means luckily one from monstrous does not necessarily eliminate the underlying capability

Also note that Access denied does not automatically mean “Defender detected it”; it can reflect insufficient privileges, an ACL, a token or session boundary, or a security-control decision. Identify the actual failing operation before drawing a conclusion.

9. Defense Evasion lab notes

Course-lab profile example The profile below changes Beacon staging, post-execution, and process-injection behavior. Those changes can create memory, process, pipe, script, and network telemetry, and their meaning depends on the installed Cobalt Strike version. Treat the block as a course example to understand, not as exam-ready settings. The exam's live rules override every lab profile; do not disable Defender or Windows Firewall.

The guided lab modifies a Cobalt Strike profile and separates settings by the behavior they control. The stage block describes selected Beacon-stage and memory-layout behavior.

Configuration map separating the main Beacon's stage settings from post-exploitation process settings.
Fig. 49. Configuration map separating the main Beacon's stage settings from post-exploitation process settings.

The three blocks below are distinct: stage, post-ex, and process-inject. Each changes a different part of the loading or execution path.

In the stage block, the lab example groups cleanup, header-copy, module, and content-transformation settings. These affect how the Beacon stage is prepared or represented in memory.

The exact effect and support for each setting depend on the Cobalt Strike version and selected artifact. Confirm the installed version's documentation before interpreting a profile. This block is not the same as the temporary-process settings in post-ex or the remote-memory behavior selected by process-inject.

stage { set userwx "false"; set cleanup "true"; set copy_pe_header "false"; set module_x64 "Hydrogen.dll";

transform-x64 {
    strrep "beacon.x64.dll" "bacon.x64.dll";
    strrep "%02d/%02d/%02d" "%02d/%02d/%04d";
    strrep "%s as %s\\\\%s: %d" "%s - %s\\\\%s: %d";
    strrep "%02d/%02d/%02d %02d:%02d:%02d" "%02d-%02d-%02d %02d:%02d:%02d";
    strrep "\\x48\\x89\\x5C\\x24\\x08\\x57\\x48\\x83\\xEC\\x20\\x48\\x8B\\x59\\x10\\x48\\x8B\\xF9\\x48\\x8B\\x49\\x08\\xFF\\x17\\x33\\xD2\\x41\\xB8\\x00\\x80\\x00\\x00" "\\x48\\x89\\x5C\\x24\\x08\\x57\\x48\\x83\\xEC\\x20\\x48\\x8B\\x59\\x10\\x48\\x8B\\xF9\\x48\\x8B\\x49\\x08\\xFF\\x17\\x33\\xD2\\x41\\xB8\\x01\\x80\\x00\\x00";
}

}

The post-ex block configures selected post-execution behavior for supported fork-and-run commands.

spawnto_x64 selects the temporary x64 process used by supported post-execution workflows; it does not mean every command runs inside that process.

Use the command's documented execution model to determine whether it uses the configured spawn-to process. post-ex { set spawnto_x64 "%windir%\\sysnative\\werfault.exe"; set cleanup "true"; set pipename "dotnet-diagnostic-#####, ########-####-####-####-############"; set thread_hint "ntdll.dll!RtlUserThreadStart+0x2c"; set amsi_disable "true";

transform-x64 {
    strrep "This program cannot be run in DOS mode." "This is totally not a PE.";
    strrepex "PowerPick" "CLRCreateInstance failed w/hr 0x%08lx" "CLRCreateInstance failed: 0x%08lx";
    strrepex "PowerPick" "Failed to get default AppDomain w/hr 0x%08lx" "Failed to get default AppDomain: 0x%08lx";
    strrepex "ExecuteAssembly" "Invoke_3 on EntryPoint failed." "Unhandled exception.";
    strrepex "ExecuteAssembly" "Failed to load the assembly w/hr 0x%08lx" "Failed to load the assembly: 0x%08lx";
}

}

In this lab profile, amsi_disable "true" is a version-specific Beacon setting that changes how selected post-exploitation content interacts with AMSI. It should not be described as a universal AMSI bypass: the setting may be unsupported, behave differently, or itself be relevant to detection depending on the Cobalt Strike version and endpoint.

Then we also added another process-inject block. What is this process-inject block for? This is the part that controls selected memory allocation and execution behavior for injected content and BOFs.

The of_allocator and of_reuse_memory settings relate to Beacon Object File memory handling in this profile. They are distinct from the remote-process allocator.

The process-inject block controls selected memory allocation and execution behavior for content injected into another process. BOFs execute inside Beacon and have separate allocation settings.

process-inject { set allocator "VirtualAllocEx"; set bof_allocator "VirtualAlloc"; set bof_reuse_memory "true"; set min_alloc "8192"; set startrwx "false"; set userwx "false";

execute {
    CreateThread "ntdll.dll!RtlUserThreadStart+0x2c";
    NtQueueApcThread-s;
    NtQueueApcThread;
    SetThreadContext;
}

}

I have a feeling that doing the labs and the I mean doing the theory it's not as connected as I would like I don't actually have to do evasion itself or creating doing the research for how to bypass they're just literally giving me the answers it's like spoon feeding so the labs are French is a good way to to get a feeling of how it is but instead in terms of actual execution in live operations is not ideal yet

it's good for navigating Cobalt shark

I'm doing the labs now and I can see why eventually if I wanna when I want to start testing these things I need to have my own home lab

With this lab we were able to create artifact kits resource kits and eventually use that as a payload that can then be run and then eventually we were able to use command to do later lateral movement with the jump command

the exact commands that were used you can looked at the lab again for that

9.1 What the profile blocks control

The profile was added because the lab examined several separate detection surfaces. The blocks configure different parts of Beacon's execution path; they are not one general-purpose “MZ bypass.” They can also interact, so changing all of them together makes it difficult to tell which change affected a particular alert.

flowchart TD A[Artifact Kit EXE or DLL] --> F[File and static inspection] B[Resource Kit script] --> F C[Beacon stage] --> S[stage: Beacon image and reflective loading in memory] S --> P[process-inject: allocation and execution path] P --> X[post-ex: post-ex DLL and temporary-process behavior] F --> D[Defender and EDR observations] S --> D P --> D X --> D
Diagram source
flowchart TD
    A[Artifact Kit EXE or DLL] --> F[File and static inspection]
    B[Resource Kit script] --> F
    C[Beacon stage] --> S[stage: Beacon image and reflective loading in memory]
    S --> P[process-inject: allocation and execution path]
    P --> X[post-ex: post-ex DLL and temporary-process behavior]
    F --> D[Defender and EDR observations]
    S --> D
    P --> D
    X --> D
Profile area What it configures Why it appeared in this lab Defensive evidence to review
stage Beacon's reflective stage, its in-memory representation, and loader characteristics. The exercise customized the Beacon stage's in-memory representation and loading behavior. Memory regions, page permissions, image/header consistency, loaded modules, and the timing of loader activity.
post-ex Content and behavior of Beacon's post-exploitation features, including temporary-process, output-pipe, cleanup, and some thread/AMSI-related behavior. Some features run in a temporary process and return results to Beacon; this block describes those jobs. Process ancestry, image loads, named-pipe activity, thread start information, AMSI events, and the specific feature that ran.
process-inject How Beacon allocates and executes injected content; it also affects memory used to run BOFs inside Beacon. It governs the injection mechanics used by applicable post-exploitation jobs and other injection actions. Cross-process memory operations, protection changes, thread creation or context changes, source/target process relationship, and BOF execution telemetry.

These descriptions are version-sensitive; check the documentation for the installed Cobalt Strike release. In particular, copy_pe_header concerns whether Beacon's reflective loader copies Beacon's PE headers into its destination memory. That is an in-memory property: it does not remove the PE header from the on-disk artifact and is not a universal MZ or AMSI bypass. The module_x64 option selects a module-backed loading path for the x64 Beacon; the exact behavior and compatibility depend on the release and target process.

The blocks can overlap in a job: post-ex can describe the temporary job and its content, while process-inject describes how that content is placed and started. Editing the profile on disk alone does not change a running Team Server; the Team Server loads its profile at startup. Changing a profile can also make already-deployed Beacons incompatible with the server's current communication configuration.

Keep the three spawn-path controls separate: the lab's ak-settings helper changes an Artifact Kit service artifact setting; the profile's post-ex spawn setting applies to supported post-exploitation jobs; Beacon's runtime spawnto setting applies to supported jobs as well. They are different controls and do not affect every Beacon command. If a later service action fails, identify the failing stage and its event evidence before attributing it to the earlier Resource Kit or script-delivery path.

9.2 Defensive lab record

For a defender-focused rerun, keep a baseline and record where each observation occurred. Do not treat “no alert” as proof that a change is safe or invisible.

  1. Record the lab scope, Cobalt Strike and Defender versions, host identity, policy state, test artifact hash, and timestamp.
  2. Classify the observation: file/reputation, static content, script or AMSI, memory, process, image/module load, network, or correlated behavior.
  3. Preserve the alert or event details, process tree, relevant image and memory events, and the exact tested input. Note whether the product blocked, quarantined, alerted, or allowed it.
  4. Separate file scanning from execution telemetry. A clean result for one file scanner applies only to that file, scanner configuration, and time.
  5. Report the detection and evidence to the lab owner. Keep the outcome as a detection finding; do not use repeated edits to turn the result into a “no detection” recipe.

This chapter records the conceptual flow and defensive observations from the lab. It is not a deployment runbook for modifying artifacts or scripts to defeat Defender, generating or launching a Beacon, or performing credential use and lateral movement.

This is a living study note. Sources and understanding may change as it is reviewed.

Ryan Sacatani

Simply curious about the world, constantly building and breaking things for fun.

sacataniryan1@gmail.com ↗

BrowseBrowse topics

Browse