Repository: paradoxwastaken/Poseidon
Branch: main
Commit: 0e08674b01d6
Files: 21
Total size: 65.7 KB
Directory structure:
gitextract__tzj7agv/
├── .gitignore
├── Poseidon/
│ ├── Poseidon.sln
│ ├── Poseidon.vcxproj
│ ├── Poseidon.vcxproj.filters
│ ├── global.h
│ ├── main.cpp
│ ├── memory.h
│ ├── process.h
│ ├── sdk.h
│ ├── sharedmemory.h
│ ├── system.h
│ └── utils.h
├── PoseidonClient/
│ ├── PoseidonClient.vcxproj
│ ├── PoseidonClient.vcxproj.filters
│ ├── global.h
│ ├── main.cpp
│ ├── memory.h
│ ├── process.h
│ ├── sdk.h
│ └── sharedmemory.h
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Created by https://www.toptal.com/developers/gitignore/api/visualstudio
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio
### VisualStudio ###
## 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/
[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*.[ji][sn][of][no]
coverage*.xml
# 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
### VisualStudio Patch ###
# Additional files built by Visual Studio
*.tlog
# End of https://www.toptal.com/developers/gitignore/api/visualstudio
================================================
FILE: Poseidon/Poseidon.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30711.63
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Poseidon", "Poseidon.vcxproj", "{A941F3A1-C164-4A34-94B4-9577B7CD5FE2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PoseidonClient", "..\PoseidonClient\PoseidonClient.vcxproj", "{46A9D08D-4962-4434-BC75-C60339512252}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A941F3A1-C164-4A34-94B4-9577B7CD5FE2}.Debug|x64.ActiveCfg = Debug|x64
{A941F3A1-C164-4A34-94B4-9577B7CD5FE2}.Debug|x64.Build.0 = Debug|x64
{A941F3A1-C164-4A34-94B4-9577B7CD5FE2}.Debug|x64.Deploy.0 = Debug|x64
{A941F3A1-C164-4A34-94B4-9577B7CD5FE2}.Release|x64.ActiveCfg = Release|x64
{A941F3A1-C164-4A34-94B4-9577B7CD5FE2}.Release|x64.Build.0 = Release|x64
{A941F3A1-C164-4A34-94B4-9577B7CD5FE2}.Release|x64.Deploy.0 = Release|x64
{46A9D08D-4962-4434-BC75-C60339512252}.Debug|x64.ActiveCfg = Debug|x64
{46A9D08D-4962-4434-BC75-C60339512252}.Debug|x64.Build.0 = Debug|x64
{46A9D08D-4962-4434-BC75-C60339512252}.Release|x64.ActiveCfg = Release|x64
{46A9D08D-4962-4434-BC75-C60339512252}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A7CE4DCC-6D4C-4C0F-A15F-3D65EBEA3C6F}
EndGlobalSection
EndGlobal
================================================
FILE: Poseidon/Poseidon.vcxproj
================================================
Debug
x64
Release
x64
{A941F3A1-C164-4A34-94B4-9577B7CD5FE2}
{1bc93793-694f-48fe-9372-81e2b05556fd}
v4.5
12.0
Debug
Win32
Poseidon
$(LatestTargetPlatformVersion)
Windows10
true
WindowsKernelModeDriver10.0
Driver
KMDF
Universal
Windows10
false
WindowsKernelModeDriver10.0
Driver
KMDF
Universal
false
DbgengKernelDebugger
driver
DbgengKernelDebugger
false
driver
stdcpp17
false
false
false
DriverEntry
false
false
stdcpp17
================================================
FILE: Poseidon/Poseidon.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hpp;hxx;hm;inl;inc;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
{8E41214B-6785-4CFE-B992-037D68949A14}
inf;inv;inx;mof;mc;
{877b8484-960c-4f48-978f-d985dc5a098a}
Source Files
Header Files\sdk
Header Files\sdk
Header Files\sdk
Header Files\sdk
Header Files\sdk
Header Files\sdk
Header Files
================================================
FILE: Poseidon/global.h
================================================
#pragma once
#include
#include
#include
#include
enum Code {
Complete,
BaseRequest,
SizeRequest,
PebRequest,
QIPRequest,
CopyRequest,
AVMRequest,
FVMRequest,
PVMRequest,
QVMRequest,
ModuleRequest,
IndexRequest,
};
enum Status {
Inactive, // We'll use this status to let the driver know it can sleep for a while
Active, // We'll use this status to let the driver know we may be sending requests any second
Waiting, // We'll use this status to let the driver know we sent a request and are waiting for completion
Exit // We'll use this status to let the driver know it can exit the shared memory loop and untrap our thread
};
typedef struct OperationData {
struct {
char* Name;
DWORD Id;
PVOID BaseAddress;
SIZE_T Size;
PPEB Peb;
PROCESS_BASIC_INFORMATION PBI;
} Process;
struct {
SIZE_T Size;
SIZE_T ReturnLength;
struct {
PVOID Address;
PVOID Buffer;
BOOLEAN ReadOperation;
} Copy;
PVOID Base;
DWORD AllocType;
DWORD FreeType;
DWORD Protect;
DWORD OldProtect;
MEMORY_BASIC_INFORMATION MBI;
} Memory;
struct {
PVOID BaseAddress;
SIZE_T SizeOfImage;
int Index;
} Module;
};
typedef struct CommunicationData {
DWORD ProcessId;
PVOID SharedMemory;
DWORD* pCode;
SHORT* pStatus;
DWORD Magic;
};
INT64(NTAPI *EnumerateDebuggingDevicesOriginal)(PVOID, PVOID);
CommunicationData gData{};
PEPROCESS gProcess{};
DWORD64 gFunc{};
CHAR* gKernelBase{};
DWORD ActiveThreadsOffset{ 0x5F0 };
typedef enum _SYSTEM_INFORMATION_CLASS
{
SystemBasicInformation,
SystemProcessorInformation,
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemPathInformation,
SystemProcessInformation,
SystemCallCountInformation,
SystemDeviceInformation,
SystemProcessorPerformanceInformation,
SystemFlagsInformation,
SystemCallTimeInformation,
SystemModuleInformation,
SystemLocksInformation,
SystemStackTraceInformation,
SystemPagedPoolInformation,
SystemNonPagedPoolInformation,
SystemHandleInformation,
SystemObjectInformation,
SystemPageFileInformation,
SystemVdmInstemulInformation,
SystemVdmBopInformation,
SystemFileCacheInformation,
SystemPoolTagInformation,
SystemInterruptInformation,
SystemDpcBehaviorInformation,
SystemFullMemoryInformation,
SystemLoadGdiDriverInformation,
SystemUnloadGdiDriverInformation,
SystemTimeAdjustmentInformation,
SystemSummaryMemoryInformation,
SystemNextEventIdInformation,
SystemEventIdsInformation,
SystemCrashDumpInformation,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemExtendServiceTableInformation,
SystemPrioritySeperation,
SystemPlugPlayBusInformation,
SystemDockInformation,
SystemProcessorSpeedInformation,
SystemCurrentTimeZoneInformation,
SystemLookasideInformation
} SYSTEM_INFORMATION_CLASS, * PSYSTEM_INFORMATION_CLASS;
typedef struct _PEB_LDR_DATA
{
ULONG Length;
UCHAR Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
LIST_ENTRY HashLinks;
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB
{
UCHAR InheritedAddressSpace;
UCHAR ReadImageFileExecOptions;
UCHAR BeingDebugged;
UCHAR BitField;
PVOID Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PVOID ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PVOID FastPebLock;
PVOID AtlThunkSListPtr;
PVOID IFEOKey;
PVOID CrossProcessFlags;
PVOID KernelCallbackTable;
ULONG SystemReserved;
ULONG AtlThunkSListPtr32;
PVOID ApiSetMap;
} PEB, * PPEB;
typedef struct _SYSTEM_MODULE
{
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[MAXIMUM_FILENAME_LENGTH];
} SYSTEM_MODULE, *PSYSTEM_MODULE;
typedef struct _SYSTEM_MODULE_INFORMATION
{
ULONG NumberOfModules;
SYSTEM_MODULE Modules[1];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULE_INFORMATION
{
HANDLE Section;
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[MAXIMUM_FILENAME_LENGTH];
} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
typedef struct _RTL_PROCESS_MODULES
{
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
typedef struct PiDDBCache
{
LIST_ENTRY List;
UNICODE_STRING DriverName;
ULONG TimeDateStamp;
NTSTATUS LoadStatus;
char _0x0028[16];
};
extern "C"
{
NTKERNELAPI
PVOID
PsGetProcessSectionBaseAddress(
PEPROCESS Process
);
NTKERNELAPI
PPEB
NTAPI
PsGetProcessPeb(
PEPROCESS Process
);
NTKERNELAPI
NTSTATUS
MmCopyVirtualMemory(
PEPROCESS SourceProcess,
PVOID SourceAddress,
PEPROCESS TarGet,
PVOID TargetAddress,
SIZE_T BufferSize,
KPROCESSOR_MODE PreviousMode,
PSIZE_T ReturnSize
);
NTSYSCALLAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation(
ULONG InfoClass,
PVOID Buffer,
ULONG Length,
PULONG ReturnLength
);
NTSYSCALLAPI
NTSTATUS
ZwQueryInformationProcess(
HANDLE ProcessHandle,
PROCESSINFOCLASS ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
NTSYSCALLAPI
NTSTATUS
NTAPI
ZwProtectVirtualMemory(
HANDLE ProcessHandle,
PVOID *BaseAddress,
PSIZE_T RegionSize,
ULONG NewAccessProtection,
PULONG OldAccessProtection
);
}
================================================
FILE: Poseidon/main.cpp
================================================
#include "sdk.h"
NTSTATUS DriverEntry(DRIVER_OBJECT* DriverObject, UNICODE_STRING* RegistryPath) {
return Driver::Initialize();
}
================================================
FILE: Poseidon/memory.h
================================================
#pragma once
#include "process.h"
namespace Memory {
template
T Allocate(SIZE_T Size) {
return reinterpret_cast(ExAllocatePool(NonPagedPool, Size));
}
VOID Free(PVOID Buffer) {
ExFreePool(Buffer);
}
BOOLEAN Copy(PVOID Destination, PVOID Source, SIZE_T Size) {
SIZE_T BytesRead{ 0 };
return NT_SUCCESS(MmCopyVirtualMemory(IoGetCurrentProcess(),
Source,
IoGetCurrentProcess(),
Destination,
Size,
KernelMode,
&BytesRead)) && BytesRead == Size;
}
NTSTATUS CopyVirtualMemory(OperationData* Data) {
NTSTATUS Status{ STATUS_SUCCESS };
PEPROCESS eProcess{ Process::GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
if (Data->Memory.Copy.ReadOperation) {
Status = MmCopyVirtualMemory(eProcess,
Data->Memory.Copy.Address,
IoGetCurrentProcess(),
Data->Memory.Copy.Buffer,
Data->Memory.Size,
UserMode,
&Data->Memory.ReturnLength);
} else {
Status = MmCopyVirtualMemory(IoGetCurrentProcess(),
Data->Memory.Copy.Buffer,
eProcess,
Data->Memory.Copy.Address,
Data->Memory.Size,
UserMode,
&Data->Memory.ReturnLength);
}
ObfDereferenceObject(eProcess);
return Status;
}
NTSTATUS AllocateVirtualMemory(OperationData* Data) {
KAPC_STATE Apc{ NULL };
PEPROCESS eProcess{ Process::GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
KeStackAttachProcess(eProcess, &Apc);
NTSTATUS Status{ ZwAllocateVirtualMemory(ZwCurrentProcess(),
&Data->Memory.Base,
NULL,
&Data->Memory.Size,
Data->Memory.AllocType,
Data->Memory.Protect) };
KeUnstackDetachProcess(&Apc);
ObfDereferenceObject(eProcess);
return Status;
}
NTSTATUS FreeVirtualMemory(OperationData* Data) {
KAPC_STATE Apc{ NULL };
PEPROCESS eProcess{ Process::GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
KeStackAttachProcess(eProcess, &Apc);
NTSTATUS Status{ ZwFreeVirtualMemory(ZwCurrentProcess(),
&Data->Memory.Base,
&Data->Memory.Size,
Data->Memory.FreeType) };
KeUnstackDetachProcess(&Apc);
ObfDereferenceObject(eProcess);
return Status;
}
NTSTATUS ProtectVirtualMemory(OperationData* Data) {
KAPC_STATE Apc{ NULL };
PEPROCESS eProcess{ Process::GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
KeStackAttachProcess(eProcess, &Apc);
NTSTATUS Status{ ZwProtectVirtualMemory(ZwCurrentProcess(),
&Data->Memory.Base,
&Data->Memory.Size,
Data->Memory.Protect,
&Data->Memory.OldProtect) };
KeUnstackDetachProcess(&Apc);
ObfDereferenceObject(eProcess);
return Status;
}
NTSTATUS QueryVirtualMemory(OperationData* Data) {
NTSTATUS Status{ STATUS_SUCCESS };
KAPC_STATE Apc{ 0 };
PEPROCESS eProcess{ Process::GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
KeStackAttachProcess(eProcess, &Apc);
Status = ZwQueryVirtualMemory(ZwCurrentProcess(),
Data->Memory.Base,
MemoryBasicInformation,
&Data->Memory.MBI,
sizeof(Data->Memory.MBI),
&Data->Memory.ReturnLength);
KeUnstackDetachProcess(&Apc);
ObfDereferenceObject(eProcess);
return Status;
}
}
================================================
FILE: Poseidon/process.h
================================================
#pragma once
#include "global.h"
namespace Process {
PEPROCESS GetProcess(DWORD ProcessId) {
PEPROCESS eProcess{ nullptr };
PsLookupProcessByProcessId(reinterpret_cast(ProcessId), &eProcess);
return eProcess;
}
NTSTATUS GetBaseAddress(OperationData* Data) {
PEPROCESS eProcess{ GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
Data->Process.BaseAddress = PsGetProcessSectionBaseAddress(eProcess);
ObfDereferenceObject(eProcess);
return Data->Process.BaseAddress ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
NTSTATUS GetMainModuleSize(OperationData* Data) {
KAPC_STATE Apc{ 0 };
DWORD Size{ NULL };
PEPROCESS eProcess{ GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
KeStackAttachProcess(eProcess, &Apc);
if (LIST_ENTRY* ModuleEntry{ PsGetProcessPeb(eProcess)->Ldr->InLoadOrderModuleList.Flink }) {
Data->Process.Size = CONTAINING_RECORD(ModuleEntry,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks)->SizeOfImage;
}
KeUnstackDetachProcess(&Apc);
ObfDereferenceObject(eProcess);
return Data->Process.Size ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
NTSTATUS GetPeb(OperationData* Data) {
PEPROCESS eProcess{ GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
Data->Process.Peb = PsGetProcessPeb(eProcess);
ObfDereferenceObject(eProcess);
return Data->Process.Peb ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
NTSTATUS QueryInformation(OperationData* Data) {
KAPC_STATE Apc{ 0 };
PEPROCESS eProcess{ GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
KeStackAttachProcess(eProcess, &Apc);
NTSTATUS Status{ ZwQueryInformationProcess(ZwCurrentProcess(),
ProcessBasicInformation,
&Data->Process.PBI,
sizeof(Data->Process.PBI),
nullptr) };
KeUnstackDetachProcess(&Apc);
ObfDereferenceObject(eProcess);
return Status;
}
NTSTATUS GetModuleInfo(OperationData* Data) {
KAPC_STATE Apc{ 0 };
PVOID Base{ nullptr };
DWORD Size{ NULL};
UNICODE_STRING usModule{ 0 };
if (Data->Process.Name) {
ANSI_STRING asModule{ 0 };
RtlInitAnsiString(&asModule, Data->Process.Name);
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&usModule, &asModule, TRUE))) {
return STATUS_UNSUCCESSFUL;
}
}
PEPROCESS eProcess{ GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
KeStackAttachProcess(eProcess, &Apc);
LIST_ENTRY* List = &(PsGetProcessPeb(eProcess)->Ldr->InLoadOrderModuleList);
for (LIST_ENTRY* Entry = List->Flink; Entry != List;) {
auto Module{ CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks) };
if (Module) {
++Data->Module.Index;
if (Data->Process.Name && !RtlCompareUnicodeString(&Module->BaseDllName, &usModule, TRUE)) {
Data->Module.BaseAddress = Module->DllBase;
Data->Module.SizeOfImage = Module->SizeOfImage;
}
}
Entry = Module->InLoadOrderLinks.Flink;
}
KeUnstackDetachProcess(&Apc);
RtlFreeUnicodeString(&usModule);
ObfDereferenceObject(eProcess);
return Data->Module.SizeOfImage ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
}
NTSTATUS GetModuleInfoByIndex(OperationData* Data) {
KAPC_STATE Apc{ 0 };
int Count{ 0 };
PEPROCESS eProcess{ GetProcess(Data->Process.Id) };
if (eProcess == nullptr) {
return STATUS_UNSUCCESSFUL;
}
KeStackAttachProcess(eProcess, &Apc);
LIST_ENTRY* List = &(PsGetProcessPeb(eProcess)->Ldr->InLoadOrderModuleList);
for (LIST_ENTRY* Entry = List->Flink; Entry != List;) {
auto Module{ CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks) };
if (Module && Count == Data->Module.Index) {
Data->Module.BaseAddress = Module->DllBase;
Data->Module.SizeOfImage = Module->SizeOfImage;
break;
}
Count += 1;
Entry = Module->InLoadOrderLinks.Flink;
}
KeUnstackDetachProcess(&Apc);
ObfDereferenceObject(eProcess);
return STATUS_SUCCESS;
}
}
================================================
FILE: Poseidon/sdk.h
================================================
#pragma once
#include "sharedmemory.h"
#define RVA(addr, size) (BYTE*)addr + *(INT*)((BYTE*)addr + ((size) - 4)) + size
namespace Driver {
INT64 NTAPI EnumerateDebuggingDevicesHook(PVOID A1, PINT64 A2) {
if (ExGetPreviousMode() != UserMode
|| A1 == nullptr
|| !Utils::ProbeUserAddress(A1, sizeof(gData), sizeof(DWORD))
|| !Memory::Copy(&gData, A1, sizeof(CommunicationData))
|| gData.Magic != 0x999) {
// NtConvertBetweenAuxiliaryCounterAndPerformanceCounter() was not called by our usermode client
// Call the original EnumerateDebuggingDevices() for whoever called
return EnumerateDebuggingDevicesOriginal(A1, A2);
}
// NtConvertBetweenAuxiliaryCounterAndPerformanceCounter() was called by the usermode client
// We're only able to execute code right now because the usermode thread within the client transitioned into the kernel to complete the system call
// We can take advantage of this and execute code in our driver for as long as we want by simply never returning
InterlockedExchangePointer((PVOID*)gFunc, (PVOID)EnumerateDebuggingDevicesOriginal); // Unhook EnumerateDebuggingDevices() - it can be detected easily
SharedMemory::Loop();
}
NTSTATUS Initialize() {
auto OSInfo{ System::GetOSVersion() };
if (OSInfo.dwBuildNumber < 19041) {
ActiveThreadsOffset = OSInfo.dwBuildNumber == 10240 ? 0x490 : 0x498;
}
if (gKernelBase = System::GetModuleInfo("ntoskrnl.exe")) {
if (auto Func = Utils::FindPatternImage(gKernelBase,
"\x48\x8B\x05\x00\x00\x00\x00\x75\x07\x48\x8B\x05\x00\x00\x00\x00\xE8\x00\x00\x00\x00",
"xxx????xxxxx????x????")) {
gFunc = (DWORD64)(Func = RVA(Func, 7));
*(PVOID*)&EnumerateDebuggingDevicesOriginal = InterlockedExchangePointer((PVOID*)Func, (PVOID)EnumerateDebuggingDevicesHook); // Hook EnumerateDebuggingDevices()
return STATUS_SUCCESS;
}
}
return STATUS_UNSUCCESSFUL;
}
}
================================================
FILE: Poseidon/sharedmemory.h
================================================
#pragma once
#include "memory.h"
#include "system.h"
namespace SharedMemory {
BOOLEAN ReadSharedMemory(PVOID Address, PVOID Buffer, SIZE_T Size) {
SIZE_T Bytes{ 0 };
if (NT_SUCCESS(MmCopyVirtualMemory(gProcess, Address, IoGetCurrentProcess(), Buffer, Size, KernelMode, &Bytes))) {
return TRUE;
} return FALSE;
}
template
BOOLEAN WriteSharedMemory(PVOID Address, T Buffer, SIZE_T Size = sizeof(T)) {
SIZE_T Bytes{ 0 };
if (NT_SUCCESS(MmCopyVirtualMemory(IoGetCurrentProcess(), (PVOID)&Buffer, gProcess, Address, Size, KernelMode, &Bytes))) {
return TRUE;
} return FALSE;
}
BYTE GetStatus() {
BYTE CurStatus{ 0 };
ReadSharedMemory(gData.pStatus, &CurStatus, sizeof(SHORT));
return CurStatus;
}
DWORD GetCode() {
DWORD CurCode{ 0 };
ReadSharedMemory(gData.pCode, &CurCode, sizeof(DWORD));
return CurCode;
}
OperationData GetBuffer() {
OperationData CurBuffer{ 0 };
ReadSharedMemory(gData.SharedMemory, &CurBuffer, sizeof(OperationData));
return CurBuffer;
}
BOOLEAN SetStatus(Status DesiredStatus) {
return WriteSharedMemory(gData.pStatus, DesiredStatus);
}
BOOLEAN SetCode() {
return WriteSharedMemory(gData.pCode, Complete);
}
BOOLEAN SetBuffer(OperationData Buffer) {
return WriteSharedMemory(gData.SharedMemory, Buffer);
}
VOID Respond() {
DWORD Code{ GetCode() };
OperationData Params{ GetBuffer() };
switch (Code) {
case BaseRequest: {
Process::GetBaseAddress(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case SizeRequest: {
Process::GetMainModuleSize(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case PebRequest: {
Process::GetPeb(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case QIPRequest: {
Process::QueryInformation(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case CopyRequest: {
Memory::CopyVirtualMemory(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case AVMRequest: {
Memory::AllocateVirtualMemory(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case FVMRequest: {
Memory::FreeVirtualMemory(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case PVMRequest: {
Memory::ProtectVirtualMemory(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case QVMRequest: {
Memory::QueryVirtualMemory(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case ModuleRequest: {
Process::GetModuleInfo(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
case IndexRequest: {
Process::GetModuleInfoByIndex(&Params);
SetBuffer(Params);
SetCode();
SetStatus(Active);
} break;
default: {
} break;
}
}
VOID Loop() {
gProcess = Process::GetProcess(gData.ProcessId);
if (gProcess == nullptr) {
return;
}
for (;;) {
if (*(DWORD*)((BYTE*)gProcess + ActiveThreadsOffset) == 1) {
// We're the only active thread - the client must be trying to terminate
ObfDereferenceObject(gProcess);
return;
}
DWORD Status{ GetStatus() };
switch (Status) {
case Inactive: {
Utils::Sleep(50);
} break;
case Active: {
Utils::Sleep(1);
} break;
case Waiting: {
Respond();
} break;
case Exit: {
SetStatus(Inactive);
ObfDereferenceObject(gProcess);
return;
} break;
default: {
Utils::Sleep(50);
} break;
}
}
}
}
================================================
FILE: Poseidon/system.h
================================================
#pragma once
#include "global.h"
#include "utils.h"
namespace System {
template
T GetModuleInfo(const char* Name, DWORD* OutSize = nullptr) {
PVOID Base{ nullptr };
DWORD RequiredSize{ 0 };
if (ZwQuerySystemInformation(SystemModuleInformation,
nullptr,
NULL,
&RequiredSize) != STATUS_INFO_LENGTH_MISMATCH) {
return reinterpret_cast(nullptr);
}
auto Modules{ Memory::Allocate(RequiredSize) };
if (!Modules) {
return reinterpret_cast(nullptr);
}
if (!NT_SUCCESS(ZwQuerySystemInformation(SystemModuleInformation,
Modules,
RequiredSize,
nullptr))) {
Memory::Free(Modules);
return reinterpret_cast(nullptr);
}
for (DWORD i = 0; i < Modules->NumberOfModules; ++i) {
SYSTEM_MODULE CurModule{ Modules->Modules[i] };
if (strstr(Utils::LowerStr((CHAR*)CurModule.FullPathName), Name))
{
Base = CurModule.ImageBase;
if (OutSize) {
*OutSize = CurModule.ImageSize;
}
break;
}
}
Memory::Free(Modules);
return reinterpret_cast(Base);
}
OSVERSIONINFOW GetOSVersion() {
OSVERSIONINFOW OSInfo{ 0 };
RtlGetVersion(&OSInfo);
return OSInfo;
}
}
================================================
FILE: Poseidon/utils.h
================================================
#pragma once
#include "global.h"
namespace Utils {
VOID Sleep(INT ms) {
LARGE_INTEGER li{ 0 };
li.QuadPart = -10000;
for (INT i{ 0 }; i < ms; i++) {
KeDelayExecutionThread(KernelMode, FALSE, &li);
}
}
BOOLEAN ProbeUserAddress(PVOID Address, SIZE_T Size, DWORD Alignment) {
if (Size == 0) {
return TRUE;
}
DWORD64 Current = (DWORD64)Address;
if (((DWORD64)Address & (Alignment - 1)) != 0) {
return FALSE;
}
DWORD64 Last{ Current + Size - 1 };
if ((Last < Current) || (Last >= MmUserProbeAddress)) {
return FALSE;
}
return TRUE;
}
CHAR* LowerStr(CHAR* Str) {
for (CHAR* S = Str; *S; ++S) {
*S = (CHAR)tolower(*S);
}
return Str;
}
BOOLEAN CheckMask(CHAR* Base, CHAR* Pattern, CHAR* Mask) {
for (; *Mask; ++Base, ++Pattern, ++Mask) {
if (*Mask == 'x' && *Base != *Pattern) {
return FALSE;
}
}
return TRUE;
}
PVOID FindPattern(CHAR* Base, DWORD Length, CHAR* Pattern, CHAR* Mask) {
Length -= (DWORD)strlen(Mask);
for (DWORD i = 0; i <= Length; ++i) {
PVOID Addr{ &Base[i] };
if (CheckMask(static_cast(Addr), Pattern, Mask)) {
return Addr;
}
}
return 0;
}
PVOID FindPatternImage(CHAR* Base, CHAR* Pattern, CHAR* Mask) {
PVOID Match{ 0 };
IMAGE_NT_HEADERS* Headers{ (PIMAGE_NT_HEADERS)(Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew) };
IMAGE_SECTION_HEADER* Sections{ IMAGE_FIRST_SECTION(Headers) };
for (DWORD i = 0; i < Headers->FileHeader.NumberOfSections; ++i) {
IMAGE_SECTION_HEADER* Section{ &Sections[i] };
if (*(INT*)Section->Name == 'EGAP' || memcmp(Section->Name, ".text", 5) == 0) {
Match = FindPattern(Base + Section->VirtualAddress, Section->Misc.VirtualSize, Pattern, Mask);
if (Match) {
break;
}
}
}
return Match;
}
}
================================================
FILE: PoseidonClient/PoseidonClient.vcxproj
================================================
Debug
Win32
Release
Win32
Debug
x64
Release
x64
16.0
Win32Proj
{46a9d08d-4962-4434-bc75-c60339512252}
PoseidonClient
10.0
Application
true
v142
Unicode
Application
false
v142
true
Unicode
Application
true
v142
Unicode
Application
false
v142
true
Unicode
true
Client
false
Client
true
Client
false
Client
Level3
true
WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
stdcpp17
Console
true
Level3
true
true
true
WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
stdcpp17
Console
true
true
true
Level3
true
_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
stdcpp17
Console
true
Level3
true
true
true
NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
true
stdcpp17
Console
true
true
true
================================================
FILE: PoseidonClient/PoseidonClient.vcxproj.filters
================================================
{4FC737F1-C7A5-4376-A066-2A32D752A2FF}
cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
{93995380-89BD-4b04-88EB-625FBE52EBFB}
h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
{a1d20eea-b682-43a7-8ec6-07bcaa3f318a}
Source Files
Header Files
Header Files\sdk
Header Files\sdk
Header Files\sdk
Header Files\sdk
================================================
FILE: PoseidonClient/global.h
================================================
#pragma once
#include
#include
#include
#include
#include
PVOID(NTAPI *NtConvertBetweenAuxiliaryCounterAndPerformanceCounter)(PVOID, PVOID, PVOID, PVOID);
enum Code {
Complete,
BaseRequest,
SizeRequest,
PebRequest,
QIPRequest,
CopyRequest,
AVMRequest,
FVMRequest,
PVMRequest,
QVMRequest,
ModuleRequest,
IndexRequest,
};
enum Status {
Inactive,
Active,
Waiting,
Exit
};
typedef struct OperationData {
struct {
char* Name;
DWORD Id;
PVOID BaseAddress;
SIZE_T Size;
PPEB Peb;
PROCESS_BASIC_INFORMATION PBI;
} Process;
struct {
SIZE_T Size;
SIZE_T ReturnLength;
struct {
PVOID Address;
PVOID Buffer;
BOOLEAN ReadOperation;
} Copy;
PVOID Base;
DWORD AllocType;
DWORD FreeType;
DWORD Protect;
DWORD OldProtect;
MEMORY_BASIC_INFORMATION MBI;
} Memory;
struct {
PVOID BaseAddress;
SIZE_T SizeOfImage;
int Index;
} Module;
};
typedef struct CommunicationData {
DWORD ProcessId;
PVOID SharedMemory;
DWORD* pCode;
SHORT* pStatus;
DWORD Magic;
};
typedef struct MODULE {
PVOID BaseAddress;
DWORD SizeOfImage;
};
================================================
FILE: PoseidonClient/main.cpp
================================================
#include "sdk.h"
#include
int main() {
Client::Connect();
// Manually calling the functions in process.h and memory.h
DWORD ProcessId{ Process::GetProcessId(L"notepad.exe") };
PVOID BaseAddress{ Process::GetBase(ProcessId) };
int ExampleValue{ Memory::Read(ProcessId, BaseAddress) };
std::cout << "0x" << std::hex << BaseAddress << std::endl;
std::cout << std::dec << ExampleValue << std::endl;
getchar();
// Or using a KProcess object
auto Notepad{ KProcess(L"notepad.exe") };
int ExampleValue2{ Notepad.Read(Notepad.BaseAddress) };
std::cout << "0x" << std::hex << Notepad.BaseAddress << std::endl;
std::cout << std::dec << ExampleValue2 << std::endl;
getchar();
Client::Disconnect(); // Once this is called or usermode closed / crashed, we can never reobtain a connection to the driver without remapping it
}
================================================
FILE: PoseidonClient/memory.h
================================================
#pragma once
#include "process.h"
namespace Memory {
bool Read(DWORD ProcessId, PVOID Address, PVOID Buffer, SIZE_T Size) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
Data.Memory.Copy.Address = Address;
Data.Memory.Copy.Buffer = Buffer;
Data.Memory.Size = Size;
Data.Memory.Copy.ReadOperation = true;
return SharedMemory::SendRequest(CopyRequest, Data);
}
template
T Read(DWORD ProcessId, PVOID Address, SIZE_T Size = sizeof(T)) {
T Buffer{};
Read(ProcessId, Address, static_cast(&Buffer), Size);
return Buffer;
}
bool Write(DWORD ProcessId, PVOID Address, PVOID Buffer, SIZE_T Size) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
Data.Memory.Copy.Address = Address;
Data.Memory.Copy.Buffer = Buffer;
Data.Memory.Size = Size;
Data.Memory.Copy.ReadOperation = false;
return SharedMemory::SendRequest(CopyRequest, Data);
}
template
bool Write(DWORD ProcessId, PVOID Address, T Value, SIZE_T Size = sizeof(T)) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
Data.Memory.Copy.Address = Address;
Data.Memory.Copy.Buffer = &Value;
Data.Memory.Size = Size;
Data.Memory.Copy.ReadOperation = false;
return SharedMemory::SendRequest(CopyRequest, Data);
}
PVOID AllocateVirtualMemory(DWORD ProcessId, PVOID Base, SIZE_T Size, DWORD AllocType, DWORD Protect) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
Data.Memory.Base = Base;
Data.Memory.Size = Size;
Data.Memory.AllocType = AllocType;
Data.Memory.Protect = Protect;
SharedMemory::SendRequest(AVMRequest, Data);
return SharedMemory::GetBuffer().Memory.Base;
}
bool FreeVirtualMemory(DWORD ProcessId, PVOID Base, SIZE_T Size, DWORD FreeType) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
Data.Memory.Base = Base;
Data.Memory.Size = Size;
Data.Memory.AllocType = FreeType;
return SharedMemory::SendRequest(FVMRequest, Data);
}
DWORD ProtectVirtualMemory(DWORD ProcessId, PVOID Base, SIZE_T Size, DWORD Protect, DWORD* OldProtect = nullptr) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
Data.Memory.Base = Base;
Data.Memory.Size = Size;
Data.Memory.Protect = Protect;
if (SharedMemory::SendRequest(PVMRequest, Data)) {
OperationData Buffer{ SharedMemory::GetBuffer() };
if (OldProtect) {
*OldProtect = Buffer.Memory.OldProtect;
}
return Buffer.Memory.Protect;
}
}
bool QueryVirtualMemory(DWORD ProcessId, PVOID Address, MEMORY_BASIC_INFORMATION& MemoryBasicInfo, SIZE_T Size) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
Data.Memory.Base = Address;
Data.Memory.Size = Size;
if (SharedMemory::SendRequest(QVMRequest, Data)) {
MemoryBasicInfo = SharedMemory::GetBuffer().Memory.MBI;
}
return MemoryBasicInfo.Protect ? true : false;
}
}
================================================
FILE: PoseidonClient/process.h
================================================
#pragma once
#include "global.h"
#include "sharedmemory.h"
namespace Process {
DWORD GetProcessId(const wchar_t* ImageName) {
HANDLE Snapshot{ CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
PROCESSENTRY32W Process{ sizeof(PROCESSENTRY32W) };
if (Process32FirstW(Snapshot, &Process)) {
do {
if (!wcscmp(ImageName, Process.szExeFile)) {
CloseHandle(Snapshot);
return Process.th32ProcessID;
}
} while (Process32NextW(Snapshot, &Process));
}
CloseHandle(Snapshot);
return NULL;
}
PVOID GetBase(DWORD ProcessId) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
if (SharedMemory::SendRequest(BaseRequest, Data)) {
return SharedMemory::GetBuffer().Process.BaseAddress;
} return nullptr;
}
DWORD GetSize(DWORD ProcessId) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
if (SharedMemory::SendRequest(SizeRequest, Data)) {
return SharedMemory::GetBuffer().Process.Size;
} return NULL;
}
template
T GetModuleInfo(DWORD ProcessId, const char* ModuleName, DWORD &OutSize) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
Data.Process.Name = const_cast(ModuleName);
if (SharedMemory::SendRequest(ModuleRequest, Data)) {
OperationData Buffer{ SharedMemory::GetBuffer() };
OutSize = Buffer.Module.SizeOfImage;
return reinterpret_cast(Buffer.Module.BaseAddress);
}
return {};
}
bool QueryInformation(DWORD ProcessId, PROCESS_BASIC_INFORMATION& PBI) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
if (SharedMemory::SendRequest(QIPRequest, Data)) {
PBI = SharedMemory::GetBuffer().Process.PBI;
}
return PBI.PebBaseAddress ? true : false;
}
PPEB GetPeb(DWORD ProcessId) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
if (SharedMemory::SendRequest(PebRequest, Data)) {
return SharedMemory::GetBuffer().Process.Peb;
} return nullptr;
}
DWORD GetModuleCount(DWORD ProcessId) {
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
if (SharedMemory::SendRequest(ModuleRequest, Data)) {
return SharedMemory::GetBuffer().Module.Index;
} return NULL;
}
PVOID GetModuleByIndex(DWORD ProcessId, DWORD Index, DWORD& OutSize) {
PVOID Base{ nullptr };
OperationData Data{ 0 };
Data.Process.Id = ProcessId;
Data.Module.Index = Index;
if (SharedMemory::SendRequest(IndexRequest, Data)) {
OperationData Buffer{ SharedMemory::GetBuffer() };
Base = Buffer.Module.BaseAddress;
OutSize = Buffer.Module.SizeOfImage;
}
return Base;
}
}
================================================
FILE: PoseidonClient/sdk.h
================================================
#pragma once
#include "memory.h"
namespace Client {
bool ErrorFlag{ false };
void KernelThread(PVOID LParam) {
INT64 Status{ 0 };
CommunicationData Data{ *(CommunicationData*)LParam };
PVOID pData{ &Data };
HMODULE Module{ LoadLibrary(L"ntdll.dll") };
if (!Module) {
return;
}
*(PVOID*)&NtConvertBetweenAuxiliaryCounterAndPerformanceCounter = GetProcAddress(Module, "NtConvertBetweenAuxiliaryCounterAndPerformanceCounter");
if (!NtConvertBetweenAuxiliaryCounterAndPerformanceCounter) {
return;
}
NtConvertBetweenAuxiliaryCounterAndPerformanceCounter((PVOID)1, &pData, &Status, nullptr);
ErrorFlag = true; // NtConvertBetweenAuxiliaryCounterAndPerformanceCounter() is the call that transitions this thread into the kernel, and as such should not return until Client::Disconnect() is called.
}
void Connect() {
CommunicationData Data{ 0 };
PVOID Memory{ VirtualAlloc(nullptr,
sizeof(OperationData) * 2,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE) };
if (!Memory) {
return;
}
Data.ProcessId = GetCurrentProcessId();
Data.SharedMemory = Memory;
Data.pCode = (DWORD*)Memory + sizeof(OperationData);
Data.pStatus = (SHORT*)Data.pCode + 8;
Data.Magic = 0x999;
CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)KernelThread, &Data, 0, nullptr);
Sleep(500);
if (ErrorFlag) {
std::cout << "Error Connecting";
getchar();
exit(0);
}
SharedMemory::Connect(Data);
}
void Disconnect() {
SharedMemory::Disconnect();
}
}
class KProcess {
public:
wchar_t* ImageName{};
DWORD ProcessId{};
PVOID BaseAddress{};
DWORD Size{};
PPEB Peb{};
DWORD ModuleCount{};
std::vector ModuleList{};
KProcess(const wchar_t* ImageName) {
this->ImageName = const_cast(ImageName);
this->ProcessId = Process::GetProcessId(ImageName);
this->BaseAddress = Process::GetBase(this->ProcessId);
this->Size = Process::GetSize(this->ProcessId);
this->Peb = Process::GetPeb(this->ProcessId);
this->ModuleCount = Process::GetModuleCount(this->ProcessId);
for (int i = 0; i < this->ModuleCount; i++) {
DWORD SizeOfImage{ 0 };
PVOID BaseAddress{ Process::GetModuleByIndex(this->ProcessId, i, SizeOfImage) };
ModuleList.push_back({ BaseAddress, SizeOfImage });
}
}
template
T GetModuleInfo(const char* ModuleName, DWORD &OutSize) {
return Process::GetModuleInfo(this->ProcessId, ModuleName, OutSize);
}
PROCESS_BASIC_INFORMATION QueryInformationProcess() {
PROCESS_BASIC_INFORMATION Pbi{ 0 };
Process::QueryInformation(this->ProcessId, Pbi);
return Pbi;
}
bool Read(PVOID Address, PVOID Buffer, SIZE_T Size) {
return Memory::Read(this->ProcessId, Address, Buffer, Size);
}
template
T Read(PVOID Address, SIZE_T Size = sizeof(T)) {
return Memory::Read(this->ProcessId, Address, Size);
}
bool Write(PVOID Address, PVOID Buffer, SIZE_T Size) {
return Memory::Write(this->ProcessId, Address, Buffer, Size);
}
template
bool Write(PVOID Address, T Value, SIZE_T Size = sizeof(T)) {
return Memory::Write(this->ProcessId, Address, Value, Size);
}
PVOID AllocateVirtualMemory(PVOID Base, SIZE_T Size, DWORD AllocType, DWORD Protect) {
return Memory::AllocateVirtualMemory(this->ProcessId, Base, Size, AllocType, Protect);
}
bool FreeVirtualMemory(PVOID Base, SIZE_T Size, DWORD FreeType) {
return Memory::FreeVirtualMemory(this->ProcessId, Base, Size, FreeType);
}
DWORD ProtectVirtualMemory(PVOID Base, SIZE_T Size, DWORD Protect, DWORD* OldProtect) {
return Memory::ProtectVirtualMemory(this->ProcessId, Base, Size, Protect, OldProtect);
}
bool QueryVirtualMemory(PVOID Address, MEMORY_BASIC_INFORMATION& MemoryBasicInfo, SIZE_T Size) {
return Memory::QueryVirtualMemory(this->ProcessId, Address, MemoryBasicInfo, Size);
}
MEMORY_BASIC_INFORMATION QueryVirtualMemory(PVOID Address, SIZE_T Size) {
MEMORY_BASIC_INFORMATION Mbi{ 0 };
this->QueryVirtualMemory(Address, Mbi, Size);
return Mbi;
}
BYTE* PatternFinder(BYTE* Start, DWORD Size, const char* Signature, const char* Mask) {
auto CompareData = [] (const char* Data, const char* Signature, const char* Mask) -> BOOL {
for (; *Mask; ++Mask, ++Data, ++Signature) {
if (*Mask == 'x' && *Data != *Signature) {
return FALSE;
}
}
return (*Mask == NULL);
};
auto Buffer{ static_cast(VirtualAlloc(nullptr, Size, MEM_COMMIT, PAGE_READWRITE)) };
this->Read(Start, Buffer, Size);
for (DWORD64 i = 0; i < Size; i++) {
if (CompareData(Buffer + i, Signature, Mask)) {
VirtualFree(Buffer, 0, MEM_RELEASE);
return Start + i;
}
}
VirtualFree(Buffer, NULL, MEM_RELEASE);
return NULL;
}
BYTE* AbsoluteAddress(BYTE* Rip, DWORD InstructionLength) {
DWORD RelativeOffset{ 0 };
this->Read(Rip + InstructionLength - 4, &RelativeOffset, sizeof(DWORD));
return Rip + InstructionLength + RelativeOffset;
}
BYTE* RelativeAddress(BYTE* DestinationAddress, BYTE* SourceAddress, DWORD InstructionLength) {
return reinterpret_cast(reinterpret_cast(SourceAddress)
- InstructionLength
- reinterpret_cast(DestinationAddress));
}
};
================================================
FILE: PoseidonClient/sharedmemory.h
================================================
#pragma once
#include "global.h"
namespace SharedMemory {
CommunicationData Data{ 0 };
INT Queue{ 0 };
void PushQueue() {
Queue += 1;
}
void PopQueue() {
Queue -= 1;
}
BOOL WriteSharedMemory(PVOID Address, PVOID Value, SIZE_T Size) {
return reinterpret_cast(memcpy(Address, Value, Size));
}
template
T ReadSharedMemory(PVOID Address, SIZE_T Size = sizeof(T)) {
T Ret{ 0 };
memcpy(static_cast(&Ret), Address, Size);
return Ret;
}
BOOL SetStatus(Status Status) {
return WriteSharedMemory(Data.pStatus, &Status, sizeof(SHORT));
}
BOOL SetCode(DWORD Code) {
return WriteSharedMemory(Data.pCode, &Code, sizeof(DWORD));
}
BOOL SetBuffer(OperationData Buffer) {
return WriteSharedMemory(Data.SharedMemory, &Buffer, sizeof(OperationData));
}
Status GetStatus() {
return static_cast(ReadSharedMemory(Data.pStatus));
}
DWORD GetCode() {
return ReadSharedMemory(Data.pCode);
}
OperationData GetBuffer() {
return ReadSharedMemory(Data.SharedMemory);
}
BOOL SendRequest(Code Request, OperationData Data) {
do {
Sleep(10);
} while (GetCode() != Complete
|| GetStatus() != Active
|| Queue >= 1);
PushQueue();
if (SetBuffer(Data)) {
if (SetCode(Request)) {
if (SetStatus(Waiting)) {
do {
Sleep(10);
} while (GetCode() != Complete || GetStatus() != Active);
PopQueue();
return true;
}
}
}
PopQueue();
return false;
}
void Connect(CommunicationData InitData) {
Data = InitData;
SetStatus(Active);
SetCode(Complete);
}
void Disconnect() {
SetStatus(Exit);
}
};
================================================
FILE: README.md
================================================
# KM-UM-Communication
Stealthy UM <-> KM communication system without creating any system threads, permanent hooks, driver objects, section objects or device objects.
Process:
- In our driver, we hook a function in ntoskrnl (.data pointer swap)
- In usermode, we manually allocate memory and index it via custom data structures
- We then create a thread in usermode and call the hooked function's corresponding usermode-accessible function
- When the correct magic number is passed to the function, the driver will know it's us, and will then unhook and enter a shared memory loop, trapping our usermode thread in the kernel until we choose to break out of the loop
As long as this is set up prior to any anti-cheat being active on your system, you can communicate with the driver without being detected by most of the various security measures employed by invasive anti-cheat technologies such as BattlEye and EasyAntiCheat.
2023 Update: There are quite a few detection vectors that can be identified by BE and EAC, some of which are discussed in (now closed) issues. Most are easy to bypass, but others are a bit more tricky. Having said that, I still have never had any action taken against me for using this for relatively licit purposes (i.e. no aimbot, ESP, or any other blatant violative use), nor has anyone I know who's used it. Regardless, steps should be taken to mitigate any potential detection vectors. I will not be providing any updates or revisions, as this is nearly four years old and there are far superior options to accomplish stealthy communication. This is mainly meant to serve as an interesting, novel communication method that demostrates the potential creativity that can be employed to get around invasive security software, mainly anti-cheat software.
Limitations:
- Dodgy synchronization
- Not many kernel features, just basic remote-process operability
- Not designed with safety as a priority (i.e. you may well BSOD)
- Only tested on Windows 10 20H2
- The client can only be used once. If you terminate it or call Client::Disconnect(), you'll need to remap the driver
The driver is intended to be manually mapped by exploiting Intel's vulnerable network adapter diagnostic driver, iqvw64e.sys (or any other suitable vulnerable driver).
This was created for fun, I do not condone the use of this code in any program that violates the integrity of any online game, nor do I condone the use of this in any malicious software. This should only be used for learning purposes or to prevent custom software from being falsely detected as an illicit program.
Usage:
- Map the driver
- Start the client
- Start the target process
- Do stuff
You have to modify the client to sleep until your target process is running (since it must be set up prior to any anti-cheat being active). Basic example of how main.cpp in the client should typically look:
```
int main() {
Client::Connect();
for (;;) {
Sleep(100);
if (YourTargetProcessIsRunning) {
break;
}
}
// Do stuff
Client::Disconnect();
}
```
You can either call the functions in memory.h and process.h manually, or you can just create a KProcess object for easier use. KProcess features are as follows:
```
// Make a process object for your target process
KProcess Notepad(L"notepad.exe");
// Read Memory
int Value = Notepad.Read((PVOID)0xDEADBEEF);
Notepad.Read((PVOID)0xDEADBEEF, &Value, sizeof(int)); // Overload
// Write Memory
Notepad.Write((PVOID)0xDEADBEEF, 2);
Notepad.Write((PVOID)0xDEADBEEF, &Value, sizeof(int)); // Overload
// Allocate Virtual Memory
Notepad.AllocateVirtualMemory(PVOID Base, SIZE_T Size, DWORD AllocType, DWORD Protect);
// Free Virtual Memory
Notepad.FreeVirtualMemory(PVOID Base, SIZE_T Size, DWORD FreeType);
// Change Virtual Memory Protection
Notepad.ProtectVirtualMemory(PVOID Base, SIZE_T Size, DWORD Protect, DWORD* OldProtect);
// Query Virtual Memory. MEMORY_BASIC_INFORMATION only.
MEMORY_BASIC_INFORMATION MBI{ 0 };
bool bResult = Notepad.QueryVirtualMemory(PVOID Address, MEMORY_BASIC_INFORMATION& MemoryBasicInfo, SIZE_T Size);
MBI = Notepad.QueryVirtualMemory(PVOID Address, SIZE_T Size); // Overload
// Query Process Information
Notepad.QueryInformationProcess();
// Get module info by name
Notepad.GetModuleInfo(const char* ModuleName, DWORD& ModuleSize);
// Pattern finder
Notepad.PatternFinder(BYTE* Start, DWORD Size, const char* Signature, const char* Mask);
// Get absolute address within specified asm instruction
Notepad.AbsoluteAddress(BYTE* Rip, DWORD InstructionLength);
// Get relative address within specified asm instruction
Notepad.RelativeAddress(BYTE* DestinationAddress, BYTE* SourceAddress, DWORD InstructionLength);
Notepad.BaseAddress; // Base Address
Notepad.ImageName; // Name
Notepad.ModuleCount; // Number of modules
Notepad.ModuleList; // std::vector containing all modules' base address and size
Notepad.Peb; // Process Environment Block
Notepad.ProcessId; // Process Id
Notepad.Size; // Main module size
```