├── README.md ├── exkern_inst_engine.cpp ├── exkern_inst_engine.vcproj ├── inst_engine.aps ├── inst_engine.rc ├── installer.h ├── resource.h └── setup.conf /README.md: -------------------------------------------------------------------------------- 1 | # nt6-unofficial-update-installer-engine 2 | Installer engine that takes care of what is needed to install unofficial system files. It was created for the benefit of the Vista Extended Kernel and Media Foundation Update, but it can adaptable to other uses. 3 | 4 | It is presently capable of obtaining lists of files to be copied into System32 and SysWOW64 folders, checking minimum and maximum build numbers via the PEB, automatically backing up replaced system files, and offline backup restoration. Privilege escalation is enforced. 5 | 6 | Feature additions, such as a GUI front-end, covering a broader variety of file paths, and the ability to specify other "jobs" for the installer to run, are possible in the future. 7 | 8 | A sample syntax for the configuration file can be found in the posted "setup.conf". 9 | -------------------------------------------------------------------------------- /exkern_inst_engine.cpp: -------------------------------------------------------------------------------- 1 | // exkern_inst_engine.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "installer.h" 5 | 6 | using namespace std; 7 | 8 | /* 9 | A perfect combination of C and C++ features are used in this installer engine designed for replacing system files on x64, x86 and IA-64 Windows NT 6.x. 10 | 11 | To work with the win32 API, I use char array based strings, but combined with the convenience of vector containers. 12 | */ 13 | BOOL LocalBackupRestore = FALSE; 14 | BOOL DeleteNewFiles; 15 | vector FileExistingNative; 16 | vector FileNewNative; 17 | #ifndef _X86_ 18 | vector FileExistingWOW64; 19 | vector FileNewWOW64; 20 | #endif 21 | 22 | CHAR curdir [MAX_PATH]; 23 | CHAR windirsys [MAX_PATH]; 24 | CHAR windircurrent [MAX_PATH]; 25 | #ifndef _X86_ 26 | CHAR windirsyswow [MAX_PATH]; 27 | #endif 28 | 29 | void SetupSystemDirs(CHAR* windir) 30 | { 31 | 32 | GetWindowsDirectoryA(windirsys, MAX_PATH); 33 | 34 | if(windir != NULL) 35 | { 36 | if(windirsys[0] == windir[0]) 37 | LocalBackupRestore = TRUE; 38 | strcpy_s(windirsys, MAX_PATH, windir); 39 | } 40 | 41 | #ifndef _X86_ 42 | strcpy_s(windirsyswow, MAX_PATH, windirsys); 43 | strcat_s(windirsyswow, MAX_PATH, "\\SysWOW64\0"); 44 | #endif 45 | 46 | strcat_s(windirsys, MAX_PATH, "\\System32\0"); 47 | 48 | } 49 | 50 | void TakeoverSystemFiles() 51 | /* 52 | Icacls calls wait for the takeown call to end before executing, due to the possibility of 53 | a race condition where the icacls call finishes before the takeown call, causing the former to fail. 54 | */ 55 | { 56 | CHAR TakeownBase [MAX_PATH]; 57 | CHAR IcaclsBase [MAX_PATH]; 58 | CHAR Bcd [MAX_PATH]; 59 | CHAR* IcaclsTemp; 60 | CHAR* Username; 61 | CHAR* TakeownTemp; 62 | DWORD UsernameBuffer = 0; 63 | DWORD ExitCode; 64 | STARTUPINFOA sua; 65 | PROCESS_INFORMATION ProcInfo; 66 | 67 | GetStartupInfoA(&sua); 68 | 69 | GetUserNameA(Username, &UsernameBuffer); 70 | Username = (CHAR*)malloc(UsernameBuffer); 71 | GetUserNameA(Username, &UsernameBuffer); 72 | 73 | strcpy_s(TakeownBase, MAX_PATH, windirsys); 74 | strcpy_s(IcaclsBase, MAX_PATH, windirsys); 75 | strcat_s(TakeownBase, MAX_PATH, "\\takeown.exe /F "); 76 | strcat_s(IcaclsBase, MAX_PATH, "\\icacls.exe \""); 77 | 78 | for (size_t i = 0; i < FileExistingNative.size(); i++) 79 | { 80 | 81 | TakeownTemp = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 82 | strcpy_s(TakeownTemp, MAX_PATH, TakeownBase); 83 | 84 | strcat_s(TakeownTemp, MAX_PATH, windirsys); 85 | strcat_s(TakeownTemp, MAX_PATH, "\\"); 86 | strcat_s(TakeownTemp, MAX_PATH, FileExistingNative.at(i)); 87 | 88 | IcaclsTemp = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 89 | 90 | strcpy_s(IcaclsTemp, MAX_PATH, IcaclsBase); 91 | strcat_s(IcaclsTemp, MAX_PATH, windirsys); 92 | strcat_s(IcaclsTemp, MAX_PATH, "\\"); 93 | strcat_s(IcaclsTemp, MAX_PATH, FileExistingNative.at(i)); 94 | strcat_s(IcaclsTemp, MAX_PATH, "\" /grant \""); 95 | strcat_s(IcaclsTemp, MAX_PATH, Username); 96 | strcat_s(IcaclsTemp, MAX_PATH, "\":F"); 97 | 98 | 99 | if(!CreateProcessA(NULL, TakeownTemp, NULL, NULL, FALSE, CREATE_PRESERVE_CODE_AUTHZ_LEVEL | CREATE_NO_WINDOW, NULL, NULL, 100 | &sua, &ProcInfo)) 101 | { 102 | printf("\nFailed to create process with the following parameters: %s.\nSetup will now exit.\nPress any key to continue.", TakeownTemp); 103 | getchar(); 104 | free(TakeownTemp); 105 | free(IcaclsTemp); 106 | exit(-1); 107 | } 108 | 109 | while(true) 110 | { 111 | GetExitCodeProcess(ProcInfo.hProcess, &ExitCode); 112 | if(ExitCode != STILL_ACTIVE) 113 | break; 114 | } 115 | 116 | CloseHandle(ProcInfo.hProcess); 117 | CloseHandle(ProcInfo.hThread); 118 | 119 | 120 | if(!CreateProcessA(NULL, IcaclsTemp, NULL, NULL, FALSE, CREATE_PRESERVE_CODE_AUTHZ_LEVEL | CREATE_NO_WINDOW, NULL, NULL, 121 | &sua, &ProcInfo)) 122 | { 123 | printf("\nFailed to create process with the following parameters: %s.\nSetup will now exit.\nPress any key to continue.", IcaclsTemp); 124 | getchar(); 125 | free(TakeownTemp); 126 | free(IcaclsTemp); 127 | exit(-1); 128 | } 129 | 130 | while(true) 131 | { 132 | GetExitCodeProcess(ProcInfo.hProcess, &ExitCode); 133 | if(ExitCode != STILL_ACTIVE) 134 | break; 135 | } 136 | 137 | CloseHandle(ProcInfo.hProcess); 138 | CloseHandle(ProcInfo.hThread); 139 | 140 | 141 | free(TakeownTemp); 142 | free(IcaclsTemp); 143 | 144 | } 145 | #ifndef _X86_ 146 | for (size_t i = 0; i < FileExistingWOW64.size(); i++) 147 | { 148 | TakeownTemp = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 149 | strcpy_s(TakeownTemp, MAX_PATH, TakeownBase); 150 | 151 | strcat_s(TakeownTemp, MAX_PATH, windirsyswow); 152 | strcat_s(TakeownTemp, MAX_PATH, "\\"); 153 | strcat_s(TakeownTemp, MAX_PATH, FileExistingWOW64.at(i)); 154 | 155 | IcaclsTemp = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 156 | 157 | strcpy_s(IcaclsTemp, MAX_PATH, IcaclsBase); 158 | strcat_s(IcaclsTemp, MAX_PATH, windirsyswow); 159 | strcat_s(IcaclsTemp, MAX_PATH, "\\"); 160 | strcat_s(IcaclsTemp, MAX_PATH, FileExistingWOW64.at(i)); 161 | strcat_s(IcaclsTemp, MAX_PATH, "\" /grant \""); 162 | strcat_s(IcaclsTemp, MAX_PATH, Username); 163 | strcat_s(IcaclsTemp, MAX_PATH, "\":F"); 164 | 165 | if(!CreateProcessA(NULL, TakeownTemp, NULL, NULL, FALSE, CREATE_PRESERVE_CODE_AUTHZ_LEVEL | CREATE_NO_WINDOW, NULL, NULL, 166 | &sua, &ProcInfo)) 167 | { 168 | printf("\nFailed to create process with the following parameters: %s.\nSetup will now exit.\nPress any key to continue.", TakeownTemp); 169 | getchar(); 170 | free(TakeownTemp); 171 | free(IcaclsTemp); 172 | exit(-1); 173 | } 174 | 175 | while(true) 176 | { 177 | GetExitCodeProcess(ProcInfo.hProcess, &ExitCode); 178 | if(ExitCode != STILL_ACTIVE) 179 | break; 180 | } 181 | 182 | CloseHandle(ProcInfo.hProcess); 183 | CloseHandle(ProcInfo.hThread); 184 | 185 | 186 | if(!CreateProcessA(NULL, IcaclsTemp, NULL, NULL, FALSE, CREATE_PRESERVE_CODE_AUTHZ_LEVEL | CREATE_NO_WINDOW, NULL, NULL, 187 | &sua, &ProcInfo)) 188 | { 189 | printf("\nFailed to create process with the following parameters: %s.\nSetup will now exit.\nPress any key to continue.", IcaclsTemp); 190 | getchar(); 191 | free(TakeownTemp); 192 | free(IcaclsTemp); 193 | exit(-1); 194 | } 195 | 196 | while(true) 197 | { 198 | GetExitCodeProcess(ProcInfo.hProcess, &ExitCode); 199 | if(ExitCode != STILL_ACTIVE) 200 | break; 201 | } 202 | 203 | CloseHandle(ProcInfo.hProcess); 204 | CloseHandle(ProcInfo.hThread); 205 | 206 | free(TakeownTemp); 207 | free(IcaclsTemp); 208 | } 209 | #endif 210 | free(Username); 211 | 212 | strcpy_s(Bcd, MAX_PATH, windirsys); 213 | // This is done for the benefit of the Vista extended kernel. 214 | // Perhaps in future, a list of "jobs" can be included, with variables representing paths that may be 215 | // part of the command line arguments. 216 | strcat_s(Bcd, MAX_PATH, "\\bcdedit.exe /set {current} nointegritychecks yes"); 217 | 218 | if(!CreateProcessA(NULL, Bcd, NULL, NULL, FALSE, CREATE_PRESERVE_CODE_AUTHZ_LEVEL | CREATE_NO_WINDOW, NULL, 219 | NULL, &sua, &ProcInfo)) 220 | { 221 | printf("\nFailed to create process with the following parameters: %s.\nSetup will now exit.\nPress any key to continue.", Bcd); 222 | getchar(); 223 | exit(-1); 224 | } 225 | 226 | CloseHandle(ProcInfo.hProcess); 227 | CloseHandle(ProcInfo.hThread); 228 | 229 | 230 | } 231 | 232 | void MoveBackupSystemFiles(BOOL Restore) 233 | /* 234 | Intended usage is to move paged/in-memory files so new ones can be copied, or to restore the old versions of files 235 | online after the installer has been run earlier in the session, or to restore backupped files offline. 236 | 237 | That is why you can use the "restore back-up" feature even if the system does not meet the 238 | requirements for installation. 239 | */ 240 | { 241 | CHAR* BackupFile; 242 | CHAR* BackupFileBak; 243 | CHAR* InUseFileToBeRemoved; 244 | BOOL Success; 245 | 246 | for(size_t i = 0; i < FileExistingNative.size(); i++) 247 | { 248 | BackupFile = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 249 | 250 | BackupFileBak = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 251 | 252 | InUseFileToBeRemoved = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 253 | 254 | strcpy_s(BackupFile, MAX_PATH, windirsys); 255 | 256 | strcat_s(BackupFile, MAX_PATH, "\\"); 257 | 258 | strcat_s(BackupFile, MAX_PATH, FileExistingNative.at(i)); 259 | 260 | strcpy_s(BackupFileBak, MAX_PATH, BackupFile); 261 | 262 | strcat_s(BackupFileBak, MAX_PATH, ".bak"); 263 | 264 | strcpy_s(InUseFileToBeRemoved, MAX_PATH, windirsys); 265 | 266 | strcat_s(InUseFileToBeRemoved, MAX_PATH, "\\"); 267 | 268 | strcat_s(InUseFileToBeRemoved, MAX_PATH, FileExistingNative.at(i)); 269 | 270 | strcat_s(InUseFileToBeRemoved, MAX_PATH, ".del"); 271 | 272 | 273 | if(Restore) 274 | { 275 | if(LocalBackupRestore) 276 | { 277 | Success = MoveFileA(BackupFile, InUseFileToBeRemoved); 278 | if(!Success && GetLastError() != 2) 279 | { 280 | printf("\nERROR: Unable to move %s for safe removal", BackupFile); 281 | } 282 | else if(GetLastError() == 2) 283 | { 284 | printf("\nBackup for %s is missing, restoring", BackupFile); 285 | MoveFileA(InUseFileToBeRemoved, BackupFile); 286 | } 287 | else 288 | MoveFileExA(InUseFileToBeRemoved, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); 289 | } 290 | Success = MoveFileExA(BackupFileBak, BackupFile, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); 291 | // Suppression of the error message when there are no files to back up (newly copied files) 292 | if(!Success && GetLastError() != 2) 293 | printf("\nERROR: Unable to restore %s to %s", BackupFileBak, BackupFile); 294 | } 295 | else 296 | { 297 | Success = MoveFileExA(BackupFile, BackupFileBak, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); 298 | if(!Success && GetLastError() != 2) 299 | printf("\nERROR: Unable to backup %s to %s", BackupFile, BackupFileBak); 300 | } 301 | 302 | free(BackupFile); 303 | 304 | free(BackupFileBak); 305 | } 306 | #ifndef _X86_ 307 | for(size_t i = 0; i < FileExistingWOW64.size(); i++) 308 | { 309 | BackupFile = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 310 | 311 | BackupFileBak = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 312 | 313 | InUseFileToBeRemoved = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 314 | 315 | strcpy_s(BackupFile, MAX_PATH, windirsyswow); 316 | 317 | strcat_s(BackupFile, MAX_PATH, "\\"); 318 | 319 | strcat_s(BackupFile, MAX_PATH, FileExistingWOW64.at(i)); 320 | 321 | strcpy_s(BackupFileBak, MAX_PATH, BackupFile); 322 | 323 | strcat_s(BackupFileBak, MAX_PATH, ".bak"); 324 | 325 | strcpy_s(InUseFileToBeRemoved, MAX_PATH, windirsyswow); 326 | 327 | strcat_s(InUseFileToBeRemoved, MAX_PATH, "\\"); 328 | 329 | strcat_s(InUseFileToBeRemoved, MAX_PATH, FileExistingWOW64.at(i)); 330 | 331 | strcat_s(InUseFileToBeRemoved, MAX_PATH, ".del"); 332 | 333 | if(Restore) 334 | { 335 | if(LocalBackupRestore) 336 | { 337 | Success = MoveFileA(BackupFile, InUseFileToBeRemoved); 338 | if(!Success && GetLastError() != 2) 339 | { 340 | printf("\nERROR: Unable to move %s for safe removal", BackupFile); 341 | } 342 | else if(GetLastError() == 2) 343 | { 344 | printf("\nBackup for %s is missing, restoring", BackupFile); 345 | MoveFileA(InUseFileToBeRemoved, BackupFile); 346 | } 347 | else 348 | MoveFileExA(InUseFileToBeRemoved, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); 349 | } 350 | Success = MoveFileExA(BackupFileBak, BackupFile, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); 351 | if(!Success && GetLastError() != 2) 352 | printf("\nERROR: Unable to restore %s to %s", BackupFileBak, BackupFile); 353 | } 354 | else 355 | { 356 | Success = MoveFileExA(BackupFile, BackupFileBak, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); 357 | if(!Success && GetLastError() != 2) 358 | printf("\nERROR: Unable to backup %s to %s", BackupFile, BackupFileBak); 359 | } 360 | free(BackupFile); 361 | 362 | free(BackupFileBak); 363 | } 364 | #endif 365 | for(size_t i = 0; i < FileNewNative.size(); i++) 366 | { 367 | BackupFile = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 368 | 369 | BackupFileBak = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 370 | 371 | InUseFileToBeRemoved = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 372 | 373 | strcpy_s(BackupFile, MAX_PATH, windirsys); 374 | 375 | strcat_s(BackupFile, MAX_PATH, "\\"); 376 | 377 | strcat_s(BackupFile, MAX_PATH, FileNewNative.at(i)); 378 | 379 | strcpy_s(BackupFileBak, MAX_PATH, BackupFile); 380 | 381 | strcat_s(BackupFileBak, MAX_PATH, ".bak"); 382 | 383 | strcpy_s(InUseFileToBeRemoved, MAX_PATH, windirsys); 384 | 385 | strcat_s(InUseFileToBeRemoved, MAX_PATH, "\\"); 386 | 387 | strcat_s(InUseFileToBeRemoved, MAX_PATH, FileNewNative.at(i)); 388 | 389 | strcat_s(InUseFileToBeRemoved, MAX_PATH, ".del"); 390 | 391 | if(Restore) 392 | { 393 | if(LocalBackupRestore) 394 | { 395 | Success = MoveFileA(BackupFile, InUseFileToBeRemoved); 396 | if(!Success && GetLastError() != 2) 397 | { 398 | printf("\nERROR: Unable to move %s for safe removal", BackupFile); 399 | } 400 | else if(GetLastError() == 2 && !DeleteNewFiles) 401 | { 402 | printf("\nBackup for %s is missing, restoring", BackupFile); 403 | MoveFileA(InUseFileToBeRemoved, BackupFile); 404 | } 405 | else 406 | MoveFileExA(InUseFileToBeRemoved, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); 407 | } 408 | Success = MoveFileExA(BackupFileBak, BackupFile, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); 409 | if(!Success && GetLastError() != 2) 410 | printf("\nERROR: Unable to restore %s to %s", BackupFileBak, BackupFile); 411 | } 412 | else 413 | { 414 | Success = MoveFileExA(BackupFile, BackupFileBak, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); 415 | if(!Success && GetLastError() != 2) 416 | printf("\nERROR: Unable to backup %s to %s", BackupFile, BackupFileBak); 417 | } 418 | 419 | free(BackupFile); 420 | 421 | free(BackupFileBak); 422 | } 423 | #ifndef _X86_ 424 | for(size_t i = 0; i < FileNewWOW64.size(); i++) 425 | { 426 | BackupFile = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 427 | 428 | BackupFileBak = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 429 | 430 | InUseFileToBeRemoved = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 431 | 432 | strcpy_s(BackupFile, MAX_PATH, windirsyswow); 433 | 434 | strcat_s(BackupFile, MAX_PATH, "\\"); 435 | 436 | strcat_s(BackupFile, MAX_PATH, FileNewWOW64.at(i)); 437 | 438 | strcpy_s(BackupFileBak, MAX_PATH, BackupFile); 439 | 440 | strcat_s(BackupFileBak, MAX_PATH, ".bak"); 441 | 442 | strcpy_s(InUseFileToBeRemoved, MAX_PATH, windirsyswow); 443 | 444 | strcat_s(InUseFileToBeRemoved, MAX_PATH, "\\"); 445 | 446 | strcat_s(InUseFileToBeRemoved, MAX_PATH, FileNewWOW64.at(i)); 447 | 448 | strcat_s(InUseFileToBeRemoved, MAX_PATH, ".del"); 449 | 450 | if(Restore) 451 | { 452 | if(LocalBackupRestore) 453 | { 454 | Success = MoveFileA(BackupFile, InUseFileToBeRemoved); 455 | if(!Success && GetLastError() != 2) 456 | { 457 | printf("\nERROR: Unable to move %s for safe removal", BackupFile); 458 | } 459 | else if(GetLastError() == 2 && !DeleteNewFiles) 460 | { 461 | printf("\nBackup for %s is missing, restoring", BackupFile); 462 | MoveFileA(InUseFileToBeRemoved, BackupFile); 463 | } 464 | else 465 | MoveFileExA(InUseFileToBeRemoved, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); 466 | } 467 | Success = MoveFileExA(BackupFileBak, BackupFile, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); 468 | if(!Success && GetLastError() != 2) 469 | printf("\nERROR: Unable to restore %s to %s", BackupFileBak, BackupFile); 470 | } 471 | else 472 | { 473 | Success = MoveFileExA(BackupFile, BackupFileBak, MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING); 474 | if(!Success && GetLastError() != 2) 475 | printf("\nERROR: Unable to backup %s to %s", BackupFile, BackupFileBak); 476 | } 477 | 478 | free(BackupFile); 479 | 480 | free(BackupFileBak); 481 | } 482 | #endif 483 | } 484 | 485 | void CopyFiles() 486 | { 487 | CHAR* NewFilePath; 488 | CHAR* SourcePath; 489 | 490 | for (size_t i = 0; i < FileExistingNative.size(); i++) 491 | { 492 | NewFilePath = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 493 | SourcePath = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 494 | 495 | strcpy_s(NewFilePath, MAX_PATH, windirsys); 496 | strcat_s(NewFilePath, MAX_PATH, "\\"); 497 | strcat_s(NewFilePath, MAX_PATH, FileExistingNative.at(i)); 498 | strcpy_s(SourcePath, MAX_PATH, curdir); 499 | strcat_s(SourcePath, MAX_PATH, "\\"); 500 | strcat_s(SourcePath, MAX_PATH, FileExistingNative.at(i)); 501 | 502 | if(!CopyFileA(SourcePath, NewFilePath, FALSE)) 503 | { 504 | free(NewFilePath); 505 | free(SourcePath); 506 | printf("\n File %s is missing from setup folder or could not be copied. Rolling back changes.", 507 | FileExistingNative.at(i)); 508 | MoveBackupSystemFiles(TRUE); 509 | return; 510 | } 511 | free(SourcePath); 512 | free(NewFilePath); 513 | } 514 | #ifndef _X86_ 515 | for (size_t i = 0; i < FileExistingWOW64.size(); i++) 516 | { 517 | NewFilePath = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 518 | SourcePath = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 519 | 520 | strcpy_s(NewFilePath, MAX_PATH, windirsyswow); 521 | strcat_s(NewFilePath, MAX_PATH, "\\"); 522 | strcat_s(NewFilePath, MAX_PATH, FileExistingWOW64.at(i)); 523 | strcpy_s(SourcePath, MAX_PATH, curdir); 524 | strcat_s(SourcePath, MAX_PATH, "\\"); 525 | strcpy_s(SourcePath, MAX_PATH, FileExistingWOW64.at(i)); 526 | strcat_s(SourcePath, MAX_PATH, ".wow64"); 527 | 528 | if(!CopyFileA(SourcePath, NewFilePath, FALSE)) 529 | { 530 | free(NewFilePath); 531 | printf("\n File %s is missing from setup folder or could not be copied. Rolling back changes.", 532 | SourcePath); 533 | free(SourcePath); 534 | MoveBackupSystemFiles(TRUE); 535 | return; 536 | } 537 | 538 | free(NewFilePath); 539 | free(SourcePath); 540 | } 541 | #endif 542 | for (size_t i = 0; i < FileNewNative.size(); i++) 543 | { 544 | NewFilePath = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 545 | SourcePath = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 546 | 547 | strcpy_s(NewFilePath, MAX_PATH, windirsys); 548 | strcat_s(NewFilePath, MAX_PATH, "\\"); 549 | strcat_s(NewFilePath, MAX_PATH, FileNewNative.at(i)); 550 | strcpy_s(SourcePath, MAX_PATH, curdir); 551 | strcat_s(SourcePath, MAX_PATH, "\\"); 552 | strcat_s(SourcePath, MAX_PATH, FileNewNative.at(i)); 553 | 554 | if(!CopyFileA(SourcePath, NewFilePath, FALSE)) 555 | { 556 | free(NewFilePath); 557 | printf("\n File %s is missing from setup folder or could not be copied. Rolling back changes.", 558 | FileNewNative.at(i)); 559 | free(SourcePath); 560 | MoveBackupSystemFiles(TRUE); 561 | return; 562 | } 563 | 564 | free(NewFilePath); 565 | free(SourcePath); 566 | } 567 | #ifndef _X86_ 568 | for (size_t i = 0; i < FileNewWOW64.size(); i++) 569 | { 570 | NewFilePath = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 571 | SourcePath = (CHAR*) malloc(sizeof(CHAR)*MAX_PATH); 572 | 573 | strcpy_s(NewFilePath, MAX_PATH, windirsyswow); 574 | strcat_s(NewFilePath, MAX_PATH, "\\"); 575 | strcat_s(NewFilePath, MAX_PATH, FileNewWOW64.at(i)); 576 | strcpy_s(SourcePath, MAX_PATH, curdir); 577 | strcat_s(SourcePath, MAX_PATH, "\\"); 578 | strcpy_s(SourcePath, MAX_PATH, FileNewWOW64.at(i)); 579 | strcat_s(SourcePath, MAX_PATH, ".wow64"); 580 | 581 | if(!CopyFileA(SourcePath, NewFilePath, FALSE)) 582 | { 583 | free(NewFilePath); 584 | printf("\n File %s is missing from setup folder or could not be copied. Rolling back changes.", 585 | SourcePath); 586 | free(SourcePath); 587 | MoveBackupSystemFiles(TRUE); 588 | return; 589 | } 590 | 591 | free(NewFilePath); 592 | free(SourcePath); 593 | } 594 | #endif 595 | } 596 | 597 | void InitFileLists() 598 | /* 599 | Filenames are read from a configuration file named setup.conf. There are two separate categories of files: 600 | "existing files" and "new files". Existing files are files that are part of the target version of Windows 601 | and require file ownership to be given to the administrator. New files are novel to the version of Windows 602 | and do not require the same file ownership and permission tasks to be performed. 603 | 604 | The (FileExisting/FileNew)Native sections are available on every platform, while only x64 and IA64 installers 605 | make use of the *WOW64 analogs. All files are assumed to be copied to System32 or SysWOW64, as is presently 606 | demanded by the projects that use this installer. 607 | */ 608 | { 609 | FILE* configfile; 610 | CHAR Path [MAX_PATH]; 611 | int List = 0; 612 | int fopenerr = fopen_s(&configfile, "setup.conf", "r"); 613 | 614 | if(fopenerr) 615 | { 616 | printf("\nUnable to load or locate configuration file. Setup will exit."); 617 | getchar(); 618 | getchar(); 619 | exit(-1); 620 | } 621 | 622 | 623 | 624 | while(!feof(configfile)) 625 | { 626 | 627 | fscanf_s(configfile, "%s ", Path, MAX_PATH); 628 | if(strstr(Path, "[FileExistingNative]")) 629 | List = 1; 630 | else if(strstr(Path, "[FileNewNative]")) 631 | List = 2; 632 | #ifndef _X86_ 633 | else if(strstr(Path, "[FileExistingWOW64]")) 634 | List = 3; 635 | else if(strstr(Path, "[FileNewWOW64]")) 636 | List = 4; 637 | #endif 638 | else 639 | { 640 | if(List == 1) 641 | { 642 | CHAR* Pos = (CHAR*)malloc(sizeof(CHAR)*MAX_PATH); 643 | strcpy_s(Pos, MAX_PATH, Path); 644 | strcat_s(Pos, MAX_PATH, "\0"); 645 | FileExistingNative.push_back(Pos); 646 | } 647 | if(List == 2) 648 | { 649 | CHAR* Pos = (CHAR*)malloc(sizeof(CHAR)*MAX_PATH); 650 | strcpy_s(Pos, MAX_PATH, Path); 651 | FileNewNative.push_back(Pos); 652 | } 653 | #ifndef _X86_ 654 | if(List == 3) 655 | { 656 | CHAR* Pos = (CHAR*)malloc(sizeof(CHAR)*MAX_PATH); 657 | strcpy_s(Pos, MAX_PATH, Path); 658 | FileExistingWOW64.push_back(Pos); 659 | } 660 | if(List == 4) 661 | { 662 | CHAR* Pos = (CHAR*)malloc(sizeof(CHAR)*MAX_PATH); 663 | strcpy_s(Pos, MAX_PATH, Path); 664 | FileNewWOW64.push_back(Pos); 665 | } 666 | #endif 667 | } 668 | } 669 | 670 | fclose(configfile); 671 | /* A listing of the contents in each file section can be printed if the DEBUG flag 672 | is used at compile time. 673 | It is possible that the same data could be printed to a file using a verbose command line switch, or 674 | printed to the command line itself also using a verbose command line switch, if this feature is desired 675 | by users. 676 | */ 677 | #ifdef DEBUG 678 | 679 | cout << "File debug listings: " << endl; 680 | 681 | for(int i = 0; i < FileExistingNative.size(); i++) 682 | cout << FileExistingNative.at(i) << "\n"; 683 | cout << "File NewX64: " << endl; 684 | for(int i = 0; i < FileNewNative.size(); i++) 685 | cout << FileNewNative.at(i) << "\n"; 686 | #ifndef _X86_ 687 | cout << "File ExistingWOW64: " << endl; 688 | for(int i = 0; i < FileExistingWOW64.size(); i++) 689 | cout << FileExistingWOW64.at(i) << "\n"; 690 | cout << "File NewWOW64: " << endl; 691 | for(int i = 0; i < FileNewWOW64.size(); i++) 692 | cout << FileNewWOW64.at(i) << "\n"; 693 | #endif 694 | 695 | #endif 696 | } 697 | 698 | 699 | 700 | int _tmain(int argc, _TCHAR* argv[]) 701 | /* 702 | Name of the product to be installed is gathered from the configuration file, as is the required maximum/minimum 703 | OS build numbers, if necessary. Build numbers are obtained directly from the PEB to best even the most 704 | powerful version spoofers, that is until you load the installer via CreateProcess in a suspended state and 705 | manually modify its PEB before resuming the starting thread. 706 | 707 | To emphasize the installer's ability to restore failed installs in situations where the target operating system 708 | install is unbootable, other systems that may not be able to install the product can be used to restore another 709 | system that is capable of using the product. 710 | */ 711 | { 712 | CHAR ProductName [128]; 713 | CHAR CurrentConfigPath [MAX_PATH]; 714 | CHAR windir [MAX_PATH]; 715 | char s; 716 | DWORD BuildNumber; 717 | DWORD MinBuildNumber; 718 | DWORD MaxBuildNumber; 719 | CHAR Test [MAX_PATH]; 720 | CHAR winsystemp [MAX_PATH]; 721 | HANDLE Check; 722 | GetCurrentDirectoryA(MAX_PATH, curdir); 723 | GetSystemDirectoryA(winsystemp, MAX_PATH); 724 | strcpy_s(CurrentConfigPath, MAX_PATH, curdir); 725 | strcat_s(CurrentConfigPath, MAX_PATH, "\\"); 726 | strcat_s(CurrentConfigPath, MAX_PATH, "setup.conf"); 727 | 728 | #ifndef _X86_ 729 | BuildNumber = (DWORD) NtCurrentTeb()->ProcessEnvironmentBlock->Reserved9[23]; 730 | #else 731 | BuildNumber = (DWORD) NtCurrentTeb()->ProcessEnvironmentBlock->Reserved9[29]; 732 | #endif 733 | BuildNumber = BuildNumber << 16; 734 | BuildNumber = BuildNumber >> 16; 735 | MinBuildNumber = GetPrivateProfileIntA("Config", "MinBuildNumber", 0, CurrentConfigPath); 736 | MaxBuildNumber = GetPrivateProfileIntA("Config", "MaxBuildNumber", (1 << 30) - 1 + (1 << 30), CurrentConfigPath); 737 | 738 | GetPrivateProfileStringA("Config", "ProductName", "Product Name Not Defined", ProductName, sizeof(ProductName), 739 | CurrentConfigPath); 740 | /* 741 | Conventional methods of detecting a lack of process elevation were not working well here, 742 | such as GetPrivilegeName() consistently providing me with an error code related to asynchronous I/O issues. 743 | So we have to create a small file in system32 then delete it immediately. If it cannot create that file, then 744 | the privileges are insufficient to run the installer. 745 | */ 746 | 747 | strcpy_s(Test, MAX_PATH, winsystemp); 748 | strcat_s(Test, MAX_PATH, "\\"); 749 | strcat_s(Test, MAX_PATH, "test"); 750 | DeleteFileA(Test); 751 | SetLastError(0); 752 | Check = CreateFileA(Test, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_SYSTEM, NULL); 753 | if(GetLastError() == 5) 754 | { 755 | printf("\nInsufficient permissions to run %s setup. Please right-click \"run as administrator\" and try again.", 756 | ProductName); 757 | getchar(); 758 | getchar(); 759 | return 0; 760 | } 761 | else 762 | { 763 | CloseHandle(Check); 764 | DeleteFileA(Test); 765 | } 766 | 767 | #ifdef _X86_ 768 | BOOL Wow64Process; 769 | if(IsWow64Process(GetCurrentProcess(), &Wow64Process)) 770 | { 771 | printf("The %s setup package is intended for an x86 version of Windows.", ProductName); 772 | printf("\nOffline backup restoration is still possible. To restore a backup, press 'R'.\n"); 773 | scanf_s("%c", &s, 1); 774 | if(s == 'r' || s == 'R') 775 | goto Restore; 776 | return 0; 777 | } 778 | #endif 779 | 780 | 781 | if(BuildNumber < MinBuildNumber || BuildNumber > MaxBuildNumber) 782 | { 783 | printf("An OS build between %d and %d is required to run %s setup.", MinBuildNumber, MaxBuildNumber, ProductName); 784 | printf("\nOffline backup restoration is still possible. To restore a backup, press 'R'.\n"); 785 | scanf_s("%c", &s, 1); 786 | if(s == 'r' || s == 'R') 787 | goto Restore; 788 | return 0; 789 | } 790 | 791 | DeleteNewFiles = GetPrivateProfileIntA("Config", "DeleteNewFiles", 0, CurrentConfigPath); 792 | 793 | 794 | printf("This is %s setup. \nPress 'R' for restore. \nPress all other keys for setup.\n", 795 | ProductName); 796 | scanf_s("%c", &s, 1); 797 | 798 | InitFileLists(); 799 | if(s == 'r' || s == 'R') 800 | { 801 | Restore: 802 | printf("Provide the path of the Windows directory that you want to restore.\n"); 803 | scanf_s("%s", windir, MAX_PATH); 804 | SetupSystemDirs(windir); 805 | MoveBackupSystemFiles(TRUE); 806 | printf("\nRestoration of backed-up files is complete\nPress any key to continue."); 807 | getchar(); 808 | getchar(); 809 | return 0; 810 | } 811 | SetupSystemDirs(NULL); 812 | TakeoverSystemFiles(); 813 | MoveBackupSystemFiles(FALSE); 814 | CopyFiles(); 815 | printf("\n%s setup is complete.\nPress any key to continue.", ProductName); 816 | getchar(); 817 | getchar(); 818 | 819 | return 0; 820 | } -------------------------------------------------------------------------------- /exkern_inst_engine.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 18 | 19 | 20 | 21 | 22 | 29 | 32 | 35 | 38 | 41 | 45 | 56 | 59 | 62 | 65 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 103 | 106 | 109 | 112 | 115 | 119 | 131 | 134 | 137 | 140 | 156 | 159 | 162 | 165 | 168 | 171 | 174 | 177 | 178 | 185 | 188 | 191 | 194 | 197 | 201 | 212 | 215 | 218 | 221 | 229 | 232 | 235 | 238 | 241 | 244 | 247 | 250 | 251 | 259 | 262 | 265 | 268 | 271 | 275 | 288 | 291 | 294 | 297 | 315 | 318 | 321 | 324 | 327 | 330 | 333 | 336 | 337 | 338 | 339 | 340 | 341 | 346 | 349 | 350 | 351 | 356 | 359 | 360 | 363 | 364 | 365 | 370 | 373 | 374 | 375 | 378 | 379 | 380 | 381 | 382 | 383 | -------------------------------------------------------------------------------- /inst_engine.aps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/win32ss/nt6-unofficial-update-installer-engine/789343946d636fcbff09b3091b9304d16eb900f0/inst_engine.aps -------------------------------------------------------------------------------- /inst_engine.rc: -------------------------------------------------------------------------------- 1 | // Microsoft Visual C++ generated resource script. 2 | // 3 | #include "resource.h" 4 | 5 | #define APSTUDIO_READONLY_SYMBOLS 6 | ///////////////////////////////////////////////////////////////////////////// 7 | // 8 | // Generated from the TEXTINCLUDE 2 resource. 9 | // 10 | #include 11 | 12 | ///////////////////////////////////////////////////////////////////////////// 13 | #undef APSTUDIO_READONLY_SYMBOLS 14 | 15 | ///////////////////////////////////////////////////////////////////////////// 16 | // English (Canada) resources 17 | 18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENC) 19 | #ifdef _WIN32 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN 21 | #pragma code_page(1252) 22 | #endif //_WIN32 23 | 24 | #ifdef APSTUDIO_INVOKED 25 | ///////////////////////////////////////////////////////////////////////////// 26 | // 27 | // TEXTINCLUDE 28 | // 29 | 30 | 1 TEXTINCLUDE 31 | BEGIN 32 | "resource.h\0" 33 | END 34 | 35 | 2 TEXTINCLUDE 36 | BEGIN 37 | "#include ""\r\n" 38 | "\0" 39 | END 40 | 41 | 3 TEXTINCLUDE 42 | BEGIN 43 | "\r\n" 44 | "\0" 45 | END 46 | 47 | #endif // APSTUDIO_INVOKED 48 | 49 | 50 | ///////////////////////////////////////////////////////////////////////////// 51 | // 52 | // Version 53 | // 54 | 55 | VS_VERSION_INFO VERSIONINFO 56 | FILEVERSION 6,0,0,6004 57 | PRODUCTVERSION 1,0,0,1 58 | FILEFLAGSMASK 0x17L 59 | #ifdef _DEBUG 60 | FILEFLAGS 0x1L 61 | #else 62 | FILEFLAGS 0x0L 63 | #endif 64 | FILEOS 0x4L 65 | FILETYPE 0x1L 66 | FILESUBTYPE 0x0L 67 | BEGIN 68 | BLOCK "StringFileInfo" 69 | BEGIN 70 | BLOCK "100904b0" 71 | BEGIN 72 | VALUE "FileDescription", "NT6 Installer Engine Stub" 73 | VALUE "FileVersion", "6, 0, 0, 6004" 74 | VALUE "InternalName", "exkern_i" 75 | VALUE "ProductName", "NT6 Third-Party System Update Installer" 76 | VALUE "ProductVersion", "1, 0, 0, 1" 77 | END 78 | END 79 | BLOCK "VarFileInfo" 80 | BEGIN 81 | VALUE "Translation", 0x1009, 1200 82 | END 83 | END 84 | 85 | #endif // English (Canada) resources 86 | ///////////////////////////////////////////////////////////////////////////// 87 | 88 | 89 | 90 | #ifndef APSTUDIO_INVOKED 91 | ///////////////////////////////////////////////////////////////////////////// 92 | // 93 | // Generated from the TEXTINCLUDE 3 resource. 94 | // 95 | 96 | 97 | ///////////////////////////////////////////////////////////////////////////// 98 | #endif // not APSTUDIO_INVOKED 99 | 100 | -------------------------------------------------------------------------------- /installer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | -------------------------------------------------------------------------------- /resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by inst_engine.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /setup.conf: -------------------------------------------------------------------------------- 1 | // The following is a sample setup.conf - which is the name of the file the installer must find in order to function. 2 | // The name of the product is listed here, followed by the minimum and maximum build numbers for which 3 | // product installation is permitted. All values are optional. 4 | 5 | // The file list contains four categories of files to be copied: "FileExistingNative" represents files already present 6 | // in the target version of Windows while "FileNewNative" represents files that are not present in the target version 7 | // of Windows. *Native lists correspond to files to be copied into the "System32" folder on all platforms, 8 | // while *WOW64 lists are only applicable on non-x86 versions of Windows, and correspond to files to be copied into 9 | // the SysWOW64 folder. 10 | // All WOW64 files are to be suffixed with *.wow64 in the setup source folder, which also contains the executable 11 | // and this configuration file. 12 | // "DeleteNewFiles" can be set to a non-zero value to indicate that "new" files will be completely deleted when the "backup restore" procedure is run. 13 | // The installer assumes by default that DeleteNewFiles is 0. 14 | 15 | [Config] 16 | ProductName=Media Foundation Update 17 | MinBuildNumber=6002 18 | MaxBuildNumber=6005 19 | DeleteNewFiles=1 20 | 21 | [FileExistingNative] 22 | ci.dll 23 | dwmapi.dll 24 | kernel32.dll 25 | ntdll.dll 26 | ntoskrnl.exe 27 | ole32.dll 28 | powrprof.dll 29 | shell32.dll 30 | user32.dll 31 | uxtheme.dll 32 | winload.efi 33 | winload.exe 34 | [FileNewNative] 35 | ntk32.dll 36 | [FileExistingWOW64] 37 | kernel32.dll 38 | powrprof.dll 39 | [FileNewWOW64] 40 | ntext.dll 41 | ntk32.dll 42 | --------------------------------------------------------------------------------