逆向工程固件

逆向工程 固件 十六进制
2021-07-02 12:40:37

我有一个带有 Attiny45 固件的 HEX 文件。我想要做的是提取某种编码在其中的公式。我做了一些研究(主要是发现“这是不可能的”等)但我决定我可以尝试一下,因为我的研究的其他部分向我表明,大多数提出此类问题的人几乎不知道什么是 HEX 文件。

这篇文章的目的不是从 HEX 文件中提出一个明亮的 C 代码,而是建立关于该主题的扎实知识。我知道编译器在完成其工作时可以使我自己的工作更加困难,但是需要遵循某种结构(可能是原始结构)以使 CPU 能够执行代码。

所以,我坐在我的桌子上编写了一个小 Python 工具来帮助我完成这个过程。它加载 HEX 文件,我可以交互地向其中添加信息。这是我到目前为止所得到的:

HEX 文件的第一行说:

: 02 0000 04 0000 FA

该工具将其解码为:

:       --> MARK
02      --> RECORD LENGTH
0000    --> LOAD OFFSET
04      --> RECORD TYPE (EXTENDED LINEAR ADDRESS RECORD)
0000    --> DATA
FA      --> CHECKSUM

似乎这一行是为了告诉应该放置代码的初始地址是0x0000.

其次,下一行说:

: 20 0000 00 34C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50C07EEE7EB9 51

该工具将其解码为:

:    --> MARK
20   --> LENGHT OF THE RECORD
0000 --> OFFSET
00   --> RECORD TYPE (00 -> DATA RECORD) 34C0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50C07EEE7EB9 (ACTUAL DATA)
51   --> CHECKSUM

这就是乐趣和问题的开始。

  1. 我在任何地方都找不到 ATTiny45 的内存映射。我认为它应该在数据表或指令集手册中的某个地方。据我0x0000所知,中断向量(第 49 页,数据表)和第一个是复位向量。所以,AVR 是小端的,指令是 16 位宽的,我可以解码重置向量包含值0xC034使用指令集,我发现0xC034是:

    rjump 0x034
    

    这个对吗?

  2. 继续这个思路,前面指出的同一条线表明一些中断向量有值0xFFFF,这让我感到惊讶,但似乎不是问题,因为这些可能会被禁用。唯一具有工作值的其他向量是USI_OVF_ISR,它等于0xC050所以,根据之前提出的想法,这说USI_OVF_ISR有指令:

    rjump 0x050
    

    这也是正确的吗?

  3. 如果重置向量指向0x034,则表示程序将从 开始运行0x034下一行

    : 20 0020 00 7FE77FB9B89A089570EE7EB95FB9B89A08957EEE7EB9B898089570EE7EB9B898 22
    

    显示0x0340xB898,那是将要执行的第一条指令。

    这个对吗?

1个回答
  1. 似乎几乎是正确的,因为数据表在第 8.1 章,重置 AVR 中说:

    放置在复位向量的指令必须是一个 RJMP——相对跳转——复位处理程序的指令

    但是,第 202 页 - 指令集摘要 - 解释RJMP如下:

    RJMP    k    Relative Jump PC   PC + k  + 1        
    

    这将意味着,RJMP在地址PC=0k=0x34跳转到的地址0x35

    不幸的是,数据表似乎没有一个操作码表来确认它C0确实是一个RJMP.

    另外,第 5.1 章说

    ATtiny25/45/85 包含用于程序存储的 2/4/8K 字节片上系统内可重编程闪存。由于所有 AVR 指令都是 16 位或 32 位宽,因此 Flash 被组织为 1024/2048/4096 x 16。

    第 9 章显示了一张表(第 48 页),其中包含RJMP指令示例,尽管它们需要 2 个字节,但每个指令都打包到一个地址中。从偏移量 0 开始,有 15 个复位向量,每个向量为 16 位宽,程序从地址 开始0x0F所以地址空间似乎被划分为每个地址的 16 位块,而不是 8 位字节,这意味着您必须将地址加倍才能在十六进制数组中获得适当的字节索引。

  2. 对我来说似乎不正确,因为 PC 是0D1A在您的十六进制字节中的偏移量)和r=50,所以RJMP应该跳转到0D+50+1= 5E,或在您的十六进制字节中的偏移量BC( 2*0x5E) 。

  3. 根据我的假设,地址表示 16 位字,并+1从操作码选项卡中添加,您可能应该查看0x35*2=0x6A以找到要执行的第一条指令。