From 9f84cc05333c378fe918ce51b9cc1a5c855d4232 Mon Sep 17 00:00:00 2001 From: Sergio Ortega Fernandez Date: Sat, 9 Jan 2021 17:26:00 +0100 Subject: [PATCH] Added options to CallMappedDLLModuleExport --- DInvoke/DInvoke/DynamicInvoke/Generic.cs | 39 ++++++++++++++------- DInvoke/DInvoke/DynamicInvoke/Win32.cs | 43 ++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/DInvoke/DInvoke/DynamicInvoke/Generic.cs b/DInvoke/DInvoke/DynamicInvoke/Generic.cs index 6208875..09bdebf 100644 --- a/DInvoke/DInvoke/DynamicInvoke/Generic.cs +++ b/DInvoke/DInvoke/DynamicInvoke/Generic.cs @@ -256,7 +256,7 @@ public static string GetAPIHash(string APIName, long Key) /// The name of the export to search for (e.g. "NtAlertResumeThread"). /// Whether or not to resolve export forwards. Default is true. /// IntPtr for the desired function. - public static IntPtr GetExportAddress(IntPtr ModuleBase, string ExportName, bool ResolveForwards = true) + public static IntPtr GetExportAddress(IntPtr ModuleBase, string ExportName, bool ResolveForwards = true, bool CanLoadFromDisk = false, bool Overload = false) { IntPtr FunctionPtr = IntPtr.Zero; try @@ -303,7 +303,7 @@ public static IntPtr GetExportAddress(IntPtr ModuleBase, string ExportName, bool if (ResolveForwards == true) // If the export address points to a forward, get the address - FunctionPtr = GetForwardAddress(FunctionPtr); + FunctionPtr = GetForwardAddress(FunctionPtr, CanLoadFromDisk, Overload); break; } @@ -331,7 +331,7 @@ public static IntPtr GetExportAddress(IntPtr ModuleBase, string ExportName, bool /// The ordinal number to search for (e.g. 0x136 -> ntdll!NtCreateThreadEx). /// Whether or not to resolve export forwards. Default is true. /// IntPtr for the desired function. - public static IntPtr GetExportAddress(IntPtr ModuleBase, short Ordinal, bool ResolveForwards = true) + public static IntPtr GetExportAddress(IntPtr ModuleBase, short Ordinal, bool ResolveForwards = true, bool CanLoadFromDisk = false, bool Overload = false) { IntPtr FunctionPtr = IntPtr.Zero; try @@ -400,7 +400,7 @@ public static IntPtr GetExportAddress(IntPtr ModuleBase, short Ordinal, bool Res /// 64-bit integer to initialize the keyed hash object (e.g. 0xabc or 0x1122334455667788). /// Whether or not to resolve export forwards. Default is true. /// IntPtr for the desired function. - public static IntPtr GetExportAddress(IntPtr ModuleBase, string FunctionHash, long Key, bool ResolveForwards = true) + public static IntPtr GetExportAddress(IntPtr ModuleBase, string FunctionHash, long Key, bool ResolveForwards = true, bool CanLoadFromDisk = false, bool Overload = false) { IntPtr FunctionPtr = IntPtr.Zero; try @@ -467,8 +467,9 @@ public static IntPtr GetExportAddress(IntPtr ModuleBase, string FunctionHash, lo /// The Wover (@TheRealWover) /// Function of an exported address, found by parsing a PE file's export table. /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list. + /// Optional, indicates if the dll should be loaded using overload /// IntPtr for the forward. If the function is not forwarded, return the original pointer. - public static IntPtr GetForwardAddress(IntPtr ExportAddress, bool CanLoadFromDisk = false) + public static IntPtr GetForwardAddress(IntPtr ExportAddress, bool CanLoadFromDisk = false, bool Overload = false) { IntPtr FunctionPtr = ExportAddress; try @@ -492,7 +493,15 @@ public static IntPtr GetForwardAddress(IntPtr ExportAddress, bool CanLoadFromDis IntPtr hModule = GetPebLdrModuleEntry(ForwardModuleName); if (hModule == IntPtr.Zero && CanLoadFromDisk == true) - hModule = LoadModuleFromDisk(ForwardModuleName); + if (Overload) + { + StringBuilder ForwardModulePath = new StringBuilder("",256); + IntPtr ForwardModulePathOut; + Data.Native.NTSTATUS res = Win32.SearchPathW(null, ForwardModuleName, null, (UInt32)ForwardModulePath.Capacity, ForwardModulePath, out ForwardModulePathOut); + hModule = ManualMap.Overload.OverloadModule(ForwardModulePath.ToString()).ModuleBase; + } + else + hModule = LoadModuleFromDisk(ForwardModuleName); if (hModule != IntPtr.Zero) { FunctionPtr = GetExportAddress(hModule, ForwardExportName); @@ -716,8 +725,10 @@ public static void CallMappedDLLModule(Data.PE.PE_META_DATA PEINFO, IntPtr Modul /// Prototype for the function, represented as a Delegate object. /// Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference. /// Specify whether to invoke the module's entry point. + /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list. + /// Optional, indicates if the dll should be loaded using overload /// void - public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, string ExportName, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true) + public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, string ExportName, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true, bool CanLoadFromDisk = false, bool Overload = false) { // Call entry point if user has specified if (CallEntry) @@ -726,7 +737,7 @@ public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntP } // Get export pointer - IntPtr pFunc = GetExportAddress(ModuleMemoryBase, ExportName); + IntPtr pFunc = GetExportAddress(ModuleMemoryBase, ExportName, CanLoadFromDisk: CanLoadFromDisk, Overload: Overload); // Call export return DynamicFunctionInvoke(pFunc, FunctionDelegateType, ref Parameters); @@ -742,8 +753,10 @@ public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntP /// Prototype for the function, represented as a Delegate object. /// Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference. /// Specify whether to invoke the module's entry point. + /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list. + /// Optional, indicates if the dll should be loaded using overload /// void - public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, short Ordinal, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true) + public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, short Ordinal, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true, bool CanLoadFromDisk = false, bool Overload = false) { // Call entry point if user has specified if (CallEntry) @@ -752,7 +765,7 @@ public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntP } // Get export pointer - IntPtr pFunc = GetExportAddress(ModuleMemoryBase, Ordinal); + IntPtr pFunc = GetExportAddress(ModuleMemoryBase, Ordinal, CanLoadFromDisk: CanLoadFromDisk, Overload: Overload); // Call export return DynamicFunctionInvoke(pFunc, FunctionDelegateType, ref Parameters); @@ -769,8 +782,10 @@ public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntP /// Prototype for the function, represented as a Delegate object. /// Arbitrary set of parameters to pass to the function. Can be modified if function uses call by reference. /// Specify whether to invoke the module's entry point. + /// Optional, indicates if the function can try to load the DLL from disk if it is not found in the loaded module list. + /// Optional, indicates if the dll should be loaded using overload /// void - public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, string FunctionHash, long Key, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true) + public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntPtr ModuleMemoryBase, string FunctionHash, long Key, Type FunctionDelegateType, object[] Parameters, bool CallEntry = true, bool CanLoadFromDisk = false, bool Overload = false) { // Call entry point if user has specified if (CallEntry) @@ -779,7 +794,7 @@ public static object CallMappedDLLModuleExport(Data.PE.PE_META_DATA PEINFO, IntP } // Get export pointer - IntPtr pFunc = GetExportAddress(ModuleMemoryBase, FunctionHash, Key); + IntPtr pFunc = GetExportAddress(ModuleMemoryBase, FunctionHash, Key, CanLoadFromDisk: CanLoadFromDisk, Overload: Overload); // Call export return DynamicFunctionInvoke(pFunc, FunctionDelegateType, ref Parameters); diff --git a/DInvoke/DInvoke/DynamicInvoke/Win32.cs b/DInvoke/DInvoke/DynamicInvoke/Win32.cs index 2211c75..7e29c45 100644 --- a/DInvoke/DInvoke/DynamicInvoke/Win32.cs +++ b/DInvoke/DInvoke/DynamicInvoke/Win32.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.InteropServices; +using System.Text; namespace DInvoke.DynamicInvoke { @@ -56,6 +57,29 @@ public static IntPtr CreateRemoteThread( return retValue; } + public static Data.Native.NTSTATUS SearchPathW( + string lpPath, + string lpFileName, + string lpExtension, + UInt32 nBufferLength, + StringBuilder lpBuffer, + out IntPtr filePartOut) + { + filePartOut = IntPtr.Zero; + // Craft an array for the arguments + object[] funcargs = + { + lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, filePartOut + }; + + Data.Native.NTSTATUS retValue = (Data.Native.NTSTATUS)Generic.DynamicAPIInvoke(@"kernel32.dll", @"SearchPathW", typeof(Delegates.SearchPathW), ref funcargs); + + // Update the modified variables + filePartOut = (IntPtr)funcargs[5]; + + return retValue; + } + /// /// Uses DynamicInvocation to call the IsWow64Process Win32 API. https://docs.microsoft.com/en-us/windows/win32/api/wow64apiset/nf-wow64apiset-iswow64process /// @@ -66,7 +90,7 @@ public static bool IsWow64Process(IntPtr hProcess, ref bool lpSystemInfo) // Build the set of parameters to pass in to IsWow64Process object[] funcargs = { - hProcess, lpSystemInfo + hProcess,lpSystemInfo }; bool retVal = (bool)Generic.DynamicAPIInvoke(@"kernel32.dll", @"IsWow64Process", typeof(Delegates.IsWow64Process), ref funcargs); @@ -79,8 +103,23 @@ public static bool IsWow64Process(IntPtr hProcess, ref bool lpSystemInfo) public static class Delegates { + // https://github.com/Tarkiyah/ansible/blob/b0c8e7926f4ed31c37fabfad7803bd378f8aaba4/lib/ansible/module_utils/csharp/Ansible.Process.cs + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + public delegate Data.Native.NTSTATUS SearchPathW( + [MarshalAs(UnmanagedType.LPWStr)] + string lpPath, + [MarshalAs(UnmanagedType.LPWStr)] + string lpFileName, + [MarshalAs(UnmanagedType.LPWStr)] + string lpExtension, + UInt32 nBufferLength, + [MarshalAs(UnmanagedType.LPTStr)] + StringBuilder lpBuffer, + ref IntPtr lpFilePart); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate IntPtr CreateRemoteThread(IntPtr hProcess, + public delegate IntPtr CreateRemoteThread( + IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress,