summaryrefslogtreecommitdiffstats
path: root/private/sdktools/instaler/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/sdktools/instaler/init.c')
-rw-r--r--private/sdktools/instaler/init.c770
1 files changed, 770 insertions, 0 deletions
diff --git a/private/sdktools/instaler/init.c b/private/sdktools/instaler/init.c
new file mode 100644
index 000000000..5a9a5c170
--- /dev/null
+++ b/private/sdktools/instaler/init.c
@@ -0,0 +1,770 @@
+/*++
+
+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}
+};
+
+
+
+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 )}
+};
+
+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 );
+
+ GetWindowsDirectoryW( WindowsDirectoryBuffer, MAX_PATH );
+ 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;
+ }
+ else {
+ sprintf( (LPSTR)PathBuffer, "%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 {
+ if (((ULONG)EntryPointAddress >= FunctionEntry->BeginAddress) &&
+ ((ULONG)EntryPointAddress < FunctionEntry->PrologEndAddress)) {
+ return (PVOID)FunctionEntry->PrologEndAddress;
+ }
+ 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;
+ 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;
+}