]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - vtoyjump/vtoyjump/vtoyjump.c
82421608fde58623a111df63cbfed31d4f476cfb
[Ventoy.git] / vtoyjump / vtoyjump / vtoyjump.c
1 /******************************************************************************
2 * vtoyjump.c
3 *
4 * Copyright (c) 2021, longpanda <admin@ventoy.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <Windows.h>
25 #include <virtdisk.h>
26 #include <winioctl.h>
27 #include <VersionHelpers.h>
28 #include "vtoyjump.h"
29 #include "fat_filelib.h"
30
31 static ventoy_os_param g_os_param;
32 static ventoy_windows_data g_windows_data;
33 static UINT8 g_os_param_reserved[32];
34 static INT g_system_bit = VTOY_BIT;
35 static ventoy_guid g_ventoy_guid = VENTOY_GUID;
36 static HANDLE g_vtoylog_mutex = NULL;
37 static HANDLE g_vtoyins_mutex = NULL;
38
39 static DWORD g_vtoy_disk_drive;
40
41 static CHAR g_prog_full_path[MAX_PATH];
42 static CHAR g_prog_dir[MAX_PATH];
43 static CHAR g_prog_name[MAX_PATH];
44
45 #define VTOY_PECMD_PATH "X:\\Windows\\system32\\ventoy\\PECMD.EXE"
46 #define ORG_PECMD_PATH "X:\\Windows\\system32\\PECMD.EXE"
47 #define ORG_PECMD_BK_PATH "X:\\Windows\\system32\\PECMD.EXE_BACK.EXE"
48
49 #define AUTO_RUN_BAT "X:\\VentoyAutoRun.bat"
50 #define AUTO_RUN_LOG "X:\\VentoyAutoRun.log"
51
52 #define VTOY_AUTO_FILE "X:\\_vtoy_auto_install"
53
54 #define LOG_FILE "X:\\Windows\\system32\\ventoy.log"
55 #define MUTEX_LOCK(hmutex) if (hmutex != NULL) LockStatus = WaitForSingleObject(hmutex, INFINITE)
56 #define MUTEX_UNLOCK(hmutex) if (hmutex != NULL && WAIT_OBJECT_0 == LockStatus) ReleaseMutex(hmutex)
57
58 static const char * GetFileNameInPath(const char *fullpath)
59 {
60 int i;
61
62 if (strstr(fullpath, ":"))
63 {
64 for (i = (int)strlen(fullpath); i > 0; i--)
65 {
66 if (fullpath[i - 1] == '/' || fullpath[i - 1] == '\\')
67 {
68 return fullpath + i;
69 }
70 }
71 }
72
73 return fullpath;
74 }
75
76 static int split_path_name(char *fullpath, char *dir, char *name)
77 {
78 CHAR ch;
79 CHAR *Pos = NULL;
80
81 Pos = (CHAR *)GetFileNameInPath(fullpath);
82
83 strcpy_s(name, MAX_PATH, Pos);
84
85 ch = *(Pos - 1);
86 *(Pos - 1) = 0;
87 strcpy_s(dir, MAX_PATH, fullpath);
88 *(Pos - 1) = ch;
89
90 return 0;
91 }
92
93
94 void Log(const char *Fmt, ...)
95 {
96 va_list Arg;
97 int Len = 0;
98 FILE *File = NULL;
99 SYSTEMTIME Sys;
100 char szBuf[1024];
101 DWORD LockStatus = 0;
102 DWORD PID = GetCurrentProcessId();
103
104 GetLocalTime(&Sys);
105 Len += sprintf_s(szBuf, sizeof(szBuf),
106 "[%4d/%02d/%02d %02d:%02d:%02d.%03d] [%u] ",
107 Sys.wYear, Sys.wMonth, Sys.wDay,
108 Sys.wHour, Sys.wMinute, Sys.wSecond,
109 Sys.wMilliseconds, PID);
110
111 va_start(Arg, Fmt);
112 Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg);
113 va_end(Arg);
114
115 MUTEX_LOCK(g_vtoylog_mutex);
116
117 fopen_s(&File, LOG_FILE, "a+");
118 if (File)
119 {
120 fwrite(szBuf, 1, Len, File);
121 fwrite("\n", 1, 1, File);
122 fclose(File);
123 }
124
125 MUTEX_UNLOCK(g_vtoylog_mutex);
126 }
127
128
129 static int LoadNtDriver(const char *DrvBinPath)
130 {
131 int i;
132 int rc = 0;
133 BOOL Ret;
134 DWORD Status;
135 SC_HANDLE hServiceMgr;
136 SC_HANDLE hService;
137 char name[256] = { 0 };
138
139 for (i = (int)strlen(DrvBinPath) - 1; i >= 0; i--)
140 {
141 if (DrvBinPath[i] == '\\' || DrvBinPath[i] == '/')
142 {
143 sprintf_s(name, sizeof(name), "%s", DrvBinPath + i + 1);
144 break;
145 }
146 }
147
148 Log("Load NT driver: %s %s", DrvBinPath, name);
149
150 hServiceMgr = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
151 if (hServiceMgr == NULL)
152 {
153 Log("OpenSCManager failed Error:%u", GetLastError());
154 return 1;
155 }
156
157 Log("OpenSCManager OK");
158
159 hService = CreateServiceA(hServiceMgr,
160 name,
161 name,
162 SERVICE_ALL_ACCESS,
163 SERVICE_KERNEL_DRIVER,
164 SERVICE_DEMAND_START,
165 SERVICE_ERROR_NORMAL,
166 DrvBinPath,
167 NULL, NULL, NULL, NULL, NULL);
168 if (hService == NULL)
169 {
170 Status = GetLastError();
171 if (Status != ERROR_IO_PENDING && Status != ERROR_SERVICE_EXISTS)
172 {
173 Log("CreateService failed v %u", Status);
174 CloseServiceHandle(hServiceMgr);
175 return 1;
176 }
177
178 hService = OpenServiceA(hServiceMgr, name, SERVICE_ALL_ACCESS);
179 if (hService == NULL)
180 {
181 Log("OpenService failed %u", Status);
182 CloseServiceHandle(hServiceMgr);
183 return 1;
184 }
185 }
186
187 Log("CreateService imdisk OK");
188
189 Ret = StartServiceA(hService, 0, NULL);
190 if (Ret)
191 {
192 Log("StartService OK");
193 }
194 else
195 {
196 Status = GetLastError();
197 if (Status == ERROR_SERVICE_ALREADY_RUNNING)
198 {
199 rc = 0;
200 }
201 else
202 {
203 Log("StartService error %u", Status);
204 rc = 1;
205 }
206 }
207
208 CloseServiceHandle(hService);
209 CloseServiceHandle(hServiceMgr);
210
211 Log("Load NT driver %s", rc ? "failed" : "success");
212
213 return rc;
214 }
215
216 static int ReadWholeFile2Buf(const char *Fullpath, void **Data, DWORD *Size)
217 {
218 int rc = 1;
219 DWORD FileSize;
220 DWORD dwSize;
221 HANDLE Handle;
222 BYTE *Buffer = NULL;
223
224 Log("ReadWholeFile2Buf <%s>", Fullpath);
225
226 Handle = CreateFileA(Fullpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
227 if (Handle == INVALID_HANDLE_VALUE)
228 {
229 Log("Could not open the file<%s>, error:%u", Fullpath, GetLastError());
230 goto End;
231 }
232
233 FileSize = SetFilePointer(Handle, 0, NULL, FILE_END);
234
235 Buffer = malloc(FileSize);
236 if (!Buffer)
237 {
238 Log("Failed to alloc memory size:%u", FileSize);
239 goto End;
240 }
241
242 SetFilePointer(Handle, 0, NULL, FILE_BEGIN);
243 if (!ReadFile(Handle, Buffer, FileSize, &dwSize, NULL))
244 {
245 Log("ReadFile failed, dwSize:%u error:%u", dwSize, GetLastError());
246 goto End;
247 }
248
249 *Data = Buffer;
250 *Size = FileSize;
251
252 Log("Success read file size:%u", FileSize);
253
254 rc = 0;
255
256 End:
257 SAFE_CLOSE_HANDLE(Handle);
258
259 return rc;
260 }
261
262 static BOOL CheckPeHead(BYTE *Buffer, DWORD Size, DWORD Offset)
263 {
264 UINT32 PeOffset;
265 BYTE *Head = NULL;
266 DWORD End;
267 ventoy_windows_data *pdata = NULL;
268
269 Head = Buffer + Offset;
270 pdata = (ventoy_windows_data *)Head;
271 Head += sizeof(ventoy_windows_data);
272
273 if (pdata->auto_install_script[0] && pdata->auto_install_len > 0)
274 {
275 End = Offset + sizeof(ventoy_windows_data) + pdata->auto_install_len + 60;
276 if (End < Size)
277 {
278 Head += pdata->auto_install_len;
279 }
280 }
281
282 if (Head[0] != 'M' || Head[1] != 'Z')
283 {
284 return FALSE;
285 }
286
287 PeOffset = *(UINT32 *)(Head + 60);
288 if (*(UINT32 *)(Head + PeOffset) != 0x00004550)
289 {
290 return FALSE;
291 }
292
293 return TRUE;
294 }
295
296
297 static BOOL CheckOsParam(ventoy_os_param *param)
298 {
299 UINT32 i;
300 BYTE Sum = 0;
301
302 if (memcmp(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid)))
303 {
304 return FALSE;
305 }
306
307 for (i = 0; i < sizeof(ventoy_os_param); i++)
308 {
309 Sum += *((BYTE *)param + i);
310 }
311
312 if (Sum)
313 {
314 return FALSE;
315 }
316
317 if (param->vtoy_img_location_addr % 4096)
318 {
319 return FALSE;
320 }
321
322 return TRUE;
323 }
324
325 static int SaveBuffer2File(const char *Fullpath, void *Buffer, DWORD Length)
326 {
327 int rc = 1;
328 DWORD dwSize;
329 HANDLE Handle;
330
331 Log("SaveBuffer2File <%s> len:%u", Fullpath, Length);
332
333 Handle = CreateFileA(Fullpath, GENERIC_READ | GENERIC_WRITE,
334 FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, 0, 0);
335 if (Handle == INVALID_HANDLE_VALUE)
336 {
337 Log("Could not create new file, error:%u", GetLastError());
338 goto End;
339 }
340
341 WriteFile(Handle, Buffer, Length, &dwSize, NULL);
342
343 rc = 0;
344
345 End:
346 SAFE_CLOSE_HANDLE(Handle);
347
348 return rc;
349 }
350
351 static int IsUTF8Encode(const char *src)
352 {
353 int i;
354 const UCHAR *Byte = (const UCHAR *)src;
355
356 for (i = 0; i < MAX_PATH && Byte[i]; i++)
357 {
358 if (Byte[i] > 127)
359 {
360 return 1;
361 }
362 }
363
364 return 0;
365 }
366
367 static int Utf8ToUtf16(const char* src, WCHAR * dst)
368 {
369 int size = MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, 0);
370 return MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size + 1);
371 }
372
373 static BOOL IsDirExist(const char *Fmt, ...)
374 {
375 va_list Arg;
376 DWORD Attr;
377 int UTF8 = 0;
378 CHAR FilePathA[MAX_PATH];
379 WCHAR FilePathW[MAX_PATH];
380
381 va_start(Arg, Fmt);
382 vsnprintf_s(FilePathA, sizeof(FilePathA), sizeof(FilePathA), Fmt, Arg);
383 va_end(Arg);
384
385 UTF8 = IsUTF8Encode(FilePathA);
386
387 if (UTF8)
388 {
389 Utf8ToUtf16(FilePathA, FilePathW);
390 Attr = GetFileAttributesW(FilePathW);
391 }
392 else
393 {
394 Attr = GetFileAttributesA(FilePathA);
395 }
396
397 if (Attr != INVALID_FILE_ATTRIBUTES && (Attr & FILE_ATTRIBUTE_DIRECTORY))
398 {
399 return TRUE;
400 }
401
402 return FALSE;
403 }
404
405 static BOOL IsFileExist(const char *Fmt, ...)
406 {
407 va_list Arg;
408 HANDLE hFile;
409 DWORD Attr;
410 BOOL bRet = FALSE;
411 int UTF8 = 0;
412 CHAR FilePathA[MAX_PATH];
413 WCHAR FilePathW[MAX_PATH];
414
415 va_start(Arg, Fmt);
416 vsnprintf_s(FilePathA, sizeof(FilePathA), sizeof(FilePathA), Fmt, Arg);
417 va_end(Arg);
418
419 UTF8 = IsUTF8Encode(FilePathA);
420
421 if (UTF8)
422 {
423 Utf8ToUtf16(FilePathA, FilePathW);
424 hFile = CreateFileW(FilePathW, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
425 }
426 else
427 {
428 hFile = CreateFileA(FilePathA, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
429 }
430 if (INVALID_HANDLE_VALUE == hFile)
431 {
432 goto out;
433 }
434
435 CloseHandle(hFile);
436
437 if (UTF8)
438 {
439 Attr = GetFileAttributesW(FilePathW);
440 }
441 else
442 {
443 Attr = GetFileAttributesA(FilePathA);
444 }
445
446 if (Attr & FILE_ATTRIBUTE_DIRECTORY)
447 {
448 goto out;
449 }
450
451 bRet = TRUE;
452
453 out:
454 Log("File <%s> %s", FilePathA, (bRet ? "exist" : "NOT exist"));
455 return bRet;
456 }
457
458 static int GetPhyDiskUUID(const char LogicalDrive, UINT8 *UUID, UINT32 *DiskSig, DISK_EXTENT *DiskExtent)
459 {
460 BOOL Ret;
461 DWORD dwSize;
462 HANDLE Handle;
463 VOLUME_DISK_EXTENTS DiskExtents;
464 CHAR PhyPath[128];
465 UINT8 SectorBuf[512];
466
467 Log("GetPhyDiskUUID %C", LogicalDrive);
468
469 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", LogicalDrive);
470 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
471 if (Handle == INVALID_HANDLE_VALUE)
472 {
473 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
474 return 1;
475 }
476
477 Ret = DeviceIoControl(Handle,
478 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
479 NULL,
480 0,
481 &DiskExtents,
482 (DWORD)(sizeof(DiskExtents)),
483 (LPDWORD)&dwSize,
484 NULL);
485 if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
486 {
487 Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, error:%u", GetLastError());
488 CloseHandle(Handle);
489 return 1;
490 }
491 CloseHandle(Handle);
492
493 memcpy(DiskExtent, DiskExtents.Extents, sizeof(DISK_EXTENT));
494 Log("%C: is in PhysicalDrive%d Offset:%llu", LogicalDrive, DiskExtents.Extents[0].DiskNumber,
495 (ULONGLONG)(DiskExtents.Extents[0].StartingOffset.QuadPart));
496
497 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", DiskExtents.Extents[0].DiskNumber);
498 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
499 if (Handle == INVALID_HANDLE_VALUE)
500 {
501 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
502 return 1;
503 }
504
505 if (!ReadFile(Handle, SectorBuf, sizeof(SectorBuf), &dwSize, NULL))
506 {
507 Log("ReadFile failed, dwSize:%u error:%u", dwSize, GetLastError());
508 CloseHandle(Handle);
509 return 1;
510 }
511
512 memcpy(UUID, SectorBuf + 0x180, 16);
513 if (DiskSig)
514 {
515 memcpy(DiskSig, SectorBuf + 0x1B8, 4);
516 }
517
518 CloseHandle(Handle);
519 return 0;
520 }
521
522 static int VentoyMountAnywhere(HANDLE Handle)
523 {
524 DWORD Status;
525 ATTACH_VIRTUAL_DISK_PARAMETERS AttachParameters;
526
527 Log("VentoyMountAnywhere");
528
529 memset(&AttachParameters, 0, sizeof(AttachParameters));
530 AttachParameters.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
531
532 Status = AttachVirtualDisk(Handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY | ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME, 0, &AttachParameters, NULL);
533 if (Status != ERROR_SUCCESS)
534 {
535 Log("Failed to attach virtual disk ErrorCode:%u", Status);
536 return 1;
537 }
538
539 return 0;
540 }
541
542 int VentoyMountY(HANDLE Handle)
543 {
544 int i;
545 BOOL bRet = FALSE;
546 DWORD Status;
547 DWORD physicalDriveNameSize;
548 CHAR *Pos = NULL;
549 WCHAR physicalDriveName[MAX_PATH];
550 CHAR physicalDriveNameA[MAX_PATH];
551 CHAR cdromDriveName[MAX_PATH];
552 ATTACH_VIRTUAL_DISK_PARAMETERS AttachParameters;
553
554 Log("VentoyMountY");
555
556 memset(&AttachParameters, 0, sizeof(AttachParameters));
557 AttachParameters.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
558
559 Status = AttachVirtualDisk(Handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY | ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER | ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME, 0, &AttachParameters, NULL);
560 if (Status != ERROR_SUCCESS)
561 {
562 Log("Failed to attach virtual disk ErrorCode:%u", Status);
563 return 1;
564 }
565
566 memset(physicalDriveName, 0, sizeof(physicalDriveName));
567 memset(physicalDriveNameA, 0, sizeof(physicalDriveNameA));
568
569 physicalDriveNameSize = MAX_PATH;
570 Status = GetVirtualDiskPhysicalPath(Handle, &physicalDriveNameSize, physicalDriveName);
571 if (Status != ERROR_SUCCESS)
572 {
573 Log("Failed GetVirtualDiskPhysicalPath ErrorCode:%u", Status);
574 return 1;
575 }
576
577 for (i = 0; physicalDriveName[i]; i++)
578 {
579 physicalDriveNameA[i] = (CHAR)toupper((CHAR)(physicalDriveName[i]));
580 }
581
582 Log("physicalDriveNameA=<%s>", physicalDriveNameA);
583
584 Pos = strstr(physicalDriveNameA, "CDROM");
585 if (!Pos)
586 {
587 Log("Not cdrom phy drive");
588 return 1;
589 }
590
591 sprintf_s(cdromDriveName, sizeof(cdromDriveName), "\\Device\\%s", Pos);
592 Log("cdromDriveName=<%s>", cdromDriveName);
593
594 for (i = 0; i < 3 && (bRet == FALSE); i++)
595 {
596 Sleep(1000);
597 bRet = DefineDosDeviceA(DDD_RAW_TARGET_PATH, "Y:", cdromDriveName);
598 Log("DefineDosDeviceA %s", bRet ? "success" : "failed");
599 }
600
601 return bRet ? 0 : 1;
602 }
603
604 static BOOL VentoyAPINeedMountY(const char *IsoPath)
605 {
606 (void)IsoPath;
607
608 /* TBD */
609 return FALSE;
610 }
611
612 static int VentoyAttachVirtualDisk(HANDLE Handle, const char *IsoPath)
613 {
614 int DriveYFree;
615 DWORD Drives;
616
617 Drives = GetLogicalDrives();
618 if ((1 << 24) & Drives)
619 {
620 Log("Y: is occupied");
621 DriveYFree = 0;
622 }
623 else
624 {
625 Log("Y: is free now");
626 DriveYFree = 1;
627 }
628
629 if (DriveYFree && VentoyAPINeedMountY(IsoPath))
630 {
631 return VentoyMountY(Handle);
632 }
633 else
634 {
635 return VentoyMountAnywhere(Handle);
636 }
637 }
638
639 int VentoyMountISOByAPI(const char *IsoPath)
640 {
641 int i;
642 HANDLE Handle;
643 DWORD Status;
644 WCHAR wFilePath[512] = { 0 };
645 VIRTUAL_STORAGE_TYPE StorageType;
646 OPEN_VIRTUAL_DISK_PARAMETERS OpenParameters;
647
648 Log("VentoyMountISOByAPI <%s>", IsoPath);
649
650 if (IsUTF8Encode(IsoPath))
651 {
652 Log("This is UTF8 encoding");
653 MultiByteToWideChar(CP_UTF8, 0, IsoPath, (int)strlen(IsoPath), wFilePath, (int)(sizeof(wFilePath) / sizeof(WCHAR)));
654 }
655 else
656 {
657 Log("This is ANSI encoding");
658 MultiByteToWideChar(CP_ACP, 0, IsoPath, (int)strlen(IsoPath), wFilePath, (int)(sizeof(wFilePath) / sizeof(WCHAR)));
659 }
660
661 memset(&StorageType, 0, sizeof(StorageType));
662 memset(&OpenParameters, 0, sizeof(OpenParameters));
663
664 OpenParameters.Version = OPEN_VIRTUAL_DISK_VERSION_1;
665
666 for (i = 0; i < 10; i++)
667 {
668 Status = OpenVirtualDisk(&StorageType, wFilePath, VIRTUAL_DISK_ACCESS_READ, 0, &OpenParameters, &Handle);
669 if (ERROR_FILE_NOT_FOUND == Status || ERROR_PATH_NOT_FOUND == Status)
670 {
671 Log("OpenVirtualDisk ErrorCode:%u, now wait and retry...", Status);
672 Sleep(1000);
673 }
674 else
675 {
676 if (ERROR_SUCCESS == Status)
677 {
678 Log("OpenVirtualDisk success");
679 }
680 else if (ERROR_VIRTDISK_PROVIDER_NOT_FOUND == Status)
681 {
682 Log("VirtualDisk for ISO file is not supported in current system");
683 }
684 else
685 {
686 Log("Failed to open virtual disk ErrorCode:%u", Status);
687 }
688 break;
689 }
690 }
691
692 if (Status != ERROR_SUCCESS)
693 {
694 return 1;
695 }
696
697 Log("OpenVirtualDisk success");
698
699 Status = VentoyAttachVirtualDisk(Handle, IsoPath);
700 if (Status != ERROR_SUCCESS)
701 {
702 Log("Failed to attach virtual disk ErrorCode:%u", Status);
703 CloseHandle(Handle);
704 return 1;
705 }
706
707 Log("VentoyAttachVirtualDisk success");
708
709 CloseHandle(Handle);
710 return 0;
711 }
712
713
714 static HANDLE g_FatPhyDrive;
715 static UINT64 g_Part2StartSec;
716
717 static int CopyFileFromFatDisk(const CHAR* SrcFile, const CHAR *DstFile)
718 {
719 int rc = 1;
720 int size = 0;
721 char *buf = NULL;
722 void *flfile = NULL;
723
724 Log("CopyFileFromFatDisk (%s)==>(%s)", SrcFile, DstFile);
725
726 flfile = fl_fopen(SrcFile, "rb");
727 if (flfile)
728 {
729 fl_fseek(flfile, 0, SEEK_END);
730 size = (int)fl_ftell(flfile);
731 fl_fseek(flfile, 0, SEEK_SET);
732
733 buf = (char *)malloc(size);
734 if (buf)
735 {
736 fl_fread(buf, 1, size, flfile);
737
738 rc = 0;
739 SaveBuffer2File(DstFile, buf, size);
740 free(buf);
741 }
742
743 fl_fclose(flfile);
744 }
745
746 return rc;
747 }
748
749 static int VentoyFatDiskRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
750 {
751 DWORD dwSize;
752 BOOL bRet;
753 DWORD ReadSize;
754 LARGE_INTEGER liCurrentPosition;
755
756 liCurrentPosition.QuadPart = Sector + g_Part2StartSec;
757 liCurrentPosition.QuadPart *= 512;
758 SetFilePointerEx(g_FatPhyDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);
759
760 ReadSize = (DWORD)(SectorCount * 512);
761
762 bRet = ReadFile(g_FatPhyDrive, Buffer, ReadSize, &dwSize, NULL);
763 if (bRet == FALSE || dwSize != ReadSize)
764 {
765 Log("ReadFile error bRet:%u WriteSize:%u dwSize:%u ErrCode:%u", bRet, ReadSize, dwSize, GetLastError());
766 }
767
768 return 1;
769 }
770
771 static BOOL Is2K10PE(void)
772 {
773 BOOL bRet = FALSE;
774 FILE *fp = NULL;
775 CHAR szLine[1024];
776
777 fopen_s(&fp, "X:\\Windows\\System32\\PECMD.INI", "r");
778 if (!fp)
779 {
780 return FALSE;
781 }
782
783 memset(szLine, 0, sizeof(szLine));
784 while (fgets(szLine, sizeof(szLine) - 1, fp))
785 {
786 if (strstr(szLine, "2k10\\"))
787 {
788 bRet = TRUE;
789 break;
790 }
791 }
792
793 fclose(fp);
794 return bRet;
795 }
796
797 static CHAR GetIMDiskMountLogicalDrive(void)
798 {
799 CHAR Letter = 'Y';
800 DWORD Drives;
801 DWORD Mask = 0x1000000;
802
803 // fixed use M as mountpoint for 2K10 PE
804 if (Is2K10PE())
805 {
806 Log("Use M: for 2K10 PE");
807 return 'M';
808 }
809
810 Drives = GetLogicalDrives();
811 Log("Drives=0x%x", Drives);
812
813 while (Mask)
814 {
815 if ((Drives & Mask) == 0)
816 {
817 break;
818 }
819
820 Letter--;
821 Mask >>= 1;
822 }
823
824 return Letter;
825 }
826
827 UINT64 GetVentoyEfiPartStartSector(HANDLE hDrive)
828 {
829 BOOL bRet;
830 DWORD dwSize;
831 MBR_HEAD MBR;
832 VTOY_GPT_INFO *pGpt = NULL;
833 UINT64 StartSector = 0;
834
835 SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
836
837 bRet = ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);
838 Log("Read MBR Ret:%u Size:%u code:%u", bRet, dwSize, LASTERR);
839
840 if ((!bRet) || (dwSize != sizeof(MBR)))
841 {
842 0;
843 }
844
845 if (MBR.PartTbl[0].FsFlag == 0xEE)
846 {
847 Log("GPT partition style");
848
849 pGpt = malloc(sizeof(VTOY_GPT_INFO));
850 if (!pGpt)
851 {
852 return 0;
853 }
854
855 SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
856 bRet = ReadFile(hDrive, pGpt, sizeof(VTOY_GPT_INFO), &dwSize, NULL);
857 if ((!bRet) || (dwSize != sizeof(VTOY_GPT_INFO)))
858 {
859 Log("Failed to read gpt info %d %u %d", bRet, dwSize, LASTERR);
860 return 0;
861 }
862
863 StartSector = pGpt->PartTbl[1].StartLBA;
864 free(pGpt);
865 }
866 else
867 {
868 Log("MBR partition style");
869 StartSector = MBR.PartTbl[1].StartSectorId;
870 }
871
872 Log("GetVentoyEfiPart StartSector: %llu", StartSector);
873 return StartSector;
874 }
875
876 static int VentoyRunImdisk(const char *IsoPath, const char *imdiskexe)
877 {
878 CHAR Letter;
879 CHAR Cmdline[512];
880 WCHAR CmdlineW[512];
881 PROCESS_INFORMATION Pi;
882
883 Log("VentoyRunImdisk <%s> <%s>", IsoPath, imdiskexe);
884
885 Letter = GetIMDiskMountLogicalDrive();
886 sprintf_s(Cmdline, sizeof(Cmdline), "%s -a -o ro -f \"%s\" -m %C:", imdiskexe, IsoPath, Letter);
887 Log("mount iso to %C: use imdisk cmd <%s>", Letter, Cmdline);
888
889 if (IsUTF8Encode(IsoPath))
890 {
891 STARTUPINFOW Si;
892 GetStartupInfoW(&Si);
893 Si.dwFlags |= STARTF_USESHOWWINDOW;
894 Si.wShowWindow = SW_HIDE;
895
896 Utf8ToUtf16(Cmdline, CmdlineW);
897 CreateProcessW(NULL, CmdlineW, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
898
899 Log("This is UTF8 encoding");
900 }
901 else
902 {
903 STARTUPINFOA Si;
904 GetStartupInfoA(&Si);
905 Si.dwFlags |= STARTF_USESHOWWINDOW;
906 Si.wShowWindow = SW_HIDE;
907
908 CreateProcessA(NULL, Cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
909
910 Log("This is ANSI encoding");
911 }
912
913 Log("Wait for imdisk process ...");
914 WaitForSingleObject(Pi.hProcess, INFINITE);
915 Log("imdisk process finished");
916
917 return 0;
918 }
919
920 int VentoyMountISOByImdisk(const char *IsoPath, DWORD PhyDrive)
921 {
922 int rc = 1;
923 BOOL bRet;
924 DWORD dwBytes;
925 HANDLE hDrive;
926 CHAR PhyPath[MAX_PATH];
927 GET_LENGTH_INFORMATION LengthInfo;
928
929 Log("VentoyMountISOByImdisk %s", IsoPath);
930
931 if (IsFileExist("X:\\Windows\\System32\\imdisk.exe"))
932 {
933 Log("imdisk.exe exist, use it directly...");
934 VentoyRunImdisk(IsoPath, "imdisk.exe");
935 return 0;
936 }
937
938 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", PhyDrive);
939 hDrive = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
940 if (hDrive == INVALID_HANDLE_VALUE)
941 {
942 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
943 goto End;
944 }
945
946 bRet = DeviceIoControl(hDrive, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &LengthInfo, sizeof(LengthInfo), &dwBytes, NULL);
947 if (!bRet)
948 {
949 Log("Could not get phy disk %s size, error:%u", PhyPath, GetLastError());
950 goto End;
951 }
952
953 g_FatPhyDrive = hDrive;
954 g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);
955
956 Log("Parse FAT fs...");
957
958 fl_init();
959
960 if (0 == fl_attach_media(VentoyFatDiskRead, NULL))
961 {
962 if (g_system_bit == 64)
963 {
964 CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.sys", "ventoy\\imdisk.sys");
965 CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.exe", "ventoy\\imdisk.exe");
966 CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.cpl", "ventoy\\imdisk.cpl");
967 }
968 else
969 {
970 CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.sys", "ventoy\\imdisk.sys");
971 CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.exe", "ventoy\\imdisk.exe");
972 CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.cpl", "ventoy\\imdisk.cpl");
973 }
974
975 GetCurrentDirectoryA(sizeof(PhyPath), PhyPath);
976 strcat_s(PhyPath, sizeof(PhyPath), "\\ventoy\\imdisk.sys");
977
978 if (LoadNtDriver(PhyPath) == 0)
979 {
980 VentoyRunImdisk(IsoPath, "ventoy\\imdisk.exe");
981 rc = 0;
982 }
983 }
984 fl_shutdown();
985
986 End:
987
988 SAFE_CLOSE_HANDLE(hDrive);
989
990 return rc;
991 }
992
993 static int MountIsoFile(CONST CHAR *IsoPath, DWORD PhyDrive)
994 {
995 if (IsWindows8OrGreater())
996 {
997 Log("This is Windows 8 or latter...");
998 if (VentoyMountISOByAPI(IsoPath) == 0)
999 {
1000 Log("Mount iso by API success");
1001 return 0;
1002 }
1003 else
1004 {
1005 Log("Mount iso by API failed, maybe not supported, try imdisk");
1006 return VentoyMountISOByImdisk(IsoPath, PhyDrive);
1007 }
1008 }
1009 else
1010 {
1011 Log("This is before Windows 8 ...");
1012 if (VentoyMountISOByImdisk(IsoPath, PhyDrive) == 0)
1013 {
1014 Log("Mount iso by imdisk success");
1015 return 0;
1016 }
1017 else
1018 {
1019 return VentoyMountISOByAPI(IsoPath);
1020 }
1021 }
1022 }
1023
1024 static int GetPhyDriveByLogicalDrive(int DriveLetter)
1025 {
1026 BOOL Ret;
1027 DWORD dwSize;
1028 HANDLE Handle;
1029 VOLUME_DISK_EXTENTS DiskExtents;
1030 CHAR PhyPath[128];
1031
1032 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", (CHAR)DriveLetter);
1033
1034 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
1035 if (Handle == INVALID_HANDLE_VALUE)
1036 {
1037 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
1038 return -1;
1039 }
1040
1041 Ret = DeviceIoControl(Handle,
1042 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
1043 NULL,
1044 0,
1045 &DiskExtents,
1046 (DWORD)(sizeof(DiskExtents)),
1047 (LPDWORD)&dwSize,
1048 NULL);
1049
1050 if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
1051 {
1052 Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed %s, error:%u", PhyPath, GetLastError());
1053 SAFE_CLOSE_HANDLE(Handle);
1054 return -1;
1055 }
1056 SAFE_CLOSE_HANDLE(Handle);
1057
1058 Log("LogicalDrive:%s PhyDrive:%d Offset:%llu ExtentLength:%llu",
1059 PhyPath,
1060 DiskExtents.Extents[0].DiskNumber,
1061 DiskExtents.Extents[0].StartingOffset.QuadPart,
1062 DiskExtents.Extents[0].ExtentLength.QuadPart
1063 );
1064
1065 return (int)DiskExtents.Extents[0].DiskNumber;
1066 }
1067
1068
1069 static int DeleteVentoyPart2MountPoint(DWORD PhyDrive)
1070 {
1071 CHAR Letter = 'A';
1072 DWORD Drives;
1073 DWORD PhyDisk;
1074 CHAR DriveName[] = "?:\\";
1075
1076 Log("DeleteVentoyPart2MountPoint Phy%u ...", PhyDrive);
1077
1078 Drives = GetLogicalDrives();
1079 while (Drives)
1080 {
1081 if ((Drives & 0x01) && IsFileExist("%C:\\ventoy\\ventoy.cpio", Letter))
1082 {
1083 Log("File %C:\\ventoy\\ventoy.cpio exist", Letter);
1084
1085 PhyDisk = GetPhyDriveByLogicalDrive(Letter);
1086 Log("PhyDisk=%u for %C", PhyDisk, Letter);
1087
1088 if (PhyDisk == PhyDrive)
1089 {
1090 DriveName[0] = Letter;
1091 DeleteVolumeMountPointA(DriveName);
1092 return 0;
1093 }
1094 }
1095
1096 Letter++;
1097 Drives >>= 1;
1098 }
1099
1100 return 1;
1101 }
1102
1103 static BOOL check_tar_archive(const char *archive, CHAR *tarName)
1104 {
1105 int len;
1106 int nameLen;
1107 const char *pos = archive;
1108 const char *slash = archive;
1109
1110 while (*pos)
1111 {
1112 if (*pos == '\\' || *pos == '/')
1113 {
1114 slash = pos;
1115 }
1116 pos++;
1117 }
1118
1119 len = (int)strlen(slash);
1120
1121 if (len > 7 && (strncmp(slash + len - 7, ".tar.gz", 7) == 0 || strncmp(slash + len - 7, ".tar.xz", 7) == 0))
1122 {
1123 nameLen = (int)sprintf_s(tarName, MAX_PATH, "X:%s", slash);
1124 tarName[nameLen - 3] = 0;
1125 return TRUE;
1126 }
1127 else if (len > 8 && strncmp(slash + len - 8, ".tar.bz2", 8) == 0)
1128 {
1129 nameLen = (int)sprintf_s(tarName, MAX_PATH, "X:%s", slash);
1130 tarName[nameLen - 4] = 0;
1131 return TRUE;
1132 }
1133 else if (len > 9 && strncmp(slash + len - 9, ".tar.lzma", 9) == 0)
1134 {
1135 nameLen = (int)sprintf_s(tarName, MAX_PATH, "X:%s", slash);
1136 tarName[nameLen - 5] = 0;
1137 return TRUE;
1138 }
1139
1140 return FALSE;
1141 }
1142
1143 static UCHAR *g_unxz_buffer = NULL;
1144 static int g_unxz_len = 0;
1145
1146 static void unxz_error(char *x)
1147 {
1148 Log("%s", x);
1149 }
1150
1151 static int unxz_flush(void *src, unsigned int size)
1152 {
1153 memcpy(g_unxz_buffer + g_unxz_len, src, size);
1154 g_unxz_len += (int)size;
1155
1156 return (int)size;
1157 }
1158
1159 static int DecompressInjectionArchive(const char *archive, DWORD PhyDrive)
1160 {
1161 int rc = 1;
1162 int writelen = 0;
1163 UCHAR *Buffer = NULL;
1164 UCHAR *RawBuffer = NULL;
1165 BOOL bRet;
1166 DWORD dwBytes;
1167 DWORD dwSize;
1168 HANDLE hDrive;
1169 HANDLE hOut;
1170 DWORD flags = CREATE_NO_WINDOW;
1171 CHAR StrBuf[MAX_PATH];
1172 CHAR tarName[MAX_PATH];
1173 STARTUPINFOA Si;
1174 PROCESS_INFORMATION Pi;
1175 PROCESS_INFORMATION NewPi;
1176 GET_LENGTH_INFORMATION LengthInfo;
1177 SECURITY_ATTRIBUTES Sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
1178
1179 Log("DecompressInjectionArchive %s", archive);
1180
1181 sprintf_s(StrBuf, sizeof(StrBuf), "\\\\.\\PhysicalDrive%d", PhyDrive);
1182 hDrive = CreateFileA(StrBuf, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
1183 if (hDrive == INVALID_HANDLE_VALUE)
1184 {
1185 Log("Could not open the disk<%s>, error:%u", StrBuf, GetLastError());
1186 goto End;
1187 }
1188
1189 bRet = DeviceIoControl(hDrive, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &LengthInfo, sizeof(LengthInfo), &dwBytes, NULL);
1190 if (!bRet)
1191 {
1192 Log("Could not get phy disk %s size, error:%u", StrBuf, GetLastError());
1193 goto End;
1194 }
1195
1196 g_FatPhyDrive = hDrive;
1197 g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);
1198
1199 Log("Parse FAT fs...");
1200
1201 fl_init();
1202
1203 if (0 == fl_attach_media(VentoyFatDiskRead, NULL))
1204 {
1205 if (g_system_bit == 64)
1206 {
1207 CopyFileFromFatDisk("/ventoy/7z/64/7za.xz", "ventoy\\7za.xz");
1208 }
1209 else
1210 {
1211 CopyFileFromFatDisk("/ventoy/7z/32/7za.xz", "ventoy\\7za.xz");
1212 }
1213
1214 ReadWholeFile2Buf("ventoy\\7za.xz", &Buffer, &dwSize);
1215 Log("7za.xz file size:%u", dwSize);
1216
1217 RawBuffer = malloc(SIZE_1MB * 4);
1218 if (RawBuffer)
1219 {
1220 g_unxz_buffer = RawBuffer;
1221 g_unxz_len = 0;
1222 unxz(Buffer, (int)dwSize, NULL, unxz_flush, NULL, &writelen, unxz_error);
1223 if (writelen == (int)dwSize)
1224 {
1225 Log("Decompress success 7za.xz(%u) ---> 7za.exe(%d)", dwSize, g_unxz_len);
1226 }
1227 else
1228 {
1229 Log("Decompress failed 7za.xz(%u) ---> 7za.exe(%u)", dwSize, dwSize);
1230 }
1231
1232 SaveBuffer2File("ventoy\\7za.exe", RawBuffer, (DWORD)g_unxz_len);
1233
1234 g_unxz_buffer = NULL;
1235 g_unxz_len = 0;
1236 free(RawBuffer);
1237 }
1238 else
1239 {
1240 Log("Failed to alloc 4MB memory");
1241 }
1242
1243 sprintf_s(StrBuf, sizeof(StrBuf), "ventoy\\7za.exe x -y -aoa -oX:\\ %s", archive);
1244
1245 Log("extract inject to X:");
1246 Log("cmdline:<%s>", StrBuf);
1247
1248 GetStartupInfoA(&Si);
1249
1250 hOut = CreateFileA("ventoy\\7z.log",
1251 FILE_APPEND_DATA,
1252 FILE_SHARE_WRITE | FILE_SHARE_READ,
1253 &Sa,
1254 OPEN_ALWAYS,
1255 FILE_ATTRIBUTE_NORMAL,
1256 NULL);
1257
1258 Si.dwFlags |= STARTF_USESTDHANDLES;
1259
1260 if (hOut != INVALID_HANDLE_VALUE)
1261 {
1262 Si.hStdError = hOut;
1263 Si.hStdOutput = hOut;
1264 }
1265
1266 CreateProcessA(NULL, StrBuf, NULL, NULL, TRUE, flags, NULL, NULL, &Si, &Pi);
1267 WaitForSingleObject(Pi.hProcess, INFINITE);
1268
1269 //
1270 // decompress tar archive, for tar.gz/tar.xz/tar.bz2
1271 //
1272 if (check_tar_archive(archive, tarName))
1273 {
1274 Log("Decompress tar archive...<%s>", tarName);
1275
1276 sprintf_s(StrBuf, sizeof(StrBuf), "ventoy\\7za.exe x -y -aoa -oX:\\ %s", tarName);
1277
1278 CreateProcessA(NULL, StrBuf, NULL, NULL, TRUE, flags, NULL, NULL, &Si, &NewPi);
1279 WaitForSingleObject(NewPi.hProcess, INFINITE);
1280
1281 Log("Now delete %s", tarName);
1282 DeleteFileA(tarName);
1283 }
1284
1285 SAFE_CLOSE_HANDLE(hOut);
1286 }
1287 fl_shutdown();
1288
1289 End:
1290
1291 SAFE_CLOSE_HANDLE(hDrive);
1292
1293 return rc;
1294 }
1295
1296 static int UnattendNeedVarExpand(const char *script)
1297 {
1298 FILE *fp = NULL;
1299 char szLine[4096];
1300
1301 fopen_s(&fp, script, "r");
1302 if (!fp)
1303 {
1304 return 0;
1305 }
1306
1307 szLine[0] = szLine[4095] = 0;
1308
1309 while (fgets(szLine, sizeof(szLine) - 1, fp))
1310 {
1311 if (strstr(szLine, "$$VT_"))
1312 {
1313 fclose(fp);
1314 return 1;
1315 }
1316
1317 szLine[0] = szLine[4095] = 0;
1318 }
1319
1320 fclose(fp);
1321 return 0;
1322 }
1323
1324 static int ExpandSingleVar(VarDiskInfo *pDiskInfo, int DiskNum, const char *var, char *value, int len)
1325 {
1326 int i;
1327 int index = -1;
1328 UINT64 uiDst = 0;
1329 UINT64 uiDelta = 0;
1330 UINT64 uiMaxSize = 0;
1331 UINT64 uiMaxDelta = ULLONG_MAX;
1332
1333 value[0] = 0;
1334
1335 if (strcmp(var, "VT_WINDOWS_DISK_1ST_NONVTOY") == 0)
1336 {
1337 for (i = 0; i < DiskNum; i++)
1338 {
1339 if (pDiskInfo[i].Capacity > 0 && i != g_vtoy_disk_drive)
1340 {
1341 Log("%s=<PhyDrive%d>", var, i);
1342 sprintf_s(value, len, "%d", i);
1343 return 0;
1344 }
1345 }
1346 }
1347 else if (strcmp(var, "VT_WINDOWS_DISK_1ST_NONUSB") == 0)
1348 {
1349 for (i = 0; i < DiskNum; i++)
1350 {
1351 if (pDiskInfo[i].Capacity > 0 && pDiskInfo[i].BusType != BusTypeUsb)
1352 {
1353 Log("%s=<PhyDrive%d>", var, i);
1354 sprintf_s(value, len, "%d", i);
1355 return 0;
1356 }
1357 }
1358 }
1359 else if (strcmp(var, "VT_WINDOWS_DISK_MAX_SIZE") == 0)
1360 {
1361 for (i = 0; i < DiskNum; i++)
1362 {
1363 if (pDiskInfo[i].Capacity > 0 && pDiskInfo[i].Capacity > uiMaxSize)
1364 {
1365 index = i;
1366 uiMaxSize = pDiskInfo[i].Capacity;
1367 }
1368 }
1369
1370 Log("%s=<PhyDrive%d>", var, index);
1371 sprintf_s(value, len, "%d", index);
1372 }
1373 else if (strncmp(var, "VT_WINDOWS_DISK_CLOSEST_", 24) == 0)
1374 {
1375 uiDst = strtoul(var + 24, NULL, 10);
1376 uiDst = uiDst * (1024ULL * 1024ULL * 1024ULL);
1377
1378 for (i = 0; i < DiskNum; i++)
1379 {
1380 if (pDiskInfo[i].Capacity == 0)
1381 {
1382 continue;
1383 }
1384
1385 if (pDiskInfo[i].Capacity > uiDst)
1386 {
1387 uiDelta = pDiskInfo[i].Capacity - uiDst;
1388 }
1389 else
1390 {
1391 uiDelta = uiDst - pDiskInfo[i].Capacity;
1392 }
1393
1394 if (uiDelta < uiMaxDelta)
1395 {
1396 uiMaxDelta = uiDelta;
1397 index = i;
1398 }
1399 }
1400
1401 Log("%s=<PhyDrive%d>", var, index);
1402 sprintf_s(value, len, "%d", index);
1403 }
1404 else
1405 {
1406 Log("Invalid var name <%s>", var);
1407 sprintf_s(value, len, "$$%s$$", var);
1408 }
1409
1410 if (value[0] == 0)
1411 {
1412 sprintf_s(value, len, "$$%s$$", var);
1413 }
1414
1415 return 0;
1416 }
1417
1418 static void TrimString(CHAR *String)
1419 {
1420 CHAR *Pos1 = String;
1421 CHAR *Pos2 = String;
1422 size_t Len = strlen(String);
1423
1424 while (Len > 0)
1425 {
1426 if (String[Len - 1] != ' ' && String[Len - 1] != '\t')
1427 {
1428 break;
1429 }
1430 String[Len - 1] = 0;
1431 Len--;
1432 }
1433
1434 while (*Pos1 == ' ' || *Pos1 == '\t')
1435 {
1436 Pos1++;
1437 }
1438
1439 while (*Pos1)
1440 {
1441 *Pos2++ = *Pos1++;
1442 }
1443 *Pos2++ = 0;
1444
1445 return;
1446 }
1447
1448 static int GetRegDwordValue(HKEY Key, LPCSTR SubKey, LPCSTR ValueName, DWORD *pValue)
1449 {
1450 HKEY hKey;
1451 DWORD Type;
1452 DWORD Size;
1453 LSTATUS lRet;
1454 DWORD Value;
1455
1456 lRet = RegOpenKeyExA(Key, SubKey, 0, KEY_QUERY_VALUE, &hKey);
1457 Log("RegOpenKeyExA <%s> Ret:%ld", SubKey, lRet);
1458
1459 if (ERROR_SUCCESS == lRet)
1460 {
1461 Size = sizeof(Value);
1462 lRet = RegQueryValueExA(hKey, ValueName, NULL, &Type, (LPBYTE)&Value, &Size);
1463 Log("RegQueryValueExA <%s> ret:%u Size:%u Value:%u", ValueName, lRet, Size, Value);
1464
1465 *pValue = Value;
1466 RegCloseKey(hKey);
1467
1468 return 0;
1469 }
1470 else
1471 {
1472 return 1;
1473 }
1474 }
1475
1476 static const CHAR * GetBusTypeString(int Type)
1477 {
1478 switch (Type)
1479 {
1480 case BusTypeUnknown: return "unknown";
1481 case BusTypeScsi: return "SCSI";
1482 case BusTypeAtapi: return "Atapi";
1483 case BusTypeAta: return "ATA";
1484 case BusType1394: return "1394";
1485 case BusTypeSsa: return "SSA";
1486 case BusTypeFibre: return "Fibre";
1487 case BusTypeUsb: return "USB";
1488 case BusTypeRAID: return "RAID";
1489 case BusTypeiScsi: return "iSCSI";
1490 case BusTypeSas: return "SAS";
1491 case BusTypeSata: return "SATA";
1492 case BusTypeSd: return "SD";
1493 case BusTypeMmc: return "MMC";
1494 case BusTypeVirtual: return "Virtual";
1495 case BusTypeFileBackedVirtual: return "FileBackedVirtual";
1496 case BusTypeSpaces: return "Spaces";
1497 case BusTypeNvme: return "Nvme";
1498 }
1499 return "unknown";
1500 }
1501
1502 static int GetHumanReadableGBSize(UINT64 SizeBytes)
1503 {
1504 int i;
1505 int Pow2 = 1;
1506 double Delta;
1507 double GB = SizeBytes * 1.0 / 1000 / 1000 / 1000;
1508
1509 if ((SizeBytes % 1073741824) == 0)
1510 {
1511 return (int)(SizeBytes / 1073741824);
1512 }
1513
1514 for (i = 0; i < 12; i++)
1515 {
1516 if (Pow2 > GB)
1517 {
1518 Delta = (Pow2 - GB) / Pow2;
1519 }
1520 else
1521 {
1522 Delta = (GB - Pow2) / Pow2;
1523 }
1524
1525 if (Delta < 0.05)
1526 {
1527 return Pow2;
1528 }
1529
1530 Pow2 <<= 1;
1531 }
1532
1533 return (int)GB;
1534 }
1535
1536 static int EnumerateAllDisk(VarDiskInfo **ppDiskInfo, int *pDiskNum)
1537 {
1538 int i;
1539 DWORD Value;
1540 int DiskNum = 0;
1541 BOOL bRet;
1542 DWORD dwBytes;
1543 VarDiskInfo *pDiskInfo = NULL;
1544 HANDLE Handle = INVALID_HANDLE_VALUE;
1545 CHAR PhyDrive[128];
1546 GET_LENGTH_INFORMATION LengthInfo;
1547 STORAGE_PROPERTY_QUERY Query;
1548 STORAGE_DESCRIPTOR_HEADER DevDescHeader;
1549 STORAGE_DEVICE_DESCRIPTOR *pDevDesc;
1550
1551 if (GetRegDwordValue(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\disk\\Enum", "Count", &Value) == 0)
1552 {
1553 DiskNum = (int)Value;
1554 }
1555 else
1556 {
1557 Log("Failed to read disk count");
1558 return 1;
1559 }
1560
1561 Log("Current phy disk count:%d", DiskNum);
1562 if (DiskNum <= 0)
1563 {
1564 return 1;
1565 }
1566
1567 pDiskInfo = malloc(DiskNum * sizeof(VarDiskInfo));
1568 if (!pDiskInfo)
1569 {
1570 Log("Failed to alloc");
1571 return 1;
1572 }
1573 memset(pDiskInfo, 0, DiskNum * sizeof(VarDiskInfo));
1574
1575 for (i = 0; i < DiskNum; i++)
1576 {
1577 SAFE_CLOSE_HANDLE(Handle);
1578
1579 safe_sprintf(PhyDrive, "\\\\.\\PhysicalDrive%d", i);
1580 Handle = CreateFileA(PhyDrive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
1581 Log("Create file Handle:%p %s status:%u", Handle, PhyDrive, LASTERR);
1582
1583 if (Handle == INVALID_HANDLE_VALUE)
1584 {
1585 continue;
1586 }
1587
1588 bRet = DeviceIoControl(Handle,
1589 IOCTL_DISK_GET_LENGTH_INFO, NULL,
1590 0,
1591 &LengthInfo,
1592 sizeof(LengthInfo),
1593 &dwBytes,
1594 NULL);
1595 if (!bRet)
1596 {
1597 Log("DeviceIoControl IOCTL_DISK_GET_LENGTH_INFO failed error:%u", LASTERR);
1598 continue;
1599 }
1600
1601 Log("PHYSICALDRIVE%d size %llu bytes", i, (ULONGLONG)LengthInfo.Length.QuadPart);
1602
1603 Query.PropertyId = StorageDeviceProperty;
1604 Query.QueryType = PropertyStandardQuery;
1605
1606 bRet = DeviceIoControl(Handle,
1607 IOCTL_STORAGE_QUERY_PROPERTY,
1608 &Query,
1609 sizeof(Query),
1610 &DevDescHeader,
1611 sizeof(STORAGE_DESCRIPTOR_HEADER),
1612 &dwBytes,
1613 NULL);
1614 if (!bRet)
1615 {
1616 Log("DeviceIoControl1 error:%u dwBytes:%u", LASTERR, dwBytes);
1617 continue;
1618 }
1619
1620 if (DevDescHeader.Size < sizeof(STORAGE_DEVICE_DESCRIPTOR))
1621 {
1622 Log("Invalid DevDescHeader.Size:%u", DevDescHeader.Size);
1623 continue;
1624 }
1625
1626 pDevDesc = (STORAGE_DEVICE_DESCRIPTOR *)malloc(DevDescHeader.Size);
1627 if (!pDevDesc)
1628 {
1629 Log("failed to malloc error:%u len:%u", LASTERR, DevDescHeader.Size);
1630 continue;
1631 }
1632
1633 bRet = DeviceIoControl(Handle,
1634 IOCTL_STORAGE_QUERY_PROPERTY,
1635 &Query,
1636 sizeof(Query),
1637 pDevDesc,
1638 DevDescHeader.Size,
1639 &dwBytes,
1640 NULL);
1641 if (!bRet)
1642 {
1643 Log("DeviceIoControl2 error:%u dwBytes:%u", LASTERR, dwBytes);
1644 free(pDevDesc);
1645 continue;
1646 }
1647
1648 pDiskInfo[i].RemovableMedia = pDevDesc->RemovableMedia;
1649 pDiskInfo[i].BusType = pDevDesc->BusType;
1650 pDiskInfo[i].DeviceType = pDevDesc->DeviceType;
1651 pDiskInfo[i].Capacity = LengthInfo.Length.QuadPart;
1652
1653 if (pDevDesc->VendorIdOffset)
1654 {
1655 safe_strcpy(pDiskInfo[i].VendorId, (char *)pDevDesc + pDevDesc->VendorIdOffset);
1656 TrimString(pDiskInfo[i].VendorId);
1657 }
1658
1659 if (pDevDesc->ProductIdOffset)
1660 {
1661 safe_strcpy(pDiskInfo[i].ProductId, (char *)pDevDesc + pDevDesc->ProductIdOffset);
1662 TrimString(pDiskInfo[i].ProductId);
1663 }
1664
1665 if (pDevDesc->ProductRevisionOffset)
1666 {
1667 safe_strcpy(pDiskInfo[i].ProductRev, (char *)pDevDesc + pDevDesc->ProductRevisionOffset);
1668 TrimString(pDiskInfo[i].ProductRev);
1669 }
1670
1671 if (pDevDesc->SerialNumberOffset)
1672 {
1673 safe_strcpy(pDiskInfo[i].SerialNumber, (char *)pDevDesc + pDevDesc->SerialNumberOffset);
1674 TrimString(pDiskInfo[i].SerialNumber);
1675 }
1676
1677 free(pDevDesc);
1678 SAFE_CLOSE_HANDLE(Handle);
1679 }
1680
1681 Log("########## DUMP DISK BEGIN ##########");
1682 for (i = 0; i < DiskNum; i++)
1683 {
1684 Log("PhyDrv:%d BusType:%-4s Removable:%u Size:%dGB(%llu) Name:%s %s",
1685 i, GetBusTypeString(pDiskInfo[i].BusType), pDiskInfo[i].RemovableMedia,
1686 GetHumanReadableGBSize(pDiskInfo[i].Capacity), pDiskInfo[i].Capacity,
1687 pDiskInfo[i].VendorId, pDiskInfo[i].ProductId);
1688 }
1689 Log("Ventoy disk is PhyDvr%d", g_vtoy_disk_drive);
1690 Log("########## DUMP DISK END ##########");
1691
1692 *ppDiskInfo = pDiskInfo;
1693 *pDiskNum = DiskNum;
1694 return 0;
1695 }
1696
1697 static int UnattendVarExpand(const char *script, const char *tmpfile)
1698 {
1699 FILE *fp = NULL;
1700 FILE *fout = NULL;
1701 char *start = NULL;
1702 char *end = NULL;
1703 char szLine[4096];
1704 char szValue[256];
1705 int DiskNum = 0;
1706 VarDiskInfo *pDiskInfo = NULL;
1707
1708 Log("UnattendVarExpand ...");
1709
1710 if (EnumerateAllDisk(&pDiskInfo, &DiskNum))
1711 {
1712 Log("Failed to EnumerateAllDisk");
1713 return 1;
1714 }
1715
1716 fopen_s(&fp, script, "r");
1717 if (!fp)
1718 {
1719 free(pDiskInfo);
1720 return 0;
1721 }
1722
1723 fopen_s(&fout, tmpfile, "w+");
1724 if (!fout)
1725 {
1726 fclose(fp);
1727 free(pDiskInfo);
1728 return 0;
1729 }
1730
1731 szLine[0] = szLine[4095] = 0;
1732
1733 while (fgets(szLine, sizeof(szLine) - 1, fp))
1734 {
1735 start = strstr(szLine, "$$VT_");
1736 if (start)
1737 {
1738 end = strstr(start + 5, "$$");
1739 }
1740
1741 if (start && end)
1742 {
1743 *start = 0;
1744 fprintf(fout, "%s", szLine);
1745
1746 *end = 0;
1747 ExpandSingleVar(pDiskInfo, DiskNum, start + 2, szValue, sizeof(szValue) - 1);
1748 fprintf(fout, "%s", szValue);
1749
1750 fprintf(fout, "%s", end + 2);
1751 }
1752 else
1753 {
1754 fprintf(fout, "%s", szLine);
1755 }
1756
1757 szLine[0] = szLine[4095] = 0;
1758 }
1759
1760 fclose(fp);
1761 fclose(fout);
1762 free(pDiskInfo);
1763 return 0;
1764 }
1765
1766 //#define VAR_DEBUG 1
1767
1768 static int ProcessUnattendedInstallation(const char *script)
1769 {
1770 DWORD dw;
1771 HKEY hKey;
1772 LSTATUS Ret;
1773 CHAR Letter;
1774 CHAR TmpFile[MAX_PATH];
1775 CHAR CurDir[MAX_PATH];
1776
1777 Log("Copy unattended XML ...");
1778
1779 GetCurrentDirectory(sizeof(CurDir), CurDir);
1780 Letter = CurDir[0];
1781 if ((Letter >= 'A' && Letter <= 'Z') || (Letter >= 'a' && Letter <= 'z'))
1782 {
1783 Log("Current Drive Letter: %C", Letter);
1784 }
1785 else
1786 {
1787 Letter = 'X';
1788 }
1789
1790 #ifdef VAR_DEBUG
1791 sprintf_s(CurDir, sizeof(CurDir), "%C:\\AutounattendXXX.xml", Letter);
1792 #else
1793 sprintf_s(CurDir, sizeof(CurDir), "%C:\\Autounattend.xml", Letter);
1794 #endif
1795
1796 if (UnattendNeedVarExpand(script))
1797 {
1798 sprintf_s(TmpFile, sizeof(TmpFile), "%C:\\__Autounattend", Letter);
1799 UnattendVarExpand(script, TmpFile);
1800
1801 Log("Expand Copy file <%s> --> <%s>", script, CurDir);
1802 CopyFile(TmpFile, CurDir, FALSE);
1803 }
1804 else
1805 {
1806 Log("No var expand copy file <%s> --> <%s>", script, CurDir);
1807 CopyFile(script, CurDir, FALSE);
1808 }
1809
1810 #ifndef VAR_DEBUG
1811 Ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "System\\Setup", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dw);
1812 if (ERROR_SUCCESS == Ret)
1813 {
1814 Ret = RegSetValueEx(hKey, "UnattendFile", 0, REG_SZ, CurDir, (DWORD)(strlen(CurDir) + 1));
1815 }
1816 #endif
1817
1818 return 0;
1819 }
1820
1821 static int Windows11BypassCheck(const char *isofile, const char MntLetter)
1822 {
1823 int Ret = 1;
1824 DWORD dwHandle;
1825 DWORD dwSize;
1826 DWORD dwValue = 1;
1827 UINT VerLen = 0;
1828 CHAR *Buffer = NULL;
1829 VS_FIXEDFILEINFO* VerInfo = NULL;
1830 CHAR CheckFile[MAX_PATH];
1831 UINT16 Major, Minor, Build, Revision;
1832
1833 Log("Windows11BypassCheck for <%s> %C:", isofile, MntLetter);
1834
1835 if (FALSE == IsFileExist("%C:\\sources\\boot.wim", MntLetter) ||
1836 FALSE == IsFileExist("%C:\\sources\\compatresources.dll", MntLetter))
1837 {
1838 Log("boot.wim/compatresources.dll not exist, this is not a windows install media.");
1839 goto End;
1840 }
1841
1842 if (FALSE == IsFileExist("%C:\\sources\\install.wim", MntLetter) &&
1843 FALSE == IsFileExist("%C:\\sources\\install.esd", MntLetter))
1844 {
1845 Log("install.wim/install.esd not exist, this is not a windows install media.");
1846 goto End;
1847 }
1848
1849 sprintf_s(CheckFile, sizeof(CheckFile), "%C:\\sources\\compatresources.dll", MntLetter);
1850 dwSize = GetFileVersionInfoSizeA(CheckFile, &dwHandle);
1851 if (0 == dwSize)
1852 {
1853 Log("Failed to get file version info size: %u", LASTERR);
1854 goto End;
1855 }
1856
1857 Buffer = malloc(dwSize);
1858 if (!Buffer)
1859 {
1860 goto End;
1861 }
1862
1863 if (FALSE == GetFileVersionInfoA(CheckFile, dwHandle, dwSize, Buffer))
1864 {
1865 Log("Failed to get file version info : %u", LASTERR);
1866 goto End;
1867 }
1868
1869 if (VerQueryValueA(Buffer, "\\", (LPVOID)&VerInfo, &VerLen) && VerLen != 0)
1870 {
1871 if (VerInfo->dwSignature == VS_FFI_SIGNATURE)
1872 {
1873 Major = HIWORD(VerInfo->dwFileVersionMS);
1874 Minor = LOWORD(VerInfo->dwFileVersionMS);
1875 Build = HIWORD(VerInfo->dwFileVersionLS);
1876 Revision = LOWORD(VerInfo->dwFileVersionLS);
1877
1878 Log("FileVersionze: <%u %u %u %u>", Major, Minor, Build, Revision);
1879
1880 if (Major == 10 && Build > 20000)
1881 {
1882 Major = 11;
1883 }
1884
1885 if (Major != 11)
1886 {
1887 Log("This is not Windows 11, not need to bypass.", Major);
1888 goto End;
1889 }
1890 }
1891 }
1892
1893 //Now we really need to bypass windows 11 check. create registry
1894 HKEY hKey = NULL;
1895 HKEY hSubKey = NULL;
1896 LSTATUS Status;
1897
1898 Status = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "System\\Setup", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwSize);
1899 if (ERROR_SUCCESS != Status)
1900 {
1901 Log("Failed to create reg key System\\Setup %u %u", LASTERR, Status);
1902 goto End;
1903 }
1904
1905 Status = RegCreateKeyExA(hKey, "LabConfig", 0, NULL, 0, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hSubKey, &dwSize);
1906 if (ERROR_SUCCESS != Status)
1907 {
1908 Log("Failed to create LabConfig reg %u %u", LASTERR, Status);
1909 goto End;
1910 }
1911
1912 //set reg value
1913 Status += RegSetValueExA(hSubKey, "BypassRAMCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
1914 Status += RegSetValueExA(hSubKey, "BypassTPMCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
1915 Status += RegSetValueExA(hSubKey, "BypassSecureBootCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
1916 Status += RegSetValueExA(hSubKey, "BypassStorageCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
1917 Status += RegSetValueExA(hSubKey, "BypassCPUCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
1918
1919 Log("Create bypass registry %s %u", (Status == ERROR_SUCCESS) ? "SUCCESS" : "FAILED", Status);
1920
1921 Ret = 0;
1922
1923 End:
1924 if (Buffer)
1925 {
1926 free(Buffer);
1927 }
1928
1929 return Ret;
1930 }
1931
1932 static BOOL CheckVentoyDisk(DWORD DiskNum)
1933 {
1934 DWORD dwSize = 0;
1935 CHAR PhyPath[128];
1936 UINT8 SectorBuf[512];
1937 HANDLE Handle;
1938 UINT8 check[8] = { 0x56, 0x54, 0x00, 0x47, 0x65, 0x00, 0x48, 0x44 };
1939
1940 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", DiskNum);
1941 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
1942 if (Handle == INVALID_HANDLE_VALUE)
1943 {
1944 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
1945 return FALSE;
1946 }
1947
1948 if (!ReadFile(Handle, SectorBuf, sizeof(SectorBuf), &dwSize, NULL))
1949 {
1950 Log("ReadFile failed, dwSize:%u error:%u", dwSize, GetLastError());
1951 CloseHandle(Handle);
1952 return FALSE;
1953 }
1954
1955 CloseHandle(Handle);
1956
1957 if (memcmp(SectorBuf + 0x190, check, 8) == 0)
1958 {
1959 return TRUE;
1960 }
1961
1962 return FALSE;
1963 }
1964
1965
1966 static int VentoyHook(ventoy_os_param *param)
1967 {
1968 int i;
1969 int rc;
1970 BOOL find = FALSE;
1971 BOOL vtoyfind = FALSE;
1972 CHAR Letter;
1973 CHAR MntLetter;
1974 CHAR VtoyLetter;
1975 DWORD Drives;
1976 DWORD NewDrives;
1977 DWORD VtoyDiskNum;
1978 UINT32 DiskSig;
1979 UINT32 VtoySig;
1980 DISK_EXTENT DiskExtent;
1981 DISK_EXTENT VtoyDiskExtent;
1982 UINT8 UUID[16];
1983 CHAR IsoPath[MAX_PATH];
1984
1985 Log("VentoyHook Path:<%s>", param->vtoy_img_path);
1986
1987 if (IsUTF8Encode(param->vtoy_img_path))
1988 {
1989 Log("This file is UTF8 encoding");
1990 }
1991
1992 for (i = 0; i < 5; i++)
1993 {
1994 Letter = 'A';
1995 Drives = GetLogicalDrives();
1996 Log("Logic Drives: 0x%x", Drives);
1997
1998 while (Drives)
1999 {
2000 if (Drives & 0x01)
2001 {
2002 sprintf_s(IsoPath, sizeof(IsoPath), "%C:\\%s", Letter, param->vtoy_img_path);
2003 if (IsFileExist("%s", IsoPath))
2004 {
2005 Log("File exist under %C:", Letter);
2006 memset(UUID, 0, sizeof(UUID));
2007 memset(&DiskExtent, 0, sizeof(DiskExtent));
2008 if (GetPhyDiskUUID(Letter, UUID, NULL, &DiskExtent) == 0)
2009 {
2010 if (memcmp(UUID, param->vtoy_disk_guid, 16) == 0)
2011 {
2012 Log("Disk UUID match");
2013 find = TRUE;
2014 break;
2015 }
2016 }
2017 }
2018 else
2019 {
2020 Log("File NOT exist under %C:", Letter);
2021 }
2022 }
2023
2024 Drives >>= 1;
2025 Letter++;
2026 }
2027
2028 if (find)
2029 {
2030 break;
2031 }
2032 else
2033 {
2034 Log("Now wait and retry ...");
2035 Sleep(1000);
2036 }
2037 }
2038
2039 if (find == FALSE)
2040 {
2041 Log("Failed to find ISO file");
2042 return 1;
2043 }
2044
2045 Log("Find ISO file <%s>", IsoPath);
2046
2047 //Find VtoyLetter in Vlnk Mode
2048 if (g_os_param_reserved[6] == 1)
2049 {
2050 memcpy(&VtoySig, g_os_param_reserved + 7, 4);
2051 for (i = 0; i < 5; i++)
2052 {
2053 VtoyLetter = 'A';
2054 Drives = GetLogicalDrives();
2055 Log("Logic Drives: 0x%x VentoySig:%08X", Drives, VtoySig);
2056
2057 while (Drives)
2058 {
2059 if (Drives & 0x01)
2060 {
2061 memset(UUID, 0, sizeof(UUID));
2062 memset(&VtoyDiskExtent, 0, sizeof(VtoyDiskExtent));
2063 DiskSig = 0;
2064 if (GetPhyDiskUUID(VtoyLetter, UUID, &DiskSig, &VtoyDiskExtent) == 0)
2065 {
2066 Log("DiskSig=%08X PartStart=%lld", DiskSig, VtoyDiskExtent.StartingOffset.QuadPart);
2067 if (DiskSig == VtoySig && VtoyDiskExtent.StartingOffset.QuadPart == SIZE_1MB)
2068 {
2069 Log("Ventoy Disk Sig match");
2070 vtoyfind = TRUE;
2071 break;
2072 }
2073 }
2074 }
2075
2076 Drives >>= 1;
2077 VtoyLetter++;
2078 }
2079
2080 if (vtoyfind)
2081 {
2082 Log("Find Ventoy Letter: %C", VtoyLetter);
2083 break;
2084 }
2085 else
2086 {
2087 Log("Now wait and retry ...");
2088 Sleep(1000);
2089 }
2090 }
2091
2092 if (vtoyfind == FALSE)
2093 {
2094 Log("Failed to find ventoy disk");
2095 return 1;
2096 }
2097
2098 VtoyDiskNum = VtoyDiskExtent.DiskNumber;
2099 }
2100 else
2101 {
2102 VtoyLetter = Letter;
2103 Log("No vlnk mode %C", Letter);
2104
2105 VtoyDiskNum = DiskExtent.DiskNumber;
2106 }
2107
2108 if (CheckVentoyDisk(VtoyDiskNum))
2109 {
2110 Log("Disk check OK %C: %u", VtoyLetter, VtoyDiskNum);
2111 }
2112 else
2113 {
2114 Log("Failed to check ventoy disk %u", VtoyDiskNum);
2115 return 1;
2116 }
2117
2118 g_vtoy_disk_drive = VtoyDiskNum;
2119
2120 Drives = GetLogicalDrives();
2121 Log("Drives before mount: 0x%x", Drives);
2122
2123 rc = MountIsoFile(IsoPath, VtoyDiskNum);
2124
2125 NewDrives = GetLogicalDrives();
2126 Log("Drives after mount: 0x%x (0x%x)", NewDrives, (NewDrives ^ Drives));
2127
2128 MntLetter = 'A';
2129 NewDrives = (NewDrives ^ Drives);
2130 while (NewDrives)
2131 {
2132 if (NewDrives & 0x01)
2133 {
2134 if ((NewDrives >> 1) == 0)
2135 {
2136 Log("The ISO file is mounted at %C:", MntLetter);
2137 }
2138 else
2139 {
2140 Log("Maybe the ISO file is mounted at %C:", MntLetter);
2141 }
2142 break;
2143 }
2144
2145 NewDrives >>= 1;
2146 MntLetter++;
2147 }
2148
2149 Log("Mount ISO FILE: %s", rc == 0 ? "SUCCESS" : "FAILED");
2150
2151 //Windows 11 bypass check
2152 if (g_windows_data.windows11_bypass_check == 1)
2153 {
2154 Windows11BypassCheck(IsoPath, MntLetter);
2155 }
2156
2157 // for protect
2158 rc = DeleteVentoyPart2MountPoint(VtoyDiskNum);
2159 Log("Delete ventoy mountpoint: %s", rc == 0 ? "SUCCESS" : "NO NEED");
2160
2161 if (g_windows_data.auto_install_script[0])
2162 {
2163 if (IsFileExist("%s", VTOY_AUTO_FILE))
2164 {
2165 Log("use auto install script %s...", VTOY_AUTO_FILE);
2166 ProcessUnattendedInstallation(VTOY_AUTO_FILE);
2167 }
2168 else
2169 {
2170 Log("auto install script %s not exist", IsoPath);
2171 }
2172 }
2173 else
2174 {
2175 Log("auto install no need");
2176 }
2177
2178 if (g_windows_data.injection_archive[0])
2179 {
2180 sprintf_s(IsoPath, sizeof(IsoPath), "%C:%s", VtoyLetter, g_windows_data.injection_archive);
2181 if (IsFileExist("%s", IsoPath))
2182 {
2183 Log("decompress injection archive %s...", IsoPath);
2184 DecompressInjectionArchive(IsoPath, VtoyDiskNum);
2185
2186 if (IsFileExist("%s", AUTO_RUN_BAT))
2187 {
2188 HANDLE hOut;
2189 DWORD flags = CREATE_NO_WINDOW;
2190 CHAR StrBuf[1024];
2191 STARTUPINFOA Si;
2192 PROCESS_INFORMATION Pi;
2193 SECURITY_ATTRIBUTES Sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
2194
2195 Log("%s exist, now run it...", AUTO_RUN_BAT);
2196
2197 GetStartupInfoA(&Si);
2198
2199 hOut = CreateFileA(AUTO_RUN_LOG,
2200 FILE_APPEND_DATA,
2201 FILE_SHARE_WRITE | FILE_SHARE_READ,
2202 &Sa,
2203 OPEN_ALWAYS,
2204 FILE_ATTRIBUTE_NORMAL,
2205 NULL);
2206
2207 Si.dwFlags |= STARTF_USESTDHANDLES;
2208 if (hOut != INVALID_HANDLE_VALUE)
2209 {
2210 Si.hStdError = hOut;
2211 Si.hStdOutput = hOut;
2212 }
2213
2214 sprintf_s(IsoPath, sizeof(IsoPath), "%C:\\%s", Letter, param->vtoy_img_path);
2215 sprintf_s(StrBuf, sizeof(StrBuf), "cmd.exe /c %s \"%s\" %C", AUTO_RUN_BAT, IsoPath, MntLetter);
2216 CreateProcessA(NULL, StrBuf, NULL, NULL, TRUE, flags, NULL, NULL, &Si, &Pi);
2217 WaitForSingleObject(Pi.hProcess, INFINITE);
2218
2219 SAFE_CLOSE_HANDLE(hOut);
2220 }
2221 else
2222 {
2223 Log("%s not exist...", AUTO_RUN_BAT);
2224 }
2225 }
2226 else
2227 {
2228 Log("injection archive %s not exist", IsoPath);
2229 }
2230 }
2231 else
2232 {
2233 Log("no injection archive found");
2234 }
2235
2236 return 0;
2237 }
2238
2239 static int ExtractWindowsDataFile(char *databuf)
2240 {
2241 int len = 0;
2242 char *filedata = NULL;
2243 ventoy_windows_data *pdata = (ventoy_windows_data *)databuf;
2244
2245 Log("ExtractWindowsDataFile: auto install <%s:%d>", pdata->auto_install_script, pdata->auto_install_len);
2246
2247 filedata = databuf + sizeof(ventoy_windows_data);
2248
2249 if (pdata->auto_install_script[0] && pdata->auto_install_len > 0)
2250 {
2251 SaveBuffer2File(VTOY_AUTO_FILE, filedata, pdata->auto_install_len);
2252 filedata += pdata->auto_install_len;
2253 len = pdata->auto_install_len;
2254 }
2255
2256 return len;
2257 }
2258
2259 int VentoyJumpWimboot(INT argc, CHAR **argv, CHAR *LunchFile)
2260 {
2261 int rc = 1;
2262 char *buf = NULL;
2263 DWORD size = 0;
2264 DWORD Pos;
2265
2266 Log("VentoyJumpWimboot %dbit", g_system_bit);
2267
2268 sprintf_s(LunchFile, MAX_PATH, "X:\\setup.exe");
2269
2270 ReadWholeFile2Buf("wimboot.data", &buf, &size);
2271 Log("wimboot.data size:%d", size);
2272
2273 memcpy(&g_os_param, buf, sizeof(ventoy_os_param));
2274 memcpy(&g_windows_data, buf + sizeof(ventoy_os_param), sizeof(ventoy_windows_data));
2275 ExtractWindowsDataFile(buf + sizeof(ventoy_os_param));
2276 memcpy(g_os_param_reserved, g_os_param.vtoy_reserved, sizeof(g_os_param_reserved));
2277
2278 if (g_os_param_reserved[0] == 1)
2279 {
2280 Log("break here for debug .....");
2281 goto End;
2282 }
2283
2284 // convert / to \\
2285 for (Pos = 0; Pos < sizeof(g_os_param.vtoy_img_path) && g_os_param.vtoy_img_path[Pos]; Pos++)
2286 {
2287 if (g_os_param.vtoy_img_path[Pos] == '/')
2288 {
2289 g_os_param.vtoy_img_path[Pos] = '\\';
2290 }
2291 }
2292
2293 if (g_os_param_reserved[0] == 2)
2294 {
2295 Log("skip hook for debug .....");
2296 rc = 0;
2297 goto End;
2298 }
2299
2300 rc = VentoyHook(&g_os_param);
2301
2302 End:
2303
2304 if (buf)
2305 {
2306 free(buf);
2307 }
2308
2309 return rc;
2310 }
2311
2312 static int ventoy_check_create_directory(void)
2313 {
2314 if (IsDirExist("ventoy"))
2315 {
2316 Log("ventoy directory already exist");
2317 }
2318 else
2319 {
2320 Log("ventoy directory not exist, now create it.");
2321 if (!CreateDirectoryA("ventoy", NULL))
2322 {
2323 Log("Failed to create ventoy directory err:%u", GetLastError());
2324 return 1;
2325 }
2326 }
2327
2328 return 0;
2329 }
2330
2331 int VentoyJump(INT argc, CHAR **argv, CHAR *LunchFile)
2332 {
2333 int rc = 1;
2334 int stat = 0;
2335 int exlen = 0;
2336 DWORD Pos;
2337 DWORD PeStart;
2338 DWORD FileSize;
2339 DWORD LockStatus = 0;
2340 BYTE *Buffer = NULL;
2341 CHAR ExeFileName[MAX_PATH];
2342
2343 sprintf_s(ExeFileName, sizeof(ExeFileName), "%s", argv[0]);
2344 if (!IsFileExist("%s", ExeFileName))
2345 {
2346 Log("File %s NOT exist, now try %s.exe", ExeFileName, ExeFileName);
2347 sprintf_s(ExeFileName, sizeof(ExeFileName), "%s.exe", argv[0]);
2348
2349 Log("File %s exist ? %s", ExeFileName, IsFileExist("%s", ExeFileName) ? "YES" : "NO");
2350 }
2351
2352 if (ReadWholeFile2Buf(ExeFileName, (void **)&Buffer, &FileSize))
2353 {
2354 goto End;
2355 }
2356
2357 Log("VentoyJump %dbit", g_system_bit);
2358
2359 MUTEX_LOCK(g_vtoyins_mutex);
2360 stat = ventoy_check_create_directory();
2361 MUTEX_UNLOCK(g_vtoyins_mutex);
2362
2363 if (stat != 0)
2364 {
2365 goto End;
2366 }
2367
2368 for (PeStart = 0; PeStart < FileSize; PeStart += 16)
2369 {
2370 if (CheckOsParam((ventoy_os_param *)(Buffer + PeStart)) &&
2371 CheckPeHead(Buffer, FileSize, PeStart + sizeof(ventoy_os_param)))
2372 {
2373 Log("Find os pararm at %u", PeStart);
2374
2375 memcpy(&g_os_param, Buffer + PeStart, sizeof(ventoy_os_param));
2376 memcpy(&g_windows_data, Buffer + PeStart + sizeof(ventoy_os_param), sizeof(ventoy_windows_data));
2377 exlen = ExtractWindowsDataFile(Buffer + PeStart + sizeof(ventoy_os_param));
2378 memcpy(g_os_param_reserved, g_os_param.vtoy_reserved, sizeof(g_os_param_reserved));
2379
2380 if (g_os_param_reserved[0] == 1)
2381 {
2382 Log("break here for debug .....");
2383 goto End;
2384 }
2385
2386 // convert / to \\
2387 for (Pos = 0; Pos < sizeof(g_os_param.vtoy_img_path) && g_os_param.vtoy_img_path[Pos]; Pos++)
2388 {
2389 if (g_os_param.vtoy_img_path[Pos] == '/')
2390 {
2391 g_os_param.vtoy_img_path[Pos] = '\\';
2392 }
2393 }
2394
2395 PeStart += sizeof(ventoy_os_param) + sizeof(ventoy_windows_data) + exlen;
2396 sprintf_s(LunchFile, MAX_PATH, "ventoy\\%s", GetFileNameInPath(ExeFileName));
2397
2398 MUTEX_LOCK(g_vtoyins_mutex);
2399 if (IsFileExist("%s", LunchFile))
2400 {
2401 Log("vtoyjump multiple call ...");
2402 rc = 0;
2403 MUTEX_UNLOCK(g_vtoyins_mutex);
2404 goto End;
2405 }
2406
2407 SaveBuffer2File(LunchFile, Buffer + PeStart, FileSize - PeStart);
2408 MUTEX_UNLOCK(g_vtoyins_mutex);
2409
2410 break;
2411 }
2412 }
2413
2414 if (PeStart >= FileSize)
2415 {
2416 Log("OS param not found");
2417 goto End;
2418 }
2419
2420 if (g_os_param_reserved[0] == 2)
2421 {
2422 Log("skip hook for debug .....");
2423 rc = 0;
2424 goto End;
2425 }
2426
2427 rc = VentoyHook(&g_os_param);
2428
2429 End:
2430
2431 if (Buffer)
2432 {
2433 free(Buffer);
2434 }
2435
2436 return rc;
2437 }
2438
2439
2440 int real_main(int argc, char **argv)
2441 {
2442 int i = 0;
2443 int rc = 0;
2444 CHAR NewFile[MAX_PATH];
2445 CHAR LunchFile[MAX_PATH];
2446 CHAR CallParam[1024] = { 0 };
2447 STARTUPINFOA Si;
2448 PROCESS_INFORMATION Pi;
2449
2450 Log("#### real_main #### argc = %d", argc);
2451 Log("program full path: <%s>", g_prog_full_path);
2452 Log("program dir: <%s>", g_prog_dir);
2453 Log("program name:: <%s>", g_prog_name);
2454
2455 Log("argc = %d", argc);
2456 for (i = 0; i < argc; i++)
2457 {
2458 Log("argv[%d]=<%s>", i, argv[i]);
2459 if (i > 0)
2460 {
2461 strcat_s(CallParam, sizeof(CallParam), " ");
2462 strcat_s(CallParam, sizeof(CallParam), argv[i]);
2463 }
2464 }
2465
2466 GetStartupInfoA(&Si);
2467 memset(LunchFile, 0, sizeof(LunchFile));
2468
2469 if (strstr(argv[0], "vtoyjump.exe"))
2470 {
2471 rc = VentoyJumpWimboot(argc, argv, LunchFile);
2472 }
2473 else
2474 {
2475 rc = VentoyJump(argc, argv, LunchFile);
2476 }
2477
2478 Log("LunchFile=<%s> CallParam=<%s>", LunchFile, CallParam);
2479
2480 if (_stricmp(g_prog_name, "winpeshl.exe") != 0 && IsFileExist("ventoy\\%s", g_prog_name))
2481 {
2482 sprintf_s(NewFile, sizeof(NewFile), "%s_BACK.EXE", g_prog_full_path);
2483 MoveFileA(g_prog_full_path, NewFile);
2484 Log("Move <%s> to <%s>", g_prog_full_path, NewFile);
2485
2486 sprintf_s(NewFile, sizeof(NewFile), "ventoy\\%s", g_prog_name);
2487 CopyFileA(NewFile, g_prog_full_path, TRUE);
2488 Log("Copy <%s> to <%s>", NewFile, g_prog_full_path);
2489
2490 sprintf_s(LunchFile, sizeof(LunchFile), "%s", g_prog_full_path);
2491 Log("Final lunchFile is <%s>", LunchFile);
2492 }
2493 else
2494 {
2495 Log("We don't need to recover original <%s>", g_prog_name);
2496 }
2497
2498 if (g_os_param_reserved[0] == 3)
2499 {
2500 Log("Open log for debug ...");
2501 sprintf_s(LunchFile, sizeof(LunchFile), "%s", "notepad.exe ventoy.log");
2502 }
2503 else
2504 {
2505 if (CallParam[0])
2506 {
2507 strcat_s(LunchFile, sizeof(LunchFile), CallParam);
2508 }
2509 else if (NULL == strstr(LunchFile, "setup.exe"))
2510 {
2511 Log("Not setup.exe, hide windows.");
2512 Si.dwFlags |= STARTF_USESHOWWINDOW;
2513 Si.wShowWindow = SW_HIDE;
2514 }
2515
2516 Log("Ventoy jump %s ...", rc == 0 ? "success" : "failed");
2517 }
2518
2519 Log("Now launch <%s> ...", LunchFile);
2520
2521 if (g_os_param_reserved[0] == 4)
2522 {
2523 Log("Open cmd for debug ...");
2524 sprintf_s(LunchFile, sizeof(LunchFile), "%s", "cmd.exe");
2525 }
2526
2527 Log("Backup log at this point");
2528 CopyFileA(LOG_FILE, "X:\\Windows\\ventoy.backup", TRUE);
2529
2530 CreateProcessA(NULL, LunchFile, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
2531
2532 for (i = 0; rc && i < 1800; i++)
2533 {
2534 Log("Ventoy hook failed, now wait and retry ...");
2535 Sleep(1000);
2536 rc = VentoyHook(&g_os_param);
2537 }
2538
2539 Log("Wait process...");
2540 WaitForSingleObject(Pi.hProcess, INFINITE);
2541
2542 Log("vtoyjump finished");
2543 return 0;
2544 }
2545
2546 static void VentoyToUpper(CHAR *str)
2547 {
2548 int i;
2549 for (i = 0; str[i]; i++)
2550 {
2551 str[i] = (CHAR)toupper(str[i]);
2552 }
2553 }
2554
2555 int main(int argc, char **argv)
2556 {
2557 int i;
2558 STARTUPINFOA Si;
2559 PROCESS_INFORMATION Pi;
2560 CHAR CurDir[MAX_PATH];
2561 CHAR NewArgv0[MAX_PATH];
2562 CHAR CallParam[1024] = { 0 };
2563
2564 g_vtoylog_mutex = CreateMutexA(NULL, FALSE, "VTOYLOG_LOCK");
2565 g_vtoyins_mutex = CreateMutexA(NULL, FALSE, "VTOYINS_LOCK");
2566
2567 Log("######## VentoyJump %dbit ##########", g_system_bit);
2568
2569 GetCurrentDirectoryA(sizeof(CurDir), CurDir);
2570 Log("Current directory is <%s>", CurDir);
2571
2572 GetModuleFileNameA(NULL, g_prog_full_path, MAX_PATH);
2573 split_path_name(g_prog_full_path, g_prog_dir, g_prog_name);
2574
2575 Log("EXE path: <%s> dir:<%s> name:<%s>", g_prog_full_path, g_prog_dir, g_prog_name);
2576
2577 if (_stricmp(g_prog_name, "WinLogon.exe") == 0)
2578 {
2579 Log("This time is rejump back ...");
2580
2581 strcpy_s(g_prog_full_path, sizeof(g_prog_full_path), argv[1]);
2582 split_path_name(g_prog_full_path, g_prog_dir, g_prog_name);
2583
2584 return real_main(argc - 1, argv + 1);
2585 }
2586 else if (_stricmp(g_prog_name, "PECMD.exe") == 0)
2587 {
2588 strcpy_s(NewArgv0, sizeof(NewArgv0), g_prog_dir);
2589 VentoyToUpper(NewArgv0);
2590
2591 if (NULL == strstr(NewArgv0, "SYSTEM32") && IsFileExist(ORG_PECMD_BK_PATH))
2592 {
2593 Log("Just call original pecmd.exe");
2594 strcpy_s(CallParam, sizeof(CallParam), ORG_PECMD_PATH);
2595 }
2596 else
2597 {
2598 Log("We need to rejump for pecmd ...");
2599
2600 ventoy_check_create_directory();
2601 CopyFileA(g_prog_full_path, "ventoy\\WinLogon.exe", TRUE);
2602
2603 sprintf_s(CallParam, sizeof(CallParam), "ventoy\\WinLogon.exe %s", g_prog_full_path);
2604 }
2605
2606 for (i = 1; i < argc; i++)
2607 {
2608 strcat_s(CallParam, sizeof(CallParam), " ");
2609 strcat_s(CallParam, sizeof(CallParam), argv[i]);
2610 }
2611
2612 Log("Now rejump to <%s> ...", CallParam);
2613 GetStartupInfoA(&Si);
2614 CreateProcessA(NULL, CallParam, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
2615
2616 Log("Wait rejump process...");
2617 WaitForSingleObject(Pi.hProcess, INFINITE);
2618 Log("rejump finished");
2619 return 0;
2620 }
2621 else
2622 {
2623 Log("We don't need to rejump ...");
2624
2625 strcpy_s(NewArgv0, sizeof(NewArgv0), g_prog_full_path);
2626 argv[0] = NewArgv0;
2627
2628 return real_main(argc, argv);
2629 }
2630 }
2631
2632