diff options
Diffstat (limited to 'private/sdktools/instaler/init.c')
-rw-r--r-- | private/sdktools/instaler/init.c | 770 |
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; +} |