Source code of Windows XP (NT5)
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.

752 lines
25 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. init.c
  5. Abstract:
  6. This is the initialization module for the INSTALER program.
  7. Author:
  8. Steve Wood (stevewo) 09-Aug-1994
  9. Revision History:
  10. --*/
  11. #include "instaler.h"
  12. #if TRACE_ENABLED
  13. ULONG EnabledTraceEvents = DBG_MASK_INTERNALERROR |
  14. DBG_MASK_MEMORYERROR;
  15. #endif
  16. MODULE_INFO ModuleInfo[ MAXIMUM_MODULE_INDEX ] = {
  17. {L"NTDLL", NULL},
  18. {L"KERNEL32", NULL},
  19. {L"ADVAPI32", NULL},
  20. {L"USER32", NULL}
  21. };
  22. API_INFO ApiInfo[ MAXIMUM_API_INDEX ] = {
  23. {NTDLL_MODULE_INDEX, "NtCreateFile", NULL, NtCreateFileHandler , sizeof( CREATEFILE_PARAMETERS ) , sizeof( NTSTATUS )},
  24. {NTDLL_MODULE_INDEX, "NtOpenFile", NULL, NtOpenFileHandler , sizeof( OPENFILE_PARAMETERS ) , sizeof( NTSTATUS )},
  25. {NTDLL_MODULE_INDEX, "NtDeleteFile", NULL, NtDeleteFileHandler , sizeof( DELETEFILE_PARAMETERS ) , sizeof( NTSTATUS )},
  26. {NTDLL_MODULE_INDEX, "NtSetInformationFile", NULL, NtSetInformationFileHandler , sizeof( SETINFORMATIONFILE_PARAMETERS ) , sizeof( NTSTATUS )},
  27. {NTDLL_MODULE_INDEX, "NtQueryAttributesFile", NULL, NtQueryAttributesFileHandler , sizeof( QUERYATTRIBUTESFILE_PARAMETERS ) , sizeof( NTSTATUS )},
  28. {NTDLL_MODULE_INDEX, "NtQueryDirectoryFile", NULL, NtQueryDirectoryFileHandler , sizeof( QUERYDIRECTORYFILE_PARAMETERS ) , sizeof( NTSTATUS )},
  29. {NTDLL_MODULE_INDEX, "NtCreateKey", NULL, NtCreateKeyHandler , sizeof( CREATEKEY_PARAMETERS ) , sizeof( NTSTATUS )},
  30. {NTDLL_MODULE_INDEX, "NtOpenKey", NULL, NtOpenKeyHandler , sizeof( OPENKEY_PARAMETERS ) , sizeof( NTSTATUS )},
  31. {NTDLL_MODULE_INDEX, "NtDeleteKey", NULL, NtDeleteKeyHandler , sizeof( DELETEKEY_PARAMETERS ) , sizeof( NTSTATUS )},
  32. {NTDLL_MODULE_INDEX, "NtSetValueKey", NULL, NtSetValueKeyHandler , sizeof( SETVALUEKEY_PARAMETERS ) , sizeof( NTSTATUS )},
  33. {NTDLL_MODULE_INDEX, "NtDeleteValueKey", NULL, NtDeleteValueKeyHandler , sizeof( DELETEVALUEKEY_PARAMETERS ) , sizeof( NTSTATUS )},
  34. {NTDLL_MODULE_INDEX, "NtClose", NULL, NtCloseHandleHandler , sizeof( CLOSEHANDLE_PARAMETERS ) , sizeof( NTSTATUS )},
  35. {KERNEL32_MODULE_INDEX, "GetVersion", NULL, GetVersionHandler , 0 , sizeof( DWORD )},
  36. {KERNEL32_MODULE_INDEX, "GetVersionExW", NULL, GetVersionExWHandler , sizeof( GETVERSIONEXW_PARAMETERS ) , sizeof( BOOL )},
  37. {KERNEL32_MODULE_INDEX, "SetCurrentDirectoryA", NULL, SetCurrentDirectoryAHandler , sizeof( SETCURRENTDIRECTORYA_PARAMETERS ) , sizeof( BOOL )},
  38. {KERNEL32_MODULE_INDEX, "SetCurrentDirectoryW", NULL, SetCurrentDirectoryWHandler , sizeof( SETCURRENTDIRECTORYW_PARAMETERS ) , sizeof( BOOL )},
  39. {KERNEL32_MODULE_INDEX, "WritePrivateProfileStringA", NULL, WritePrivateProfileStringAHandler , sizeof( WRITEPRIVATEPROFILESTRINGA_PARAMETERS ) , sizeof( DWORD )},
  40. {KERNEL32_MODULE_INDEX, "WritePrivateProfileStringW", NULL, WritePrivateProfileStringWHandler , sizeof( WRITEPRIVATEPROFILESTRINGW_PARAMETERS ) , sizeof( DWORD )},
  41. {KERNEL32_MODULE_INDEX, "WritePrivateProfileSectionA", NULL, WritePrivateProfileSectionAHandler, sizeof( WRITEPRIVATEPROFILESECTIONA_PARAMETERS ) , sizeof( DWORD )},
  42. {KERNEL32_MODULE_INDEX, "WritePrivateProfileSectionW", NULL, WritePrivateProfileSectionWHandler, sizeof( WRITEPRIVATEPROFILESECTIONW_PARAMETERS ) , sizeof( DWORD )},
  43. {KERNEL32_MODULE_INDEX, "GetPrivateProfileStringW", NULL, NULL, 0, sizeof( DWORD )},
  44. {KERNEL32_MODULE_INDEX, "GetPrivateProfileStringA", NULL, NULL, 0, sizeof( DWORD )},
  45. {KERNEL32_MODULE_INDEX, "GetPrivateProfileSectionW", NULL, NULL, 0, sizeof( DWORD )},
  46. {KERNEL32_MODULE_INDEX, "GetPrivateProfileSectionA", NULL, NULL, 0, sizeof( DWORD )},
  47. {ADVAPI32_MODULE_INDEX, "RegConnectRegistryW", NULL, RegConnectRegistryWHandler , sizeof( REGCONNECTREGISTRYW_PARAMETERS ) , sizeof( DWORD )},
  48. {USER32_MODULE_INDEX, "ExitWindowsEx", NULL, ExitWindowsExHandler , sizeof( EXITWINDOWSEX_PARAMETERS ) , sizeof( BOOL )}
  49. };
  50. BOOLEAN
  51. LoadApplicationForDebug(
  52. PWSTR CommandLine
  53. );
  54. BOOLEAN
  55. LoadDriveLetterDefinitions( VOID );
  56. WCHAR WindowsDirectoryBuffer[ MAX_PATH ];
  57. UNICODE_STRING WindowsDirectory;
  58. BOOLEAN
  59. InitializeInstaler(
  60. int argc,
  61. char *argv[]
  62. )
  63. {
  64. UINT ModuleIndex, ApiIndex;
  65. PWSTR CommandLine;
  66. UINT i;
  67. LPSTR s;
  68. UCHAR c;
  69. SYSTEM_INFO SystemInfo;
  70. BOOLEAN ProcessingDebugSwitch;
  71. InitCommonCode( "INSTALER",
  72. "[-9] [-r] [-dAE] CommandLine...",
  73. "-9 specifies that GetVersion should lie and tell application\n"
  74. " that it is running on Windows 95\n"
  75. "-r specifies that attempts to do a wildcard scan of the root\n"
  76. " directory of a drive should fail.\n"
  77. "-d specifies one or more debugging message options\n"
  78. " A - shows all errors\n"
  79. " E - shows all debug events\n"
  80. " C - shows all create API calls\n"
  81. );
  82. AppHeap = GetProcessHeap();
  83. InstalerModuleHandle = GetModuleHandle( NULL );
  84. if (GetWindowsDirectoryW( WindowsDirectoryBuffer, MAX_PATH ) == 0) {
  85. return FALSE;
  86. }
  87. RtlInitUnicodeString( &WindowsDirectory, WindowsDirectoryBuffer );
  88. GetSystemInfo( &SystemInfo );
  89. TemporaryBufferLengthGrowth = SystemInfo.dwPageSize;
  90. TemporaryBufferMaximumLength = ((128 * 1024) + SystemInfo.dwAllocationGranularity - 1) &
  91. ~SystemInfo.dwAllocationGranularity;
  92. TemporaryBuffer = VirtualAlloc( NULL,
  93. TemporaryBufferMaximumLength,
  94. MEM_RESERVE,
  95. PAGE_READWRITE
  96. );
  97. if (TemporaryBuffer == NULL) {
  98. return FALSE;
  99. }
  100. InitializeListHead( &ProcessListHead );
  101. InitializeListHead( &FileReferenceListHead );
  102. InitializeListHead( &KeyReferenceListHead );
  103. InitializeListHead( &IniReferenceListHead );
  104. InitializeCriticalSection( &BreakTable );
  105. //
  106. // Loop over the table of modules and make sure each is loaded in our
  107. // address space so we can access their export tables.
  108. //
  109. for (ModuleIndex=0; ModuleIndex<MAXIMUM_MODULE_INDEX; ModuleIndex++) {
  110. ModuleInfo[ ModuleIndex ].ModuleHandle =
  111. GetModuleHandle( ModuleInfo[ ModuleIndex ].ModuleName );
  112. if (ModuleInfo[ ModuleIndex ].ModuleHandle == NULL) {
  113. //
  114. // Bail if any are missing.
  115. //
  116. DeclareError( INSTALER_MISSING_MODULE,
  117. GetLastError(),
  118. ModuleInfo[ ModuleIndex ].ModuleName
  119. );
  120. return FALSE;
  121. }
  122. }
  123. //
  124. // Now loop over the table of entry points that we care about and
  125. // get the address of each entry point from the
  126. for (ApiIndex=0; ApiIndex<MAXIMUM_API_INDEX; ApiIndex++) {
  127. ModuleIndex = ApiInfo[ ApiIndex ].ModuleIndex;
  128. ApiInfo[ ApiIndex ].EntryPointAddress =
  129. LookupEntryPointInIAT( ModuleInfo[ ModuleIndex ].ModuleHandle,
  130. ApiInfo[ ApiIndex ].EntryPointName
  131. );
  132. if (ApiInfo[ ApiIndex ].EntryPointAddress == NULL) {
  133. //
  134. // Bail if we are unable to get the address of any of them
  135. //
  136. DeclareError( INSTALER_MISSING_ENTRYPOINT,
  137. GetLastError(),
  138. ApiInfo[ ApiIndex ].EntryPointName,
  139. ModuleInfo[ ModuleIndex ].ModuleName
  140. );
  141. return FALSE;
  142. }
  143. }
  144. CommandLine = NULL;
  145. ProcessingDebugSwitch = FALSE;
  146. AskUserOnce = FALSE;
  147. while (--argc) {
  148. s = *++argv;
  149. if (*s == '-' || *s == '/') {
  150. while (*++s) {
  151. switch( tolower( *s ) ) {
  152. case '9':
  153. DefaultGetVersionToWin95 = TRUE;
  154. break;
  155. case 'r':
  156. FailAllScansOfRootDirectories = TRUE;
  157. break;
  158. #if TRACE_ENABLED
  159. case 'd':
  160. ProcessingDebugSwitch = TRUE;
  161. break;
  162. case 'a':
  163. if (ProcessingDebugSwitch) {
  164. EnabledTraceEvents = 0xFFFFFFFF;
  165. break;
  166. }
  167. case 'e':
  168. if (ProcessingDebugSwitch) {
  169. EnabledTraceEvents |= DBG_MASK_DBGEVENT;
  170. break;
  171. }
  172. case 'c':
  173. if (ProcessingDebugSwitch) {
  174. EnabledTraceEvents |= DBG_MASK_CREATEEVENT;
  175. break;
  176. }
  177. #endif
  178. default:
  179. if (!ProcessingDebugSwitch) {
  180. CommonSwitchProcessing( &argc, &argv, *s );
  181. } else {
  182. Usage( "Invalid debug switch (-%c)", (ULONG)*s );
  183. }
  184. break;
  185. }
  186. }
  187. ProcessingDebugSwitch = FALSE;
  188. } else if (!CommonArgProcessing( &argc, &argv )) {
  189. CommandLine = GetCommandLine();
  190. while (*CommandLine && *CommandLine <= L' ') {
  191. CommandLine += 1;
  192. }
  193. while (*CommandLine && *CommandLine > L' ') {
  194. CommandLine += 1;
  195. }
  196. CommandLine = wcsstr( CommandLine, GetArgAsUnicode( s ) );
  197. break;
  198. }
  199. }
  200. if (ImlPath == NULL) {
  201. Usage( "Must specify an installation name as first argument", 0 );
  202. }
  203. if (CommandLine == NULL) {
  204. Usage( "Command line missing", 0 );
  205. }
  206. pImlNew = CreateIml( ImlPath, FALSE );
  207. if (pImlNew == NULL) {
  208. FatalError( "Unable to create %ws (%u)\n",
  209. (ULONG)ImlPath,
  210. GetLastError()
  211. );
  212. }
  213. //
  214. // Ready to roll. Cache the drive letter information and then load
  215. // the application with the DEBUG option so we can watch what it does
  216. //
  217. if (!LoadDriveLetterDefinitions() ||
  218. !LoadApplicationForDebug( CommandLine )
  219. ) {
  220. return FALSE;
  221. }
  222. return TRUE;
  223. }
  224. BOOLEAN
  225. LoadApplicationForDebug(
  226. PWSTR CommandLine
  227. )
  228. {
  229. STARTUPINFO StartupInfo;
  230. PROCESS_INFORMATION ProcessInformation;
  231. PWSTR ImageFilePath;
  232. PWSTR ImageFileName;
  233. PWSTR CurrentDirectory;
  234. PWSTR TemporaryNull;
  235. WCHAR TemporaryChar;
  236. ULONG Length;
  237. WCHAR PathBuffer[ MAX_PATH ];
  238. TemporaryNull = CommandLine;
  239. while(TemporaryChar = *TemporaryNull) {
  240. if (TemporaryChar == L' ' || TemporaryChar == L'\t') {
  241. *TemporaryNull = UNICODE_NULL;
  242. break;
  243. }
  244. TemporaryNull += 1;
  245. }
  246. ImageFilePath = AllocMem( MAX_PATH * sizeof( WCHAR ) );
  247. Length = SearchPath( NULL,
  248. CommandLine,
  249. L".exe",
  250. MAX_PATH,
  251. ImageFilePath,
  252. &ImageFileName
  253. );
  254. *TemporaryNull = TemporaryChar;
  255. if (!Length || Length >= MAX_PATH) {
  256. DeclareError( INSTALER_CANT_DEBUG_PROGRAM,
  257. GetLastError(),
  258. CommandLine
  259. );
  260. return FALSE;
  261. }
  262. if (ImageFileName != NULL &&
  263. ImageFileName > ImageFilePath &&
  264. ImageFileName[ -1 ] == L'\\'
  265. ) {
  266. ImageFileName[ -1 ] = UNICODE_NULL;
  267. CurrentDirectory = wcscpy( PathBuffer, ImageFilePath );
  268. ImageFileName[ -1 ] = L'\\';
  269. SetCurrentDirectory( CurrentDirectory );
  270. } else {
  271. CurrentDirectory = NULL;
  272. }
  273. memset( &StartupInfo, 0, sizeof( StartupInfo ) );
  274. StartupInfo.cb = sizeof(StartupInfo);
  275. //
  276. // Create the process with DEBUG option, as a separate WOW so we only see our
  277. // application's damage.
  278. //
  279. if (!CreateProcess( ImageFilePath,
  280. CommandLine,
  281. NULL,
  282. NULL,
  283. FALSE, // No handles to inherit
  284. DEBUG_PROCESS |
  285. CREATE_SEPARATE_WOW_VDM, // Ignored for 32 bit apps
  286. NULL,
  287. CurrentDirectory,
  288. &StartupInfo,
  289. &ProcessInformation
  290. ) ) {
  291. DeclareError( INSTALER_CANT_DEBUG_PROGRAM,
  292. GetLastError(),
  293. CommandLine
  294. );
  295. return FALSE;
  296. }
  297. sprintf( (LPSTR)PathBuffer, "%ws%ws.log", InstalerDirectory, InstallationName );
  298. InstalerLogFile = fopen( (LPSTR)PathBuffer, "w" );
  299. //
  300. // Will pick up the process and thread handles with the
  301. // CREATE_PROCESS_DEBUG_EVENT and CREATE_PROCESS_THREAD_EVENT
  302. //
  303. return TRUE;
  304. }
  305. PVOID
  306. LookupEntryPointInIAT(
  307. HMODULE ModuleHandle,
  308. PCHAR EntryPointName
  309. )
  310. {
  311. PIMAGE_EXPORT_DIRECTORY Exports;
  312. PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTableEntries;
  313. DWORD NumberOfFunctionTableEntries;
  314. ULONG ExportSize, FunctionTableSize;
  315. PCHAR *EntryPointNames;
  316. PULONG EntryPointAddresses;
  317. PUSHORT EntryPointOrdinals;
  318. PVOID EntryPointAddress;
  319. ULONG i;
  320. Exports = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( ModuleHandle,
  321. TRUE,
  322. IMAGE_DIRECTORY_ENTRY_EXPORT,
  323. &ExportSize
  324. );
  325. if (Exports == NULL) {
  326. return NULL;
  327. }
  328. FunctionTableEntries = (PIMAGE_RUNTIME_FUNCTION_ENTRY)
  329. RtlImageDirectoryEntryToData( ModuleHandle,
  330. TRUE,
  331. IMAGE_DIRECTORY_ENTRY_EXCEPTION,
  332. &FunctionTableSize
  333. );
  334. if (FunctionTableEntries != NULL) {
  335. NumberOfFunctionTableEntries = FunctionTableSize / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY );
  336. } else {
  337. NumberOfFunctionTableEntries = 0;
  338. }
  339. EntryPointNames = (PCHAR *)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfNames);
  340. EntryPointOrdinals = (PUSHORT)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfNameOrdinals);
  341. EntryPointAddresses = (PULONG)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfFunctions);
  342. for (i=0; i<Exports->NumberOfNames; i++) {
  343. EntryPointAddress = (PVOID)((PCHAR)ModuleHandle +
  344. EntryPointAddresses[ EntryPointOrdinals[ i ] ]
  345. );
  346. if ((ULONG)EntryPointAddress > (ULONG)Exports &&
  347. (ULONG)EntryPointAddress < ((ULONG)Exports + ExportSize) ) {
  348. //
  349. // Skip this... It's a forwarded reference
  350. //
  351. } else if (!_stricmp( EntryPointName, (PCHAR)ModuleHandle + (ULONG)EntryPointNames[ i ] )) {
  352. return GetAddressForEntryPointBreakpoint( EntryPointAddress,
  353. NumberOfFunctionTableEntries,
  354. FunctionTableEntries
  355. );
  356. }
  357. }
  358. DbgEvent( INTERNALERROR, ( "Unable to find entry point '%s' in module at %x\n", EntryPointName, ModuleHandle ) );
  359. return NULL;
  360. }
  361. PVOID
  362. GetAddressForEntryPointBreakpoint(
  363. PVOID EntryPointAddress,
  364. DWORD NumberOfFunctionTableEntries OPTIONAL,
  365. PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTableEntries OPTIONAL
  366. )
  367. {
  368. PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry;
  369. PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTable;
  370. LONG High;
  371. LONG Low;
  372. LONG Middle;
  373. //
  374. // If no function table, then okay to set breakpoint at exported
  375. // address.
  376. //
  377. if (NumberOfFunctionTableEntries == 0) {
  378. return EntryPointAddress;
  379. }
  380. //
  381. // Initialize search indicies.
  382. //
  383. Low = 0;
  384. High = NumberOfFunctionTableEntries - 1;
  385. FunctionTable = FunctionTableEntries;
  386. //
  387. // Perform binary search on the function table for a function table
  388. // entry that subsumes the specified PC.
  389. //
  390. while (High >= Low) {
  391. //
  392. // Compute next probe index and test entry. If the specified PC
  393. // is greater than of equal to the beginning address and less
  394. // than the ending address of the function table entry, then
  395. // return the address of the function table entry. Otherwise,
  396. // continue the search.
  397. //
  398. Middle = (Low + High) >> 1;
  399. FunctionEntry = &FunctionTable[Middle];
  400. if ((ULONG)EntryPointAddress < FunctionEntry->BeginAddress) {
  401. High = Middle - 1;
  402. } else if ((ULONG)EntryPointAddress >= FunctionEntry->EndAddress) {
  403. Low = Middle + 1;
  404. } else {
  405. break;
  406. }
  407. }
  408. //
  409. // A function table entry for the specified PC was not found. Just use
  410. // the exported address and hope for the best.
  411. //
  412. return EntryPointAddress;
  413. }
  414. BOOLEAN
  415. LoadDriveLetterDefinitions( VOID )
  416. {
  417. PVOID Buffer;
  418. ULONG BufferSize;
  419. ULONG cchDeviceName;
  420. ULONG cch;
  421. ULONG cchTargetPath;
  422. PWSTR DeviceName;
  423. PWSTR TargetPath;
  424. ULONG DriveLetterIndex;
  425. ULONG cb;
  426. PDRIVE_LETTER_INFO p;
  427. RtlInitUnicodeString( &AltDriveLetterPrefix, L"\\DosDevices\\" );
  428. RtlInitUnicodeString( &DriveLetterPrefix, L"\\??\\" );
  429. RtlInitUnicodeString( &UNCPrefix, L"UNC\\" );
  430. BufferSize = 0x1000;
  431. Buffer = VirtualAlloc( NULL, BufferSize, MEM_COMMIT, PAGE_READWRITE );
  432. if (Buffer == NULL) {
  433. DbgEvent( INTERNALERROR, ( "VirtualAlloc( %0x8 ) failed (%u)\n", BufferSize, GetLastError() ) );
  434. return FALSE;
  435. }
  436. cchTargetPath = BufferSize / sizeof( WCHAR );
  437. cchDeviceName = QueryDosDeviceW( NULL,
  438. Buffer,
  439. cchTargetPath
  440. );
  441. if (cchDeviceName == 0) {
  442. DbgEvent( INTERNALERROR, ( "QueryDosDeviceW( NULL ) failed (%u)\n", GetLastError() ) );
  443. return FALSE;
  444. }
  445. cchTargetPath -= (cchDeviceName + 2);
  446. DeviceName = Buffer;
  447. TargetPath = DeviceName + 2 + cchDeviceName;
  448. while (*DeviceName) {
  449. if (wcslen( DeviceName ) == 2 &&
  450. DeviceName[ 1 ] == L':' &&
  451. _wcsupr( DeviceName ) &&
  452. DeviceName[ 0 ] >= L'@' &&
  453. DeviceName[ 0 ] <= L'_'
  454. ) {
  455. cch = QueryDosDeviceW( DeviceName, TargetPath, cchTargetPath );
  456. if (cch == 0) {
  457. DbgEvent( INTERNALERROR, ( "QueryDosDeviceW( %ws ) failed (%u)\n", DeviceName, GetLastError() ) );
  458. return FALSE;
  459. }
  460. DriveLetterIndex = DeviceName[ 0 ] - L'@';
  461. p = &DriveLetters[ DriveLetterIndex ];
  462. p->DriveLetter = (WCHAR)(L'@' + DriveLetterIndex);
  463. cb = (cch+1) * sizeof( WCHAR );
  464. p->NtLinkTarget.Buffer = AllocMem( cb );
  465. if (p->NtLinkTarget.Buffer == NULL) {
  466. return FALSE;
  467. }
  468. MoveMemory( p->NtLinkTarget.Buffer, TargetPath, cb );
  469. p->NtLinkTarget.Length = (USHORT)( cb - sizeof( WCHAR ));
  470. p->NtLinkTarget.MaximumLength = (USHORT)cb;
  471. p->DriveLetterValid = TRUE;
  472. }
  473. while (*DeviceName++) {}
  474. }
  475. return TRUE;
  476. }
  477. BOOLEAN
  478. IsDriveLetterPath(
  479. PUNICODE_STRING Path
  480. )
  481. {
  482. ULONG DriveLetterIndex;
  483. PDRIVE_LETTER_INFO p;
  484. PUNICODE_STRING Prefix;
  485. if (RtlPrefixUnicodeString( Prefix = &DriveLetterPrefix, Path, TRUE ) ||
  486. RtlPrefixUnicodeString( Prefix = &AltDriveLetterPrefix, Path, TRUE ) ) {
  487. Path->Length -= Prefix->Length;
  488. RtlMoveMemory( Path->Buffer,
  489. (PCHAR)(Path->Buffer) + Prefix->Length,
  490. Path->Length + sizeof( UNICODE_NULL )
  491. );
  492. if (RtlPrefixUnicodeString( &UNCPrefix, Path, TRUE )) {
  493. Path->Length -= UNCPrefix.Length;
  494. Path->Buffer[0] = L'\\';
  495. Path->Buffer[1] = L'\\';
  496. RtlMoveMemory( &Path->Buffer[2],
  497. (PCHAR)(Path->Buffer) + UNCPrefix.Length,
  498. Path->Length + sizeof( UNICODE_NULL )
  499. );
  500. Path->Length += 2 * sizeof( WCHAR );
  501. }
  502. return TRUE;
  503. }
  504. for (DriveLetterIndex=0, p = &DriveLetters[ DriveLetterIndex ];
  505. DriveLetterIndex<32;
  506. DriveLetterIndex++, p++
  507. )
  508. {
  509. if (p->DriveLetterValid &&
  510. RtlPrefixUnicodeString( &p->NtLinkTarget, Path, TRUE )
  511. )
  512. {
  513. Path->Length -= p->NtLinkTarget.Length;
  514. RtlMoveMemory( &Path->Buffer[ 2 ],
  515. (PCHAR)(Path->Buffer) + p->NtLinkTarget.Length,
  516. Path->Length + sizeof( UNICODE_NULL )
  517. );
  518. Path->Buffer[ 0 ] = p->DriveLetter;
  519. Path->Buffer[ 1 ] = L':';
  520. Path->Length += 2;
  521. return TRUE;
  522. }
  523. }
  524. return FALSE;
  525. }
  526. VOID
  527. TrimTemporaryBuffer( VOID )
  528. {
  529. PVOID CommitAddress;
  530. if (TemporaryBufferLength == 0) {
  531. return;
  532. }
  533. if (VirtualFree( (PCHAR)TemporaryBuffer,
  534. TemporaryBufferLength,
  535. MEM_DECOMMIT
  536. )
  537. )
  538. {
  539. TemporaryBufferLength = 0;
  540. }
  541. return;
  542. }
  543. BOOLEAN
  544. GrowTemporaryBuffer(
  545. ULONG NeededSize
  546. )
  547. {
  548. PVOID CommitAddress;
  549. if (NeededSize <= TemporaryBufferLength) {
  550. return TRUE;
  551. }
  552. if (TemporaryBufferLength == TemporaryBufferMaximumLength) {
  553. return FALSE;
  554. }
  555. CommitAddress = VirtualAlloc( (PCHAR)TemporaryBuffer + TemporaryBufferLength,
  556. NeededSize - TemporaryBufferLength,
  557. MEM_COMMIT,
  558. PAGE_READWRITE
  559. );
  560. if (CommitAddress == NULL) {
  561. DbgEvent( INTERNALERROR, ( "VirtualAlloc( %0x8 ) failed (%u)\n",
  562. NeededSize - TemporaryBufferLength,
  563. GetLastError()
  564. )
  565. );
  566. return FALSE;
  567. }
  568. TemporaryBufferLength += TemporaryBufferLengthGrowth;
  569. return TRUE;
  570. }
  571. ULONG
  572. FillTemporaryBuffer(
  573. PPROCESS_INFO Process,
  574. PVOID Address,
  575. BOOLEAN Unicode,
  576. BOOLEAN DoubleNullTermination
  577. )
  578. {
  579. ULONG BytesRead;
  580. ULONG TotalBytesRead;
  581. PVOID Source;
  582. PVOID Destination;
  583. LPSTR s1;
  584. PWSTR s2;
  585. BOOLEAN MoreToRead;
  586. BOOLEAN SeenOneNull;
  587. TotalBytesRead = 0;
  588. Destination = (PCHAR)TemporaryBuffer;
  589. MoreToRead = TRUE;
  590. SeenOneNull = FALSE;
  591. while (MoreToRead) {
  592. TotalBytesRead += TemporaryBufferLengthGrowth;
  593. if (!GrowTemporaryBuffer( TotalBytesRead )) {
  594. return 0;
  595. }
  596. Source = Destination;
  597. BytesRead = 0;
  598. if (!ReadProcessMemory( Process->Handle,
  599. Address,
  600. Destination,
  601. TemporaryBufferLengthGrowth,
  602. &BytesRead
  603. )
  604. )
  605. {
  606. if (BytesRead == 0) {
  607. MoreToRead = FALSE;
  608. } else {
  609. return 0;
  610. }
  611. }
  612. Destination = (PCHAR)Destination + TotalBytesRead;
  613. if (Unicode) {
  614. s2 = (PWSTR)Source;
  615. while (s2 < (PWSTR)Destination) {
  616. if (*s2 == UNICODE_NULL) {
  617. if (SeenOneNull || !DoubleNullTermination) {
  618. return (PCHAR)s2 - (PCHAR)TemporaryBuffer;
  619. } else {
  620. SeenOneNull = TRUE;
  621. }
  622. } else {
  623. SeenOneNull = FALSE;
  624. }
  625. s2++;
  626. }
  627. } else {
  628. s1 = (LPSTR)Source;
  629. while (s1 < (LPSTR)Destination) {
  630. if (*s1 == '\0') {
  631. if (SeenOneNull || !DoubleNullTermination) {
  632. return (PCHAR)s1 - (PCHAR)TemporaryBuffer;
  633. } else {
  634. SeenOneNull = TRUE;
  635. }
  636. } else {
  637. SeenOneNull = FALSE;
  638. }
  639. s1++;
  640. }
  641. }
  642. }
  643. return 0;
  644. }