]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - vtoyjump/vtoyjump/vtoyjump.c
29e1d5ea205b3263425a7738f598bce2d48a47a1
[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 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 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(const char *suffix)
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 //fixed use Z as mountpoint for Lenovo Product Recovery
933 if (strcmp(suffix, "VTLRI") == 0)
934 {
935 return 'Z';
936 }
937
938 Drives = GetLogicalDrives();
939 Log("Drives=0x%x", Drives);
940
941 while (Mask)
942 {
943 if ((Drives & Mask) == 0)
944 {
945 break;
946 }
947
948 Letter--;
949 Mask >>= 1;
950 }
951
952 return Letter;
953 }
954
955 UINT64 GetVentoyEfiPartStartSector(HANDLE hDrive)
956 {
957 BOOL bRet;
958 DWORD dwSize;
959 MBR_HEAD MBR;
960 VTOY_GPT_INFO *pGpt = NULL;
961 UINT64 StartSector = 0;
962
963 SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
964
965 bRet = ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);
966 Log("Read MBR Ret:%u Size:%u code:%u", bRet, dwSize, LASTERR);
967
968 if ((!bRet) || (dwSize != sizeof(MBR)))
969 {
970 0;
971 }
972
973 if (MBR.PartTbl[0].FsFlag == 0xEE)
974 {
975 Log("GPT partition style");
976
977 pGpt = malloc(sizeof(VTOY_GPT_INFO));
978 if (!pGpt)
979 {
980 return 0;
981 }
982
983 SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
984 bRet = ReadFile(hDrive, pGpt, sizeof(VTOY_GPT_INFO), &dwSize, NULL);
985 if ((!bRet) || (dwSize != sizeof(VTOY_GPT_INFO)))
986 {
987 Log("Failed to read gpt info %d %u %d", bRet, dwSize, LASTERR);
988 return 0;
989 }
990
991 StartSector = pGpt->PartTbl[1].StartLBA;
992 free(pGpt);
993 }
994 else
995 {
996 Log("MBR partition style");
997 StartSector = MBR.PartTbl[1].StartSectorId;
998 }
999
1000 Log("GetVentoyEfiPart StartSector: %llu", StartSector);
1001 return StartSector;
1002 }
1003
1004 static int VentoyCopyImdisk(DWORD PhyDrive, CHAR *ImPath)
1005 {
1006 int rc = 1;
1007 BOOL bRet;
1008 DWORD dwBytes;
1009 HANDLE hDrive;
1010 CHAR PhyPath[MAX_PATH];
1011 GET_LENGTH_INFORMATION LengthInfo;
1012
1013 if (IsFileExist("X:\\Windows\\System32\\imdisk.exe"))
1014 {
1015 Log("imdisk.exe already exist, no need to copy...");
1016 strcpy_s(ImPath, MAX_PATH, "imdisk.exe");
1017 return 0;
1018 }
1019
1020 if (IsFileExist("X:\\Windows\\System32\\ventoy\\imdisk.exe"))
1021 {
1022 Log("imdisk.exe already copied, no need to copy...");
1023 strcpy_s(ImPath, MAX_PATH, "ventoy\\imdisk.exe");
1024 return 0;
1025 }
1026
1027 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", PhyDrive);
1028 hDrive = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
1029 if (hDrive == INVALID_HANDLE_VALUE)
1030 {
1031 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
1032 goto End;
1033 }
1034
1035 bRet = DeviceIoControl(hDrive, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &LengthInfo, sizeof(LengthInfo), &dwBytes, NULL);
1036 if (!bRet)
1037 {
1038 Log("Could not get phy disk %s size, error:%u", PhyPath, GetLastError());
1039 goto End;
1040 }
1041
1042 g_FatPhyDrive = hDrive;
1043 g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);
1044
1045 Log("Parse FAT fs...");
1046
1047 fl_init();
1048
1049 if (0 == fl_attach_media(VentoyFatDiskRead, NULL))
1050 {
1051 if (g_system_bit == 64)
1052 {
1053 CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.sys", "ventoy\\imdisk.sys");
1054 CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.exe", "ventoy\\imdisk.exe");
1055 CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.cpl", "ventoy\\imdisk.cpl");
1056 }
1057 else
1058 {
1059 CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.sys", "ventoy\\imdisk.sys");
1060 CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.exe", "ventoy\\imdisk.exe");
1061 CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.cpl", "ventoy\\imdisk.cpl");
1062 }
1063
1064 GetCurrentDirectoryA(sizeof(PhyPath), PhyPath);
1065 strcat_s(PhyPath, sizeof(PhyPath), "\\ventoy\\imdisk.sys");
1066
1067 if (LoadNtDriver(PhyPath) == 0)
1068 {
1069 strcpy_s(ImPath, MAX_PATH, "ventoy\\imdisk.exe");
1070 rc = 0;
1071 }
1072 }
1073 fl_shutdown();
1074
1075 End:
1076
1077 SAFE_CLOSE_HANDLE(hDrive);
1078
1079 return rc;
1080 }
1081
1082 static int VentoyRunImdisk(const char *suffix, const char *IsoPath, const char *imdiskexe, const char *opt)
1083 {
1084 CHAR Letter;
1085 CHAR Cmdline[512];
1086 WCHAR CmdlineW[512];
1087 PROCESS_INFORMATION Pi;
1088
1089 Log("VentoyRunImdisk <%s> <%s> <%s> <%s>", suffix, IsoPath, imdiskexe, opt);
1090
1091 Letter = GetIMDiskMountLogicalDrive(suffix);
1092
1093 sprintf_s(Cmdline, sizeof(Cmdline), "%s -a -o %s -f \"%s\" -m %C:", imdiskexe, opt, IsoPath, Letter);
1094 Log("mount iso to %C: use imdisk cmd <%s>", Letter, Cmdline);
1095
1096 if (IsUTF8Encode(IsoPath))
1097 {
1098 STARTUPINFOW Si;
1099 GetStartupInfoW(&Si);
1100 Si.dwFlags |= STARTF_USESHOWWINDOW;
1101 Si.wShowWindow = SW_HIDE;
1102
1103 Utf8ToUtf16(Cmdline, CmdlineW);
1104 CreateProcessW(NULL, CmdlineW, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
1105
1106 Log("This is UTF8 encoding");
1107 }
1108 else
1109 {
1110 STARTUPINFOA Si;
1111 GetStartupInfoA(&Si);
1112 Si.dwFlags |= STARTF_USESHOWWINDOW;
1113 Si.wShowWindow = SW_HIDE;
1114
1115 CreateProcessA(NULL, Cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
1116
1117 Log("This is ANSI encoding");
1118 }
1119
1120 Log("Wait for imdisk process ...");
1121 WaitForSingleObject(Pi.hProcess, INFINITE);
1122 Log("imdisk process finished");
1123
1124 return 0;
1125 }
1126
1127 int VentoyMountISOByImdisk(const char *IsoPath, DWORD PhyDrive)
1128 {
1129 int rc = 1;
1130 CHAR ImPath[MAX_PATH];
1131
1132 Log("VentoyMountISOByImdisk %s", IsoPath);
1133
1134 if (0 == VentoyCopyImdisk(PhyDrive, ImPath))
1135 {
1136 VentoyRunImdisk("iso", IsoPath, ImPath, "ro");
1137 rc = 0;
1138 }
1139
1140 return rc;
1141 }
1142
1143 static int GetIsoId(CONST CHAR *IsoPath, IsoId *ids)
1144 {
1145 int i;
1146 int n = 0;
1147 HANDLE hFile;
1148 DWORD dwSize = 0;
1149 BOOL bRet[8];
1150
1151 hFile = CreateFileA(IsoPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
1152 if (hFile == INVALID_HANDLE_VALUE)
1153 {
1154 return 1;
1155 }
1156
1157 SetFilePointer(hFile, 2048 * 16 + 8, NULL, FILE_BEGIN);
1158 bRet[n++] = ReadFile(hFile, ids->SystemId, 32, &dwSize, NULL);
1159
1160 SetFilePointer(hFile, 2048 * 16 + 40, NULL, FILE_BEGIN);
1161 bRet[n++] = ReadFile(hFile, ids->VolumeId, 32, &dwSize, NULL);
1162
1163 SetFilePointer(hFile, 2048 * 16 + 318, NULL, FILE_BEGIN);
1164 bRet[n++] = ReadFile(hFile, ids->PulisherId, 128, &dwSize, NULL);
1165
1166 SetFilePointer(hFile, 2048 * 16 + 446, NULL, FILE_BEGIN);
1167 bRet[n++] = ReadFile(hFile, ids->PreparerId, 128, &dwSize, NULL);
1168
1169 CloseHandle(hFile);
1170
1171
1172 for (i = 0; i < n; i++)
1173 {
1174 if (bRet[i] == FALSE)
1175 {
1176 return 1;
1177 }
1178 }
1179
1180
1181 TrimString(ids->SystemId, FALSE);
1182 TrimString(ids->VolumeId, FALSE);
1183 TrimString(ids->PulisherId, FALSE);
1184 TrimString(ids->PreparerId, FALSE);
1185
1186 Log("ISO ID: System<%s> Volume<%s> Pulisher<%s> Preparer<%s>",
1187 ids->SystemId, ids->VolumeId, ids->PulisherId, ids->PreparerId);
1188
1189 return 0;
1190 }
1191
1192 static int CheckSkipMountIso(CONST CHAR *IsoPath)
1193 {
1194 BOOL InRoot = FALSE;
1195 int slashcnt = 0;
1196 CONST CHAR *p = NULL;
1197 IsoId ID;
1198
1199 // C:\\xxx
1200 for (p = IsoPath; *p; p++)
1201 {
1202 if (*p == '\\' || *p == '/')
1203 {
1204 slashcnt++;
1205 }
1206 }
1207
1208 if (slashcnt == 2)
1209 {
1210 InRoot = TRUE;
1211 }
1212
1213 memset(&ID, 0, sizeof(ID));
1214 if (GetIsoId(IsoPath, &ID))
1215 {
1216 return 0;
1217 }
1218
1219 //Bob.Ombs.Modified.Win10PEx64.iso will auto find ISO file in root, so we can skip the mount
1220 if (InRoot && strcmp(ID.VolumeId, "Modified-Win10PEx64") == 0)
1221 {
1222 return 1;
1223 }
1224
1225 return 0;
1226 }
1227
1228 static int MountIsoFile(CONST CHAR *IsoPath, DWORD PhyDrive)
1229 {
1230 if (CheckSkipMountIso(IsoPath))
1231 {
1232 Log("Skip mount ISO file for <%s>", IsoPath);
1233 return 0;
1234 }
1235
1236 if (IsWindows8OrGreater())
1237 {
1238 Log("This is Windows 8 or latter...");
1239 if (VentoyMountISOByAPI(IsoPath) == 0)
1240 {
1241 Log("Mount iso by API success");
1242 return 0;
1243 }
1244 else
1245 {
1246 Log("Mount iso by API failed, maybe not supported, try imdisk");
1247 return VentoyMountISOByImdisk(IsoPath, PhyDrive);
1248 }
1249 }
1250 else
1251 {
1252 Log("This is before Windows 8 ...");
1253 if (VentoyMountISOByImdisk(IsoPath, PhyDrive) == 0)
1254 {
1255 Log("Mount iso by imdisk success");
1256 return 0;
1257 }
1258 else
1259 {
1260 return VentoyMountISOByAPI(IsoPath);
1261 }
1262 }
1263 }
1264
1265 static int GetPhyDriveByLogicalDrive(int DriveLetter)
1266 {
1267 BOOL Ret;
1268 DWORD dwSize;
1269 HANDLE Handle;
1270 VOLUME_DISK_EXTENTS DiskExtents;
1271 CHAR PhyPath[128];
1272
1273 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", (CHAR)DriveLetter);
1274
1275 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
1276 if (Handle == INVALID_HANDLE_VALUE)
1277 {
1278 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
1279 return -1;
1280 }
1281
1282 Ret = DeviceIoControl(Handle,
1283 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
1284 NULL,
1285 0,
1286 &DiskExtents,
1287 (DWORD)(sizeof(DiskExtents)),
1288 (LPDWORD)&dwSize,
1289 NULL);
1290
1291 if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
1292 {
1293 Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed %s, error:%u", PhyPath, GetLastError());
1294 SAFE_CLOSE_HANDLE(Handle);
1295 return -1;
1296 }
1297 SAFE_CLOSE_HANDLE(Handle);
1298
1299 Log("LogicalDrive:%s PhyDrive:%d Offset:%llu ExtentLength:%llu",
1300 PhyPath,
1301 DiskExtents.Extents[0].DiskNumber,
1302 DiskExtents.Extents[0].StartingOffset.QuadPart,
1303 DiskExtents.Extents[0].ExtentLength.QuadPart
1304 );
1305
1306 return (int)DiskExtents.Extents[0].DiskNumber;
1307 }
1308
1309
1310 static int DeleteVentoyPart2MountPoint(DWORD PhyDrive)
1311 {
1312 CHAR Letter = 'A';
1313 DWORD Drives;
1314 DWORD PhyDisk;
1315 CHAR DriveName[] = "?:\\";
1316
1317 Log("DeleteVentoyPart2MountPoint Phy%u ...", PhyDrive);
1318
1319 Drives = GetLogicalDrives();
1320 while (Drives)
1321 {
1322 if ((Drives & 0x01) && IsFileExist("%C:\\ventoy\\ventoy.cpio", Letter))
1323 {
1324 Log("File %C:\\ventoy\\ventoy.cpio exist", Letter);
1325
1326 PhyDisk = GetPhyDriveByLogicalDrive(Letter);
1327 Log("PhyDisk=%u for %C", PhyDisk, Letter);
1328
1329 if (PhyDisk == PhyDrive)
1330 {
1331 DriveName[0] = Letter;
1332 DeleteVolumeMountPointA(DriveName);
1333 return 0;
1334 }
1335 }
1336
1337 Letter++;
1338 Drives >>= 1;
1339 }
1340
1341 return 1;
1342 }
1343
1344 static BOOL check_tar_archive(const char *archive, CHAR *tarName)
1345 {
1346 int len;
1347 int nameLen;
1348 const char *pos = archive;
1349 const char *slash = archive;
1350
1351 while (*pos)
1352 {
1353 if (*pos == '\\' || *pos == '/')
1354 {
1355 slash = pos;
1356 }
1357 pos++;
1358 }
1359
1360 len = (int)strlen(slash);
1361
1362 if (len > 7 && (strncmp(slash + len - 7, ".tar.gz", 7) == 0 || strncmp(slash + len - 7, ".tar.xz", 7) == 0))
1363 {
1364 nameLen = (int)sprintf_s(tarName, MAX_PATH, "X:%s", slash);
1365 tarName[nameLen - 3] = 0;
1366 return TRUE;
1367 }
1368 else if (len > 8 && strncmp(slash + len - 8, ".tar.bz2", 8) == 0)
1369 {
1370 nameLen = (int)sprintf_s(tarName, MAX_PATH, "X:%s", slash);
1371 tarName[nameLen - 4] = 0;
1372 return TRUE;
1373 }
1374 else if (len > 9 && strncmp(slash + len - 9, ".tar.lzma", 9) == 0)
1375 {
1376 nameLen = (int)sprintf_s(tarName, MAX_PATH, "X:%s", slash);
1377 tarName[nameLen - 5] = 0;
1378 return TRUE;
1379 }
1380
1381 return FALSE;
1382 }
1383
1384 static UCHAR *g_unxz_buffer = NULL;
1385 static int g_unxz_len = 0;
1386
1387 static void unxz_error(char *x)
1388 {
1389 Log("%s", x);
1390 }
1391
1392 static int unxz_flush(void *src, unsigned int size)
1393 {
1394 memcpy(g_unxz_buffer + g_unxz_len, src, size);
1395 g_unxz_len += (int)size;
1396
1397 return (int)size;
1398 }
1399
1400 static int DecompressInjectionArchive(const char *archive, DWORD PhyDrive)
1401 {
1402 int rc = 1;
1403 int writelen = 0;
1404 UCHAR *Buffer = NULL;
1405 UCHAR *RawBuffer = NULL;
1406 BOOL bRet;
1407 DWORD dwBytes;
1408 DWORD dwSize;
1409 HANDLE hDrive;
1410 HANDLE hOut;
1411 DWORD flags = CREATE_NO_WINDOW;
1412 CHAR StrBuf[MAX_PATH];
1413 CHAR tarName[MAX_PATH];
1414 STARTUPINFOA Si;
1415 PROCESS_INFORMATION Pi;
1416 PROCESS_INFORMATION NewPi;
1417 GET_LENGTH_INFORMATION LengthInfo;
1418 SECURITY_ATTRIBUTES Sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
1419
1420 Log("DecompressInjectionArchive %s", archive);
1421
1422 sprintf_s(StrBuf, sizeof(StrBuf), "\\\\.\\PhysicalDrive%d", PhyDrive);
1423 hDrive = CreateFileA(StrBuf, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
1424 if (hDrive == INVALID_HANDLE_VALUE)
1425 {
1426 Log("Could not open the disk<%s>, error:%u", StrBuf, GetLastError());
1427 goto End;
1428 }
1429
1430 bRet = DeviceIoControl(hDrive, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &LengthInfo, sizeof(LengthInfo), &dwBytes, NULL);
1431 if (!bRet)
1432 {
1433 Log("Could not get phy disk %s size, error:%u", StrBuf, GetLastError());
1434 goto End;
1435 }
1436
1437 g_FatPhyDrive = hDrive;
1438 g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);
1439
1440 Log("Parse FAT fs...");
1441
1442 fl_init();
1443
1444 if (0 == fl_attach_media(VentoyFatDiskRead, NULL))
1445 {
1446 if (g_system_bit == 64)
1447 {
1448 CopyFileFromFatDisk("/ventoy/7z/64/7za.xz", "ventoy\\7za.xz");
1449 }
1450 else
1451 {
1452 CopyFileFromFatDisk("/ventoy/7z/32/7za.xz", "ventoy\\7za.xz");
1453 }
1454
1455 ReadWholeFile2Buf("ventoy\\7za.xz", &Buffer, &dwSize);
1456 Log("7za.xz file size:%u", dwSize);
1457
1458 RawBuffer = malloc(SIZE_1MB * 4);
1459 if (RawBuffer)
1460 {
1461 g_unxz_buffer = RawBuffer;
1462 g_unxz_len = 0;
1463 unxz(Buffer, (int)dwSize, NULL, unxz_flush, NULL, &writelen, unxz_error);
1464 if (writelen == (int)dwSize)
1465 {
1466 Log("Decompress success 7za.xz(%u) ---> 7za.exe(%d)", dwSize, g_unxz_len);
1467 }
1468 else
1469 {
1470 Log("Decompress failed 7za.xz(%u) ---> 7za.exe(%u)", dwSize, dwSize);
1471 }
1472
1473 SaveBuffer2File("ventoy\\7za.exe", RawBuffer, (DWORD)g_unxz_len);
1474
1475 g_unxz_buffer = NULL;
1476 g_unxz_len = 0;
1477 free(RawBuffer);
1478 }
1479 else
1480 {
1481 Log("Failed to alloc 4MB memory");
1482 }
1483
1484 sprintf_s(StrBuf, sizeof(StrBuf), "ventoy\\7za.exe x -y -aoa -oX:\\ %s", archive);
1485
1486 Log("extract inject to X:");
1487 Log("cmdline:<%s>", StrBuf);
1488
1489 GetStartupInfoA(&Si);
1490
1491 hOut = CreateFileA("ventoy\\7z.log",
1492 FILE_APPEND_DATA,
1493 FILE_SHARE_WRITE | FILE_SHARE_READ,
1494 &Sa,
1495 OPEN_ALWAYS,
1496 FILE_ATTRIBUTE_NORMAL,
1497 NULL);
1498
1499 Si.dwFlags |= STARTF_USESTDHANDLES;
1500
1501 if (hOut != INVALID_HANDLE_VALUE)
1502 {
1503 Si.hStdError = hOut;
1504 Si.hStdOutput = hOut;
1505 }
1506
1507 CreateProcessA(NULL, StrBuf, NULL, NULL, TRUE, flags, NULL, NULL, &Si, &Pi);
1508 WaitForSingleObject(Pi.hProcess, INFINITE);
1509
1510 //
1511 // decompress tar archive, for tar.gz/tar.xz/tar.bz2
1512 //
1513 if (check_tar_archive(archive, tarName))
1514 {
1515 Log("Decompress tar archive...<%s>", tarName);
1516
1517 sprintf_s(StrBuf, sizeof(StrBuf), "ventoy\\7za.exe x -y -aoa -oX:\\ %s", tarName);
1518
1519 CreateProcessA(NULL, StrBuf, NULL, NULL, TRUE, flags, NULL, NULL, &Si, &NewPi);
1520 WaitForSingleObject(NewPi.hProcess, INFINITE);
1521
1522 Log("Now delete %s", tarName);
1523 DeleteFileA(tarName);
1524 }
1525
1526 SAFE_CLOSE_HANDLE(hOut);
1527 }
1528 fl_shutdown();
1529
1530 End:
1531
1532 SAFE_CLOSE_HANDLE(hDrive);
1533
1534 return rc;
1535 }
1536
1537 static int UnattendNeedVarExpand(const char *script)
1538 {
1539 FILE *fp = NULL;
1540 char szLine[4096];
1541
1542 fopen_s(&fp, script, "r");
1543 if (!fp)
1544 {
1545 return 0;
1546 }
1547
1548 szLine[0] = szLine[4095] = 0;
1549
1550 while (fgets(szLine, sizeof(szLine) - 1, fp))
1551 {
1552 if (strstr(szLine, "$$VT_"))
1553 {
1554 fclose(fp);
1555 return 1;
1556 }
1557
1558 szLine[0] = szLine[4095] = 0;
1559 }
1560
1561 fclose(fp);
1562 return 0;
1563 }
1564
1565 static int ExpandSingleVar(VarDiskInfo *pDiskInfo, int DiskNum, const char *var, char *value, int len)
1566 {
1567 int i;
1568 int index = -1;
1569 UINT64 uiDst = 0;
1570 UINT64 uiDelta = 0;
1571 UINT64 uiMaxSize = 0;
1572 UINT64 uiMaxDelta = ULLONG_MAX;
1573
1574 value[0] = 0;
1575
1576 if (strcmp(var, "VT_WINDOWS_DISK_1ST_NONVTOY") == 0)
1577 {
1578 for (i = 0; i < DiskNum; i++)
1579 {
1580 if (pDiskInfo[i].Capacity > 0 && i != g_vtoy_disk_drive)
1581 {
1582 Log("%s=<PhyDrive%d>", var, i);
1583 sprintf_s(value, len, "%d", i);
1584 return 0;
1585 }
1586 }
1587 }
1588 else if (strcmp(var, "VT_WINDOWS_DISK_1ST_NONUSB") == 0)
1589 {
1590 for (i = 0; i < DiskNum; i++)
1591 {
1592 if (pDiskInfo[i].Capacity > 0 && pDiskInfo[i].BusType != BusTypeUsb)
1593 {
1594 Log("%s=<PhyDrive%d>", var, i);
1595 sprintf_s(value, len, "%d", i);
1596 return 0;
1597 }
1598 }
1599 }
1600 else if (strcmp(var, "VT_WINDOWS_DISK_MAX_SIZE") == 0)
1601 {
1602 for (i = 0; i < DiskNum; i++)
1603 {
1604 if (pDiskInfo[i].Capacity > 0 && pDiskInfo[i].Capacity > uiMaxSize)
1605 {
1606 index = i;
1607 uiMaxSize = pDiskInfo[i].Capacity;
1608 }
1609 }
1610
1611 Log("%s=<PhyDrive%d>", var, index);
1612 sprintf_s(value, len, "%d", index);
1613 }
1614 else if (strncmp(var, "VT_WINDOWS_DISK_CLOSEST_", 24) == 0)
1615 {
1616 uiDst = strtoul(var + 24, NULL, 10);
1617 uiDst = uiDst * (1024ULL * 1024ULL * 1024ULL);
1618
1619 for (i = 0; i < DiskNum; i++)
1620 {
1621 if (pDiskInfo[i].Capacity == 0)
1622 {
1623 continue;
1624 }
1625
1626 if (pDiskInfo[i].Capacity > uiDst)
1627 {
1628 uiDelta = pDiskInfo[i].Capacity - uiDst;
1629 }
1630 else
1631 {
1632 uiDelta = uiDst - pDiskInfo[i].Capacity;
1633 }
1634
1635 if (uiDelta < uiMaxDelta)
1636 {
1637 uiMaxDelta = uiDelta;
1638 index = i;
1639 }
1640 }
1641
1642 Log("%s=<PhyDrive%d>", var, index);
1643 sprintf_s(value, len, "%d", index);
1644 }
1645 else
1646 {
1647 Log("Invalid var name <%s>", var);
1648 sprintf_s(value, len, "$$%s$$", var);
1649 }
1650
1651 if (value[0] == 0)
1652 {
1653 sprintf_s(value, len, "$$%s$$", var);
1654 }
1655
1656 return 0;
1657 }
1658
1659 static int GetRegDwordValue(HKEY Key, LPCSTR SubKey, LPCSTR ValueName, DWORD *pValue)
1660 {
1661 HKEY hKey;
1662 DWORD Type;
1663 DWORD Size;
1664 LSTATUS lRet;
1665 DWORD Value;
1666
1667 lRet = RegOpenKeyExA(Key, SubKey, 0, KEY_QUERY_VALUE, &hKey);
1668 Log("RegOpenKeyExA <%s> Ret:%ld", SubKey, lRet);
1669
1670 if (ERROR_SUCCESS == lRet)
1671 {
1672 Size = sizeof(Value);
1673 lRet = RegQueryValueExA(hKey, ValueName, NULL, &Type, (LPBYTE)&Value, &Size);
1674 Log("RegQueryValueExA <%s> ret:%u Size:%u Value:%u", ValueName, lRet, Size, Value);
1675
1676 *pValue = Value;
1677 RegCloseKey(hKey);
1678
1679 return 0;
1680 }
1681 else
1682 {
1683 return 1;
1684 }
1685 }
1686
1687 static const CHAR * GetBusTypeString(int Type)
1688 {
1689 switch (Type)
1690 {
1691 case BusTypeUnknown: return "unknown";
1692 case BusTypeScsi: return "SCSI";
1693 case BusTypeAtapi: return "Atapi";
1694 case BusTypeAta: return "ATA";
1695 case BusType1394: return "1394";
1696 case BusTypeSsa: return "SSA";
1697 case BusTypeFibre: return "Fibre";
1698 case BusTypeUsb: return "USB";
1699 case BusTypeRAID: return "RAID";
1700 case BusTypeiScsi: return "iSCSI";
1701 case BusTypeSas: return "SAS";
1702 case BusTypeSata: return "SATA";
1703 case BusTypeSd: return "SD";
1704 case BusTypeMmc: return "MMC";
1705 case BusTypeVirtual: return "Virtual";
1706 case BusTypeFileBackedVirtual: return "FileBackedVirtual";
1707 case BusTypeSpaces: return "Spaces";
1708 case BusTypeNvme: return "Nvme";
1709 }
1710 return "unknown";
1711 }
1712
1713 static int GetHumanReadableGBSize(UINT64 SizeBytes)
1714 {
1715 int i;
1716 int Pow2 = 1;
1717 double Delta;
1718 double GB = SizeBytes * 1.0 / 1000 / 1000 / 1000;
1719
1720 if ((SizeBytes % 1073741824) == 0)
1721 {
1722 return (int)(SizeBytes / 1073741824);
1723 }
1724
1725 for (i = 0; i < 12; i++)
1726 {
1727 if (Pow2 > GB)
1728 {
1729 Delta = (Pow2 - GB) / Pow2;
1730 }
1731 else
1732 {
1733 Delta = (GB - Pow2) / Pow2;
1734 }
1735
1736 if (Delta < 0.05)
1737 {
1738 return Pow2;
1739 }
1740
1741 Pow2 <<= 1;
1742 }
1743
1744 return (int)GB;
1745 }
1746
1747 static int EnumerateAllDisk(VarDiskInfo **ppDiskInfo, int *pDiskNum)
1748 {
1749 int i;
1750 DWORD Value;
1751 int DiskNum = 0;
1752 BOOL bRet;
1753 DWORD dwBytes;
1754 VarDiskInfo *pDiskInfo = NULL;
1755 HANDLE Handle = INVALID_HANDLE_VALUE;
1756 CHAR PhyDrive[128];
1757 GET_LENGTH_INFORMATION LengthInfo;
1758 STORAGE_PROPERTY_QUERY Query;
1759 STORAGE_DESCRIPTOR_HEADER DevDescHeader;
1760 STORAGE_DEVICE_DESCRIPTOR *pDevDesc;
1761
1762 if (GetRegDwordValue(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\disk\\Enum", "Count", &Value) == 0)
1763 {
1764 DiskNum = (int)Value;
1765 }
1766 else
1767 {
1768 Log("Failed to read disk count");
1769 return 1;
1770 }
1771
1772 Log("Current phy disk count:%d", DiskNum);
1773 if (DiskNum <= 0)
1774 {
1775 return 1;
1776 }
1777
1778 pDiskInfo = malloc(DiskNum * sizeof(VarDiskInfo));
1779 if (!pDiskInfo)
1780 {
1781 Log("Failed to alloc");
1782 return 1;
1783 }
1784 memset(pDiskInfo, 0, DiskNum * sizeof(VarDiskInfo));
1785
1786 for (i = 0; i < DiskNum; i++)
1787 {
1788 SAFE_CLOSE_HANDLE(Handle);
1789
1790 safe_sprintf(PhyDrive, "\\\\.\\PhysicalDrive%d", i);
1791 Handle = CreateFileA(PhyDrive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
1792 Log("Create file Handle:%p %s status:%u", Handle, PhyDrive, LASTERR);
1793
1794 if (Handle == INVALID_HANDLE_VALUE)
1795 {
1796 continue;
1797 }
1798
1799 bRet = DeviceIoControl(Handle,
1800 IOCTL_DISK_GET_LENGTH_INFO, NULL,
1801 0,
1802 &LengthInfo,
1803 sizeof(LengthInfo),
1804 &dwBytes,
1805 NULL);
1806 if (!bRet)
1807 {
1808 Log("DeviceIoControl IOCTL_DISK_GET_LENGTH_INFO failed error:%u", LASTERR);
1809 continue;
1810 }
1811
1812 Log("PHYSICALDRIVE%d size %llu bytes", i, (ULONGLONG)LengthInfo.Length.QuadPart);
1813
1814 Query.PropertyId = StorageDeviceProperty;
1815 Query.QueryType = PropertyStandardQuery;
1816
1817 bRet = DeviceIoControl(Handle,
1818 IOCTL_STORAGE_QUERY_PROPERTY,
1819 &Query,
1820 sizeof(Query),
1821 &DevDescHeader,
1822 sizeof(STORAGE_DESCRIPTOR_HEADER),
1823 &dwBytes,
1824 NULL);
1825 if (!bRet)
1826 {
1827 Log("DeviceIoControl1 error:%u dwBytes:%u", LASTERR, dwBytes);
1828 continue;
1829 }
1830
1831 if (DevDescHeader.Size < sizeof(STORAGE_DEVICE_DESCRIPTOR))
1832 {
1833 Log("Invalid DevDescHeader.Size:%u", DevDescHeader.Size);
1834 continue;
1835 }
1836
1837 pDevDesc = (STORAGE_DEVICE_DESCRIPTOR *)malloc(DevDescHeader.Size);
1838 if (!pDevDesc)
1839 {
1840 Log("failed to malloc error:%u len:%u", LASTERR, DevDescHeader.Size);
1841 continue;
1842 }
1843
1844 bRet = DeviceIoControl(Handle,
1845 IOCTL_STORAGE_QUERY_PROPERTY,
1846 &Query,
1847 sizeof(Query),
1848 pDevDesc,
1849 DevDescHeader.Size,
1850 &dwBytes,
1851 NULL);
1852 if (!bRet)
1853 {
1854 Log("DeviceIoControl2 error:%u dwBytes:%u", LASTERR, dwBytes);
1855 free(pDevDesc);
1856 continue;
1857 }
1858
1859 pDiskInfo[i].RemovableMedia = pDevDesc->RemovableMedia;
1860 pDiskInfo[i].BusType = pDevDesc->BusType;
1861 pDiskInfo[i].DeviceType = pDevDesc->DeviceType;
1862 pDiskInfo[i].Capacity = LengthInfo.Length.QuadPart;
1863
1864 if (pDevDesc->VendorIdOffset)
1865 {
1866 safe_strcpy(pDiskInfo[i].VendorId, (char *)pDevDesc + pDevDesc->VendorIdOffset);
1867 TrimString(pDiskInfo[i].VendorId, TRUE);
1868 }
1869
1870 if (pDevDesc->ProductIdOffset)
1871 {
1872 safe_strcpy(pDiskInfo[i].ProductId, (char *)pDevDesc + pDevDesc->ProductIdOffset);
1873 TrimString(pDiskInfo[i].ProductId, TRUE);
1874 }
1875
1876 if (pDevDesc->ProductRevisionOffset)
1877 {
1878 safe_strcpy(pDiskInfo[i].ProductRev, (char *)pDevDesc + pDevDesc->ProductRevisionOffset);
1879 TrimString(pDiskInfo[i].ProductRev, TRUE);
1880 }
1881
1882 if (pDevDesc->SerialNumberOffset)
1883 {
1884 safe_strcpy(pDiskInfo[i].SerialNumber, (char *)pDevDesc + pDevDesc->SerialNumberOffset);
1885 TrimString(pDiskInfo[i].SerialNumber, TRUE);
1886 }
1887
1888 free(pDevDesc);
1889 SAFE_CLOSE_HANDLE(Handle);
1890 }
1891
1892 Log("########## DUMP DISK BEGIN ##########");
1893 for (i = 0; i < DiskNum; i++)
1894 {
1895 Log("PhyDrv:%d BusType:%-4s Removable:%u Size:%dGB(%llu) Name:%s %s",
1896 i, GetBusTypeString(pDiskInfo[i].BusType), pDiskInfo[i].RemovableMedia,
1897 GetHumanReadableGBSize(pDiskInfo[i].Capacity), pDiskInfo[i].Capacity,
1898 pDiskInfo[i].VendorId, pDiskInfo[i].ProductId);
1899 }
1900 Log("Ventoy disk is PhyDvr%d", g_vtoy_disk_drive);
1901 Log("########## DUMP DISK END ##########");
1902
1903 *ppDiskInfo = pDiskInfo;
1904 *pDiskNum = DiskNum;
1905 return 0;
1906 }
1907
1908 static int UnattendVarExpand(const char *script, const char *tmpfile)
1909 {
1910 FILE *fp = NULL;
1911 FILE *fout = NULL;
1912 char *start = NULL;
1913 char *end = NULL;
1914 char szLine[4096];
1915 char szValue[256];
1916 int DiskNum = 0;
1917 VarDiskInfo *pDiskInfo = NULL;
1918
1919 Log("UnattendVarExpand ...");
1920
1921 if (EnumerateAllDisk(&pDiskInfo, &DiskNum))
1922 {
1923 Log("Failed to EnumerateAllDisk");
1924 return 1;
1925 }
1926
1927 fopen_s(&fp, script, "r");
1928 if (!fp)
1929 {
1930 free(pDiskInfo);
1931 return 0;
1932 }
1933
1934 fopen_s(&fout, tmpfile, "w+");
1935 if (!fout)
1936 {
1937 fclose(fp);
1938 free(pDiskInfo);
1939 return 0;
1940 }
1941
1942 szLine[0] = szLine[4095] = 0;
1943
1944 while (fgets(szLine, sizeof(szLine) - 1, fp))
1945 {
1946 start = strstr(szLine, "$$VT_");
1947 if (start)
1948 {
1949 end = strstr(start + 5, "$$");
1950 }
1951
1952 if (start && end)
1953 {
1954 *start = 0;
1955 fprintf(fout, "%s", szLine);
1956
1957 *end = 0;
1958 ExpandSingleVar(pDiskInfo, DiskNum, start + 2, szValue, sizeof(szValue) - 1);
1959 fprintf(fout, "%s", szValue);
1960
1961 fprintf(fout, "%s", end + 2);
1962 }
1963 else
1964 {
1965 fprintf(fout, "%s", szLine);
1966 }
1967
1968 szLine[0] = szLine[4095] = 0;
1969 }
1970
1971 fclose(fp);
1972 fclose(fout);
1973 free(pDiskInfo);
1974 return 0;
1975 }
1976
1977 //#define VAR_DEBUG 1
1978
1979 static int CreateUnattendRegKey(const char *file)
1980 {
1981 DWORD dw;
1982 HKEY hKey;
1983 LSTATUS Ret;
1984
1985 #ifndef VAR_DEBUG
1986 Ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "System\\Setup", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dw);
1987 if (ERROR_SUCCESS == Ret)
1988 {
1989 Ret = RegSetValueEx(hKey, "UnattendFile", 0, REG_SZ, file, (DWORD)(strlen(file) + 1));
1990 }
1991 #endif
1992
1993 return 0;
1994 }
1995
1996 static int ProcessUnattendedInstallation(const char *script, DWORD PhyDrive)
1997 {
1998 CHAR Letter;
1999 CHAR DrvLetter;
2000 CHAR TmpFile[MAX_PATH];
2001 CHAR CurDir[MAX_PATH];
2002 CHAR ImPath[MAX_PATH];
2003
2004 Log("Copy unattended XML ...");
2005
2006 GetCurrentDirectory(sizeof(CurDir), CurDir);
2007 Letter = CurDir[0];
2008 if ((Letter >= 'A' && Letter <= 'Z') || (Letter >= 'a' && Letter <= 'z'))
2009 {
2010 Log("Current Drive Letter: %C", Letter);
2011 }
2012 else
2013 {
2014 Letter = 'X';
2015 }
2016
2017 #ifdef VAR_DEBUG
2018 sprintf_s(CurDir, sizeof(CurDir), "%C:\\AutounattendXXX.xml", Letter);
2019 #else
2020 sprintf_s(CurDir, sizeof(CurDir), "%C:\\Unattend.xml", Letter);
2021 #endif
2022
2023 if (UnattendNeedVarExpand(script))
2024 {
2025 sprintf_s(TmpFile, sizeof(TmpFile), "%C:\\__Autounattend", Letter);
2026 UnattendVarExpand(script, TmpFile);
2027
2028 Log("Expand Copy file <%s> --> <%s>", script, CurDir);
2029 CopyFileA(TmpFile, CurDir, FALSE);
2030 }
2031 else
2032 {
2033 Log("No var expand copy file <%s> --> <%s>", script, CurDir);
2034 CopyFileA(script, CurDir, FALSE);
2035 }
2036
2037 VentoyCopyImdisk(PhyDrive, ImPath);
2038 DrvLetter = VentoyGetFirstFreeDriveLetter(FALSE);
2039 VentoyProcessRunCmd("%s -a -s 64M -m %C: -p \"/fs:FAT32 /q /y\"", ImPath, DrvLetter);
2040
2041 Sleep(300);
2042
2043 sprintf_s(TmpFile, sizeof(TmpFile), "%C:\\Unattend.xml", DrvLetter);
2044 if (CopyFileA(CurDir, TmpFile, FALSE))
2045 {
2046 DeleteFileA(CurDir);
2047 Log("Move file <%s> ==> <%s>, use the later as unattend XML", CurDir, TmpFile);
2048 CreateUnattendRegKey(TmpFile);
2049 }
2050 else
2051 {
2052 Log("Failed to copy file <%s> ==> <%s>, use OLD", CurDir, TmpFile);
2053 CreateUnattendRegKey(CurDir);
2054 }
2055
2056 return 0;
2057 }
2058
2059 static int VentoyGetFileVersion(const CHAR *FilePath, UINT16 *pMajor, UINT16 *pMinor, UINT16 *pBuild, UINT16 *pRevision)
2060 {
2061 int ret = 1;
2062 DWORD dwHandle;
2063 DWORD dwSize;
2064 UINT VerLen = 0;
2065 CHAR *Buffer = NULL;
2066 VS_FIXEDFILEINFO* VerInfo = NULL;
2067 UINT16 Major, Minor, Build, Revision;
2068
2069 Log("Get file version for <%s>", FilePath);
2070
2071 dwSize = GetFileVersionInfoSizeA(FilePath, &dwHandle);
2072 if (0 == dwSize)
2073 {
2074 Log("Failed to get file version info size: %u", LASTERR);
2075 goto End;
2076 }
2077
2078 Buffer = malloc(dwSize);
2079 if (!Buffer)
2080 {
2081 Log("malloc failed %u", dwSize);
2082 goto End;
2083 }
2084
2085 if (FALSE == GetFileVersionInfoA(FilePath, dwHandle, dwSize, Buffer))
2086 {
2087 Log("Failed to get file version info : %u", LASTERR);
2088 goto End;
2089 }
2090
2091 if (VerQueryValueA(Buffer, "\\", (LPVOID)&VerInfo, &VerLen) && VerLen != 0)
2092 {
2093 if (VerInfo->dwSignature == VS_FFI_SIGNATURE)
2094 {
2095 Major = HIWORD(VerInfo->dwFileVersionMS);
2096 Minor = LOWORD(VerInfo->dwFileVersionMS);
2097 Build = HIWORD(VerInfo->dwFileVersionLS);
2098 Revision = LOWORD(VerInfo->dwFileVersionLS);
2099
2100 Log("FileVersionze: <%u %u %u %u>", Major, Minor, Build, Revision);
2101
2102 if (Major == 10 && Build > 20000)
2103 {
2104 Major = 11;
2105 }
2106
2107 if (pMajor)
2108 {
2109 *pMajor = Major;
2110 }
2111 if (pMinor)
2112 {
2113 *pMinor = Minor;
2114 }
2115 if (pBuild)
2116 {
2117 *pBuild = Build;
2118 }
2119 if (pRevision)
2120 {
2121 *pRevision = Revision;
2122 }
2123
2124 ret = 0;
2125 }
2126 else
2127 {
2128 Log("Invalid verinfo signature 0x%x", VerInfo->dwSignature);
2129 }
2130 }
2131 else
2132 {
2133 Log("VerQueryValueA failed %u", LASTERR);
2134 }
2135
2136 End:
2137 if (Buffer)
2138 {
2139 free(Buffer);
2140 }
2141
2142 return ret;
2143 }
2144
2145 static BOOL VentoyIsNeedBypass(const char *isofile, const char MntLetter)
2146 {
2147 UINT16 Major;
2148 BOOL bRet = FALSE;
2149 CHAR CheckFile[MAX_PATH];
2150
2151 if (FALSE == IsFileExist("%C:\\sources\\install.wim", MntLetter) &&
2152 FALSE == IsFileExist("%C:\\sources\\install.esd", MntLetter))
2153 {
2154 Log("install.wim/install.esd not exist, this is not a windows install media.");
2155 goto End;
2156 }
2157
2158 if (FALSE == IsFileExist("%C:\\sources\\boot.wim", MntLetter))
2159 {
2160 Log("boot.wim not exist, this is not a windows install media.");
2161 goto End;
2162 }
2163
2164 if (IsFileExist("%C:\\sources\\compatresources.dll", MntLetter))
2165 {
2166 sprintf_s(CheckFile, sizeof(CheckFile), "%C:\\sources\\compatresources.dll", MntLetter);
2167 }
2168 else if (IsFileExist("%C:\\setup.exe", MntLetter))
2169 {
2170 sprintf_s(CheckFile, sizeof(CheckFile), "%C:\\setup.exe", MntLetter);
2171 }
2172 else if (IsFileExist("X:\\setup.exe"))
2173 {
2174 sprintf_s(CheckFile, sizeof(CheckFile), "X:\\setup.exe");
2175 }
2176 else
2177 {
2178 Log("No Check file found");
2179 goto End;
2180 }
2181
2182 if (VentoyGetFileVersion(CheckFile, &Major, NULL, NULL, NULL))
2183 {
2184 goto End;
2185 }
2186
2187 if (Major >= 11)
2188 {
2189 Log("Enable for Windows 11 %u", Major);
2190 bRet = TRUE;
2191 }
2192 else
2193 {
2194 Log("This is not Windows 11, not need to bypass.", Major);
2195 }
2196
2197 End:
2198 return bRet;
2199 }
2200
2201 static int Windows11Bypass(const char *isofile, const char MntLetter, UINT8 Check, UINT8 NRO)
2202 {
2203 int Ret = 1;
2204 HKEY hKey = NULL;
2205 HKEY hSubKey = NULL;
2206 LSTATUS Status;
2207 DWORD dwValue = 1;
2208 DWORD dwSize;
2209
2210 Log("Windows11Bypass for <%s> %C: Check:%u NRO:%u", isofile, MntLetter, Check, NRO);
2211
2212 if (!VentoyIsNeedBypass(isofile, MntLetter))
2213 {
2214 goto End;
2215 }
2216
2217 //Now we really need to bypass windows 11 check. create registry
2218
2219 if (Check)
2220 {
2221 Status = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "System\\Setup", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwSize);
2222 if (ERROR_SUCCESS != Status)
2223 {
2224 Log("Failed to create reg key System\\Setup %u %u", LASTERR, Status);
2225 goto End;
2226 }
2227
2228 Status = RegCreateKeyExA(hKey, "LabConfig", 0, NULL, 0, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hSubKey, &dwSize);
2229 if (ERROR_SUCCESS != Status)
2230 {
2231 Log("Failed to create LabConfig reg %u %u", LASTERR, Status);
2232 goto End;
2233 }
2234
2235 //set reg value
2236 Status += RegSetValueExA(hSubKey, "BypassRAMCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
2237 Status += RegSetValueExA(hSubKey, "BypassTPMCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
2238 Status += RegSetValueExA(hSubKey, "BypassSecureBootCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
2239 Status += RegSetValueExA(hSubKey, "BypassCPUCheck", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
2240
2241 Log("Create bypass check registry %s %u", (Status == ERROR_SUCCESS) ? "SUCCESS" : "FAILED", Status);
2242 }
2243
2244
2245 if (NRO)
2246 {
2247 Status = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwSize);
2248 if (ERROR_SUCCESS != Status)
2249 {
2250 Log("Failed to create reg key SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OOBE %u %u", LASTERR, Status);
2251 goto End;
2252 }
2253
2254 Status = RegCreateKeyExA(hKey, "OOBE", 0, NULL, 0, KEY_SET_VALUE | KEY_QUERY_VALUE | KEY_CREATE_SUB_KEY, NULL, &hSubKey, &dwSize);
2255 if (ERROR_SUCCESS != Status)
2256 {
2257 Log("Failed to create OOBE reg %u %u", LASTERR, Status);
2258 goto End;
2259 }
2260
2261 Status += RegSetValueExA(hSubKey, "BypassNRO", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
2262 Log("Create BypassNRO registry %s %u", (Status == ERROR_SUCCESS) ? "SUCCESS" : "FAILED", Status);
2263
2264 SetupMonNroStart(isofile);
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 STARTUPINFOA Si;
2368 PROCESS_INFORMATION Pi;
2369 CHAR Cmdline[256];
2370 CHAR ImDiskPath[256];
2371
2372 Log("MountVTLRI <%s> %u", ImgPath, PhyDrive);
2373
2374 VentoyCopyImdisk(PhyDrive, ImDiskPath);
2375
2376 VentoyRunImdisk("VTLRI", ImgPath, ImDiskPath, "ro,rem");
2377
2378 CopyFileA(g_prog_full_path, "ventoy\\VTLRISRV.exe", FALSE);
2379
2380 sprintf_s(Cmdline, sizeof(Cmdline), "ventoy\\VTLRISRV.exe VTLRI_SRV %C Z", ImgPath[0]);
2381
2382
2383 GetStartupInfoA(&Si);
2384 Si.dwFlags |= STARTF_USESHOWWINDOW;
2385 Si.wShowWindow = SW_HIDE;
2386 CreateProcessA(NULL, Cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
2387
2388 Log("Process cmdline <%s>", Cmdline);
2389
2390 return 0;
2391 }
2392
2393 static int VentoyHook(ventoy_os_param *param)
2394 {
2395 int i;
2396 int rc;
2397 BOOL find = FALSE;
2398 BOOL vtoyfind = FALSE;
2399 CHAR Letter;
2400 CHAR MntLetter;
2401 CHAR VtoyLetter;
2402 DWORD Drives;
2403 DWORD NewDrives;
2404 DWORD VtoyDiskNum;
2405 UINT32 DiskSig;
2406 UINT32 VtoySig;
2407 DISK_EXTENT DiskExtent;
2408 DISK_EXTENT VtoyDiskExtent;
2409 UINT8 UUID[16];
2410 CHAR IsoPath[MAX_PATH];
2411 CHAR VTLRIPath[MAX_PATH];
2412
2413 Log("VentoyHook Path:<%s>", param->vtoy_img_path);
2414
2415 if (IsUTF8Encode(param->vtoy_img_path))
2416 {
2417 Log("This file is UTF8 encoding");
2418 }
2419
2420 for (i = 0; i < 5; i++)
2421 {
2422 Letter = 'A';
2423 Drives = GetLogicalDrives();
2424 Log("Logic Drives: 0x%x", Drives);
2425
2426 while (Drives)
2427 {
2428 if (Drives & 0x01)
2429 {
2430 sprintf_s(IsoPath, sizeof(IsoPath), "%C:\\%s", Letter, param->vtoy_img_path);
2431 if (IsFileExist("%s", IsoPath))
2432 {
2433 Log("File exist under %C:", Letter);
2434 memset(UUID, 0, sizeof(UUID));
2435 memset(&DiskExtent, 0, sizeof(DiskExtent));
2436 if (GetPhyDiskUUID(Letter, UUID, NULL, &DiskExtent) == 0)
2437 {
2438 if (memcmp(UUID, param->vtoy_disk_guid, 16) == 0)
2439 {
2440 Log("Disk UUID match");
2441 find = TRUE;
2442 break;
2443 }
2444 }
2445 }
2446 else
2447 {
2448 Log("File NOT exist under %C:", Letter);
2449 }
2450 }
2451
2452 Drives >>= 1;
2453 Letter++;
2454 }
2455
2456 if (find)
2457 {
2458 break;
2459 }
2460 else
2461 {
2462 Log("Now wait and retry ...");
2463 Sleep(1000);
2464 }
2465 }
2466
2467 if (find == FALSE)
2468 {
2469 Log("Failed to find ISO file");
2470 return 1;
2471 }
2472
2473 Log("Find ISO file <%s>", IsoPath);
2474
2475 //Find VtoyLetter in Vlnk Mode
2476 if (g_os_param_reserved[6] == 1)
2477 {
2478 memcpy(&VtoySig, g_os_param_reserved + 7, 4);
2479 for (i = 0; i < 5; i++)
2480 {
2481 VtoyLetter = 'A';
2482 Drives = GetLogicalDrives();
2483 Log("Logic Drives: 0x%x VentoySig:%08X", Drives, VtoySig);
2484
2485 while (Drives)
2486 {
2487 if (Drives & 0x01)
2488 {
2489 memset(UUID, 0, sizeof(UUID));
2490 memset(&VtoyDiskExtent, 0, sizeof(VtoyDiskExtent));
2491 DiskSig = 0;
2492 if (GetPhyDiskUUID(VtoyLetter, UUID, &DiskSig, &VtoyDiskExtent) == 0)
2493 {
2494 Log("DiskSig=%08X PartStart=%lld", DiskSig, VtoyDiskExtent.StartingOffset.QuadPart);
2495 if (DiskSig == VtoySig && VtoyDiskExtent.StartingOffset.QuadPart == SIZE_1MB)
2496 {
2497 Log("Ventoy Disk Sig match");
2498 vtoyfind = TRUE;
2499 break;
2500 }
2501 }
2502 }
2503
2504 Drives >>= 1;
2505 VtoyLetter++;
2506 }
2507
2508 if (vtoyfind)
2509 {
2510 Log("Find Ventoy Letter: %C", VtoyLetter);
2511 break;
2512 }
2513 else
2514 {
2515 Log("Now wait and retry ...");
2516 Sleep(1000);
2517 }
2518 }
2519
2520 if (vtoyfind == FALSE)
2521 {
2522 Log("Failed to find ventoy disk");
2523 return 1;
2524 }
2525
2526 VtoyDiskNum = VtoyDiskExtent.DiskNumber;
2527 }
2528 else
2529 {
2530 VtoyLetter = Letter;
2531 Log("No vlnk mode %C", Letter);
2532
2533 VtoyDiskNum = DiskExtent.DiskNumber;
2534 }
2535
2536 if (CheckVentoyDisk(VtoyDiskNum))
2537 {
2538 Log("Disk check OK %C: %u", VtoyLetter, VtoyDiskNum);
2539 }
2540 else
2541 {
2542 Log("Failed to check ventoy disk %u", VtoyDiskNum);
2543 return 1;
2544 }
2545
2546 g_vtoy_disk_drive = VtoyDiskNum;
2547
2548 Drives = GetLogicalDrives();
2549 Log("Drives before mount: 0x%x", Drives);
2550
2551 if (VentoyIsLenovoRecovery(IsoPath, VTLRIPath))
2552 {
2553 Log("This is lenovo recovery image, mount VTLRI file.");
2554 rc = MountVTLRI(VTLRIPath, VtoyDiskNum);
2555 }
2556 else
2557 {
2558 Log("This is normal image, mount ISO file.");
2559 rc = MountIsoFile(IsoPath, VtoyDiskNum);
2560 }
2561
2562 NewDrives = GetLogicalDrives();
2563 Log("Drives after mount: 0x%x (0x%x)", NewDrives, (NewDrives ^ Drives));
2564
2565 MntLetter = 'A';
2566 NewDrives = (NewDrives ^ Drives);
2567 while (NewDrives)
2568 {
2569 if (NewDrives & 0x01)
2570 {
2571 if ((NewDrives >> 1) == 0)
2572 {
2573 Log("The ISO file is mounted at %C:", MntLetter);
2574 }
2575 else
2576 {
2577 Log("Maybe the ISO file is mounted at %C:", MntLetter);
2578 }
2579 break;
2580 }
2581
2582 NewDrives >>= 1;
2583 MntLetter++;
2584 }
2585
2586 Log("Mount ISO FILE: %s", rc == 0 ? "SUCCESS" : "FAILED");
2587
2588 //Windows 11 bypass check
2589 if (g_windows_data.windows11_bypass_check == 1 || g_windows_data.windows11_bypass_nro == 1)
2590 {
2591 Windows11Bypass(IsoPath, MntLetter, g_windows_data.windows11_bypass_check, g_windows_data.windows11_bypass_nro);
2592 }
2593
2594 // for protect
2595 rc = DeleteVentoyPart2MountPoint(VtoyDiskNum);
2596 Log("Delete ventoy mountpoint: %s", rc == 0 ? "SUCCESS" : "NO NEED");
2597
2598 if (g_windows_data.auto_install_script[0])
2599 {
2600 if (IsFileExist("%s", VTOY_AUTO_FILE))
2601 {
2602 Log("use auto install script %s...", VTOY_AUTO_FILE);
2603 ProcessUnattendedInstallation(VTOY_AUTO_FILE, VtoyDiskNum);
2604 }
2605 else
2606 {
2607 Log("auto install script %s not exist", IsoPath);
2608 }
2609 }
2610 else
2611 {
2612 Log("auto install no need");
2613 }
2614
2615 if (g_windows_data.injection_archive[0])
2616 {
2617 sprintf_s(IsoPath, sizeof(IsoPath), "%C:%s", VtoyLetter, g_windows_data.injection_archive);
2618 if (IsFileExist("%s", IsoPath))
2619 {
2620 Log("decompress injection archive %s...", IsoPath);
2621 DecompressInjectionArchive(IsoPath, VtoyDiskNum);
2622
2623 if (IsFileExist("%s", AUTO_RUN_BAT))
2624 {
2625 HANDLE hOut;
2626 DWORD flags = CREATE_NO_WINDOW;
2627 CHAR StrBuf[1024];
2628 STARTUPINFOA Si;
2629 PROCESS_INFORMATION Pi;
2630 SECURITY_ATTRIBUTES Sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
2631
2632 Log("%s exist, now run it...", AUTO_RUN_BAT);
2633
2634 GetStartupInfoA(&Si);
2635
2636 hOut = CreateFileA(AUTO_RUN_LOG,
2637 FILE_APPEND_DATA,
2638 FILE_SHARE_WRITE | FILE_SHARE_READ,
2639 &Sa,
2640 OPEN_ALWAYS,
2641 FILE_ATTRIBUTE_NORMAL,
2642 NULL);
2643
2644 Si.dwFlags |= STARTF_USESTDHANDLES;
2645 if (hOut != INVALID_HANDLE_VALUE)
2646 {
2647 Si.hStdError = hOut;
2648 Si.hStdOutput = hOut;
2649 }
2650
2651 sprintf_s(IsoPath, sizeof(IsoPath), "%C:\\%s", Letter, param->vtoy_img_path);
2652 sprintf_s(StrBuf, sizeof(StrBuf), "cmd.exe /c %s \"%s\" %C", AUTO_RUN_BAT, IsoPath, MntLetter);
2653 CreateProcessA(NULL, StrBuf, NULL, NULL, TRUE, flags, NULL, NULL, &Si, &Pi);
2654 WaitForSingleObject(Pi.hProcess, INFINITE);
2655
2656 SAFE_CLOSE_HANDLE(hOut);
2657 }
2658 else
2659 {
2660 Log("%s not exist...", AUTO_RUN_BAT);
2661 }
2662 }
2663 else
2664 {
2665 Log("injection archive %s not exist", IsoPath);
2666 }
2667 }
2668 else
2669 {
2670 Log("no injection archive found");
2671 }
2672
2673 return 0;
2674 }
2675
2676 static int ExtractWindowsDataFile(char *databuf)
2677 {
2678 int len = 0;
2679 char *filedata = NULL;
2680 ventoy_windows_data *pdata = (ventoy_windows_data *)databuf;
2681
2682 Log("ExtractWindowsDataFile: auto install <%s:%d>", pdata->auto_install_script, pdata->auto_install_len);
2683
2684 filedata = databuf + sizeof(ventoy_windows_data);
2685
2686 if (pdata->auto_install_script[0] && pdata->auto_install_len > 0)
2687 {
2688 SaveBuffer2File(VTOY_AUTO_FILE, filedata, pdata->auto_install_len);
2689 filedata += pdata->auto_install_len;
2690 len = pdata->auto_install_len;
2691 }
2692
2693 return len;
2694 }
2695
2696 static int ventoy_check_create_directory(void)
2697 {
2698 if (IsDirExist("ventoy"))
2699 {
2700 Log("ventoy directory already exist");
2701 }
2702 else
2703 {
2704 Log("ventoy directory not exist, now create it.");
2705 if (!CreateDirectoryA("ventoy", NULL))
2706 {
2707 Log("Failed to create ventoy directory err:%u", GetLastError());
2708 return 1;
2709 }
2710 }
2711
2712 return 0;
2713 }
2714
2715 int VentoyJump(INT argc, CHAR **argv, CHAR *LunchFile)
2716 {
2717 int rc = 1;
2718 int stat = 0;
2719 int exlen = 0;
2720 DWORD Pos;
2721 DWORD PeStart;
2722 DWORD FileSize;
2723 DWORD LockStatus = 0;
2724 BYTE *Buffer = NULL;
2725 CHAR ExeFileName[MAX_PATH];
2726
2727 sprintf_s(ExeFileName, sizeof(ExeFileName), "%s", argv[0]);
2728 if (!IsFileExist("%s", ExeFileName))
2729 {
2730 Log("File %s NOT exist, now try %s.exe", ExeFileName, ExeFileName);
2731 sprintf_s(ExeFileName, sizeof(ExeFileName), "%s.exe", argv[0]);
2732
2733 Log("File %s exist ? %s", ExeFileName, IsFileExist("%s", ExeFileName) ? "YES" : "NO");
2734 }
2735
2736 if (ReadWholeFile2Buf(ExeFileName, (void **)&Buffer, &FileSize))
2737 {
2738 goto End;
2739 }
2740
2741 Log("VentoyJump %dbit", g_system_bit);
2742
2743 MUTEX_LOCK(g_vtoyins_mutex);
2744 stat = ventoy_check_create_directory();
2745 MUTEX_UNLOCK(g_vtoyins_mutex);
2746
2747 if (stat != 0)
2748 {
2749 goto End;
2750 }
2751
2752 for (PeStart = 0; PeStart < FileSize; PeStart += 16)
2753 {
2754 if (CheckOsParam((ventoy_os_param *)(Buffer + PeStart)) &&
2755 CheckPeHead(Buffer, FileSize, PeStart + sizeof(ventoy_os_param)))
2756 {
2757 Log("Find os pararm at %u", PeStart);
2758
2759 memcpy(&g_os_param, Buffer + PeStart, sizeof(ventoy_os_param));
2760 memcpy(&g_windows_data, Buffer + PeStart + sizeof(ventoy_os_param), sizeof(ventoy_windows_data));
2761 exlen = ExtractWindowsDataFile(Buffer + PeStart + sizeof(ventoy_os_param));
2762 memcpy(g_os_param_reserved, g_os_param.vtoy_reserved, sizeof(g_os_param_reserved));
2763
2764 if (g_os_param_reserved[0] == 1)
2765 {
2766 Log("break here for debug .....");
2767 goto End;
2768 }
2769
2770 // convert / to \\
2771 for (Pos = 0; Pos < sizeof(g_os_param.vtoy_img_path) && g_os_param.vtoy_img_path[Pos]; Pos++)
2772 {
2773 if (g_os_param.vtoy_img_path[Pos] == '/')
2774 {
2775 g_os_param.vtoy_img_path[Pos] = '\\';
2776 }
2777 }
2778
2779 PeStart += sizeof(ventoy_os_param) + sizeof(ventoy_windows_data) + exlen;
2780 sprintf_s(LunchFile, MAX_PATH, "ventoy\\%s", GetFileNameInPath(ExeFileName));
2781
2782 MUTEX_LOCK(g_vtoyins_mutex);
2783 if (IsFileExist("%s", LunchFile))
2784 {
2785 Log("vtoyjump multiple call ...");
2786 rc = 0;
2787 MUTEX_UNLOCK(g_vtoyins_mutex);
2788 goto End;
2789 }
2790
2791 SaveBuffer2File(LunchFile, Buffer + PeStart, FileSize - PeStart);
2792 MUTEX_UNLOCK(g_vtoyins_mutex);
2793
2794 break;
2795 }
2796 }
2797
2798 if (PeStart >= FileSize)
2799 {
2800 Log("OS param not found");
2801 goto End;
2802 }
2803
2804 if (g_os_param_reserved[0] == 2)
2805 {
2806 Log("skip hook for debug .....");
2807 rc = 0;
2808 goto End;
2809 }
2810
2811 rc = VentoyHook(&g_os_param);
2812
2813 End:
2814
2815 if (Buffer)
2816 {
2817 free(Buffer);
2818 }
2819
2820 return rc;
2821 }
2822
2823
2824 int real_main(int argc, char **argv)
2825 {
2826 int i = 0;
2827 int rc = 0;
2828 CHAR NewFile[MAX_PATH];
2829 CHAR LunchFile[MAX_PATH];
2830 CHAR CallParam[1024] = { 0 };
2831 STARTUPINFOA Si;
2832 PROCESS_INFORMATION Pi;
2833
2834 Log("#### real_main #### argc = %d", argc);
2835 Log("program full path: <%s>", g_prog_full_path);
2836 Log("program dir: <%s>", g_prog_dir);
2837 Log("program name: <%s>", g_prog_name);
2838
2839 Log("argc = %d", argc);
2840 for (i = 0; i < argc; i++)
2841 {
2842 Log("argv[%d]=<%s>", i, argv[i]);
2843 if (i > 0)
2844 {
2845 strcat_s(CallParam, sizeof(CallParam), " ");
2846 strcat_s(CallParam, sizeof(CallParam), argv[i]);
2847 }
2848 }
2849
2850 GetStartupInfoA(&Si);
2851 memset(LunchFile, 0, sizeof(LunchFile));
2852
2853 rc = VentoyJump(argc, argv, LunchFile);
2854
2855 Log("LunchFile=<%s> CallParam=<%s>", LunchFile, CallParam);
2856
2857 if (_stricmp(g_prog_name, "winpeshl.exe") != 0 && IsFileExist("ventoy\\%s", g_prog_name))
2858 {
2859 sprintf_s(NewFile, sizeof(NewFile), "%s\\VTOYJUMP.EXE", g_prog_dir);
2860 MoveFileA(g_prog_full_path, NewFile);
2861 Log("Move <%s> to <%s>", g_prog_full_path, NewFile);
2862
2863 sprintf_s(NewFile, sizeof(NewFile), "ventoy\\%s", g_prog_name);
2864 CopyFileA(NewFile, g_prog_full_path, TRUE);
2865 Log("Copy <%s> to <%s>", NewFile, g_prog_full_path);
2866
2867 sprintf_s(LunchFile, sizeof(LunchFile), "%s", g_prog_full_path);
2868 Log("Final lunchFile is <%s>", LunchFile);
2869 }
2870 else
2871 {
2872 Log("We don't need to recover original <%s>", g_prog_name);
2873 }
2874
2875 if (g_os_param_reserved[0] == 3)
2876 {
2877 Log("Open log for debug ...");
2878 sprintf_s(LunchFile, sizeof(LunchFile), "%s", "notepad.exe ventoy.log");
2879 }
2880 else
2881 {
2882 if (CallParam[0])
2883 {
2884 strcat_s(LunchFile, sizeof(LunchFile), CallParam);
2885 }
2886 else if (NULL == strstr(LunchFile, "setup.exe"))
2887 {
2888 Log("Not setup.exe, hide windows.");
2889 Si.dwFlags |= STARTF_USESHOWWINDOW;
2890 Si.wShowWindow = SW_HIDE;
2891 }
2892
2893 Log("Ventoy jump %s ...", rc == 0 ? "success" : "failed");
2894 }
2895
2896 Log("Now launch <%s> ...", LunchFile);
2897
2898 if (g_os_param_reserved[0] == 4)
2899 {
2900 Log("Open cmd for debug ...");
2901 Si.dwFlags |= STARTF_USESHOWWINDOW;
2902 Si.wShowWindow = SW_NORMAL;
2903 sprintf_s(LunchFile, sizeof(LunchFile), "%s", "cmd.exe");
2904 }
2905
2906 Log("Backup log at this point");
2907 CopyFileA(LOG_FILE, "X:\\Windows\\ventoy.backup", TRUE);
2908
2909 CreateProcessA(NULL, LunchFile, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
2910
2911 for (i = 0; rc && i < 1800; i++)
2912 {
2913 Log("Ventoy hook failed, now wait and retry ...");
2914 Sleep(1000);
2915 rc = VentoyHook(&g_os_param);
2916 }
2917
2918 Log("Wait process...");
2919 WaitForSingleObject(Pi.hProcess, INFINITE);
2920
2921 Log("vtoyjump finished");
2922 return 0;
2923 }
2924
2925 static void VentoyToUpper(CHAR *str)
2926 {
2927 int i;
2928 for (i = 0; str[i]; i++)
2929 {
2930 str[i] = (CHAR)toupper(str[i]);
2931 }
2932 }
2933
2934 static int vtoy_remove_duplicate_file(char *File)
2935 {
2936 CHAR szCmd[MAX_PATH];
2937 CHAR NewFile[MAX_PATH];
2938 STARTUPINFOA Si;
2939 PROCESS_INFORMATION Pi;
2940
2941 Log("<1> Copy New file", File);
2942 sprintf_s(NewFile, sizeof(NewFile), "%s_NEW", File);
2943 CopyFileA(File, NewFile, FALSE);
2944
2945 Log("<2> Remove file <%s>", File);
2946 GetStartupInfoA(&Si);
2947 Si.dwFlags |= STARTF_USESHOWWINDOW;
2948 Si.wShowWindow = SW_HIDE;
2949 sprintf_s(szCmd, sizeof(szCmd), "cmd.exe /c del /F /Q %s", File);
2950 CreateProcessA(NULL, szCmd, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
2951 WaitForSingleObject(Pi.hProcess, INFINITE);
2952
2953 Log("<3> Copy back file <%s>", File);
2954 MoveFileA(NewFile, File);
2955
2956 return 0;
2957 }
2958
2959 static int VTLRI_ServiceMain(int argc, char **argv)
2960 {
2961 int n = 0;
2962 DWORD Err;
2963 BOOL bRet = TRUE;
2964 CHAR Drive[16];
2965 CHAR FsType[64];
2966 CHAR Cmdline[256];
2967 PROCESS_INFORMATION Pi;
2968 STARTUPINFOA Si;
2969
2970 //XXX.exe VTLRI_SRV D Z
2971 Log("VTLRI_ServiceMain start %s %s %s ...", argv[0], argv[1], argv[2]);
2972
2973 sprintf_s(Drive, sizeof(Drive), "%C:\\", argv[2][0]);
2974
2975 while (n < 3)
2976 {
2977 bRet = GetVolumeInformationA(Drive, NULL, 0, NULL, NULL, NULL, FsType, sizeof(FsType));
2978 if (bRet)
2979 {
2980 Sleep(400);
2981 }
2982 else
2983 {
2984 Err = LASTERR;
2985 if (Err == ERROR_PATH_NOT_FOUND)
2986 {
2987 Log("%s not found", Drive);
2988 n++;
2989 }
2990 }
2991 }
2992
2993 sprintf_s(Cmdline, sizeof(Cmdline), "ventoy\\imdisk.exe -d -m %C:", argv[3][0]);
2994 Log("Remove disk by <%s>", Cmdline);
2995
2996 GetStartupInfoA(&Si);
2997 Si.dwFlags |= STARTF_USESHOWWINDOW;
2998 Si.wShowWindow = SW_HIDE;
2999
3000 CreateProcessA(NULL, Cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
3001 WaitForSingleObject(Pi.hProcess, INFINITE);
3002 return 0;
3003 }
3004
3005 int main(int argc, char **argv)
3006 {
3007 int i;
3008 STARTUPINFOA Si;
3009 PROCESS_INFORMATION Pi;
3010 CHAR CurDir[MAX_PATH];
3011 CHAR NewArgv0[MAX_PATH];
3012 CHAR CallParam[1024] = { 0 };
3013
3014 g_vtoylog_mutex = CreateMutexA(NULL, FALSE, "VTOYLOG_LOCK");
3015 g_vtoyins_mutex = CreateMutexA(NULL, FALSE, "VTOYINS_LOCK");
3016
3017 Log("######## VentoyJump %dbit ##########", g_system_bit);
3018
3019 if (argc > 1 && strcmp(argv[1], "VTLRI_SRV") == 0)
3020 {
3021 return VTLRI_ServiceMain(argc, argv);
3022 }
3023
3024 GetCurrentDirectoryA(sizeof(CurDir), CurDir);
3025 Log("Current directory is <%s>", CurDir);
3026
3027 GetModuleFileNameA(NULL, g_prog_full_path, MAX_PATH);
3028 split_path_name(g_prog_full_path, g_prog_dir, g_prog_name);
3029
3030 Log("EXE path: <%s> dir:<%s> name:<%s>", g_prog_full_path, g_prog_dir, g_prog_name);
3031
3032 if (IsFileExist(WIMBOOT_FILE))
3033 {
3034 Log("This is wimboot mode ...");
3035 g_wimboot_mode = TRUE;
3036
3037 if (!IsFileExist(WIMBOOT_DONE))
3038 {
3039 vtoy_remove_duplicate_file(g_prog_full_path);
3040 SaveBuffer2File(WIMBOOT_DONE, g_prog_full_path, 1);
3041 }
3042 }
3043 else
3044 {
3045 Log("This is normal mode ...");
3046 }
3047
3048 if (_stricmp(g_prog_name, "WinLogon.exe") == 0)
3049 {
3050 Log("This time is rejump back ...");
3051
3052 strcpy_s(g_prog_full_path, sizeof(g_prog_full_path), argv[1]);
3053 split_path_name(g_prog_full_path, g_prog_dir, g_prog_name);
3054
3055 return real_main(argc - 1, argv + 1);
3056 }
3057 else if (_stricmp(g_prog_name, "PECMD.exe") == 0)
3058 {
3059 strcpy_s(NewArgv0, sizeof(NewArgv0), g_prog_dir);
3060 VentoyToUpper(NewArgv0);
3061
3062 if (NULL == strstr(NewArgv0, "SYSTEM32") && IsFileExist(ORG_PECMD_BK_PATH))
3063 {
3064 Log("Just call original pecmd.exe");
3065 strcpy_s(CallParam, sizeof(CallParam), ORG_PECMD_PATH);
3066 }
3067 else
3068 {
3069 Log("We need to rejump for pecmd ...");
3070
3071 ventoy_check_create_directory();
3072 CopyFileA(g_prog_full_path, "ventoy\\WinLogon.exe", TRUE);
3073
3074 sprintf_s(CallParam, sizeof(CallParam), "ventoy\\WinLogon.exe %s", g_prog_full_path);
3075 }
3076
3077 for (i = 1; i < argc; i++)
3078 {
3079 strcat_s(CallParam, sizeof(CallParam), " ");
3080 strcat_s(CallParam, sizeof(CallParam), argv[i]);
3081 }
3082
3083 Log("Now rejump to <%s> ...", CallParam);
3084 GetStartupInfoA(&Si);
3085 CreateProcessA(NULL, CallParam, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
3086
3087 Log("Wait rejump process...");
3088 WaitForSingleObject(Pi.hProcess, INFINITE);
3089 Log("rejump finished");
3090 return 0;
3091 }
3092 else
3093 {
3094 Log("We don't need to rejump ...");
3095
3096 ventoy_check_create_directory();
3097 strcpy_s(NewArgv0, sizeof(NewArgv0), g_prog_full_path);
3098 argv[0] = NewArgv0;
3099
3100 return real_main(argc, argv);
3101 }
3102 }