📄 disasm.cpp
字号:
//////////////////////////////////////////////////////////////////////////////
//
// Module: detours.lib
// File: disasm.cpp
// Author: Doug Brubacher
//
// Detours for binary functions. Version 1.2. (Build 35)
// Includes support for all x86 chips prior to the Pentium III.
//
// Copyright 1999, Microsoft Corporation
//
// http://research.microsoft.com/sn/detours
//
#include <ole2.h>
#include <imagehlp.h>
#include "detours.h"
#include "disasm.h"
#undef ASSERT
#define ASSERT(x)
//////////////////////////////////////////////////////////////////////////////
//
// Function:
// DetourCopyInstruction(PBYTE pbDst, PBYTE pbSrc, PBYTE *ppbTarget)
// Purpose:
// Copy a single instruction from pbSrc to pbDst.
// Arguments:
// pbDst:
// Destination address for the instruction. May be NULL in which
// case DetourCopyInstruction is used to measure an instruction.
// If not NULL then the source instruction is copied to the
// destination instruction and any relative arguments are adjusted.
// pbSrc:
// Source address of the instruction.
// ppbTarget:
// Out parameter for any target instruction address pointed to by
// the instruction. For example, a branch or a jump insruction has
// a target, but a load or store instruction doesn't. A target is
// another instruction that may be executed as a result of this
// instruction. ppbTarget may be NULL.
// plExtra:
// Out parameter for the number of extra bytes needed by the
// instruction to reach the target. For example, lExtra = 3 if the
// instruction had an 8-bit relative offset, but needs a 32-bit
// relative offset.
// Returns:
// Returns the address of the next instruction (following in the source)
// instruction. By subtracting pbSrc from the return value, the caller
// can determinte the size of the instruction copied.
// Comments:
// By following the pbTarget, the caller can follow alternate
// instruction streams. However, it is not always possible to determine
// the target based on static analysis. For example, the destination of
// a jump relative to a register cannot be determined from just the
// instruction stream. The output value, pbTarget, can have any of the
// following outputs:
// DETOUR_INSTRUCTION_TARGET_NONE:
// The instruction has no targets.
// DETOUR_INSTRUCTION_TARGET_DYNAMIC:
// The instruction has a non-deterministic (dynamic) target.
// (i.e. the jump is to an address held in a register.)
// Address: The instruction has the specified target.
//
// When copying instructions, DetourCopyInstruction insures that any
// targets remain constant. It does so by adjusting any IP relative
// offsets.
//
PBYTE WINAPI DetourCopyInstructionEx(PBYTE pbDst,
PBYTE pbSrc,
PBYTE *ppbTarget,
LONG *plExtra)
{
CDetourDis oDetourDisasm(ppbTarget, plExtra);
return oDetourDisasm.CopyInstruction(pbDst, pbSrc);
}
PBYTE WINAPI DetourCopyInstruction(PBYTE pbDst, PBYTE pbSrc, PBYTE *ppbTarget)
{
CDetourDis oDetourDisasm(ppbTarget, NULL);
return oDetourDisasm.CopyInstruction(pbDst, pbSrc);
}
/////////////////////////////////////////////////////////// Disassembler Code.
//
CDetourDis::CDetourDis(PBYTE *ppbTarget, LONG *plExtra)
{
Set32BitOperand();
Set32BitAddress();
m_ppbTarget = ppbTarget ? ppbTarget : &m_pbScratchTarget;
m_plExtra = plExtra ? plExtra : &m_lScratchExtra;
*m_ppbTarget = DETOUR_INSTRUCTION_TARGET_NONE;
*m_plExtra = 0;
}
VOID CDetourDis::Set16BitOperand()
{
m_b16BitOperand = TRUE;
}
VOID CDetourDis::Set32BitOperand()
{
m_b16BitOperand = FALSE;
}
VOID CDetourDis::Set16BitAddress()
{
m_b16BitAddress = TRUE;
}
VOID CDetourDis::Set32BitAddress()
{
m_b16BitAddress = FALSE;
}
PBYTE CDetourDis::CopyInstruction(PBYTE pbDst, PBYTE pbSrc)
{
// Configure scratch areas if real areas are not available.
if (NULL == pbDst) {
pbDst = m_rbScratchDst;
}
if (NULL == pbSrc) {
// We can't copy a non-existent instruction.
SetLastError(ERROR_INVALID_DATA);
return NULL;
}
// Figure out how big the instruction is, do the appropriate copy,
// and figure out what the target of the instruction is if any.
//
REFCOPYENTRY pEntry = &s_rceCopyTable[pbSrc[0]];
return (this->*pEntry->pfCopy)(pEntry, pbDst, pbSrc);
}
PBYTE CDetourDis::CopyBytes(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
{
LONG nBytesFixed = (pEntry->nFlagBits & ADDRESS)
? (m_b16BitAddress ? pEntry->nFixedSize16 : pEntry->nFixedSize)
: (m_b16BitOperand ? pEntry->nFixedSize16 : pEntry->nFixedSize);
LONG nBytes = nBytesFixed;
if (pEntry->nModOffset > 0) {
BYTE bModRm = pbSrc[pEntry->nModOffset];
BYTE bFlags = s_rbModRm[bModRm];
if (bFlags & SIB) {
BYTE bSib = pbSrc[pEntry->nModOffset + 1];
if ((bSib & 0x07) == 0x05) {
if ((bModRm & 0xc0) == 0x00) {
nBytes += 4;
}
else if ((bModRm & 0xc0) == 0x40) {
nBytes += 1;
}
else if ((bModRm & 0xc0) == 0x80) {
nBytes += 4;
}
}
}
nBytes += bFlags & NOTSIB;
}
CopyMemory(pbDst, pbSrc, nBytes);
if (pEntry->nRelOffset) {
*m_ppbTarget = AdjustTarget(pbDst, pbSrc, nBytesFixed, pEntry->nRelOffset);
}
if (pEntry->nFlagBits & NOENLARGE) {
*m_plExtra = -*m_plExtra;
}
if (pEntry->nFlagBits & DYNAMIC) {
*m_ppbTarget = DETOUR_INSTRUCTION_TARGET_DYNAMIC;
}
return pbSrc + nBytes;
}
PBYTE CDetourDis::CopyBytesPrefix(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
{
CopyBytes(pEntry, pbDst, pbSrc);
pEntry = &s_rceCopyTable[pbSrc[1]];
return (this->*pEntry->pfCopy)(pEntry, pbDst + 1, pbSrc + 1);
}
PBYTE CDetourDis::AdjustTarget(PBYTE pbDst, PBYTE pbSrc, LONG cbOp, LONG cbTargetOffset)
{
LONG cbTargetSize = cbOp - cbTargetOffset;
PBYTE pbTarget = NULL;
PVOID pvTargetAddr = &pbDst[cbTargetOffset];
LONG nOldOffset = 0;
switch (cbTargetSize) {
case 1:
nOldOffset = (LONG)*(PCHAR&)pvTargetAddr;
*m_plExtra = 3;
break;
case 2:
nOldOffset = (LONG)*(PSHORT&)pvTargetAddr;
*m_plExtra = 2;
break;
case 4:
nOldOffset = (LONG)*(PLONG&)pvTargetAddr;
*m_plExtra = 0;
break;
default:
ASSERT(!"cbTargetSize is invalid.");
break;
}
pbTarget = pbSrc + cbOp + nOldOffset;
LONG nNewOffset = nOldOffset - (pbDst - pbSrc);
switch (cbTargetSize) {
case 1:
*(PCHAR&)pvTargetAddr = (CHAR)nNewOffset;
break;
case 2:
*(PSHORT&)pvTargetAddr = (SHORT)nNewOffset;
break;
case 4:
*(PLONG&)pvTargetAddr = (LONG)nNewOffset;
break;
}
ASSERT(pbDst + cbOp + nNewOffset == pbTarget);
return pbTarget;
}
PBYTE CDetourDis::Invalid(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
{
ASSERT(!"Invalid Instruction");
return pbSrc + 1;
}
////////////////////////////////////////////////////// Individual Bytes Codes.
//
PBYTE CDetourDis::Copy0F(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
{
CopyBytes(pEntry, pbDst, pbSrc);
pEntry = &s_rceCopyTable0F[pbSrc[1]];
return (this->*pEntry->pfCopy)(pEntry, pbDst + 1, pbSrc + 1);
}
PBYTE CDetourDis::Copy66(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
{ // Operand-size override prefix
Set16BitOperand();
return CopyBytesPrefix(pEntry, pbDst, pbSrc);
}
PBYTE CDetourDis::Copy67(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
{ // Address size override prefix
Set16BitAddress();
return CopyBytesPrefix(pEntry, pbDst, pbSrc);
}
PBYTE CDetourDis::CopyF6(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
{
// TEST BYTE /0
if (0x00 == (0x38 & pbSrc[1])) { // reg(bits 543) of ModR/M == 0
const COPYENTRY ce = { 0xf6, ENTRY_CopyBytes2Mod1 };
return (this->*ce.pfCopy)(&ce, pbDst, pbSrc);
}
// DIV /6
// IDIV /7
// IMUL /5
// MUL /4
// NEG /3
// NOT /2
const COPYENTRY ce = { 0xf6, ENTRY_CopyBytes2Mod };
return (this->*ce.pfCopy)(&ce, pbDst, pbSrc);
}
PBYTE CDetourDis::CopyF7(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
{
// TEST WORD /0
if (0x00 == (0x38 & pbSrc[1])) { // reg(bits 543) of ModR/M == 0
const COPYENTRY ce = { 0xf7, ENTRY_CopyBytes2ModOperand };
return (this->*ce.pfCopy)(&ce, pbDst, pbSrc);
}
// DIV /6
// IDIV /7
// IMUL /5
// MUL /4
// NEG /3
// NOT /2
const COPYENTRY ce = { 0xf7, ENTRY_CopyBytes2Mod };
return (this->*ce.pfCopy)(&ce, pbDst, pbSrc);
}
PBYTE CDetourDis::CopyFF(REFCOPYENTRY pEntry, PBYTE pbDst, PBYTE pbSrc)
{ // CALL /2
// CALL /3
// INC /0
// JMP /4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -