如何解决C 中自定义操作码的反汇编逻辑
所以我正在构建一个反汇编程序,它将包含十六进制数据的文件转换为汇编语言。
因此,从这种格式中,我可以使用 uint8_t 将文件中的十六进制数据转换为十进制并将它们存储在数组中。然后我决定对数组中的最后一个数字进行位移以获得最后一个函数的指令数;基本上我是在向后解析,因为我不知道开头有多少填充,并且函数中的操作数在函数末尾给出。但后来我意识到这些操作的位大小不同,并且不在完美的 8 位或 16 位范围内。然后我被卡住了,因为我的数组,使用顶部的例子,本质上是这样的:
uint8_t hex[] = {0x00,0x03,0x02,0x01,0x42,0x82,0x86,0x04,0x10,0x45};
那么谁能帮我解析逻辑?这是我第一次发帖,所以如果我遗漏了什么,我很抱歉,如果需要,我会提供更多信息或删除
解决方法
如果将 uint8_t 数组转换为位数组,而不是移位和屏蔽(我认为这会非常复杂)会怎样 - 它使用更多内存,但您可以更轻松地访问单个位。
这是一个执行此操作的示例程序:
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
uint8_t getBits(uint8_t *bits,uint8_t size,uint32_t *index)
{
uint8_t value = 0;
*index -= size; // decrement index to the starting point
for(uint32_t i=0; i<size; i++)
value = (value<<1) | bits[*index+i];
return value;
}
int main()
{
// sample program
uint8_t array[] = {0x00,0x03,0x02,0x01,0x42,0x82,0x86,0x04,0x10,0x45};
// program with zero padding
// uint8_t array[] = {0xE8,0x39,0x06,0xA0,0xC4,0x16,0x90,0x4A,0x08,0x41};
uint32_t array_size = sizeof(array)/sizeof(*array); // 10 bytes
uint32_t bits_size = 8*array_size; // 80 bytes
uint8_t* bits = malloc(bits_size);
for(uint32_t a=0;a<array_size;a++)
for(uint32_t b=0;b<8;b++)
bits[a*8+b] = (array[a] >> (7-b)) & 1;
puts("Binary program file:");
for(uint32_t i=0;i<bits_size;i++)
printf("%s%d",(i%8?"":" "),bits[i]);
puts("");
enum { MOV,CAL,RET,REF,ADD,PRINT,NOT,EQU};
uint8_t params[] = { 2,1,2,1};
const char *opcodes[] = {"MOV","CAL","RET","REF","ADD","PRINT","NOT","EQU"};
enum { VAL,REG,STK,PTR};
uint8_t value_size[] = { 8,3,5,5};
const char *types[] = {"VAL","REG","STK","PTR"};
uint32_t index = bits_size; // start at end
// minimum program size is function(3) + opcode(3) + size(5)
// if there are less than that number of bits then it must be padding
while(index>10)
{
uint8_t size = getBits(bits,&index);
printf("\nsize=%d\n",size);
if (size > 0)
{
for(int o=0; o<size; o++)
{
uint8_t opcode = getBits(bits,&index);
printf("opcode=%s",opcodes[opcode]);
for(int p=0; p<params[opcode]; p++)
{
printf("%c ",p?',':':');
uint8_t type = getBits(bits,&index);
printf("type=%s ",types[type]);
uint8_t value = getBits(bits,value_size[type],&index);
printf("value=%d",value);
}
puts("");
}
uint8_t function = getBits(bits,&index);
printf("function=%d\n",function);
}
}
return 0;
}
在 https://onlinegdb.com/S1qVStz8d 尝试
它是如何getBits()
工作的:
您从原始值中创建一个由单个数字组成的数组,然后一次从它中取出一个位来创建一个新值 - getBits()
是我为此编写的函数。
要了解它是如何工作的,请想象一下它在基数 10 中是如何工作的:321
被放入数组 {3,1}
中,您可以使用以下命令将其转回一个值:
value = 0;
value = value*10 + digits[0];
value = value*10 + digits[1];
value = value*10 + digits[2];
哪个给出 (((0)*10+3)*10+2)*10+1
是 321
如果将 5
(二进制 101
)放入数组 {1,1}
中,您可以使用以下命令将其重新转换为值:
value = 0;
value = value*2 + bits[0];
value = value*2 + bits[1];
value = value*2 + bits[2];
给出 (((0)*2+1)*2+0)*2+1
是 5
(二进制 101
)
这确实有效。一个体面的编译器会将 *2
优化为 <<1
,将 +
优化为 |
,但您可以自己完成(我就是这样做的):
value = 0;
value = (value<<1) | bits[0];
value = (value<<1) | bits[1];
value = (value<<1) | bits[2];
产生相同的二进制 00000101
这只是一个可读性问题 - 对于十进制,您希望看到 value*10+x
,但对于二进制,您希望看到诸如移位/或数学运算之类的位运算,例如乘法/加法。
然后,如果你使用一个循环的大小和一个指向数组末尾的索引,你会得到:
uint8_t value = 0;
index -= size; // decrement index to the starting point
for(uint32_t i=0; i<size; i++)
value = (value<<1) | bits[index+i];
但是,当然,如果它是一个函数,那么 index 需要是一个指针,你需要在任何地方取消引用它:
uint8_t getBits(uint8_t *bits,uint32_t *index)
{
uint8_t value = 0;
*index -= size; // decrement index to the starting point
for(uint32_t i=0; i<size; i++)
value = (value<<1) | bits[*index+i];
return value;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。