From e4d32f54fdb094e9b1259c8d8ee7b6f43b730ddb Mon Sep 17 00:00:00 2001
From: Ironhammer Std <2482911962@qq.com>
Date: Thu, 14 May 2026 11:48:00 +0800
Subject: [PATCH 1/6] Disable Warning C4456 for a certain part of code
---
SyringeDebugger.h | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/SyringeDebugger.h b/SyringeDebugger.h
index 88797c2..0e9e0e4 100644
--- a/SyringeDebugger.h
+++ b/SyringeDebugger.h
@@ -1,4 +1,4 @@
-#pragma once
+#pragma once
#define WIN32_LEAN_AND_MEAN
// WIN32_FAT_AND_STUPID
@@ -45,6 +45,10 @@ class SyringeDebugger
{
std::string_view const flagView = flag;
+//Disable Warning C4456
+#pragma warning( push )
+#pragma warning( disable : 4456 )
+
// parse all -i=filename_to_inject from flags
if (auto const pos = flagView.find(INCLUDE_FLAG); pos != std::string_view::npos)
{
@@ -68,6 +72,8 @@ class SyringeDebugger
}
}
+#pragma warning( pop )
+
if (dlls.empty())
{
dlls.emplace_back("*.dll");
From 5475e50e98e3d52acda9fa8615e735290de815b3 Mon Sep 17 00:00:00 2001
From: Ironhammer Std <2482911962@qq.com>
Date: Thu, 14 May 2026 17:54:16 +0800
Subject: [PATCH 2/6] Basic Hook Analyzer with INJ generation
---
Debugger.vcxproj | 3 +
Debugger.vcxproj.filters | 12 ++++
HookAnalyzer.cpp | 145 +++++++++++++++++++++++++++++++++++++++
HookAnalyzer.h | 50 ++++++++++++++
SyringeDebugger.cpp | 40 ++++++++++-
SyringeDebugger.h | 20 ++++++
ToolFunctions.cpp | 77 +++++++++++++++++++++
7 files changed, 345 insertions(+), 2 deletions(-)
create mode 100644 HookAnalyzer.cpp
create mode 100644 HookAnalyzer.h
create mode 100644 ToolFunctions.cpp
diff --git a/Debugger.vcxproj b/Debugger.vcxproj
index 120d7c3..7c48406 100644
--- a/Debugger.vcxproj
+++ b/Debugger.vcxproj
@@ -148,15 +148,18 @@
+
+
+
diff --git a/Debugger.vcxproj.filters b/Debugger.vcxproj.filters
index c4cd35f..1039ce5 100644
--- a/Debugger.vcxproj.filters
+++ b/Debugger.vcxproj.filters
@@ -13,6 +13,9 @@
{e85625c5-48c3-4acf-a47a-873697970105}
ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe
+
+ {0a7cbdbd-6556-4c84-b288-4ffa95f8120b}
+
@@ -30,6 +33,12 @@
Source Files
+
+ Components
+
+
+ Components
+
@@ -56,6 +65,9 @@
Header Files
+
+ Components
+
diff --git a/HookAnalyzer.cpp b/HookAnalyzer.cpp
new file mode 100644
index 0000000..714a71e
--- /dev/null
+++ b/HookAnalyzer.cpp
@@ -0,0 +1,145 @@
+#include "HookAnalyzer.h"
+#include "Handle.h"
+//#include "Setting.h"
+#include
+#include "Log.h"
+
+const std::string& ExecutableDirectoryPath();
+
+void HookAnalyzer::Add(HookAnalyzeData&& Data, bool Show)
+{
+ if (Show)
+ {
+ ByLibName[Data.Lib].push_back(Data);
+ HookMap[Data.Lib + AnalyzerDelim + Data.Proc] = Data;
+ ByAddress[Data.Addr].push_back(std::move(Data));
+ }
+
+ HookMapEx[Data.Lib + AnalyzerDelim + Data.Proc] = Data;
+ ByLibNameEx[Data.Lib].push_back(Data);
+ ByAddressEx[Data.RelLib][Data.Addr].push_back(std::move(Data));
+}
+
+//bool HookAnalyzer::Report()
+//{
+// FileHandle File = FileHandle(fopen("HookAnalysis.log", "w"));
+// if (!File)return false;
+// fprintf(File, "%s 将分析获取到的钩子。\n", VersionString);
+// if (ShowHookAnalysis_ByAddr)
+// {
+// fputs("========================\n", File);
+// fputs("按照钩子位置分析:(每个地址处按照钩子执行序)\n", File);
+// for (auto& p : ByAddress)
+// {
+// fprintf(File, "在 %08X :\n", p.first);
+// for (auto v : p.second)
+// {
+// fprintf(File, "钩子\"%s,相对于\"%s\",来自\"%s\",长度%d,优先级 %d,次优先级 \"%s\"\n", v.Proc.c_str(), v.RelLib.c_str(), v.Lib.c_str(), v.Len, v.Priority, v.SubPriority.c_str());
+// }
+// }
+// }
+//
+// if (ShowHookAnalysis_ByLib)
+// {
+// fputs("========================\n", File);
+// fputs("按照钩子来源分析:\n", File);
+// for (auto& p : ByLibName)
+// {
+// fprintf(File, "正在分析 DLL :\"%s\" ……\n", p.first.c_str());
+// for (auto v : p.second)
+// {
+// fprintf(File, "钩子\"%s\",相对于\"%s\",位于%08X,长度%d,优先级 %d,次优先级 \"%s\"\n", v.Proc.c_str(), v.RelLib.c_str(), v.Addr, v.Len, v.Priority, v.SubPriority.c_str());
+// }
+// }
+// }
+//
+// fputs("========================\n", File);
+// fprintf(File, "%s 分析完毕。\n", VersionString);
+// return true;
+//}
+//
+//bool HookAnalyzer::HasHookConflict()
+//{
+// //check if there are conflicting hooks
+// bool Conflict = false;
+// for (auto& [lib, byaddr] : ByAddressEx)
+// {
+// std::vector*> SortedHooks;
+// for (auto& p : byaddr)
+// SortedHooks.push_back(&p.second);
+// std::sort(SortedHooks.begin(), SortedHooks.end(), [](const auto& lhs, const auto& rhs) -> bool
+// {
+// return lhs->front().Addr < rhs->front().Addr;
+// });
+// for (size_t i = 0; i < SortedHooks.size() - 1; i++)
+// {
+// auto Addr1 = SortedHooks[i]->front().Addr;
+// auto Addr2 = SortedHooks[i + 1]->front().Addr;
+// auto Len1 = std::max_element(SortedHooks[i]->begin(), SortedHooks[i]->end(), [](const auto& lhs, const auto& rhs) -> bool
+// {
+// return lhs.Len < rhs.Len;
+// })->Len;
+// Len1 = std::max(Len1, 5);//a JMP is 5 bytes
+// if (Addr1 + Len1 > Addr2)
+// {
+// Log::WriteLine("检测到钩子冲突:");
+// for (auto& h : *SortedHooks[i])
+// Log::WriteLine("钩子\"%s\",来自\"%s\",相对于\"%s\",位于%08X,长度%d,优先级 %d,次优先级 \"%s\"",
+// h.Proc.c_str(),
+// h.Lib.c_str(),
+// h.RelLib.c_str(),
+// h.Addr,
+// h.Len,
+// h.Priority,
+// h.SubPriority.c_str());
+// for (auto& h : *SortedHooks[i + 1])
+// Log::WriteLine("钩子\"%s\",来自\"%s\",相对于\"%s\",位于%08X,长度%d,优先级 %d,次优先级 \"%s\"",
+// h.Proc.c_str(),
+// h.Lib.c_str(),
+// h.RelLib.c_str(),
+// h.Addr,
+// h.Len,
+// h.Priority,
+// h.SubPriority.c_str());
+// if (!Conflict && ShowHookConflictPopup)
+// {
+// wchar_t ErrorStr[1000];
+// swprintf_s(ErrorStr, 1000, L"检测到位于 0x%08X 和 0x%08X 的钩子冲突,详见 Syringe.log 。", Addr1, Addr2);
+// MessageBoxW(NULL, ErrorStr, VersionLString, MB_OK | MB_ICONERROR);
+// }
+// Conflict = true;
+// }
+// }
+// return Conflict;
+// }
+//}
+
+bool HookAnalyzer::GenerateINJ()
+{
+ //Log::WriteLine(ExecutableDirectoryPath().c_str());
+ auto path = ExecutableDirectoryPath() + "\\INJ";
+ auto pp = CreateDirectoryA(path.c_str(), NULL);
+ if (pp || GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ //Log::WriteLine((path + "\\").c_str());
+ for (auto& p : ByLibNameEx)
+ {
+ //Log::WriteLine((path + "\\" + p.first).c_str());
+ FileHandle File = FileHandle(fopen((path + "\\" + p.first + ".inj").c_str(), "w"));
+ if (!File)return false;
+ for (auto& h : p.second)
+ {
+ if (!h.RelLib.empty())
+ fputs(";Relative Hook Found ,failed to Generate", File);
+ else if (!h.SubPriority.empty())
+ fprintf(File, "%X=%s,%X,%d,%s\n", h.Addr, h.Proc.c_str(), h.Len, h.Priority, h.SubPriority.c_str());
+ else if (h.Priority == 100000)
+ fprintf(File, "%X=%s,%X\n", h.Addr, h.Proc.c_str(), h.Len);
+ else
+ fprintf(File, "%X=%s,%X,%d\n", h.Addr, h.Proc.c_str(), h.Len, h.Priority);
+ }
+ }
+ return true;
+ }
+ return false;
+}
\ No newline at end of file
diff --git a/HookAnalyzer.h b/HookAnalyzer.h
new file mode 100644
index 0000000..562cb74
--- /dev/null
+++ b/HookAnalyzer.h
@@ -0,0 +1,50 @@
+#pragma once
+
+#include
+#include
+#include
+
+const std::string AnalyzerDelim = "\\*^*\\";
+
+struct HookAnalyzeData
+{
+ std::string Lib;
+ std::string Proc;
+ int Addr;
+ int Len;
+
+ int Priority{ 100000 };
+ std::string SubPriority{ "" };
+ std::string RelLib{ "" };
+};
+
+class HookAnalyzer
+{
+private:
+ std::unordered_map> ByLibName;
+ std::unordered_map> ByLibNameEx;
+public:
+ std::unordered_map HookMap;
+ std::unordered_map> ByAddress;
+ std::unordered_map HookMapEx;
+ std::unordered_map>> ByAddressEx;
+
+ void Add(HookAnalyzeData&& , bool Show);
+ bool Report();
+ bool GenerateINJ();
+ bool HasHookConflict();
+};
+
+//static constexpr size_t MaxNameLength = 0x100u;
+//
+//struct Hook
+//{
+// char lib[MaxNameLength];
+// char proc[MaxNameLength];
+// void* proc_address;
+//
+// size_t num_overridden;
+// int Priority;
+// char SubPriority[MaxNameLength];
+// char RelativeLib[MaxNameLength];
+//};
\ No newline at end of file
diff --git a/SyringeDebugger.cpp b/SyringeDebugger.cpp
index 5715a6f..2b6d7a8 100644
--- a/SyringeDebugger.cpp
+++ b/SyringeDebugger.cpp
@@ -1,4 +1,4 @@
-#include "SyringeDebugger.h"
+#include "SyringeDebugger.h"
#include "CRC32.h"
#include "FindFile.h"
@@ -788,8 +788,28 @@ DWORD SyringeDebugger::HandleException(DEBUG_EVENT const& dbgEvent)
return DBG_CONTINUE;
}
-void SyringeDebugger::Run(std::string_view const arguments)
+void SyringeDebugger::Run(std::string_view arguments)
{
+ if(bDryRun)
+ {
+ Log::WriteLine(__FUNCTION__ ": Entering dry run mode, not actually running the process.");
+ DryRun(arguments);
+ }
+ else
+ {
+ RealRun(arguments);
+ }
+}
+
+void SyringeDebugger::DryRun(std::string_view const arguments)
+{
+ PreLoadData();
+}
+
+void SyringeDebugger::RealRun(std::string_view const arguments)
+{
+ PreLoadData();
+
constexpr auto AllocDataSize = sizeof(AllocData);
Log::WriteLine(
@@ -937,6 +957,17 @@ void SyringeDebugger::Run(std::string_view const arguments)
Log::WriteLine();
}
+void SyringeDebugger::PreLoadData()
+{
+ if (bGenerateINJ)
+ {
+ Log::WriteLine(__FUNCTION__ ": Creating INJ files...");
+ if (analyzer.GenerateINJ())
+ Log::WriteLine(__FUNCTION__ ": Complete.");
+ else Log::WriteLine(__FUNCTION__ ": Failed.");
+ }
+}
+
void SyringeDebugger::RemoveBP(LPVOID const address, bool const restoreOpcode)
{
if (auto const i = Breakpoints.find(address); i != Breakpoints.end())
@@ -1108,6 +1139,11 @@ void SyringeDebugger::FindDLLs()
{
for (auto& i : it.second.hooks)
{
+ std::string_view filename = i.lib;
+ auto sz = filename.find_last_of('\\');
+ auto sv = (sz != std::string_view::npos) ? filename.substr(sz + 1, filename.size() - sz - 1) : filename;
+ analyzer.Add(HookAnalyzeData{ sv.data(), i.proc, (int)it.first, (int)i.num_overridden }, false);
+
v_AllHooks.push_back(&i);
}
}
diff --git a/SyringeDebugger.h b/SyringeDebugger.h
index 0e9e0e4..36368dc 100644
--- a/SyringeDebugger.h
+++ b/SyringeDebugger.h
@@ -22,6 +22,8 @@
#include
#pragma warning(pop)
+#include "HookAnalyzer.h"
+
using std::operator""sv;
class SyringeDebugger
@@ -36,6 +38,8 @@ class SyringeDebugger
static constexpr std::string_view NODETACH_FLAG = "--nodetach";
static constexpr std::string_view NOWAIT_FLAG = "--nowait";
static constexpr std::string_view HANDSHAKES_FLAG = "--handshakes";
+ static constexpr std::string_view DRYRUN_FLAG = "--dryrun";
+ static constexpr std::string_view GENERATEINJ_FLAG = "--generate-inj";
public:
SyringeDebugger(std::string_view filename, std::vector flags = {})
@@ -66,6 +70,14 @@ class SyringeDebugger
{
bHandshakes = true;
}
+ else if (auto const pos = flagView.find(DRYRUN_FLAG); pos != std::string_view::npos)
+ {
+ bDryRun = true;
+ }
+ else if (auto const pos = flagView.find(GENERATEINJ_FLAG); pos != std::string_view::npos)
+ {
+ bGenerateINJ = true;
+ }
else
{
Log::WriteLine(__FUNCTION__ ": Unknown flag \"%.*s\", skipping.", printable(flagView));
@@ -83,6 +95,8 @@ class SyringeDebugger
}
// debugger
+ void DryRun(std::string_view arguments);
+ void RealRun(std::string_view arguments);
void Run(std::string_view arguments);
DWORD HandleException(DEBUG_EVENT const& dbgEvent);
@@ -195,12 +209,17 @@ class SyringeDebugger
bool bDetachWhenDone{ true };
bool bWaitForProcessEnd{ true };
bool bHandshakes{ false };
+ bool bDryRun{ false };
+ bool bGenerateINJ{ false };
bool bDLLsLoaded{ false };
bool bHooksCreated{ false };
bool bAVLogged{ false };
+ // components
+ HookAnalyzer analyzer;
+
// data addresses
struct AllocData
{
@@ -250,6 +269,7 @@ class SyringeDebugger
bool CanHostDLL(PortableExecutable const& DLL, IMAGE_SECTION_HEADER const& hosts) const;
bool ParseHooksSection(PortableExecutable const& DLL, IMAGE_SECTION_HEADER const& hooks, HookBuffer& buffer);
std::optional Handshake(char const* lib, int hooks, unsigned int crc);
+ void PreLoadData();
};
// disable "structures padded due to alignment specifier"
diff --git a/ToolFunctions.cpp b/ToolFunctions.cpp
new file mode 100644
index 0000000..47d84d6
--- /dev/null
+++ b/ToolFunctions.cpp
@@ -0,0 +1,77 @@
+#include
+#include
+#include
+
+const std::string& ExecutableDirectoryPath()
+{
+ static std::string ss;
+ if (!ss.empty())return ss;
+ std::vector full_path_exe(MAX_PATH);
+
+ for (;;)
+ {
+ const DWORD result = GetModuleFileNameA(NULL,
+ &full_path_exe[0],
+ full_path_exe.size());
+
+ if (result == 0)
+ {
+ // Report failure to caller.
+ }
+ else if (full_path_exe.size() == result)
+ {
+ // Buffer too small: increase size.
+ full_path_exe.resize(full_path_exe.size() * 2);
+ }
+ else
+ {
+ // Success.
+ break;
+ }
+ }
+
+ // Remove executable name.
+ std::string result(full_path_exe.begin(), full_path_exe.end());
+ std::string::size_type i = result.find_last_of("\\/");
+ if (std::string::npos != i) result.erase(i);
+
+ ss = result;
+ return ss;
+}
+
+const std::wstring& ExecutableDirectoryPathW()
+{
+ static std::wstring ss;
+ if (!ss.empty())return ss;
+ std::vector full_path_exe(MAX_PATH);
+
+ for (;;)
+ {
+ const DWORD result = GetModuleFileNameW(NULL,
+ &full_path_exe[0],
+ full_path_exe.size());
+
+ if (result == 0)
+ {
+ // Report failure to caller.
+ }
+ else if (full_path_exe.size() == result)
+ {
+ // Buffer too small: increase size.
+ full_path_exe.resize(full_path_exe.size() * 2);
+ }
+ else
+ {
+ // Success.
+ break;
+ }
+ }
+
+ // Remove executable name.
+ std::wstring result(full_path_exe.begin(), full_path_exe.end());
+ std::wstring::size_type i = result.find_last_of(L"\\/");
+ if (std::string::npos != i) result.erase(i);
+
+ ss = result;
+ return ss;
+}
From 7d140541521c203f67618ca360c7a6ac099a8253 Mon Sep 17 00:00:00 2001
From: Ironhammer Std <2482911962@qq.com>
Date: Thu, 14 May 2026 17:56:19 +0800
Subject: [PATCH 3/6] Set DefaultPriority
---
HookAnalyzer.cpp | 2 +-
HookAnalyzer.h | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/HookAnalyzer.cpp b/HookAnalyzer.cpp
index 714a71e..496855a 100644
--- a/HookAnalyzer.cpp
+++ b/HookAnalyzer.cpp
@@ -133,7 +133,7 @@ bool HookAnalyzer::GenerateINJ()
fputs(";Relative Hook Found ,failed to Generate", File);
else if (!h.SubPriority.empty())
fprintf(File, "%X=%s,%X,%d,%s\n", h.Addr, h.Proc.c_str(), h.Len, h.Priority, h.SubPriority.c_str());
- else if (h.Priority == 100000)
+ else if (h.Priority == DefaultPriority)
fprintf(File, "%X=%s,%X\n", h.Addr, h.Proc.c_str(), h.Len);
else
fprintf(File, "%X=%s,%X,%d\n", h.Addr, h.Proc.c_str(), h.Len, h.Priority);
diff --git a/HookAnalyzer.h b/HookAnalyzer.h
index 562cb74..35c3f83 100644
--- a/HookAnalyzer.h
+++ b/HookAnalyzer.h
@@ -5,6 +5,7 @@
#include
const std::string AnalyzerDelim = "\\*^*\\";
+const int DefaultPriority = 100000;
struct HookAnalyzeData
{
@@ -13,7 +14,7 @@ struct HookAnalyzeData
int Addr;
int Len;
- int Priority{ 100000 };
+ int Priority{ DefaultPriority };
std::string SubPriority{ "" };
std::string RelLib{ "" };
};
From bf6668eecfeebd7699e239e0e52fe7b173f6bd24 Mon Sep 17 00:00:00 2001
From: Ironhammer Std <2482911962@qq.com>
Date: Thu, 14 May 2026 17:58:00 +0800
Subject: [PATCH 4/6] Temp show all hooks in HookAnalysis (until rule sets
implemented)
---
SyringeDebugger.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/SyringeDebugger.cpp b/SyringeDebugger.cpp
index 2b6d7a8..61276cf 100644
--- a/SyringeDebugger.cpp
+++ b/SyringeDebugger.cpp
@@ -1142,7 +1142,7 @@ void SyringeDebugger::FindDLLs()
std::string_view filename = i.lib;
auto sz = filename.find_last_of('\\');
auto sv = (sz != std::string_view::npos) ? filename.substr(sz + 1, filename.size() - sz - 1) : filename;
- analyzer.Add(HookAnalyzeData{ sv.data(), i.proc, (int)it.first, (int)i.num_overridden }, false);
+ analyzer.Add(HookAnalyzeData{ sv.data(), i.proc, (int)it.first, (int)i.num_overridden }, true);
v_AllHooks.push_back(&i);
}
From f677f56f681d8bad640a9375768a7a524b3ecd57 Mon Sep 17 00:00:00 2001
From: Ironhammer Std <2482911962@qq.com>
Date: Thu, 14 May 2026 20:59:31 +0800
Subject: [PATCH 5/6] ReportLOG & DetectConflict ReportJSON not yet implemented
---
HookAnalyzer.cpp | 190 ++++++++++++++++++++++----------------------
HookAnalyzer.h | 5 +-
SyringeDebugger.cpp | 19 +++++
SyringeDebugger.h | 40 ++++++++++
4 files changed, 158 insertions(+), 96 deletions(-)
diff --git a/HookAnalyzer.cpp b/HookAnalyzer.cpp
index 496855a..5f3988a 100644
--- a/HookAnalyzer.cpp
+++ b/HookAnalyzer.cpp
@@ -3,6 +3,7 @@
//#include "Setting.h"
#include
#include "Log.h"
+#include "resource.h"
const std::string& ExecutableDirectoryPath();
@@ -12,7 +13,7 @@ void HookAnalyzer::Add(HookAnalyzeData&& Data, bool Show)
{
ByLibName[Data.Lib].push_back(Data);
HookMap[Data.Lib + AnalyzerDelim + Data.Proc] = Data;
- ByAddress[Data.Addr].push_back(std::move(Data));
+ ByAddress[Data.Addr].push_back(Data);
}
HookMapEx[Data.Lib + AnalyzerDelim + Data.Proc] = Data;
@@ -20,99 +21,100 @@ void HookAnalyzer::Add(HookAnalyzeData&& Data, bool Show)
ByAddressEx[Data.RelLib][Data.Addr].push_back(std::move(Data));
}
-//bool HookAnalyzer::Report()
-//{
-// FileHandle File = FileHandle(fopen("HookAnalysis.log", "w"));
-// if (!File)return false;
-// fprintf(File, "%s 将分析获取到的钩子。\n", VersionString);
-// if (ShowHookAnalysis_ByAddr)
-// {
-// fputs("========================\n", File);
-// fputs("按照钩子位置分析:(每个地址处按照钩子执行序)\n", File);
-// for (auto& p : ByAddress)
-// {
-// fprintf(File, "在 %08X :\n", p.first);
-// for (auto v : p.second)
-// {
-// fprintf(File, "钩子\"%s,相对于\"%s\",来自\"%s\",长度%d,优先级 %d,次优先级 \"%s\"\n", v.Proc.c_str(), v.RelLib.c_str(), v.Lib.c_str(), v.Len, v.Priority, v.SubPriority.c_str());
-// }
-// }
-// }
-//
-// if (ShowHookAnalysis_ByLib)
-// {
-// fputs("========================\n", File);
-// fputs("按照钩子来源分析:\n", File);
-// for (auto& p : ByLibName)
-// {
-// fprintf(File, "正在分析 DLL :\"%s\" ……\n", p.first.c_str());
-// for (auto v : p.second)
-// {
-// fprintf(File, "钩子\"%s\",相对于\"%s\",位于%08X,长度%d,优先级 %d,次优先级 \"%s\"\n", v.Proc.c_str(), v.RelLib.c_str(), v.Addr, v.Len, v.Priority, v.SubPriority.c_str());
-// }
-// }
-// }
-//
-// fputs("========================\n", File);
-// fprintf(File, "%s 分析完毕。\n", VersionString);
-// return true;
-//}
-//
-//bool HookAnalyzer::HasHookConflict()
-//{
-// //check if there are conflicting hooks
-// bool Conflict = false;
-// for (auto& [lib, byaddr] : ByAddressEx)
-// {
-// std::vector*> SortedHooks;
-// for (auto& p : byaddr)
-// SortedHooks.push_back(&p.second);
-// std::sort(SortedHooks.begin(), SortedHooks.end(), [](const auto& lhs, const auto& rhs) -> bool
-// {
-// return lhs->front().Addr < rhs->front().Addr;
-// });
-// for (size_t i = 0; i < SortedHooks.size() - 1; i++)
-// {
-// auto Addr1 = SortedHooks[i]->front().Addr;
-// auto Addr2 = SortedHooks[i + 1]->front().Addr;
-// auto Len1 = std::max_element(SortedHooks[i]->begin(), SortedHooks[i]->end(), [](const auto& lhs, const auto& rhs) -> bool
-// {
-// return lhs.Len < rhs.Len;
-// })->Len;
-// Len1 = std::max(Len1, 5);//a JMP is 5 bytes
-// if (Addr1 + Len1 > Addr2)
-// {
-// Log::WriteLine("检测到钩子冲突:");
-// for (auto& h : *SortedHooks[i])
-// Log::WriteLine("钩子\"%s\",来自\"%s\",相对于\"%s\",位于%08X,长度%d,优先级 %d,次优先级 \"%s\"",
-// h.Proc.c_str(),
-// h.Lib.c_str(),
-// h.RelLib.c_str(),
-// h.Addr,
-// h.Len,
-// h.Priority,
-// h.SubPriority.c_str());
-// for (auto& h : *SortedHooks[i + 1])
-// Log::WriteLine("钩子\"%s\",来自\"%s\",相对于\"%s\",位于%08X,长度%d,优先级 %d,次优先级 \"%s\"",
-// h.Proc.c_str(),
-// h.Lib.c_str(),
-// h.RelLib.c_str(),
-// h.Addr,
-// h.Len,
-// h.Priority,
-// h.SubPriority.c_str());
-// if (!Conflict && ShowHookConflictPopup)
-// {
-// wchar_t ErrorStr[1000];
-// swprintf_s(ErrorStr, 1000, L"检测到位于 0x%08X 和 0x%08X 的钩子冲突,详见 Syringe.log 。", Addr1, Addr2);
-// MessageBoxW(NULL, ErrorStr, VersionLString, MB_OK | MB_ICONERROR);
-// }
-// Conflict = true;
-// }
-// }
-// return Conflict;
-// }
-//}
+bool HookAnalyzer::ReportLOG(bool ByAddr, bool ByLib)
+{
+ constexpr auto const VersionString = "SyringeEx " SYRINGEEX_VER_TEXT ", based on Syringe 0.7.2.0";
+
+ FileHandle File = FileHandle(fopen("HookAnalysis.log", "w"));
+ if (!File)return false;
+ fprintf(File, "%s will analyze the specified hooks.\n", VersionString);
+ if (ByAddr)
+ {
+ fputs("========================\n", File);
+ fputs("By Hook Position: (Execution order for each address)\n", File);
+ for (auto& p : ByAddress)
+ {
+ fprintf(File, "At %08X : \n", p.first);
+ for (auto v : p.second)
+ {
+ //fprintf(File, "Hook\"%s, Relative to\"%s\", From\"%s\", %d Bytes Overridden ,Priority %d, Sub Priority \"%s\"\n", v.Proc.c_str(), v.RelLib.c_str(), v.Lib.c_str(), v.Len, v.Priority, v.SubPriority.c_str());
+ fprintf(File, "Hook\"%s, From\"%s\", %d Bytes Overridden\n", v.Proc.c_str(), v.Lib.c_str(), v.Len);
+ }
+ }
+ }
+
+ if (ByLib)
+ {
+ fputs("========================\n", File);
+ fputs("By Hook Source: \n", File);
+ for (auto& p : ByLibName)
+ {
+ fprintf(File, "Analyzing DLL : \"%s\" ……\n", p.first.c_str());
+ for (auto v : p.second)
+ {
+ //fprintf(File, "Hook\"%s, Relative to\"%s\", From\"%s\", %d Bytes Overridden ,Priority %d, Sub Priority \"%s\"\n", v.Proc.c_str(), v.RelLib.c_str(), v.Lib.c_str(), v.Len, v.Priority, v.SubPriority.c_str());
+ fprintf(File, "Hook\"%s, From\"%s\", %d Bytes Overridden\n", v.Proc.c_str(), v.Lib.c_str(), v.Len);
+ }
+ }
+ }
+
+ fputs("========================\n", File);
+ fprintf(File, "%s : Complete.\n", VersionString);
+ return true;
+}
+
+bool HookAnalyzer::ReportNDJSON()
+{
+ //TODO
+ //Until a JSON library is chosen and imported
+ //A format may work :
+ //every line :
+ //Hook Address / Name / Source / Bytes Overridden
+}
+
+bool HookAnalyzer::HasHookConflict(bool ShowHookConflictPopup)
+{
+ //check if there are conflicting hooks
+ bool Conflict = false;
+ for (auto& [lib, byaddr] : ByAddressEx)
+ {
+ std::vector*> SortedHooks;
+ for (auto& p : byaddr)
+ SortedHooks.push_back(&p.second);
+ std::sort(SortedHooks.begin(), SortedHooks.end(), [](const auto& lhs, const auto& rhs) -> bool
+ {
+ return lhs->front().Addr < rhs->front().Addr;
+ });
+ for (size_t i = 0; i < SortedHooks.size() - 1; i++)
+ {
+ auto Addr1 = SortedHooks[i]->front().Addr;
+ auto Addr2 = SortedHooks[i + 1]->front().Addr;
+ auto Len1 = std::max_element(SortedHooks[i]->begin(), SortedHooks[i]->end(), [](const auto& lhs, const auto& rhs) -> bool
+ {
+ return lhs.Len < rhs.Len;
+ })->Len;
+ Len1 = std::max(Len1, 5);//a JMP is 5 bytes
+ if (Addr1 + Len1 > Addr2)
+ {
+ Log::WriteLine("Hook Conflict Detected:");
+ for (auto& v : *SortedHooks[i])
+ //Log::WriteLine("Hook\"%s, Relative to\"%s\", From\"%s\", %d Bytes Overridden ,Priority %d, Sub Priority \"%s\"\n", v.Proc.c_str(), v.RelLib.c_str(), v.Lib.c_str(), v.Len, v.Priority, v.SubPriority.c_str());
+ Log::WriteLine("Hook\"%s, From\"%s\", %d Bytes Overridden\n", v.Proc.c_str(), v.Lib.c_str(), v.Len);
+ for (auto& v : *SortedHooks[i + 1])
+ //Log::WriteLine("Hook\"%s, Relative to\"%s\", From\"%s\", %d Bytes Overridden ,Priority %d, Sub Priority \"%s\"\n", v.Proc.c_str(), v.RelLib.c_str(), v.Lib.c_str(), v.Len, v.Priority, v.SubPriority.c_str());
+ Log::WriteLine("Hook\"%s, From\"%s\", %d Bytes Overridden\n", v.Proc.c_str(), v.Lib.c_str(), v.Len);
+ if (!Conflict && ShowHookConflictPopup)
+ {
+ wchar_t ErrorStr[1000];
+ swprintf_s(ErrorStr, 1000, L"Hook Conflict detected at 0x%08X and 0x%08X , see details in Syringe.log.", Addr1, Addr2);
+ MessageBoxW(NULL, ErrorStr, L"SyringeEx", MB_OK | MB_ICONERROR);
+ }
+ Conflict = true;
+ }
+ }
+ return Conflict;
+ }
+}
bool HookAnalyzer::GenerateINJ()
{
diff --git a/HookAnalyzer.h b/HookAnalyzer.h
index 35c3f83..bfb7c6b 100644
--- a/HookAnalyzer.h
+++ b/HookAnalyzer.h
@@ -31,9 +31,10 @@ class HookAnalyzer
std::unordered_map>> ByAddressEx;
void Add(HookAnalyzeData&& , bool Show);
- bool Report();
+ bool ReportLOG(bool ByAddr, bool ByLib);
+ bool ReportNDJSON();//TODO
bool GenerateINJ();
- bool HasHookConflict();
+ bool HasHookConflict(bool ShowHookConflictPopup);
};
//static constexpr size_t MaxNameLength = 0x100u;
diff --git a/SyringeDebugger.cpp b/SyringeDebugger.cpp
index 61276cf..8dd6848 100644
--- a/SyringeDebugger.cpp
+++ b/SyringeDebugger.cpp
@@ -959,6 +959,25 @@ void SyringeDebugger::RealRun(std::string_view const arguments)
void SyringeDebugger::PreLoadData()
{
+ if (bReportLOG)
+ {
+ Log::WriteLine(__FUNCTION__ ": Writing Hook Analysis Report LOG……", v_AllHooks.size());
+ if(analyzer.ReportLOG(bReportLogByAddress, bReportLogByLibrary))Log::WriteLine(__FUNCTION__ ": Complete, see HookAnalysis.log 。", v_AllHooks.size());
+ else Log::WriteLine(__FUNCTION__ ": Failed to generate.", v_AllHooks.size());
+ }
+
+ if (bReportJSON)
+ {
+ Log::WriteLine(__FUNCTION__ ": Writing Hook Analysis Report JSON……", v_AllHooks.size());
+ if (analyzer.ReportNDJSON())Log::WriteLine(__FUNCTION__ ": Complete, see HookAnalysis.json 。", v_AllHooks.size());
+ else Log::WriteLine(__FUNCTION__ ": Failed to generate.", v_AllHooks.size());
+ }
+
+ if (bDetectConflict)
+ {
+ analyzer.HasHookConflict(bShowHookConflictPopup);
+ }
+
if (bGenerateINJ)
{
Log::WriteLine(__FUNCTION__ ": Creating INJ files...");
diff --git a/SyringeDebugger.h b/SyringeDebugger.h
index 36368dc..0619940 100644
--- a/SyringeDebugger.h
+++ b/SyringeDebugger.h
@@ -40,6 +40,15 @@ class SyringeDebugger
static constexpr std::string_view HANDSHAKES_FLAG = "--handshakes";
static constexpr std::string_view DRYRUN_FLAG = "--dryrun";
static constexpr std::string_view GENERATEINJ_FLAG = "--generate-inj";
+ static constexpr std::string_view REPORT_LOG_FLAG = "--report-log";
+ static constexpr std::string_view REPORT_JSON_FLAG = "--report-json";
+ static constexpr std::string_view DETECT_CONFLICT_FLAG = "--detect-conflict";
+ static constexpr std::string_view SHOW_HOOK_CONFLICT_POPUP_FLAG = "--show-hook-conflict-popup";
+ static constexpr std::string_view NO_BY_ADDRESS_FLAG = "--no-by-address";
+ static constexpr std::string_view NO_BY_LIBRARY_FLAG = "--no-by-library";
+
+
+
public:
SyringeDebugger(std::string_view filename, std::vector flags = {})
@@ -78,6 +87,30 @@ class SyringeDebugger
{
bGenerateINJ = true;
}
+ if (auto const pos = flagView.find(REPORT_LOG_FLAG); pos != std::string_view::npos)
+ {
+ bReportLOG = true;
+ }
+ else if (auto const pos = flagView.find(REPORT_JSON_FLAG); pos != std::string_view::npos)
+ {
+ bReportJSON = true;
+ }
+ else if (auto const pos = flagView.find(DETECT_CONFLICT_FLAG); pos != std::string_view::npos)
+ {
+ bDetectConflict = true;
+ }
+ else if (auto const pos = flagView.find(SHOW_HOOK_CONFLICT_POPUP_FLAG); pos != std::string_view::npos)
+ {
+ bShowHookConflictPopup = true;
+ }
+ else if (auto const pos = flagView.find(NO_BY_ADDRESS_FLAG); pos != std::string_view::npos)
+ {
+ bReportLogByAddress = false;
+ }
+ else if (auto const pos = flagView.find(NO_BY_LIBRARY_FLAG); pos != std::string_view::npos)
+ {
+ bReportLogByLibrary = false;
+ }
else
{
Log::WriteLine(__FUNCTION__ ": Unknown flag \"%.*s\", skipping.", printable(flagView));
@@ -211,6 +244,13 @@ class SyringeDebugger
bool bHandshakes{ false };
bool bDryRun{ false };
bool bGenerateINJ{ false };
+ bool bReportLOG{ false };
+ bool bReportJSON{ false };
+ bool bDetectConflict{ false };
+ bool bShowHookConflictPopup{ false };
+ bool bReportLogByAddress{ true };
+ bool bReportLogByLibrary{ true };
+
bool bDLLsLoaded{ false };
bool bHooksCreated{ false };
From d25421557aea9767b4fcd3d5f5e1b1852afa9a37 Mon Sep 17 00:00:00 2001
From: Ironhammer Std <2482911962@qq.com>
Date: Fri, 15 May 2026 11:47:21 +0800
Subject: [PATCH 6/6] fix a return of HookAnalyzer::HasHookConflict
---
HookAnalyzer.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/HookAnalyzer.cpp b/HookAnalyzer.cpp
index 5f3988a..c729d9e 100644
--- a/HookAnalyzer.cpp
+++ b/HookAnalyzer.cpp
@@ -112,8 +112,8 @@ bool HookAnalyzer::HasHookConflict(bool ShowHookConflictPopup)
Conflict = true;
}
}
- return Conflict;
}
+ return Conflict;
}
bool HookAnalyzer::GenerateINJ()