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 ```