Files
WinArk/KernelLibrary/Section.cpp
T
2022-09-05 08:38:10 +08:00

227 lines
5.8 KiB
C++

#include "pch.h"
#include "Section.h"
#include "Logging.h"
#include "Memory.h"
#include "ObjectAttributes.h"
#include "Common.h"
NTSTATUS Section::Initialize(SectionType type){
// Initialize this object
_type = type;
// Initialize our singleton
RtlRunOnceInitialize(&_sectionSingletonState);
return STATUS_SUCCESS;
}
// Get DLL section object
NTSTATUS Section::GetSection(DllStats** ppSectionInfo) {
NTSTATUS status = STATUS_SUCCESS;
// make sure that Initialize was called!
ASSERT(_type == SectionType::Native || _type == SectionType::Wow);
// Use the single approach
PVOID Context = nullptr;
do
{
status = RtlRunOnceBeginInitialize(&_sectionSingletonState, 0, &Context);
if (status == STATUS_PENDING) {
// We get here only during the first initialization
Context = nullptr;
// Allocate memory
DllStats* pDllState = new (PagedPool,'mSDk') DllStats;
if (pDllState) {
// Need to "trick" the system into creating a KnownDll section for us with the SD of
// the kernel32.dll section
// Temporarily attach the current thread to the address space of the system process
KAPC_STATE state;
KeStackAttachProcess(PsInitialSystemProcess, &state);
// Create our KnownDll section to bypass code integrity guard
status = CreateKnownDllSection(*pDllState);
// Revert back
KeUnstackDetachProcess(&state);
// Check the result
if (NT_SUCCESS(status)) {
Context = pDllState;
}
else {
LogError("ERROR: (0x%x), sectionType=%d", status, _type);
// Free memory
delete pDllState;
pDllState = nullptr;
}
}
else {
status = STATUS_MEMORY_NOT_ALLOCATED;
LogError("ERROR: (0x%x) , section type=%d", status, _type);
break;
}
// Finilize our singleton
status = RtlRunOnceComplete(&_sectionSingletonState, 0, Context);
if (!NT_SUCCESS(status)) {
// Error
LogError("ERROR: (0x%x) RtlRunOnceComplete, section type=%d", status, _type);
ASSERT(nullptr);
// Free memory
if (pDllState) {
delete pDllState;
pDllState = nullptr;
}
Context = nullptr;
break;
}
}
else if (status != STATUS_SUCCESS) {
// Error
LogError("ERROR: (0x%x) RtlRunOnceBeginInitialize, section type=%d", status, _type);
}
} while (false);
if (ppSectionInfo)
*ppSectionInfo = (DllStats*)Context;
return status;
}
NTSTATUS Section::FreeSection() {
// Release resources held for the mapped section
NTSTATUS status;
PVOID Context = nullptr;
status = RtlRunOnceBeginInitialize(&_sectionSingletonState, 0, &Context);
if (NT_SUCCESS(status)) {
// We have initilized our singleton
// do we have the context - otherwise there's nothing to delete
if (Context) {
LogInfo("FreeSection ,sectionType=%d", _type);
DllStats* pDllState = (DllStats*)Context;
// Free memory
delete pDllState;
Context = nullptr;
}
// Reset the singleton back
RtlRunOnceInitialize(&_sectionSingletonState);
}
else if (status == STATUS_UNSUCCESSFUL) {
// GetSection() wasn't called yet
status = STATUS_SUCCESS;
}
else {
// Error
LogError("0x%x RtlRunOnceBeginInitialize", status);
ASSERT(nullptr);
}
return status;
}
NTSTATUS Section::CreateKnownDllSection(DllStats& dllState) {
// Create a known dll system section of our own
NTSTATUS status;
// Clear the return data (assuming only primitive data types)
memset(&dllState, 0, sizeof(dllState));
// need to steal a security descriptor from a existing KnownDll - we'll use kernel32
HANDLE hSectionK32;
#ifdef _WIN64
UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\KnownDlls\\kernel32.dll");
ObjectAttributes attr(&name, ObjectAttributesFlags::Caseinsensive);
UNICODE_STRING objName = RTL_CONSTANT_STRING(INJECTED_DLL_FILE_NAME);
#else
UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\KnownDlls32\\kernel32.dll");
ObjectAttributes attr(&name, ObjectAttributesFlags::Caseinsensive);
UNICODE_STRING objName = RTL_CONSTANT_STRING(INJECTED_DLL_FILE_NAME);
#endif // _WIN64
status = ZwOpenSection(&hSectionK32, READ_CONTROL, &attr);
if (NT_SUCCESS(status)) {
status = STATUS_GENERIC_COMMAND_FAILED;
// INFO: Make our section "permanent", which means that it won't be deleted if all of its handle are closed
// and we will need to call ZwMakeTemporaryObject() on it first to allow it.
ObjectAttributes objAttr(&objName, ObjectAttributesFlags::Caseinsensive | ObjectAttributesFlags::Permanent);
LogInfo("Got KnownDll Ok!\n");
ULONG size = 0;
for (;;) {
ULONG needSize = 0;
status = ZwQuerySecurityObject(hSectionK32, PROCESS_TRUST_LABEL_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
objAttr.SecurityDescriptor, // SD
size, // mem size
&needSize);
if (NT_SUCCESS(status)) {
// Got it
break;
}
else if (STATUS_BUFFER_TOO_SMALL == status) {
// We need more memory
ASSERT(needSize > size);
if (objAttr.SecurityDescriptor) {
// Free previous memory
ExFreePool(objAttr.SecurityDescriptor);
objAttr.SecurityDescriptor = nullptr;
}
// Allocate mem
objAttr.SecurityDescriptor = ExAllocatePoolWithTag(PagedPool, needSize, 'm23k');
if (objAttr.SecurityDescriptor) {
// Need to retry
size = needSize;
}
else {
// Error
status = STATUS_MEMORY_NOT_ALLOCATED;
LogError("0x%x\n", status);
break;
}
}
else {
// Error
LogError("0x%x\n", status);
break;
}
}
// Close section
status = ZwClose(hSectionK32);
if (NT_SUCCESS(status)) {
// Now we can create our own seciton for our injected DLL in the KnownDlls kernel object directory
}
// Free our memory
if (objAttr.SecurityDescriptor) {
ExFreePool(objAttr.SecurityDescriptor);
objAttr.SecurityDescriptor = nullptr;
}
}
else {
// Error
LogError("Error: 0x%x ZwOpenSection PID=%u sectionType=%d\n", status,
PsGetCurrentProcessId(),_type);
}
return status;
}