VirtualBox

Changeset 86162 in vbox for trunk/src


Ignore:
Timestamp:
Sep 18, 2020 7:12:13 AM (4 years ago)
Author:
vboxsync
Message:

Debugger/DBGPlugInWinNt: Add KPCR/KPCRB extraction for 32bit Windows

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Debugger/DBGPlugInWinNt.cpp

    r86159 r86162  
    179179typedef NTHDRS const *PCNTHDRS;
    180180
     181
     182/**
     183 * NT KD version block.
     184 */
     185typedef 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. */
     203typedef NTKDVERSIONBLOCK *PNTKDVERSIONBLOCK;
     204/** Pointer to a const NT KD version block. */
     205typedef const NTKDVERSIONBLOCK *PCNTKDVERSIONBLOCK;
     206
    181207/** @} */
    182208
     
    318344static void dbgDiggerWinNtResolveKpcr(PDBGDIGGERWINNT pThis, PUVM pUVM)
    319345{
    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++)
    335363        {
    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)
    341368            {
    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            {
    345449                /* Read GS base which points to the base of the KPCR for each CPU. */
    346450                RTGCUINTPTR GCPtrTmp = 0;
    347451                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))
    349464                {
    350465                    LogFlow(("DigWinNt/KPCR[%u]: GS Base %RGv\n", idCpu, GCPtrTmp));
     
    378493                            }
    379494                            else
    380                                 LogRel(("DigWinNt/KPCR[%u]: KPCR validation error GDT=(%RGv vs %RGv) KPCRB=(%RGv vs %RGv)\n", idCpu,
     495                                LogRel(("DigWinNt/KPCR[%u]: KPCR validation error GDT=(%RGv vs %RGv) KPCR=(%RGv vs %RGv)\n", idCpu,
    381496                                        Kpcr.GCPtrGdt, GCPtrTmp, Kpcr.GCPtrSelf, pKpcrAddr->FlatPtr));
    382497                        }
     
    390505                    LogRel(("DigWinNt/KPCR[%u]: Getting GS base register failed with %Rrc\n", idCpu, rc));
    391506            }
    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             }
    400507        }
    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        }
    403516    }
     517    else
     518        LogRel(("DigWinNt/KPCR: Failed to allocate %u entries for the KPCR/KPCRB addresses\n", cCpus * 2));
    404519}
    405520
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette