688 lines
17 KiB
C
688 lines
17 KiB
C
#include "pch.h"
|
|
#include "loader.h"
|
|
#include <stdlib.h>
|
|
#pragma hdrstop
|
|
|
|
|
|
#define ISNT() (g_VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
#define ISOSR2() (LOWORD(g_VersionInfo.dwBuildNumber) > 1080)
|
|
#define BUILDNUM() (g_VersionInfo.dwBuildNumber)
|
|
|
|
//
|
|
// Global variables defined here
|
|
//
|
|
|
|
//
|
|
// TargetNativeLangID : this is native language ID of running system
|
|
//
|
|
LANGID TargetNativeLangID;
|
|
|
|
//
|
|
// SourceNativeLangID : this is native language ID of new NT you want to install
|
|
//
|
|
LANGID SourceNativeLangID;
|
|
|
|
//
|
|
// g_IsLanguageMatched : if source and target language are matched (or compatible)
|
|
//
|
|
// 1. if SourceNativeLangID == TargetNativeLangID
|
|
//
|
|
// 2. if SourceNativeLangID's alternative ID == TargetNativeLangID
|
|
//
|
|
BOOL g_IsLanguageMatched;
|
|
|
|
typedef struct _tagAltSourceLocale {
|
|
LANGID LangId;
|
|
LANGID AltLangId;
|
|
DWORD MajorOs;
|
|
DWORD MinorOs;
|
|
DWORD ExcludedOs;
|
|
} ALTSOURCELOCALE, *PALTSOURCELOCALE;
|
|
|
|
ALTSOURCELOCALE g_AltSourceLocale [] = {{0x00000C04, 0x00000409, 0x0200, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x0000040D, 0x00000409, 0x0200, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00000401, 0x00000409, 0x0200, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x0000041E, 0x00000409, 0x0200, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00000809, 0x00000409, 0x00FF, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x0000080A, 0x00000C0A, 0x00FF, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x0000040A, 0x00000C0A, 0x0300, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00000425, 0x00000409, 0x00FF, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00000801, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00000c01, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00001001, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00001401, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00001801, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00001c01, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00002001, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00002401, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00002801, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00002c01, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00003001, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00003401, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00003801, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00003c01, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0x00004001, 0x00000401, 0x0001, 0xFFFFFFFF, 0xFFFFFFFF},
|
|
{0, 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}};
|
|
|
|
typedef struct _tagTrustedSourceLocale {
|
|
LANGID LangId;
|
|
DWORD MajorOs;
|
|
DWORD MinorOs;
|
|
DWORD ExcludedOs;
|
|
} TRUSTEDSOURCELOCALE, *PTRUSTEDSOURCELOCALE;
|
|
|
|
TRUSTEDSOURCELOCALE g_TrustedSourceLocale [] = {{0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}};
|
|
|
|
typedef struct _tagOSVERSIONMAJORID {
|
|
PCTSTR Name;
|
|
DWORD MajorId;
|
|
DWORD Platform;
|
|
DWORD Major;
|
|
DWORD Minor;
|
|
} OSVERSIONMAJORID, *POSVERSIONMAJORID;
|
|
|
|
OSVERSIONMAJORID g_OsVersionMajorId [] = {{TEXT("Win95"), 0x0001, 1, 4, 0},
|
|
{TEXT("Win98"), 0x0002, 1, 4, 10},
|
|
{TEXT("WinME"), 0x0004, 1, 4, 90},
|
|
{TEXT("WinNT351"), 0x0100, 2, 3, 51},
|
|
{TEXT("WinNT40"), 0x0200, 2, 4, 0},
|
|
{NULL, 0, 0, 0, 0}};
|
|
|
|
typedef struct _tagOSVERSIONMINORID {
|
|
PCTSTR Name;
|
|
DWORD MajorId;
|
|
DWORD MinorId;
|
|
DWORD Platform;
|
|
DWORD Major;
|
|
DWORD Minor;
|
|
DWORD Build;
|
|
PCTSTR CSDVer;
|
|
} OSVERSIONMINORID, *POSVERSIONMINORID;
|
|
|
|
OSVERSIONMINORID g_OsVersionMinorId [] = {{NULL, 0, 0, 0, 0, 0, 0, NULL}};
|
|
|
|
typedef struct _tagLANGINFO {
|
|
LANGID LangID;
|
|
INT Count;
|
|
} LANGINFO,*PLANGINFO;
|
|
|
|
BOOL
|
|
TrustedDefaultUserLocale (
|
|
LANGID LangID
|
|
);
|
|
|
|
BOOL
|
|
CALLBACK
|
|
EnumLangProc(
|
|
HANDLE hModule, // resource-module handle
|
|
LPCTSTR lpszType, // pointer to resource type
|
|
LPCTSTR lpszName, // pointer to resource name
|
|
WORD wIDLanguage, // resource language identifier
|
|
LONG_PTR lParam // application-defined parameter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback that counts versions stamps.
|
|
|
|
Arguments:
|
|
|
|
Details of version enumerated version stamp. (Ignore.)
|
|
|
|
Return Value:
|
|
|
|
Indirectly thru lParam: count, langID
|
|
|
|
--*/
|
|
{
|
|
PLANGINFO LangInfo;
|
|
|
|
LangInfo = (PLANGINFO) lParam;
|
|
|
|
LangInfo->Count++;
|
|
|
|
//
|
|
// for localized build contains multiple resource,
|
|
// it usually contains 0409 as backup lang.
|
|
//
|
|
// if LangInfo->LangID != 0 means we already assigned an ID to it
|
|
//
|
|
// so when wIDLanguage == 0x409, we keep the one we got from last time
|
|
//
|
|
if ((wIDLanguage == 0x409) && (LangInfo->LangID != 0)) {
|
|
return TRUE;
|
|
}
|
|
|
|
LangInfo->LangID = wIDLanguage;
|
|
|
|
return TRUE; // continue enumeration
|
|
}
|
|
|
|
LANGID
|
|
GetNTDLLNativeLangID (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is designed specifically for getting native lang of ntdll.dll
|
|
|
|
This is not a generic function to get other module's language
|
|
|
|
the assumption is:
|
|
|
|
1. if only one language in resource then return this lang
|
|
|
|
2. if two languages in resource then return non-US language
|
|
|
|
3. if more than two languages, it's invalid in our case, but returns the last one.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
Native lang ID in ntdll.dll
|
|
|
|
--*/
|
|
{
|
|
LPCTSTR Type = (LPCTSTR) RT_VERSION;
|
|
LPCTSTR Name = (LPCTSTR) 1;
|
|
|
|
LANGINFO LangInfo;
|
|
|
|
ZeroMemory(&LangInfo,sizeof(LangInfo));
|
|
|
|
EnumResourceLanguages (
|
|
GetModuleHandle(TEXT("ntdll.dll")),
|
|
Type,
|
|
Name,
|
|
EnumLangProc,
|
|
(LONG_PTR) &LangInfo
|
|
);
|
|
|
|
if ((LangInfo.Count > 2) || (LangInfo.Count < 1) ) {
|
|
//
|
|
// put error log here
|
|
//
|
|
// so far, for NT 3.51, only JPN has two language resources
|
|
}
|
|
|
|
return LangInfo.LangID;
|
|
}
|
|
|
|
BOOL
|
|
IsHongKongVersion (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Try to identify HongKong NT 4.0
|
|
|
|
It based on:
|
|
|
|
NTDLL's language is English and build is 1381 and
|
|
pImmReleaseContext return TRUE
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
Language ID of running system
|
|
|
|
--*/
|
|
{
|
|
HMODULE hMod;
|
|
BOOL bRet=FALSE;
|
|
typedef BOOL (*IMMRELEASECONTEXT) (HWND,HANDLE);
|
|
IMMRELEASECONTEXT pImmReleaseContext;
|
|
|
|
LANGID TmpID = GetNTDLLNativeLangID();
|
|
|
|
if ((g_VersionInfo.dwBuildNumber == 1381) &&
|
|
(TmpID == 0x0409)){
|
|
|
|
hMod = LoadLibrary(TEXT("imm32.dll"));
|
|
|
|
if (hMod) {
|
|
|
|
pImmReleaseContext = (IMMRELEASECONTEXT) GetProcAddress(hMod,"ImmReleaseContext");
|
|
|
|
if (pImmReleaseContext) {
|
|
bRet = pImmReleaseContext(NULL,NULL);
|
|
}
|
|
|
|
FreeLibrary(hMod);
|
|
}
|
|
}
|
|
return (bRet);
|
|
}
|
|
|
|
LANGID
|
|
GetDefaultUserLangID (
|
|
VOID
|
|
)
|
|
{
|
|
LONG dwErr;
|
|
HKEY hkey;
|
|
DWORD dwSize;
|
|
CHAR buffer[512];
|
|
LANGID langid = 0;
|
|
|
|
dwErr = RegOpenKeyEx( HKEY_USERS,
|
|
TEXT(".DEFAULT\\Control Panel\\International"),
|
|
0,
|
|
KEY_READ,
|
|
&hkey );
|
|
|
|
if( dwErr == ERROR_SUCCESS ) {
|
|
|
|
dwSize = sizeof(buffer);
|
|
dwErr = RegQueryValueExA(hkey,
|
|
"Locale",
|
|
NULL, //reserved
|
|
NULL, //type
|
|
buffer,
|
|
&dwSize );
|
|
|
|
if(dwErr == ERROR_SUCCESS) {
|
|
langid = LANGIDFROMLCID(strtoul(buffer,NULL,16));
|
|
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
return langid;
|
|
}
|
|
|
|
LANGID
|
|
GetTargetNativeLangID (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Applies different rules to different platforms
|
|
|
|
NT
|
|
build number <= 1840 : check ntdll's language,
|
|
we scaned all 3.51's ntdll on boneyard\intl,
|
|
it looks like we can trust them.
|
|
build number > 1840 : user MUI language
|
|
|
|
Win9x
|
|
use default user's resource language
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
Language ID of running system
|
|
|
|
--*/
|
|
{
|
|
LONG dwErr;
|
|
HKEY hkey;
|
|
DWORD dwSize;
|
|
CHAR buffer[512];
|
|
LANGID rcLang;
|
|
LANGID langid = 0;
|
|
|
|
|
|
// Find out if we are running on NT or WIN9X
|
|
|
|
if( ISNT() ) {
|
|
|
|
//
|
|
// We're on NT, but which version? GetSystemDefaultUILanguage() was broke until 1840...
|
|
//
|
|
if( g_VersionInfo.dwBuildNumber > 1840 ) {
|
|
FARPROC NT5API;
|
|
|
|
//
|
|
// Use the API to find out our locale.
|
|
//
|
|
|
|
if( NT5API = GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "GetSystemDefaultUILanguage") ) {
|
|
|
|
rcLang = (LANGID)NT5API();
|
|
//
|
|
// need to convert decimal to hex, LANGID to chr.
|
|
//
|
|
langid = rcLang;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// by looking into \\boneyard\intl, almost every ntdll.dll marked correct lang ID
|
|
// so get langID from ntdll.dll
|
|
//
|
|
|
|
langid = GetNTDLLNativeLangID();
|
|
|
|
if (langid == 0x0409) {
|
|
|
|
if (IsHongKongVersion()) {
|
|
|
|
langid = 0x0C04;
|
|
|
|
} else {
|
|
//
|
|
// if default user's locale is in [TrustedDefaultUserLocale]
|
|
//
|
|
// then this is a backdoor for some localized build that its ntdll.dll marked
|
|
//
|
|
// as English but can't be upgrade by US version.
|
|
//
|
|
LANGID DefaultUserLangID = GetDefaultUserLangID();
|
|
|
|
if (DefaultUserLangID &&
|
|
TrustedDefaultUserLocale (DefaultUserLangID)) {
|
|
|
|
langid = DefaultUserLangID;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// We're on Win9x.
|
|
//
|
|
dwErr = RegOpenKeyEx( HKEY_USERS,
|
|
TEXT(".Default\\Control Panel\\desktop\\ResourceLocale"),
|
|
0,
|
|
KEY_READ,
|
|
&hkey );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(buffer);
|
|
dwErr = RegQueryValueExA( hkey,
|
|
"",
|
|
NULL, //reserved
|
|
NULL, //type
|
|
buffer,
|
|
&dwSize );
|
|
|
|
if(dwErr == ERROR_SUCCESS) {
|
|
langid = LANGIDFROMLCID(strtoul(buffer,NULL,16));
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
if ( dwErr != ERROR_SUCCESS ) {
|
|
// Check HKLM\System\CurrentControlSet\Control\Nls\Locale
|
|
|
|
dwErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("System\\CurrentControlSet\\Control\\Nls\\Locale"),
|
|
0,
|
|
KEY_READ,
|
|
&hkey );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
|
|
dwSize = sizeof(buffer);
|
|
dwErr = RegQueryValueExA( hkey,
|
|
"",
|
|
NULL, //reserved
|
|
NULL, //type
|
|
buffer,
|
|
&dwSize );
|
|
|
|
if (dwErr == ERROR_SUCCESS) {
|
|
langid = LANGIDFROMLCID(strtoul(buffer,NULL,16));
|
|
}
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (langid);
|
|
}
|
|
|
|
|
|
LANGID
|
|
GetSourceNativeLangID (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
[DefaultValues]
|
|
Locale = xxxx
|
|
|
|
every localized build has it's own Locale in intl.inf,
|
|
|
|
so we use this value to identify source languag
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Language ID of source
|
|
|
|
--*/
|
|
{
|
|
|
|
// BUGBUG - implement this by reading our own version info.
|
|
|
|
LPCTSTR Type = (LPCTSTR) RT_VERSION;
|
|
LPCTSTR Name = (LPCTSTR) 1;
|
|
|
|
LANGINFO LangInfo;
|
|
|
|
ZeroMemory(&LangInfo,sizeof(LangInfo));
|
|
|
|
EnumResourceLanguages (
|
|
NULL, // our own module
|
|
Type,
|
|
Name,
|
|
EnumLangProc,
|
|
(LONG_PTR) &LangInfo
|
|
);
|
|
|
|
if ((LangInfo.Count > 2) || (LangInfo.Count < 1) ) {
|
|
//
|
|
// put error log here
|
|
//
|
|
// so far, for NT 3.51, only JPN has two language resources
|
|
}
|
|
|
|
return LangInfo.LangID;
|
|
}
|
|
|
|
DWORD
|
|
GetOsMajorId (
|
|
VOID
|
|
)
|
|
{
|
|
POSVERSIONMAJORID p = g_OsVersionMajorId;
|
|
|
|
while (p->Name) {
|
|
if ((p->Platform == g_VersionInfo.dwPlatformId) &&
|
|
(p->Major == g_VersionInfo.dwMajorVersion) &&
|
|
(p->Minor == g_VersionInfo.dwMinorVersion)
|
|
) {
|
|
return p->MajorId;
|
|
}
|
|
p++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
DWORD
|
|
GetOsMinorId (
|
|
VOID
|
|
)
|
|
{
|
|
POSVERSIONMINORID p = g_OsVersionMinorId;
|
|
|
|
while (p->Name) {
|
|
if ((p->Platform == g_VersionInfo.dwPlatformId) &&
|
|
(p->Major == g_VersionInfo.dwMajorVersion) &&
|
|
(p->Minor == g_VersionInfo.dwMinorVersion) &&
|
|
(p->Build == g_VersionInfo.dwBuildNumber) &&
|
|
((p->CSDVer == NULL) || _tcsicmp (p->CSDVer, g_VersionInfo.szCSDVersion))
|
|
) {
|
|
return p->MinorId;
|
|
}
|
|
p++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BOOL
|
|
TrustedDefaultUserLocale (
|
|
LANGID LangID
|
|
)
|
|
{
|
|
PTRUSTEDSOURCELOCALE p = g_TrustedSourceLocale;
|
|
|
|
while (p->LangId) {
|
|
if ((!(p->ExcludedOs & GetOsMinorId ())) &&
|
|
((p->MinorOs & GetOsMinorId ()) || (p->MajorOs & GetOsMajorId ()))
|
|
) {
|
|
return TRUE;
|
|
}
|
|
p++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
CheckLanguageVersion (
|
|
LANGID SourceLangID,
|
|
LANGID TargetLangID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if the language of source NT is same as target NT or ,at least,
|
|
|
|
compatibile
|
|
|
|
Arguments:
|
|
|
|
Inf handle of intl.inf
|
|
|
|
Return Value:
|
|
|
|
TRUE They are same or compatibile
|
|
FALSE They are different
|
|
|
|
--*/
|
|
{
|
|
PALTSOURCELOCALE p = g_AltSourceLocale;
|
|
TCHAR TargetLangIDStr[9];
|
|
|
|
LANGID SrcLANGID;
|
|
LANGID DstLANGID;
|
|
LANGID AltSourceLangID;
|
|
|
|
//
|
|
// If either one is 0, allow the upgrade. This is Windows 2000 Beta3 behavior.
|
|
//
|
|
if (SourceLangID == 0 || TargetLangID == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (SourceLangID == TargetLangID) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// if Src != Dst, then we need to look up inf file to see
|
|
//
|
|
// if we can open a backdoor for Target language
|
|
//
|
|
|
|
//
|
|
// use TargetLangID as key to find alternative SourceLangID
|
|
//
|
|
|
|
while (p->LangId) {
|
|
//
|
|
// Check if we found alternative locale
|
|
//
|
|
AltSourceLangID = LANGIDFROMLCID(p->AltLangId);
|
|
if ((TargetLangID == p->LangId) &&
|
|
(SourceLangID == AltSourceLangID)
|
|
) {
|
|
//
|
|
// We are here if we found alternative source lang,
|
|
//
|
|
// now check the version criteria
|
|
//
|
|
if ((!(p->ExcludedOs & GetOsMinorId ())) &&
|
|
((p->MinorOs & GetOsMinorId ()) || (p->MajorOs & GetOsMajorId ()))
|
|
) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
p++;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
InitLanguageDetection (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize language detection and put the result in 3 global variables
|
|
|
|
SourceNativeLangID - LANGID of Source (NT is going to be installed)
|
|
|
|
TargetNativeLangID - LANGID of Target (OS system which is running)
|
|
|
|
g_IsLanguageMatched - If language is not matched, then blocks upgrade
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE init correctly
|
|
FALSE init failed
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Init Global Variables
|
|
//
|
|
|
|
SourceNativeLangID = GetSourceNativeLangID();
|
|
|
|
TargetNativeLangID = GetTargetNativeLangID();
|
|
|
|
g_IsLanguageMatched = CheckLanguageVersion(SourceNativeLangID,TargetNativeLangID);
|
|
|
|
if (!g_IsLanguageMatched) {
|
|
if (SourceNativeLangID == 0x00000409) {
|
|
// This is a localized system running an English wizard.
|
|
// We want to allow that.
|
|
g_IsLanguageMatched = TRUE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|