Skip to content

Instantly share code, notes, and snippets.

@rbmm
Created May 30, 2023 09:54
Show Gist options
  • Save rbmm/f6fb914e74b5a81b448889a25e500365 to your computer and use it in GitHub Desktop.
Save rbmm/f6fb914e74b5a81b448889a25e500365 to your computer and use it in GitHub Desktop.

Revisions

  1. rbmm created this gist May 30, 2023.
    327 changes: 327 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,327 @@
    #include "stdafx.h"

    _NT_BEGIN

    NTSTATUS CreatePlaceHolder(PCWSTR lpFileName, ULONG SizeOfImage)
    {
    struct SEF : IMAGE_DOS_HEADER, IMAGE_NT_HEADERS, IMAGE_SECTION_HEADER
    {
    } y {};

    SYSTEM_INFO si;
    GetSystemInfo(&si);
    SizeOfImage = (SizeOfImage + si.dwAllocationGranularity - 1) & ~(si.dwAllocationGranularity - 1);

    SIZE_T Alignment = si.dwPageSize - 1;

    y.e_magic = IMAGE_DOS_SIGNATURE;
    y.e_lfanew = sizeof(IMAGE_DOS_HEADER);
    y.Signature = IMAGE_NT_SIGNATURE;

    #ifdef _WIN64
    y.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64;
    y.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
    y.OptionalHeader.ImageBase = 1 + (ULONG_PTR)MAXULONG;
    #else
    y.FileHeader.Machine = IMAGE_FILE_MACHINE_I386;
    y.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC;
    y.OptionalHeader.ImageBase = 0x40000000;
    #endif
    y.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER);
    y.FileHeader.NumberOfSections = 1;
    y.FileHeader.Characteristics = IMAGE_FILE_DLL|IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_LARGE_ADDRESS_AWARE;
    y.OptionalHeader.SectionAlignment = si.dwPageSize;
    y.OptionalHeader.FileAlignment = si.dwPageSize;
    y.OptionalHeader.MajorOperatingSystemVersion = _WIN32_WINNT_VISTA >> 8;
    y.OptionalHeader.MajorSubsystemVersion = _WIN32_WINNT_VISTA >> 8;
    y.OptionalHeader.SizeOfHeaders = (ULONG)((sizeof(y) + Alignment) & ~Alignment);
    y.OptionalHeader.SizeOfImage = SizeOfImage;
    y.OptionalHeader.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
    y.OptionalHeader.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE|IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA|IMAGE_DLLCHARACTERISTICS_NX_COMPAT;
    y.OptionalHeader.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
    y.VirtualAddress = si.dwPageSize;
    y.Misc.VirtualSize = SizeOfImage - si.dwPageSize;
    y.Characteristics = IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;

    NTSTATUS status;
    UNICODE_STRING ObjectName;
    if (0 <= (status = RtlDosPathNameToNtPathName_U_WithStatus(lpFileName, &ObjectName, 0, 0)))
    {
    HANDLE hFile = 0;
    IO_STATUS_BLOCK iosb;
    OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName, OBJ_CASE_INSENSITIVE };

    FILE_BASIC_INFORMATION fbi;
    if (0 > ZwQueryAttributesFile(&oa, &fbi))
    {
    status = NtCreateFile(&hFile, FILE_APPEND_DATA|SYNCHRONIZE, &oa, &iosb, 0,
    FILE_ATTRIBUTE_TEMPORARY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, 0,
    FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE, 0, 0);
    }

    RtlFreeUnicodeString(&ObjectName);

    if (0 <= status && hFile)
    {
    status = NtWriteFile(hFile, 0, 0, 0, &iosb, &y, sizeof(y), 0, 0);
    NtClose(hFile);
    }
    }

    return status;
    }

    struct IMAGE_Ctx : public TEB_ACTIVE_FRAME
    {
    inline static const char FrameName[] = "{0A0659E5-2962-480a-9A6F-01A02C5C043B}";

    PIMAGE_NT_HEADERS _M_pinth;
    PVOID _M_retAddr = 0, _M_pvImage, *_M_pBaseAddress = 0;
    PCWSTR _M_lpFileName;
    NTSTATUS _M_status = STATUS_UNSUCCESSFUL;

    IMAGE_Ctx(PVOID pvImage, PIMAGE_NT_HEADERS pinth, PCWSTR lpFileName)
    : _M_pvImage(pvImage), _M_pinth(pinth), _M_lpFileName(lpFileName)
    {
    const static TEB_ACTIVE_FRAME_CONTEXT FrameContext = { 0, FrameName };
    Context = &FrameContext;
    Flags = 0;
    RtlPushFrame(this);
    }

    ~IMAGE_Ctx()
    {
    RtlPopFrame(this);
    }

    static IMAGE_Ctx* get()
    {
    if (TEB_ACTIVE_FRAME * frame = RtlGetFrame())
    {
    do
    {
    if (frame->Context->FrameName == FrameName)
    {
    return static_cast<IMAGE_Ctx*>(frame);
    }
    } while (frame = frame->Previous);
    }

    return 0;
    }
    };

    NTSTATUS OverwriteSection(_In_ PVOID BaseAddress, _In_ PVOID pvImage, _In_ PIMAGE_NT_HEADERS pinth)
    {
    ULONG op, cb = pinth->OptionalHeader.SizeOfHeaders, VirtualSize, SizeOfRawData;
    PVOID pv = BaseAddress, VirtualAddress;
    SIZE_T ProtectSize = cb;

    NTSTATUS status;
    if (0 > (status = ZwProtectVirtualMemory(NtCurrentProcess(), &pv, &ProtectSize, PAGE_READWRITE, &op)))
    {
    return status;
    }

    memcpy(BaseAddress, pvImage, cb);

    ZwProtectVirtualMemory(NtCurrentProcess(), &pv, &ProtectSize, PAGE_READONLY, &op);

    if (ULONG NumberOfSections = pinth->FileHeader.NumberOfSections)
    {
    PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinth);

    do
    {
    if (VirtualSize = pish->Misc.VirtualSize)
    {
    VirtualAddress = RtlOffsetToPointer(BaseAddress, pish->VirtualAddress);

    ULONG Characteristics = pish->Characteristics;

    if (0 > (status = ZwProtectVirtualMemory(NtCurrentProcess(), &(pv = VirtualAddress),
    &(ProtectSize = VirtualSize),
    Characteristics & IMAGE_SCN_MEM_EXECUTE ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &op)))
    {
    return status;
    }

    if (cb = min(VirtualSize, SizeOfRawData = pish->SizeOfRawData))
    {
    memcpy(VirtualAddress, RtlOffsetToPointer(pvImage, pish->PointerToRawData), cb);
    }

    if (SizeOfRawData < VirtualSize)
    {
    RtlZeroMemory(RtlOffsetToPointer(VirtualAddress, cb), VirtualSize - SizeOfRawData);
    }

    if (!(Characteristics & IMAGE_SCN_MEM_WRITE))
    {
    if (0 > (status = ZwProtectVirtualMemory(NtCurrentProcess(), &pv, &ProtectSize,
    Characteristics & IMAGE_SCN_MEM_EXECUTE ? PAGE_EXECUTE_READ : PAGE_READONLY, &op)))
    {
    return status;
    }
    }
    }

    } while (pish++, --NumberOfSections);
    }

    return STATUS_SUCCESS;
    }

    //#define _PRINT_CPP_NAMES_
    #include "../inc/asmfunc.h"

    NTSTATUS __fastcall retFromMapViewOfSection(NTSTATUS status)
    {
    CPP_FUNCTION;

    if (IMAGE_Ctx* ctx = IMAGE_Ctx::get())
    {
    *(void**)_AddressOfReturnAddress() = ctx->_M_retAddr;

    if (0 <= status)
    {
    PVOID BaseAddress = *ctx->_M_pBaseAddress;

    if (0 <= (status = OverwriteSection(BaseAddress, ctx->_M_pvImage, ctx->_M_pinth)))
    {
    if (BaseAddress != (PVOID)ctx->_M_pinth->OptionalHeader.ImageBase)
    {
    status = STATUS_IMAGE_NOT_AT_BASE;
    }
    }

    if (0 > status)
    {
    ZwUnmapViewOfSection(NtCurrentProcess(), BaseAddress);

    *ctx->_M_pBaseAddress = 0;
    }
    }

    ctx->_M_status = status;
    }

    return status;
    }

    NTSTATUS aretFromMapViewOfSection()ASM_FUNCTION;

    LONG NTAPI MyVexHandler(::PEXCEPTION_POINTERS ExceptionInfo)
    {
    ::PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord;
    ::PCONTEXT ContextRecord = ExceptionInfo->ContextRecord;

    if (ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP && ExceptionRecord->ExceptionAddress == ZwMapViewOfSection)
    {
    if (IMAGE_Ctx* ctx = IMAGE_Ctx::get())
    {
    PCWSTR lpFileName = (PCWSTR)reinterpret_cast<PNT_TIB>(NtCurrentTeb())->ArbitraryUserPointer;
    if (lpFileName && !wcscmp(lpFileName, ctx->_M_lpFileName))
    {
    ctx->_M_pBaseAddress =
    #ifdef _WIN64
    (void**)ContextRecord->R8;

    #define SP Rsp
    #else
    #define SP Esp
    ((void***)ContextRecord->Esp)[3];
    #endif

    *(PSIZE_T)((void**)ContextRecord->SP)[7] = ctx->_M_pinth->OptionalHeader.SizeOfImage;

    ctx->_M_retAddr = ((void**)ContextRecord->SP)[0];

    ((void**)ContextRecord->SP)[0] = aretFromMapViewOfSection;
    }
    }

    ContextRecord->EFlags |= 0x10000;

    return EXCEPTION_CONTINUE_EXECUTION;
    }

    return EXCEPTION_CONTINUE_SEARCH;
    }

    NTSTATUS LoadLibraryFromMem(_Out_ HMODULE* phmod, _In_ PVOID pvImage, _In_ PIMAGE_NT_HEADERS pinth, _In_ PCWSTR lpFileName)
    {
    if (PVOID VectoredHandlerHandle = RtlAddVectoredExceptionHandler(TRUE, MyVexHandler))
    {
    CONTEXT ctx = {};
    ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
    ctx.Dr3 = (ULONG_PTR)ZwMapViewOfSection;
    ctx.Dr7 = 0x440;

    NTSTATUS status;
    if (0 <= (status = ZwSetContextThread(NtCurrentThread(), &ctx)))
    {
    IMAGE_Ctx ictx(pvImage, pinth, lpFileName);

    UNICODE_STRING us;
    RtlInitUnicodeString(&us, lpFileName);

    status = LdrLoadDll(0, 0, &us, phmod);

    ctx.Dr3 = 0;
    ctx.Dr7 = 0x400;
    ZwSetContextThread(NtCurrentThread(), &ctx);

    if (0 <= status && 0 > ictx._M_status)
    {
    LdrUnloadDll(*phmod);
    }

    status = ictx._M_status;
    }

    RtlRemoveVectoredExceptionHandler(VectoredHandlerHandle);

    return status;
    }

    return STATUS_UNSUCCESSFUL;
    }

    NTSTATUS LoadLibraryFromMem(_Out_ HMODULE* phmod, _In_ PVOID pvImage)
    {
    PIMAGE_NT_HEADERS pinth = RtlImageNtHeader(pvImage);

    if (!pinth)
    {
    return STATUS_INVALID_IMAGE_FORMAT;
    }

    WCHAR buf[32];
    if (0 < swprintf_s(buf, _countof(buf), L"%%tmp%%\\$$%X.%X.tmp",
    pinth->OptionalHeader.SizeOfImage, pinth->FileHeader.Machine))
    {
    ULONG cch = 0;
    PWSTR lpFileName = 0;
    while (cch = ExpandEnvironmentStringsW(buf, lpFileName, cch))
    {
    if (lpFileName)
    {
    NTSTATUS status = CreatePlaceHolder(lpFileName, pinth->OptionalHeader.SizeOfImage);
    if (0 <= status)
    {
    status = LoadLibraryFromMem(phmod, pvImage, pinth, lpFileName);
    }
    return status;
    }

    lpFileName = (PWSTR)alloca(cch * sizeof(WCHAR));
    }

    return HRESULT_FROM_WIN32(GetLastError());
    }

    return STATUS_INTERNAL_ERROR;
    }

    _NT_END