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