?? disasm.c
字號:
da->immconst=seg;
if (addr==0 || seg==0) da->zeroconst=1;
if (mode>=DISASM_FILE) {
nresult+=sprintf(da->result+nresult,"%s %04X:%08X",
(lowercase==0?"FAR":"far"),seg,addr);
};
};
// Decode segment register. In flat model, operands of this type are seldom.
static void DecodeSG(int index) {
int i;
if (mode<DISASM_DATA) return;
index&=0x07;
if (index>=6) softerror=DAE_BADSEG; // Undefined segment register
if (mode>=DISASM_FILE) {
i=sprintf(da->result+nresult,"%s",segname[index]);
if (lowercase) strlwr(da->result+nresult);
nresult+=i;
};
};
// Decode control register addressed in R part of ModRM byte. Operands of
// this type are extremely rare. Contents of control registers are accessible
// only from privilege level 0, so I cannot dump them here.
static void DecodeCR(int index) {
hasrm=1;
if (mode>=DISASM_FILE) {
index=(index>>3) & 0x07;
nresult+=sprintf(da->result+nresult,"%s",crname[index]);
if (lowercase) strlwr(da->result+nresult);
};
};
// Decode debug register addressed in R part of ModRM byte. Operands of
// this type are extremely rare. I can dump only those debug registers
// available in CONTEXT structure.
static void DecodeDR(int index) {
int i;
hasrm=1;
if (mode>=DISASM_FILE) {
index=(index>>3) & 0x07;
i=sprintf(da->result+nresult,"%s",drname[index]);
if (lowercase) strlwr(da->result+nresult);
nresult+=i;
};
};
// Skips 3DNow! operands and extracts command suffix. Returns suffix or -1 if
// suffix lies outside the memory block. This subroutine assumes that cmd still
// points to the beginning of 3DNow! command (i.e. to the sequence of two bytes
// 0F, 0F).
static int Get3dnowsuffix(void) {
int c,sib;
ulong offset;
if (size<3) return -1; // Suffix outside the memory block
offset=3;
c=cmd[2] & 0xC7; // Leave only Mod and M fields
// Register in ModM - general-purpose, MMX or 3DNow!
if ((c & 0xC0)==0xC0)
;
// 16-bit addressing mode, SIB byte is never used here.
else if (addrsize==2) {
if (c==0x06) // Special case of immediate address
offset+=2;
else if ((c & 0xC0)==0x40) // 8-bit signed displacement
offset++;
else if ((c & 0xC0)==0x80) // 16-bit unsigned displacement
offset+=2;
; }
// Immediate 32-bit address.
else if (c==0x05) // Special case of immediate address
offset+=4;
// 32-bit address with SIB byte.
else if ((c & 0x07)==0x04) { // SIB addresation
if (size<4) return -1; // Suffix outside the memory block
sib=cmd[3]; offset++;
if (c==0x04 && (sib & 0x07)==0x05)
offset+=4; // Immediate address without base
else if ((c & 0xC0)==0x40) // 8-bit displacement
offset+=1;
else if ((c & 0xC0)==0x80) // 32-bit dislacement
offset+=4;
; }
// 32-bit address without SIB byte
else if ((c & 0xC0)==0x40)
offset+=1;
else if ((c & 0xC0)==0x80)
offset+=4;
if (offset>=size) return -1; // Suffix outside the memory block
return cmd[offset];
};
// Function checks whether 80x86 flags meet condition set in the command.
// Returns 1 if condition is met, 0 if not and -1 in case of error (which is
// not possible).
int Checkcondition(int code,ulong flags) {
ulong cond,temp;
switch (code & 0x0E) {
case 0: // If overflow
cond=flags & 0x0800; break;
case 2: // If below
cond=flags & 0x0001; break;
case 4: // If equal
cond=flags & 0x0040; break;
case 6: // If below or equal
cond=flags & 0x0041; break;
case 8: // If sign
cond=flags & 0x0080; break;
case 10: // If parity
cond=flags & 0x0004; break;
case 12: // If less
temp=flags & 0x0880;
cond=(temp==0x0800 || temp==0x0080); break;
case 14: // If less or equal
temp=flags & 0x0880;
cond=(temp==0x0800 || temp==0x0080 || (flags & 0x0040)!=0); break;
default: return -1; // Internal error, not possible!
};
if ((code & 0x01)==0) return (cond!=0);
else return (cond==0); // Invert condition
};
ulong Disasm(char *src,ulong srcsize,ulong srcip,
t_disasm *disasm,int disasmmode) {
int i,j,isprefix,is3dnow,repeated,operand,mnemosize,arg;
ulong u,code;
int lockprefix; // Non-zero if lock prefix present
int repprefix; // REPxxx prefix or 0
int cxsize;
char name[TEXTLEN],*pname;
const t_cmddata *pd,*pdan;
// Prepare disassembler variables and initialize structure disasm.
datasize=addrsize=4; // 32-bit code and data segments only!
segprefix=SEG_UNDEF;
hasrm=hassib=0; dispsize=immsize=0;
lockprefix=0; repprefix=0;
ndump=0; nresult=0;
cmd=src; size=srcsize; pfixup=NULL;
softerror=0; is3dnow=0;
da=disasm;
da->ip=srcip;
da->comment[0]='\0';
da->cmdtype=C_BAD; da->nprefix=0;
da->memtype=DEC_UNKNOWN; da->indexed=0;
da->jmpconst=0; da->jmptable=0;
da->adrconst=0; da->immconst=0;
da->zeroconst=0;
da->fixupoffset=0; da->fixupsize=0;
da->warnings=0;
da->error=DAE_NOERR;
mode=disasmmode; // No need to use register contents
// Correct 80x86 command may theoretically contain up to 4 prefixes belonging
// to different prefix groups. This limits maximal possible size of the
// command to MAXCMDSIZE=16 bytes. In order to maintain this limit, if
// Disasm() detects second prefix from the same group, it flushes first
// prefix in the sequence as a pseudocommand.
u=0; repeated=0;
while (size>0) {
isprefix=1; // Assume that there is some prefix
switch (*cmd) {
case 0x26: if (segprefix==SEG_UNDEF) segprefix=SEG_ES;
else repeated=1; break;
case 0x2E: if (segprefix==SEG_UNDEF) segprefix=SEG_CS;
else repeated=1; break;
case 0x36: if (segprefix==SEG_UNDEF) segprefix=SEG_SS;
else repeated=1; break;
case 0x3E: if (segprefix==SEG_UNDEF) segprefix=SEG_DS;
else repeated=1; break;
case 0x64: if (segprefix==SEG_UNDEF) segprefix=SEG_FS;
else repeated=1; break;
case 0x65: if (segprefix==SEG_UNDEF) segprefix=SEG_GS;
else repeated=1; break;
case 0x66: if (datasize==4) datasize=2;
else repeated=1; break;
case 0x67: if (addrsize==4) addrsize=2;
else repeated=1; break;
case 0xF0: if (lockprefix==0) lockprefix=0xF0;
else repeated=1; break;
case 0xF2: if (repprefix==0) repprefix=0xF2;
else repeated=1; break;
case 0xF3: if (repprefix==0) repprefix=0xF3;
else repeated=1; break;
default: isprefix=0; break; };
if (isprefix==0 || repeated!=0)
break; // No more prefixes or duplicated prefix
if (mode>=DISASM_FILE)
ndump+=sprintf(da->dump+ndump,"%02X:",*cmd);
da->nprefix++;
cmd++; srcip++; size--; u++; };
// We do have repeated prefix. Flush first prefix from the sequence.
if (repeated) {
if (mode>=DISASM_FILE) {
da->dump[3]='\0'; // Leave only first dumped prefix
da->nprefix=1;
switch (cmd[-(long)u]) {
case 0x26: pname=(char *)(segname[SEG_ES]); break;
case 0x2E: pname=(char *)(segname[SEG_CS]); break;
case 0x36: pname=(char *)(segname[SEG_SS]); break;
case 0x3E: pname=(char *)(segname[SEG_DS]); break;
case 0x64: pname=(char *)(segname[SEG_FS]); break;
case 0x65: pname=(char *)(segname[SEG_GS]); break;
case 0x66: pname="DATASIZE"; break;
case 0x67: pname="ADDRSIZE"; break;
case 0xF0: pname="LOCK"; break;
case 0xF2: pname="REPNE"; break;
case 0xF3: pname="REPE"; break;
default: pname="?"; break; };
nresult+=sprintf(da->result+nresult,"PREFIX %s:",pname);
if (lowercase) strlwr(da->result);
if (extraprefix==0) strcpy(da->comment,"Superfluous prefix"); };
da->warnings|=DAW_PREFIX;
if (lockprefix) da->warnings|=DAW_LOCK;
da->cmdtype=C_RARE;
return 1; // Any prefix is 1 byte long
};
// If lock prefix available, display it and forget, because it has no
// influence on decoding of rest of the command.
if (lockprefix!=0) {
if (mode>=DISASM_FILE) nresult+=sprintf(da->result+nresult,"LOCK ");
da->warnings|=DAW_LOCK; };
// Fetch (if available) first 3 bytes of the command, add repeat prefix and
// find command in the command table.
code=0;
if (size>0) *(((char *)&code)+0)=cmd[0];
if (size>1) *(((char *)&code)+1)=cmd[1];
if (size>2) *(((char *)&code)+2)=cmd[2];
if (repprefix!=0) // RER/REPE/REPNE is considered to be
code=(code<<8) | repprefix; // part of command.
if (decodevxd && (code & 0xFFFF)==0x20CD)
pd=&vxdcmd; // Decode VxD call (Win95/98)
else {
for (pd=cmddata; pd->mask!=0; pd++) {
if (((code^pd->code) & pd->mask)!=0) continue;
if (mode>=DISASM_FILE && shortstringcmds &&
(pd->arg1==MSO || pd->arg1==MDE || pd->arg2==MSO || pd->arg2==MDE))
continue; // Search short form of string command
break;
};
};
if ((pd->type & C_TYPEMASK)==C_NOW) {
// 3DNow! commands require additional search.
is3dnow=1;
j=Get3dnowsuffix();
if (j<0)
da->error=DAE_CROSS;
else {
for ( ; pd->mask!=0; pd++) {
if (((code^pd->code) & pd->mask)!=0) continue;
if (((uchar *)&(pd->code))[2]==j) break;
};
};
};
if (pd->mask==0) { // Command not found
da->cmdtype=C_BAD;
if (size<2) da->error=DAE_CROSS;
else da->error=DAE_BADCMD; }
else { // Command recognized, decode it
da->cmdtype=pd->type;
cxsize=datasize; // Default size of ECX used as counter
if (segprefix==SEG_FS || segprefix==SEG_GS || lockprefix!=0)
da->cmdtype|=C_RARE; // These prefixes are rare
if (pd->bits==PR)
da->warnings|=DAW_PRIV; // Privileged command (ring 0)
else if (pd->bits==WP)
da->warnings|=DAW_IO; // I/O command
// Win32 programs usually try to keep stack dword-aligned, so INC ESP
// (44) and DEC ESP (4C) usually don't appear in real code. Also check for
// ADD ESP,imm and SUB ESP,imm (81,C4,imm32; 83,C4,imm8; 81,EC,imm32;
// 83,EC,imm8).
if (cmd[0]==0x44 || cmd[0]==0x4C ||
(size>=3 && (cmd[0]==0x81 || cmd[0]==0x83) &&
(cmd[1]==0xC4 || cmd[1]==0xEC) && (cmd[2] & 0x03)!=0)
) {
da->warnings|=DAW_STACK;
da->cmdtype|=C_RARE; };
// Warn also on MOV SEG,... (8E...). Win32 works in flat mode.
if (cmd[0]==0x8E)
da->warnings|=DAW_SEGMENT;
// If opcode is 2-byte, adjust command.
if (pd->len==2) {
if (size==0) da->error=DAE_CROSS;
else {
if (mode>=DISASM_FILE)
ndump+=sprintf(da->dump+ndump,"%02X",*cmd);
cmd++; srcip++; size--;
}; };
if (size==0) da->error=DAE_CROSS;
// Some commands either feature non-standard data size or have bit which
// allowes to select data size.
if ((pd->bits & WW)!=0 && (*cmd & WW)==0)
datasize=1; // Bit W in command set to 0
else if ((pd->bits & W3)!=0 && (*cmd & W3)==0)
datasize=1; // Another position of bit W
else if ((pd->bits & FF)!=0)
datasize=2; // Forced word (2-byte) size
// Some commands either have mnemonics which depend on data size (8/16 bits
// or 32 bits, like CWD/CDQ), or have several different mnemonics (like
// JNZ/JNE). First case is marked by either '&' (mnemonic depends on
// operand size) or '$' (depends on address size). In the second case,
// there is no special marker and disassembler selects main mnemonic.
if (mode>=DISASM_FILE) {
if (pd->name[0]=='&') mnemosize=datasize;
else if (pd->name[0]=='$') mnemosize=addrsize;
else mnemosize=0;
if (mnemosize!=0) {
for (i=0,j=1; pd->name[j]!='\0'; j++) {
if (pd->name[j]==':') { // Separator between 16/32 mnemonics
if (mnemosize==4) i=0;
else break; }
else if (pd->name[j]=='*') { // Substitute by 'W', 'D' or none
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -