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

Can i export a method just called 'DllMain'? #5

Open
cia48621793 opened this issue Aug 18, 2016 · 8 comments
Open

Can i export a method just called 'DllMain'? #5

cia48621793 opened this issue Aug 18, 2016 · 8 comments

Comments

@cia48621793
Copy link

That would be funny if it could be possible.

@3F
Copy link
Owner

3F commented Aug 18, 2016

?

using DllMain = DllExportAttribute;

or do you mean something like:

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
        case DLL_PROCESS_ATTACH:
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
            break;
    }
    return TRUE;
}

:)

I also started new project Conari (the LunaRoad works via this) to work with unmanaged code as a flexible binder between .net and C/C++ etc.

so, if you need to find the available entry points to functions, you can use, for example:

using(var l = new ConariL("Library.dll")) {

    l.ExportFunctionNames  // reads all available names from PE export table
    ...
    dlr.myEntryPoint(2, 1); //to call something at Runtime
                            //or via lambda: `bind<Action<int, int>>("myEntryPoint")(2, 1)`
}

@cia48621793
Copy link
Author

Yes, I wanted to do the latter one just you have described. But since we are calling managed code and if there wasn't a managed environment we cannot launch the code in managed space and usually when we had to initialize the environment during dll attaching and it occupies DllMain, unless we are initializing from TLB initializer which was before DllMain.

@cia48621793
Copy link
Author

Tl;dr I wanted to DllExport the DllMain, but there would be conflicts if I do so.

@cia48621793
Copy link
Author

cia48621793 commented Aug 18, 2016

Well, according to some document, DllMain was called from CRT. DllEntryPoint is where the actual DLL loading happens. Maybe this issue is irrelevant now.

@3F
Copy link
Owner

3F commented Aug 18, 2016

I see :( but the DllMain has another place, and in general it used for LoadLibrary/LoadLibraryEx functions.

let me explain:

The address of DllMain stored in optional header +0x10 offset from the beginning header / size is 4 (PE32/PE32+)

it's RVA of main entry point - DriverEntry for drivers and DllMain for dll, or 0

https://msdn.microsoft.com/en-us/library/windows/desktop/ms680339.aspx

    typedef struct _IMAGE_OPTIONAL_HEADER {
      WORD                 Magic;
      BYTE                 MajorLinkerVersion;
      BYTE                 MinorLinkerVersion;
      DWORD                SizeOfCode;
      DWORD                SizeOfInitializedData;
      DWORD                SizeOfUninitializedData;
>>>   DWORD                AddressOfEntryPoint;  //+0x10 same for IMAGE_OPTIONAL_HEADER64
     ...

But, the DllExport works over ILAsm which provides useful .export directive to finally add some records into export directory table.

i.e.:

.method public hidebysig static int32 
        modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) 
        entrypoint(native int L) cil managed
{
  .vtentry 1 : 1 // use vtfixup 
  .export [0] as Init // to export table
  ...
}

and

.vtfixup [1] int32 fromunmanaged at D_00004000 // adds slot, see vtentry above

...

and finally we're here:

IMAGE_DATA_DIRECTORY DataDirectory[0]; // #define IMAGE_DIRECTORY_ENTRY_EXPORT  0   // Export Directory

RVA points to export directory that contains:

typedef struct _IMAGE_EXPORT_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    DWORD   Name;
    DWORD   Base;
    DWORD   NumberOfFunctions;
    DWORD   NumberOfNames;
    DWORD   AddressOfFunctions;     // RVA from base of image
    DWORD   AddressOfNames;         // RVA from base of image
    DWORD   AddressOfNameOrdinals;  // RVA from base of image
} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
...
00000C20  02 00 00 00 30 40 00 00 38 40 00 00 40 40 00 00  ....0@..8@..@@..
00000C30  1E 27 00 00 2E 27 00 00 44 40 00 00 49 40 00 00  .'...'..D@..I@..
00000C40  01 00 00 00 49 6E 69 74 00 4D 79 45 78 70 6F 72  ....Init.MyExpor
00000C50  74 46 75 6E 63 74 69 6F 6E 00 5C 54 65 73 74 44  tFunction.\TestD
00000C60  6C 6C 4D 61 69 6E 2E 64 6C 6C 00 00 00 00 00 00  llMain.dll......
...

so yes, theoretically it's possible with manually changing of PE data :)

but it's not trivial task as you can see (seems ILAsm may work only with export directory), this hard for my time with other projects, but I will look it later :) a good point to avoid ILAsm/ILDasm at all !

cia48621793 closed this a minute ago :)

@cia48621793
Copy link
Author

Now I had a workaround for my problem.

I could have just created a C++/CLI DLL...Indeed it works but bootstraping C# code in mixed assemblies seems like a pain in the a**.

Also the size of the executable of mixed assemblies were gorgeous.

I would could then have my C# DLL embedded with Costura.Fody. Shady.

@cia48621793
Copy link
Author

The second way: Export the function. Then write a DLL stub for injection. Also known as CLR hosting.
The third way: Manually map the DLL that contains the exported function then create a thread to that exported function address.

@3F
Copy link
Owner

3F commented Aug 18, 2016

when we had to initialize the environment during dll attaching

to forget about this - is more right choice :) seriously,

this is not so good place while DllMain holds the loader lock etc.

try to avoid the using of this at all (if it's possible), because your ~'DLL stub for injection' or something else - like a bullet to his temple >_<

...deadlock or access data or code in an uninitialized DLL:

dllmain

but anyway, I think it possible. At least, with injection some bootloader inside PE (i.e. I'm not sure about simple remapping the RVA's), that of course is overhead :)

I reopened this Issue to look it in details later (me or anyone else), but with very-very low priority.

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

No branches or pull requests

2 participants