⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 disasm.c

📁 反汇编intel32位指令的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* 将二进制文件中的机器指令翻译成32位intel格式汇编指令 */
/* 使用方法: disasm 文件名 ,如果输出多于一屏,可以使用重定向: disasm 文件名>res.txt 然后查看res.txt*/
/* 默认从偏移0开始翻译,也可以通过向DisAsmBinFile()传递参数指定偏移 */

/* 程序假设char型是1字节,long型至少是4字节.可以用vc编译,我想应该也可以用gcc,在linux下编译的话将四个#define中的\\替换成/就可以了.本来可以用win-tc编译,可是后来不知道加了什么功能后用win-tc编译出的程序运行有问题 */
/* DisAsmBinFile()函数负责反汇编,main()函数只负责打开待翻译文件和执行DisAsmBinFile(),因此容易扩展程序功能或将反汇编的程序代码移植到其它程序中 */
/* 我只写了80386指令,没有加入浮点指令和新出的指令,需要扩展的话在AnalyzeOpCode()中添加 */

/* version 1.0 ,2005.10.8.12:39 */
/* writer 又改名了 */
/* email ringken@gmail.com */

/* 源代码注释中的"操作码"均指除操作数以外的指令部份,而不是指整条指令,如mov eax,1的操作码是mov */
/* 源代码注释中的"指令"如单独作为一个词出现,均指整条指令的二进制代码 */

#include <stdio.h>
#include <string.h>

/********************************************************/
/*		定义数据文件路径			*/
/********************************************************/

#define opcode_table "data\\opcode.dat"
#define opcode_table2 "data\\2Bopcode.dat"
#define opcode_grp_table "data\\extra.dat"
#define reg_table "data\\reg.dat"

/********************************************************/
/*		声明全局变量				*/
/********************************************************/

char *writer = "ken";
char *email = "ringken@gmail.com";
                                      
FILE *BinFile;          //指向要译码的bin文件
FILE *CodeTable;        //指向操作码索引表
FILE *CodeTable2;       //指向双字节操作码表
FILE *CodeGrpTable;     //指向用于索引需要MODRM字段5,4,3位确定操作码的指令表
FILE *RegTable;         //指向保存寄存器名称的索引表

struct
{
        long current_code;              //正在处理的指令在.bin文件中的偏移
        int opcode_len;                 //正在处理的指令的操作码字节数,包括前缀码
        int operand_len;                //正在处理的指令的操作数字节数

        unsigned char ins_buf[30];	//保存正在处理的指令代码
        int processing;                 //分析指令时保存ins_buf中当前正在处理的字节

        int prefix[4];                  //指令前缀,ins.prefix[0]保存前缀66,[1]是前缀67,[2]是f0,f2,f3,[3]是6个段前缀
        char code_data[16];             //从opcode表中取得的数据

        char asm_code[50];              //临时存放反汇编后的字串
	char *asm_code_writing;		//指向asm_code[]中下一个应该写的位置

	struct				//MODRM
	{
		int mod;
		int reg;
		int rm;
	} modrm;
	struct				//SIB
	{
		int s;
		int index;
		int base;
	} sib;
        long num;			//在分析操作数时保存立即数或内存偏移

}  ins;

/********************************************************************************/
/*                      函数声明                                                */
/********************************************************************************/

void LoadDataFile(void);        //载入数据文件
void CloseDataFile(void);       //关闭数据文件
void InitInsStruct(void);       //在处理新一条指令时初始化struct ins结构
void NumToText(int byte);	//将ins.num中存放的byte个字节的数字转换成对应的16进制格式文本放到ins.asm_code[]中

//DisAsmBinFile()是执行反汇编的主函数
//由DisAsmBinFile()从要分析的BIN文件读出指令码放入ins.ins_buf中,调用分析操作码的函数AnalyzeOpCode()分析操作码并由AnalyzeOpCode()调用必要的函数完成操作码的分析
//如有操作数,由DisAsmBinFile()调用分析操作数的函数AnalyzeOperand()并由AnalyzeOperand()调用必要的函数完成操作数的分析
//如有操作数,DisAsmBinFile()从ins.code_data[]中取得待分析的操作数属性放入ins.code_data[8]开始的四个字节,由AnalyzeOperand()分析
//每分析完一条指令,DisAsmBinFile()根据操作码长度ins.opcode_len和操作数长度ins.operand_len计算下一条指令的偏移保存在ins.current_code中
//每分析完一条指令,指令的反汇编字串保存在ins.asm_code[]中,由DisAsmBinFile()输出

void DisAsmBinFile(long head);	//从文件偏移的head处执行反汇编

//以下各函数分析操作码,计算指字中操作码的字节数保存在ins.opcode_len中,并处理操作码前缀保存在ins.prefix[]中
//分析完操作码后,ins.processing指向操作码后的第一个字节,分析操作数的函数会根据这个变量找到操作数
//AnalyzeOpCode()是分析操作码的主函数,由AnalyzeOpCode()调用必要的函数完成对操作码的分析
void AnalyzeOpCode(void);       //根据opcode_table翻译操作码字段(包括前缀)
void ProcessPrefix(void);       //翻译操作码前缀
void ModifyOpCode(void);        //根据获得的前缀和操作码信息修改反汇编出的操作码部份,比如MOVSD改为MOVSW及确定REPE还是REP
void Process2ByteIns(void);     //根据opcode_table2翻译2字节操作码
void Process3BitGroup(void);    //根据opcode_grp_table翻译由MODRM的5,4,3位决定的操作码

//以下各函数分析操作数,计算指令中操作数的字节数保存在ins.operand_len中.除寻址方式B和I外都假设ins.ins_buf[ins.processing]为待处理的操作数
//寻址方式B可直接获得操作数,寻址方式I会根据ins.ins_buf[ins.processing]和已处理的操作数长度计算出ins.processing使其指向操作数,容易验证这样计算是正确的
//AnalyzeOperand()是分析操作数的主函数,由AnalyzeOpCode调用必要的函数完成对操作数的分析
//AnalyzeOperand()从ins.code_data[]中获得操作数寻址方式和操作数长度的信息
//AnalyzeOperImm()和AnalyzeOperModrm()函数还会根据正处理的操作数长度计算ins.operand_len,其它的寻址方式中B没有操作数,C、D、T、G、S的操作数是MODRM的reg字段,而只要有MODRM的reg字段,就必定有寻址方式E,M,R
void AnalyzeOperand(void);      //根据code_data翻译操作数字段(操作数属性保存在ins.code_data[8]处2至4个字节),寻址方式B直接在此函数处理,其它寻址试要调用相应的函数处理
void AnalyzeOperReg(void);      //根据code_data翻译操作数由MODRM的reg字段确定的情况,寻址方式为C,D,T,G,S
void AnalyzeOperImm(void);      //根据code_data翻译操作数包含在指令中的情况,并计算本条操作数的长度.寻址方式为I,J
void AnalyzeOperModrm(void);    //根据code_data翻译操作数由MODRM确定的情况以及寻址方式为O的情况,并计算本条操作数的长度.寻址方式为O,E,M,R
void GetModrm(void);            //取得modrm字段

/********************************************************************************/

main(int argc, char *argv[])
{
	if ( argc == 1)
	{
		puts("usage:\n\tdisasm filename");
		exit(1);
	}

        if ( (BinFile = fopen(argv[1],"rb"))==NULL )
        {
                printf("Cannot open bin file %s",argv[1]);
                exit(1);
        }

        DisAsmBinFile(0);	//从文件偏移0处开始反汇编

}

void LoadDataFile(void)
{
        if ( (CodeTable = fopen(opcode_table,"rb")) == NULL)
        {
                printf("Cannot open data file %s.",opcode_table);
                exit(1);
        }
        if ( (CodeTable2 = fopen(opcode_table2,"rb")) == NULL)
        {
                printf("Cannot open data file %s.",opcode_table2);
                exit(1);
        }
        if ( (CodeGrpTable = fopen(opcode_grp_table,"rb")) == NULL)
        {
                printf("Cannot open data file %s.",opcode_grp_table);
                exit(1);
        }
        if ( (RegTable = fopen(reg_table,"rb")) == NULL)
        {
                printf("Cannot open data file %s.",reg_table);
                exit(1);
        }

        return;
}

void CloseDataFile(void)
{
        fclose(CodeTable);
        fclose(CodeTable2);
        fclose(CodeGrpTable);
        fclose(RegTable);

        return;
}

void NumToText(int byte)		//将ins.num中存放的byte字节16进制数转成ASCII码存放在ins.asm_code[]中
{
	byte = (byte<<3) -4;		//把字节数转成要处理的位数,从 8*byte-4开始处理

	for ( ; byte >= 0; byte -= 4)
	{
		*ins.asm_code_writing = ( (ins.num>>byte) & 0xf) +0x30;	//16进制数转成ASCII码
		if ( *ins.asm_code_writing > 0x39)	//如果是A到F
			*ins.asm_code_writing += 7;

		ins.asm_code_writing ++;
	}

	return;
}

void DisAsmBinFile(long head)		//执行反汇编的主函数
{
        LoadDataFile();

        ins.current_code = head;		//设置反汇编的起点

        while (1)
        {
                InitInsStruct();		//初始化ins

                fseek(BinFile, ins.current_code, SEEK_SET);  //将下一条指令读入缓冲区
                if ( fread( (void*)(ins.ins_buf), 1, 10, BinFile) < 1  )
                         break;

                AnalyzeOpCode();                //分析操作码部分并在ins.asm_code中填入操作码字串,包括前缀

                if ( ins.code_data[8] )         //判断是否有操作数
                {
			ins.asm_code_writing = ins.asm_code+strlen(ins.asm_code);	//移动指针

			* ins.asm_code_writing++ = '\t';

                        AnalyzeOperand();       //分析第一操作数并在ins.asm_code中填入操作数字串

                        if ( (ins.code_data[8] != 'B') && ins.code_data[10])    //如果是三操作数指令
                        {
				* ins.asm_code_writing++ = ',';
                                strncpy(ins.code_data+8,ins.code_data+10,2);	//将操作数属性信息由ins.code_data+10处拷到ins.code_data+8处
                                AnalyzeOperand();       //分析第二操作数并在ins.asm_code中填入操作数字串
                        }

                        if ( ins.code_data[12] )        //如果还有操作数
                        {
				* ins.asm_code_writing++ = ',';
                                strncpy(ins.code_data+8,ins.code_data+12,4);	//将操作数属性信息由ins.code_data+12处拷到ins.code_data+8处
                                AnalyzeOperand();       //分析最后一个操作数并在ins.asm_code中填入操作数字串
                        }

                }

		//输出结果

		printf("%08lX ",ins.current_code);		//输出指令偏移
		ins.current_code += (ins.opcode_len + ins.operand_len);	//计算下一条指令的偏移

		ins.processing = 0;
		while ( ins.opcode_len-- )	//输出操作码部份的16进制数
			printf("%02X",ins.ins_buf[ins.processing++]);
		while ( ins.operand_len-- )	//输出操作数部份的16进制数
			printf("%02X",ins.ins_buf[ins.processing++]);

		ins.processing = 3 - ( ins.processing >>2);	//计算需要输出的tab数,每个指令的操作数字串输出占3个tab,计算公式为tab数=3-(指令字节数*2)/8
		while ( ins.processing-- )
			putchar('\t');

		printf("%s\n",ins.asm_code);	//输出反汇编字串
        }

        CloseDataFile();

        return;
}

void InitInsStruct(void)        //初始化struct ins结构
{
        ins.prefix[0] = 0;
        ins.prefix[1] = 0;
        ins.prefix[2] = 0;
        ins.prefix[3] = 0;

        ins.processing = 0;
        ins.operand_len = 0;

	ins.asm_code[0] = '\0';

        return;
}

void AnalyzeOpCode(void)                //根据code_data的前八个字节翻译操作码字段(包括前缀),code_data从数据文件中获得
{
        fseek(CodeTable,ins.ins_buf[0]<<4, SEEK_SET); //从opcode表中读取ins.ins_buf缓冲区第一个字节的信息
        fread( (void*)(ins.code_data), 16, 1, CodeTable) ;


        while ( !ins.code_data[0] )     //若从opcode表中读出的不是一个操作码
        {

                switch (ins.code_data[1])       //第二个字节保存了编码的信息
                {
                        case 1: ProcessPrefix();        //处理前缀码,并从opcode表中读出下一字节的信息放入ins.code_data
                                break;
                        case 2: Process2ByteIns();      //处理2字节指令码
                                break;
                        case 3: Process3BitGroup();     //处理由MODRM的5,4,3位决定的操作码
                                break;
                        case 4:
                                strcpy(ins.code_data,"387code!");
                                //ProcessX87Ins();      //处理协处理器指令集
                                break;
			case 0:				//不是一个机器指令码
				ins.code_data[0] = ' ';

				strcpy(ins.asm_code,"DB ");	//输出16进制代码
				ins.num = ins.ins_buf[0];	//将第一字节放入ins.num并设置ins.ins_code_writing交给NumToText()处理
				ins.asm_code_writing = ins.asm_code+3;
				NumToText(1);
				* ins.asm_code_writing = '\0';

				ins.processing = 0;
				break;

                }

        }

        if ( ins.prefix[1] || ins.prefix[2] )   //如果有前缀需要修改反汇编字串
                ModifyOpCode();                 //那就改吧

        
        strcat( ins.asm_code,ins.code_data);    //在ins.asm_code中保存反汇编得到的字串

        ins.processing ++;                      //处理完操作码后ins.processing指向操作数字段
        ins.opcode_len = ins.processing;        //计算操作码长度

        return;
}

void ProcessPrefix(void)	//处理前缀码
{
        switch (ins.ins_buf[ins.processing])     //看正在处理的指令字节是什么前缀
        {
                case 0x66:      ins.prefix[0] = 0x66;
                                break;
                case 0x67:      ins.prefix[1] = 0x67;
                                break;
                case 0xf0:
                case 0xf2:      
                case 0xf3:      ins.prefix[2] = ins.ins_buf[ins.processing];
                                break;
                case 0x2e:
                case 0x36:
                case 0x3e:
                case 0x26:
                case 0x64:
                case 0x65:      ins.prefix[3] = ins.ins_buf[ins.processing];
                                break;
        }

	ins.processing ++;
        fseek(CodeTable,ins.ins_buf[ins.processing]<<4, SEEK_SET);     //从CodeTable中读入下一字节的信息

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -