Add HookAnalyzer Logic#20
Conversation
|
Can you elaborate on what this does? |
|
OK let me explain the rest flags. Dry Run Mode
|
| 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; | ||
| } |
There was a problem hiding this comment.
why do we need to write this in a separate log other than syringe.log?
| 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; | ||
| } No newline at end of file |
There was a problem hiding this comment.
what's the INJ generation for? is there some other tool that uses INJ files, or what's the premise for it?
| 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"; |
There was a problem hiding this comment.
is it a slow operation? is there a reason to make it optional?
I would expect the conflict detection to be always on and outputting to syringe.log
| 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; | ||
| } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
If you think these changes are needed, I will make a new commit for it.
Another thing is that what JSON library should we import ?
the NDJSON format output won't be there until a JSON library is chosen.
Details :
1.
why do we need to write this in a separate log other than syringe.log?
of course we can if you think this is necessary. If you want a why, it is just as it was.
If you think it should be in Syringe.log, we can change the target.
2.
what's the INJ generation for? is there some other tool that uses INJ files, or what's the premise for it?
For there was a INJ generation function.
If you think this is meaningless, a removal will be considered.
3.
is it a slow operation? is there a reason to make it optional?
I would expect the conflict detection to be always on and outputting to syringe.log
I'm sorry to say that again but it is optional because it was optional.
It's OK to let it enabled all the time.
4.
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?
this ReportLOG function is not the thing that detects conflicts.
there should be flags to control the range that ReportLOG outputs, however it isn't here.
" by DLL "just output these hooks DLL after DLL.
Sorting modes are not currently configurable.
There was a problem hiding this comment.
about --report-log :
Another thing is that TaranDahl's SKILL.md still depends on the HookAnalysis.log now and we need the adjusted logic functions similarly when rewritting it.
It enumerates hooks in the configured range. (still cannot configure it in this PR)
(an output format or output target change is OK)
about --detect-conflict :
Now the result is written in Syringe.log.
also you can change it's format and target.
It detects all cross-dll hook conflicts.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
let --detect-conflict always on .. it seems that there may be a few milliseconds and I need a further benchmark.
Most of the time is used to sort the hooks( see std::sort in the function)
And I will try and give the result.
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.
In this PR, they just output all the hooks sorted by addresses and libraries respectively.
for these two arguments , they affects the behavior of --report-log flag.
ByAddr and ByLib should be enabled for various ranges but I haven't implemented these ranges in this repo because the config component is not here.
|
I just try to measure the time cost of function Status Log:
Conflicts detected:
Time (in nanoseconds) : We can consider that the time cost is no more than 1 millisecond. |
|
OK 1 and 3 complete. If there is no separate log, I think we should act quicker for a NDJSON format. |
Context
See Phobos PR #2201
NOTE
all the flags are temporarily stored in the SyringeDebugger class, and maybe we need to move it to another subclass.
HookAnalyzer class is moved from SyringeIH here as it was except a few translations.
HookAnalyzer::ReportNDJSON is not yet implemented until we import a JSON library,and I place the function here just as Kerbiter's wish.
some of the flags are set to default because the coupled components are not here in SyringeEx, so now every hook are set to be shown in the hook analysis.
New & Enhanced Logic :
Components (1) :
HookAnalyzer
New Flags (8) :
Launch Arguments (8) :
--dryrun : run syringe without launching game.
--generate-inj : generate INJ files and place them in .\INJ folder
--report-log : generate a HookAnalysis.log, as it functions in SyringeIH but in English
--no-by-address : Disable the "By Address" part in HookAnalysis.log.
--no-by-library : Disable the "By Library" part in HookAnalysis.log.
--report-json : generate a HookAnalysis.json TODO
--detect-conflict : Detect hook conflict and output to Syringe.log, as it functions in SyringeIH but in English
--show-hook-conflict-popup : Show a popup when --detect-conflict is enabled and a conflict is detected.
In the dry run mode all other 7 flags are available.