monoxgas / sRDI

Shellcode implementation of Reflective DLL Injection. Convert DLLs to position independent shellcode
Other
2.1k stars 456 forks source link

convert user32.dll to shellcode and load it into memory failed #10

Open rainkin1993 opened 6 years ago

rainkin1993 commented 6 years ago

Environment: Win10 1709 DLL: C:\Windows\SysWOW64\user32.dll

  1. I firstly use command python Python\ConvertToShellcode.py user32.dll convert user32.dll to user32.bin.
  2. Then I change the code in Native\Loader.cpp to call API MessageBoxA after loading the user32.dll and compile the Native project using Visual Studio 2015 Debug x86.

    
    // Only set the first page to RWX
    // This is should sufficiently cover the sRDI shellcode up top
    if (VirtualProtect(finalShellcode, sysInfo.dwPageSize, PAGE_EXECUTE_READWRITE, &dwOldProtect1)) {
        RDI rdi = (RDI)(finalShellcode);
    
        printf("[+] Executing RDI\n");
        UINT_PTR hLoadedDLL = rdi(); // Excute DLL
    
        free(finalShellcode); // Free the RDI blob. We no longer need it.
    
        /*Function exportedFunction = (Function)GetProcAddressR(hLoadedDLL, "SayGoodbye");
        if (exportedFunction) {
            printf("[+] Calling exported functon\n");
            exportedFunction();
        }*/
        MyMessageBoxA exportedFunction = (MyMessageBoxA)GetProcAddressR(hLoadedDLL, "MessageBoxA");
        if (exportedFunction) {
            printf("[+] Calling exported functon\n");
            exportedFunction(0, "Hello", "user32.dll message", 1);
        }
    }

typedef int (WINAPI *MyMessageBoxA)(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);


3. Then use command `Native.exe user32.bin` to load the shellcode.
The exe crashed and report a error : 

> 0x7774CCC5 (ntdll.dll) (located at Native.exe) Exception: 0xC0000005: Access violation reading location 0x00000008.

I ensure that the GetProcAddressR return the correct address of MessageBoxA.

I found that the **0x7774CCC5** belongs to ntdll.dll!RtlAllocateHeap function:
![image](https://user-images.githubusercontent.com/2485043/42331896-31f87a56-80a9-11e8-909f-f47f30d3052f.png)

Do you have comments that which possible cause this problem? My conclusion is that reflective loading a DLL written by ourselves works fine but loading a system dll(ntdll, user32..) will not work. It seems that there is something the loader doesn't handle when load the system dll into memory.
rainkin1993 commented 6 years ago

Have you ever load a system dll(user32.dll, ntdll.dll) succeed?

monoxgas commented 6 years ago

I have played with this as well, but had similar results.

I can try to find some time to take a look, I agree with your setiment that some part of the loading process is obviously being missed.

You could try loading with the MemoryModule project and see if you have better luck. Their code does a much better job of handling edge cases in the unpacking process. Off the top of my head, delayed imports and TLS call backs are still missing from sRDI

rainkin1993 commented 6 years ago

AH, I firstly try MemoryModule but also failed with another error messages

  1. When loading user32.dll using MemoryModule in Win10, the DLLMain was invoked and I get an error code 14: ERROR_OUTOFMEMORY
  2. For urlmon.dll, the DLL was successfully loaded, but when I invoke the URLDownloadToFileA API, the program crashed as well.

It seems that totally simulating the process of loading system DLLs is very difficult.

monoxgas commented 6 years ago

Interesting results. I might assume there is a class of core system DLLs (kernel32, user32, ntdll, etc.) which have special handling to deny loading multiple instances in one process.

Other Microsoft DLLs like urlmon, gdi, etc. might not have this special handling and therefore might give better results. Going to do some digging to try and find out more.

The PE load process is well documented, but I can't shake the feeling that Microsoft has some special handling that doesn't conform to well-known standards.

monoxgas commented 6 years ago

Adding an interesting note here, kernel32.dll appears to load and run fine for those wondering.

I can validate the failure of user32 and the crash from urlmon. Looking through ReactOS and online material, my guess for the user32 failure is the relation to GDI. Potentially something about GDI heaps being allocated and mapped in the PEB.