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

Manual Map issue #173

Closed
frostiest opened this issue Oct 17, 2020 · 9 comments
Closed

Manual Map issue #173

frostiest opened this issue Oct 17, 2020 · 9 comments
Labels

Comments

@frostiest
Copy link

Just curious if you know why all manual map libraries seem to fail and a possible way to make them work? The goal is embed the .net dll inside an unmanaged exe and load the dll from bye array/memory instead of file.

an example library is https://github.com/strivexjun/MemoryModulePP

@3F
Copy link
Owner

3F commented Oct 17, 2020

As I can see they use DllMain like (*DllEntry)((HINSTANCE)code, DLL_PROCESS_ATTACH, 0); that will not work because you need init CLR first to init your managed module: #45 (comment)

@frostiest
Copy link
Author

frostiest commented Oct 17, 2020

Thank you for responding, I want to elaborate is I may

I modified MemoryModulePP library (and others) to supposedly successfully map the dll in memory, namely I removed the dllentry call and commented out this check
`

GetNativeSystemInfo(&sysInfo);
alignedImageSize = AlignValueUp(lastSectionEnd, sysInfo.dwPageSize);
//if (alignedImageSize != AlignValueUp(lastSectionEnd, sysInfo.dwPageSize)) {

`

which provided a valid base address/return. Then used their export function "MemoryGetProcAddress" to get the export from the C# dll I want to call, and that's where things crash. The address appears valid, The debugger says it crashes somewhere in mscoree.dll.

I also tried the old school method of loading the clr like you mentioned before doing the above

int loadclr()
{
	ICLRMetaHost* metaHost = NULL; //Declare our CLR Meta Host value as a NULL
	ICLRRuntimeInfo* runtimeInfo = NULL; //Declare our CLR Runtime Info as a Null
	ICLRRuntimeHost* runtimeHost = NULL; //Delcare our CLR HOST as a NULL
 
	if (CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost) == S_OK) //If Creating CLR Instance with follow parameters is successful
		if (metaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&runtimeInfo) == S_OK) //If getting Runtime version is successful
			if (runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost) == S_OK) //If getting the interface with the follow parameters is successful
				if (runtimeHost->Start() == S_OK) //Start the CLR (If it is successful)
				{
					DWORD pReturnValue; //Declare our return value as a DWORD
					
					//Invoke our method through CLR host using following parameters
					//runtimeHost->ExecuteInDefaultAppDomain(L"Path\\To\\Our\\DLL", L"TestDLL.Class1", L"TestMethod", L"It works!!", &pReturnValue);
 
					//OPTIONAL: You can keep the CLR Opened depending on your needs
					runtimeInfo->Release();
					metaHost->Release();
					runtimeHost->Release();
				}
	return 0;
}

that didn't do much. So my question is what is LoadLibrary doing that these mapping librabries aren't that's making loading the C# dll unsuccessful? They're

  • Relocations
  • Executing TLS
  • Resolving Import/Exports
  • Resolving Resources
  • Mapping Exception Table

and is there a way I can preload the CLR or do anything to avoid having to load from disk first(or use LoadLibrary for that matter) ?

Thanks

@frostiest
Copy link
Author

Guess not, ok thank you for share and project, have good day.

@3F
Copy link
Owner

3F commented Oct 19, 2020

Not sure about completeness for the mentioned equivalent to the LoadLibrary(), and unfortunately I don't have time/health to review it today, but first of all,

RVAs in export table will point exactly to export stubs --> that points to --> v-table slots !

Each slot contains method token which will be replaced with the address of a marshaling point providing unmanaged entry to managed method. All this must be processed with actual addresses at runtime.

What about unmanaged starter for CLR,

It must be located in .text section where vtfixup, that is ~

clr header + ... + export stubs + vtfixup + clr starter

Its RVA should be assigned to PE AddressOfEntryPoint and my highlights above looks correct:

((DllEntryProc)(LPVOID)(code + result->headers->OptionalHeader.AddressOfEntryPoint))

@frostiest, but as I voiced, you need init CLR ~"environment" (I do not mean clr hosting way like from your "old school" example above, it's different to the task) before processing/calculating related to it.

Also note v-table should be located in other .sdata section because of RW

@tapika
Copy link

tapika commented Nov 1, 2020

@frostiest I'm not sure what exactly you're doing, but suspect easiest approach would be to make small C# library "loader", which in a turn would use Assembly.Load and perform assembly loading from ram - I guess this is equivalent to C++ MemoryModulePP. This approach however will not work on all assemblies - some assemblies might need to be loaded from disk in order to work.

I'm also not sure about debugging of such in-ram loaded dll's, as debugger will not be aware of any newly loaded dll unless you explicitly specify it somehow to debugger.

But I'm actually interested on what you want to achieve and what was the last problem.

I by myself want to fully release .net framework assembly without any good result. Don't understand why there aren't any FreeLibrary for C#. I've slightly played around with .net core - situation seems to be better, but I haven't yet tried C++ / mixed mode clr dlls.

Can you tell me bit more on where you've ended up with your experiments ?

@tapika
Copy link

tapika commented Nov 1, 2020

Btw, MemoryModulePP perform something similar to https://github.com/nickcano/ReloadLibrary

One approach is to actually allow PE loader perform what it wants to perform, but intercept windows API calls, like LoadLibrary, GetProcAddress, FreeLibrary to manually control what you do with these dlls, and remove file locking.

Using minhook in similar manner to:
https://github.com/tapika/stacktrace/blob/develop/src/exception_handler.cpp#L204

You can intercept windows api.

But main question - is what loader is performing, and how to "reset" loader state back to "not loaded" state.

I guess with C++ it's easy - existence of MemoryModulePP and ReloadLibrary tells me that this is something that was already achieved. With .net it's bit more complex, as need to interspect what loader / clr includes.

At the moment clrmd - https://github.com/microsoft/clrmd knows everything about state of C# - I was thinking maybe later on try to debug what it knows that I don't know.

Either way, please inform me if you know something more that I don't know.

@tapika
Copy link

tapika commented Nov 1, 2020

Here are bit more links on IAT problem, which I have tried to analyze by myself without any good result:

https://stackoverflow.com/questions/5005409/exception-with-resolving-assemblies-attempt-to-load-an-unverifiable-executable

https://stackoverflow.com/questions/2945080/how-do-i-dynamically-load-raw-assemblies-that-contains-unmanaged-codebypassing

https://web.archive.org/web/20130906220206/https://connect.microsoft.com/VisualStudio/feedback/details/97801/loading-mixed-assembly-with-assembly-load-byte-throw-exception-changed-behaviour

https://stackoverflow.com/questions/5005409/exception-with-resolving-assemblies-attempt-to-load-an-unverifiable-executable

https://tech-zealots.com/malware-analysis/journey-towards-import-address-table-of-an-executable-file/

To my best understanding IAT table refers to external dll. I'm not sure why which reference is needed, but apparently C++ linker generates it if you have C++/cli in use and you use some sort of global symbols. There are some attempts to make data as appdomain specific (now it's .net framework specific, not necessarily applicable to .net core) using __declspec(appdomain) - but this goes deeper in .net framework appdomain non-sense. (C# has globals per appdomain, C++ has globals per process, and if you start second appdomain - you will need to re-initialize all C# stuff again - eats RAM and produces a lot of complexities)

I probably need to try how this works on .net core level, as things are different in there.

(.net framework is officially deprecated by Microsoft by now).

@tapika
Copy link

tapika commented Nov 1, 2020

FYI also: https://dev.to/thebuzzsaw/building-a-better-library-loader-in-c-part-1-1446

Interesting reading, but suspect Conary somehow walks in that direction.

@frostiest
Copy link
Author

frostiest commented Nov 2, 2020

I no find solution but I wanted to link you to similar project that also doesn't fix my issue at all but DOES have the feature of DllEntry so can simply use LoadLibrary("test.dll"); and ability to export other methods.

https://github.com/seanrussell2/DotNetExport

example use
ClassLibrary1.dll C#
`

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace ClassLibrary1
{
    public class Class1
    {
        [System.Runtime.InteropServices.DllMain]
        static void DllMain(IntPtr hModule)
        {
            MessageBox.Show("Hi!");
        }
    }
}

Tool
DotNetExport.exe ClassLibrary1.dll

Test (c++)
HMODULE A = LoadLibraryA("ClassLibrary1.dll");

maybe can copy if care about DllEntry.

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

No branches or pull requests

3 participants