diff --git a/Help/How To.txt b/Help/How To.txt index 5ffee11..148dcb3 100644 Binary files a/Help/How To.txt and b/Help/How To.txt differ diff --git a/Help/Readme.txt b/Help/Readme.txt index be9ca6e..d246568 100644 --- a/Help/Readme.txt +++ b/Help/Readme.txt @@ -32,18 +32,112 @@ R: SRLx32.dll is corrupted, maybe... -I Have Injected the SRLx32.dll in my game, but the Char reloads shows wrong char... R: Maybe you need modify the CreateFont function, break the CreateFont Calls and see the right place to change the font encoding -N: puting a "mov byte ptr [eax+0x17], 0x00" before the CreateFontCall where EAX = the push pointer to the CreateFontIndirect, -N: and 0x00 the Charset, read more here: https://msdn.microsoft.com/en-us/library/cc194829.aspx +N: Try enalbed the CreateFont Hook and set the Charset to 0x00 in the SRL.ini -About the SRL.ini I will explain only what looks needed, run the game with "-help" to se the others value... At StringsReloader -"InEncoding" The Input Encoding; you can use 932/Unicode/utf8/ISO-8859-1 or any shit, google your encoding name... -"OutEncoding" The same; but used to return a matched string... +-"Encoding" Set the InEncoding and OutEncoding the same encoding. -"Wide" True or False; Is the setting to modify the read/write method to Encoding with 16-bits -"AntiCrash" True or False; Is the setting to games who crash on close, this can fix some cases terminating the process on you request to close it. +-"FreeOnExit" A alternative to the AntiCrash -"MatchIgnore" Txt1,Txt2,Txt3; Is a setting to append at the default Match ignore list, every string in the list is ignored by the string match. -"TrimChars" (,),*; Is a setting to append strings to trim from end and begin of every line, this don't affect the return string. +-"Delay" Log the Delay to reload very string +-"Dump" Dump the Strings.srl including the translation +-"DumpRetail" Dump the Strings.srl but don't export the translation +-"Debug" Enable the Debug Output Window +-"LogAll" Verbose mode, log all string reloads +-"LogInput" Log all strings that the game requested the SRL translation +-"LogOutput" Log all strings that the SRL return to the game +-"LogFile" Save the Log window output to the a file (SRL.log) +-"Unsafe" When false the SRL don't initialize while the game don't try load a string that is recognized game as dialogue. +-"Rebuild" Rebuild the Strings.srl every time that the game starts +-"TrimRangeMismatch" Trim from the begin and end all chars from input strings that isn't in the "AcceptableRange" list +-"AcceptableRanges" Acceptable range of chars, use the char: - to specify a range, like 0-9, A-z, you can put a single char too, just don't put the - +-"NoTrim" Disable all trim algorithms of the SRL +-"BreakLine" Set if the game have their own breakline flag, (the default is the 0x0A byte) +-"ReloadedPrefix" Put a prefix in all reloaded lines +-"ReloadedSufix" Put a sufix in all realoaded lines +-"Multithread" Make the SRL optimized for Multithreaded games, when false the SRL create a new process to store their database, keep true +-"WindowHook" Try hook all windows user interface strings and allow translate it +-"Invalidate" If the WindowHook only translate when you put the cursor over the text, enable this +-"CachePointer" Cache the reload and speed up if the game request it again +-"NoDiagCheck" Allways think in a string as a Dialogue, Don't enable with Unsafe=false +-"LiteralMask" Reload strings Mask literally +-"LiveSettings" Reload the SRL.ini without restart the game (Some features require restart) +-"DecodeInputRemap" Restore any char reload in the input string before process +-"MultiDatabase" Create multiple databases to every .lst file, Increase memory usage but speed up the SRL +-"NoReload" Disable the SRL +-"WorkingDir" Set a custom directory as workspace of the SRL, keep empty to use the SRL dll directory +-"ReloadMaskArgs" If a mask contains a string that needs be translated, keep true +-"CustomCredits" Set a custom message during the SRL loading screen +-"LiteMode" Disable many features of the SRL to speed up +-"RemoveViolations" If you put a char in the .lst that is being used by the Char Reloader feature, when true, the SRL will cutoff all 'ilegal' chars +-"AsianInput" Hint the Dialogue Detection algorithm saying if the game is a japanese game or not. +-"CaseSensitive" The SRL database match can match with case senstive or not, just change this +-"NotCachedOnly" Use the pointer cache to don't allow the SRL process again the same string +-"SetOutEncoding" If the Debug Low Window (aka console) display invalid chars, set true +-"AllowEmptyReloads" Keep in the database Reloads that don't change nothing + +At WordWrap +-"Enable" Disable or Enable the SRL Auto Wordwrap engine +-"Monospaced" When false the FontName, FontSize, Bold are required +-"FakeBreakLine" If the engine don't have any breakline char, the fakebreakline full the line with space to automatically break the line where needed +-"FontName" The font face name to be used in the string measure +-"FontSize" The font size to be used in hte string measure (decimal) +-"Bold" If true, the string will measure using bold font +-"MaxWidth" When Monospaced is true, put the max count of characters per line, when false, the max line width in pixels At MTL --Self-Explanatory entries... But to enable the TLib.dll is required in the game directory, you can get it at my github. \ No newline at end of file +-Self-Explanatory entries... But to enable the TLib.dll is required in the game directory, contact-me + +At Overlay (Required the Overlay.dll in the directory) +-"Enabled" Enable or Disable the Overlay +-"Padding" Set a default overlay padding + +At Filter (Dialogue Detection algorithm) +-"DenyList" List of all characters that never will appear in a dialogue (split with ,) +-"QuoteList" List of all quotes that appears in the game (split with ,) +-"IgnoreList" List of things to ignore when try detect if is a dialogue +-"TrimList" List of characters that can appears in the begin or end of a string that needs be removed before process the dialogue +-"Sensitivity" The dialogue sensitivity level, (can use negative values), bigger values are more 'permessive' than smaller values (5 is recommended) +-"UseDB" If the string is present in the database is automatically accepted as dialogue +-"ForceTrim" If you enable the "NoTrim" feature, can enable this to reenable the trim only to verify if is a dialogue + +At Intro +-"MinSize" Minimal Window Width and Height to show the introduction +-"Seconds" The seconds to show the introduction screen +-"CheckProportion" A alternative to the MinSize, Only show the introduction when the Width is bigger than the Height +-"CreateWindowEx" Hook the CreateWindowEx to show the Intro +-"ShowWindow" Hook the ShowWindow to show the intro (Recommended) +-"SetWindowPos" Hook the SetWindowPost to show the Intro +-"MoveWindow" Hook the MoveWindow to show the Intro + +At Hook +-"CreateFile" Hook the game file reading and allow he read files from the SRL worspace or a directory called "Patch" +-"UndoChars" Undo the char reload in the MultiByteToWideChar, TextOut and ExtTextOut hooks +-"MultibyteToWideChar" Hook the MultibyteToWideChar and reload the string +-"SetWindowText" Hook the SetWindowText and reload the string +-"GetGlyphOutline" Hook the "GetGlyphOutline" and reload the character +-"TextOut" Hook the TextOut and reload the string +-"ExtTextOut" Hook the ExtTextOut and reload the string +-"CreateFont" Hook the CreateFontA and CreateFontW and allow modify the game font +-"CreateFontIndirect" Hook the CreateFontIndirectA and the CreateFontIndirectW and allow modify the game font +-"FontCharset" Modify the Font Charset +-"FaceName" Modify all fonts facename + +At [Hook.Font.?] (You can create any amount of font remap, just put Hook.Font.0, Hook.Font.1, Hook.Font.2, Hook.Font.3... and etc) +-"FromFont" The original font facename to replace (keep * to all fonts) +-"ToFont" The modified font facename to force the game load +-"Size" Try modify the font size (accept relative values, +10, -10... and absolute values 32, 20, 24) + +-How to use the Intro +R: To the intro hook catch the game initilization it's obvious, the SRL needs initialize before the game, +N: If the SRL have a delayed initialization try rename the SRLx32.dll to d3d9.dll, and modify the game exe to load the d3d9.dll and not the old SRLx32.dll + +-I have 2 identic lines that but I don't want the same translation to both +R: Split the .LST in 2 files, the .lst format don't support duplicated lines, then put one of those lines in a new .lst file +N: If you put ::SETDB-Sample:: in the first of the line translation, the SRL will change to the "Strings-Sample.lst" after match the current string, with this you can translate a duplicate that appears one after other \ No newline at end of file diff --git a/SRL/FileWorker.cs b/SRL/FileWorker.cs index 6077cf8..ec87d27 100644 --- a/SRL/FileWorker.cs +++ b/SRL/FileWorker.cs @@ -131,6 +131,7 @@ private static void LoadConfig() { ForceTrim = false; NotCachedOnly = false; AllowEmpty = false; + ImportHook = false; HookCreateWindowEx = false; HookShowWindow = false; HookSetWindowPos = false; @@ -628,6 +629,12 @@ private static void LoadConfig() { Log("Intro Injector Proportion Validator Enabled", true); } + if (HookSettings.ImportHook) + { + ImportHook = true; + Log("Import Table Hook Method Enabled", true); + } + if (IntroSettings.Seconds > 0) Seconds = IntroSettings.Seconds; diff --git a/SRL/Hook/FileHook.cs b/SRL/Hook/FileHook.cs index b544ee5..9ab8248 100644 --- a/SRL/Hook/FileHook.cs +++ b/SRL/Hook/FileHook.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Runtime.InteropServices; namespace SRL @@ -15,12 +14,13 @@ static void InstallCreateFileHooks() dCreateFileA = new CreateFileADelegate(CreateFile); dCreateFileW = new CreateFileWDelegate(CreateFile); - hCreateFileA = new FxHook("kernel32.dll", "CreateFileA", dCreateFileA); - hCreateFileW = new FxHook("kernel32.dll", "CreateFileW", dCreateFileW); - hGetFileAttrA = new FxHook("kernel32.dll", "GetFileAttributesA", dGetFileAttrA); - hGetFileAttrW = new FxHook("kernel32.dll", "GetFileAttributesW", dGetFileAttrW); - hGetFileAttrExA = new FxHook("kernel32.dll", "GetFileAttributesExA", dGetFileAttrExA); - hGetFileAttrExW = new FxHook("kernel32.dll", "GetFileAttributesExW", dGetFileAttrExW); + hCreateFileA = AutoHookCreator("kernel32.dll", "CreateFileA", dCreateFileA); + hCreateFileW = AutoHookCreator("kernel32.dll", "CreateFileW", dCreateFileW); + hGetFileAttrA = AutoHookCreator("kernel32.dll", "GetFileAttributesA", dGetFileAttrA); + hGetFileAttrW = AutoHookCreator("kernel32.dll", "GetFileAttributesW", dGetFileAttrW); + hGetFileAttrExA = AutoHookCreator("kernel32.dll", "GetFileAttributesExA", dGetFileAttrExA); + hGetFileAttrExW = AutoHookCreator("kernel32.dll", "GetFileAttributesExW", dGetFileAttrExW); + hCreateFileA.Install(); hCreateFileW.Install(); @@ -87,12 +87,12 @@ static string ParsePath(string Path) static CreateFileADelegate dCreateFileA; static CreateFileWDelegate dCreateFileW; - static FxHook hGetFileAttrA; - static FxHook hGetFileAttrW; - static FxHook hGetFileAttrExA; - static FxHook hGetFileAttrExW; - static FxHook hCreateFileA; - static FxHook hCreateFileW; + static UnmanagedHook hGetFileAttrA; + static UnmanagedHook hGetFileAttrW; + static UnmanagedHook hGetFileAttrExA; + static UnmanagedHook hGetFileAttrExW; + static UnmanagedHook hCreateFileA; + static UnmanagedHook hCreateFileW; [UnmanagedFunctionPointer(CallingConvention.Winapi, CharSet = CharSet.Ansi, SetLastError = true)] delegate uint GetFileAttributesADelegate([MarshalAs(UnmanagedType.LPStr)] string Filepath); diff --git a/SRL/Hook/HookFX.cs b/SRL/Hook/HookFX.cs deleted file mode 100644 index 842ef6a..0000000 --- a/SRL/Hook/HookFX.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Text; -using System.Runtime.InteropServices; - -public class FxHook : IDisposable { - - static int nBytes = IntPtr.Size == 8 ? 12 : 5; - - IntPtr addr; - Protection old; - byte[] src = new byte[nBytes]; - byte[] dst = new byte[nBytes]; - - public FxHook(IntPtr source, IntPtr destination) { - VirtualProtect(source, nBytes, Protection.PAGE_EXECUTE_READWRITE, out old); - Marshal.Copy(source, src, 0, nBytes); - if (IntPtr.Size == 8) { - //x64 - new byte[] { 0x48, 0xb8 }.CopyTo(dst, 0); - BitConverter.GetBytes(unchecked((ulong)destination.ToInt64())).CopyTo(dst, 2); - new byte[] { 0xFF, 0xE0 }.CopyTo(dst, 10); - } else { - //x86 - dst[0] = 0xE9; - var Result = (int)(destination.ToInt64() - source.ToInt64() - nBytes); - var dx = BitConverter.GetBytes(Result); - Array.Copy(dx, 0, dst, 1, nBytes - 1); - } - addr = source; - } - public FxHook(IntPtr source, Delegate destination) : this(source, Marshal.GetFunctionPointerForDelegate(destination)) { - } - - public FxHook(string library, string function, Delegate destination) : this(GetProcAddress(LoadLibrary(library), function), destination) { - } - - public void Install() { - Marshal.Copy(dst, 0, addr, nBytes); - } - - public void Uninstall() { - Marshal.Copy(src, 0, addr, nBytes); - } - - public void Dispose() { - Uninstall(); - Protection x; - VirtualProtect(addr, nBytes, old, out x); - } - - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool VirtualProtect(IntPtr lpAddress, int dwSize, Protection flNewProtect, out Protection lpflOldProtect); - - [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] - static extern IntPtr GetProcAddress(IntPtr hModule, string procName); - - [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] - static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName); - - public enum Protection { - PAGE_NOACCESS = 0x01, - PAGE_READONLY = 0x02, - PAGE_READWRITE = 0x04, - PAGE_WRITECOPY = 0x08, - PAGE_EXECUTE = 0x10, - PAGE_EXECUTE_READ = 0x20, - PAGE_EXECUTE_READWRITE = 0x40, - PAGE_EXECUTE_WRITECOPY = 0x80, - PAGE_GUARD = 0x100, - PAGE_NOCACHE = 0x200, - PAGE_WRITECOMBINE = 0x400 - } - -} \ No newline at end of file diff --git a/SRL/Hook/IntroInjector.cs b/SRL/Hook/IntroInjector.cs index c4113a9..c1b6648 100644 --- a/SRL/Hook/IntroInjector.cs +++ b/SRL/Hook/IntroInjector.cs @@ -14,45 +14,40 @@ static partial class StringReloader { #if !DEBUG static CreateWindowExADelegate CreateWindowExADel; static CreateWindowExWDelegate CreateWindowExWDel; - static FxHook CreateWindowExAHook; - static FxHook CreateWindowExWHook; + static UnmanagedHook CreateWindowExAHook; + static UnmanagedHook CreateWindowExWHook; #endif static ShowWindowDelegate ShowWindowDel; static SetWindowPosDelegate SetWindowPosDel; static MoveWindowDelegate MoveWindowDel; - static FxHook ShowWindowHook; - static FxHook SetWindowPosHook; - static FxHook MoveWindowHook; + static UnmanagedHook ShowWindowHook; + static UnmanagedHook SetWindowPosHook; + static UnmanagedHook MoveWindowHook; - static bool SysCall = true; static void InstallIntroInjector() { if (ShowWindowHook != null) return; #if !DEBUG CreateWindowExADel = new CreateWindowExADelegate(hCreateWindowEx); CreateWindowExWDel = new CreateWindowExWDelegate(hCreateWindowEx); - CreateWindowExAHook = new FxHook("user32.dll", "CreateWindowExA", CreateWindowExADel); - CreateWindowExWHook = new FxHook("user32.dll", "CreateWindowExW", CreateWindowExWDel); + CreateWindowExAHook = AutoHookCreator("user32.dll", "CreateWindowExA", CreateWindowExADel); + CreateWindowExWHook = AutoHookCreator("user32.dll", "CreateWindowExW", CreateWindowExWDel); if (HookCreateWindowEx) CreateWindowExADel = new CreateWindowExADelegate(hCreateWindowEx); #endif - SysCall = !ValidLibrary("win32u.dll"); - - Log($"Intro Injector SysCall Support {(SysCall ? "Enabled" : "Disabled")}", true); - ShowWindowDel = new ShowWindowDelegate(hShowWindow); - ShowWindowHook = new FxHook("user32.dll", "ShowWindow", ShowWindowDel); + ShowWindowHook = AutoHookCreator("user32.dll", "ShowWindow", ShowWindowDel); if (HookShowWindow) ShowWindowHook.Install(); SetWindowPosDel = new SetWindowPosDelegate(hSetWindowPos); - SetWindowPosHook = new FxHook("user32.dll", "SetWindowPos", SetWindowPosDel); + SetWindowPosHook = AutoHookCreator("user32.dll", "SetWindowPos", SetWindowPosDel); if (HookSetWindowPos) SetWindowPosHook.Install(); MoveWindowDel = new MoveWindowDelegate(hMoveWindow); - MoveWindowHook = new FxHook("user32.dll", "MoveWindow", MoveWindowDel); + MoveWindowHook = AutoHookCreator("user32.dll", "MoveWindow", MoveWindowDel); if (HookMoveWindow) MoveWindowHook.Install(); @@ -60,60 +55,59 @@ static void InstallIntroInjector() { } static bool IntroInitialized = false; - static bool hShowWindow(IntPtr hWnd, int nCmdShow) { - if (SysCall) - { + static bool hShowWindow(IntPtr hWnd, int nCmdShow) + { + if (!ShowWindowHook.ImportHook) ShowWindowHook.Uninstall(); - bool Rst = ShowWindow(hWnd, nCmdShow); - ShowWindowHook.Install(); - if (nCmdShow != SW_HIDE) - ShowIntro(hWnd); + bool Rst = ShowWindow(hWnd, nCmdShow); - return Rst; - } - - bool Result = NtUserShowWindow(hWnd, nCmdShow); + if (!ShowWindowHook.ImportHook) + ShowWindowHook.Install(); if (nCmdShow != SW_HIDE) ShowIntro(hWnd); - return Result; + return Rst; } - static bool hSetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags) { - if (SysCall) - { + static bool hSetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags uFlags) + { + if (!SetWindowPosHook.ImportHook) SetWindowPosHook.Uninstall(); - bool Rst = SetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags); - SetWindowPosHook.Install(); - ShowIntro(hWnd); - return Rst; - } - bool Result = NtUserSetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags); + bool Rst = SetWindowPos(hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags); + + if (!SetWindowPosHook.ImportHook) + SetWindowPosHook.Install(); ShowIntro(hWnd); - return Result; + + return Rst; } - static bool hMoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint) { - if (SysCall) - { + static bool hMoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint) + { + if (!MoveWindowHook.ImportHook) MoveWindowHook.Uninstall(); - bool Rst = MoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint); + + bool Rst = MoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint); + + if (!MoveWindowHook.ImportHook) MoveWindowHook.Install(); - ShowIntro(hWnd); - return Rst; - } - bool Result = NtUserMoveWindow(hWnd, X, Y, nWidth, nHeight, bRepaint); ShowIntro(hWnd); - return Result; + + return Rst; } - static IntPtr hCreateWindowEx(WindowStylesEx dwExStyle, string lpClassName, string lpWindowName, WindowStyles dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam) { - CreateWindowExWHook.Uninstall(); + static IntPtr hCreateWindowEx(WindowStylesEx dwExStyle, string lpClassName, string lpWindowName, WindowStyles dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam) + { + if (!CreateWindowExWHook.ImportHook) + CreateWindowExWHook.Uninstall(); + IntPtr Result = CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); - CreateWindowExWHook.Install(); + + if (!CreateWindowExWHook.ImportHook) + CreateWindowExWHook.Install(); ShowIntro(Result); return Result; } @@ -330,7 +324,13 @@ static Bitmap SetBitmapOpacity(Bitmap image, float opacity) { } } - static bool ValidLibrary(string fileName) => LoadLibrary(fileName) != IntPtr.Zero; + static bool ValidExport(string Module, string Function) + { + var hModule = LoadLibrary(Module); + if (hModule == IntPtr.Zero) + return false; + return GetProcAddress(hModule, Function) != IntPtr.Zero; + } struct IntroHelper { public Bitmap[] Fade; diff --git a/SRL/Hook/TextHook.cs b/SRL/Hook/TextHook.cs index b1ba3bb..86c8d50 100644 --- a/SRL/Hook/TextHook.cs +++ b/SRL/Hook/TextHook.cs @@ -26,36 +26,36 @@ static partial class StringReloader { static SetWindowTextADelegate dSetWindowTextA; static SetWindowTextWDelegate dSetWindowTextW; - static FxHook OutlineA; - static FxHook OutlineW; - static FxHook hTextOutA; - static FxHook hTextOutW; - static FxHook hExtTextOutA; - static FxHook hExtTextOutW; - static FxHook hCreatFontA; - static FxHook hCreatFontW; - static FxHook hCreatFontIndirectA; - static FxHook hCreatFontIndirectW; + static UnmanagedHook OutlineA; + static UnmanagedHook OutlineW; + static UnmanagedHook hTextOutA; + static UnmanagedHook hTextOutW; + static UnmanagedHook hExtTextOutA; + static UnmanagedHook hExtTextOutW; + static UnmanagedHook hCreatFontA; + static UnmanagedHook hCreatFontW; + static UnmanagedHook hCreatFontIndirectA; + static UnmanagedHook hCreatFontIndirectW; #if DEBUG - static FxHook hSendMessageA; - static FxHook hSendMessageW; - static FxHook hCreateWindowExA; - static FxHook hCreateWindowExW; - static FxHook hCreateWindowA; - static FxHook hCreateWindowW; + static UnmanagedHook hSendMessageA; + static UnmanagedHook hSendMessageW; + static UnmanagedHook hCreateWindowExA; + static UnmanagedHook hCreateWindowExW; + static UnmanagedHook hCreateWindowA; + static UnmanagedHook hCreateWindowW; #endif - static FxHook hSetWindowTextA; - static FxHook hSetWindowTextW; + static UnmanagedHook hSetWindowTextA; + static UnmanagedHook hSetWindowTextW; - static FxHook hMultiByteToWideChar; + static UnmanagedHook hMultiByteToWideChar; static void InstallGlyphHooks() { dOutlineA = new GetGlyphOutlineDelegate(hGetGlyphOutlineA); dOutlineW = new GetGlyphOutlineDelegate(hGetGlyphOutlineW); - OutlineA = new FxHook("gdi32.dll", "GetGlyphOutlineA", dOutlineA); - OutlineW = new FxHook("gdi32.dll", "GetGlyphOutlineW", dOutlineW); + OutlineA = AutoHookCreator("gdi32.dll", "GetGlyphOutlineA", dOutlineA); + OutlineW = AutoHookCreator("gdi32.dll", "GetGlyphOutlineW", dOutlineW); OutlineA.Install(); OutlineW.Install(); @@ -65,18 +65,19 @@ static void InstallTextOutHooks() { dTextOutA = new TextOutADelegate(hTextOut); dTextOutW = new TextOutWDelegate(hTextOut); - hTextOutA = new FxHook("gdi32.dll", "TextOutA", dTextOutA); - hTextOutW = new FxHook("gdi32.dll", "TextOutW", dTextOutW); + hTextOutA = AutoHookCreator("gdi32.dll", "TextOutA", dTextOutA); + hTextOutW = AutoHookCreator("gdi32.dll", "TextOutW", dTextOutW); hTextOutA.Install(); hTextOutW.Install(); } + static void InstallExtTextOutHooks() { dExtTextOutA = new ExtTextOutADelegate(hExtTextOut); dExtTextOutW = new ExtTextOutWDelegate(hExtTextOut); - hExtTextOutA = new FxHook("gdi32.dll", "ExtTextOutA", dExtTextOutA); - hExtTextOutW = new FxHook("gdi32.dll", "ExtTextOutW", dExtTextOutW); + hExtTextOutA = AutoHookCreator("gdi32.dll", "ExtTextOutA", dExtTextOutA); + hExtTextOutW = AutoHookCreator("gdi32.dll", "ExtTextOutW", dExtTextOutW); hExtTextOutA.Install(); hExtTextOutW.Install(); @@ -86,8 +87,8 @@ static void InstallCreateFontHooks() { dCreateFontA = new CreateFontADelegate(hCreateFont); dCreateFontW = new CreateFontWDelegate(hCreateFont); - hCreatFontA = new FxHook("gdi32.dll", "CreateFontA", dCreateFontA); - hCreatFontW = new FxHook("gdi32.dll", "CreateFontW", dCreateFontW); + hCreatFontA = AutoHookCreator("gdi32.dll", "CreateFontA", dCreateFontA); + hCreatFontW = AutoHookCreator("gdi32.dll", "CreateFontW", dCreateFontW); hCreatFontA.Install(); hCreatFontW.Install(); @@ -98,8 +99,8 @@ static void InstallCreateFontIndirectHooks() { dCreateFontIndirectW = new CreateFontIndirectWDelegate(hCreateFontIndirectW); - hCreatFontIndirectA = new FxHook("gdi32.dll", "CreateFontIndirectA", dCreateFontIndirectA); - hCreatFontIndirectW = new FxHook("gdi32.dll", "CreateFontIndirectW", dCreateFontIndirectW); + hCreatFontIndirectA = AutoHookCreator("gdi32.dll", "CreateFontIndirectA", dCreateFontIndirectA); + hCreatFontIndirectW = AutoHookCreator("gdi32.dll", "CreateFontIndirectW", dCreateFontIndirectW); hCreatFontIndirectA.Install(); hCreatFontIndirectW.Install(); @@ -110,8 +111,8 @@ static void InstallSendMessageHooks() { dSendMessageA = new SendMessageADelegate(SendMessageAHook); dSendMessageW = new SendMessageWDelegate(SendMessageWHook); - hSendMessageA = new FxHook("user32.dll", "SendMessageA", dSendMessageA); - hSendMessageW = new FxHook("user32.dll", "SendMessageW", dSendMessageW); + hSendMessageA = AutoHookCreator("user32.dll", "SendMessageA", dSendMessageA); + hSendMessageW = AutoHookCreator("user32.dll", "SendMessageW", dSendMessageW); hSendMessageA.Install(); hSendMessageW.Install(); @@ -121,8 +122,8 @@ static void InstallCreateWindowHooks() { dCreateWindowA = new CreateWindowADelegate(CreateWindow); dCreateWindowW = new CreateWindowWDelegate(CreateWindow); - hCreateWindowA = new FxHook("user32.dll", "CreateWindowA", dCreateWindowA); - hCreateWindowW = new FxHook("user32.dll", "CreateWindowW", dCreateWindowW); + hCreateWindowA = AutoHookCreator("user32.dll", "CreateWindowA", dCreateWindowA); + hCreateWindowW = AutoHookCreator("user32.dll", "CreateWindowW", dCreateWindowW); hCreateWindowA.Install(); hCreateWindowW.Install(); @@ -132,8 +133,8 @@ static void InstallCreateWindowExHooks() { dCreateWindowExA = new CreateWindowExADelegate(CreateWindowEx); dCreateWindowExW = new CreateWindowExWDelegate(CreateWindowEx); - hCreateWindowExA = new FxHook("user32.dll", "CreateWindowExA", dCreateWindowExA); - hCreateWindowExW = new FxHook("user32.dll", "CreateWindowExW", dCreateWindowExW); + hCreateWindowExA = AutoHookCreator("user32.dll", "CreateWindowExA", dCreateWindowExA); + hCreateWindowExW = AutoHookCreator("user32.dll", "CreateWindowExW", dCreateWindowExW); hCreateWindowExA.Install(); hCreateWindowExW.Install(); @@ -144,8 +145,8 @@ static void InstallSetWindowTextHooks() { dSetWindowTextA = new SetWindowTextADelegate(SetWindowTextHook); dSetWindowTextW = new SetWindowTextWDelegate(SetWindowTextHook); - hSetWindowTextA = new FxHook("user32.dll", "SetWindowTextA", dSetWindowTextA); - hSetWindowTextW = new FxHook("user32.dll", "SetWindowTextW", dSetWindowTextW); + hSetWindowTextA = AutoHookCreator("user32.dll", "SetWindowTextA", dSetWindowTextA); + hSetWindowTextW = AutoHookCreator("user32.dll", "SetWindowTextW", dSetWindowTextW); hSetWindowTextA.Install(); hSetWindowTextW.Install(); @@ -154,7 +155,7 @@ static void InstallSetWindowTextHooks() { static void InstallMultiByteToWideChar() { dMultiByteToWideChar = new MultiByteToWideCharDelegate(MultiByteToWideCharHook); - hMultiByteToWideChar = new FxHook("kernel32.dll", "MultiByteToWideChar", dMultiByteToWideChar); + hMultiByteToWideChar = AutoHookCreator("kernel32.dll", "MultiByteToWideChar", dMultiByteToWideChar); hMultiByteToWideChar.Install(); } @@ -167,6 +168,8 @@ public static uint hGetGlyphOutlineA(IntPtr hdc, uint uChar, uint uFormat, out G if (Debugging) Log("OutlineA Hooked, {0:X4}", true, uChar); #endif + if (OutlineA.ImportHook) + return GetGlyphOutlineA(hdc, uChar, uFormat, out lpgm, cbBuffer, lpvBuffer, ref lpmat2); OutlineA.Uninstall(); uint Ret = GetGlyphOutlineA(hdc, uChar, uFormat, out lpgm, cbBuffer, lpvBuffer, ref lpmat2); @@ -181,6 +184,9 @@ public static uint hGetGlyphOutlineW(IntPtr hdc, uint uChar, uint uFormat, out G Log("OutlineW Hooked, {0:X4}", true, uChar); #endif + if (OutlineW.ImportHook) + return GetGlyphOutlineW(hdc, uChar, uFormat, out lpgm, cbBuffer, lpvBuffer, ref lpmat2); + OutlineW.Uninstall(); uint Ret = GetGlyphOutlineW(hdc, uChar, uFormat, out lpgm, cbBuffer, lpvBuffer, ref lpmat2); OutlineW.Install(); @@ -188,7 +194,7 @@ public static uint hGetGlyphOutlineW(IntPtr hdc, uint uChar, uint uFormat, out G } public static bool hTextOut(IntPtr hdc, int nXStart, int nYStart, string lpString, int cbString) { - lpString = ProcessManaged(lpString, false); + lpString = Process(lpString); if (UndoChars) { for (int i = 0; i < lpString.Length; i++) { char C = lpString[i]; @@ -205,10 +211,11 @@ public static bool hTextOut(IntPtr hdc, int nXStart, int nYStart, string lpStrin } } -#if DEBUG - if (Debugging) + if (LogInput) Log("TextOut Hooked, {0}", true, lpString); -#endif + + if (hTextOutW.ImportHook) + return TextOutW(hdc, nXStart, nYStart, lpString, cbString); hTextOutW.Uninstall(); bool Rst = TextOutW(hdc, nXStart, nYStart, lpString, cbString); @@ -217,7 +224,7 @@ public static bool hTextOut(IntPtr hdc, int nXStart, int nYStart, string lpStrin } public static bool hExtTextOut(IntPtr hdc, int X, int Y, uint fuOptions, ref RECT lprc, string lpString, uint cbCount, IntPtr lpDx) { - lpString = ProcessManaged(lpString, false); + lpString = Process(lpString); if (UndoChars) { for (int i = 0; i < lpString.Length; i++) { char C = lpString[i]; @@ -234,10 +241,13 @@ public static bool hExtTextOut(IntPtr hdc, int X, int Y, uint fuOptions, ref REC } } -#if DEBUG - if (Debugging) + + if (LogInput) Log("ExtTextOut Hooked, {0}", true, lpString); -#endif + + + if (hExtTextOutW.ImportHook) + return ExtTextOutW(hdc, X, Y, fuOptions, ref lprc, lpString, cbCount, lpDx); hExtTextOutW.Uninstall(); bool Rst = ExtTextOutW(hdc, X, Y, fuOptions, ref lprc, lpString, cbCount, lpDx); @@ -265,10 +275,11 @@ static IntPtr hCreateFont(int nHeight, int nWidth, int nEscapement, int nOrienta fdwCharSet = FontCharset; -#if DEBUG - if (Debugging) + if (LogInput) Log("CreateFont Hooked, {0} 0x{1:X2}", true, lpszFace, fdwCharSet); -#endif + + if (hCreateFileW.ImportHook) + return CreateFontW(nHeight, nWidth, nEscapement, nOrientation, fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet, fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily, lpszFace); hCreatFontW.Uninstall(); var Result = CreateFontW(nHeight, nWidth, nEscapement, nOrientation, fnWeight, fdwItalic, fdwUnderline, fdwStrikeOut, fdwCharSet, fdwOutputPrecision, fdwClipPrecision, fdwQuality, fdwPitchAndFamily, lpszFace); @@ -296,11 +307,11 @@ static IntPtr hCreateFontIndirectA(ref LOGFONTA FontInfo) { if (FontCharset != 0) FontInfo.lfCharSet = FontCharset; - -#if DEBUG - if (Debugging) + if (LogInput) Log("CreateIndirectA Hooked, {0} 0x{1:X2}", true, FontInfo.lfFaceName, FontInfo.lfCharSet); -#endif + + if (hCreatFontIndirectA.ImportHook) + return CreateFontIndirectA(ref FontInfo); hCreatFontIndirectA.Uninstall(); var Result = CreateFontIndirectA(ref FontInfo); @@ -326,11 +337,11 @@ static IntPtr hCreateFontIndirectW(ref LOGFONTW FontInfo) { if (FontCharset != 0) FontInfo.lfCharSet = FontCharset; - -#if DEBUG - if (Debugging) + if (LogInput) Log("CreateIndirectW Hooked, {0} 0x{1:X2}", true, FontInfo.lfFaceName, FontInfo.lfCharSet); -#endif + + if (hCreatFontIndirectW.ImportHook) + return CreateFontIndirectW(ref FontInfo); hCreatFontIndirectW.Uninstall(); var Result = CreateFontIndirectW(ref FontInfo); @@ -352,6 +363,10 @@ static Int32 SendMessageWHook(int hWnd, int Msg, int wParam, IntPtr lParam) { lParam = GenString(Reload, true); } } + + if (hSendMessageW.ImportHook) + return SendMessageW(hWnd, Msg, wParam, lParam); + hSendMessageW.Uninstall(); var Rst = SendMessageW(hWnd, Msg, wParam, lParam); hSendMessageW.Install(); @@ -369,6 +384,10 @@ static Int32 SendMessageAHook(int hWnd, int Msg, int wParam, IntPtr lParam) { lParam = GenString(Reload); } } + + if (hSendMessageA.ImportHook) + return SendMessageA(hWnd, Msg, wParam, lParam); + hSendMessageA.Uninstall(); var Rst = SendMessageA(hWnd, Msg, wParam, lParam); hSendMessageA.Install(); @@ -381,8 +400,11 @@ static IntPtr CreateWindowEx(WindowStylesEx dwExStyle, string lpClassName, strin string Reload = StrMap(lpWindowName, IntPtr.Zero, true); + if (hCreateWindowExW.ImportHook) + return CreateWindowExW(dwExStyle, lpClassName, Reload, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + hCreateWindowExW.Uninstall(); - var Rst = CreateWindowExW(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + var Rst = CreateWindowExW(dwExStyle, lpClassName, Reload, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); hCreateWindowExW.Install(); return Rst; } @@ -392,8 +414,11 @@ static IntPtr CreateWindow(string lpClassName, string lpWindowName, uint dwStyle string Reload = StrMap(lpWindowName, IntPtr.Zero, true); + if (hCreateWindowExW.ImportHook) + return CreateWindowW(lpClassName, Reload, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + hCreateWindowExW.Uninstall(); - var Rst = CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + var Rst = CreateWindowW(lpClassName, Reload, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); hCreateWindowExW.Install(); return Rst; } @@ -401,6 +426,9 @@ static IntPtr CreateWindow(string lpClassName, string lpWindowName, uint dwStyle static bool SetWindowTextHook(IntPtr hwnd, string lpString) { lpString = StrMap(lpString, IntPtr.Zero, true); + if (hSetWindowTextW.ImportHook) + return SetWindowTextW(hwnd, lpString); + hSetWindowTextW.Uninstall(); var Ret = SetWindowTextW(hwnd, lpString); hSetWindowTextW.Install(); @@ -408,10 +436,14 @@ static bool SetWindowTextHook(IntPtr hwnd, string lpString) { } static int MultiByteToWideCharHook(int Codepage, uint dwFlags, IntPtr Input, int cbMultiByte, IntPtr Output, int cchWideChar) { - hMultiByteToWideChar.Uninstall(); + + if (!hMultiByteToWideChar.ImportHook) + hMultiByteToWideChar.Uninstall(); + if (!Initialized || cbMultiByte == 0) { int Rst = MultiByteToWideChar(Codepage, dwFlags, Input, cbMultiByte, Output, cchWideChar); - hMultiByteToWideChar.Install(); + if (!hMultiByteToWideChar.ImportHook) + hMultiByteToWideChar.Install(); return Rst; } string Str = GetString(Input, Len: cbMultiByte == -1 ? null : (int?)cbMultiByte, CP: Codepage); @@ -420,15 +452,19 @@ static int MultiByteToWideCharHook(int Codepage, uint dwFlags, IntPtr Input, int if (RStr == Str) { int Rst = MultiByteToWideChar(Codepage, dwFlags, Input, cbMultiByte, Output, cchWideChar); - hMultiByteToWideChar.Install(); + if (!hMultiByteToWideChar.ImportHook) + hMultiByteToWideChar.Install(); return Rst; } - Log("MBTWC Hook: {0}", true, RStr); + if (LogInput) + Log("MBTWC Hook: {0}", true, RStr); Output = GenString(RStr, true, Output == IntPtr.Zero ? null : (IntPtr?)Output); - hMultiByteToWideChar.Install(); + if (!hMultiByteToWideChar.ImportHook) + hMultiByteToWideChar.Install(); + return cchWideChar; } diff --git a/SRL/Hook/UmanagedHook.cs b/SRL/Hook/UmanagedHook.cs new file mode 100644 index 0000000..29743b5 --- /dev/null +++ b/SRL/Hook/UmanagedHook.cs @@ -0,0 +1,883 @@ +//Original Repo of this class: https://github.com/marcussacana/RemoteControl +using System; +using System.Runtime.InteropServices; +using System.Reflection.Emit; +using System.Linq; +using System.Reflection; +using static SRL.UnmanagedImports; +using System.Collections.Generic; +using System.Diagnostics; + +namespace SRL +{ + public struct ImportEntry + { + + /// + /// The Imported Module Name + /// + public string Module; + + /// + /// The Imported Function Name + /// + public string Function; + + /// + /// The Import Ordinal Hint + /// + public ushort Ordinal; + + /// + /// The Address of this Import in the IAT (Import Address Table) + /// + public IntPtr ImportAddress; + + /// + /// The Address of the Imported Function + /// + public IntPtr FunctionAddress; + } + + public class UnmanagedHook : UnmanagedHook { + + /// + /// Create a new hook to the function in given pointer + /// + /// The pointer of the unmanaged function to hook + /// The delegate with the hook function + public UnmanagedHook(IntPtr Original, Delegate Hook) : base(Original, Hook, false) { } + + /// Create a new Hook + /// + /// The Library name, Ex: Kernel32.dll + /// The Function name, Ex: CreateFile + /// The delegate wit the hook function + public UnmanagedHook(string Library, string Function, Delegate Hook) : base(Library, Function, Hook, false) { } + + /// Create a new Hook + /// + /// The Import Entry to install the hook + /// The delegate wit the hook function + + public UnmanagedHook(ImportEntry Import, Delegate Hook) : base(Import, Hook) { } + + /// + /// Enumarete all imports of a specified process main module + /// + /// The process that have loaded the module + /// All Import Entries + public static ImportEntry[] GetImports() => GetModuleImports(Process.GetCurrentProcess().MainModule.BaseAddress); + + /// + /// Create a hook by Import if possible + /// + /// + /// + /// + /// + public static UnmanagedHook TryHookImport(string Library, string Function, Delegate Hook) + { + var Import = GetImport(Library, Function); + if (Import.HasValue) + return new UnmanagedHook(Import.Value, Hook); + else + return new UnmanagedHook(Library, Function, Hook); + } + + public static ImportEntry? GetImport(string Module, string Function) + { + try + { + return (from x in GetImports() where (x.Module.ToLower() == Module.ToLower() && Function == x.Function) select x).Single(); + } + catch { + return null; + } + } + + public static ImportEntry? GetImport(string Module, ushort Ordinal) + { + try + { + return (from x in GetImports() where (x.Module.ToLower() == Module.ToLower() && Ordinal == x.Ordinal) select x).Single(); + } + catch { + return null; + } + } + + public bool ImportHook => base.ImportHook; + } + + public class UnmanagedHook : IDisposable, Hook where T : Delegate { + + static int nBytes = IntPtr.Size == 8 ? 12 : 5; + + IntPtr destination; + IntPtr addr; + Protection old; + byte[] src = new byte[nBytes]; + byte[] dst = new byte[nBytes]; + bool AutoHook = false; + public bool ImportHook { get; private set; } = false; + + List Followers = new List(); + + T RealDestination; + T HookDestination; + + + /// + /// Create a new hook to the function in given pointer + /// + /// The pointer of the unmanaged function to hook + /// The delegate with the hook function + /// When true the hook will be automatically uninstalled during he execution + public UnmanagedHook(IntPtr Original, T Hook, bool AutoHook) { + this.AutoHook = AutoHook; + RealDestination = Hook; + + if (AutoHook) + GenerateMethod(); + + destination = Marshal.GetFunctionPointerForDelegate(AutoHook ? HookDestination : RealDestination); + + VirtualProtect(Original, nBytes, Protection.PAGE_EXECUTE_READWRITE, out old); + Marshal.Copy(Original, src, 0, nBytes); + if (IntPtr.Size == 8) { + //x64 + new byte[] { 0x48, 0xb8 }.CopyTo(dst, 0); + BitConverter.GetBytes(unchecked((ulong)destination.ToInt64())).CopyTo(dst, 2); + new byte[] { 0xFF, 0xE0 }.CopyTo(dst, 10); + } else { + //x86 + dst[0] = 0xE9; + var Result = (int)(destination.ToInt64() - Original.ToInt64() - nBytes); + var dx = BitConverter.GetBytes(Result); + Array.Copy(dx, 0, dst, 1, nBytes - 1); + } + addr = Original; + } + + /// + /// Install a hook exclusive to a certain module (Using the IAT Method) + /// + /// The Module Import To Hook + /// The Delegate with the hook function + public UnmanagedHook(ImportEntry Import, T Hook) + { + ImportHook = true; + + addr = Import.ImportAddress; + + src = new byte[IntPtr.Size]; + VirtualProtect(Import.ImportAddress, IntPtr.Size, Protection.PAGE_READWRITE, out old); + Marshal.Copy(Import.ImportAddress, src, 0, IntPtr.Size); + + destination = Marshal.GetFunctionPointerForDelegate(Hook); + dst = BitConverter.GetBytes(IntPtr.Size == 8 ? destination.ToUInt64() : destination.ToUInt32()); + } + + + /// + /// Create a new hook to the function in given pointer + /// + /// The pointer of the unmanaged function to hook + /// The delegate with the hook function + public UnmanagedHook(IntPtr Original, T Hook) : this(Original, Hook, true) { } + + /// Create a new Hook + /// + /// The Library name, Ex: Kernel32.dll + /// The Function name, Ex: CreateFile + /// The delegate wit the hook function + public UnmanagedHook(string Library, string Function, T Hook) : this(GetProcAddress(LoadLibrary(Library), Function), Hook) { + } + + + /// Create a new Hook + /// + /// The Library name, Ex: Kernel32.dll + /// The Function name, Ex: CreateFile + /// The delegate wit the hook function + /// When true the hook will be automatically uninstalled during he execution + public UnmanagedHook(string Library, string Function, T Hook, bool AutoHook) : this(GetProcAddress(LoadLibrary(Library), Function), Hook, AutoHook) { + + } + + void GenerateMethod() { + string ID = CurrentID++.ToString(); + SetInstance(ID, this); + + var ParametersInfo = RealDestination.Method.GetParameters(); + var Parameters = (from x in ParametersInfo select x.ParameterType).ToArray(); + + List IL = new List(); + //Uninstall(IID); + IL.Add(new Instruction(OpCodes.Ldstr, ID)); + IL.Add(new Instruction(OpCodes.Call, UninstallMI)); + + //Invoke(Parameters); + switch (Parameters.Length + 1) { + case 1: + IL.Add(new Instruction(OpCodes.Ldc_I4_1)); + break; + case 2: + IL.Add(new Instruction(OpCodes.Ldc_I4_2)); + break; + case 3: + IL.Add(new Instruction(OpCodes.Ldc_I4_3)); + break; + case 4: + IL.Add(new Instruction(OpCodes.Ldc_I4_4)); + break; + case 5: + IL.Add(new Instruction(OpCodes.Ldc_I4_5)); + break; + case 6: + IL.Add(new Instruction(OpCodes.Ldc_I4_6)); + break; + case 7: + IL.Add(new Instruction(OpCodes.Ldc_I4_7)); + break; + case 8: + IL.Add(new Instruction(OpCodes.Ldc_I4_8)); + break; + default: + int Count = Parameters.Length + 1; + if (Count <= byte.MaxValue) + IL.Add(new Instruction(OpCodes.Ldc_I4_S, (byte)Count)); + else + IL.Add(new Instruction(OpCodes.Ldc_I4, Count)); + break; + } + IL.Add(new Instruction(OpCodes.Newarr, typeof(object))); + + for (int i = 0, ind = -1; i < Parameters.Length + 1; i++, ind++) { + bool IsOut = ind >= 0 && ParametersInfo[ind].IsOut; + bool IsRef = ind >= 0 && ParametersInfo[ind].ParameterType.IsByRef & !IsOut; + if (IsOut) + continue; + + IL.Add(new Instruction(OpCodes.Dup)); + switch (i) { + case 0: + IL.Add(new Instruction(OpCodes.Ldc_I4_0)); + break; + case 1: + IL.Add(new Instruction(OpCodes.Ldc_I4_1)); + break; + case 2: + IL.Add(new Instruction(OpCodes.Ldc_I4_2)); + break; + case 3: + IL.Add(new Instruction(OpCodes.Ldc_I4_3)); + break; + case 4: + IL.Add(new Instruction(OpCodes.Ldc_I4_4)); + break; + case 5: + IL.Add(new Instruction(OpCodes.Ldc_I4_5)); + break; + case 6: + IL.Add(new Instruction(OpCodes.Ldc_I4_6)); + break; + case 7: + IL.Add(new Instruction(OpCodes.Ldc_I4_7)); + break; + case 8: + IL.Add(new Instruction(OpCodes.Ldc_I4_8)); + break; + default: + if (i <= byte.MaxValue) + IL.Add(new Instruction(OpCodes.Ldc_I4_S, (byte)i)); + else + IL.Add(new Instruction(OpCodes.Ldc_I4, i)); + break; + } + + + if (ind >= 0 && (ParametersInfo[ind].IsIn || ParametersInfo[ind].IsOut)) { + if (ind <= byte.MaxValue) + IL.Add(new Instruction(OpCodes.Ldarga_S, (byte)ind)); + else + IL.Add(new Instruction(OpCodes.Ldarga, (short)ind)); + } else { + switch (i) { + case 0: + IL.Add(new Instruction(OpCodes.Ldstr, ID)); + break; + case 1: + IL.Add(new Instruction(OpCodes.Ldarg_0)); + break; + case 2: + IL.Add(new Instruction(OpCodes.Ldarg_1)); + break; + case 3: + IL.Add(new Instruction(OpCodes.Ldarg_2)); + break; + case 4: + IL.Add(new Instruction(OpCodes.Ldarg_3)); + break; + default: + if (ind <= byte.MaxValue) + IL.Add(new Instruction(OpCodes.Ldarg_S, (byte)ind)); + else + IL.Add(new Instruction(OpCodes.Ldarg, (short)ind)); + break; + } + } + + var Type = ind >= 0 ? Parameters[ind] : null; + if (Type != null && IsRef) + Type = Parameters[ind].GetElementType(); + + bool Cast = true; + if (IsRef) { + var PType = Type; + if (PType.IsEnum && PType.IsValueType) + PType = Enum.GetUnderlyingType(PType); + + switch (PType.FullName) { + case "System.SByte": + IL.Add(new Instruction(OpCodes.Ldind_I1)); + break; + case "System.Byte": + IL.Add(new Instruction(OpCodes.Ldind_U1)); + break; + case "System.Int16": + IL.Add(new Instruction(OpCodes.Ldind_I2)); + break; + case "System.Char": + case "System.UInt16": + IL.Add(new Instruction(OpCodes.Ldind_U2)); + break; + case "System.Int32": + IL.Add(new Instruction(OpCodes.Ldind_I4)); + break; + case "System.UInt32": + IL.Add(new Instruction(OpCodes.Ldind_U4)); + break; + case "System.Int64": + case "System.UInt64": + IL.Add(new Instruction(OpCodes.Ldind_I8)); + break; + case "System.Single": + IL.Add(new Instruction(OpCodes.Ldind_R4)); + break; + case "System.Double": + IL.Add(new Instruction(OpCodes.Ldind_R8)); + break; + case "System.IntPtr": + case "System.UIntPtr": + IL.Add(new Instruction(OpCodes.Ldind_I)); + break; + default: + if ((PType.IsValueType && !PType.IsEnum) || PType.IsClass) { + IL.Add(new Instruction(OpCodes.Ldobj, PType)); + } else { + IL.Add(new Instruction(OpCodes.Ldind_Ref)); + Cast = false; + } + break; + } + } + + if (ind >= 0 && Cast ) + IL.Add(new Instruction(OpCodes.Box, Type)); + + IL.Add(new Instruction(OpCodes.Stelem_Ref)); + } + + IL.Add(new Instruction(OpCodes.Stloc_0)); + IL.Add(new Instruction(OpCodes.Ldloc_0)); + IL.Add(new Instruction(OpCodes.Call, InvokeMI)); + + //Cast Return Type + var RetType = RealDestination.Method.ReturnType; + if (RetType.IsInterface) + IL.Add(new Instruction(OpCodes.Castclass, RetType)); + else { + IL.Add(new Instruction(OpCodes.Unbox_Any, RetType)); + } + + for (int i = 0, ind = -1; i < Parameters.Length + 1; i++, ind++) { + bool IsOut = ind >= 0 && ParametersInfo[ind].IsOut; + bool IsRef = ind >= 0 && ParametersInfo[ind].ParameterType.IsByRef & !IsOut; + + if (!IsRef && !IsOut || ind < 0) + continue; + + + switch (ind) { + case 0: + IL.Add(new Instruction(OpCodes.Ldarg_0)); + break; + case 1: + IL.Add(new Instruction(OpCodes.Ldarg_1)); + break; + case 2: + IL.Add(new Instruction(OpCodes.Ldarg_2)); + break; + case 3: + IL.Add(new Instruction(OpCodes.Ldarg_3)); + break; + default: + + if (ind <= byte.MaxValue) + IL.Add(new Instruction(OpCodes.Ldarg_S, (byte)ind)); + else + IL.Add(new Instruction(OpCodes.Ldarg, (short)ind)); + break; + } + + IL.Add(new Instruction(OpCodes.Ldloc_0)); + switch (i) { + case 0: + IL.Add(new Instruction(OpCodes.Ldc_I4_0)); + break; + case 1: + IL.Add(new Instruction(OpCodes.Ldc_I4_1)); + break; + case 2: + IL.Add(new Instruction(OpCodes.Ldc_I4_2)); + break; + case 3: + IL.Add(new Instruction(OpCodes.Ldc_I4_3)); + break; + case 4: + IL.Add(new Instruction(OpCodes.Ldc_I4_4)); + break; + case 5: + IL.Add(new Instruction(OpCodes.Ldc_I4_5)); + break; + case 6: + IL.Add(new Instruction(OpCodes.Ldc_I4_6)); + break; + case 7: + IL.Add(new Instruction(OpCodes.Ldc_I4_7)); + break; + case 8: + IL.Add(new Instruction(OpCodes.Ldc_I4_8)); + break; + default: + if (ind <= byte.MaxValue) + IL.Add(new Instruction(OpCodes.Ldc_I4_S, (byte)ind)); + else + IL.Add(new Instruction(OpCodes.Ldc_I4, ind)); + break; + } + + IL.Add(new Instruction(OpCodes.Ldelem_Ref)); + + var Type = Parameters[ind]; + if (IsRef || IsOut) + Type = Type.GetElementType(); + + if (Type.IsInterface) { + IL.Add(new Instruction(OpCodes.Castclass, Type)); + IL.Add(new Instruction(OpCodes.Stind_Ref)); + } else { + IL.Add(new Instruction(OpCodes.Unbox_Any, Type)); + + if (Type.IsEnum && Type.IsValueType) + Type = Enum.GetUnderlyingType(Type); + + switch (Type.FullName) { + case "System.Byte": + case "System.SByte": + IL.Add(new Instruction(OpCodes.Stind_I1)); + break; + case "System.Char": + case "System.UInt16": + case "System.Int16": + IL.Add(new Instruction(OpCodes.Stind_I2)); + break; + case "System.UInt32": + case "System.Int32": + IL.Add(new Instruction(OpCodes.Stind_I4)); + break; + case "System.Int64": + case "System.UInt64": + IL.Add(new Instruction(OpCodes.Stind_I8)); + break; + case "System.Single": + IL.Add(new Instruction(OpCodes.Stind_R4)); + break; + case "System.Double": + IL.Add(new Instruction(OpCodes.Stind_R8)); + break; + case "System.IntPtr": + case "System.UIntPtr": + IL.Add(new Instruction(OpCodes.Stind_I)); + break; + default: + if (Type.IsValueType && !Type.IsEnum) { + IL.Add(new Instruction(OpCodes.Stobj, Type)); + } else { + IL.Add(new Instruction(OpCodes.Stind_Ref)); + } + break; + } + } + + } + + + //Install(IID); + IL.Add(new Instruction(OpCodes.Ldstr, ID)); + IL.Add(new Instruction(OpCodes.Call, InstallMI)); + + //return; + IL.Add(new Instruction(OpCodes.Ret)); + +#if ILDEBUG + var NewMethod = GenerateAssembly(ID, IL, ParametersInfo); + HookDestination = (T)Delegate.CreateDelegate(typeof(T), NewMethod); +#else + DynamicMethod Method = new DynamicMethod("UnmanagedHook", RealDestination.Method.ReturnType, Parameters, typeof(UnmanagedImports), true); + + + + var ILGen = Method.GetILGenerator(); + ILGen.DeclareLocal(typeof(object[])); + + foreach (var Pair in IL) { + if (Pair.Value == null) + ILGen.Emit(Pair.Key); + else + ILGen.Emit(Pair.Key, Pair.Value); + } + + HookDestination = (T)Method.CreateDelegate(typeof(T)); +#endif + + } + + MethodInfo InstallMI => (from x in typeof(UnmanagedImports).GetMethods(BindingFlags.Static | BindingFlags.Public) where x.Name == "Install" select x).First(); + MethodInfo UninstallMI => (from x in typeof(UnmanagedImports).GetMethods(BindingFlags.Static | BindingFlags.Public) where x.Name == "Uninstall" select x).First(); + MethodInfo InvokeMI => (from x in typeof(UnmanagedImports).GetMethods(BindingFlags.Static | BindingFlags.Public) where x.Name == "Invoke" select x).First(); + + /// + /// Install the hook + /// + public void Install() { + Marshal.Copy(dst, 0, addr, ImportHook ? IntPtr.Size : nBytes); + } + + + /// + /// Uninstall the hook + /// + public void Uninstall() { + Marshal.Copy(src, 0, addr, ImportHook ? IntPtr.Size : nBytes); + } + + Delegate Hook.GetDelegate() { + return RealDestination; + } + + /// + /// Adds a hook to be disabled during the execution of the this hook + /// + /// The hook to be disabled + public void AddFollower(params object[] Followers) { + if (!AutoHook) + throw new Exception("The Auto Hook must be enabled"); + + foreach (object Follower in Followers) { + if (!(Follower is Hook)) + throw new Exception(Follower.GetType().Name + " Isn't an UnmanagedHook Class"); + + this.Followers.Add(Follower); + } + } + + /// + /// Remove a hook from the Follower list + /// + /// The hook to be removed + public void RemoveFollower(params object[] Followers) { + if (!AutoHook) + throw new Exception("The Auto Hook must be enabled"); + + foreach (object Follower in Followers) { + if (!(Follower is Hook)) + throw new Exception(Follower.GetType().Name + " Isn't an UnmanagedHook Class"); + + this.Followers.Remove(Follower); + } + } + + object[] Hook.GetFollowers() { + return Followers.ToArray(); + } + + public void Dispose() { + Uninstall(); + Protection x; + VirtualProtect(addr, nBytes, old, out x); + } + + } + + static class UnmanagedImports { + + [DebuggerDisplay("{Key} {Value}")] + internal struct Instruction { + public dynamic Key; + public dynamic Value; + + public Instruction(dynamic Key, dynamic Value) { + this.Key = Key; + this.Value = Value; + } + public Instruction(dynamic Key) { + this.Key = Key; + Value = null; + } + } + + internal interface Hook { + void Install(); + void Uninstall(); + + dynamic[] GetFollowers(); + + Delegate GetDelegate(); + } + + + static Dictionary InstanceMap = new Dictionary(); + + internal static long CurrentID = 0; + + /// + /// INTERNAL UNMANAGED HOOK USAGE, DON'T TOUCH ME + /// + public static void Install(string ID) { + Hook Hook = (Hook)InstanceMap[ID]; + Hook.Install(); + + foreach (object dFollower in Hook.GetFollowers()) { + Hook Follower = (Hook)dFollower; + Follower.Install(); + } + } + + /// + /// INTERNAL UNMANAGED HOOK USAGE, DON'T TOUCH ME + /// + public static void Uninstall(string ID) { + Hook Hook = (Hook)InstanceMap[ID]; + Hook.Uninstall(); + + foreach (object dFollower in Hook.GetFollowers()) { + Hook Follower = (Hook)dFollower; + Follower.Uninstall(); + } + } + + /// + /// INTERNAL UNMANAGED HOOK USAGE, DON'T TOUCH ME + /// + public static object Invoke(object[] Parameters) { + if (Parameters.Length == 0) + throw new Exception("No Arguments Found"); + + string ID = (string)Parameters.First(); + object[] Args = Parameters.Skip(1).ToArray(); + + Hook Hook = (Hook)InstanceMap[ID]; + + object Result = Hook.GetDelegate().DynamicInvoke(Args); + Args.CopyTo(Parameters, 1); + return Result; + } + + + internal static void SetInstance(string ID, object Instance) { + InstanceMap[ID] = Instance; + } + internal static ImportEntry[] GetModuleImports(IntPtr Module) + { + if (Module == IntPtr.Zero) + throw new Exception("Failed to catch the Main Module..."); + + uint PtrSize = Environment.Is64BitProcess ? 8u : 4u; + + ulong OrdinalFlag = (1ul << (int)((8 * PtrSize) - 1)); + + ulong PEStart = Read(Module.Sum(0x3C), 4).ToUInt32(); + ulong OptionalHeader = PEStart + 0x18; + + ulong ImageDataDirectoryPtr = OptionalHeader + (PtrSize == 8 ? 0x70u : 0x60u); + + ulong ImportTableEntry = ImageDataDirectoryPtr + 0x8; + + IntPtr RVA = ImportTableEntry.ToIntPtr(); + + IntPtr ImportDesc = Module.Sum(Read(Module.Sum(RVA), 4).ToUInt32()); + + if (ImportDesc == Module) + return new ImportEntry[0]; + + List Entries = new List(); + + while (true) + { + uint OriginalFirstThunk = Read(ImportDesc.Sum(4 * 0), 4).ToUInt32(); + //uint TimeDateStamp = Read(ImportDesc.Sum(4 * 1), 4).ToUInt32(); + //uint ForwarderChain = Read(ImportDesc.Sum(4 * 2), 4).ToUInt32(); + uint Name = Read(ImportDesc.Sum(4 * 3), 4).ToUInt32(); + uint FirstThunk = Read(ImportDesc.Sum(4 * 4), 4).ToUInt32(); + + if (OriginalFirstThunk == 0x00) + break; + + string ModuleName = ReadString(Module.Sum(Name), false); + + IntPtr DataAddr = Module.Sum(OriginalFirstThunk); + IntPtr IATAddr = Module.Sum(FirstThunk); + while (true) + { + IntPtr EntryPtr = Read(DataAddr, PtrSize).ToIntPtr(); + + if (EntryPtr == IntPtr.Zero) + break; + + bool ImportByOrdinal = false; + if ((EntryPtr.ToUInt64() & OrdinalFlag) == OrdinalFlag) + { + EntryPtr = (EntryPtr.ToUInt64() ^ OrdinalFlag).ToIntPtr(); + ImportByOrdinal = true; + } + else + EntryPtr = Module.Sum(EntryPtr); + + ushort Hint = ImportByOrdinal ? (ushort)EntryPtr.ToUInt32() : Read(EntryPtr, 2).ToUInt16(); + string ExportName = ImportByOrdinal ? null : ReadString(EntryPtr.Sum(2), false); + + Entries.Add(new ImportEntry() + { + Function = ExportName, + Ordinal = Hint, + Module = ModuleName, + ImportAddress = IATAddr, + FunctionAddress = Read(IATAddr, PtrSize).ToIntPtr() + }); + + DataAddr = DataAddr.Sum(PtrSize); + IATAddr = IATAddr.Sum(PtrSize); + } + + + ImportDesc = ImportDesc.Sum(0x14);//sizeof(_IMAGE_IMPORT_DESCRIPTOR) + } + + return Entries.ToArray(); + } + + internal static byte[] Read(IntPtr Address, uint Length) + { + byte[] Buffer = new byte[Length]; + ChangeProtection(Address, Buffer.Length, Protection.PAGE_READWRITE, out Protection Original); + Marshal.Copy(Address, Buffer, 0, Buffer.Length); + ChangeProtection(Address, Buffer.Length, Original); + return Buffer; + } + + internal static string ReadString(IntPtr Address, bool Unicode) + { + List Buffer = new List(); + IntPtr CPos = Address; + do + { + byte[] Char = Read(CPos, Unicode ? 2u : 1u); + if (Unicode && Char[0] == 0x00 && Char[1] == 0x00) + break; + if (!Unicode && Char[0] == 0x00) + break; + + + Buffer.AddRange(Char); + + CPos = CPos.Sum(Unicode ? 2u : 1u); + } while (true); + + return Unicode ? System.Text.Encoding.Unicode.GetString(Buffer.ToArray()) : System.Text.Encoding.Default.GetString(Buffer.ToArray()); + } + + + internal static ulong ToUInt64(this IntPtr Ptr) => unchecked((ulong)Ptr.ToInt64()); + internal static uint ToUInt32(this IntPtr Ptr) => unchecked((uint)(Ptr.ToInt64() & 0xFFFFFFFF)); + + internal static IntPtr ToIntPtr(this ulong Int) => new IntPtr(unchecked((long)Int)); + + internal static IntPtr Sum(this IntPtr Pointer, IntPtr Value) => (Pointer.ToUInt64() + Value.ToUInt64()).ToIntPtr(); + internal static IntPtr Sum(this IntPtr Pointer, long Value) => (Pointer.ToUInt64() + (ulong)Value).ToIntPtr(); + + internal static uint ToUInt32(this byte[] Data, int Address = 0) => BitConverter.ToUInt32(Data, Address); + internal static ushort ToUInt16(this byte[] Data, int Address = 0) => BitConverter.ToUInt16(Data, Address); + internal static int ToInt32(this byte[] Data, int Address = 0) => BitConverter.ToInt32(Data, Address); + internal static long ToInt64(this byte[] Data, int Address = 0) => BitConverter.ToInt64(Data, Address); + + internal static IntPtr ToIntPtr(this byte[] Data, bool? x64 = null) + { + if (x64.HasValue) + return new IntPtr(x64.Value ? Data.ToInt64() : Data.ToInt32()); + if (Data.Length >= 8) + return new IntPtr(IntPtr.Size == 8 ? Data.ToInt64() : Data.ToInt32()); + return new IntPtr(Data.ToInt32()); + } + + + internal static bool ChangeProtection(IntPtr Address, int Range, Protection Protection, out Protection OriginalProtection) + { + return VirtualProtect(Address, Range, Protection, out OriginalProtection); + } + + internal static bool ChangeProtection(IntPtr Address, int Range, Protection Protection) + { + return VirtualProtect(Address, Range, Protection, out Protection OriginalProtection); + } + + [DllImport("kernel32.dll", SetLastError = true)] + internal static extern bool VirtualProtect(IntPtr lpAddress, int dwSize, Protection flNewProtect, out Protection lpflOldProtect); + + [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)] + internal static extern IntPtr GetProcAddress(IntPtr hModule, string procName); + + [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)] + internal static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName); + internal enum Protection { + PAGE_NOACCESS = 0x01, + PAGE_READONLY = 0x02, + PAGE_READWRITE = 0x04, + PAGE_WRITECOPY = 0x08, + PAGE_EXECUTE = 0x10, + PAGE_EXECUTE_READ = 0x20, + PAGE_EXECUTE_READWRITE = 0x40, + PAGE_EXECUTE_WRITECOPY = 0x80, + PAGE_GUARD = 0x100, + PAGE_NOCACHE = 0x200, + PAGE_WRITECOMBINE = 0x400 + } + } + + static partial class StringReloader + { + public static UnmanagedHook AutoHookCreator(string Module, string Function, Delegate Hook) + { + if (!ImportHook) + return new UnmanagedHook(Module, Function, Hook); + + var RHook = UnmanagedHook.TryHookImport(Module, Function, Hook); + if (Debugging && !RHook.ImportHook) + Log("Import Hook Failed: {0} => {1}", true, Module, Function); + + return RHook; + } + } +} \ No newline at end of file diff --git a/SRL/Main.cs b/SRL/Main.cs index 2bac0f9..4c95a3a 100644 --- a/SRL/Main.cs +++ b/SRL/Main.cs @@ -146,7 +146,8 @@ public static IntPtr GetDirectProcess() { } catch { return IntPtr.Zero; } } - public static string ProcessManaged(string Text) { + public static string ProcessManaged(string Text) + { Managed = true; IntPtr Ptr = Marshal.StringToHGlobalAuto(Text); IntPtr New = ProcessReal(Ptr); @@ -157,15 +158,18 @@ public static string ProcessManaged(string Text) { Marshal.FreeHGlobal(New); return Text; } - static string ProcessManaged(string Text, bool Managed) { - bool IsManaged = Managed; - string Result = ProcessManaged(Text); - if (!Managed) - Managed = IsManaged; - - return Result; + public static string Process(string Text) + { + Managed = true; + IntPtr Ptr = Marshal.StringToHGlobalAuto(Text); + IntPtr New = ProcessReal(Ptr); + if (New == Ptr) + return Text; + Text = Marshal.PtrToStringAuto(New); + Marshal.FreeHGlobal(Ptr); + Marshal.FreeHGlobal(New); + return Text; } - public static char ProcessManaged(char Char) { Managed = true; IntPtr Result = ProcessReal(new IntPtr(Char)); diff --git a/SRL/Output.cs b/SRL/Output.cs index 6b89155..1ef3e07 100644 --- a/SRL/Output.cs +++ b/SRL/Output.cs @@ -261,36 +261,26 @@ internal static bool PECSVal(byte[] Data) { return true; } - internal static void Error(string Message, params object[] Format) { - if (LiteMode) - return; - - bool BakLogFile = LogFile; - LogFile = true; - ConsoleColor Color = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Red; - Log(Message, false, Format); - Console.ForegroundColor = Color; - LogFile = BakLogFile; - } - internal static void Warning(string Message, params object[] Format) { - if (LiteMode) - return; - - bool BakLogFile = LogFile; - LogFile = true & Debugging; - ConsoleColor Color = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Yellow; - Log(Message, true, Format); - Console.ForegroundColor = Color; - LogFile = BakLogFile; - } + internal static void Error(string Message, params object[] Format) => + Log(ConsoleColor.Red, Message, false, Format); + internal static void Warning(string Message, params object[] Format) => + Log(ConsoleColor.Yellow, Message, true, Format); internal static void Log(ConsoleColor Color, string Message, bool Optional = false, params object[] Format) { if (LiteMode) return; + if (!ConsoleShowed) + { + Log("", true); + + if (ConsoleShowed) + Console.Clear(); + else + return; + } + bool BakLogFile = LogFile; LogFile = true & Debugging; ConsoleColor ColorBack = Console.ForegroundColor; diff --git a/SRL/Reloader.cs b/SRL/Reloader.cs index d905992..bb47429 100644 --- a/SRL/Reloader.cs +++ b/SRL/Reloader.cs @@ -271,14 +271,13 @@ internal static void Init() { } CheckArguments(); - LoadConfig(); - if (Debugging) { Log(ConsoleColor.Green, "Strings Reloads - v" + SRLVersion, true); Log(ConsoleColor.Green, "Soft-Translation Engine - By Marcussacana", true); Log(ConsoleColor.Green, "Debug Mode Enabled...", true); } + LoadConfig(); if (!DirectRequested) Warning("You are using SRL through the old function, it is recommended to use GetDirectProcess"); diff --git a/SRL/SRL.csproj b/SRL/SRL.csproj index e695b0d..15f2495 100644 --- a/SRL/SRL.csproj +++ b/SRL/SRL.csproj @@ -67,8 +67,8 @@ - + diff --git a/SRL/SRL.ini b/SRL/SRL.ini index 2164d0f..ee9d7c6 100644 --- a/SRL/SRL.ini +++ b/SRL/SRL.ini @@ -80,6 +80,7 @@ MoveWindow=false [Hook] CreateFile=false +ImportHook=true UndoChars=true MultiByteToWideChar=false SetWindowText=false diff --git a/SRL/Types.cs b/SRL/Types.cs index 3863aee..97b9be8 100644 --- a/SRL/Types.cs +++ b/SRL/Types.cs @@ -343,6 +343,8 @@ internal struct HookSettings { [FieldParmaters(Name = "SendMessage", DefaultValue = false)] public bool SendMessage; #endif + [FieldParmaters(Name = "ImportHook", DefaultValue = false)] + public bool ImportHook; [FieldParmaters(Name = "CreateFile", DefaultValue = false)] public bool CreateFile; [FieldParmaters(Name = "MultiByteToWideChar", DefaultValue = false)] diff --git a/SRL/Variables.cs b/SRL/Variables.cs index f746171..fa60078 100644 --- a/SRL/Variables.cs +++ b/SRL/Variables.cs @@ -133,6 +133,7 @@ struct Range { static bool HookCreateWindowEx; static bool HookSendMessage; #endif + static bool ImportHook; static bool HookCreateFile; static bool HookMultiByteToWideChar; static bool HookSetWindowText;