fancycode / MemoryModule

Library to load a DLL from memory.
http://www.joachim-bauch.de/tutorials/loading-a-dll-from-memory/
Mozilla Public License 2.0
2.84k stars 759 forks source link

Crash when throwing exception inside loaded dll. #4

Open Niblitlvl50 opened 12 years ago

Niblitlvl50 commented 12 years ago

When throwing and catching an exception inside the "memory-loaded" dll the application crashes with "Unhandled exception at ...". Even though the appropriate catch is in place.

This is when using Visual Studio 2010. I've created a repository that demonstrates this problem. Hopefully i am the one who has missed something and the memory loading is working as intended.

Link to repo: https://github.com/Niblitlvl50/DLL-crash-when-loading-dll-into-memory

Thank you.

JesseKlugmann commented 12 years ago

Hi

A temporary fix is to disable DEP[1] in the Visual Studio build options. Another possibility is to implement the missing parts of the pe loading process in MemoryModule. I'll provide some code, if I get an allowance from my boss.

[1] DEP: http://en.wikipedia.org/wiki/Data_Execution_Prevention

fancycode commented 12 years ago

Hi JesseKlugmann, any updates on this? Could you provide some code, or give some hints what parts are missing and maybe describe how they should be implemented?

kovidgoyal commented 11 years ago

My guess (and I dont know a lot about the subject) is that you have to load the .SAFESEH section of the dll, otherwise the SafeSeh mechanism will terminate the process when an exception occurs, as it cannot verify that the exception handlers are safe. See http://msdn.microsoft.com/en-us/library/9a89h429(v=vs.90).aspx

fancycode commented 11 years ago

@JesseKlugmann do you have any hints or links to documentation how this could be implemented?

Zorro1 commented 11 years ago

@fancycode 1) on x32 the problem in inside RtlIsValidHandler (ntdll.dll). It's check if handler address in module. For solve this problem you can disable DEP (that's not so cool because some times you can't do this because you inside another app) OR try to find function RtlInsertInvertedFunctionTable and addr of LdrpInvertedFunctionTable because it's all not exported. And call RtlInsertInvertedFunctionTable(LdrpInvertedFunctionTable, 'imagebase', 'sizeofimage') for manually loaded module.

2) on x64 problem is in two places

bigmacattack commented 10 years ago

The "DarkMMap" project found here (https://github.com/DarthTon/DarkMMap) loads libraries from memory and according to the project page, has "Exception handling support (SEH and C++), needs more testing though, but seems reliable". Perhaps someone could take a look at how they implement exception handling support and adopt it to work with MemoryModule.

Tsury commented 10 years ago

I checked DarkMMap (now deprecated and called Blackbone). It works just fine but doesn't support Windows XP.

I found the relevant code from their library, can someone help incorporate it into MemoryModule? I'm a not too good at Win32...

It's in MMap.cpp:550

///

/// Set custom exception handler to bypass SafeSEH under DEP ///

/// image data /// true on success bool MMap::EnableExceptions( ImageContext* pImage ) { BLACBONE_TRACE( L"ManualMap: Enabling exception support for image '%ls'", pImage->FileName.c_str() );

ifdef USE64

size_t size = pImage->PEImage.DirectorySize( IMAGE_DIRECTORY_ENTRY_EXCEPTION );
IMAGE_RUNTIME_FUNCTION_ENTRY *pExpTable = 
    reinterpret_cast<decltype(pExpTable)>(pImage->PEImage.DirectoryAddress( IMAGE_DIRECTORY_ENTRY_EXCEPTION ));
// Invoke RtlAddFunctionTable
if(pExpTable)
{     
    AsmJitHelper a;
    uint64_t result = 0;

    pImage->pExpTableAddr = REBASE( pExpTable, pImage->FileImage.base(), pImage->imgMem.ptr<ptr_t>() );
    auto pAddTable = _process.modules().GetExport( _process.modules().GetModule( L"ntdll.dll", LdrList, pImage->PEImage.mType() ),
                                                   "RtlAddFunctionTable" );

    a.GenPrologue();
    a.GenCall( static_cast<size_t>(pAddTable.procAddress), { pImage->pExpTableAddr, 
                                                              size / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY),
                                                              pImage->imgMem.ptr<size_t>() } );
    _process.remote().AddReturnWithEvent( a );
    a.GenEpilogue();

    if (_process.remote().ExecInWorkerThread( a->make(), a->getCodeSize(), result ) != STATUS_SUCCESS)
        return false;

    if (pImage->flags & CreateLdrRef)
        return true;
    else
        return (MExcept::CreateVEH( pImage->imgMem.ptr<size_t>(), pImage->PEImage.imageSize() ) == STATUS_SUCCESS);
}
else
    return false;

else

bool safeseh = false;
_process.nativeLdr().InsertInvertedFunctionTable( pImage->imgMem.ptr<void*>(), pImage->PEImage.imageSize(), safeseh );
if ((pImage->flags & PartialExcept) || safeseh)
    return true;
else
    return (MExcept::CreateVEH( pImage->imgMem.ptr<size_t>(), pImage->PEImage.imageSize() ) == STATUS_SUCCESS);

endif

}

fancycode commented 10 years ago

Could you please create a pull request for the changes or provide a proper diff?

Tsury commented 10 years ago

This is just code I found on Blackbone's repository which I found relevant. I lack the knowledge to actually add it to your library.

Here's a direct link to the relevant code: https://github.com/DarthTon/Blackbone/blob/master/src/BlackBone/MMap.cpp#L550-L595

I think that using your knowledge and Zorro1's advice, you can manage to merge it into your library.

ghost commented 10 years ago

Hi, have you had any luck implementing try/catch support? I tried to understand the code linked to above (Blackbone) but it deals with a lot of assembly that I can't really follow.

Thanks

ghost commented 8 years ago

I found an article on how SEH and VEH exceptions are handled and it seems to expand on what Zorro1 posted.

https://hackmag.com/uncategorized/exceptions-for-hardcore-users/

I will be trying to figure this out but in the mean time maybe someone else can use what I found.

GR-C commented 8 years ago

Hello, I'm also interessted in a solution.

ghost commented 7 years ago

I have located another possible source for a solution. It is designed to load windows DLLs on linux and it supports exception handling.

https://github.com/taviso/loadlibrary

ghost commented 7 years ago

I have found a working solution to the problem!

https://github.com/nettitude/SimplePELoader

I have confirmed that an exception can be thrown and caught within the loaded library. I have also confirmed that an exception can be thrown inside the library and caught in the executable that loaded it. This is explicitly handled on 64 bit builds but has not be implemented for 32 bit builds. However the disabling DEP solution is a viable workaround for 32 bit builds.

Notes:

  1. You cannot use the '/EHsc' compiler flag without causing a crash
  2. You must use the '/NXCOMPAT:NO' linker flag on 32 bit builds

Edit:

This solution will only allow you to catch exceptions with a catch all block on 64 bit builds.

catch(...){
// You can do whatever you want here.. but you can't know what the exception is
}

The moment you try to define the exception the program will crash as usual.