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.

469 lines
13 KiB

  1. #include "vdmp.h"
  2. #include <ntos.h>
  3. #include <zwapi.h>
  4. #include <ntconfig.h>
  5. #ifdef ALLOC_PRAGMA
  6. #pragma alloc_text(PAGE, VdmpInitialize)
  7. #endif
  8. #define KEY_VALUE_BUFFER_SIZE 1024
  9. #if DEVL
  10. ULONG VdmBopCount;
  11. #endif
  12. NTSTATUS
  13. VdmpInitialize(
  14. PVDM_INITIALIZE_DATA VdmInitData
  15. )
  16. /*++
  17. Routine Description:
  18. Initialize the address space of a VDM.
  19. Arguments:
  20. VdmInitData - Supplies the captured initialization data.
  21. Return Value:
  22. NTSTATUS.
  23. --*/
  24. {
  25. PETHREAD CurrentThread;
  26. PVOID OriginalVdmObjects;
  27. NTSTATUS Status, StatusCopy;
  28. OBJECT_ATTRIBUTES ObjectAttributes;
  29. UNICODE_STRING SectionName;
  30. UNICODE_STRING WorkString;
  31. ULONG ViewSize;
  32. LARGE_INTEGER ViewBase;
  33. PVOID BaseAddress;
  34. PVOID destination;
  35. HANDLE SectionHandle, RegistryHandle;
  36. PEPROCESS Process = PsGetCurrentProcess();
  37. ULONG ResultLength;
  38. ULONG Index;
  39. PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor;
  40. PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor;
  41. PKEY_VALUE_FULL_INFORMATION KeyValueBuffer;
  42. PCM_ROM_BLOCK BiosBlock;
  43. ULONG LastMappedAddress;
  44. PVDM_PROCESS_OBJECTS pVdmObjects;
  45. HANDLE hThread;
  46. PVDMICAUSERDATA pIcaUserData;
  47. PVOID TrapcHandler;
  48. PAGED_CODE();
  49. NtCurrentTeb()->Vdm = NULL;
  50. //
  51. // Simple check to sure it is not already initialized. A final synchronized
  52. // check is made farther down.
  53. //
  54. if (Process->VdmObjects) {
  55. return STATUS_UNSUCCESSFUL;
  56. }
  57. RtlInitUnicodeString (&SectionName, L"\\Device\\PhysicalMemory");
  58. InitializeObjectAttributes (&ObjectAttributes,
  59. &SectionName,
  60. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  61. (HANDLE) NULL,
  62. (PSECURITY_DESCRIPTOR) NULL);
  63. Status = ZwOpenSection (&SectionHandle,
  64. SECTION_ALL_ACCESS,
  65. &ObjectAttributes);
  66. if (!NT_SUCCESS(Status)) {
  67. return Status;
  68. }
  69. pIcaUserData = VdmInitData->IcaUserData;
  70. TrapcHandler = VdmInitData->TrapcHandler;
  71. //
  72. // Copy the first page of memory into the VDM's address space
  73. //
  74. BaseAddress = 0;
  75. destination = 0;
  76. ViewSize = 0x1000;
  77. ViewBase.LowPart = 0;
  78. ViewBase.HighPart = 0;
  79. Status = ZwMapViewOfSection (SectionHandle,
  80. NtCurrentProcess(),
  81. &BaseAddress,
  82. 0,
  83. ViewSize,
  84. &ViewBase,
  85. &ViewSize,
  86. ViewUnmap,
  87. 0,
  88. PAGE_READWRITE);
  89. if (!NT_SUCCESS(Status)) {
  90. ZwClose (SectionHandle);
  91. return Status;
  92. }
  93. StatusCopy = STATUS_SUCCESS;
  94. try {
  95. RtlCopyMemory (destination, BaseAddress, ViewSize);
  96. }
  97. except(ExSystemExceptionFilter()) {
  98. StatusCopy = GetExceptionCode ();
  99. }
  100. Status = ZwUnmapViewOfSection (NtCurrentProcess(), BaseAddress);
  101. if (!NT_SUCCESS(Status) || !NT_SUCCESS(StatusCopy)) {
  102. ZwClose (SectionHandle);
  103. return (NT_SUCCESS(Status) ? StatusCopy : Status);
  104. }
  105. //
  106. // Map Rom into address space
  107. //
  108. BaseAddress = (PVOID) 0x000C0000;
  109. ViewSize = 0x40000;
  110. ViewBase.LowPart = 0x000C0000;
  111. ViewBase.HighPart = 0;
  112. //
  113. // First unmap the reserved memory. This must be done here to prevent
  114. // the virtual memory in question from being consumed by some other
  115. // alloc vm call.
  116. //
  117. Status = ZwFreeVirtualMemory (NtCurrentProcess(),
  118. &BaseAddress,
  119. &ViewSize,
  120. MEM_RELEASE);
  121. //
  122. // N.B. This should probably take into account the fact that there are
  123. // a handful of error conditions that are ok (such as no memory to
  124. // release).
  125. //
  126. if (!NT_SUCCESS(Status)) {
  127. ZwClose (SectionHandle);
  128. return Status;
  129. }
  130. //
  131. // Set up and open KeyPath
  132. //
  133. InitializeObjectAttributes (&ObjectAttributes,
  134. &CmRegistryMachineHardwareDescriptionSystemName,
  135. OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,
  136. (HANDLE)NULL,
  137. NULL);
  138. Status = ZwOpenKey (&RegistryHandle, KEY_READ, &ObjectAttributes);
  139. if (!NT_SUCCESS(Status)) {
  140. ZwClose(SectionHandle);
  141. return Status;
  142. }
  143. //
  144. // Allocate space for the data
  145. //
  146. KeyValueBuffer = ExAllocatePoolWithTag (PagedPool,
  147. KEY_VALUE_BUFFER_SIZE,
  148. ' MDV');
  149. if (KeyValueBuffer == NULL) {
  150. ZwClose(RegistryHandle);
  151. ZwClose(SectionHandle);
  152. return STATUS_NO_MEMORY;
  153. }
  154. //
  155. // Get the data for the rom information
  156. //
  157. RtlInitUnicodeString (&WorkString, L"Configuration Data");
  158. Status = ZwQueryValueKey (RegistryHandle,
  159. &WorkString,
  160. KeyValueFullInformation,
  161. KeyValueBuffer,
  162. KEY_VALUE_BUFFER_SIZE,
  163. &ResultLength);
  164. if (!NT_SUCCESS(Status)) {
  165. ExFreePool(KeyValueBuffer);
  166. ZwClose(RegistryHandle);
  167. ZwClose(SectionHandle);
  168. return Status;
  169. }
  170. ResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)
  171. ((PUCHAR) KeyValueBuffer + KeyValueBuffer->DataOffset);
  172. if ((KeyValueBuffer->DataLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) ||
  173. (ResourceDescriptor->PartialResourceList.Count < 2)) {
  174. //
  175. // No rom blocks.
  176. //
  177. ExFreePool(KeyValueBuffer);
  178. ZwClose(RegistryHandle);
  179. ZwClose(SectionHandle);
  180. return STATUS_SUCCESS;
  181. }
  182. PartialResourceDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
  183. ((PUCHAR)ResourceDescriptor +
  184. sizeof(CM_FULL_RESOURCE_DESCRIPTOR) +
  185. ResourceDescriptor->PartialResourceList.PartialDescriptors[0]
  186. .u.DeviceSpecificData.DataSize);
  187. if (KeyValueBuffer->DataLength < ((PUCHAR)PartialResourceDescriptor -
  188. (PUCHAR)ResourceDescriptor + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  189. + sizeof(CM_ROM_BLOCK))) {
  190. ExFreePool(KeyValueBuffer);
  191. ZwClose(RegistryHandle);
  192. ZwClose(SectionHandle);
  193. return STATUS_ILL_FORMED_SERVICE_ENTRY;
  194. }
  195. BiosBlock = (PCM_ROM_BLOCK)((PUCHAR)PartialResourceDescriptor +
  196. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  197. Index = PartialResourceDescriptor->u.DeviceSpecificData.DataSize /
  198. sizeof(CM_ROM_BLOCK);
  199. //
  200. // N.B. Rom blocks begin on 2K (not necessarily page) boundaries
  201. // They end on 512 byte boundaries. This means that we have
  202. // to keep track of the last page mapped, and round the next
  203. // Rom block up to the next page boundary if necessary.
  204. //
  205. LastMappedAddress = 0xC0000;
  206. while (Index) {
  207. #if 0
  208. DbgPrint ("Bios Block, PhysAddr = %lx, size = %lx\n",
  209. BiosBlock->Address,
  210. BiosBlock->Size);
  211. #endif
  212. if ((Index > 1) &&
  213. ((BiosBlock->Address + BiosBlock->Size) == BiosBlock[1].Address)) {
  214. //
  215. // Coalesce adjacent blocks
  216. //
  217. BiosBlock[1].Address = BiosBlock[0].Address;
  218. BiosBlock[1].Size += BiosBlock[0].Size;
  219. Index -= 1;
  220. BiosBlock += 1;
  221. continue;
  222. }
  223. BaseAddress = (PVOID)(BiosBlock->Address);
  224. ViewSize = BiosBlock->Size;
  225. if ((ULONG)BaseAddress < LastMappedAddress) {
  226. if (ViewSize > (LastMappedAddress - (ULONG)BaseAddress)) {
  227. ViewSize = ViewSize - (LastMappedAddress - (ULONG)BaseAddress);
  228. BaseAddress = (PVOID)LastMappedAddress;
  229. } else {
  230. ViewSize = 0;
  231. }
  232. }
  233. ViewBase.LowPart = (ULONG)BaseAddress;
  234. if (ViewSize > 0) {
  235. Status = ZwMapViewOfSection (SectionHandle,
  236. NtCurrentProcess(),
  237. &BaseAddress,
  238. 0,
  239. ViewSize,
  240. &ViewBase,
  241. &ViewSize,
  242. ViewUnmap,
  243. MEM_DOS_LIM,
  244. PAGE_READWRITE);
  245. if (!NT_SUCCESS(Status)) {
  246. break;
  247. }
  248. LastMappedAddress = (ULONG)BaseAddress + ViewSize;
  249. }
  250. Index -= 1;
  251. BiosBlock += 1;
  252. }
  253. //
  254. // Free up the handles
  255. //
  256. ExFreePool(KeyValueBuffer);
  257. ZwClose(SectionHandle);
  258. ZwClose(RegistryHandle);
  259. //
  260. // Create VdmObjects structure
  261. //
  262. // N.B. We don't use ExAllocatePoolWithQuota because it
  263. // takes a reference to the process (which ExFreePool
  264. // dereferences). Since we expect to clean up on
  265. // process deletion, we don't need or want the reference
  266. // (which will prevent the process from being deleted)
  267. //
  268. pVdmObjects = ExAllocatePoolWithTag (NonPagedPool,
  269. sizeof(VDM_PROCESS_OBJECTS),
  270. ' MDV');
  271. if (pVdmObjects == NULL) {
  272. return STATUS_NO_MEMORY;
  273. }
  274. Status = PsChargeProcessPoolQuota (Process,
  275. NonPagedPool,
  276. sizeof(VDM_PROCESS_OBJECTS));
  277. if (!NT_SUCCESS (Status)) {
  278. ExFreePool (pVdmObjects);
  279. return Status;
  280. }
  281. RtlZeroMemory (pVdmObjects, sizeof(VDM_PROCESS_OBJECTS));
  282. ExInitializeFastMutex (&pVdmObjects->DelayIntFastMutex);
  283. KeInitializeSpinLock (&pVdmObjects->DelayIntSpinLock);
  284. InitializeListHead (&pVdmObjects->DelayIntListHead);
  285. pVdmObjects->pIcaUserData = ExAllocatePoolWithTag (PagedPool,
  286. sizeof(VDMICAUSERDATA),
  287. ' MDV');
  288. if (pVdmObjects->pIcaUserData == NULL) {
  289. PsReturnPoolQuota (Process, NonPagedPool, sizeof(VDM_PROCESS_OBJECTS));
  290. ExFreePool (pVdmObjects);
  291. return STATUS_NO_MEMORY;
  292. }
  293. Status = PsChargeProcessPoolQuota (Process,
  294. PagedPool,
  295. sizeof(VDMICAUSERDATA));
  296. if (!NT_SUCCESS (Status)) {
  297. PsReturnPoolQuota (Process, NonPagedPool, sizeof(VDM_PROCESS_OBJECTS));
  298. ExFreePool (pVdmObjects->pIcaUserData);
  299. ExFreePool (pVdmObjects);
  300. return Status;
  301. }
  302. try {
  303. //
  304. // Copy Ica addresses from service data (in user space) into
  305. // pVdmObjects->pIcaUserData
  306. //
  307. ProbeForRead(pIcaUserData, sizeof(VDMICAUSERDATA), sizeof(UCHAR));
  308. *pVdmObjects->pIcaUserData = *pIcaUserData;
  309. //
  310. // Probe static addresses in IcaUserData.
  311. //
  312. pIcaUserData = pVdmObjects->pIcaUserData;
  313. ProbeForWriteHandle (pIcaUserData->phWowIdleEvent);
  314. ProbeForWrite (pIcaUserData->pIcaLock,
  315. sizeof(RTL_CRITICAL_SECTION),
  316. sizeof(UCHAR));
  317. ProbeForWrite (pIcaUserData->pIcaMaster,
  318. sizeof(VDMVIRTUALICA),
  319. sizeof(UCHAR));
  320. ProbeForWrite (pIcaUserData->pIcaSlave,
  321. sizeof(VDMVIRTUALICA),
  322. sizeof(UCHAR));
  323. ProbeForWriteUlong(pIcaUserData->pIretHooked);
  324. ProbeForWriteUlong(pIcaUserData->pDelayIrq);
  325. ProbeForWriteUlong(pIcaUserData->pUndelayIrq);
  326. ProbeForWriteUlong(pIcaUserData->pDelayIret);
  327. } except(ExSystemExceptionFilter()) {
  328. Status = GetExceptionCode();
  329. PsReturnPoolQuota (Process, NonPagedPool, sizeof(VDM_PROCESS_OBJECTS));
  330. PsReturnPoolQuota(Process, PagedPool, sizeof(VDMICAUSERDATA));
  331. ExFreePool (pVdmObjects->pIcaUserData);
  332. ExFreePool (pVdmObjects);
  333. return Status;
  334. }
  335. //
  336. // Save a pointer to the main thread for the delayed interrupt DPC routine.
  337. // To keep the pointer to the main thread valid, reference the thread
  338. // and don't dereference it until process exit.
  339. //
  340. CurrentThread = PsGetCurrentThread ();
  341. ObReferenceObject (CurrentThread);
  342. pVdmObjects->MainThread = CurrentThread;
  343. ASSERT (pVdmObjects->VdmTib == NULL);
  344. //
  345. // Carefully mark the process as a vdm (as other threads may be racing to
  346. // do the same marking).
  347. //
  348. OriginalVdmObjects = InterlockedCompareExchangePointer (&Process->VdmObjects, pVdmObjects, NULL);
  349. if (OriginalVdmObjects != NULL) {
  350. PsReturnPoolQuota (Process, NonPagedPool, sizeof(VDM_PROCESS_OBJECTS));
  351. PsReturnPoolQuota(Process, PagedPool, sizeof(VDMICAUSERDATA));
  352. ExFreePool (pVdmObjects->pIcaUserData);
  353. ExFreePool (pVdmObjects);
  354. ObDereferenceObject (CurrentThread);
  355. return STATUS_UNSUCCESSFUL;
  356. }
  357. ASSERT (Process->VdmObjects == pVdmObjects);
  358. Process->Pcb.VdmTrapcHandler = TrapcHandler;
  359. return Status;
  360. }