📄 disasm.c
字号:
fread( (void*)(ins.code_data), 16, 1, CodeTable) ;
return;
}
void ModifyOpCode(void) //根据段前缀修改反汇编的操作码字串
{
switch (ins.prefix[2]) //处理前缀f0,f2,f3
{
case 0:
break;
case 0xf0:
strcat(ins.asm_code,"LOCK ");
break;
case 0xf2:
strcat (ins.asm_code,"REPNE ");
break;
case 0xf3:
switch (ins.ins_buf[ins.processing])
{
case 0xa6:
case 0xa7:
case 0xae:
case 0xaf:
strcat (ins.asm_code,"REPE ");
break;
default:
strcat (ins.asm_code,"REP ");
}
}
if (ins.prefix[1]) //处理前缀67
{
switch (ins.ins_buf[ins.processing]) //看看有没有必要修改操作码
{
case 0x6d:
ins.code_data[3] = 'W'; //如果当前指令是INSD,改为INSW
break;
case 0x9c:
ins.code_data[5] = '\0';//如果是PUSHFD,改为PUSHF
break;
case 0x9d:
ins.code_data[4] = '\0';//POPFD改为POPF
break;
case 0xa5: //MOVSD
case 0xa7: //CMPSD
case 0xab: //STOSD
case 0xad: //LODSD
case 0x6f: //OUTSD
case 0xaf: //SCASD
ins.code_data[4] = 'W';
break;
}
}
return;
}
void Process2ByteIns(void) //处理双字节操作码
{
ins.processing ++;
fseek(CodeTable2, ins.ins_buf[ins.processing]<<4, SEEK_SET); //从CodeTable2中读入双字节指令信息,这里没考虑非法指令的情况,也没必要
fread( (void*)(ins.code_data), 16, 1, CodeTable2);
return;
}
void Process3BitGroup(void) //处理需要MODRM的5,4,3位确定的操作码
{
ins.modrm.reg = (ins.ins_buf[ins.processing+1]>>3)&7; //计算modrm的reg字段
fseek(CodeGrpTable, ((ins.code_data[2]<<3) + ins.modrm.reg)<<4, SEEK_SET); //从opcode_grp_table中读取操作码信息
fread( (void*)(ins.code_data), 16, 1, CodeGrpTable);
return;
}
void GetModrm(void) //从ins.ins_buf[ins.insprocessing]取得MODRM
{
ins.modrm.mod = (ins.ins_buf[ins.processing]>>6)&3;
ins.modrm.reg = (ins.ins_buf[ins.processing]>>3)&7;
ins.modrm.rm = (ins.ins_buf[ins.processing])&7;
if (ins.prefix[1]) //先判断下前缀67,如果是67先写进16位偏移(不管有没有偏移),如果是8位偏移再进行转换
{
ins.num = *((long *)(ins.ins_buf+ins.processing+1)) & 0xffff;
if (ins.modrm.mod == 1) //8位偏移
{
ins.num &= 0xff;
if ( ins.num & 0x80 ) //如果是负的
ins.num |= ( (~0)<<8 ); //符号扩展
}
else if ( ins.num & 0x8000 ) //如果是负的
ins.num |= ( (~0)<<16 );//符号扩展
return;
}
if (ins.modrm.rm==4 && ins.modrm.mod!=3) //如果需要读出SIB字段,读SIB
{
ins.sib.s = 1 << ( (ins.ins_buf[ins.processing+1]>>6)&3 ); //s值等于2^s
ins.sib.index = (ins.ins_buf[ins.processing+1]>>3)&7;
ins.sib.base = (ins.ins_buf[ins.processing+1])&7;
ins.num = *((long *)(ins.ins_buf+ins.processing+2)) ; //不管有没有disp,读一下,省着判断
if (ins.modrm.mod == 1) //如果8位disp
{
ins.num &= 0xff;
if ( ins.num & 0x80) //如果是负的
ins.num |= ( (~0)<<8 ); //符号扩展
}
else if ( ins.num & 0x80000000 ) //如果是负的
ins.num |= ( (~0)<<32 ); //符号扩展
}
else if ( (ins.modrm.mod==0&&ins.modrm.rm==5) || (ins.modrm.mod==2) ) //如果modrm后为32位disp字段,读32位disp
{
ins.num = *((long *)(ins.ins_buf+ins.processing+1)) & 0xffffffff;
if ( ins.num & 0x80000000 ) //如果是负的
ins.num |= ( (~0)<<32 );//符号扩展
}
else if ( ins.modrm.mod == 1 ) //如果modrm后为8位disp字段,读8位disp
{
ins.num = *((long *)(ins.ins_buf+ins.processing+1)) & 0xff;
if ( ins.num & 0x80 ) //如果是负的
ins.num |= ( (~0)<<8 ); //符号扩展
}
return;
}
void AnalyzeOperand(void) //根据code_data后八字节中前二到四个字节翻译操作数字段,code_data从数据文件中获得
{
switch (ins.code_data[8]) //分析寻址方式
{
case 'B': //寻址方式B,操作数的反汇编字串已知,根据前缀确定
if ( ins.code_data[9]=='$') //串指令和PUSHAD,POPAD,这一段if可能不好理解,弄懂前缀66和段前缀对串指令和PUSHAD,POPAD的影响就好理解了
{
//如果是串指令且有段更改前缀(ins.prefix[3]),就要写操作数,比如MODSD要写上[EDI],XX:[ESI],真麻烦,这种特殊的情况要这么多行来处理
//如果是PUSHAD或POPAD且有前缀66就要去掉D
if ( ins.ins_buf[ins.processing-1]==0x60 || ins.ins_buf[ins.processing-1]==0x61 ) //PUSHAD/POPAD
{
ins.asm_code_writing --;
if ( !ins.prefix[0] )
break;
ins.asm_code_writing --;
break;
}
if ( !ins.prefix[3])
{
ins.asm_code_writing --;
break;
}
ins.prefix[2] = ins.prefix[3]; //ins.prefix[2]是存放REP之类的地方,在分析操作码的时候才会用到,这以下不会用到,因此借用一下保存段前缀,因为AnalyzeOperModrm()是要处理段前缀的,而串指令的目的操作数不受段前缀影响
ins.prefix[3] = 0;
ins.ins_buf[ins.processing] = 7; //设置缓冲区当前的操作数为"[EDI]"然后交给AnalyzeOperModrm()处理
AnalyzeOperModrm();
* ins.asm_code_writing++ = ',';
ins.prefix[3] = ins.prefix[2]; //写上段前缀给AnalyzeOperModrm()处理
ins.ins_buf[ins.processing] = 6; //设置缓冲区当前的操作数为"[ESI]"然后交给AnalyzeOperModrm()处理
AnalyzeOperModrm();
break;
}
strncpy(ins.asm_code_writing, ins.code_data+9, 3); //拷贝ins.code_data[9]处的三字节
if (ins.prefix[0] && ins.code_data[9]=='E') //如果有前缀66,且是寄存器Exx,则寄存器Exx变成xx
* ins.asm_code_writing = ' ';
ins.asm_code_writing += 3;
break;
case 'C':
case 'D':
case 'T':
case 'G':
case 'S':
AnalyzeOperReg(); //这5类寻址方式是到MODRM的reg字段分析
break;
case 'I':
case 'J':
AnalyzeOperImm(); //这2类是立即数寻址
break;
case 'O':
case 'E':
case 'M':
case 'R':
AnalyzeOperModrm(); //O类操作数在内存中,指令直接给出了偏移,其它三类操作数根据MODRM的mod字段判断
break;
}
*ins.asm_code_writing = '\0';
return;
}
void AnalyzeOperReg(void) //分析寻址方式为C,D,T,G,S的情况,操作数在MODRM的reg字段
{
ins.modrm.reg = (ins.ins_buf[ins.processing]>>3)&7; //计算ins.modrm.reg
switch (ins.code_data[8]) //分析寻址方式
{
case 'C': //寻址方式C,D,T,分别根据MODRM的reg字段确定CRx,DRx,TRx寄存器
case 'D':
case 'T':
* ins.asm_code_writing++ = ins.code_data[8]; //C,D还是T?
* ins.asm_code_writing++ = 'R';
* ins.asm_code_writing++ = ( (ins.modrm.reg>>3)&7 ) + 0x30; //从modrm的reg字段获得寄存器号
break;
case 'G': //寻址方式G根据操作数大小和MODRM的reg字段从reg_table中找到表示相应寄存器的字串
if (ins.code_data[9] == 'B') //如果操作数大小是B,即字节型
{
fseek(RegTable, (ins.modrm.reg<<3)+0x80, SEEK_SET); ////从reg_table表读8位寄存器字串
fread( ins.asm_code_writing, 8, 1, RegTable);
ins.asm_code_writing += 2;
}
else //否则就应该是V,即32/16位,根据有无指令前缀66判断
{
if (ins.prefix[0]) //如果有前缀66,取16位寄存器
{
fseek(RegTable, (ins.modrm.reg<<3)+0x40, SEEK_SET); //从reg_table表读16位寄存器字串
fread( ins.asm_code_writing, 8, 1, RegTable);
ins.asm_code_writing += 2;
}
else //否则取32位寄存器
{
fseek(RegTable, ins.modrm.reg<<3, SEEK_SET); //从reg_table表读32位寄存器字串
fread( ins.asm_code_writing, 8, 1, RegTable);
ins.asm_code_writing += 3;
}
}
break;
case 'S': //寻址方式S是段寄存器
fseek(RegTable, (ins.modrm.reg<<3)+0xc0, SEEK_SET); //从reg_table表读段寄存器字串
fread( ins.asm_code_writing, 8, 1, RegTable);
ins.asm_code_writing += 2;
break;
}
return;
}
void AnalyzeOperImm(void) //分析寻址方式是I,J的情况,操作数为立即数
{
ins.processing += ins.operand_len; //如果操作数是立即数,则操作数在指令中的位移必定在已经处理过的操作数之后
switch (ins.code_data[9] ) //根据操作数大小判断
{
case 'P': //操作数大小P在这个函数里只与J搭配,表示48位或32位远指针
strcpy(ins.asm_code_writing,"FAR PTR ");
ins.asm_code_writing += 8;
if (ins.prefix[0]) //如果有前缀66,取seg:disp16格式
{
ins.operand_len += 4;
ins.num = *((long *)(ins.ins_buf+ins.processing+2)); //取long型就可以,NumToText()会根据正确的字节数截断
NumToText(2);
* ins.asm_code_writing++ = ':';
ins.num = *((long *)(ins.ins_buf+ins.processing));
NumToText(2);
}
else //否则取seg:disp32格式
{
ins.operand_len += 6;
ins.num = *((long *)(ins.ins_buf+ins.processing+4));
NumToText(2);
* ins.asm_code_writing++ = ':';
ins.num = *((long *)(ins.ins_buf+ins.processing));
NumToText(4);
}
break;
case 'B': //操作数大小是BYTE
ins.operand_len += 1;
ins.num = *( (long *)(ins.ins_buf+ins.processing) ) & 0xff; //这里ins.num保存的必须是正确的8位数,因为下边寻址方式J要加上下一指令的偏移
if (ins.code_data[8] == 'J') //如果是跳转指令
{
if ( ins.num & 0x80 ) //如果是负的
ins.num |= (~(long)0) << 8; //做符号扩展
ins.num += (ins.current_code+2);//加上下一条指令的偏移
NumToText(4);
}else
NumToText(1);
break;
case 'W': //操作数大小是WORD
ins.operand_len += 2;
ins.num = *((long *)(ins.ins_buf+ins.processing));
NumToText(2);
break;
case 'D': //操作数大小是DWORD
ins.operand_len += 4;
ins.num = *((long *)(ins.ins_buf+ins.processing));
NumToText(4);
break;
case 'V': //操作数大小是WORD或DWORD,根据前缀66判断
if (ins.prefix[0]) //判断前缀66
{
ins.operand_len += 2;
ins.num = *((long *)(ins.ins_buf+ins.processing)) & 0xffff; //这里ins.num保存的必须是正确的16位数,因为下边寻址方式J要加上下一指令的偏移
if (ins.code_data[8] == 'J') //如果是跳转指令
{
if ( ins.num & 0x8000 ) //如果是负的
ins.num |= (~(long)0) << 16; //做符号扩展
ins.num += (ins.current_code+3);//加上下一条指令的偏移
NumToText(4);
}
else
NumToText(2);
}
else
{
ins.operand_len += 4;
ins.num = *((long *)(ins.ins_buf+ins.processing)) & 0xffffffff; //这里ins.num保存的必须是正确的32位数,因为下边寻址方式J要加上下一指令的偏移
if (ins.code_data[8] == 'J') //如果是跳转指令
{
if ( ins.num & 0x80000000 ) //如果是负的
ins.num |= (~(long)0) << 32; //做符号扩展
ins.num += (ins.current_code+5); //加上下一条指令的偏移
}
NumToText(4);
}
break;
}
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -