|
|
/* @ Author: Gerd Immeyer @ Version: */ /* */ /* @ Creation Date: 10.19.89 @ Modification Date: */ /* */ /***************************************************************************/
//
// Munged for my purposes on 10/20/99 (v-johnwh)
//
#include <string.h>
typedef unsigned long DWORD; typedef unsigned long ULONG; typedef unsigned short USHORT; typedef unsigned __int64 ULONGLONG; typedef int BOOL; typedef ULONG *PULONG; typedef void * PVOID; #define ADDR_V86 ((USHORT)0x0002)
#define ADDR_16 ((USHORT)0x0004)
#define FALSE 0
#define TRUE 1
#define BIT20(b) (b & 0x07)
#define BIT53(b) (b >> 3 & 0x07)
#define BIT76(b) (b >> 6 & 0x03)
#define MAXL 16
#define MAXOPLEN 10
#define REGDS 3
#define REGSS 15
#define REGEBX 6
#define REGEBP 10
#define REGEDI 4
#define REGESI 5
#define REGEAX 9
#define REGECX 8
#define REGEDX 7
#define REGESP 14
#define Off(x) ((x).off)
#define Type(x) ((x).type)
#define OBOFFSET 26
#define OBOPERAND 34
#define OBLINEEND 77
#define MAX_SYMNAME_SIZE 1024
#include "86dis.h"
ULONG X86BrkptLength = 1L; ULONG X86TrapInstr = 0xcc;
/***** static tables and variables *****/ static char regtab[] = "alcldlblahchdhbhaxcxdxbxspbpsidi"; /* reg table */ static char *mrmtb16[] = { "bx+si", /* modRM string table (16-bit) */ "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx" };
static char *mrmtb32[] = { "eax", /* modRM string table (32-bit) */ "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
static char seg16[8] = { REGDS, REGDS, REGSS, REGSS, REGDS, REGDS, REGSS, REGDS }; static char reg16[8] = { REGEBX, REGEBX, REGEBP, REGEBP, REGESI, REGEDI, REGEBP, REGEBX }; static char reg16_2[4] = { REGESI, REGEDI, REGESI, REGEDI };
static char seg32[8] = { REGDS, REGDS, REGDS, REGDS, REGSS, REGSS, REGDS, REGDS }; static char reg32[8] = { REGEAX, REGECX, REGEDX, REGEBX, REGESP, REGEBP, REGESI, REGEDI };
static char sregtab[] = "ecsdfg"; // first letter of ES, CS, SS, DS, FS, GS
char hexdigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
typedef struct _DECODEDATA { int mod; /* mod of mod/rm byte */ int rm; /* rm of mod/rm byte */ int ttt; /* return reg value (of mod/rm) */ unsigned char *pMem; /* current position in instruction */ ADDR EAaddr[2]; // offset of effective address
int EAsize[2]; // size of effective address item
char *pchEAseg[2]; // normal segment for operand
BOOL fMovX; // indicates a MOVSX or MOVZX
BOOL fMmRegEa; // Use mm? registers in reg-only EA.
} DECODEDATA; /*...........................internal function..............................*/ /* */ /* generate a mod/rm string */ /* */
void DIdoModrm (char **ppchBuf, int segOvr, DECODEDATA *decodeData) { int mrm; /* modrm byte */ char *src; /* source string */ int sib; int ss; int ind; int oldrm;
mrm = *(decodeData->pMem)++; /* get the mrm byte from instruction */ decodeData->mod = BIT76(mrm); /* get mod */ decodeData->ttt = BIT53(mrm); /* get reg - used outside routine */ decodeData->rm = BIT20(mrm); /* get rm */
if (decodeData->mod == 3) { /* register only mode */ if (decodeData->fMmRegEa) { *(*ppchBuf)++ = 'm'; *(*ppchBuf)++ = 'm'; *(*ppchBuf)++ = decodeData->rm + '0'; } else { src = ®tab[decodeData->rm * 2]; /* point to 16-bit register */ if (decodeData->EAsize[0] > 1) { src += 16; /* point to 16-bit register */ if (!(decodeData->fMovX)) *(*ppchBuf)++ = 'e'; /* make it a 32-bit register */ } *(*ppchBuf)++ = *src++; /* copy register name */ *(*ppchBuf)++ = *src; } decodeData->EAsize[0] = 0; // no EA value to output
return; }
if (1) { /* 32-bit addressing mode */ oldrm = decodeData->rm; if (decodeData->rm == 4) { /* rm == 4 implies sib byte */ sib = *(decodeData->pMem)++; /* get s_i_b byte */ decodeData->rm = BIT20(sib); /* return base */ }
*(*ppchBuf)++ = '['; if (decodeData->mod == 0 && decodeData->rm == 5) { decodeData->pMem += 4; }
if (oldrm == 4) { // finish processing sib
ind = BIT53(sib); if (ind != 4) { *(*ppchBuf)++ = '+'; ss = 1 << BIT76(sib); if (ss != 1) { *(*ppchBuf)++ = '*'; *(*ppchBuf)++ = (char)(ss + '0'); } } } }
// output any displacement
if (decodeData->mod == 1) { decodeData->pMem++; } else if (decodeData->mod == 2) { long tmp = 0; if (1) { decodeData->pMem += 4; } else { decodeData->pMem += 2; } } }
DWORD GetInstructionLengthFromAddress(PVOID paddr) { PULONG pOffset = 0; int G_mode_32; int mode_32; /* local addressing mode indicator */ int opsize_32; /* operand size flag */ int opcode; /* current opcode */ int olen = 2; /* operand length */ int alen = 2; /* address length */ int end = FALSE; /* end of instruction flag */ int mrm = FALSE; /* indicator that modrm is generated*/ unsigned char *action; /* action for operand interpretation*/ long tmp; /* temporary storage field */ int indx; /* temporary index */ int action2; /* secondary action */ int instlen; /* instruction length */ int segOvr = 0; /* segment override opcode */ unsigned char *membuf; /* current instruction buffer */ char *pEAlabel = ""; /* optional label for operand */ char RepPrefixBuffer[32]; /* rep prefix buffer */ char *pchRepPrefixBuf = RepPrefixBuffer; /* pointer to prefix buffer */ char OpcodeBuffer[8]; /* opcode buffer */ char *pchOpcodeBuf = OpcodeBuffer; /* pointer to opcode buffer */ char OperandBuffer[MAX_SYMNAME_SIZE + 20]; /* operand buffer */ char *pchOperandBuf = OperandBuffer; /* pointer to operand buffer */ char ModrmBuffer[MAX_SYMNAME_SIZE + 20]; /* modRM buffer */ char *pchModrmBuf = ModrmBuffer; /* pointer to modRM buffer */ char EABuffer[42]; /* effective address buffer */ char *pchEABuf = EABuffer; /* pointer to EA buffer */
unsigned char BOPaction; int subcode; /* bop subcode */ DECODEDATA decodeData;
decodeData.fMovX = FALSE; decodeData.fMmRegEa = FALSE; decodeData.EAsize[0] = decodeData.EAsize[1] = 0; // no effective address
decodeData.pchEAseg[0] = dszDS_; decodeData.pchEAseg[1] = dszES_;
G_mode_32 = 1;
mode_32 = opsize_32 = (G_mode_32 == 1); /* local addressing mode */ olen = alen = (1 + mode_32) << 1; // set operand/address lengths
// 2 for 16-bit and 4 for 32-bit
#if MULTIMODE
if (paddr->type & (ADDR_V86 | ADDR_16)) { mode_32 = opsize_32 = 0; olen = alen = 2; } #endif
membuf = (unsigned char *)paddr; decodeData.pMem = membuf; /* point to begin of instruction */ opcode = *(decodeData.pMem)++; /* get opcode */
if ( opcode == 0xc4 && *(decodeData.pMem) == 0xC4 ) { (decodeData.pMem)++; action = &BOPaction; BOPaction = IB | END; subcode = *(decodeData.pMem); if ( subcode == 0x50 || subcode == 0x52 || subcode == 0x53 || subcode == 0x54 || subcode == 0x57 || subcode == 0x58 || subcode == 0x58 ) { BOPaction = IW | END; } } else { action = actiontbl + distbl[opcode].opr; /* get operand action */ }
/***** loop through all operand actions *****/
do { action2 = (*action) & 0xc0; switch((*action++) & 0x3f) { case ALT: /* alter the opcode if 32-bit */ if (opsize_32) { indx = *action++; pchOpcodeBuf = &OpcodeBuffer[indx]; if (indx == 0) ; else { *pchOpcodeBuf++ = 'd'; if (indx == 1) *pchOpcodeBuf++ = 'q'; } } break;
case STROP: // compute size of operands in indx
// also if dword operands, change fifth
// opcode letter from 'w' to 'd'.
if (opcode & 1) { if (opsize_32) { indx = 4; OpcodeBuffer[4] = 'd'; } else indx = 2; } else indx = 1;
if (*action & 1) { } if (*action++ & 2) { } break;
case CHR: /* insert a character */ *pchOperandBuf++ = *action++; break;
case CREG: /* set debug, test or control reg */ if ((opcode - SECTAB_OFFSET_2)&0x04) //remove bias from opcode
*pchOperandBuf++ = 't'; else if ((opcode - SECTAB_OFFSET_2) & 0x01) *pchOperandBuf++ = 'd'; else *pchOperandBuf++ = 'c'; *pchOperandBuf++ = 'r'; *pchOperandBuf++ = (char)('0' + decodeData.ttt); break;
case SREG2: /* segment register */ // Handle special case for fs/gs (OPC0F adds SECTAB_OFFSET_5
// to these codes)
if (opcode > 0x7e) decodeData.ttt = BIT53((opcode-SECTAB_OFFSET_5)); else decodeData.ttt = BIT53(opcode); // set value to fall through
case SREG3: /* segment register */ *pchOperandBuf++ = sregtab[decodeData.ttt]; // reg is part of modrm
*pchOperandBuf++ = 's'; break;
case BRSTR: /* get index to register string */ decodeData.ttt = *action++; /* from action table */ goto BREGlabel;
case BOREG: /* byte register (in opcode) */ decodeData.ttt = BIT20(opcode); /* register is part of opcode */ goto BREGlabel;
case ALSTR: decodeData.ttt = 0; /* point to AL register */ BREGlabel: case BREG: /* general register */ *pchOperandBuf++ = regtab[decodeData.ttt * 2]; *pchOperandBuf++ = regtab[decodeData.ttt * 2 + 1]; break;
case WRSTR: /* get index to register string */ decodeData.ttt = *action++; /* from action table */ goto WREGlabel;
case VOREG: /* register is part of opcode */ decodeData.ttt = BIT20(opcode); goto VREGlabel;
case AXSTR: decodeData.ttt = 0; /* point to eAX register */ VREGlabel: case VREG: /* general register */ if (opsize_32) /* test for 32bit mode */ *pchOperandBuf++ = 'e'; WREGlabel: case WREG: /* register is word size */ *pchOperandBuf++ = regtab[decodeData.ttt * 2 + 16]; *pchOperandBuf++ = regtab[decodeData.ttt * 2 + 17]; break;
case MMWREG: *pchOperandBuf++ = 'm'; *pchOperandBuf++ = 'm'; *pchOperandBuf++ = decodeData.ttt + '0'; break;
case IST_ST: *(pchOperandBuf - 5) += (char)decodeData.rm; break;
case ST_IST: ; case IST: ; *(pchOperandBuf - 2) += (char)decodeData.rm; break;
case xBYTE: /* set instruction to byte only */ decodeData.EAsize[0] = 1; break;
case VAR: if (opsize_32) goto DWORDlabel;
case xWORD: decodeData.EAsize[0] = 2; break;
case EDWORD: opsize_32 = 1; // for control reg move, use eRegs
case xDWORD: DWORDlabel: decodeData.EAsize[0] = 4; break;
case MMQWORD: decodeData.fMmRegEa = TRUE;
case QWORD: decodeData.EAsize[0] = 8; break;
case TBYTE: decodeData.EAsize[0] = 10; break;
case FARPTR: if (opsize_32) { decodeData.EAsize[0] = 6; } else { decodeData.EAsize[0] = 4; } break;
case LMODRM: // output modRM data type
if (decodeData.mod != 3) ; else decodeData.EAsize[0] = 0;
case MODRM: /* output modrm string */ if (segOvr) /* in case of segment override */ 0; break;
case ADDRP: /* address pointer */ decodeData.pMem += olen + 2; break;
case REL8: /* relative address 8-bit */ if (opcode == 0xe3 && mode_32) { pchOpcodeBuf = OpcodeBuffer; } tmp = (long)*(char *)(decodeData.pMem)++; /* get the 8-bit rel offset */ goto DoRelDispl;
case REL16: /* relative address 16-/32-bit */ tmp = 0; if (mode_32) memmove(&tmp,decodeData.pMem,sizeof(long)); else memmove(&tmp,decodeData.pMem,sizeof(short)); decodeData.pMem += alen; /* skip over offset */ DoRelDispl: // tmp += *pOffset + (decodeData.pMem - membuf); /* calculate address */
// address
break;
case UBYTE: // unsigned byte for int/in/out
decodeData.pMem++; break;
case IB: /* operand is immediate byte */ if ((opcode & ~1) == 0xd4) { // postop for AAD/AAM is 0x0a
if (*(decodeData.pMem)++ != 0x0a) // test post-opcode byte
0; break; } olen = 1; /* set operand length */ goto DoImmed;
case IW: /* operand is immediate word */ olen = 2; /* set operand length */
case IV: /* operand is word or dword */ DoImmed: decodeData.pMem += olen; break;
case OFFS: /* operand is offset */ decodeData.EAsize[0] = (opcode & 1) ? olen : 1;
if (segOvr) /* in case of segment override */ 0;
decodeData.pMem += alen; break;
case GROUP: /* operand is of group 1,2,4,6 or 8 */ /* output opcode symbol */ action++; break;
case GROUPT: /* operand is of group 3,5 or 7 */ indx = *action; /* get indx into group from action */ goto doGroupT;
case EGROUPT: /* x87 ESC (D8-DF) group index */ indx = BIT20(opcode) * 2; /* get group index from opcode */ if (decodeData.mod == 3) { /* some operand variations exists */ /* for x87 and mod == 3 */ ++indx; /* take the next group table entry */ if (indx == 3) { /* for x87 ESC==D9 and mod==3 */ if (decodeData.ttt > 3) { /* for those D9 instructions */ indx = 12 + decodeData.ttt; /* offset index to table by 12 */ decodeData.ttt = decodeData.rm; /* set secondary index to rm */ } } else if (indx == 7) { /* for x87 ESC==DB and mod==3 */ if (decodeData.ttt == 4) { /* if ttt==4 */ decodeData.ttt = decodeData.rm; /* set secondary group table index */ } else if ((decodeData.ttt<4)||(decodeData.ttt>4 && decodeData.ttt<7)) { // adjust for pentium pro opcodes
indx = 24; /* offset index to table by 24*/ } } } doGroupT: /* handle group with different types of operands */ action = actiontbl + groupt[indx][decodeData.ttt].opr; /* get new action */ break; //
// The secondary opcode table has been compressed in the
// original design. Hence while disassembling the 0F sequence,
// opcode needs to be displaced by an appropriate amount depending
// on the number of "filled" entries in the secondary table.
// These displacements are used throughout the code.
//
case OPC0F: /* secondary opcode table (opcode 0F) */ opcode = *(decodeData.pMem)++; /* get real opcode */ decodeData.fMovX = (BOOL)(opcode == 0xBF || opcode == 0xB7); if (opcode < 12) /* for the first 12 opcodes */ opcode += SECTAB_OFFSET_1; // point to begin of sec op tab
else if (opcode > 0x1f && opcode < 0x27) opcode += SECTAB_OFFSET_2; // adjust for undefined opcodes
else if (opcode > 0x2f && opcode < 0x34) opcode += SECTAB_OFFSET_3; // adjust for undefined opcodes
else if (opcode > 0x3f && opcode < 0x50) opcode += SECTAB_OFFSET_4; // adjust for undefined opcodes
else if (opcode > 0x5f && opcode < 0xff) opcode += SECTAB_OFFSET_5; // adjust for undefined opcodes
else opcode = SECTAB_OFFSET_UNDEF; // all non-existing opcodes
goto getNxtByte1;
case ADR_OVR: /* address override */ mode_32 = !G_mode_32; /* override addressing mode */ alen = (mode_32 + 1) << 1; /* toggle address length */ goto getNxtByte;
case OPR_OVR: /* operand size override */ opsize_32 = !G_mode_32; /* override operand size */ olen = (opsize_32 + 1) << 1; /* toggle operand length */ goto getNxtByte;
case SEG_OVR: /* handle segment override */ segOvr = opcode; /* save segment override opcode */ pchOpcodeBuf = OpcodeBuffer; // restart the opcode string
goto getNxtByte;
case REP: /* handle rep/lock prefixes */ if (pchRepPrefixBuf != RepPrefixBuffer) *pchRepPrefixBuf++ = ' '; pchOpcodeBuf = OpcodeBuffer; getNxtByte: opcode = *(decodeData.pMem)++; /* next byte is opcode */ getNxtByte1: action = actiontbl + distbl[opcode].opr;
default: /* opcode has no operand */ break; } switch (action2) { /* secondary action */ case MRM: /* generate modrm for later use */ if (!mrm) { /* ignore if it has been generated */ DIdoModrm(&pchModrmBuf, segOvr, &decodeData); mrm = TRUE; /* remember its generation */ } break;
case COM: /* insert a comma after operand */ break;
case END: /* end of instruction */ end = TRUE; break; } } while (!end); /* loop til end of instruction */
instlen = (decodeData.pMem) - membuf;
return instlen; }
|