commit 6210fbc616cb2e02a39c75dbb8b015faa2c0466e Author: ActiveBreach Date: Fri Jan 7 13:04:57 2022 +0000 Create Parallel.cpp diff --git a/Parallel.cpp b/Parallel.cpp new file mode 100644 index 0000000..530e8b7 --- /dev/null +++ b/Parallel.cpp @@ -0,0 +1,460 @@ +#include +#include +#include +#include + +typedef void* PRTL_USER_PROCESS_PARAMETERS; +typedef void* PPS_POST_PROCESS_INIT_ROUTINE; + +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef struct _PEB_LDR_DATA //, 7 elements, 0x28 bytes +{ + DWORD dwLength; + DWORD dwInitialized; + LPVOID lpSsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + LPVOID lpEntryInProgress; +} PEB_LDR_DATA, * PPEB_LDR_DATA; + +typedef struct _PEB { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[1]; + PVOID Reserved3[2]; + PPEB_LDR_DATA Ldr; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + PVOID Reserved4[3]; + PVOID AtlThunkSListPtr; + PVOID Reserved5; + ULONG Reserved6; + PVOID Reserved7; + ULONG Reserved8; + ULONG AtlThunkSListPtr32; + PVOID Reserved9[45]; + BYTE Reserved10[96]; + PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; + BYTE Reserved11[128]; + PVOID Reserved12[1]; + ULONG SessionId; +} PEB, * PPEB; + +typedef struct /*_LDR_DATA_TABLE_ENTRY*/ +{ + LIST_ENTRY InLoadOrderLinks; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; + PVOID DllBase; + PVOID EntryPoint; + ULONG SizeOfImage; + UNICODE_STRING FullDllName; + UNICODE_STRING BaseDllName; + ULONG Flags; + SHORT LoadCount; + SHORT TlsIndex; + LIST_ENTRY HashTableEntry; + ULONG TimeDateStamp; +} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY; + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; // Points to type SECURITY_DESCRIPTOR + PVOID SecurityQualityOfService; // Points to type SECURITY_QUALITY_OF_SERVICE + +} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES; + +typedef struct _IO_STATUS_BLOCK +{ + union + { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK; + +typedef NTSYSAPI NTSTATUS(NTAPI* FUNC_NTOPENFILE)( + OUT PHANDLE FileHandle, + IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG ShareAccess, + IN ULONG OpenOptions + ); + +typedef NTSTATUS(NTAPI* FUNC_NTCREATESECTION) +(_Out_ PHANDLE SectionHandle, _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_opt_ PLARGE_INTEGER MaximumSize, _In_ ULONG SectionPageProtection, + _In_ ULONG AllocationAttributes, _In_opt_ HANDLE FileHandle); + +typedef NTSTATUS(NTAPI* FUNC_NTMAPVIEWOFSECTION) +(_In_ HANDLE SectionHandle, _In_ HANDLE ProcessHandle, + _Inout_ PVOID* BaseAddress, _In_ ULONG_PTR ZeroBits, _In_ SIZE_T CommitSize, + _Inout_opt_ PLARGE_INTEGER SectionOffset, _Inout_ PSIZE_T ViewSize, + _In_ DWORD InheritDisposition, _In_ ULONG AllocationType, + _In_ ULONG Win32Protect); + +typedef VOID(NTAPI* FUNC_RTLINITUNICODESTRING)( + IN OUT PUNICODE_STRING DestinationString, + IN PCWSTR SourceString + ); + +#ifndef NT_SUCCESS +#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) +#endif + +#ifndef InitializeObjectAttributes +#define InitializeObjectAttributes( p, n, a, r, s ) { \ + (p)->Length = sizeof( OBJECT_ATTRIBUTES ); \ + (p)->RootDirectory = r; \ + (p)->Attributes = a; \ + (p)->ObjectName = n; \ + (p)->SecurityDescriptor = s; \ + (p)->SecurityQualityOfService = NULL; \ + } +#endif + +#define OBJ_CASE_INSENSITIVE 0x40 +#define STATUS_IMAGE_NOT_AT_BASE 0x40000003 + +#define MAX_EXPORT_NAME_LENGTH 64 +#define MAX_SYSCALL_STUB_SIZE 64 +#define MAX_NUMBER_OF_SYSCALLS 1024 + +/* +0:001> u ntdll!LdrpThunkSignature +ntdll!LdrpThunkSignature: +00007ff9`2e1860d0 4c8bd1 mov r10,rcx +00007ff9`2e1860d3 b833000000 mov eax,33h +00007ff9`2e1860d8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1 +00007ff9`2e1860e0 4c8bd1 mov r10,rcx +00007ff9`2e1860e3 b84a000000 mov eax,4Ah +00007ff9`2e1860e8 f604250803fe7f01 test byte ptr [SharedUserData+0x308 (00000000`7ffe0308)],1 +00007ff9`2e1860f0 4c8bd1 mov r10,rcx +00007ff9`2e1860f3 b83d000000 mov eax,3Dh +0:001> db ntdll!LdrpThunkSignature +00007ff9`2e1860d0 4c 8b d1 b8 33 00 00 00-f6 04 25 08 03 fe 7f 01 L...3.....%..... +00007ff9`2e1860e0 4c 8b d1 b8 4a 00 00 00-f6 04 25 08 03 fe 7f 01 L...J.....%..... +00007ff9`2e1860f0 4c 8b d1 b8 3d 00 00 00-f6 04 25 08 03 fe 7f 01 L...=.....%..... +00007ff9`2e186100 4c 8b d1 b8 37 00 00 00-f6 04 25 08 03 fe 7f 01 L...7.....%..... +00007ff9`2e186110 4c 8b d1 b8 28 00 00 00-f6 04 25 08 03 fe 7f 01 L...(.....%..... +*/ + + + +FUNC_NTOPENFILE NtOpenFile = NULL; +FUNC_NTCREATESECTION NtCreateSection = NULL; +FUNC_NTMAPVIEWOFSECTION NtMapViewOfSection = NULL; + +FUNC_RTLINITUNICODESTRING RtlInitUnicodeString = (FUNC_RTLINITUNICODESTRING)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "RtlInitUnicodeString"); + +ULONG_PTR BuildSyscallStub(ULONG_PTR StubRegion, DWORD dwSyscallNo) +{ + BYTE SyscallStub[] = + { + 0x4c, 0x8b, 0xd1, // mov r10,rcx + 0xb8, 0x00, 0x00, 0x00, 0x00, // mov eax,xxx + 0x0f, 0x05, // syscall + 0xc3 // ret + }; + + memcpy((PBYTE)StubRegion, SyscallStub, sizeof(SyscallStub)); + *(DWORD*)(StubRegion + 4) = dwSyscallNo; + + return StubRegion; +} + +BOOL InitSyscallsFromLdrpThunkSignature() +{ + PPEB Peb = (PPEB)__readgsqword(0x60); + PPEB_LDR_DATA Ldr = Peb->Ldr; + PLDR_DATA_TABLE_ENTRY NtdllLdrEntry = NULL; + + for (PLDR_DATA_TABLE_ENTRY LdrEntry = (PLDR_DATA_TABLE_ENTRY)Ldr->InLoadOrderModuleList.Flink; + LdrEntry->DllBase != NULL; + LdrEntry = (PLDR_DATA_TABLE_ENTRY)LdrEntry->InLoadOrderLinks.Flink) + { + if (_wcsnicmp(LdrEntry->BaseDllName.Buffer, L"ntdll.dll", 9) == 0) + { + // got ntdll + NtdllLdrEntry = LdrEntry; + break; + } + } + + if (NtdllLdrEntry == NULL) + { + return FALSE; + } + + PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)NtdllLdrEntry->DllBase + ((PIMAGE_DOS_HEADER)NtdllLdrEntry->DllBase)->e_lfanew); + PIMAGE_SECTION_HEADER SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&ImageNtHeaders->OptionalHeader + ImageNtHeaders->FileHeader.SizeOfOptionalHeader); + + ULONG_PTR DataSectionAddress = NULL; + DWORD DataSectionSize; + + for (WORD i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++) + { + if (!strcmp((char*)SectionHeader[i].Name, ".data")) + { + DataSectionAddress = (ULONG_PTR)NtdllLdrEntry->DllBase + SectionHeader[i].VirtualAddress; + DataSectionSize = SectionHeader[i].Misc.VirtualSize; + break; + } + } + + DWORD dwSyscallNo_NtOpenFile = 0, dwSyscallNo_NtCreateSection = 0, dwSyscallNo_NtMapViewOfSection = 0; + + if (!DataSectionAddress || DataSectionSize < 16 * 5) + { + return FALSE; + } + + for (UINT uiOffset = 0; uiOffset < DataSectionSize - (16 * 5); uiOffset++) + { + if (*(DWORD*)(DataSectionAddress + uiOffset) == 0xb8d18b4c && + *(DWORD*)(DataSectionAddress + uiOffset + 16) == 0xb8d18b4c && + *(DWORD*)(DataSectionAddress + uiOffset + 32) == 0xb8d18b4c && + *(DWORD*)(DataSectionAddress + uiOffset + 48) == 0xb8d18b4c && + *(DWORD*)(DataSectionAddress + uiOffset + 64) == 0xb8d18b4c) + { + dwSyscallNo_NtOpenFile = *(DWORD*)(DataSectionAddress + uiOffset + 4); + dwSyscallNo_NtCreateSection = *(DWORD*)(DataSectionAddress + uiOffset + 16 + 4); + dwSyscallNo_NtMapViewOfSection = *(DWORD*)(DataSectionAddress + uiOffset + 64 + 4); + break; + } + } + + if (!dwSyscallNo_NtOpenFile) + { + return FALSE; + } + + ULONG_PTR SyscallRegion = (ULONG_PTR)VirtualAlloc(NULL, 3 * MAX_SYSCALL_STUB_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + + if (!SyscallRegion) + { + return FALSE; + } + + NtOpenFile = (FUNC_NTOPENFILE)BuildSyscallStub(SyscallRegion, dwSyscallNo_NtOpenFile); + NtCreateSection = (FUNC_NTCREATESECTION)BuildSyscallStub(SyscallRegion + MAX_SYSCALL_STUB_SIZE, dwSyscallNo_NtCreateSection); + NtMapViewOfSection = (FUNC_NTMAPVIEWOFSECTION)BuildSyscallStub(SyscallRegion + (2* MAX_SYSCALL_STUB_SIZE), dwSyscallNo_NtMapViewOfSection); + + return TRUE; +} + +ULONG_PTR LoadNtdllIntoSection() +{ + NTSTATUS ntStatus; + HANDLE hFile = NULL; + OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; + UNICODE_STRING ObjectPath = { 0 }; + IO_STATUS_BLOCK IoStatusBlock = { 0 }; + HANDLE hSection = NULL; + LARGE_INTEGER maxSize = { 0 }; + LPVOID lpvSection = NULL; + SIZE_T viewSize = 0; + + RtlInitUnicodeString(&ObjectPath, L"\\??\\C:\\Windows\\System32\\ntdll.dll"); + + InitializeObjectAttributes( + &ObjectAttributes, + &ObjectPath, + OBJ_CASE_INSENSITIVE, + 0, + NULL + ); + + ntStatus = NtOpenFile( + &hFile, + FILE_READ_DATA, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ, + 0 + ); + + if (!NT_SUCCESS(ntStatus)) + { + goto Cleanup; + } + + ntStatus = NtCreateSection( + &hSection, + SECTION_ALL_ACCESS, + NULL, + NULL, + PAGE_READONLY, + SEC_COMMIT, + hFile + ); + + if (!NT_SUCCESS(ntStatus)) + { + goto Cleanup; + } + + ntStatus = NtMapViewOfSection(hSection, GetCurrentProcess(), &lpvSection, NULL, NULL, NULL, &viewSize, 1, 0, PAGE_READONLY); + + if (!NT_SUCCESS(ntStatus)) + { + return NULL; + } + +Cleanup: + if (hSection) CloseHandle(hSection); + if (hFile) CloseHandle(hFile); + return (ULONG_PTR)lpvSection; +} + +ULONG_PTR RVAToFileOffsetPointer(ULONG_PTR pModule, DWORD dwRVA) +{ + PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)pModule; + PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)(pModule + ((PIMAGE_DOS_HEADER)pModule)->e_lfanew); + PIMAGE_SECTION_HEADER SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&ImageNtHeaders->OptionalHeader + ImageNtHeaders->FileHeader.SizeOfOptionalHeader); + + for (WORD i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++) + { + if (SectionHeader[i].VirtualAddress <= dwRVA && SectionHeader[i].VirtualAddress + SectionHeader[i].Misc.VirtualSize > dwRVA) + { + dwRVA -= SectionHeader[i].VirtualAddress; + dwRVA += SectionHeader[i].PointerToRawData; + + return pModule + dwRVA; + } + } + + return NULL; +} + +ULONG_PTR FindBytes(ULONG_PTR Source, DWORD SourceLength, ULONG_PTR Search, DWORD SearchLength) +{ + while (SearchLength <= SourceLength) + { + if (!memcmp((PBYTE)Source, (PBYTE)Search, SearchLength)) + { + return Source; + } + + Source++; + SourceLength--; + } + + return NULL; +} + +UINT ExtractSyscalls(ULONG_PTR pNtdll, CHAR rgszNames[MAX_NUMBER_OF_SYSCALLS][MAX_EXPORT_NAME_LENGTH], ULONG_PTR rgpStubs[MAX_NUMBER_OF_SYSCALLS]) +{ + PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)pNtdll; + PIMAGE_NT_HEADERS ImageNtHeaders = (PIMAGE_NT_HEADERS)(pNtdll + ((PIMAGE_DOS_HEADER)pNtdll)->e_lfanew); + PIMAGE_SECTION_HEADER SectionHeader = (PIMAGE_SECTION_HEADER)((ULONG_PTR)&ImageNtHeaders->OptionalHeader + ImageNtHeaders->FileHeader.SizeOfOptionalHeader); + + PIMAGE_DATA_DIRECTORY DataDirectory = (PIMAGE_DATA_DIRECTORY)ImageNtHeaders->OptionalHeader.DataDirectory; + DWORD VirtualAddress = DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; + PIMAGE_EXPORT_DIRECTORY ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)RVAToFileOffsetPointer(pNtdll, VirtualAddress); + + DWORD NumberOfNames = ExportDirectory->NumberOfNames; + + NumberOfNames = ExportDirectory->NumberOfNames; + + PDWORD Functions = (PDWORD)RVAToFileOffsetPointer(pNtdll, ExportDirectory->AddressOfFunctions); + PDWORD Names = (PDWORD)RVAToFileOffsetPointer(pNtdll, ExportDirectory->AddressOfNames); + PWORD Ordinals = (PWORD)RVAToFileOffsetPointer(pNtdll, ExportDirectory->AddressOfNameOrdinals); + + UINT uiCount = 0; + + ULONG_PTR pStubs = (ULONG_PTR)VirtualAlloc(NULL, MAX_NUMBER_OF_SYSCALLS * MAX_SYSCALL_STUB_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + + if (!pStubs) + { + return 0; + } + + for (DWORD i = 0; i < NumberOfNames && uiCount < MAX_NUMBER_OF_SYSCALLS; i++) + { + PCHAR FunctionName = (PCHAR)RVAToFileOffsetPointer(pNtdll, Names[i]); + + if (*(USHORT*)FunctionName == 'wZ') + { + ULONG_PTR FunctionPtr = RVAToFileOffsetPointer(pNtdll, Functions[Ordinals[i]]); + ULONG_PTR FunctionEnd = FindBytes(FunctionPtr, MAX_SYSCALL_STUB_SIZE, (ULONG_PTR)"\x0f\x05\xc3", 3) + 3; + + if (FunctionEnd) + { + strcpy_s(rgszNames[uiCount], MAX_EXPORT_NAME_LENGTH, FunctionName); + *(WORD*)(rgszNames[uiCount]) = 'tN'; + + memcpy((PBYTE)pStubs + (uiCount * MAX_SYSCALL_STUB_SIZE), (PBYTE)FunctionPtr, FunctionEnd - FunctionPtr); + rgpStubs[uiCount] = pStubs + (uiCount * MAX_SYSCALL_STUB_SIZE); + uiCount++; + } + } + } + + return uiCount; +} + +ULONG_PTR GetSyscall(CHAR rgszNames[MAX_NUMBER_OF_SYSCALLS][MAX_EXPORT_NAME_LENGTH], ULONG_PTR rgpStubs[MAX_NUMBER_OF_SYSCALLS], UINT uiCount, PCHAR pzSyscallName) +{ + for (UINT i = 0; i < uiCount; i++) + { + if (!strcmp(rgszNames[i], pzSyscallName)) + { + return rgpStubs[i]; + } + } + + return NULL; +} + +typedef NTSTATUS(NTAPI* FUNC_NTCREATETHREADEX)( + OUT PHANDLE hThread, + IN ACCESS_MASK DesiredAccess, + IN PVOID ObjectAttributes, + IN HANDLE ProcessHandle, + IN PVOID lpStartAddress, + IN PVOID lpParameter, + IN ULONG Flags, + IN SIZE_T StackZeroBits, + IN SIZE_T SizeOfStackCommit, + IN SIZE_T SizeOfStackReserve, + OUT PVOID lpBytesBuffer); + +int main(void) +{ + InitSyscallsFromLdrpThunkSignature(); + ULONG_PTR pNtdll = LoadNtdllIntoSection(); + + CHAR rgszNames[MAX_NUMBER_OF_SYSCALLS][MAX_EXPORT_NAME_LENGTH] = { 0 }; + ULONG_PTR rgpStubs[MAX_NUMBER_OF_SYSCALLS] = { 0 }; + + UINT uiCount = ExtractSyscalls(pNtdll, rgszNames, rgpStubs); + + FUNC_NTCREATETHREADEX NtCreateThreadEx = (FUNC_NTCREATETHREADEX)GetSyscall(rgszNames, rgpStubs, uiCount, (PCHAR)"NtCreateThreadEx"); + + NTSTATUS ntStatus; + HANDLE hThread = NULL; + + ntStatus = NtCreateThreadEx(&hThread, GENERIC_ALL, NULL, GetCurrentProcess(), (LPTHREAD_START_ROUTINE)0x41414141, NULL, 0, 0, 0, 0, NULL); + + if (!NT_SUCCESS(ntStatus)) + { + return FALSE; + } + + Sleep(INFINITE); + + return 0; +}