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.

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