Files
rbmm 1d1cc7dd82 s
2019-08-12 15:26:16 +03:00

481 lines
12 KiB
C++

BOOL IsKeySz(PKEY_VALUE_PARTIAL_INFORMATION pkvpi)
{
ULONG DataLength = pkvpi->DataLength;
return (pkvpi->Type == REG_SZ || pkvpi->Type == REG_EXPAND_SZ) &&
(DataLength - 1 < MAXUSHORT) && !(DataLength & (sizeof(WCHAR) - 1)) &&
!((PWSTR)RtlOffsetToPointer(pkvpi->Data, DataLength))[-1];
}
NTSTATUS RegGetValue(
HANDLE hKey,
PCUNICODE_STRING ValueName,
BOOL (*Validate)(PKEY_VALUE_PARTIAL_INFORMATION),
PKEY_VALUE_PARTIAL_INFORMATION* ppkvpi
)
{
NTSTATUS status;
DWORD cb = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 16 * sizeof(WCHAR);
union {
PVOID buf;
PKEY_VALUE_PARTIAL_INFORMATION pkvpi;
};
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (buf = LocalAlloc(0, cb))
{
if (0 <= (status = ZwQueryValueKey(hKey, ValueName, KeyValuePartialInformation, pkvpi, cb, &cb)))
{
if (Validate(pkvpi))
{
*ppkvpi = pkvpi;
return STATUS_SUCCESS;
}
status = STATUS_OBJECT_TYPE_MISMATCH;
}
LocalFree(pkvpi);
}
} while (status == STATUS_BUFFER_OVERFLOW);
DbgPrint("GetValue(%wZ)=%x\n", ValueName, status);
return status;
}
#pragma intrinsic(_lrotr, _lrotl)
#define RUN_ONCE_STATUS_TO_CONTEXT(status) ((PVOID)(ULONG_PTR)(_lrotl(status, 4) & ~((1 << RTL_RUN_ONCE_CTX_RESERVED_BITS) - 1)))
#define RUN_ONCE_CONTEXT_TO_STATUS(Context) ((NTSTATUS)_lrotr((ULONG)(ULONG_PTR)Context, 4))
struct DLL_INFORMATION
{
RTL_RUN_ONCE SectionStatus;
PVOID Section, PreferredAddress;
ULONG rva_1, SizeOfImage;
NTSTATUS CreateDllSection();
NTSTATUS GetSection(PVOID* pSection)
{
union {
PVOID Context;
NTSTATUS status;
};
if (RtlRunOnceBeginInitialize(&SectionStatus, 0, &Context) == STATUS_PENDING)
{
RtlRunOnceComplete(&SectionStatus, 0, Context = RUN_ONCE_STATUS_TO_CONTEXT(CreateDllSection()));
}
status = RUN_ONCE_CONTEXT_TO_STATUS(Context);
*pSection = Section;
return status;
}
NTSTATUS MapSection(HANDLE hProcess, PVOID& hmod)
{
PVOID ReservedAddress = PreferredAddress, BaseAddress = 0;
SIZE_T RegionSize = SizeOfImage, ViewSize = 0;
NTSTATUS status = ZwAllocateVirtualMemory(hProcess, &ReservedAddress, 0, &RegionSize, MEM_RESERVE, PAGE_NOACCESS);
bool bFreeMemory = false;
switch (status)
{
case STATUS_SUCCESS:
bFreeMemory = true;
case STATUS_CONFLICTING_ADDRESSES:
static LARGE_INTEGER ZeroOffset;
if (0 <= (status = ZwMapViewOfSection(Section, hProcess, &BaseAddress,
0, 0, &ZeroOffset, &ViewSize, ViewUnmap, 0, PAGE_EXECUTE)))
{
hmod = BaseAddress;
}
break;
}
DbgPrint("MapSection[%x]: %x %p\n", status, bFreeMemory, BaseAddress);
if (bFreeMemory)
{
ZwFreeVirtualMemory(hProcess, &ReservedAddress, &RegionSize, MEM_RELEASE);
}
return status;
}
};
namespace DLL_32
{
#include "../dlldemo/md5_32.h" // autogenerated file, on post-build step for DllDemo
DLL_INFORMATION di {};
}
#ifdef _WIN64
namespace DLL_64
{
#include "../dlldemo/md5_64.h" // autogenerated file, on post-build step for DllDemo
DLL_INFORMATION di {};
}
#endif
#ifdef _WIN64
#define NATIVE_DLL DLL_64
#define WOW_DLL DLL_32
#else
#define NATIVE_DLL DLL_32
#endif
NTSTATUS MapPeAsData(HANDLE hFile, PVOID* BaseAddress, PSIZE_T ViewSize)
{
HANDLE hSection;
NTSTATUS status = ZwCreateSection(&hSection, SECTION_MAP_READ, 0, 0, PAGE_READONLY, SEC_COMMIT, hFile);
if (0 <= status)
{
status = ZwMapViewOfSection(hSection, NtCurrentProcess(), BaseAddress, 0, 0, 0, ViewSize, ViewUnmap, 0, PAGE_READONLY);
}
ZwClose(hSection);
return status;
}
PVOID AddressInSectionTable
(
PIMAGE_NT_HEADERS NtHeaders,
PVOID Base,
ULONG Rva
)
{
if (ULONG NumberOfSections = NtHeaders->FileHeader.NumberOfSections)
{
PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(NtHeaders);
do
{
ULONG o = Rva - pish->VirtualAddress;
if (o < pish->Misc.VirtualSize)
{
return (PBYTE)Base + pish->PointerToRawData + o;
}
} while (pish++, --NumberOfSections);
}
return 0;
}
NTSTATUS IsFileOk(HANDLE hFile, PVOID _md5, ULONG FileSize, PULONG rva, PULONG AddressOfEntryPoint, PULONG SizeOfImage)
{
NTSTATUS status;
BCRYPT_ALG_HANDLE hAlgorithm;
if (0 <= (status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_MD5_ALGORITHM, 0, 0)))
{
union {
ULONG64 align;
UCHAR md5[16];
};
BCRYPT_HASH_HANDLE hHash;
if (0 <= (status = BCryptCreateHash(hAlgorithm, &hHash, 0, 0, 0, 0, 0)))
{
PVOID BaseAddress = 0;
SIZE_T ViewSize = 0;
if (0 <= (status = MapPeAsData(hFile, &BaseAddress, &ViewSize)))
{
status = FileSize > ViewSize ? STATUS_INVALID_IMAGE_HASH : BCryptHashData(hHash, (PUCHAR)BaseAddress, FileSize, 0);
if (0 <= status && 0 <= (status = BCryptFinishHash(hHash, md5, sizeof(md5), 0)))
{
DbgPrint("md5_0: %016I64x%016I64x\nmd5_1: %016I64x%016I64x\n",
*(1 + (PULONG64)_md5), *(PULONG64)_md5,
*(1 + (PULONG64)md5), *(PULONG64)md5);
if (memcmp(md5, _md5, sizeof(md5)))
{
status = STATUS_INVALID_IMAGE_HASH;
}
else
{
status = STATUS_INVALID_IMAGE_FORMAT;
if (PIMAGE_NT_HEADERS pinth = RtlImageNtHeader(BaseAddress))
{
status = STATUS_PROCEDURE_NOT_FOUND;
ULONG size, Ordinal = 1;
PIMAGE_EXPORT_DIRECTORY pied = (PIMAGE_EXPORT_DIRECTORY)
RtlImageDirectoryEntryToData(BaseAddress, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &size);
if (pied && size >= sizeof(IMAGE_EXPORT_DIRECTORY) && (Ordinal -= pied->Base) < pied->NumberOfFunctions)
{
if (PULONG AddressOfFunctions = (PULONG)AddressInSectionTable(pinth, BaseAddress, pied->AddressOfFunctions))
{
*rva = AddressOfFunctions[Ordinal];
*AddressOfEntryPoint = pinth->OptionalHeader.AddressOfEntryPoint;
*SizeOfImage = pinth->OptionalHeader.SizeOfImage;
status = STATUS_SUCCESS;
}
}
}
}
}
ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
}
BCryptDestroyHash(hHash);
}
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
}
return status;
}
NTSTATUS CreateKnownSection(HANDLE hFile, PCOBJECT_ATTRIBUTES poaKernel32, PCUNICODE_STRING My, PVOID* pTransferAddress, PVOID *pSection)
{
ULONG cb = 0, rcb = 64;
static volatile UCHAR guz;
PVOID stack = alloca(guz);
HANDLE hSection;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, const_cast<PUNICODE_STRING>(My), OBJ_CASE_INSENSITIVE };
// look for system (smss.exe) assigned SD for known dlls
NTSTATUS status = ZwOpenSection(&hSection, READ_CONTROL, const_cast<POBJECT_ATTRIBUTES>(poaKernel32));
if (0 <= status)
{
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(oa.SecurityDescriptor = alloca(rcb - cb), stack);
}
status = ZwQuerySecurityObject(hSection,
PROCESS_TRUST_LABEL_SECURITY_INFORMATION|
DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION,
oa.SecurityDescriptor, cb, &rcb);
} while (status == STATUS_BUFFER_TOO_SMALL);
NtClose(hSection);
if (0 <= status)
{
// not use &oa - no access to \\KnownDlls as result S-1-19-512-8192 label
// SECURITY_PROCESS_TRUST_AUTHORITY - SECURITY_PROCESS_PROTECTION_TYPE_LITE_RID - SECURITY_PROCESS_PROTECTION_LEVEL_WINTCB_RID
status = ZwCreateSection(&hSection, SECTION_MAP_EXECUTE|SECTION_QUERY, /*&oa*/0, 0, PAGE_EXECUTE, SEC_IMAGE, hFile);
if (0 <= status)
{
SECTION_IMAGE_INFORMATION sii;
status = ZwQuerySection(hSection, SectionImageInformation, &sii, sizeof(sii), 0);
DbgPrint("[%08x]:%wZ<%p> at %p\n", status, My, hSection, sii.TransferAddress);
if (0 <= status)
{
*pTransferAddress = sii.TransferAddress;
*pSection = hSection;
return STATUS_SUCCESS;
}
ZwClose(hSection);
}
}
}
return status;
}
NTSTATUS DLL_INFORMATION::CreateDllSection()
{
ULONG FileSize;
PVOID md5;
PCOBJECT_ATTRIBUTES poaKernel32, poaDLL;
PCUNICODE_STRING pMy;
#ifdef _WIN64
if (this == &WOW_DLL::di)
{
STATIC_UNICODE_STRING(My, "\\KnownDlls32\\{EBB50DDB-F6AA-492d-94E3-1D51B299F627}.DLL");
STATIC_OBJECT_ATTRIBUTES(oaKernel32, "\\KnownDlls32\\kernel32.dll");
STATIC_OBJECT_ATTRIBUTES(oaDLL, "\\systemroot\\syswow64\\{EBB50DDB-F6AA-492d-94E3-1D51B299F627}.DLL");
poaKernel32 = &oaKernel32, pMy = &My, poaDLL = &oaDLL;
FileSize = WOW_DLL::FileSize;
md5 = &WOW_DLL::md5;
}
else
#endif
{
STATIC_UNICODE_STRING(My, "\\KnownDlls\\{EBB50DDB-F6AA-492d-94E3-1D51B299F627}.DLL");
STATIC_OBJECT_ATTRIBUTES(oaKernel32, "\\KnownDlls\\kernel32.dll");
STATIC_OBJECT_ATTRIBUTES(oaDLL, "\\systemroot\\system32\\{EBB50DDB-F6AA-492d-94E3-1D51B299F627}.DLL");
poaKernel32 = &oaKernel32, pMy = &My, poaDLL = &oaDLL;
FileSize = NATIVE_DLL::FileSize;
md5 = &NATIVE_DLL::md5;
}
HANDLE hFile;
IO_STATUS_BLOCK iosb;
NTSTATUS status = ZwOpenFile(&hFile, FILE_GENERIC_READ|FILE_EXECUTE,
const_cast<POBJECT_ATTRIBUTES>(poaDLL), &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
DbgPrint("OpenFile(%wZ)=%x\n", poaDLL->ObjectName, status);
if (0 <= status)
{
FILE_STANDARD_INFORMATION fsi;
if (0 <= (status = ZwQueryInformationFile(hFile, &iosb, &fsi, sizeof(fsi), FileStandardInformation)))
{
DbgPrint("EndOfFile=%I64x\n_FileSize=%x\n", fsi.EndOfFile.QuadPart, FileSize);
if (fsi.EndOfFile.QuadPart == FileSize)
{
ULONG AddressOfEntryPoint;
if (0 <= (status = IsFileOk(hFile, md5, FileSize, &rva_1, &AddressOfEntryPoint, &SizeOfImage)))
{
PVOID TransferAddress;
status = CreateKnownSection(hFile, poaKernel32, pMy, &TransferAddress, &Section);
PreferredAddress = (PBYTE)TransferAddress - AddressOfEntryPoint;
}
}
else
{
status = STATUS_INVALID_IMAGE_HASH;
}
}
ZwClose(hFile);
}
return status;
}
void FreeLoadImageData()
{
PVOID Context;
if (STATUS_SUCCESS == RtlRunOnceBeginInitialize(&NATIVE_DLL::di.SectionStatus, RTL_RUN_ONCE_CHECK_ONLY, &Context))
{
if (0 <= RUN_ONCE_CONTEXT_TO_STATUS(Context))
{
DbgPrint("delete section %p\n", NATIVE_DLL::di.Section);
NtClose(NATIVE_DLL::di.Section);
}
}
#ifdef _WIN64
if (STATUS_SUCCESS == RtlRunOnceBeginInitialize(&WOW_DLL::di.SectionStatus, RTL_RUN_ONCE_CHECK_ONLY, &Context))
{
if (0 <= RUN_ONCE_CONTEXT_TO_STATUS(Context))
{
DbgPrint("delete section %p\n", WOW_DLL::di.Section);
NtClose(WOW_DLL::di.Section);
}
}
#endif
}
void DoInject(BOOL Wow, HANDLE hProcess, HANDLE hThread)
{
DLL_INFORMATION* pdi = Wow ? &DLL_32::di : &DLL_64::di;
HANDLE hSection;
if (0 <= pdi->GetSection(&hSection))
{
PVOID BasseAddress;
union {
PVOID pvNormalRoutine;
PKNORMAL_ROUTINE NormalRoutine;
};
if (0 <= pdi->MapSection(hProcess, BasseAddress))
{
pvNormalRoutine = (PBYTE)BasseAddress + pdi->rva_1;
if (0 > (Wow ? RtlQueueApcWow64Thread : ZwQueueApcThread)(hThread, NormalRoutine, BasseAddress, NtCurrentProcess(), BasseAddress))
{
ZwUnmapViewOfSection(hProcess, BasseAddress);
}
}
}
}
void DoInject(HANDLE hProcess, HANDLE hThread)
{
DoInject(FALSE, hProcess, hThread);
#ifdef _WIN64
BOOL Wow;
if (IsWow64Process(hProcess, &Wow) && Wow)
{
DoInject(TRUE, hProcess, hThread);
}
#endif
}
void WINAPI EpZ(void*)
{
PROCESS_MITIGATION_CONTROL_FLOW_GUARD_POLICY cfg {};
cfg.EnableControlFlowGuard = 1;
cfg.EnableExportSuppression = 1;
cfg.StrictMode = 1;
if (SetProcessMitigationPolicy(::ProcessControlFlowGuardPolicy, &cfg, sizeof(cfg)))
{
DoInject(NtCurrentProcess(), NtCurrentThread());
ZwTestAlert();
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
if (CreateProcessW(L"c:/windows/syswow64/notepad.exe", 0, 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi))
{
DoInject(pi.hProcess, pi.hThread);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
if (CreateProcessW(L"c:/windows/notepad.exe", 0, 0, 0, 0, CREATE_SUSPENDED, 0, 0, &si, &pi))
{
DoInject(pi.hProcess, pi.hThread);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
}
FreeLoadImageData();
}
}