Open phiber0 opened 1 year ago
hi @phiber0 !
I tried to reproduce the problem you described, but for some reason everything worked fine for me.
This is what I used to build the project: https://gist.github.com/hasherezade/21d3938a3f846d988c1b030c3a713872 - your snippet + my CMakeLists.txt
from which I generated a VisualStudio project, used VS2019.
I am attaching the binaries generated from my build, both converted and before conversion: test_case2_bin.zip
Please let me know if my binaries work for you. Also, please share the binaries from your builds, and I will check them.
P.S. Although the DllMain
worked fine, and the DLL got loaded, I see a problem with the SayGoodbye
function: this function throws and exception, which won't be handled if the binary is loaded manually by the stub. So it not gonna work from the shellcode, but crash instead. But I guess this was not your question.
Hi!, Thank you for taking the time to check this one.
I have used your CMakeLists.txt to create my VS project and you are right, the dll is loaded if the compiled is set to 2019/2017, but crashed if we use 2015/2013. (tested on win10 and win7, same results).
I have attached 4 compilations, one for each version if you can take a look. I didn't change anything on the code/options, just the toolset version and compiled release.
let me know if I can do anything else.
Ps, SayGoodbye was in the original code, I just use it to have a place to insert the std::mutex to trigger the error.
I see, you are right - the binaries created with the older Visual Studio indeed crash. I will check them in more details and let you know what I found.
@phiber0 - I investigated it, and now I understand what causes it.
The binaries compiled in older versions of Visual Studio have one more initialization function that they run in _initterm
.
This is from VS2015:
And from VS2017:
And the problem with that function is, that it makes use of the API function RtlPcToFileHeader
to fetch the base of the current module.
Due to the fact that the shellcodified PE is loaded manually, its base will not be retrieved. The function returns a NULL pointer, which will be further used as a base. And finally it causes exception:
I tested it with a libPeConv-based manual loader, where I hooked the function RtlPcToFileHeader
, and finally it works:
This PoC confirms that this is where the problem is located.
However, in the stub that I use in pe2shc, I don't want to use any function hooking, so I can't solve it the same way. Looking at the implementation of this function from ReactOS:
PVOID NTAPI
RtlPcToFileHeader(IN PVOID PcValue,
PVOID* BaseOfImage)
{
PLIST_ENTRY ModuleListHead;
PLIST_ENTRY Entry;
PLDR_DATA_TABLE_ENTRY Module;
PVOID ImageBase = NULL;
RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock);
ModuleListHead = &NtCurrentPeb()->Ldr->InLoadOrderModuleList;
Entry = ModuleListHead->Flink;
while (Entry != ModuleListHead)
{
Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
if ((ULONG_PTR)PcValue >= (ULONG_PTR)Module->DllBase &&
(ULONG_PTR)PcValue < (ULONG_PTR)Module->DllBase + Module->SizeOfImage)
{
ImageBase = Module->DllBase;
break;
}
Entry = Entry->Flink;
}
RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock);
*BaseOfImage = ImageBase;
return ImageBase;
}
It seems the only way to solve this would be to add the shellcode to the list of loaded modules. But doing so will make the injected shellcode to be less stealthy. I will probably make it optional.
wow, you are amazing!
I will wait for your pe2shc update!.
this problem is also happening if you use ReflectiveDLLInjection so your solution could help a loot of people.
thank you
thank you! at least now we know the reason! but solving it seems not so easy as I thought earlier:
I tried to add the shellcode to the list of the loaded modules, and it seemed to work fine (the module got added) - yet RtlPcToFileHeader
still didn't work as expected.
I was doing my experiments on Windows 10, and I ended up going down the function RtlPcToFileHeader
to see what is wrong. It turns out that this function evolved quite a lot, and is no longer that simple as in the ReactOS version (the decompiled version of the new one is here).
So, adding the module to the InLoadOrderLinks
list is no longer the solution. I need to analyze it in more details, and then will see what else I can do.
Hi hasherezade!
I have found a weird problem adding some std headers. for example if you add < string > nothing happens and the dll is loaded 10/10 times, but if you add < thread > < mutex > or < condition_variable > the dll mostly crash before injection is complited. (works 1 of 10 times).
I have tested the dll compiled on VS 2013,2015 both /MT. works just fine without < mutex >
basic dll code taked from ShellCodeRDI for testing.
can you share some light about this. thank you!
edit: forgot to add my test steps.
1) pe2shc.exe TestDLL_x64.dll 2) runshc64.exe TestDLL_x64.shc.dll