You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
762 lines
26 KiB
762 lines
26 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
init.c
|
|
|
|
Abstract:
|
|
|
|
This is the initialization module for the INSTALER program.
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 09-Aug-1994
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "instaler.h"
|
|
|
|
#if TRACE_ENABLED
|
|
ULONG EnabledTraceEvents = DBG_MASK_INTERNALERROR |
|
|
DBG_MASK_MEMORYERROR;
|
|
#endif
|
|
|
|
MODULE_INFO ModuleInfo[ MAXIMUM_MODULE_INDEX ] = {
|
|
{L"NTDLL", NULL},
|
|
{L"KERNEL32", NULL},
|
|
{L"ADVAPI32", NULL},
|
|
{L"USER32", NULL}
|
|
};
|
|
|
|
|
|
|
|
API_INFO ApiInfo[ MAXIMUM_API_INDEX ] = {
|
|
{NTDLL_MODULE_INDEX, "NtCreateFile", NULL, NtCreateFileHandler , sizeof( CREATEFILE_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtOpenFile", NULL, NtOpenFileHandler , sizeof( OPENFILE_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtDeleteFile", NULL, NtDeleteFileHandler , sizeof( DELETEFILE_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtSetInformationFile", NULL, NtSetInformationFileHandler , sizeof( SETINFORMATIONFILE_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtQueryAttributesFile", NULL, NtQueryAttributesFileHandler , sizeof( QUERYATTRIBUTESFILE_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtQueryDirectoryFile", NULL, NtQueryDirectoryFileHandler , sizeof( QUERYDIRECTORYFILE_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtCreateKey", NULL, NtCreateKeyHandler , sizeof( CREATEKEY_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtOpenKey", NULL, NtOpenKeyHandler , sizeof( OPENKEY_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtDeleteKey", NULL, NtDeleteKeyHandler , sizeof( DELETEKEY_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtSetValueKey", NULL, NtSetValueKeyHandler , sizeof( SETVALUEKEY_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtDeleteValueKey", NULL, NtDeleteValueKeyHandler , sizeof( DELETEVALUEKEY_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{NTDLL_MODULE_INDEX, "NtClose", NULL, NtCloseHandleHandler , sizeof( CLOSEHANDLE_PARAMETERS ) , sizeof( NTSTATUS )},
|
|
{KERNEL32_MODULE_INDEX, "GetVersion", NULL, GetVersionHandler , 0 , sizeof( DWORD )},
|
|
{KERNEL32_MODULE_INDEX, "GetVersionExW", NULL, GetVersionExWHandler , sizeof( GETVERSIONEXW_PARAMETERS ) , sizeof( BOOL )},
|
|
{KERNEL32_MODULE_INDEX, "SetCurrentDirectoryA", NULL, SetCurrentDirectoryAHandler , sizeof( SETCURRENTDIRECTORYA_PARAMETERS ) , sizeof( BOOL )},
|
|
{KERNEL32_MODULE_INDEX, "SetCurrentDirectoryW", NULL, SetCurrentDirectoryWHandler , sizeof( SETCURRENTDIRECTORYW_PARAMETERS ) , sizeof( BOOL )},
|
|
{KERNEL32_MODULE_INDEX, "WritePrivateProfileStringA", NULL, WritePrivateProfileStringAHandler , sizeof( WRITEPRIVATEPROFILESTRINGA_PARAMETERS ) , sizeof( DWORD )},
|
|
{KERNEL32_MODULE_INDEX, "WritePrivateProfileStringW", NULL, WritePrivateProfileStringWHandler , sizeof( WRITEPRIVATEPROFILESTRINGW_PARAMETERS ) , sizeof( DWORD )},
|
|
{KERNEL32_MODULE_INDEX, "WritePrivateProfileSectionA", NULL, WritePrivateProfileSectionAHandler, sizeof( WRITEPRIVATEPROFILESECTIONA_PARAMETERS ) , sizeof( DWORD )},
|
|
{KERNEL32_MODULE_INDEX, "WritePrivateProfileSectionW", NULL, WritePrivateProfileSectionWHandler, sizeof( WRITEPRIVATEPROFILESECTIONW_PARAMETERS ) , sizeof( DWORD )},
|
|
{KERNEL32_MODULE_INDEX, "GetPrivateProfileStringW", NULL, NULL, 0, sizeof( DWORD )},
|
|
{KERNEL32_MODULE_INDEX, "GetPrivateProfileStringA", NULL, NULL, 0, sizeof( DWORD )},
|
|
{KERNEL32_MODULE_INDEX, "GetPrivateProfileSectionW", NULL, NULL, 0, sizeof( DWORD )},
|
|
{KERNEL32_MODULE_INDEX, "GetPrivateProfileSectionA", NULL, NULL, 0, sizeof( DWORD )},
|
|
{ADVAPI32_MODULE_INDEX, "RegConnectRegistryW", NULL, RegConnectRegistryWHandler , sizeof( REGCONNECTREGISTRYW_PARAMETERS ) , sizeof( DWORD )},
|
|
{USER32_MODULE_INDEX, "ExitWindowsEx", NULL, ExitWindowsExHandler , sizeof( EXITWINDOWSEX_PARAMETERS ) , sizeof( BOOL )}
|
|
};
|
|
|
|
BOOLEAN
|
|
LoadApplicationForDebug(
|
|
PWSTR CommandLine
|
|
);
|
|
|
|
BOOLEAN
|
|
LoadDriveLetterDefinitions( VOID );
|
|
|
|
WCHAR WindowsDirectoryBuffer[ MAX_PATH ];
|
|
UNICODE_STRING WindowsDirectory;
|
|
|
|
BOOLEAN
|
|
InitializeInstaler(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
UINT ModuleIndex, ApiIndex;
|
|
PWSTR CommandLine;
|
|
UINT i;
|
|
LPSTR s;
|
|
UCHAR c;
|
|
SYSTEM_INFO SystemInfo;
|
|
BOOLEAN ProcessingDebugSwitch;
|
|
|
|
InitCommonCode( "INSTALER",
|
|
"[-9] [-r] [-dAE] CommandLine...",
|
|
"-9 specifies that GetVersion should lie and tell application\n"
|
|
" that it is running on Windows 95\n"
|
|
"-r specifies that attempts to do a wildcard scan of the root\n"
|
|
" directory of a drive should fail.\n"
|
|
"-d specifies one or more debugging message options\n"
|
|
" A - shows all errors\n"
|
|
" E - shows all debug events\n"
|
|
" C - shows all create API calls\n"
|
|
);
|
|
|
|
AppHeap = GetProcessHeap();
|
|
InstalerModuleHandle = GetModuleHandle( NULL );
|
|
|
|
if (GetWindowsDirectoryW( WindowsDirectoryBuffer, MAX_PATH ) == 0) {
|
|
return FALSE;
|
|
}
|
|
RtlInitUnicodeString( &WindowsDirectory, WindowsDirectoryBuffer );
|
|
|
|
GetSystemInfo( &SystemInfo );
|
|
|
|
TemporaryBufferLengthGrowth = SystemInfo.dwPageSize;
|
|
TemporaryBufferMaximumLength = ((128 * 1024) + SystemInfo.dwAllocationGranularity - 1) &
|
|
~SystemInfo.dwAllocationGranularity;
|
|
TemporaryBuffer = VirtualAlloc( NULL,
|
|
TemporaryBufferMaximumLength,
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE
|
|
);
|
|
if (TemporaryBuffer == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeListHead( &ProcessListHead );
|
|
InitializeListHead( &FileReferenceListHead );
|
|
InitializeListHead( &KeyReferenceListHead );
|
|
InitializeListHead( &IniReferenceListHead );
|
|
InitializeCriticalSection( &BreakTable );
|
|
|
|
//
|
|
// Loop over the table of modules and make sure each is loaded in our
|
|
// address space so we can access their export tables.
|
|
//
|
|
for (ModuleIndex=0; ModuleIndex<MAXIMUM_MODULE_INDEX; ModuleIndex++) {
|
|
ModuleInfo[ ModuleIndex ].ModuleHandle =
|
|
GetModuleHandle( ModuleInfo[ ModuleIndex ].ModuleName );
|
|
|
|
if (ModuleInfo[ ModuleIndex ].ModuleHandle == NULL) {
|
|
//
|
|
// Bail if any are missing.
|
|
//
|
|
DeclareError( INSTALER_MISSING_MODULE,
|
|
GetLastError(),
|
|
ModuleInfo[ ModuleIndex ].ModuleName
|
|
);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now loop over the table of entry points that we care about and
|
|
// get the address of each entry point from the
|
|
|
|
for (ApiIndex=0; ApiIndex<MAXIMUM_API_INDEX; ApiIndex++) {
|
|
ModuleIndex = ApiInfo[ ApiIndex ].ModuleIndex;
|
|
|
|
ApiInfo[ ApiIndex ].EntryPointAddress =
|
|
LookupEntryPointInIAT( ModuleInfo[ ModuleIndex ].ModuleHandle,
|
|
ApiInfo[ ApiIndex ].EntryPointName
|
|
);
|
|
|
|
if (ApiInfo[ ApiIndex ].EntryPointAddress == NULL) {
|
|
//
|
|
// Bail if we are unable to get the address of any of them
|
|
//
|
|
DeclareError( INSTALER_MISSING_ENTRYPOINT,
|
|
GetLastError(),
|
|
ApiInfo[ ApiIndex ].EntryPointName,
|
|
ModuleInfo[ ModuleIndex ].ModuleName
|
|
);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
CommandLine = NULL;
|
|
ProcessingDebugSwitch = FALSE;
|
|
AskUserOnce = FALSE;
|
|
while (--argc) {
|
|
s = *++argv;
|
|
if (*s == '-' || *s == '/') {
|
|
while (*++s) {
|
|
switch( tolower( *s ) ) {
|
|
case '9':
|
|
DefaultGetVersionToWin95 = TRUE;
|
|
break;
|
|
|
|
case 'r':
|
|
FailAllScansOfRootDirectories = TRUE;
|
|
break;
|
|
#if TRACE_ENABLED
|
|
case 'd':
|
|
ProcessingDebugSwitch = TRUE;
|
|
break;
|
|
|
|
case 'a':
|
|
if (ProcessingDebugSwitch) {
|
|
EnabledTraceEvents = 0xFFFFFFFF;
|
|
break;
|
|
}
|
|
case 'e':
|
|
if (ProcessingDebugSwitch) {
|
|
EnabledTraceEvents |= DBG_MASK_DBGEVENT;
|
|
break;
|
|
}
|
|
case 'c':
|
|
if (ProcessingDebugSwitch) {
|
|
EnabledTraceEvents |= DBG_MASK_CREATEEVENT;
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
if (!ProcessingDebugSwitch) {
|
|
CommonSwitchProcessing( &argc, &argv, *s );
|
|
|
|
} else {
|
|
Usage( "Invalid debug switch (-%c)", (ULONG)*s );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
ProcessingDebugSwitch = FALSE;
|
|
|
|
} else if (!CommonArgProcessing( &argc, &argv )) {
|
|
CommandLine = GetCommandLine();
|
|
while (*CommandLine && *CommandLine <= L' ') {
|
|
CommandLine += 1;
|
|
}
|
|
|
|
while (*CommandLine && *CommandLine > L' ') {
|
|
CommandLine += 1;
|
|
}
|
|
|
|
CommandLine = wcsstr( CommandLine, GetArgAsUnicode( s ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ImlPath == NULL) {
|
|
Usage( "Must specify an installation name as first argument", 0 );
|
|
}
|
|
|
|
if (CommandLine == NULL) {
|
|
Usage( "Command line missing", 0 );
|
|
}
|
|
|
|
pImlNew = CreateIml( ImlPath, FALSE );
|
|
if (pImlNew == NULL) {
|
|
FatalError( "Unable to create %ws (%u)\n",
|
|
(ULONG)ImlPath,
|
|
GetLastError()
|
|
);
|
|
}
|
|
|
|
//
|
|
// Ready to roll. Cache the drive letter information and then load
|
|
// the application with the DEBUG option so we can watch what it does
|
|
//
|
|
if (!LoadDriveLetterDefinitions() ||
|
|
!LoadApplicationForDebug( CommandLine )
|
|
) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
LoadApplicationForDebug(
|
|
PWSTR CommandLine
|
|
)
|
|
{
|
|
STARTUPINFO StartupInfo;
|
|
PROCESS_INFORMATION ProcessInformation;
|
|
PWSTR ImageFilePath;
|
|
PWSTR ImageFileName;
|
|
PWSTR CurrentDirectory;
|
|
PWSTR TemporaryNull;
|
|
WCHAR TemporaryChar;
|
|
ULONG Length;
|
|
WCHAR PathBuffer[ MAX_PATH ];
|
|
|
|
TemporaryNull = CommandLine;
|
|
while(TemporaryChar = *TemporaryNull) {
|
|
if (TemporaryChar == L' ' || TemporaryChar == L'\t') {
|
|
*TemporaryNull = UNICODE_NULL;
|
|
break;
|
|
}
|
|
|
|
TemporaryNull += 1;
|
|
}
|
|
|
|
ImageFilePath = AllocMem( MAX_PATH * sizeof( WCHAR ) );
|
|
Length = SearchPath( NULL,
|
|
CommandLine,
|
|
L".exe",
|
|
MAX_PATH,
|
|
ImageFilePath,
|
|
&ImageFileName
|
|
);
|
|
*TemporaryNull = TemporaryChar;
|
|
if (!Length || Length >= MAX_PATH) {
|
|
DeclareError( INSTALER_CANT_DEBUG_PROGRAM,
|
|
GetLastError(),
|
|
CommandLine
|
|
);
|
|
return FALSE;
|
|
}
|
|
|
|
if (ImageFileName != NULL &&
|
|
ImageFileName > ImageFilePath &&
|
|
ImageFileName[ -1 ] == L'\\'
|
|
) {
|
|
ImageFileName[ -1 ] = UNICODE_NULL;
|
|
CurrentDirectory = wcscpy( PathBuffer, ImageFilePath );
|
|
ImageFileName[ -1 ] = L'\\';
|
|
SetCurrentDirectory( CurrentDirectory );
|
|
|
|
} else {
|
|
CurrentDirectory = NULL;
|
|
}
|
|
|
|
memset( &StartupInfo, 0, sizeof( StartupInfo ) );
|
|
StartupInfo.cb = sizeof(StartupInfo);
|
|
|
|
//
|
|
// Create the process with DEBUG option, as a separate WOW so we only see our
|
|
// application's damage.
|
|
//
|
|
if (!CreateProcess( ImageFilePath,
|
|
CommandLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE, // No handles to inherit
|
|
DEBUG_PROCESS |
|
|
CREATE_SEPARATE_WOW_VDM, // Ignored for 32 bit apps
|
|
NULL,
|
|
CurrentDirectory,
|
|
&StartupInfo,
|
|
&ProcessInformation
|
|
) ) {
|
|
|
|
DeclareError( INSTALER_CANT_DEBUG_PROGRAM,
|
|
GetLastError(),
|
|
CommandLine
|
|
);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// BogdanA 02/19/2002: this is ugly but whatever.
|
|
// Make sure we terminate the Unicode string.
|
|
// Then use it as an ANSI one. Oh well...
|
|
//
|
|
PathBuffer[sizeof(PathBuffer)/sizeof(PathBuffer[0]) - 1] = 0;
|
|
_snprintf( (LPSTR)PathBuffer,
|
|
sizeof(PathBuffer) - 1,
|
|
"%ws%ws.log", InstalerDirectory, InstallationName );
|
|
InstalerLogFile = fopen( (LPSTR)PathBuffer, "w" );
|
|
|
|
//
|
|
// Will pick up the process and thread handles with the
|
|
// CREATE_PROCESS_DEBUG_EVENT and CREATE_PROCESS_THREAD_EVENT
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PVOID
|
|
LookupEntryPointInIAT(
|
|
HMODULE ModuleHandle,
|
|
PCHAR EntryPointName
|
|
)
|
|
{
|
|
PIMAGE_EXPORT_DIRECTORY Exports;
|
|
PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTableEntries;
|
|
DWORD NumberOfFunctionTableEntries;
|
|
ULONG ExportSize, FunctionTableSize;
|
|
PCHAR *EntryPointNames;
|
|
PULONG EntryPointAddresses;
|
|
PUSHORT EntryPointOrdinals;
|
|
PVOID EntryPointAddress;
|
|
ULONG i;
|
|
|
|
Exports = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( ModuleHandle,
|
|
TRUE,
|
|
IMAGE_DIRECTORY_ENTRY_EXPORT,
|
|
&ExportSize
|
|
);
|
|
if (Exports == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
FunctionTableEntries = (PIMAGE_RUNTIME_FUNCTION_ENTRY)
|
|
RtlImageDirectoryEntryToData( ModuleHandle,
|
|
TRUE,
|
|
IMAGE_DIRECTORY_ENTRY_EXCEPTION,
|
|
&FunctionTableSize
|
|
);
|
|
if (FunctionTableEntries != NULL) {
|
|
NumberOfFunctionTableEntries = FunctionTableSize / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY );
|
|
|
|
} else {
|
|
NumberOfFunctionTableEntries = 0;
|
|
}
|
|
|
|
EntryPointNames = (PCHAR *)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfNames);
|
|
EntryPointOrdinals = (PUSHORT)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfNameOrdinals);
|
|
EntryPointAddresses = (PULONG)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfFunctions);
|
|
for (i=0; i<Exports->NumberOfNames; i++) {
|
|
EntryPointAddress = (PVOID)((PCHAR)ModuleHandle +
|
|
EntryPointAddresses[ EntryPointOrdinals[ i ] ]
|
|
);
|
|
if ((ULONG)EntryPointAddress > (ULONG)Exports &&
|
|
(ULONG)EntryPointAddress < ((ULONG)Exports + ExportSize) ) {
|
|
//
|
|
// Skip this... It's a forwarded reference
|
|
//
|
|
|
|
} else if (!_stricmp( EntryPointName, (PCHAR)ModuleHandle + (ULONG)EntryPointNames[ i ] )) {
|
|
return GetAddressForEntryPointBreakpoint( EntryPointAddress,
|
|
NumberOfFunctionTableEntries,
|
|
FunctionTableEntries
|
|
);
|
|
}
|
|
}
|
|
|
|
DbgEvent( INTERNALERROR, ( "Unable to find entry point '%s' in module at %x\n", EntryPointName, ModuleHandle ) );
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PVOID
|
|
GetAddressForEntryPointBreakpoint(
|
|
PVOID EntryPointAddress,
|
|
DWORD NumberOfFunctionTableEntries OPTIONAL,
|
|
PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTableEntries OPTIONAL
|
|
)
|
|
{
|
|
PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry;
|
|
PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTable;
|
|
LONG High;
|
|
LONG Low;
|
|
LONG Middle;
|
|
|
|
//
|
|
// If no function table, then okay to set breakpoint at exported
|
|
// address.
|
|
//
|
|
if (NumberOfFunctionTableEntries == 0) {
|
|
return EntryPointAddress;
|
|
}
|
|
|
|
//
|
|
// Initialize search indicies.
|
|
//
|
|
Low = 0;
|
|
High = NumberOfFunctionTableEntries - 1;
|
|
FunctionTable = FunctionTableEntries;
|
|
|
|
//
|
|
// Perform binary search on the function table for a function table
|
|
// entry that subsumes the specified PC.
|
|
//
|
|
while (High >= Low) {
|
|
//
|
|
// Compute next probe index and test entry. If the specified PC
|
|
// is greater than of equal to the beginning address and less
|
|
// than the ending address of the function table entry, then
|
|
// return the address of the function table entry. Otherwise,
|
|
// continue the search.
|
|
//
|
|
Middle = (Low + High) >> 1;
|
|
FunctionEntry = &FunctionTable[Middle];
|
|
if ((ULONG)EntryPointAddress < FunctionEntry->BeginAddress) {
|
|
High = Middle - 1;
|
|
|
|
} else if ((ULONG)EntryPointAddress >= FunctionEntry->EndAddress) {
|
|
Low = Middle + 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// A function table entry for the specified PC was not found. Just use
|
|
// the exported address and hope for the best.
|
|
//
|
|
return EntryPointAddress;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
LoadDriveLetterDefinitions( VOID )
|
|
{
|
|
PVOID Buffer;
|
|
ULONG BufferSize;
|
|
ULONG cchDeviceName;
|
|
ULONG cch;
|
|
ULONG cchTargetPath;
|
|
PWSTR DeviceName;
|
|
PWSTR TargetPath;
|
|
ULONG DriveLetterIndex;
|
|
ULONG cb;
|
|
PDRIVE_LETTER_INFO p;
|
|
|
|
RtlInitUnicodeString( &AltDriveLetterPrefix, L"\\DosDevices\\" );
|
|
RtlInitUnicodeString( &DriveLetterPrefix, L"\\??\\" );
|
|
RtlInitUnicodeString( &UNCPrefix, L"UNC\\" );
|
|
|
|
BufferSize = 0x1000;
|
|
Buffer = VirtualAlloc( NULL, BufferSize, MEM_COMMIT, PAGE_READWRITE );
|
|
if (Buffer == NULL) {
|
|
DbgEvent( INTERNALERROR, ( "VirtualAlloc( %0x8 ) failed (%u)\n", BufferSize, GetLastError() ) );
|
|
return FALSE;
|
|
}
|
|
|
|
cchTargetPath = BufferSize / sizeof( WCHAR );
|
|
cchDeviceName = QueryDosDeviceW( NULL,
|
|
Buffer,
|
|
cchTargetPath
|
|
);
|
|
if (cchDeviceName == 0) {
|
|
DbgEvent( INTERNALERROR, ( "QueryDosDeviceW( NULL ) failed (%u)\n", GetLastError() ) );
|
|
return FALSE;
|
|
}
|
|
|
|
cchTargetPath -= (cchDeviceName + 2);
|
|
DeviceName = Buffer;
|
|
TargetPath = DeviceName + 2 + cchDeviceName;
|
|
while (*DeviceName) {
|
|
if (wcslen( DeviceName ) == 2 &&
|
|
DeviceName[ 1 ] == L':' &&
|
|
_wcsupr( DeviceName ) &&
|
|
DeviceName[ 0 ] >= L'@' &&
|
|
DeviceName[ 0 ] <= L'_'
|
|
) {
|
|
cch = QueryDosDeviceW( DeviceName, TargetPath, cchTargetPath );
|
|
if (cch == 0) {
|
|
DbgEvent( INTERNALERROR, ( "QueryDosDeviceW( %ws ) failed (%u)\n", DeviceName, GetLastError() ) );
|
|
return FALSE;
|
|
}
|
|
|
|
DriveLetterIndex = DeviceName[ 0 ] - L'@';
|
|
p = &DriveLetters[ DriveLetterIndex ];
|
|
p->DriveLetter = (WCHAR)(L'@' + DriveLetterIndex);
|
|
cb = (cch+1) * sizeof( WCHAR );
|
|
p->NtLinkTarget.Buffer = AllocMem( cb );
|
|
if (p->NtLinkTarget.Buffer == NULL) {
|
|
return FALSE;
|
|
}
|
|
MoveMemory( p->NtLinkTarget.Buffer, TargetPath, cb );
|
|
p->NtLinkTarget.Length = (USHORT)( cb - sizeof( WCHAR ));
|
|
p->NtLinkTarget.MaximumLength = (USHORT)cb;
|
|
p->DriveLetterValid = TRUE;
|
|
}
|
|
|
|
while (*DeviceName++) {}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
IsDriveLetterPath(
|
|
PUNICODE_STRING Path
|
|
)
|
|
{
|
|
ULONG DriveLetterIndex;
|
|
PDRIVE_LETTER_INFO p;
|
|
PUNICODE_STRING Prefix;
|
|
|
|
if (RtlPrefixUnicodeString( Prefix = &DriveLetterPrefix, Path, TRUE ) ||
|
|
RtlPrefixUnicodeString( Prefix = &AltDriveLetterPrefix, Path, TRUE ) ) {
|
|
|
|
Path->Length -= Prefix->Length;
|
|
RtlMoveMemory( Path->Buffer,
|
|
(PCHAR)(Path->Buffer) + Prefix->Length,
|
|
Path->Length + sizeof( UNICODE_NULL )
|
|
);
|
|
if (RtlPrefixUnicodeString( &UNCPrefix, Path, TRUE )) {
|
|
Path->Length -= UNCPrefix.Length;
|
|
Path->Buffer[0] = L'\\';
|
|
Path->Buffer[1] = L'\\';
|
|
RtlMoveMemory( &Path->Buffer[2],
|
|
(PCHAR)(Path->Buffer) + UNCPrefix.Length,
|
|
Path->Length + sizeof( UNICODE_NULL )
|
|
);
|
|
Path->Length += 2 * sizeof( WCHAR );
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
for (DriveLetterIndex=0, p = &DriveLetters[ DriveLetterIndex ];
|
|
DriveLetterIndex<32;
|
|
DriveLetterIndex++, p++
|
|
)
|
|
{
|
|
|
|
if (p->DriveLetterValid &&
|
|
RtlPrefixUnicodeString( &p->NtLinkTarget, Path, TRUE )
|
|
)
|
|
{
|
|
Path->Length -= p->NtLinkTarget.Length;
|
|
RtlMoveMemory( &Path->Buffer[ 2 ],
|
|
(PCHAR)(Path->Buffer) + p->NtLinkTarget.Length,
|
|
Path->Length + sizeof( UNICODE_NULL )
|
|
);
|
|
Path->Buffer[ 0 ] = p->DriveLetter;
|
|
Path->Buffer[ 1 ] = L':';
|
|
Path->Length += 2;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
TrimTemporaryBuffer( VOID )
|
|
{
|
|
PVOID CommitAddress;
|
|
|
|
if (TemporaryBufferLength == 0) {
|
|
return;
|
|
}
|
|
|
|
if (VirtualFree( (PCHAR)TemporaryBuffer,
|
|
TemporaryBufferLength,
|
|
MEM_DECOMMIT
|
|
)
|
|
)
|
|
{
|
|
TemporaryBufferLength = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
GrowTemporaryBuffer(
|
|
ULONG NeededSize
|
|
)
|
|
{
|
|
PVOID CommitAddress;
|
|
|
|
if (NeededSize <= TemporaryBufferLength) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (TemporaryBufferLength == TemporaryBufferMaximumLength) {
|
|
return FALSE;
|
|
}
|
|
|
|
CommitAddress = VirtualAlloc( (PCHAR)TemporaryBuffer + TemporaryBufferLength,
|
|
NeededSize - TemporaryBufferLength,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE
|
|
);
|
|
if (CommitAddress == NULL) {
|
|
DbgEvent( INTERNALERROR, ( "VirtualAlloc( %0x8 ) failed (%u)\n",
|
|
NeededSize - TemporaryBufferLength,
|
|
GetLastError()
|
|
)
|
|
);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
TemporaryBufferLength += TemporaryBufferLengthGrowth;
|
|
return TRUE;
|
|
}
|
|
|
|
ULONG
|
|
FillTemporaryBuffer(
|
|
PPROCESS_INFO Process,
|
|
PVOID Address,
|
|
BOOLEAN Unicode,
|
|
BOOLEAN DoubleNullTermination
|
|
)
|
|
{
|
|
ULONG BytesRead;
|
|
ULONG TotalBytesRead;
|
|
PVOID Source;
|
|
PVOID Destination;
|
|
LPSTR s1;
|
|
PWSTR s2;
|
|
BOOLEAN MoreToRead;
|
|
BOOLEAN SeenOneNull;
|
|
|
|
TotalBytesRead = 0;
|
|
Destination = (PCHAR)TemporaryBuffer;
|
|
MoreToRead = TRUE;
|
|
SeenOneNull = FALSE;
|
|
while (MoreToRead) {
|
|
TotalBytesRead += TemporaryBufferLengthGrowth;
|
|
if (!GrowTemporaryBuffer( TotalBytesRead )) {
|
|
return 0;
|
|
}
|
|
|
|
Source = Destination;
|
|
BytesRead = 0;
|
|
if (!ReadProcessMemory( Process->Handle,
|
|
Address,
|
|
Destination,
|
|
TemporaryBufferLengthGrowth,
|
|
&BytesRead
|
|
)
|
|
)
|
|
{
|
|
if (BytesRead == 0) {
|
|
MoreToRead = FALSE;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Destination = (PCHAR)Destination + TotalBytesRead;
|
|
if (Unicode) {
|
|
s2 = (PWSTR)Source;
|
|
while (s2 < (PWSTR)Destination) {
|
|
if (*s2 == UNICODE_NULL) {
|
|
if (SeenOneNull || !DoubleNullTermination) {
|
|
return (PCHAR)s2 - (PCHAR)TemporaryBuffer;
|
|
} else {
|
|
SeenOneNull = TRUE;
|
|
}
|
|
} else {
|
|
SeenOneNull = FALSE;
|
|
}
|
|
|
|
s2++;
|
|
}
|
|
|
|
} else {
|
|
s1 = (LPSTR)Source;
|
|
while (s1 < (LPSTR)Destination) {
|
|
if (*s1 == '\0') {
|
|
if (SeenOneNull || !DoubleNullTermination) {
|
|
return (PCHAR)s1 - (PCHAR)TemporaryBuffer;
|
|
} else {
|
|
SeenOneNull = TRUE;
|
|
}
|
|
|
|
} else {
|
|
SeenOneNull = FALSE;
|
|
}
|
|
|
|
s1++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|