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.

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