Skip to content

Conversation

@s0rtega
Copy link

@s0rtega s0rtega commented Jan 9, 2021

Description

Based on the changes addressing the Issue #17 I added two additional options (CanLoadFromDisk, Overload) to CallMappedDLLModuleExport and GetExportAddress. Using these flags when a module is forwarded (e.g., SAMCLI.dll) it is possible to control if the module will be loaded from disk and how it will be loaded (direct / overload).

I am not 100% sure if this make sense, because is also increasing the complexity of the code, but can be handy under certain scenarios. If I am trying to overload the parent module does not make sense to end loading the forwarded one which could be even more suspicious. Happy to discuss is there is a better approach (or if that even makes sense).

Test code

I did some "regression" testing with some of the DInvoke examples and DInvisibleRegistry (https://github.com/NVISO-BE/DInvisibleRegistry) everything seems to work OK.
To check the new flags, there is a quick example reusing the same:

using System;
using System.Runtime.InteropServices;

namespace overload_poc
{
    class STRUCTS
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct LOCALGROUP_MEMBERS_INFO_3
        {
            [MarshalAs(UnmanagedType.LPWStr)]
            public string domainandname;
        }
    }

    class DELEGATES
    {
        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate DInvoke.Data.Native.NTSTATUS NetLocalGroupAddMembers(
            string servername,
            [MarshalAs(UnmanagedType.LPWStr)]
            string groupName,
            UInt32 level,
            ref STRUCTS.LOCALGROUP_MEMBERS_INFO_3 info,
            UInt32 totalentries);
    }
    class Program
    {
        static void Main(string[] args)
        {

            // NetLocalGroupAddMember (forwarded to SAMCLI.NetLocalGroupAddMember)
            DInvoke.Data.PE.PE_MANUAL_MAP mappedDLL = DInvoke.ManualMap.Overload.OverloadModule(@"C:\Windows\System32\netapi32.dll", @"C:\Windows\System32\netapi32.dll");


            String group = @"Administrators";
            STRUCTS.LOCALGROUP_MEMBERS_INFO_3 username = new STRUCTS.LOCALGROUP_MEMBERS_INFO_3();
            username.domainandname = @"myUser";

            object[] funcParams =
                {
                    null,
                    group,
                    (UInt32)3,
                    username,
                    (UInt32)1};

            
            DInvoke.Data.Native.NTSTATUS res = (DInvoke.Data.Native.NTSTATUS)DInvoke.DynamicInvoke.Generic.CallMappedDLLModuleExport(
                                        mappedDLL.PEINFO,
                                        mappedDLL.ModuleBase,
                                        "NetLocalGroupAddMembers",
                                        typeof(DELEGATES.NetLocalGroupAddMembers),
                                        funcParams,
                                        false,
                                        true,
                                        false
                                        );

            Console.WriteLine(res);
        }
    }
} 

@TheWover
Copy link
Owner

TheWover commented Sep 16, 2021

Overall this makes sense, but according to the documentation of the SearchPathW function:

"""
The SearchPath function is not recommended as a method of locating a .dll file if the intended use of the output is in a call to the LoadLibrary function. This can result in locating the wrong .dll file because the search order of the SearchPath function differs from the search order used by the LoadLibrary function. If you need to locate and load a .dll file, use the LoadLibrary function.
"""

I'll have to think about whether that is acceptable. The user may not care, but there are cases where this could result in a different DLL than they would expect compared to LoadLibrary. As an alternative, ntdll.dll!LdrGetDllPath might work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants