- Timestamp:
- Sep 18, 2020 7:12:13 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGPlugInWinNt.cpp
r86159 r86162 179 179 typedef NTHDRS const *PCNTHDRS; 180 180 181 182 /** 183 * NT KD version block. 184 */ 185 typedef struct NTKDVERSIONBLOCK 186 { 187 uint16_t MajorVersion; 188 uint16_t MinorVersion; 189 uint8_t ProtocolVersion; 190 uint8_t KdSecondaryVersion; 191 uint16_t Flags; 192 uint16_t MachineType; 193 uint8_t MaxPacketType; 194 uint8_t MaxStateChange; 195 uint8_t MaxManipulate; 196 uint8_t Simulation; 197 uint16_t Unused; 198 uint64_t KernBase; 199 uint64_t PsLoadedModuleList; 200 uint64_t DebuggerDataList; 201 } NTKDVERSIONBLOCK; 202 /** Pointer to an NT KD version block. */ 203 typedef NTKDVERSIONBLOCK *PNTKDVERSIONBLOCK; 204 /** Pointer to a const NT KD version block. */ 205 typedef const NTKDVERSIONBLOCK *PCNTKDVERSIONBLOCK; 206 181 207 /** @} */ 182 208 … … 318 344 static void dbgDiggerWinNtResolveKpcr(PDBGDIGGERWINNT pThis, PUVM pUVM) 319 345 { 320 if (pThis->f32Bit) 321 { /** @todo */ } 322 else 323 { 324 /* 325 * Getting at the KPCR and KPCRB is explained here: 326 * https://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kprcb/amd64.htm 327 * Together with the available offsets from: 328 * https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/shared/ksamd64.inc#L883 329 * we can verify that the found addresses are valid by cross checking that the GDTR and self reference 330 * match what we expect. 331 */ 332 VMCPUID cCpus = DBGFR3CpuGetCount(pUVM); 333 pThis->paKpcrAddr = (PDBGFADDRESS)RTMemAllocZ(cCpus * 2 * sizeof(DBGFADDRESS)); 334 if (RT_LIKELY(pThis->paKpcrAddr)) 346 /* 347 * Getting at the KPCR and KPCRB is explained here: 348 * https://www.geoffchappell.com/studies/windows/km/ntoskrnl/structs/kpcr.htm 349 * Together with the available offsets from: 350 * https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/shared/ksamd64.inc#L883 351 * we can verify that the found addresses are valid by cross checking that the GDTR and self reference 352 * match what we expect. 353 */ 354 VMCPUID cCpus = DBGFR3CpuGetCount(pUVM); 355 pThis->paKpcrAddr = (PDBGFADDRESS)RTMemAllocZ(cCpus * 2 * sizeof(DBGFADDRESS)); 356 if (RT_LIKELY(pThis->paKpcrAddr)) 357 { 358 pThis->paKpcrbAddr = &pThis->paKpcrAddr[cCpus]; 359 360 /* Work each CPU, unexpected values in each CPU make the whole thing fail to play safe. */ 361 int rc = VINF_SUCCESS; 362 for (VMCPUID idCpu = 0; (idCpu < cCpus) && RT_SUCCESS(rc); idCpu++) 335 363 { 336 pThis->paKpcrbAddr = &pThis->paKpcrAddr[cCpus]; 337 338 /* Work each CPU, unexpected values in each CPU make the whole thing fail to play safe. */ 339 int rc = VINF_SUCCESS; 340 for (VMCPUID idCpu = 0; (idCpu < cCpus) && RT_SUCCESS(rc); idCpu++) 364 PDBGFADDRESS pKpcrAddr = &pThis->paKpcrAddr[idCpu]; 365 PDBGFADDRESS pKpcrbAddr = &pThis->paKpcrbAddr[idCpu]; 366 367 if (pThis->f32Bit) 341 368 { 342 PDBGFADDRESS pKpcrAddr = &pThis->paKpcrAddr[idCpu]; 343 PDBGFADDRESS pKpcrbAddr = &pThis->paKpcrbAddr[idCpu]; 344 369 /* Read FS base */ 370 uint32_t GCPtrKpcrBase = 0; 371 372 rc = DBGFR3RegCpuQueryU32(pUVM, idCpu, DBGFREG_FS_BASE, &GCPtrKpcrBase); 373 if ( RT_SUCCESS(rc) 374 && WINNT_VALID_ADDRESS(pThis, GCPtrKpcrBase)) 375 { 376 /* 377 * Read the start of the KPCR (@todo Probably move this to a global header) 378 * and verify its content. 379 */ 380 struct 381 { 382 uint8_t abOoi[28]; /* Out of interest */ 383 uint32_t GCPtrSelf; 384 uint32_t GCPtrCurrentPrcb; 385 uint32_t u32Irql; 386 uint32_t u32Iir; 387 uint32_t u32IirActive; 388 uint32_t u32Idr; 389 uint32_t GCPtrKdVersionBlock; 390 uint32_t GCPtrIdt; 391 uint32_t GCPtrGdt; 392 uint32_t GCPtrTss; 393 } Kpcr; 394 395 LogFlow(("DigWinNt/KPCR[%u]: GS Base %RGv\n", idCpu, GCPtrKpcrBase)); 396 DBGFR3AddrFromFlat(pUVM, pKpcrAddr, GCPtrKpcrBase); 397 398 rc = DBGFR3MemRead(pUVM, idCpu, pKpcrAddr, &Kpcr, sizeof(Kpcr)); 399 if (RT_SUCCESS(rc)) 400 { 401 uint32_t GCPtrGdt = 0; 402 uint32_t GCPtrIdt = 0; 403 404 rc = DBGFR3RegCpuQueryU32(pUVM, idCpu, DBGFREG_GDTR_BASE, &GCPtrGdt); 405 if (RT_SUCCESS(rc)) 406 rc = DBGFR3RegCpuQueryU32(pUVM, idCpu, DBGFREG_IDTR_BASE, &GCPtrIdt); 407 if (RT_SUCCESS(rc)) 408 { 409 if ( Kpcr.GCPtrGdt == GCPtrGdt 410 && Kpcr.GCPtrIdt == GCPtrIdt 411 && Kpcr.GCPtrSelf == pKpcrAddr->FlatPtr) 412 { 413 DBGFR3AddrFromFlat(pUVM, pKpcrbAddr, Kpcr.GCPtrCurrentPrcb); 414 LogRel(("DigWinNt/KPCR[%u]: KPCR=%RGv KPCRB=%RGv\n", idCpu, pKpcrAddr->FlatPtr, pKpcrbAddr->FlatPtr)); 415 416 /* 417 * Try to extract the NT build number from the KD version block if it exists, 418 * the shared user data might have set it to 0. 419 * 420 * @todo We can use this method to get at the kern base and loaded module list if the other detection 421 * method fails (seen with Windows 10 x86). 422 * @todo On 32bit Windows the debugger data list is also always accessible this way contrary to 423 * the amd64 version where it is only available with "/debug on" set. 424 */ 425 if (!pThis->NtBuildNumber) 426 { 427 NTKDVERSIONBLOCK KdVersBlock; 428 DBGFADDRESS AddrKdVersBlock; 429 430 DBGFR3AddrFromFlat(pUVM, &AddrKdVersBlock, Kpcr.GCPtrKdVersionBlock); 431 rc = DBGFR3MemRead(pUVM, idCpu, &AddrKdVersBlock, &KdVersBlock, sizeof(KdVersBlock)); 432 if (RT_SUCCESS(rc)) 433 pThis->NtBuildNumber = KdVersBlock.MinorVersion; 434 } 435 } 436 else 437 LogRel(("DigWinNt/KPCR[%u]: KPCR validation error GDT=(%RGv vs %RGv) KPCR=(%RGv vs %RGv)\n", idCpu, 438 Kpcr.GCPtrGdt, GCPtrGdt, Kpcr.GCPtrSelf, pKpcrAddr->FlatPtr)); 439 } 440 else 441 LogRel(("DigWinNt/KPCR[%u]: Getting GDT or IDT base register failed with %Rrc\n", idCpu, rc)); 442 } 443 } 444 else 445 LogRel(("DigWinNt/KPCR[%u]: Getting FS base register failed with %Rrc (%RGv)\n", idCpu, rc, GCPtrKpcrBase)); 446 } 447 else 448 { 345 449 /* Read GS base which points to the base of the KPCR for each CPU. */ 346 450 RTGCUINTPTR GCPtrTmp = 0; 347 451 rc = DBGFR3RegCpuQueryU64(pUVM, idCpu, DBGFREG_GS_BASE, &GCPtrTmp); 348 if (RT_SUCCESS(rc)) 452 if ( RT_SUCCESS(rc) 453 && !WINNT_VALID_ADDRESS(pThis, GCPtrTmp)) 454 { 455 /* 456 * Could be a user address when we stopped the VM right in usermode, 457 * read the GS kernel base MSR instead. 458 */ 459 rc = DBGFR3RegCpuQueryU64(pUVM, idCpu, DBGFREG_MSR_K8_KERNEL_GS_BASE, &GCPtrTmp); 460 } 461 462 if ( RT_SUCCESS(rc) 463 && WINNT_VALID_ADDRESS(pThis, GCPtrTmp)) 349 464 { 350 465 LogFlow(("DigWinNt/KPCR[%u]: GS Base %RGv\n", idCpu, GCPtrTmp)); … … 378 493 } 379 494 else 380 LogRel(("DigWinNt/KPCR[%u]: KPCR validation error GDT=(%RGv vs %RGv) KPCR B=(%RGv vs %RGv)\n", idCpu,495 LogRel(("DigWinNt/KPCR[%u]: KPCR validation error GDT=(%RGv vs %RGv) KPCR=(%RGv vs %RGv)\n", idCpu, 381 496 Kpcr.GCPtrGdt, GCPtrTmp, Kpcr.GCPtrSelf, pKpcrAddr->FlatPtr)); 382 497 } … … 390 505 LogRel(("DigWinNt/KPCR[%u]: Getting GS base register failed with %Rrc\n", idCpu, rc)); 391 506 } 392 393 if (RT_FAILURE(rc))394 {395 LogRel(("DigWinNt/KPCR: Failed to detmine KPCR and KPCRB rc=%Rrc\n", rc));396 RTMemFree(pThis->paKpcrAddr);397 pThis->paKpcrAddr = NULL;398 pThis->paKpcrbAddr = NULL;399 }400 507 } 401 else 402 LogRel(("DigWinNt/KPCR: Failed to allocate %u entries for the KPCR/KPCRB addresses\n", cCpus * 2)); 508 509 if (RT_FAILURE(rc)) 510 { 511 LogRel(("DigWinNt/KPCR: Failed to detmine KPCR and KPCRB rc=%Rrc\n", rc)); 512 RTMemFree(pThis->paKpcrAddr); 513 pThis->paKpcrAddr = NULL; 514 pThis->paKpcrbAddr = NULL; 515 } 403 516 } 517 else 518 LogRel(("DigWinNt/KPCR: Failed to allocate %u entries for the KPCR/KPCRB addresses\n", cCpus * 2)); 404 519 } 405 520
Note:
See TracChangeset
for help on using the changeset viewer.