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.

2358 lines
57 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. stat.c
  5. Abstract:
  6. Pentium stat driver.
  7. Author:
  8. Ken Reneris
  9. Environment:
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include "stdarg.h"
  14. #include "stdio.h"
  15. #define _NTDDK_
  16. #include "ntos.h" // *** USES INTERNAL DEFINES ***
  17. #include "..\..\pstat.h"
  18. #include "stat.h"
  19. #include "zwapi.h"
  20. typedef
  21. VOID
  22. (*pHalProfileInterrupt) (
  23. KPROFILE_SOURCE ProfileSource
  24. );
  25. //
  26. // Global data (not in device extension)
  27. //
  28. //
  29. // stats
  30. //
  31. PACCUMULATORS StatProcessorAccumulators[MAXIMUM_PROCESSORS];
  32. ACCUMULATORS StatGlobalAccumulators [MAXIMUM_PROCESSORS];
  33. PKPCR KiProcessorControlRegister [MAXIMUM_PROCESSORS];
  34. //
  35. // hooked thunks
  36. //
  37. ULONG KeUpdateSystemTimeThunk;
  38. ULONG KeUpdateRunTimeThunk;
  39. pHalProfileInterrupt HaldStartProfileInterrupt;
  40. pHalProfileInterrupt HaldStopProfileInterrupt;
  41. pHalQuerySystemInformation HaldQuerySystemInformation;
  42. pHalSetSystemInformation HaldSetSystemInformation;
  43. //
  44. // hardware control
  45. //
  46. ULONG NoCESR;
  47. ULONG MsrCESR;
  48. ULONG MsrCount;
  49. #define MsrTSC 0x10
  50. #define NoCount 2
  51. ULONG CESR[MAX_EVENTS];
  52. ULONG EventID[MAX_EVENTS];
  53. FAST_MUTEX HookLock;
  54. ULONG StatMaxThunkCounter;
  55. LIST_ENTRY HookedThunkList;
  56. LIST_ENTRY LazyFreeList;
  57. ULONG LazyFreeCountdown;
  58. KTIMER LazyFreeTimer;
  59. KDPC LazyFreeDpc;
  60. WORK_QUEUE_ITEM LazyFreePoolWorkItem;
  61. extern COUNTED_EVENTS P5Events[];
  62. extern COUNTED_EVENTS P6Events[];
  63. ULONG MaxEvent;
  64. PCOUNTED_EVENTS Events;
  65. ULONG ProcType;
  66. #define GENERIC_X86 0
  67. #define INTEL_P5 1
  68. #define INTEL_P6 2
  69. //
  70. // Profile support
  71. //
  72. #define PROFILE_SOURCE_BASE 0x1000
  73. typedef struct {
  74. ULONG CESR;
  75. KPROFILE_SOURCE Source;
  76. ULONGLONG InitialCount;
  77. } PROFILE_EVENT, *PPROFILE_EVENT;
  78. BOOLEAN DisableRDPMC;
  79. BOOLEAN ProfileSupported;
  80. PPROFILE_EVENT ProfileEvents, CurrentProfileEvent;
  81. ULONGLONG FASTCALL RDMSR(ULONG);
  82. VOID WRMSR(ULONG, ULONGLONG);
  83. VOID StatSystemTimeHook(VOID);
  84. VOID StatRunTimeHook(VOID);
  85. VOID SystemTimeHook(VOID);
  86. VOID RunTimeHook(VOID);
  87. PKPCR CurrentPcr(VOID);
  88. ULONG GetCR4(VOID);
  89. VOID SetCR4(ULONG);
  90. NTSTATUS
  91. DriverEntry(
  92. IN PDRIVER_OBJECT DriverObject,
  93. IN PUNICODE_STRING RegistryPath
  94. );
  95. NTSTATUS
  96. StatDeviceControl(
  97. IN PDEVICE_OBJECT DeviceObject,
  98. IN PIRP Irp
  99. );
  100. NTSTATUS
  101. StatQueryEvents (
  102. ULONG Index,
  103. PEVENTID Buffer,
  104. ULONG Length
  105. );
  106. NTSTATUS
  107. StatQueryEventsInfo (
  108. PEVENTS_INFO Buffer,
  109. ULONG Length
  110. );
  111. NTSTATUS
  112. StatHookGenericThunk (
  113. IN PHOOKTHUNK Buffer
  114. );
  115. VOID
  116. StatRemoveGenericHook (
  117. IN PULONG pTracerId
  118. );
  119. NTSTATUS
  120. StatOpen(
  121. IN PDEVICE_OBJECT DeviceObject,
  122. IN PIRP Irp
  123. );
  124. NTSTATUS
  125. StatClose(
  126. IN PDEVICE_OBJECT DeviceObject,
  127. IN PIRP Irp
  128. );
  129. BOOLEAN
  130. StatHookTimer (VOID);
  131. VOID StatReadStats (PULONG Buffer);
  132. VOID StatSetCESR (PSETEVENT);
  133. ULONG StatGetP5CESR (PSETEVENT);
  134. ULONG StatGetP6CESR (PSETEVENT, BOOLEAN);
  135. VOID RemoveAllHookedThunks (VOID);
  136. VOID FASTCALL TimerHook (ULONG p);
  137. VOID FASTCALL TimerHook (ULONG p);
  138. VOID SetMaxThunkCounter (VOID);
  139. VOID RemoveAllHookedThunks (VOID);
  140. VOID LazyFreePoolDPC (PKDPC, PVOID, PVOID, PVOID);
  141. VOID LazyFreePool (PVOID);
  142. VOID
  143. StatEnableRDPMC(
  144. );
  145. PPROFILE_EVENT
  146. StatProfileEvent (
  147. KPROFILE_SOURCE Source
  148. );
  149. VOID
  150. StatStartProfileInterrupt (
  151. KPROFILE_SOURCE Source
  152. );
  153. VOID
  154. StatStopProfileInterrupt (
  155. KPROFILE_SOURCE Source
  156. );
  157. NTSTATUS
  158. FASTCALL
  159. StatProfileInterrupt (
  160. IN PKTRAP_FRAME TrapFrame
  161. );
  162. NTSTATUS
  163. StatQuerySystemInformation(
  164. IN HAL_QUERY_INFORMATION_CLASS InformationClass,
  165. IN ULONG BufferSize,
  166. OUT PVOID Buffer,
  167. OUT PULONG ReturnedLength
  168. );
  169. NTSTATUS
  170. StatSetSystemInformation(
  171. IN HAL_SET_INFORMATION_CLASS InformationClass,
  172. IN ULONG BufferSize,
  173. IN PVOID Buffer
  174. );
  175. VOID
  176. CreateHook (
  177. IN PVOID HookCode,
  178. IN PVOID HookAddress,
  179. IN ULONG HitCounters,
  180. IN ULONG HookType
  181. );
  182. NTSTATUS
  183. openfile (
  184. IN PHANDLE FileHandle,
  185. IN PUCHAR BasePath,
  186. IN PUCHAR Name
  187. );
  188. VOID
  189. readfile (
  190. HANDLE handle,
  191. ULONG offset,
  192. ULONG len,
  193. PVOID buffer
  194. );
  195. ULONG
  196. ImportThunkAddress (
  197. IN PUCHAR SourceModule,
  198. IN ULONG_PTR ImageBase,
  199. IN PUCHAR ImportModule,
  200. IN PUCHAR ThunkName,
  201. IN PVOID ModuleList
  202. );
  203. ULONG
  204. ImportThunkAddressModule (
  205. IN PRTL_PROCESS_MODULE_INFORMATION SourceModule,
  206. IN PUCHAR ImportModule,
  207. IN PUCHAR ThunkName
  208. );
  209. ULONG
  210. ImportThunkAddressProcessFile(
  211. IN ULONG_PTR ImageBase,
  212. IN HANDLE FileHandle,
  213. IN PUCHAR ImportModule,
  214. IN PUCHAR ThunkName
  215. );
  216. ULONG_PTR
  217. LookupImageBase (
  218. IN PUCHAR SourceModule,
  219. IN PVOID ModuleList
  220. );
  221. ULONG
  222. ConvertImportAddress (
  223. IN ULONG ImageRelativeAddress,
  224. IN ULONG PoolAddress,
  225. IN PIMAGE_SECTION_HEADER SectionHeader
  226. );
  227. #if 0
  228. PRTL_PROCESS_MODULE_INFORMATION
  229. GetModuleInformationFuzzy(
  230. IN PUCHAR StartsWith,
  231. IN PUCHAR EndsWith,
  232. IN PRTL_PROCESS_MODULES Modules
  233. );
  234. #endif
  235. VOID
  236. FASTCALL
  237. NakedCallToKeProfileInterruptWithSource(
  238. IN PKTRAP_FRAME TrapFrame,
  239. IN KPROFILE_SOURCE Source
  240. );
  241. PVOID
  242. GetLoadedModuleList(
  243. VOID
  244. );
  245. #ifdef ALLOC_PRAGMA
  246. #pragma alloc_text(INIT,DriverEntry)
  247. #pragma alloc_text(INIT,StatHookTimer)
  248. #pragma alloc_text(PAGE,StatDeviceControl)
  249. #pragma alloc_text(PAGE,StatOpen)
  250. #pragma alloc_text(PAGE,StatClose)
  251. #pragma alloc_text(PAGE,StatReadStats)
  252. #pragma alloc_text(PAGE,StatSetCESR)
  253. #pragma alloc_text(PAGE,StatGetP5CESR)
  254. #pragma alloc_text(PAGE,StatGetP6CESR)
  255. #pragma alloc_text(PAGE,StatDeviceControl)
  256. #pragma alloc_text(PAGE,StatQueryEvents)
  257. #pragma alloc_text(PAGE,ImportThunkAddress)
  258. #pragma alloc_text(PAGE,ImportThunkAddressModule)
  259. #pragma alloc_text(PAGE,ImportThunkAddressProcessFile)
  260. #pragma alloc_text(PAGE,StatHookGenericThunk)
  261. #pragma alloc_text(PAGE,StatRemoveGenericHook)
  262. #pragma alloc_text(PAGE,SetMaxThunkCounter)
  263. #pragma alloc_text(PAGE,LazyFreePool)
  264. #pragma alloc_text(PAGE,StatQuerySystemInformation)
  265. #pragma alloc_text(PAGE,StatSetSystemInformation)
  266. #pragma alloc_text(PAGE,openfile)
  267. #pragma alloc_text(PAGE,readfile)
  268. #pragma alloc_text(PAGE,LookupImageBase)
  269. #pragma alloc_text(PAGE,ConvertImportAddress)
  270. #pragma alloc_text(PAGE,StatEnableRDPMC)
  271. #pragma alloc_text(PAGE,GetLoadedModuleList)
  272. #endif
  273. VOID
  274. StatEnableRDPMC()
  275. {
  276. ULONG Cr4;
  277. PKPRCB Prcb;
  278. Prcb = CurrentPcr()->Prcb;
  279. if (strcmp(Prcb->VendorString, "GenuineIntel") == 0) {
  280. //
  281. // Profiling only supported on family 6 or above.
  282. //
  283. if (Prcb->CpuType < 6) {
  284. DisableRDPMC = TRUE;
  285. return;
  286. }
  287. //
  288. // Check for busted parts. Anything below stepping 6,1,9
  289. // is subject to errata 26 which says RDPMC cannot be used
  290. // with SMM. As we have know way of knowing if SMM is in
  291. // use (but it probably is), we must disable on those chips.
  292. //
  293. if ((Prcb->CpuType == 6) &&
  294. (Prcb->CpuStep < 0x0109)) {
  295. DisableRDPMC = TRUE;
  296. return;
  297. }
  298. //
  299. // This processor is believed to be able to handle RDPMC
  300. // from user mode. Enable it by setting CR4.PCE (bit 8).
  301. //
  302. Cr4 = GetCR4();
  303. Cr4 |= 0x100;
  304. SetCR4(Cr4);
  305. }
  306. }
  307. NTSTATUS
  308. DriverEntry(
  309. IN PDRIVER_OBJECT DriverObject,
  310. IN PUNICODE_STRING RegistryPath
  311. )
  312. /*++
  313. Routine Description:
  314. This routine initializes the stat driver.
  315. Arguments:
  316. DriverObject - Pointer to driver object created by system.
  317. RegistryPath - Pointer to the Unicode name of the registry path
  318. for this driver.
  319. Return Value:
  320. The function value is the final status from the initialization operation.
  321. --*/
  322. {
  323. UNICODE_STRING unicodeString;
  324. PDEVICE_OBJECT deviceObject;
  325. NTSTATUS status;
  326. ULONG i;
  327. KdPrint(( "STAT: DriverEntry()\n" ));
  328. //
  329. // Create non-exclusive device object for beep device.
  330. //
  331. RtlInitUnicodeString(&unicodeString, L"\\Device\\PStat");
  332. status = IoCreateDevice(
  333. DriverObject,
  334. 0,
  335. &unicodeString,
  336. FILE_DEVICE_UNKNOWN, // DeviceType
  337. 0,
  338. FALSE,
  339. &deviceObject
  340. );
  341. if (status != STATUS_SUCCESS) {
  342. KdPrint(( "Stat - DriverEntry: unable to create device object: %X\n", status ));
  343. return(status);
  344. }
  345. deviceObject->Flags |= DO_BUFFERED_IO;
  346. //
  347. // Set up the device driver entry points.
  348. //
  349. DriverObject->MajorFunction[IRP_MJ_CREATE] = StatOpen;
  350. DriverObject->MajorFunction[IRP_MJ_CLOSE] = StatClose;
  351. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = StatDeviceControl;
  352. //
  353. // Initialize globals
  354. //
  355. for (i = 0; i < MAXIMUM_PROCESSORS; i++) {
  356. StatProcessorAccumulators[i] =
  357. &StatGlobalAccumulators[i];
  358. }
  359. ExInitializeFastMutex (&HookLock);
  360. KeInitializeDpc (&LazyFreeDpc, LazyFreePoolDPC, 0);
  361. ExInitializeWorkItem (&LazyFreePoolWorkItem, LazyFreePool, NULL)
  362. KeInitializeTimer (&LazyFreeTimer);
  363. if (strcmp (CurrentPcr()->Prcb->VendorString, "GenuineIntel") == 0) {
  364. switch (CurrentPcr()->Prcb->CpuType) {
  365. case 5:
  366. NoCESR = 1;
  367. MsrCESR = 0x11;
  368. MsrCount = 0x12;
  369. Events = P5Events;
  370. ProcType = INTEL_P5;
  371. ProfileSupported = FALSE;
  372. DisableRDPMC = TRUE;
  373. break;
  374. case 6:
  375. NoCESR = 2;
  376. MsrCESR = 0x186;
  377. MsrCount = 0xc1;
  378. Events = P6Events;
  379. ProcType = INTEL_P6;
  380. ProfileSupported = TRUE;
  381. DisableRDPMC = FALSE;
  382. break;
  383. }
  384. }
  385. if (Events) {
  386. while (Events[MaxEvent].Description) {
  387. MaxEvent += 1;
  388. }
  389. }
  390. if (ProfileSupported) {
  391. i = (ULONG) StatProfileInterrupt;
  392. status = HalSetSystemInformation (
  393. HalProfileSourceInterruptHandler,
  394. sizeof (i),
  395. &i
  396. );
  397. if (!NT_SUCCESS(status)) {
  398. // hal did not support hooking the performance interrupt
  399. ProfileSupported = FALSE;
  400. }
  401. }
  402. if (ProfileSupported) {
  403. //
  404. // Allocate ProfileEvents
  405. //
  406. ProfileEvents = ExAllocatePool (NonPagedPool, sizeof (PROFILE_EVENT) * MaxEvent);
  407. if (!ProfileEvents) {
  408. ProfileSupported = FALSE;
  409. } else {
  410. RtlZeroMemory (ProfileEvents, sizeof (PROFILE_EVENT) * MaxEvent);
  411. }
  412. }
  413. if (!StatHookTimer()) {
  414. IoDeleteDevice(DriverObject->DeviceObject);
  415. return STATUS_UNSUCCESSFUL;
  416. }
  417. InitializeListHead (&HookedThunkList);
  418. InitializeListHead (&LazyFreeList);
  419. return(STATUS_SUCCESS);
  420. }
  421. NTSTATUS
  422. StatDeviceControl(
  423. IN PDEVICE_OBJECT DeviceObject,
  424. IN PIRP Irp
  425. )
  426. /*++
  427. Routine Description:
  428. This routine is the dispatch routine for device control requests.
  429. Arguments:
  430. DeviceObject - Pointer to class device object.
  431. Irp - Pointer to the request packet.
  432. Return Value:
  433. Status is returned.
  434. --*/
  435. {
  436. PIO_STACK_LOCATION irpSp;
  437. NTSTATUS status;
  438. ULONG BufferLength;
  439. PULONG Buffer;
  440. //
  441. // Get a pointer to the current parameters for this request. The
  442. // information is contained in the current stack location.
  443. //
  444. irpSp = IoGetCurrentIrpStackLocation(Irp);
  445. //
  446. // Case on the device control subfunction that is being performed by the
  447. // requestor.
  448. //
  449. status = STATUS_SUCCESS;
  450. try {
  451. Buffer = (PULONG) irpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  452. BufferLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  453. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  454. case PSTAT_READ_STATS:
  455. //
  456. // read stats
  457. //
  458. StatReadStats (Buffer);
  459. break;
  460. case PSTAT_SET_CESR:
  461. //
  462. // Set MSRs to collect stats
  463. //
  464. StatSetCESR ((PSETEVENT) Buffer);
  465. break;
  466. case PSTAT_HOOK_THUNK:
  467. //
  468. // Hook an import entry point
  469. //
  470. status = StatHookGenericThunk ((PHOOKTHUNK) Buffer);
  471. break;
  472. case PSTAT_REMOVE_HOOK:
  473. //
  474. // Remove a hook from an entry point
  475. //
  476. StatRemoveGenericHook (Buffer);
  477. break;
  478. case PSTAT_QUERY_EVENTS:
  479. //
  480. // Query possible stats which can be collected
  481. //
  482. status = StatQueryEvents (*Buffer, (PEVENTID) Buffer, BufferLength);
  483. break;
  484. case PSTAT_QUERY_EVENTS_INFO:
  485. //
  486. // Query events info
  487. //
  488. status = StatQueryEventsInfo( (PEVENTS_INFO) Buffer, BufferLength );
  489. break;
  490. default:
  491. status = STATUS_INVALID_PARAMETER;
  492. break;
  493. }
  494. } except(EXCEPTION_EXECUTE_HANDLER) {
  495. status = GetExceptionCode();
  496. }
  497. //
  498. // Request is done...
  499. //
  500. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  501. return(status);
  502. }
  503. NTSTATUS
  504. StatOpen(
  505. IN PDEVICE_OBJECT DeviceObject,
  506. IN PIRP Irp
  507. )
  508. {
  509. PAGED_CODE();
  510. //
  511. // Complete the request and return status.
  512. //
  513. Irp->IoStatus.Status = STATUS_SUCCESS;
  514. Irp->IoStatus.Information = 0;
  515. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  516. return(STATUS_SUCCESS);
  517. }
  518. NTSTATUS
  519. StatClose(
  520. IN PDEVICE_OBJECT DeviceObject,
  521. IN PIRP Irp
  522. )
  523. {
  524. PAGED_CODE();
  525. //
  526. // Complete the request and return status.
  527. //
  528. RemoveAllHookedThunks ();
  529. Irp->IoStatus.Status = STATUS_SUCCESS;
  530. Irp->IoStatus.Information = 0;
  531. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  532. return(STATUS_SUCCESS);
  533. }
  534. #if 0
  535. VOID
  536. StatUnload (
  537. IN PDRIVER_OBJECT DriverObject
  538. )
  539. {
  540. PDEVICE_OBJECT deviceObject;
  541. PAGED_CODE();
  542. RemoveAllHookedThunks ();
  543. KeCancelTimer (&LazyFreeTimer);
  544. LazyFreePool (NULL);
  545. //
  546. // Restore hooked addresses
  547. //
  548. *((PULONG) HalThunkForKeUpdateSystemTime) = KeUpdateSystemTimeThunk;
  549. if (HalThunkForKeUpdateRunTime) {
  550. *((PULONG) HalThunkForKeUpdateRunTime) = KeUpdateRunTimeThunk;
  551. }
  552. //
  553. // Delete the device object.
  554. //
  555. IoDeleteDevice(DriverObject->DeviceObject);
  556. return;
  557. }
  558. #endif
  559. VOID
  560. StatReadStats (PULONG Buffer)
  561. {
  562. PACCUMULATORS Accum;
  563. ULONG i, r1;
  564. pPSTATS Inf;
  565. PKPCR Pcr;
  566. PAGED_CODE();
  567. Buffer[0] = sizeof (PSTATS);
  568. Inf = (pPSTATS)(Buffer + 1);
  569. for (i = 0; i < MAXIMUM_PROCESSORS; i++, Inf++) {
  570. Pcr = KiProcessorControlRegister[i];
  571. if (Pcr == NULL) {
  572. continue;
  573. }
  574. Accum = StatProcessorAccumulators[i];
  575. do {
  576. r1 = Accum->CountStart;
  577. Inf->TSC = Accum->TSC;
  578. for (i=0; i < MAX_EVENTS; i++) {
  579. Inf->Counters[i] = Accum->Counters[i];
  580. Inf->EventId[i] = EventID[i];
  581. }
  582. Inf->SpinLockAcquires = Pcr->KernelReserved[0];
  583. Inf->SpinLockCollisions = Pcr->KernelReserved[1];
  584. Inf->SpinLockSpins = Pcr->KernelReserved[2];
  585. Inf->Irqls = Pcr->KernelReserved[3];
  586. } while (r1 != Accum->CountEnd);
  587. RtlMoveMemory (Inf->ThunkCounters, (CONST VOID *)(Accum->ThunkCounters),
  588. StatMaxThunkCounter * sizeof (ULONG));
  589. }
  590. }
  591. NTSTATUS
  592. StatQueryEvents (
  593. ULONG Index,
  594. PEVENTID Buffer,
  595. ULONG Length
  596. )
  597. {
  598. ULONG i;
  599. if (Index >= MaxEvent) {
  600. return STATUS_NO_MORE_ENTRIES;
  601. }
  602. i = sizeof (EVENTID) +
  603. strlen(Events[Index].Token) + 1 +
  604. strlen(Events[Index].Description) + 1;
  605. if (Length < i) {
  606. return STATUS_BUFFER_TOO_SMALL;
  607. }
  608. memset (Buffer, 0, i);
  609. Buffer->EventId = Events[Index].Encoding;
  610. Buffer->DescriptionOffset = strlen (Events[Index].Token) + 1;
  611. Buffer->SuggestedIntervalBase = Events[Index].SuggestedIntervalBase;
  612. strcpy (Buffer->Buffer, Events[Index].Token);
  613. strcpy (Buffer->Buffer + Buffer->DescriptionOffset, Events[Index].Description);
  614. if (ProfileSupported) {
  615. Buffer->ProfileSource = PROFILE_SOURCE_BASE + Index;
  616. }
  617. return STATUS_SUCCESS;
  618. }
  619. NTSTATUS
  620. StatQueryEventsInfo (
  621. PEVENTS_INFO Buffer,
  622. ULONG Length
  623. )
  624. {
  625. size_t maxLenToken, maxLenOfficialToken;
  626. size_t maxLenDescription, maxLenOfficialDescription;
  627. PAGED_CODE();
  628. if ( Length < sizeof(*Buffer) ) {
  629. return STATUS_INVALID_PARAMETER;
  630. }
  631. maxLenToken = maxLenOfficialToken = 0;
  632. maxLenDescription = maxLenOfficialDescription = 0;
  633. if ( MaxEvent ) {
  634. ULONG i;
  635. size_t len;
  636. for ( i = 0; i < MaxEvent; i++ ) {
  637. len = ( Events[i].Token ) ? strlen( Events[i].Token ) : 0;
  638. if ( len > maxLenToken ) {
  639. maxLenToken = len;
  640. }
  641. len = ( Events[i].OfficialToken ) ? strlen( Events[i].OfficialToken ) : 0;
  642. if ( len > maxLenToken ) {
  643. maxLenOfficialToken = len;
  644. }
  645. len = ( Events[i].Description ) ? strlen( Events[i].Description ) : 0;
  646. if ( len > maxLenDescription ) {
  647. maxLenDescription = len;
  648. }
  649. len = ( Events[i].OfficialDescription ) ? strlen( Events[i].OfficialDescription ) : 0;
  650. if ( len > maxLenOfficialDescription ) {
  651. maxLenOfficialDescription = len;
  652. }
  653. }
  654. }
  655. Buffer->Events = MaxEvent;
  656. Buffer->TokenMaxLength = maxLenToken;
  657. Buffer->DescriptionMaxLength = maxLenDescription;
  658. Buffer->OfficialTokenMaxLength = maxLenOfficialToken;
  659. Buffer->OfficialDescriptionMaxLength = maxLenOfficialDescription;
  660. return STATUS_SUCCESS;
  661. } // StatQueryEventsInfo()
  662. ULONG
  663. StatGetP5CESR (
  664. PSETEVENT NewEvent
  665. )
  666. {
  667. ULONG NewCESR;
  668. if (!NewEvent->Active) {
  669. return 0;
  670. }
  671. NewCESR = NewEvent->EventId & 0x3f;
  672. NewCESR |= NewEvent->UserMode ? 0x80 : 0;
  673. NewCESR |= NewEvent->KernelMode ? 0x40 : 0;
  674. return NewCESR;
  675. }
  676. ULONG
  677. StatGetP6CESR (
  678. PSETEVENT NewEvent,
  679. BOOLEAN Profile
  680. )
  681. {
  682. ULONG NewCESR;
  683. NewCESR = NewEvent->EventId & 0xffff;
  684. NewCESR |= NewEvent->Active ? (1 << 22) : 0;
  685. NewCESR |= NewEvent->UserMode ? (1 << 16) : 0;
  686. NewCESR |= NewEvent->KernelMode ? (1 << 17) : 0;
  687. NewCESR |= NewEvent->EdgeDetect ? (1 << 18) : 0;
  688. NewCESR |= Profile ? (1 << 20) : 0;
  689. return NewCESR;
  690. }
  691. VOID
  692. StatSetCESR (
  693. PSETEVENT NewEvent
  694. )
  695. {
  696. ULONG i, j, NoProc;
  697. ULONG NewCESR[MAX_EVENTS];
  698. PAGED_CODE();
  699. switch (ProcType) {
  700. case INTEL_P5:
  701. NewCESR[0] = StatGetP5CESR(NewEvent+0);
  702. NewCESR[0] |= StatGetP5CESR(NewEvent+1) << 16;
  703. break;
  704. case INTEL_P6:
  705. NewCESR[0] = StatGetP6CESR(NewEvent+0, FALSE);
  706. NewCESR[1] = StatGetP6CESR(NewEvent+1, FALSE);
  707. break;
  708. }
  709. //
  710. // Check if CESR changed
  711. //
  712. for (i=0; i < NoCESR; i++) {
  713. if (NewCESR[i] != CESR[i]) {
  714. break;
  715. }
  716. }
  717. if (i == NoCESR) {
  718. // no change, all done
  719. return;
  720. }
  721. //
  722. // Set new events
  723. //
  724. for (i=0; i < MAX_EVENTS; i++) {
  725. EventID[i] = NewEvent[i].EventId;
  726. }
  727. //
  728. // Set new CESR values
  729. //
  730. for (i=0; i < NoCESR; i++) {
  731. CESR[i] = NewCESR[i];
  732. }
  733. //
  734. // Clear each processors Pcr pointer so they will reset.
  735. // Also count how many processors there are.
  736. //
  737. for (i = 0, NoProc = 0; i < MAXIMUM_PROCESSORS; i++) {
  738. if (KiProcessorControlRegister[i]) {
  739. KiProcessorControlRegister[i] = NULL;
  740. NoProc++;
  741. }
  742. }
  743. //
  744. // wait for each processor to get the new Pcr value
  745. //
  746. do {
  747. //Sleep (0); // yield
  748. j = 0;
  749. for (i = 0; i < MAXIMUM_PROCESSORS; i++) {
  750. if (KiProcessorControlRegister[i]) {
  751. j++;
  752. }
  753. }
  754. } while (j < NoProc);
  755. }
  756. VOID
  757. FASTCALL
  758. StatTimerHook (
  759. IN ULONG processor
  760. )
  761. {
  762. PACCUMULATORS Total;
  763. ULONG i;
  764. if (KiProcessorControlRegister[processor] == NULL) {
  765. for (i=0; i < NoCESR; i++) {
  766. WRMSR (MsrCESR+i, 0); // clear old CESR
  767. }
  768. for (i=0; i < NoCESR; i++) {
  769. WRMSR (MsrCESR+i, CESR[i]); // write new CESR
  770. }
  771. KiProcessorControlRegister[processor] = CurrentPcr();
  772. //
  773. // Enable RDPMC from Rings 1, 2 and 3.
  774. //
  775. StatEnableRDPMC();
  776. }
  777. Total = StatProcessorAccumulators[ processor ];
  778. Total->CountStart += 1;
  779. for (i=0; i < NoCount; i++) {
  780. Total->Counters[i] = RDMSR(MsrCount+i);
  781. }
  782. Total->TSC = RDMSR(MsrTSC);
  783. Total->CountEnd += 1;
  784. }
  785. VOID
  786. FASTCALL
  787. TimerHook (
  788. IN ULONG processor
  789. )
  790. {
  791. // for compatibility
  792. //
  793. if (KiProcessorControlRegister[processor] == NULL) {
  794. KiProcessorControlRegister[processor] = CurrentPcr();
  795. }
  796. }
  797. PVOID
  798. GetLoadedModuleList(
  799. VOID
  800. )
  801. {
  802. NTSTATUS Status;
  803. ULONG BufferSize;
  804. ULONG NeededSize;
  805. ULONG ModuleNumber;
  806. PRTL_PROCESS_MODULES Modules;
  807. PRTL_PROCESS_MODULE_INFORMATION Module;
  808. //
  809. // 64K should be plenty,... if it isn't we'll come around again.
  810. //
  811. BufferSize = 64000;
  812. while (TRUE) {
  813. Modules = ExAllocatePool (PagedPool, BufferSize);
  814. if (!Modules) {
  815. return NULL;
  816. }
  817. //
  818. // Get system loaded module list.
  819. //
  820. Status = ZwQuerySystemInformation (
  821. SystemModuleInformation,
  822. Modules,
  823. BufferSize,
  824. &NeededSize
  825. );
  826. if (NeededSize > BufferSize) {
  827. //
  828. // Buffer not big enough, try again.
  829. //
  830. ExFreePool(Modules);
  831. BufferSize = NeededSize;
  832. continue;
  833. }
  834. if (!NT_SUCCESS(Status)) {
  835. //
  836. // Not good, give up.
  837. //
  838. ExFreePool(Modules);
  839. return NULL;
  840. }
  841. //
  842. // All is good.
  843. //
  844. break;
  845. }
  846. return Modules;
  847. }
  848. #if 0
  849. PRTL_PROCESS_MODULE_INFORMATION
  850. GetModuleInformationFuzzy(
  851. IN PUCHAR StartsWith,
  852. IN PUCHAR EndsWith,
  853. IN PRTL_PROCESS_MODULES Modules
  854. )
  855. /*++
  856. Routine Description:
  857. Run Down the loaded module list looking for a module
  858. whos name begins with StartWith and ends with EndsWith.
  859. (What's in the middle doesn't matter). This is useful
  860. for finding the kernel and the hal which are of the
  861. form
  862. nt*.exe for the kernel
  863. hal*.dll for the hal.
  864. Arguments:
  865. StartsWith Beginning string match.
  866. EndsWith Ending string match.
  867. ModuleList List of loaded modules.
  868. Returns:
  869. Pointer to the loaded module information for the matching
  870. module or null if no match is found.
  871. --*/
  872. {
  873. ULONG StartLength = 0;
  874. ULONG EndLength = 0;
  875. ULONG ModulesRemaining;
  876. PRTL_PROCESS_MODULE_INFORMATION Module;
  877. PUCHAR FileName;
  878. ULONG FileNameLength;
  879. if (StartsWith) {
  880. StartLength = strlen(StartsWith);
  881. }
  882. if (EndsWith) {
  883. EndLength = strlen(EndsWith);
  884. }
  885. if ((!StartsWith) && (!EndsWith)) {
  886. //
  887. // In theory we could claim this matches anything,.. in reality
  888. // the caller doesn't know what they're doing.
  889. //
  890. return NULL;
  891. }
  892. for (ModulesRemaining = Modules->NumberOfModules, Module = Modules->Modules;
  893. ModulesRemaining;
  894. ModulesRemaining--, Module++) {
  895. FileName = Module->FullPathName + Module->OffsetToFileName;
  896. //
  897. // Check start.
  898. //
  899. if (StartLength) {
  900. if (_strnicmp(FileName, StartsWith, StartLength) != 0) {
  901. //
  902. // No match.
  903. //
  904. continue;
  905. }
  906. }
  907. FileNameLength = strlen(FileName);
  908. if (FileNameLength < (StartLength + EndLength)) {
  909. //
  910. // FileName is too short to contain both strings.
  911. //
  912. continue;
  913. }
  914. if (!EndLength) {
  915. //
  916. // Not checking the end but the start matches, success.
  917. //
  918. return Module;
  919. }
  920. //
  921. // Check end.
  922. //
  923. if (_stricmp(FileName + FileNameLength - EndLength, EndsWith) == 0) {
  924. //
  925. // Tail matches!
  926. //
  927. return Module;
  928. }
  929. }
  930. //
  931. // No match found.
  932. //
  933. return NULL;
  934. }
  935. #endif
  936. BOOLEAN
  937. StatHookTimer (VOID)
  938. {
  939. PULONG Address;
  940. ULONG HalThunkForKeUpdateSystemTime;
  941. ULONG HalThunkForKeUpdateRunTime;
  942. ULONG HalThunkForStartProfileInterrupt;
  943. ULONG HalThunkForStopProfileInterrupt;
  944. PRTL_PROCESS_MODULES ModuleList;
  945. PRTL_PROCESS_MODULE_INFORMATION Kernel;
  946. PRTL_PROCESS_MODULE_INFORMATION Hal;
  947. ModuleList = GetLoadedModuleList();
  948. if (!ModuleList) {
  949. //
  950. // No loaded module list, we aren't going to make much
  951. // progress, give up.
  952. //
  953. return FALSE;
  954. }
  955. #if 0
  956. Kernel = GetModuleInformationFuzzy("nt", ".exe", ModuleList);
  957. Hal = GetModuleInformationFuzzy("hal", ".dll", ModuleList);
  958. if ((!Kernel) || (!Hal)) {
  959. ExFreePool(ModuleList);
  960. return FALSE;
  961. }
  962. #endif
  963. //
  964. // The kernel is always the first entry on the loaded module
  965. // list, the hal is always the second. If this ever changes
  966. // we'll need to come up with another approach.
  967. //
  968. if (ModuleList->NumberOfModules < 2) {
  969. //
  970. // Something's very wrong with this module list.
  971. //
  972. return 0;
  973. }
  974. Kernel = ModuleList->Modules;
  975. Hal = Kernel + 1;
  976. HalThunkForKeUpdateSystemTime =
  977. ImportThunkAddressModule(
  978. Hal,
  979. "ntoskrnl.exe",
  980. "KeUpdateSystemTime"
  981. );
  982. //
  983. // KeUpdateRunTime is not always available.
  984. //
  985. HalThunkForKeUpdateRunTime =
  986. ImportThunkAddressModule(
  987. Hal,
  988. "ntoskrnl.exe",
  989. "KeUpdateRunTime"
  990. );
  991. HalThunkForStartProfileInterrupt =
  992. ImportThunkAddressModule(
  993. Kernel,
  994. "hal.dll",
  995. "HalStartProfileInterrupt"
  996. );
  997. HalThunkForStopProfileInterrupt =
  998. ImportThunkAddressModule(
  999. Kernel,
  1000. "hal.dll",
  1001. "HalStopProfileInterrupt"
  1002. );
  1003. ExFreePool(ModuleList);
  1004. if (!HalThunkForKeUpdateSystemTime ||
  1005. !HalThunkForStartProfileInterrupt ||
  1006. !HalThunkForStopProfileInterrupt) {
  1007. //
  1008. // Imports not found.
  1009. //
  1010. return FALSE;
  1011. }
  1012. //
  1013. // Patch in timer hooks, Read current values
  1014. //
  1015. KeUpdateSystemTimeThunk = *((PULONG) HalThunkForKeUpdateSystemTime);
  1016. if (HalThunkForKeUpdateRunTime) {
  1017. KeUpdateRunTimeThunk = *((PULONG) HalThunkForKeUpdateRunTime);
  1018. }
  1019. HaldStartProfileInterrupt = (pHalProfileInterrupt) *((PULONG) HalThunkForStartProfileInterrupt);
  1020. HaldStopProfileInterrupt = (pHalProfileInterrupt) *((PULONG) HalThunkForStopProfileInterrupt);
  1021. HaldQuerySystemInformation = HalQuerySystemInformation;
  1022. HaldSetSystemInformation = HalSetSystemInformation;
  1023. //
  1024. // Set Stat hook functions
  1025. //
  1026. switch (ProcType) {
  1027. case INTEL_P6:
  1028. case INTEL_P5:
  1029. Address = (PULONG) HalThunkForKeUpdateSystemTime;
  1030. *Address = (ULONG) StatSystemTimeHook;
  1031. if (HalThunkForKeUpdateRunTime) {
  1032. Address = (PULONG) HalThunkForKeUpdateRunTime;
  1033. *Address = (ULONG)StatRunTimeHook;
  1034. }
  1035. if (ProfileSupported) {
  1036. Address = (PULONG) HalThunkForStartProfileInterrupt;
  1037. *Address = (ULONG) StatStartProfileInterrupt;
  1038. Address = (PULONG) HalThunkForStopProfileInterrupt;
  1039. *Address = (ULONG) StatStopProfileInterrupt;
  1040. HalQuerySystemInformation = StatQuerySystemInformation;
  1041. HalSetSystemInformation = StatSetSystemInformation;
  1042. }
  1043. break;
  1044. default:
  1045. Address = (PULONG) HalThunkForKeUpdateSystemTime;
  1046. KdPrint(( "Stat - DriverEntry(5): %X\n", Address ));
  1047. *Address = (ULONG)SystemTimeHook;
  1048. if (HalThunkForKeUpdateRunTime) {
  1049. Address = (PULONG) HalThunkForKeUpdateRunTime;
  1050. KdPrint(( "Stat - DriverEntry(6): %X\n", Address ));
  1051. *Address = (ULONG)RunTimeHook;
  1052. }
  1053. break;
  1054. }
  1055. return TRUE;
  1056. }
  1057. PPROFILE_EVENT
  1058. StatProfileEvent(
  1059. KPROFILE_SOURCE Source
  1060. )
  1061. {
  1062. ULONG Index;
  1063. Index = (ULONG) Source;
  1064. if (Index < PROFILE_SOURCE_BASE) {
  1065. return NULL;
  1066. }
  1067. Index -= PROFILE_SOURCE_BASE;
  1068. if (Index > MaxEvent) {
  1069. return NULL;
  1070. }
  1071. return ProfileEvents + Index;
  1072. }
  1073. VOID
  1074. StatStartProfileInterrupt (
  1075. KPROFILE_SOURCE Source
  1076. )
  1077. {
  1078. ULONG i;
  1079. PPROFILE_EVENT ProfileEvent;
  1080. //
  1081. // If this isn't a profile source we're supporting, pass it on
  1082. //
  1083. ProfileEvent = StatProfileEvent(Source);
  1084. if (!ProfileEvent) {
  1085. HaldStartProfileInterrupt (Source);
  1086. return;
  1087. }
  1088. if (CurrentPcr()->Number == 0) {
  1089. if (!ProfileEvent->Source) {
  1090. return ;
  1091. }
  1092. CurrentProfileEvent = ProfileEvent;
  1093. }
  1094. //
  1095. // Set the CESR
  1096. //
  1097. WRMSR (MsrCESR, ProfileEvent->CESR);
  1098. //
  1099. // Prime the interval counter
  1100. //
  1101. WRMSR (MsrCount, ProfileEvent->InitialCount);
  1102. }
  1103. VOID
  1104. StatStopProfileInterrupt (
  1105. KPROFILE_SOURCE Source
  1106. )
  1107. {
  1108. ULONG i;
  1109. PPROFILE_EVENT ProfileEvent;
  1110. //
  1111. // If this isn't a profile source we're supporting, pass it on
  1112. //
  1113. ProfileEvent = StatProfileEvent(Source);
  1114. if (!ProfileEvent) {
  1115. HaldStopProfileInterrupt (Source);
  1116. return ;
  1117. }
  1118. if (CurrentPcr()->Number == 0) {
  1119. if (ProfileEvent == CurrentProfileEvent) {
  1120. //
  1121. // Stop calling the kernel
  1122. //
  1123. CurrentProfileEvent = NULL;
  1124. }
  1125. }
  1126. }
  1127. // The naked call does not work anymore because the call parameters are not saved
  1128. // (probably due to change in compiler behaviour)
  1129. //_declspec(naked)
  1130. VOID
  1131. FASTCALL
  1132. NakedCallToKeProfileInterruptWithSource(
  1133. IN PKTRAP_FRAME TrapFrame,
  1134. IN KPROFILE_SOURCE Source
  1135. )
  1136. {
  1137. /*
  1138. _asm {
  1139. push ebp ; Save these as KeProfileInterrupt nukes them
  1140. push ebx
  1141. push esi
  1142. push edi
  1143. }
  1144. */
  1145. KeProfileInterruptWithSource (TrapFrame, Source);
  1146. /*
  1147. _asm {
  1148. pop edi
  1149. pop esi
  1150. pop ebx
  1151. pop ebp
  1152. ret
  1153. }
  1154. */
  1155. }
  1156. NTSTATUS
  1157. FASTCALL
  1158. StatProfileInterrupt (
  1159. IN PKTRAP_FRAME TrapFrame
  1160. )
  1161. {
  1162. ULONG i;
  1163. ULONG current;
  1164. PPROFILE_EVENT ProfileEvent;
  1165. ProfileEvent = CurrentProfileEvent;
  1166. if (ProfileEvent) {
  1167. current = (ULONG) RDMSR(MsrCount);
  1168. //
  1169. // Did this event fire?
  1170. //
  1171. if (current < ProfileEvent->InitialCount) {
  1172. //
  1173. // Notify kernel
  1174. //
  1175. NakedCallToKeProfileInterruptWithSource( TrapFrame, ProfileEvent->Source );
  1176. //
  1177. // Reset trigger counter
  1178. //
  1179. WRMSR (MsrCount, ProfileEvent->InitialCount);
  1180. }
  1181. }
  1182. return STATUS_SUCCESS;
  1183. }
  1184. NTSTATUS
  1185. StatQuerySystemInformation (
  1186. IN HAL_QUERY_INFORMATION_CLASS InformationClass,
  1187. IN ULONG BufferSize,
  1188. OUT PVOID Buffer,
  1189. OUT PULONG ReturnedLength
  1190. )
  1191. {
  1192. PHAL_PROFILE_SOURCE_INFORMATION ProfileSource;
  1193. ULONG i;
  1194. PPROFILE_EVENT ProfileEvent;
  1195. if (InformationClass == HalProfileSourceInformation) {
  1196. ProfileSource = (PHAL_PROFILE_SOURCE_INFORMATION) Buffer;
  1197. *ReturnedLength = sizeof (HAL_PROFILE_SOURCE_INFORMATION);
  1198. if (BufferSize < sizeof (HAL_PROFILE_SOURCE_INFORMATION)) {
  1199. return STATUS_BUFFER_TOO_SMALL;
  1200. }
  1201. ProfileEvent = StatProfileEvent(ProfileSource->Source);
  1202. if (ProfileEvent) {
  1203. ProfileSource->Interval = 0 - (ULONG) ProfileEvent->InitialCount;
  1204. ProfileSource->Supported = TRUE;
  1205. return STATUS_SUCCESS;
  1206. }
  1207. }
  1208. //
  1209. // Not our QuerySystemInformation request, pass it on
  1210. //
  1211. return HaldQuerySystemInformation (InformationClass, BufferSize, Buffer, ReturnedLength);
  1212. }
  1213. NTSTATUS
  1214. StatSetSystemInformation(
  1215. IN HAL_SET_INFORMATION_CLASS InformationClass,
  1216. IN ULONG BufferSize,
  1217. IN PVOID Buffer
  1218. )
  1219. {
  1220. PHAL_PROFILE_SOURCE_INTERVAL ProfileInterval;
  1221. SETEVENT SetEvent;
  1222. PPROFILE_EVENT ProfileEvent;
  1223. if (InformationClass == HalProfileSourceInterval) {
  1224. ProfileInterval = (PHAL_PROFILE_SOURCE_INTERVAL) Buffer;
  1225. if (BufferSize < sizeof (HAL_PROFILE_SOURCE_INTERVAL)) {
  1226. return STATUS_BUFFER_TOO_SMALL;
  1227. }
  1228. ProfileEvent = StatProfileEvent(ProfileInterval->Source);
  1229. if (ProfileEvent) {
  1230. ProfileEvent->Source = ProfileInterval->Source;
  1231. ProfileEvent->InitialCount = 0;
  1232. ProfileEvent->InitialCount -= (ULONGLONG) ProfileInterval->Interval;
  1233. SetEvent.EventId = Events[ProfileEvent->Source - PROFILE_SOURCE_BASE].Encoding;
  1234. SetEvent.Active = TRUE;
  1235. SetEvent.UserMode = TRUE;
  1236. SetEvent.KernelMode = TRUE;
  1237. switch (ProcType) {
  1238. case INTEL_P6:
  1239. ProfileEvent->CESR = StatGetP6CESR (&SetEvent, TRUE);
  1240. break;
  1241. }
  1242. return STATUS_SUCCESS;
  1243. }
  1244. }
  1245. //
  1246. // Not our SetSystemInforamtion request, pass it on
  1247. //
  1248. return HaldSetSystemInformation (InformationClass, BufferSize, Buffer);
  1249. }
  1250. NTSTATUS
  1251. StatHookGenericThunk (
  1252. IN PHOOKTHUNK ThunkToHook
  1253. )
  1254. {
  1255. ULONG HookAddress;
  1256. ULONG i, TracerId;
  1257. UCHAR sourcename[50];
  1258. ULONG HitCounterOffset;
  1259. PLIST_ENTRY Link;
  1260. PHOOKEDTHUNK HookRecord;
  1261. UCHAR IdInUse[MAX_THUNK_COUNTERS];
  1262. PAGED_CODE();
  1263. i = strlen (ThunkToHook->SourceModule);
  1264. if (i >= 50) {
  1265. return STATUS_UNSUCCESSFUL;
  1266. }
  1267. strcpy (sourcename, ThunkToHook->SourceModule);
  1268. HookAddress = ImportThunkAddress (
  1269. sourcename,
  1270. ThunkToHook->ImageBase,
  1271. ThunkToHook->TargetModule,
  1272. ThunkToHook->Function,
  1273. NULL
  1274. );
  1275. if (!HookAddress) {
  1276. return STATUS_UNSUCCESSFUL;
  1277. }
  1278. //
  1279. // Hook this thunk
  1280. //
  1281. //
  1282. // If counting bucket is not known (also tracerid), then allocate one
  1283. //
  1284. TracerId = ThunkToHook->TracerId;
  1285. ExAcquireFastMutex (&HookLock);
  1286. if (TracerId == 0) {
  1287. RtlZeroMemory (IdInUse, MAX_THUNK_COUNTERS);
  1288. for (Link = HookedThunkList.Flink;
  1289. Link != &HookedThunkList;
  1290. Link = Link->Flink) {
  1291. HookRecord = CONTAINING_RECORD (Link, HOOKEDTHUNK, HookList);
  1292. IdInUse[HookRecord->TracerId-1] = 1;
  1293. }
  1294. while (IdInUse[TracerId]) {
  1295. if (++TracerId >= MAX_THUNK_COUNTERS) {
  1296. goto Abort;
  1297. }
  1298. }
  1299. TracerId += 1;
  1300. }
  1301. if (TracerId >= MAX_THUNK_COUNTERS) {
  1302. goto Abort;
  1303. }
  1304. if (TracerId > StatMaxThunkCounter) {
  1305. StatMaxThunkCounter = TracerId;
  1306. }
  1307. HookRecord = ExAllocatePool (NonPagedPool, sizeof (HOOKEDTHUNK));
  1308. if (!HookRecord) {
  1309. goto Abort;
  1310. }
  1311. HitCounterOffset =
  1312. ((ULONG) &StatGlobalAccumulators[0].ThunkCounters[TracerId-1]
  1313. - (ULONG) StatGlobalAccumulators);
  1314. HookRecord->HookAddress = HookAddress;
  1315. HookRecord->OriginalDispatch = *((PULONG) HookAddress);
  1316. HookRecord->TracerId = TracerId;
  1317. InsertHeadList (&HookedThunkList, &HookRecord->HookList);
  1318. CreateHook (HookRecord->HookCode, (PVOID)HookAddress, HitCounterOffset, 0);
  1319. SetMaxThunkCounter ();
  1320. ExReleaseFastMutex (&HookLock);
  1321. ThunkToHook->TracerId = TracerId;
  1322. return STATUS_SUCCESS;
  1323. Abort:
  1324. ExReleaseFastMutex (&HookLock);
  1325. return STATUS_UNSUCCESSFUL;
  1326. }
  1327. VOID
  1328. StatRemoveGenericHook (
  1329. IN PULONG pTracerId
  1330. )
  1331. {
  1332. PLIST_ENTRY Link, NextLink, Temp, NextTemp;
  1333. PHOOKEDTHUNK HookRecord, AltRecord;
  1334. ULONG HitCounterOffset;
  1335. LIST_ENTRY DisabledHooks;
  1336. ULONG TracerId;
  1337. PULONG HookAddress;
  1338. PAGED_CODE();
  1339. //
  1340. // Run list of hooks undo-ing any hook which matches this tracerid.
  1341. // Note: that hooks are undone in the reverse order for which they
  1342. // were applied.
  1343. //
  1344. TracerId = *pTracerId;
  1345. InitializeListHead (&DisabledHooks);
  1346. ExAcquireFastMutex (&HookLock);
  1347. Link = HookedThunkList.Flink;
  1348. while (Link != &HookedThunkList) {
  1349. NextLink = Link->Flink;
  1350. HookRecord = CONTAINING_RECORD (Link, HOOKEDTHUNK, HookList);
  1351. if (HookRecord->TracerId == TracerId) {
  1352. //
  1353. // Found a hook with a matching ID
  1354. // Scan for any hooks which need to be temporaly removed
  1355. // in order to get this hook removed
  1356. //
  1357. HookAddress = (PULONG) HookRecord->HookAddress;
  1358. Temp = HookedThunkList.Flink;
  1359. while (Temp != Link) {
  1360. NextTemp = Temp->Flink;
  1361. AltRecord = CONTAINING_RECORD (Temp, HOOKEDTHUNK, HookList);
  1362. if (AltRecord->HookAddress == HookRecord->HookAddress) {
  1363. RemoveEntryList(&AltRecord->HookList);
  1364. *HookAddress = AltRecord->OriginalDispatch;
  1365. InsertTailList (&DisabledHooks, &AltRecord->HookList);
  1366. }
  1367. Temp = NextTemp;
  1368. }
  1369. //
  1370. // Remove this hook
  1371. //
  1372. RemoveEntryList(&HookRecord->HookList);
  1373. HookAddress = (PULONG) HookRecord->HookAddress;
  1374. *HookAddress = HookRecord->OriginalDispatch;
  1375. InsertTailList (&LazyFreeList, &HookRecord->HookList);
  1376. }
  1377. Link = NextLink;
  1378. }
  1379. //
  1380. // Re-hook any hooks which were disabled for the remove operation
  1381. //
  1382. while (DisabledHooks.Flink != &DisabledHooks) {
  1383. HookRecord = CONTAINING_RECORD (DisabledHooks.Flink, HOOKEDTHUNK, HookList);
  1384. AltRecord = ExAllocatePool (NonPagedPool, sizeof (HOOKEDTHUNK));
  1385. if (!AltRecord) {
  1386. goto OutOfMemory;
  1387. }
  1388. RemoveEntryList(&HookRecord->HookList);
  1389. HookAddress = (PULONG) HookRecord->HookAddress;
  1390. AltRecord->HookAddress = HookRecord->HookAddress;
  1391. AltRecord->OriginalDispatch = *HookAddress;
  1392. AltRecord->TracerId = HookRecord->TracerId;
  1393. InsertHeadList (&HookedThunkList, &AltRecord->HookList);
  1394. HitCounterOffset =
  1395. (ULONG) &StatGlobalAccumulators[0].ThunkCounters[AltRecord->TracerId-1]
  1396. - (ULONG) StatGlobalAccumulators;
  1397. CreateHook (AltRecord->HookCode, (PVOID)HookAddress, HitCounterOffset, 0);
  1398. InsertTailList (&LazyFreeList, &HookRecord->HookList);
  1399. }
  1400. SetMaxThunkCounter();
  1401. ExReleaseFastMutex (&HookLock);
  1402. return ;
  1403. OutOfMemory:
  1404. while (DisabledHooks.Flink != &DisabledHooks) {
  1405. HookRecord = CONTAINING_RECORD (DisabledHooks.Flink, HOOKEDTHUNK, HookList);
  1406. RemoveEntryList(&HookRecord->HookList);
  1407. InsertTailList (&LazyFreeList, &HookRecord->HookList);
  1408. }
  1409. ExReleaseFastMutex (&HookLock);
  1410. RemoveAllHookedThunks ();
  1411. return ;
  1412. }
  1413. VOID RemoveAllHookedThunks ()
  1414. {
  1415. PHOOKEDTHUNK HookRecord;
  1416. PULONG HookAddress;
  1417. PAGED_CODE();
  1418. ExAcquireFastMutex (&HookLock);
  1419. while (!IsListEmpty(&HookedThunkList)) {
  1420. HookRecord = CONTAINING_RECORD (HookedThunkList.Flink, HOOKEDTHUNK, HookList);
  1421. RemoveEntryList(&HookRecord->HookList);
  1422. HookAddress = (PULONG) HookRecord->HookAddress;
  1423. *HookAddress = HookRecord->OriginalDispatch;
  1424. InsertTailList (&LazyFreeList, &HookRecord->HookList);
  1425. }
  1426. SetMaxThunkCounter();
  1427. ExReleaseFastMutex (&HookLock);
  1428. }
  1429. VOID SetMaxThunkCounter ()
  1430. {
  1431. LARGE_INTEGER duetime;
  1432. PLIST_ENTRY Link;
  1433. PHOOKEDTHUNK HookRecord;
  1434. ULONG Max;
  1435. PAGED_CODE();
  1436. Max = 0;
  1437. for (Link = HookedThunkList.Flink;
  1438. Link != &HookedThunkList;
  1439. Link = Link->Flink) {
  1440. HookRecord = CONTAINING_RECORD (Link, HOOKEDTHUNK, HookList);
  1441. if (HookRecord->TracerId > Max) {
  1442. Max = HookRecord->TracerId;
  1443. }
  1444. }
  1445. StatMaxThunkCounter = Max;
  1446. LazyFreeCountdown = 2;
  1447. duetime.QuadPart = -10000000;
  1448. KeSetTimer (&LazyFreeTimer, duetime, &LazyFreeDpc);
  1449. }
  1450. VOID LazyFreePoolDPC (PKDPC dpc, PVOID a, PVOID b, PVOID c)
  1451. {
  1452. ExQueueWorkItem (&LazyFreePoolWorkItem, DelayedWorkQueue);
  1453. }
  1454. VOID LazyFreePool (PVOID conext)
  1455. {
  1456. PHOOKEDTHUNK HookRecord;
  1457. LARGE_INTEGER duetime;
  1458. PAGED_CODE();
  1459. ExAcquireFastMutex (&HookLock);
  1460. if (--LazyFreeCountdown == 0) {
  1461. while (!IsListEmpty(&LazyFreeList)) {
  1462. HookRecord = CONTAINING_RECORD (LazyFreeList.Flink, HOOKEDTHUNK, HookList);
  1463. RemoveEntryList(&HookRecord->HookList);
  1464. RtlFillMemory(HookRecord, sizeof(HOOKEDTHUNK), 0xCC);
  1465. ExFreePool (HookRecord) ;
  1466. }
  1467. } else {
  1468. duetime.QuadPart = -10000000;
  1469. KeSetTimer (&LazyFreeTimer, duetime, &LazyFreeDpc);
  1470. }
  1471. ExReleaseFastMutex (&HookLock);
  1472. }
  1473. #define IMPKERNELADDRESS(a) ((ULONG)a + ImageBase)
  1474. #define IMPIMAGEADDRESS(a) ConvertImportAddress((ULONG)a, (ULONG)Pool, &SectionHeader)
  1475. #define INITIAL_POOLSIZE 0x7000
  1476. ULONG
  1477. ImportThunkAddressProcessFile(
  1478. IN ULONG_PTR ImageBase,
  1479. IN HANDLE FileHandle,
  1480. IN PUCHAR ImportModule,
  1481. IN PUCHAR ThunkName
  1482. )
  1483. {
  1484. ULONG i, j;
  1485. ULONG Dir;
  1486. PVOID Pool;
  1487. ULONG PoolSize;
  1488. IMAGE_DOS_HEADER DosImageHeader;
  1489. IMAGE_NT_HEADERS NtImageHeader;
  1490. PIMAGE_NT_HEADERS LoadedNtHeader;
  1491. PIMAGE_IMPORT_BY_NAME pImportNameData;
  1492. PIMAGE_SECTION_HEADER pSectionHeader;
  1493. IMAGE_SECTION_HEADER SectionHeader;
  1494. PIMAGE_IMPORT_DESCRIPTOR ImpDescriptor;
  1495. PULONG pThunkAddr, pThunkData;
  1496. PAGED_CODE();
  1497. try {
  1498. //
  1499. // Find module in loaded module list
  1500. //
  1501. PoolSize = INITIAL_POOLSIZE;
  1502. Pool = ExAllocatePool (PagedPool, PoolSize);
  1503. if (!Pool) {
  1504. return 0;
  1505. }
  1506. try {
  1507. //
  1508. // Read in source image's headers
  1509. //
  1510. readfile (
  1511. FileHandle,
  1512. 0,
  1513. sizeof (DosImageHeader),
  1514. (PVOID) &DosImageHeader
  1515. );
  1516. if (DosImageHeader.e_magic != IMAGE_DOS_SIGNATURE) {
  1517. return 0;
  1518. }
  1519. readfile (
  1520. FileHandle,
  1521. DosImageHeader.e_lfanew,
  1522. sizeof (NtImageHeader),
  1523. (PVOID) &NtImageHeader
  1524. );
  1525. if (NtImageHeader.Signature != IMAGE_NT_SIGNATURE) {
  1526. return 0;
  1527. }
  1528. if (!ImageBase) {
  1529. ImageBase = NtImageHeader.OptionalHeader.ImageBase;
  1530. }
  1531. //
  1532. // Check in read in copy header against loaded image
  1533. //
  1534. LoadedNtHeader = (PIMAGE_NT_HEADERS) ((ULONG) ImageBase +
  1535. DosImageHeader.e_lfanew);
  1536. if (LoadedNtHeader->Signature != IMAGE_NT_SIGNATURE ||
  1537. LoadedNtHeader->FileHeader.TimeDateStamp !=
  1538. NtImageHeader.FileHeader.TimeDateStamp) {
  1539. return 0;
  1540. }
  1541. //
  1542. // read in complete sections headers from image
  1543. //
  1544. i = NtImageHeader.FileHeader.NumberOfSections
  1545. * sizeof (IMAGE_SECTION_HEADER);
  1546. j = ((ULONG) IMAGE_FIRST_SECTION (&NtImageHeader)) -
  1547. ((ULONG) &NtImageHeader) +
  1548. DosImageHeader.e_lfanew;
  1549. if (i > PoolSize) {
  1550. ExFreePool(Pool);
  1551. PoolSize = i;
  1552. Pool = ExAllocatePool(PagedPool, PoolSize);
  1553. if (!Pool) {
  1554. return 0;
  1555. }
  1556. }
  1557. readfile (
  1558. FileHandle,
  1559. j, // file offset
  1560. i, // length
  1561. Pool
  1562. );
  1563. //
  1564. // Find section with import directory
  1565. //
  1566. Dir = NtImageHeader.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
  1567. i = 0;
  1568. pSectionHeader = Pool;
  1569. for (; ;) {
  1570. if (i >= NtImageHeader.FileHeader.NumberOfSections) {
  1571. return 0;
  1572. }
  1573. if (pSectionHeader->VirtualAddress <= Dir &&
  1574. pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData > Dir) {
  1575. break;
  1576. }
  1577. i += 1;
  1578. pSectionHeader += 1;
  1579. }
  1580. //
  1581. // read in complete import section from image
  1582. //
  1583. Dir -= pSectionHeader->VirtualAddress;
  1584. pSectionHeader->VirtualAddress += Dir;
  1585. pSectionHeader->PointerToRawData += Dir;
  1586. pSectionHeader->SizeOfRawData -= Dir;
  1587. SectionHeader = *pSectionHeader;
  1588. if (SectionHeader.SizeOfRawData > PoolSize) {
  1589. ExFreePool (Pool);
  1590. PoolSize = SectionHeader.SizeOfRawData;
  1591. Pool = ExAllocatePool (PagedPool, PoolSize);
  1592. if (!Pool) {
  1593. return 0;
  1594. }
  1595. }
  1596. readfile (
  1597. FileHandle,
  1598. SectionHeader.PointerToRawData,
  1599. SectionHeader.SizeOfRawData,
  1600. Pool
  1601. );
  1602. //
  1603. // Find imports from specified module
  1604. //
  1605. ImpDescriptor = (PIMAGE_IMPORT_DESCRIPTOR) Pool;
  1606. while (ImpDescriptor->Characteristics) {
  1607. if (_stricmp((PUCHAR)IMPIMAGEADDRESS((ULONG)(ImpDescriptor->Name)), ImportModule) == 0) {
  1608. break;
  1609. }
  1610. ImpDescriptor += 1;
  1611. }
  1612. //
  1613. // Find thunk for imported ThunkName
  1614. //
  1615. pThunkData = (PULONG) IMPIMAGEADDRESS (ImpDescriptor->OriginalFirstThunk);
  1616. pThunkAddr = (PULONG) IMPKERNELADDRESS (ImpDescriptor->FirstThunk);
  1617. for (; ;) {
  1618. if (*pThunkData == 0L) {
  1619. // end of table
  1620. break;
  1621. }
  1622. pImportNameData = (PIMAGE_IMPORT_BY_NAME) IMPIMAGEADDRESS (*pThunkData);
  1623. if (_stricmp(pImportNameData->Name, ThunkName) == 0) {
  1624. //
  1625. // Success, return this address.
  1626. //
  1627. return (ULONG)pThunkAddr;
  1628. }
  1629. // check next thunk
  1630. pThunkData += 1;
  1631. pThunkAddr += 1;
  1632. }
  1633. } except(EXCEPTION_EXECUTE_HANDLER) {
  1634. return 0;
  1635. }
  1636. } finally {
  1637. //
  1638. // Clean up
  1639. //
  1640. if (Pool) {
  1641. ExFreePool (Pool);
  1642. }
  1643. }
  1644. return 0;
  1645. }
  1646. ULONG
  1647. ImportThunkAddress (
  1648. IN PUCHAR SourceModule,
  1649. IN ULONG_PTR ImageBase,
  1650. IN PUCHAR ImportModule,
  1651. IN PUCHAR ThunkName,
  1652. IN PVOID ModuleList
  1653. )
  1654. {
  1655. NTSTATUS Status;
  1656. HANDLE FileHandle;
  1657. ULONG ImportAddress;
  1658. PAGED_CODE();
  1659. Status = openfile (&FileHandle, "\\SystemRoot\\", SourceModule);
  1660. if (!NT_SUCCESS(Status)) {
  1661. Status = openfile (&FileHandle, "\\SystemRoot\\System32\\", SourceModule);
  1662. }
  1663. if (!NT_SUCCESS(Status)) {
  1664. Status = openfile (&FileHandle, "\\SystemRoot\\System32\\Drivers\\", SourceModule);
  1665. }
  1666. if (!NT_SUCCESS(Status)) {
  1667. return 0;
  1668. }
  1669. if (!ImageBase) {
  1670. ImageBase = LookupImageBase (SourceModule, ModuleList);
  1671. }
  1672. ImportAddress = ImportThunkAddressProcessFile(ImageBase,
  1673. FileHandle,
  1674. ImportModule,
  1675. ThunkName);
  1676. NtClose (FileHandle);
  1677. return ImportAddress;
  1678. }
  1679. ULONG
  1680. ImportThunkAddressModule (
  1681. IN PRTL_PROCESS_MODULE_INFORMATION SourceModule,
  1682. IN PUCHAR ImportModule,
  1683. IN PUCHAR ThunkName
  1684. )
  1685. {
  1686. NTSTATUS Status;
  1687. HANDLE FileHandle;
  1688. ULONG ImportAddress;
  1689. PUCHAR SubPath;
  1690. PAGED_CODE();
  1691. //
  1692. // Strip the system root from the file path so we can use
  1693. // the \SystemRoot object as the head of the path.
  1694. //
  1695. SubPath = strchr(SourceModule->FullPathName + 1, '\\');
  1696. if (!SubPath) {
  1697. //
  1698. // If we got here we don't know what we're doing,
  1699. // bail out.
  1700. //
  1701. return 0;
  1702. }
  1703. Status = openfile (&FileHandle, "\\SystemRoot", SubPath);
  1704. if (!NT_SUCCESS(Status)) {
  1705. return 0;
  1706. }
  1707. ImportAddress = ImportThunkAddressProcessFile(
  1708. (ULONG_PTR)SourceModule->ImageBase,
  1709. FileHandle,
  1710. ImportModule,
  1711. ThunkName);
  1712. NtClose(FileHandle);
  1713. return ImportAddress;
  1714. }
  1715. ULONG_PTR
  1716. LookupImageBase (
  1717. IN PUCHAR SourceModule,
  1718. IN PVOID ModuleList
  1719. )
  1720. {
  1721. NTSTATUS status;
  1722. ULONG BufferSize;
  1723. ULONG junk, ModuleNumber;
  1724. ULONG_PTR ImageBase;
  1725. PRTL_PROCESS_MODULES Modules;
  1726. PRTL_PROCESS_MODULE_INFORMATION Module;
  1727. ImageBase = 0;
  1728. if (ModuleList) {
  1729. Modules = ModuleList;
  1730. } else {
  1731. BufferSize = 64000;
  1732. Modules = ExAllocatePool (PagedPool, BufferSize);
  1733. if (!Modules) {
  1734. return 0;
  1735. }
  1736. //
  1737. // Locate system drivers.
  1738. //
  1739. status = ZwQuerySystemInformation (
  1740. SystemModuleInformation,
  1741. Modules,
  1742. BufferSize,
  1743. &junk
  1744. );
  1745. if (!NT_SUCCESS(status)) {
  1746. ExFreePool(Modules);
  1747. return 0;
  1748. }
  1749. }
  1750. Module = &Modules->Modules[ 0 ];
  1751. for (ModuleNumber = 0;
  1752. ModuleNumber < Modules->NumberOfModules;
  1753. ModuleNumber++,Module++) {
  1754. if (_stricmp(Module->FullPathName + Module->OffsetToFileName,
  1755. SourceModule) == 0) {
  1756. ImageBase = (ULONG_PTR)Module->ImageBase;
  1757. break;
  1758. }
  1759. }
  1760. if (!ModuleList) {
  1761. ExFreePool (Modules);
  1762. }
  1763. return ImageBase;
  1764. }
  1765. NTSTATUS
  1766. openfile (
  1767. IN PHANDLE FileHandle,
  1768. IN PUCHAR BasePath,
  1769. IN PUCHAR Name
  1770. )
  1771. {
  1772. ANSI_STRING AscBasePath, AscName;
  1773. UNICODE_STRING UniPathName, UniName;
  1774. NTSTATUS status;
  1775. OBJECT_ATTRIBUTES ObjA;
  1776. IO_STATUS_BLOCK IOSB;
  1777. UCHAR StringBuf[500];
  1778. //
  1779. // Build name
  1780. //
  1781. UniPathName.Buffer = (PWCHAR)StringBuf;
  1782. UniPathName.Length = 0;
  1783. UniPathName.MaximumLength = sizeof( StringBuf );
  1784. RtlInitString(&AscBasePath, BasePath);
  1785. status = RtlAnsiStringToUnicodeString( &UniPathName, &AscBasePath, FALSE );
  1786. if (!NT_SUCCESS(status)) {
  1787. return status;
  1788. }
  1789. RtlInitString(&AscName, Name);
  1790. status = RtlAnsiStringToUnicodeString( &UniName, &AscName, TRUE );
  1791. if (!NT_SUCCESS(status)) {
  1792. return status;
  1793. }
  1794. status = RtlAppendUnicodeStringToString (&UniPathName, &UniName);
  1795. if (!NT_SUCCESS(status)) {
  1796. return status;
  1797. }
  1798. InitializeObjectAttributes(
  1799. &ObjA,
  1800. &UniPathName,
  1801. OBJ_CASE_INSENSITIVE,
  1802. 0,
  1803. 0 );
  1804. //
  1805. // open file
  1806. //
  1807. status = ZwOpenFile (
  1808. FileHandle, // return handle
  1809. SYNCHRONIZE | FILE_READ_DATA, // desired access
  1810. &ObjA, // Object
  1811. &IOSB, // io status block
  1812. FILE_SHARE_READ | FILE_SHARE_WRITE, // share access
  1813. FILE_SYNCHRONOUS_IO_ALERT // open options
  1814. );
  1815. RtlFreeUnicodeString (&UniName);
  1816. return status;
  1817. }
  1818. VOID
  1819. readfile (
  1820. HANDLE handle,
  1821. ULONG offset,
  1822. ULONG len,
  1823. PVOID buffer
  1824. )
  1825. {
  1826. NTSTATUS status;
  1827. IO_STATUS_BLOCK iosb;
  1828. LARGE_INTEGER foffset;
  1829. foffset = RtlConvertUlongToLargeInteger(offset);
  1830. status = ZwReadFile (
  1831. handle,
  1832. NULL, // event
  1833. NULL, // apc routine
  1834. NULL, // apc context
  1835. &iosb,
  1836. buffer,
  1837. len,
  1838. &foffset,
  1839. NULL
  1840. );
  1841. if (!NT_SUCCESS(status)) {
  1842. ExRaiseStatus (1);
  1843. }
  1844. }
  1845. ULONG
  1846. ConvertImportAddress (
  1847. IN ULONG ImageRelativeAddress,
  1848. IN ULONG PoolAddress,
  1849. IN PIMAGE_SECTION_HEADER SectionHeader
  1850. )
  1851. {
  1852. ULONG EffectiveAddress;
  1853. EffectiveAddress = PoolAddress + ImageRelativeAddress -
  1854. SectionHeader->VirtualAddress;
  1855. if (EffectiveAddress < PoolAddress ||
  1856. EffectiveAddress > PoolAddress + SectionHeader->SizeOfRawData) {
  1857. ExRaiseStatus (1);
  1858. }
  1859. return EffectiveAddress;
  1860. }