Пример #1
0
int main(int argc, char **argv)
{
    printf("VBox Disassembler Test\n");
    if (argc != 1)
    {
        //printf("DisasmBlock on printf:\n");
        //DisasmBlock((uint8_t *)printf, 256);
    }
    else
    {
        RTUINTPTR pInstr = (uintptr_t)TestProc;

        for (int i=0;i<50;i++)
        {
            unsigned    cb;
            DISCPUSTATE cpu;
            char         szOutput[256];

            memset(&cpu, 0, sizeof(cpu));
            cpu.mode = CPUMODE_32BIT;
            if (RT_SUCCESS(DISInstr(&cpu, pInstr, 0, &cb, szOutput)))
            {
                printf("%s", szOutput);
            }
            else
            {
                printf("DISOne failed!\n");
                return 1;
            }
            pInstr += cb;
        }

#ifndef RT_OS_OS2
        printf("\n64 bits disassembly\n");
        pInstr = (uintptr_t)TestProc64;

////__debugbreak();
        for (int i=0;i<50;i++)
        {
            unsigned    cb;
            DISCPUSTATE cpu;
            char         szOutput[256];

            memset(&cpu, 0, sizeof(cpu));
            cpu.mode = CPUMODE_64BIT;
            if (RT_SUCCESS(DISInstr(&cpu, pInstr, 0, &cb, szOutput)))
                printf("%s", szOutput);
            else
            {
                printf("DISOne failed!\n");
                return 1;
            }
            pInstr += cb;
        }
#endif
    }
    return 0;
}
Пример #2
0
extern "C" DECLEXPORT(void *) SomeExportFunction4(void)
{
    static unsigned cb;
    DISCPUSTATE Cpu;

    memset(&Cpu, 0, sizeof(Cpu));

    DISInstr((void *)(uintptr_t)SomeExportFunction3, DISCPUMODE_32BIT, &Cpu, &cb);
    return (void *)(uintptr_t)&SomeExportFunction1;
}
Пример #3
0
bool MyDisBlock(PDISCPUSTATE pCpu, RTHCUINTPTR pvCodeBlock, int32_t cbMax, RTUINTPTR off)
{
    int32_t i = 0;
    while (i < cbMax)
    {
        char        szOutput[256];
        uint32_t    cbInstr;
        if (RT_FAILURE(DISInstr(pCpu, pvCodeBlock + i, off, &cbInstr, szOutput)))
            return false;

        RTPrintf("%s", szOutput);

        /* next */
        i += cbInstr;
    }
    return true;
}
Пример #4
0
/**
 * Disassembles a code block.
 *
 * @returns VBox error code
 * @param   pCpu            Pointer to cpu structure which have DISCPUSTATE::mode
 *                          set correctly.
 * @param   pvCodeBlock     Pointer to the structure to disassemble.
 * @param   cbMax           Maximum number of bytes to disassemble.
 * @param   pcbSize         Where to store the size of the instruction.
 *                          NULL is allowed.
 *
 *
 * @todo    Define output callback.
 * @todo    Using signed integers as sizes is a bit odd. There are still
 *          some GCC warnings about mixing signed and unsigned integers.
 * @todo    Need to extend this interface to include a code address so we
 *          can disassemble GC code. Perhaps a new function is better...
 * @remark  cbMax isn't respected as a boundary. DISInstr() will read beyond cbMax.
 *          This means *pcbSize >= cbMax sometimes.
 */
DISDECL(int) DISBlock(PDISCPUSTATE pCpu, RTUINTPTR pvCodeBlock, unsigned cbMax, unsigned *pSize)
{
    unsigned i = 0;
    char szOutput[256];

    while (i < cbMax)
    {
        unsigned cbInstr;
        int rc = DISInstr(pCpu, pvCodeBlock + i, 0, &cbInstr, szOutput);
        if (RT_FAILURE(rc))
            return rc;

        i += cbInstr;
    }

    if (pSize)
        *pSize = i;
    return true;
}
Пример #5
0
/**
 * Disassembles a block of memory.
 *
 * @returns VBox status code.
 * @param   argv0           Program name (for errors and warnings).
 * @param   enmCpuMode      The cpu mode to disassemble in.
 * @param   uAddress        The address we're starting to disassemble at.
 * @param   uHighlightAddr  The address of the instruction that should be
 *                          highlighted.  Pass UINT64_MAX to keep quiet.
 * @param   pbFile          Where to start disassemble.
 * @param   cbFile          How much to disassemble.
 * @param   enmStyle        The assembly output style.
 * @param   fListing        Whether to print in a listing like mode.
 * @param   enmUndefOp      How to deal with undefined opcodes.
 */
static int MyDisasmBlock(const char *argv0, DISCPUMODE enmCpuMode, uint64_t uAddress,
                         uint64_t uHighlightAddr, uint8_t *pbFile, size_t cbFile,
                         ASMSTYLE enmStyle, bool fListing, UNDEFOPHANDLING enmUndefOp)
{
    /*
     * Initialize the CPU context.
     */
    MYDISSTATE State;
    State.Cpu.mode = enmCpuMode;
    State.Cpu.pfnReadBytes = MyDisasInstrRead;
    State.uAddress = uAddress;
    State.pbInstr = pbFile;
    State.cbInstr = 0;
    State.enmUndefOp = enmUndefOp;
    State.rc = VINF_SUCCESS;
    State.cbLeft = cbFile;
    State.pbNext = pbFile;
    State.uNextAddr = uAddress;

    void (*pfnFormatter)(PMYDISSTATE pState);
    switch (enmStyle)
    {
        case kAsmStyle_Default:
            pfnFormatter = MyDisasDefaultFormatter;
            break;

        case kAsmStyle_yasm:
            RTPrintf("    BITS %d\n", enmCpuMode == CPUMODE_16BIT ? 16 : enmCpuMode == CPUMODE_32BIT ? 32 : 64);
            pfnFormatter = MyDisasYasmFormatter;
            break;

        case kAsmStyle_masm:
            pfnFormatter = MyDisasMasmFormatter;
            break;

        default:
            AssertFailedReturn(VERR_INTERNAL_ERROR);
    }

    /*
     * The loop.
     */
    int rcRet = VINF_SUCCESS;
    while (State.cbLeft > 0)
    {
        /*
         * Disassemble it.
         */
        State.cbInstr = 0;
        State.cbLeft += State.pbNext - State.pbInstr;
        State.uNextAddr = State.uAddress;
        State.pbNext = State.pbInstr;

        int rc = DISInstr(&State.Cpu, State.uAddress, 0, &State.cbInstr, State.szLine);
        if (    RT_SUCCESS(rc)
            ||  (   (   rc == VERR_DIS_INVALID_OPCODE
                     || rc == VERR_DIS_GEN_FAILURE)
                 &&  State.enmUndefOp == kUndefOp_DefineByte))
        {
            State.fUndefOp = rc == VERR_DIS_INVALID_OPCODE
                          || rc == VERR_DIS_GEN_FAILURE
                          || State.Cpu.pCurInstr->opcode == OP_INVALID
                          || State.Cpu.pCurInstr->opcode == OP_ILLUD2
                          || (    State.enmUndefOp == kUndefOp_DefineByte
                              && !MyDisasIsValidInstruction(&State.Cpu));
            if (State.fUndefOp && State.enmUndefOp == kUndefOp_DefineByte)
            {
                RTPrintf("    db");
                if (!State.cbInstr)
                    State.cbInstr = 1;
                for (unsigned off = 0; off < State.cbInstr; off++)
                {
                    uint8_t b;
                    State.Cpu.pfnReadBytes(State.uAddress + off, &b, 1, &State.Cpu);
                    RTPrintf(off ? ", %03xh" : " %03xh", b);
                }
                RTPrintf("    ; %s\n", State.szLine);
            }
            else if (!State.fUndefOp && State.enmUndefOp == kUndefOp_All)
            {
                RTPrintf("%s: error at %#RX64: unexpected valid instruction (op=%d)\n", argv0, State.uAddress, State.Cpu.pCurInstr->opcode);
                pfnFormatter(&State);
                rcRet = VERR_GENERAL_FAILURE;
            }
            else if (State.fUndefOp && State.enmUndefOp == kUndefOp_Fail)
            {
                RTPrintf("%s: error at %#RX64: undefined opcode (op=%d)\n", argv0, State.uAddress, State.Cpu.pCurInstr->opcode);
                pfnFormatter(&State);
                rcRet = VERR_GENERAL_FAILURE;
            }
            else
            {
                /* Use db for odd encodings that we can't make the assembler use. */
                if (    State.enmUndefOp == kUndefOp_DefineByte
                    &&  MyDisasYasmFormatterIsOddEncoding(&State))
                {
                    RTPrintf("    db");
                    for (unsigned off = 0; off < State.cbInstr; off++)
                    {
                        uint8_t b;
                        State.Cpu.pfnReadBytes(State.uAddress + off, &b, 1, &State.Cpu);
                        RTPrintf(off ? ", %03xh" : " %03xh", b);
                    }
                    RTPrintf(" ; ");
                }

                pfnFormatter(&State);
            }
        }
        else
        {
            State.cbInstr = State.pbNext - State.pbInstr;
            if (!State.cbLeft)
                RTPrintf("%s: error at %#RX64: read beyond the end (%Rrc)\n", argv0, State.uAddress, rc);
            else if (State.cbInstr)
                RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d\n", argv0, State.uAddress, rc, State.cbInstr);
            else
            {
                RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d!\n", argv0, State.uAddress, rc, State.cbInstr);
                if (rcRet == VINF_SUCCESS)
                    rcRet = rc;
                break;
            }
        }

        /* Highlight this instruction? */
        if (uHighlightAddr - State.uAddress < State.cbInstr)
            RTPrintf("; ^^^^^^^^^^^^^^^^^^^^^\n");

        /* next */
        State.uAddress += State.cbInstr;
        State.pbInstr += State.cbInstr;
    }

    return rcRet;
}
Пример #6
0
static void rtMemReplaceMallocAndFriends(void)
{
    struct
    {
        const char *pszName;
        PFNRT       pfnReplacement;
        PFNRT       pfnOrg;
        PFNRT      *ppfnJumpBack;
    } aApis[] =
    {
        { "free",    (PFNRT)rtMemReplacementFree,    (PFNRT)free,    (PFNRT *)&g_pfnOrgFree },
        { "realloc", (PFNRT)rtMemReplacementRealloc, (PFNRT)realloc, (PFNRT *)&g_pfnOrgRealloc },
        { "calloc",  (PFNRT)rtMemReplacementCalloc,  (PFNRT)calloc,  (PFNRT *)&g_pfnOrgCalloc },
        { "malloc",  (PFNRT)rtMemReplacementMalloc,  (PFNRT)malloc,  (PFNRT *)&g_pfnOrgMalloc },
#ifdef RT_OS_DARWIN
        { "malloc_size", (PFNRT)rtMemReplacementMallocSize,  (PFNRT)malloc_size,  (PFNRT *)&g_pfnOrgMallocSize },
#endif
    };

    /*
     * Initialize the jump backs to avoid recursivly entering this function.
     */
    for (unsigned i = 0; i < RT_ELEMENTS(aApis); i++)
        *aApis[i].ppfnJumpBack = aApis[i].pfnOrg;

    /*
     * Give the user an option to skip replacing malloc.
     */
    if (getenv("IPRT_DONT_REPLACE_MALLOC"))
        return;

    /*
     * Allocate a page for jump back code (we leak it).
     */
    uint8_t *pbExecPage = (uint8_t *)RTMemPageAlloc(PAGE_SIZE); AssertFatal(pbExecPage);
    int rc = RTMemProtect(pbExecPage, PAGE_SIZE, RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC); AssertFatalRC(rc);

    /*
     * Do the ground work.
     */
    uint8_t *pb = pbExecPage;
    for (unsigned i = 0; i < RT_ELEMENTS(aApis); i++)
    {
        /* Resolve it. */
        PFNRT pfnOrg = (PFNRT)(uintptr_t)dlsym(RTLD_DEFAULT, aApis[i].pszName);
        if (pfnOrg)
            aApis[i].pfnOrg = pfnOrg;
        else
            pfnOrg = aApis[i].pfnOrg;

        /* Figure what we can replace and how much to duplicate in the jump back code. */
# ifdef RT_ARCH_AMD64
        uint32_t         cbNeeded   = 12;
        DISCPUMODE const enmCpuMode = DISCPUMODE_64BIT;
# elif defined(RT_ARCH_X86)
        uint32_t   const cbNeeded   = 5;
        DISCPUMODE const enmCpuMode = DISCPUMODE_32BIT;
# else
#  error "Port me"
# endif
        uint32_t offJmpBack = 0;
        uint32_t cbCopy = 0;
        while (offJmpBack < cbNeeded)
        {
            DISCPUSTATE Dis;
            uint32_t cbInstr = 1;
            rc = DISInstr((void *)((uintptr_t)pfnOrg + offJmpBack), enmCpuMode, &Dis, &cbInstr); AssertFatalRC(rc);
            AssertFatal(!(Dis.pCurInstr->fOpType & (DISOPTYPE_CONTROLFLOW)));
# ifdef RT_ARCH_AMD64
#  ifdef RT_OS_DARWIN
            /* Kludge for: cmp [malloc_def_zone_state], 1; jg 2; call _malloc_initialize; 2: */
            DISQPVPARAMVAL Parm;
            if (   Dis.ModRM.Bits.Mod == 0
                && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */
                && (Dis.Param2.fUse & (DISUSE_IMMEDIATE16_SX8 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE64_SX8))
                && Dis.Param2.uValue == 1
                && Dis.pCurInstr->uOpcode == OP_CMP)
            {
                cbCopy = offJmpBack;

                offJmpBack += cbInstr;
                rc = DISInstr((void *)((uintptr_t)pfnOrg + offJmpBack), enmCpuMode, &Dis, &cbInstr); AssertFatalRC(rc);
                if (   Dis.pCurInstr->uOpcode == OP_JNBE
                    && Dis.Param1.uDisp.i8 == 5)
                {
                    offJmpBack += cbInstr + 5;
                    AssertFatal(offJmpBack >= cbNeeded);
                    break;
                }
            }
#  endif
            AssertFatal(!(Dis.ModRM.Bits.Mod == 0 && Dis.ModRM.Bits.Rm == 5 /* wrt RIP */));
# endif
            offJmpBack += cbInstr;
        }
        if (!cbCopy)
            cbCopy = offJmpBack;

        /* Assemble the jump back. */
        memcpy(pb, (void *)(uintptr_t)pfnOrg, cbCopy);
        uint32_t off = cbCopy;
# ifdef RT_ARCH_AMD64
        pb[off++] = 0xff; /* jmp qword [$+8 wrt RIP] */
        pb[off++] = 0x25;
        *(uint32_t *)&pb[off] = 0;
        off += 4;
        *(uint64_t *)&pb[off] = (uintptr_t)pfnOrg + offJmpBack;
        off += 8;
        off = RT_ALIGN_32(off, 16);
# elif defined(RT_ARCH_X86)
        pb[off++] = 0xe9; /* jmp rel32 */
        *(uint32_t *)&pb[off] = (uintptr_t)pfnOrg + offJmpBack - (uintptr_t)&pb[4];
        off += 4;
        off = RT_ALIGN_32(off, 8);
# else
#  error "Port me"
# endif
        *aApis[i].ppfnJumpBack = (PFNRT)(uintptr_t)pb;
        pb += off;
    }

    /*
     * Modify the APIs.
     */
    for (unsigned i = 0; i < RT_ELEMENTS(aApis); i++)
    {
        pb = (uint8_t *)(uintptr_t)aApis[i].pfnOrg;
        rc = RTMemProtect(pb, 16, RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC); AssertFatalRC(rc);

# ifdef RT_ARCH_AMD64
        /* Assemble the LdrLoadDll patch. */
        *pb++ = 0x48; /* mov rax, qword */
        *pb++ = 0xb8;
        *(uint64_t *)pb = (uintptr_t)aApis[i].pfnReplacement;
        pb += 8;
        *pb++ = 0xff; /* jmp rax */
        *pb++ = 0xe0;
# elif defined(RT_ARCH_X86)
        *pb++ = 0xe9; /* jmp rel32 */
        *(uint32_t *)pb = (uintptr_t)aApis[i].pfnReplacement - (uintptr_t)&pb[4];
# else
#  error "Port me"
# endif
    }
}