-
Notifications
You must be signed in to change notification settings - Fork 19
Add HookAnalyzer Logic #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e4d32f5
5475e50
7d14054
bf6668e
f677f56
d254215
154c7e5
930c208
127e575
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,144 @@ | ||
| #include "HookAnalyzer.h" | ||
| #include "Handle.h" | ||
| //#include "Setting.h" | ||
| #include <filesystem> | ||
| #include "Log.h" | ||
| #include "resource.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(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::ReportLOG(bool ByAddr, bool ByLib) | ||
| { | ||
| Log::WriteLine(__FUNCTION__ ": Hook Analysis "); | ||
| if (ByAddr) | ||
| { | ||
| Log::WriteLine("========================"); | ||
| Log::WriteLine("By Hook Position: (Execution order for each address)"); | ||
| for (auto& p : ByAddress) | ||
| { | ||
| Log::WriteLine("At %08X : ", p.first); | ||
| for (auto v : p.second) | ||
| { | ||
| //Log::WriteLine("Hook\"%s, Relative to\"%s\", From\"%s\", %d Bytes Overridden ,Priority %d, Sub Priority \"%s\"", 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", v.Proc.c_str(), v.Lib.c_str(), v.Len); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (ByLib) | ||
| { | ||
| Log::WriteLine("========================"); | ||
| Log::WriteLine("By Hook Source: "); | ||
| for (auto& p : ByLibName) | ||
| { | ||
| Log::WriteLine("Analyzing DLL : \"%s\" ……", p.first.c_str()); | ||
| for (auto v : p.second) | ||
| { | ||
| //Log::WriteLine("Hook\"%s, Relative to\"%s\", At 0x%08X, From\"%s\", %d Bytes Overridden ,Priority %d, Sub Priority \"%s\"", v.Proc.c_str(), v.RelLib.c_str(), v.Addr, v.Lib.c_str(), v.Len, v.Priority, v.SubPriority.c_str()); | ||
| Log::WriteLine("Hook\"%s, At 0x%08X, From\"%s\", %d Bytes Overridden", v.Proc.c_str(), v.Addr, v.Lib.c_str(), v.Len); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Log::WriteLine("========================"); | ||
| Log::WriteLine(__FUNCTION__ ": Complete. "); | ||
| return true; | ||
| } | ||
|
Comment on lines
+24
to
+60
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this output all hooks or only conflicts? I would expect only conflicts to be outputted, and I feel like they should always be sorted by address? not sure how the by DLL one functions, since the conflicts can (and will) be cross-dll. do we even need any sorting modes?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK let me explain : Sorry to say that I did not redesign the hook analysis module so there might be something that didnt meet your expectations. Details : 1.
of course we can if you think this is necessary. If you want a why, it is just as it was. 2.
3.
I'm sorry to say that again but it is optional because it was optional. 4.
this ReportLOG function is not the thing that detects conflicts.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. about about
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to be sorry, it's alright. On 1 and 3 let's do it then (though I wonder if having it always on will impact startup time a lot, have you checked it?); on 2: I mean I don't mind it in principle, I just wonder what's the specific use case? on 4, sorry, I didn't understand what you mean. I was asking about the ByAddr and ByLib function, and I was also wondering whether the output is only conflicts or something else too.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let On 2 : Currently there is no active use case but it was used before though. Besides, it's just another way to output all the hooks in a more familiar format. On 4 : ByAddr and ByLib not only output the conflicts. They are independent of conflict detection. |
||
|
|
||
| bool HookAnalyzer::ReportNDJSON() | ||
| { | ||
| //TODO | ||
| //Until a JSON library is chosen and imported | ||
| //A format may work : | ||
| //every line : | ||
| //Hook Address / Name / Source / Bytes Overridden | ||
| return true; | ||
| } | ||
|
|
||
| bool HookAnalyzer::HasHookConflict(bool ShowHookConflictPopup) | ||
| { | ||
| //check if there are conflicting hooks | ||
| bool Conflict = false; | ||
| for (auto& [lib, byaddr] : ByAddressEx) | ||
| { | ||
| std::vector<std::vector<HookAnalyzeData>*> 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\", At 0x%08X, From\"%s\", %d Bytes Overridden\n", v.Proc.c_str(), v.Addr, 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\", At 0x%08X, From\"%s\", %d Bytes Overridden\n", v.Proc.c_str(), v.Addr, 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() | ||
| { | ||
| //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 == 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); | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
Comment on lines
+116
to
+144
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what's the INJ generation for? is there some other tool that uses INJ files, or what's the premise for it? |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| #pragma once | ||
|
|
||
| #include<vector> | ||
| #include<unordered_map> | ||
| #include<string> | ||
|
|
||
| const std::string AnalyzerDelim = "\\*^*\\"; | ||
| const int DefaultPriority = 100000; | ||
|
|
||
| struct HookAnalyzeData | ||
| { | ||
| std::string Lib; | ||
| std::string Proc; | ||
| int Addr; | ||
| int Len; | ||
|
|
||
| int Priority{ DefaultPriority }; | ||
| std::string SubPriority{ "" }; | ||
| std::string RelLib{ "" }; | ||
| }; | ||
|
|
||
| class HookAnalyzer | ||
| { | ||
| private: | ||
| std::unordered_map<std::string, std::vector<HookAnalyzeData>> ByLibName; | ||
| std::unordered_map<std::string, std::vector<HookAnalyzeData>> ByLibNameEx; | ||
| public: | ||
| std::unordered_map<std::string, HookAnalyzeData> HookMap; | ||
| std::unordered_map<int, std::vector<HookAnalyzeData>> ByAddress; | ||
| std::unordered_map<std::string, HookAnalyzeData> HookMapEx; | ||
| std::unordered_map<std::string, std::unordered_map<int, std::vector<HookAnalyzeData>>> ByAddressEx; | ||
|
|
||
| void Add(HookAnalyzeData&& , bool Show); | ||
| bool ReportLOG(bool ByAddr, bool ByLib); | ||
| bool ReportNDJSON();//TODO | ||
| bool GenerateINJ(); | ||
| bool HasHookConflict(bool ShowHookConflictPopup); | ||
| }; | ||
|
|
||
| //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]; | ||
| //}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need to write this in a separate log other than syringe.log?