Mattiwatti / EfiGuard

Disable PatchGuard and Driver Signature Enforcement at boot time
GNU General Public License v3.0
1.69k stars 326 forks source link

Does ntoskrnl self-reparing? #84

Closed DecoderCoder closed 1 year ago

DecoderCoder commented 1 year ago

After trying to fake Windows Build Number (compatibility purpose) RtlGetVersion Patch works normally , but patch MmCreatePeb does not apply after win loading, neither does NtBuildNumber. I viewed Kernel Memory and there was not modified memory. But if modify ntoskrnl.exe file, it works perfect.

RtlGetVersion dbgView

MmCreatePeb (from PEB and import from ntdll.dll) RtlGetVersion

Sorry for off topic, if it is, close it

code:

STATIC CONST UINT8 SigRtlGetVersion[] = {
    0x0F ,0xB7, 0x05, 0xCC, 0xCC ,0xCC ,0xCC ,0x48, 0x8B ,0xD9
};

STATIC CONST UINT8 SigMmCreatePeb[] = {
    0x4C, 0x89, 0x7C, 0x24, 0xCC ,0x0F, 0xB7, 0x0D, 0xCC ,0xCC, 0xCC, 0xCC
};
--------------------------------------
UINT8* RtlGetVersionAddress = NULL;
    {
        PRINT_KERNEL_PATCH_MSG(L"== Searching for nt!RtlGetVersion pattern in PAGE ==\r\n");
        EFI_STATUS FindRtlGetVersion = FindPattern(SigRtlGetVersion,
            0xCC,
            sizeof(SigRtlGetVersion),
            ImageBase + PageSection->VirtualAddress,
            PageSection->SizeOfRawData,
            (VOID**)&RtlGetVersionAddress);

        if (EFI_ERROR(FindRtlGetVersion))
        {
            PRINT_KERNEL_PATCH_MSG(L"    Failed to find RtlGetVersion. Skipping patch.\r\n");
        }
        else {
            PRINT_KERNEL_PATCH_MSG(L"    Found RtlGetVersion pattern at 0x%llX.\r\n", (UINTN)RtlGetVersionAddress);
        }
    }

UINT8* MmCreatePebAddress = NULL;
    {
        PRINT_KERNEL_PATCH_MSG(L"== Searching for nt!MmCreatePebAddress pattern in PAGE ==\r\n");
        EFI_STATUS FinMmCreatePeb = FindPattern(SigMmCreatePeb,
            0xCC,
            sizeof(SigMmCreatePeb),
            ImageBase + PageSection->VirtualAddress,
            PageSection->SizeOfRawData,
            (VOID**)&MmCreatePebAddress);

        if (EFI_ERROR(FinMmCreatePeb))
        {
            PRINT_KERNEL_PATCH_MSG(L"    Failed to find MmCreatePeb. Skipping patch.\r\n");
        }
        else {
            MmCreatePebAddress += 5;
            PRINT_KERNEL_PATCH_MSG(L"    Found MmCreatePeb pattern at 0x%llX.\r\n", (UINTN)RtlGetVersionAddress);
        }
    }

------------------------------------------
    short newWinBuildNumber = 24000;
    char buildNumPatch[] = { 0xB8, 0xCC, 0xCC, 0x00, 0x00, 0x90, 0x90 }; //
    char buildNumPatch2[] = { 0xB9, 0xCC, 0xCC, 0x00, 0x00, 0x90, 0x90 }; // bad code, but i thought they would be different :D
    CopyWpMem(&buildNumPatch[1], &newWinBuildNumber, sizeof(short));
    CopyWpMem(&buildNumPatch2[1], &newWinBuildNumber, sizeof(short));
    if (RtlGetVersionAddress != NULL) {
        PRINT_KERNEL_PATCH_MSG(L"\r\n    Patching RtlGetVersion (NtBuildNumber)\r\n");
        int offset = 0;
        CopyWpMem(&offset, RtlGetVersionAddress + 3, sizeof(int));

        PRINT_KERNEL_PATCH_MSG(L"      NtBuildNumber [RVA: 0x%X]\r\n", (UINT32)(offset));
        UINT8* NtBuildNumberAddress = RtlGetVersionAddress + offset + 7;
        PRINT_KERNEL_PATCH_MSG(L"      NtBuildNumber [PTR: 0x%llX]\r\n", (UINTN)(NtBuildNumberAddress));

        short curVersion = 0;

        CopyWpMem(&curVersion, NtBuildNumberAddress, sizeof(short));

        PRINT_KERNEL_PATCH_MSG(L"      NtBuildNumber Current  : %d\r\n", (UINT32)(curVersion));

        SetWpMem(NtBuildNumberAddress, sizeof(short), 0); // 11 x nop
        CopyWpMem(NtBuildNumberAddress, &newWinBuildNumber, sizeof(short));
        PRINT_KERNEL_PATCH_MSG(L"      NtBuildNumber New      : %d \r\n", (UINT32)(newWinBuildNumber));

        PRINT_KERNEL_PATCH_MSG(L"    NtBuildNumber Patched \r\n");

        CopyWpMem(RtlGetVersionAddress, &buildNumPatch, sizeof(buildNumPatch));
        PRINT_KERNEL_PATCH_MSG(L"    Patched RtlGetVersion [RVA: 0x%X]\r\n", (UINT32)(NtBuildNumberAddress - ImageBase));
    }

    if (MmCreatePebAddress != NULL) {
        CopyWpMem(MmCreatePebAddress, &buildNumPatch2, sizeof(buildNumPatch2));
        PRINT_KERNEL_PATCH_MSG(L"    Patched MmCreatePeb [RVA: 0x%X]\r\n", (UINT32)(MmCreatePebAddress - ImageBase));
    }
Mattiwatti commented 1 year ago

You're right that this isn't really an EfiGuard issue, but it's fine.

I don't really see any issues with your code, other than being unnecessarily verbose. NtBuildNumber is exported, so if you want to change it you can just do this instead:

UINT8* NtBuildNumberAddress = GetProcedureAddress((UINTN)ImageBase, NtHeaders, "NtBuildNumber");
CONST UINT32 NewBuildNumber = *(UINT32*)NtBuildNumberAddress + 1;
CopyWpMem(NtBuildNumberAddress, &NewBuildNumber, sizeof(NewBuildNumber));

(Note that NtBuildNumber is a 32 bit value, not 16.) There is no need to modify RtlGetVersion or MmCreatePeb since they already reference NtBuildNumber.

However, this does not prevent the kernel from writing the original build number to SharedUserData->NtBuildNumber, because the instruction that does this uses a hardcoded value. See InitBootProcessor:

mov rcx, MmWriteableSharedUserData
; ...snip...
mov dword ptr [rcx+0x260], 0x585D ; for build 22621

Additionally, there is a new registry key since Windows 11 that may contain a replacement build number. This registry key is located at HKLM\SYSTEM\Software\Microsoft\BuildLayers and contains several sub-keys, each of which may specify a BuildNumber which will be used to update SharedUserData->NtBuildNumber later during boot. See CmpLoadSystemVersionData:

or eax, 0xF0000000
mov NtBuildNumber, eax
mov rax, MmWriteableSharedUserData
mov ecx, [rdx+8] ; *(uint32_t*)(CmpEditionVersion + 8)
mov [rax+0x260], ecx

If you want the SharedUserData->NtBuildNumber value to match the kernel's NtBuildNumber in .data, you will need to do something about these two functions. By far the easiest way is to simply change the value in the registry. If that's not an option, you will need to patch at least one of the two occurrences (which one depends on whether the registry key is present or not). Also, if the registry key is present, it will be used to update NtBuildNumber again as you can see.

Note that I couldn't reproduce the PEB build number not changing; for me the first three lines of code to update NtBuildNumber suffice to change the build number in the PEB.

DecoderCoder commented 1 year ago

Thank for answer, I've already know about InitBootProcessor and patching it. Didn't know about SharedUserData. I will try and post the result

DecoderCoder commented 1 year ago

I patching it successfully, but in windows doesn't matter about my patches 👍 like it upload some sections after load

Code for quick test


STATIC CONST UINT8 SigInitBootProcessor[] = {
    0xC7, 0x81, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,0xCC,0xCC,0xC7,0x41,0xCC,0xCC,0xCC,0xCC,0xCC
};
///
    UINT8* InitBootProcessorAddress = NULL;
    {
        PRINT_KERNEL_PATCH_MSG(L"== Searching for nt!InitBootProcessor pattern in PAGE ==\r\n");
        EFI_STATUS FindInitBootProcessor = FindPattern(SigInitBootProcessor,
            0xCC,
            sizeof(SigInitBootProcessor),
            ImageBase + InitSection->VirtualAddress,
            InitSection->SizeOfRawData,
            (VOID**)&InitBootProcessorAddress);

        if (EFI_ERROR(FindInitBootProcessor))
        {
            PRINT_KERNEL_PATCH_MSG(L"    Failed to find InitBootProcessor. Skipping patch.\r\n");
        }
        else {
            PRINT_KERNEL_PATCH_MSG(L"    Found InitBootProcessor pattern at 0x%llX.\r\n", (UINTN)InitBootProcessorAddress);
        }
    }

if (InitBootProcessorAddress) {
short newWinBuildNumber = 24000;
            CopyWpMem(InitBootProcessorAddress + 6, &newWinBuildNumber, sizeof(short));
            PRINT_KERNEL_PATCH_MSG(L"    Patched InitBootProcessor [RVA: 0x%X]\r\n", (UINT32)(InitBootProcessorAddress - ImageBase));
        }

UINT8* NtBuildNumberAddress = GetProcedureAddress((UINTN)ImageBase, NtHeaders, "NtBuildNumber");
    if (NtBuildNumberAddress != NULL) {
        CONST UINT32 NewBuildNumber = 24000;
        CopyWpMem(NtBuildNumberAddress, &NewBuildNumber, sizeof(NewBuildNumber));
        PRINT_KERNEL_PATCH_MSG(L"    Patched NtBuildNumberAddress [RVA: 0x%X]\r\n", (UINT32)(NtBuildNumberAddress - ImageBase));
    }
    else {
        PRINT_KERNEL_PATCH_MSG(L"    Failed to find NtBuildNumberAddress");
    }
DecoderCoder commented 1 year ago

Im idiot forgot about CmpLoadSystemVersionData

STATIC CONST UINT8 SigCmpLoadSystemVersionData[] = {
    0x48, 0x83, 0x3D, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x74, 0x6A
};
//----------------------
    UINT8* CmpLoadSystemVersionDataAddress = NULL;
    {
        PRINT_KERNEL_PATCH_MSG(L"== Searching for nt!CmpLoadSystemVersionData pattern in PAGE ==\r\n");
        EFI_STATUS FindCmpLoadSystemVersionData = FindPattern(SigCmpLoadSystemVersionData,
            0xCC,
            sizeof(SigCmpLoadSystemVersionData),
            ImageBase + PageSection->VirtualAddress,
            PageSection->SizeOfRawData,
            (VOID**)&CmpLoadSystemVersionDataAddress);

        if (EFI_ERROR(FindCmpLoadSystemVersionData))
        {
            PRINT_KERNEL_PATCH_MSG(L"    Failed to find CmpLoadSystemVersionData. Skipping patch.\r\n");
        }
        else {
            PRINT_KERNEL_PATCH_MSG(L"    Found CmpLoadSystemVersionData pattern at 0x%llX.\r\n", (UINTN)CmpLoadSystemVersionDataAddress);
        }
    }
//---------------------------

    if (CmpLoadSystemVersionDataAddress) {
        CmpLoadSystemVersionDataAddress += 8;
        UINT8 jmp = 0xEB;
        CopyWpMem(CmpLoadSystemVersionDataAddress, &jmp, sizeof(UINT8));
        PRINT_KERNEL_PATCH_MSG(L"    Patched CmpLoadSystemVersionData [RVA: 0x%X]\r\n", (UINT32)(CmpLoadSystemVersionDataAddress- ImageBase));
    }
    else {
        PRINT_KERNEL_PATCH_MSG(L"    Failed to find CmpLoadSystemVersionData");
    }
DecoderCoder commented 1 year ago

Mattiwatti I want to say that you helped me A LOT and now it's working PERFECTLY, thank you very much. I close Issue