Leaked source code of windows server 2003
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

  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. //
  298. // BogdanA 02/19/2002: this is ugly but whatever.
  299. // Make sure we terminate the Unicode string.
  300. // Then use it as an ANSI one. Oh well...
  301. //
  302. PathBuffer[sizeof(PathBuffer)/sizeof(PathBuffer[0]) - 1] = 0;
  303. _snprintf( (LPSTR)PathBuffer,
  304. sizeof(PathBuffer) - 1,
  305. "%ws%ws.log", InstalerDirectory, InstallationName );
  306. InstalerLogFile = fopen( (LPSTR)PathBuffer, "w" );
  307. //
  308. // Will pick up the process and thread handles with the
  309. // CREATE_PROCESS_DEBUG_EVENT and CREATE_PROCESS_THREAD_EVENT
  310. //
  311. return TRUE;
  312. }
  313. PVOID
  314. LookupEntryPointInIAT(
  315. HMODULE ModuleHandle,
  316. PCHAR EntryPointName
  317. )
  318. {
  319. PIMAGE_EXPORT_DIRECTORY Exports;
  320. PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTableEntries;
  321. DWORD NumberOfFunctionTableEntries;
  322. ULONG ExportSize, FunctionTableSize;
  323. PCHAR *EntryPointNames;
  324. PULONG EntryPointAddresses;
  325. PUSHORT EntryPointOrdinals;
  326. PVOID EntryPointAddress;
  327. ULONG i;
  328. Exports = (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData( ModuleHandle,
  329. TRUE,
  330. IMAGE_DIRECTORY_ENTRY_EXPORT,
  331. &ExportSize
  332. );
  333. if (Exports == NULL) {
  334. return NULL;
  335. }
  336. FunctionTableEntries = (PIMAGE_RUNTIME_FUNCTION_ENTRY)
  337. RtlImageDirectoryEntryToData( ModuleHandle,
  338. TRUE,
  339. IMAGE_DIRECTORY_ENTRY_EXCEPTION,
  340. &FunctionTableSize
  341. );
  342. if (FunctionTableEntries != NULL) {
  343. NumberOfFunctionTableEntries = FunctionTableSize / sizeof( IMAGE_RUNTIME_FUNCTION_ENTRY );
  344. } else {
  345. NumberOfFunctionTableEntries = 0;
  346. }
  347. EntryPointNames = (PCHAR *)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfNames);
  348. EntryPointOrdinals = (PUSHORT)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfNameOrdinals);
  349. EntryPointAddresses = (PULONG)((PCHAR)ModuleHandle + (ULONG)Exports->AddressOfFunctions);
  350. for (i=0; i<Exports->NumberOfNames; i++) {
  351. EntryPointAddress = (PVOID)((PCHAR)ModuleHandle +
  352. EntryPointAddresses[ EntryPointOrdinals[ i ] ]
  353. );
  354. if ((ULONG)EntryPointAddress > (ULONG)Exports &&
  355. (ULONG)EntryPointAddress < ((ULONG)Exports + ExportSize) ) {
  356. //
  357. // Skip this... It's a forwarded reference
  358. //
  359. } else if (!_stricmp( EntryPointName, (PCHAR)ModuleHandle + (ULONG)EntryPointNames[ i ] )) {
  360. return GetAddressForEntryPointBreakpoint( EntryPointAddress,
  361. NumberOfFunctionTableEntries,
  362. FunctionTableEntries
  363. );
  364. }
  365. }
  366. DbgEvent( INTERNALERROR, ( "Unable to find entry point '%s' in module at %x\n", EntryPointName, ModuleHandle ) );
  367. return NULL;
  368. }
  369. PVOID
  370. GetAddressForEntryPointBreakpoint(
  371. PVOID EntryPointAddress,
  372. DWORD NumberOfFunctionTableEntries OPTIONAL,
  373. PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTableEntries OPTIONAL
  374. )
  375. {
  376. PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry;
  377. PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionTable;
  378. LONG High;
  379. LONG Low;
  380. LONG Middle;
  381. //
  382. // If no function table, then okay to set breakpoint at exported
  383. // address.
  384. //
  385. if (NumberOfFunctionTableEntries == 0) {
  386. return EntryPointAddress;
  387. }
  388. //
  389. // Initialize search indicies.
  390. //
  391. Low = 0;
  392. High = NumberOfFunctionTableEntries - 1;
  393. FunctionTable = FunctionTableEntries;
  394. //
  395. // Perform binary search on the function table for a function table
  396. // entry that subsumes the specified PC.
  397. //
  398. while (High >= Low) {
  399. //
  400. // Compute next probe index and test entry. If the specified PC
  401. // is greater than of equal to the beginning address and less
  402. // than the ending address of the function table entry, then
  403. // return the address of the function table entry. Otherwise,
  404. // continue the search.
  405. //
  406. Middle = (Low + High) >> 1;
  407. FunctionEntry = &FunctionTable[Middle];
  408. if ((ULONG)EntryPointAddress < FunctionEntry->BeginAddress) {
  409. High = Middle - 1;
  410. } else if ((ULONG)EntryPointAddress >= FunctionEntry->EndAddress) {
  411. Low = Middle + 1;
  412. } else {
  413. break;
  414. }
  415. }
  416. //
  417. // A function table entry for the specified PC was not found. Just use
  418. // the exported address and hope for the best.
  419. //
  420. return EntryPointAddress;
  421. }
  422. BOOLEAN
  423. LoadDriveLetterDefinitions( VOID )
  424. {
  425. PVOID Buffer;
  426. ULONG BufferSize;
  427. ULONG cchDeviceName;
  428. ULONG cch;
  429. ULONG cchTargetPath;
  430. PWSTR DeviceName;
  431. PWSTR TargetPath;
  432. ULONG DriveLetterIndex;
  433. ULONG cb;
  434. PDRIVE_LETTER_INFO p;
  435. RtlInitUnicodeString( &AltDriveLetterPrefix, L"\\DosDevices\\" );
  436. RtlInitUnicodeString( &DriveLetterPrefix, L"\\??\\" );
  437. RtlInitUnicodeString( &UNCPrefix, L"UNC\\" );
  438. BufferSize = 0x1000;
  439. Buffer = VirtualAlloc( NULL, BufferSize, MEM_COMMIT, PAGE_READWRITE );
  440. if (Buffer == NULL) {
  441. DbgEvent( INTERNALERROR, ( "VirtualAlloc( %0x8 ) failed (%u)\n", BufferSize, GetLastError() ) );
  442. return FALSE;
  443. }
  444. cchTargetPath = BufferSize / sizeof( WCHAR );
  445. cchDeviceName = QueryDosDeviceW( NULL,
  446. Buffer,
  447. cchTargetPath
  448. );
  449. if (cchDeviceName == 0) {
  450. DbgEvent( INTERNALERROR, ( "QueryDosDeviceW( NULL ) failed (%u)\n", GetLastError() ) );
  451. return FALSE;
  452. }
  453. cchTargetPath -= (cchDeviceName + 2);
  454. DeviceName = Buffer;
  455. TargetPath = DeviceName + 2 + cchDeviceName;
  456. while (*DeviceName) {
  457. if (wcslen( DeviceName ) == 2 &&
  458. DeviceName[ 1 ] == L':' &&
  459. _wcsupr( DeviceName ) &&
  460. DeviceName[ 0 ] >= L'@' &&
  461. DeviceName[ 0 ] <= L'_'
  462. ) {
  463. cch = QueryDosDeviceW( DeviceName, TargetPath, cchTargetPath );
  464. if (cch == 0) {
  465. DbgEvent( INTERNALERROR, ( "QueryDosDeviceW( %ws ) failed (%u)\n", DeviceName, GetLastError() ) );
  466. return FALSE;
  467. }
  468. DriveLetterIndex = DeviceName[ 0 ] - L'@';
  469. p = &DriveLetters[ DriveLetterIndex ];
  470. p->DriveLetter = (WCHAR)(L'@' + DriveLetterIndex);
  471. cb = (cch+1) * sizeof( WCHAR );
  472. p->NtLinkTarget.Buffer = AllocMem( cb );
  473. if (p->NtLinkTarget.Buffer == NULL) {
  474. return FALSE;
  475. }
  476. MoveMemory( p->NtLinkTarget.Buffer, TargetPath, cb );
  477. p->NtLinkTarget.Length = (USHORT)( cb - sizeof( WCHAR ));
  478. p->NtLinkTarget.MaximumLength = (USHORT)cb;
  479. p->DriveLetterValid = TRUE;
  480. }
  481. while (*DeviceName++) {}
  482. }
  483. return TRUE;
  484. }
  485. BOOLEAN
  486. IsDriveLetterPath(
  487. PUNICODE_STRING Path
  488. )
  489. {
  490. ULONG DriveLetterIndex;
  491. PDRIVE_LETTER_INFO p;
  492. PUNICODE_STRING Prefix;
  493. if (RtlPrefixUnicodeString( Prefix = &DriveLetterPrefix, Path, TRUE ) ||
  494. RtlPrefixUnicodeString( Prefix = &AltDriveLetterPrefix, Path, TRUE ) ) {
  495. Path->Length -= Prefix->Length;
  496. RtlMoveMemory( Path->Buffer,
  497. (PCHAR)(Path->Buffer) + Prefix->Length,
  498. Path->Length + sizeof( UNICODE_NULL )
  499. );
  500. if (RtlPrefixUnicodeString( &UNCPrefix, Path, TRUE )) {
  501. Path->Length -= UNCPrefix.Length;
  502. Path->Buffer[0] = L'\\';
  503. Path->Buffer[1] = L'\\';
  504. RtlMoveMemory( &Path->Buffer[2],
  505. (PCHAR)(Path->Buffer) + UNCPrefix.Length,
  506. Path->Length + sizeof( UNICODE_NULL )
  507. );
  508. Path->Length += 2 * sizeof( WCHAR );
  509. }
  510. return TRUE;
  511. }
  512. for (DriveLetterIndex=0, p = &DriveLetters[ DriveLetterIndex ];
  513. DriveLetterIndex<32;
  514. DriveLetterIndex++, p++
  515. )
  516. {
  517. if (p->DriveLetterValid &&
  518. RtlPrefixUnicodeString( &p->NtLinkTarget, Path, TRUE )
  519. )
  520. {
  521. Path->Length -= p->NtLinkTarget.Length;
  522. RtlMoveMemory( &Path->Buffer[ 2 ],
  523. (PCHAR)(Path->Buffer) + p->NtLinkTarget.Length,
  524. Path->Length + sizeof( UNICODE_NULL )
  525. );
  526. Path->Buffer[ 0 ] = p->DriveLetter;
  527. Path->Buffer[ 1 ] = L':';
  528. Path->Length += 2;
  529. return TRUE;
  530. }
  531. }
  532. return FALSE;
  533. }
  534. VOID
  535. TrimTemporaryBuffer( VOID )
  536. {
  537. PVOID CommitAddress;
  538. if (TemporaryBufferLength == 0) {
  539. return;
  540. }
  541. if (VirtualFree( (PCHAR)TemporaryBuffer,
  542. TemporaryBufferLength,
  543. MEM_DECOMMIT
  544. )
  545. )
  546. {
  547. TemporaryBufferLength = 0;
  548. }
  549. return;
  550. }
  551. BOOLEAN
  552. GrowTemporaryBuffer(
  553. ULONG NeededSize
  554. )
  555. {
  556. PVOID CommitAddress;
  557. if (NeededSize <= TemporaryBufferLength) {
  558. return TRUE;
  559. }
  560. if (TemporaryBufferLength == TemporaryBufferMaximumLength) {
  561. return FALSE;
  562. }
  563. CommitAddress = VirtualAlloc( (PCHAR)TemporaryBuffer + TemporaryBufferLength,
  564. NeededSize - TemporaryBufferLength,
  565. MEM_COMMIT,
  566. PAGE_READWRITE
  567. );
  568. if (CommitAddress == NULL) {
  569. DbgEvent( INTERNALERROR, ( "VirtualAlloc( %0x8 ) failed (%u)\n",
  570. NeededSize - TemporaryBufferLength,
  571. GetLastError()
  572. )
  573. );
  574. return FALSE;
  575. }
  576. TemporaryBufferLength += TemporaryBufferLengthGrowth;
  577. return TRUE;
  578. }
  579. ULONG
  580. FillTemporaryBuffer(
  581. PPROCESS_INFO Process,
  582. PVOID Address,
  583. BOOLEAN Unicode,
  584. BOOLEAN DoubleNullTermination
  585. )
  586. {
  587. ULONG BytesRead;
  588. ULONG TotalBytesRead;
  589. PVOID Source;
  590. PVOID Destination;
  591. LPSTR s1;
  592. PWSTR s2;
  593. BOOLEAN MoreToRead;
  594. BOOLEAN SeenOneNull;
  595. TotalBytesRead = 0;
  596. Destination = (PCHAR)TemporaryBuffer;
  597. MoreToRead = TRUE;
  598. SeenOneNull = FALSE;
  599. while (MoreToRead) {
  600. TotalBytesRead += TemporaryBufferLengthGrowth;
  601. if (!GrowTemporaryBuffer( TotalBytesRead )) {
  602. return 0;
  603. }
  604. Source = Destination;
  605. BytesRead = 0;
  606. if (!ReadProcessMemory( Process->Handle,
  607. Address,
  608. Destination,
  609. TemporaryBufferLengthGrowth,
  610. &BytesRead
  611. )
  612. )
  613. {
  614. if (BytesRead == 0) {
  615. MoreToRead = FALSE;
  616. } else {
  617. return 0;
  618. }
  619. }
  620. Destination = (PCHAR)Destination + TotalBytesRead;
  621. if (Unicode) {
  622. s2 = (PWSTR)Source;
  623. while (s2 < (PWSTR)Destination) {
  624. if (*s2 == UNICODE_NULL) {
  625. if (SeenOneNull || !DoubleNullTermination) {
  626. return (PCHAR)s2 - (PCHAR)TemporaryBuffer;
  627. } else {
  628. SeenOneNull = TRUE;
  629. }
  630. } else {
  631. SeenOneNull = FALSE;
  632. }
  633. s2++;
  634. }
  635. } else {
  636. s1 = (LPSTR)Source;
  637. while (s1 < (LPSTR)Destination) {
  638. if (*s1 == '\0') {
  639. if (SeenOneNull || !DoubleNullTermination) {
  640. return (PCHAR)s1 - (PCHAR)TemporaryBuffer;
  641. } else {
  642. SeenOneNull = TRUE;
  643. }
  644. } else {
  645. SeenOneNull = FALSE;
  646. }
  647. s1++;
  648. }
  649. }
  650. }
  651. return 0;
  652. }