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