From c7e31bc95c4d47fb8ab337795b8daf0502593fac Mon Sep 17 00:00:00 2001
From: Belonit <54427022+Belonit@users.noreply.github.com>
Date: Sat, 22 Aug 2026 01:58:52 +0300
Subject: [PATCH 1/6] Enforce W^X for generated code and enable exploit
mitigations
---
Debugger.vcxproj | 12 ++++++------
Handle.h | 15 ++++++++++++++-
SyringeDebugger.cpp | 21 +++++++++++++++++++--
SyringeDebugger.h | 8 +++++++-
4 files changed, 46 insertions(+), 10 deletions(-)
diff --git a/Debugger.vcxproj b/Debugger.vcxproj
index 120d7c3..143d585 100644
--- a/Debugger.vcxproj
+++ b/Debugger.vcxproj
@@ -74,7 +74,7 @@
true
false
stdcpp20
- false
+ true
true
true
@@ -89,8 +89,8 @@
true
.\Debug\Syringe.pdb
Windows
- false
-
+ true
+ true
MachineX86
true
true
@@ -121,7 +121,7 @@
/Zc:threadSafeInit- /Zc:throwingNew /Gw %(AdditionalOptions)
false
stdcpp20
- false
+ true
true
$(ProjectDir)external\include;%(AdditionalIncludeDirectories)
@@ -133,8 +133,8 @@
.\Release\Syringe.exe
.\Release\Syringe.pdb
Windows
- false
-
+ true
+ true
MachineX86
true
true
diff --git a/Handle.h b/Handle.h
index d98fed5..ca476e6 100644
--- a/Handle.h
+++ b/Handle.h
@@ -176,7 +176,7 @@ struct VirtualMemoryHandle
{
if (process && size)
{
- this->Value = VirtualAllocEx(process, address, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ this->Value = VirtualAllocEx(process, address, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
}
}
@@ -217,6 +217,19 @@ struct VirtualMemoryHandle
return static_cast(this->Value);
}
+ bool protect(SIZE_T size, DWORD protection) const noexcept
+ {
+ DWORD oldProtection;
+ return this->Value && this->Process
+ && VirtualProtectEx(this->Process, this->Value, size, protection, &oldProtection) != FALSE;
+ }
+
+ bool flush_instruction_cache(SIZE_T size) const noexcept
+ {
+ return this->Value && this->Process
+ && FlushInstructionCache(this->Process, this->Value, size) != FALSE;
+ }
+
void clear() noexcept
{
VirtualMemoryHandle(std::move(*this));
diff --git a/SyringeDebugger.cpp b/SyringeDebugger.cpp
index 72d70bc..e2ade7b 100644
--- a/SyringeDebugger.cpp
+++ b/SyringeDebugger.cpp
@@ -57,6 +57,15 @@ VirtualMemoryHandle SyringeDebugger::AllocMem(void* address, size_t size)
throw_lasterror_or(ERROR_ERRORS_ENCOUNTERED, exe);
}
+void SyringeDebugger::MakeExecutable(VirtualMemoryHandle const& memory, size_t size)
+{
+ if (!memory.protect(size, PAGE_EXECUTE_READ)
+ || !memory.flush_instruction_cache(size))
+ {
+ throw_lasterror_or(ERROR_ERRORS_ENCOUNTERED, exe);
+ }
+}
+
bool SyringeDebugger::SetBP(void* address)
{
// save overwritten code and set INT 3
@@ -610,7 +619,11 @@ DWORD SyringeDebugger::HandleException(DEBUG_EVENT const& dbgEvent)
p_code += sizeof(jmp_back);
auto const actual_sz = static_cast(p_code - code.data());
- PatchMem(base, code.data(), actual_sz);
+ if (!PatchMem(base, code.data(), actual_sz))
+ {
+ throw_lasterror_or(ERROR_ERRORS_ENCOUNTERED, exe);
+ }
+ MakeExecutable(it.second.p_caller_code, sz);
// dump
/*
@@ -831,7 +844,11 @@ void SyringeDebugger::Run(std::string_view const arguments)
ApplyPatch(data.data() + 0x13, &GetData()->ProcName);
ApplyPatch(data.data() + 0x1A, pImGetProcAddress);
ApplyPatch(data.data() + 0x1F, &GetData()->ProcAddress);
- PatchMem(pAlloc, data.data(), data.size());
+ if (!PatchMem(pAlloc, data.data(), data.size()))
+ {
+ throw_lasterror_or(ERROR_ERRORS_ENCOUNTERED, exe);
+ }
+ MakeExecutable(pAlloc, AllocData::CodeSize);
Log::WriteLine(__FUNCTION__ ": pcLoadLibrary = 0x%08X", &GetData()->LoadLibraryFunc);
diff --git a/SyringeDebugger.h b/SyringeDebugger.h
index a56eb65..143e306 100644
--- a/SyringeDebugger.h
+++ b/SyringeDebugger.h
@@ -6,6 +6,7 @@
#include "PortableExecutable.h"
#include "Log.h"
+#include
#include
#include
#include