[ros-dev] [ros-diffs] [hbelusca] 74550: [USETUP]: Continue implementing the NT OS installation detector. What remains to be done here, besides cleaning up the code from temporary comments and DPRINTs (and fixing potenti...
Thomas Faber
thomas.faber at reactos.org
Tue May 16 08:05:17 UTC 2017
Hi again,
some comments inline.
On 2017-05-15 03:59, hbelusca at svn.reactos.org wrote:
> --- branches/setup_improvements/base/setup/usetup/osdetect.c [iso-8859-1] (original)
> +++ branches/setup_improvements/base/setup/usetup/osdetect.c [iso-8859-1] Mon May 15 01:59:28 2017
> @@ -19,6 +19,9 @@
> /* GLOBALS ******************************************************************/
>
> extern PPARTLIST PartitionList;
> +
> +/* Language-independent Vendor strings */
> +static const PCWSTR KnownVendors[] = { L"ReactOS", L"Microsoft" };
>
>
> /* VERSION RESOURCE API ******************************************************/
> @@ -361,36 +364,331 @@
>
> #endif
>
> +
> +/***
> +*wchar_t *wcsstr(string1, string2) - search for string2 in string1
> +* (wide strings)
Copypasta?
> +*
> +*Purpose:
> +* finds the first occurrence of string2 in string1 (wide strings)
> +*
> +*Entry:
> +* wchar_t *string1 - string to search in
> +* wchar_t *string2 - string to search for
> +*
> +*Exit:
> +* returns a pointer to the first occurrence of string2 in
> +* string1, or NULL if string2 does not occur in string1
> +*
> +*Uses:
> +*
> +*Exceptions:
> +*
> +*******************************************************************************/
> +PWSTR FindSubStrI(PCWSTR str, PCWSTR strSearch)
> +{
> + PWSTR cp = (PWSTR)str;
> + PWSTR s1, s2;
> +
> + if (!*strSearch)
> + return (PWSTR)str;
> +
> + while (*cp)
> + {
> + s1 = cp;
> + s2 = (PWSTR)strSearch;
> +
> + while (*s1 && *s2 && (towupper(*s1) == towupper(*s2)))
> + ++s1, ++s2;
> +
> + if (!*s2)
> + return cp;
> +
> + ++cp;
> + }
> +
> + return NULL;
> +}
> +
> static BOOLEAN
> -IsRecognizedOS(
> +CheckForValidPEAndVendor(
> + IN HANDLE RootDirectory OPTIONAL,
> + IN PCWSTR PathName OPTIONAL,
> + IN PCWSTR FileName, // OPTIONAL
> + IN PCWSTR VendorName // Better would be OUT PCWSTR*, and the function returning NTSTATUS ?
> + )
> +{
> + BOOLEAN Success = FALSE;
> + NTSTATUS Status;
> + HANDLE FileHandle, SectionHandle;
> + // SIZE_T ViewSize;
> + PVOID ViewBase;
> + PVOID VersionBuffer = NULL; // Read-only
> + PVOID pvData = NULL;
> + UINT BufLen = 0;
> +
> + Status = OpenAndMapFile(RootDirectory, PathName, FileName,
> + &FileHandle, &SectionHandle, &ViewBase);
> + if (!NT_SUCCESS(Status))
> + {
> + DPRINT1("Failed to open and map file %wZ, Status 0x%08lx\n", &FileName, Status);
> + return FALSE; // Status;
> + }
> +
> + /* Make sure it's a valid PE file */
> + if (!RtlImageNtHeader(ViewBase))
> + {
> + DPRINT1("File %wZ does not seem to be a valid PE, bail out\n", &FileName);
> + Status = STATUS_INVALID_IMAGE_FORMAT;
> + goto UnmapFile;
> + }
> +
> + /*
> + * Search for a valid executable version and vendor.
> + * NOTE: The module is loaded as a data file, it should be marked as such.
> + */
> + Status = NtGetVersionResource((PVOID)((ULONG_PTR)ViewBase | 1), &VersionBuffer, NULL);
> + if (!NT_SUCCESS(Status))
> + {
> + DPRINT1("Failed to get version resource for file %wZ, Status 0x%08lx\n", &FileName, Status);
> + goto UnmapFile;
> + }
> +
> + Status = NtVerQueryValue(VersionBuffer, L"\\VarFileInfo\\Translation", &pvData, &BufLen);
> + if (NT_SUCCESS(Status))
> + {
> + USHORT wCodePage = 0, wLangID = 0;
> + WCHAR FileInfo[MAX_PATH];
> + UNICODE_STRING Vendor;
> +
> + wCodePage = LOWORD(*(ULONG*)pvData);
> + wLangID = HIWORD(*(ULONG*)pvData);
> +
> + StringCchPrintfW(FileInfo, ARRAYSIZE(FileInfo),
> + L"StringFileInfo\\%04X%04X\\CompanyName",
> + wCodePage, wLangID);
> +
> + Status = NtVerQueryValue(VersionBuffer, FileInfo, &pvData, &BufLen);
> + if (NT_SUCCESS(Status) && pvData)
> + {
> + /* BufLen includes the NULL terminator count */
> + RtlInitEmptyUnicodeString(&Vendor, pvData, BufLen * sizeof(WCHAR));
> + Vendor.Length = Vendor.MaximumLength - sizeof(UNICODE_NULL);
> +
> + DPRINT1("Found version vendor: \"%wZ\" for file %wZ\n", &Vendor, &FileName);
> +
> + Success = !!FindSubStrI(pvData, VendorName);
> + }
> + else
> + {
> + DPRINT1("No version vendor found for file %wZ\n", &FileName);
> + }
> + }
> +
> +UnmapFile:
> + /* Finally, unmap and close the file */
> + UnMapFile(SectionHandle, ViewBase);
> + NtClose(FileHandle);
This seems clumsy. If there's a single function to open and map the
file, why isn't there one function to unmap and close?
> +
> + return Success;
> +}
> +
> +static BOOLEAN
> +IsValidNTOSInstallation(
> + IN HANDLE PartitionHandle,
> + IN PCWSTR SystemRoot)
> +{
> + BOOLEAN Success = FALSE;
> + USHORT i;
> + WCHAR PathBuffer[MAX_PATH];
> +
> + // DoesPathExist(PartitionHandle, SystemRoot, L"System32\\"); etc...
> +
> + /* Check for the existence of \SystemRoot\System32 */
> + StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), L"%s%s", SystemRoot, L"System32\\");
> + if (!DoesPathExist(PartitionHandle, PathBuffer))
> + {
> + // DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &FileName, Status);
You know there's DPRINT for exactly this purpose, right?
> + return FALSE;
> + }
> +
> + /* Check for the existence of \SystemRoot\System32\drivers */
> + StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), L"%s%s", SystemRoot, L"System32\\drivers\\");
> + if (!DoesPathExist(PartitionHandle, PathBuffer))
> + {
> + // DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &FileName, Status);
> + return FALSE;
> + }
> +
> + /* Check for the existence of \SystemRoot\System32\config */
> + StringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer), L"%s%s", SystemRoot, L"System32\\config\\");
> + if (!DoesPathExist(PartitionHandle, PathBuffer))
> + {
> + // DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &FileName, Status);
> + return FALSE;
> + }
> +
> +#if 0
> + /*
> + * Check for the existence of SYSTEM and SOFTWARE hives in \SystemRoot\System32\config
> + * (but we don't check here whether they are actually valid).
> + */
> + if (!DoesFileExist(PartitionHandle, SystemRoot, L"System32\\config\\SYSTEM"))
> + {
> + // DPRINT1("Failed to open file %wZ, Status 0x%08lx\n", &FileName, Status);
> + return FALSE;
> + }
> + if (!DoesFileExist(PartitionHandle, SystemRoot, L"System32\\config\\SOFTWARE"))
> + {
> + // DPRINT1("Failed to open file %wZ, Status 0x%08lx\n", &FileName, Status);
> + return FALSE;
> + }
> +#endif
> +
> + for (i = 0; i < ARRAYSIZE(KnownVendors); ++i)
> + {
> + /* Check for the existence of \SystemRoot\System32\ntoskrnl.exe and verify its version */
> + Success = CheckForValidPEAndVendor(PartitionHandle, SystemRoot, L"System32\\ntoskrnl.exe", KnownVendors[i]);
> +
> + /* OPTIONAL: Check for the existence of \SystemRoot\System32\ntkrnlpa.exe */
> +
> + /* Check for the existence of \SystemRoot\System32\ntdll.dll */
> + Success = CheckForValidPEAndVendor(PartitionHandle, SystemRoot, L"System32\\ntdll.dll", KnownVendors[i]);
> +
> + /* We have found a correct vendor combination */
> + if (Success)
> + break;
> + }
> +
> + return Success;
> +}
> +
> +typedef struct _NTOS_INSTALLATION
> +{
> + LIST_ENTRY ListEntry;
> + ULONG DiskNumber;
> + ULONG PartitionNumber;
> +// Vendor????
> + WCHAR SystemRoot[MAX_PATH];
> +/**/WCHAR InstallationName[MAX_PATH];/**/
> +} NTOS_INSTALLATION, *PNTOS_INSTALLATION;
> +
> +static VOID
> +ListNTOSInstalls(
> + IN PGENERIC_LIST List)
> +{
> + PGENERIC_LIST_ENTRY Entry;
> + PNTOS_INSTALLATION NtOsInstall;
> + ULONG NtOsInstallsCount = GetNumberOfListEntries(List);
> +
> + DPRINT1("There %s %d installation%s detected:\n",
> + NtOsInstallsCount >= 2 ? "are" : "is",
> + NtOsInstallsCount,
> + NtOsInstallsCount >= 2 ? "s" : "");
> +
> + Entry = GetFirstListEntry(List);
> + while (Entry)
> + {
> + NtOsInstall = (PNTOS_INSTALLATION)GetListEntryUserData(Entry);
Casts from PVOID to other pointer types are unnecessary.
Thanks,
Thomas
More information about the Ros-dev
mailing list