最近,我一直在筛选整个程序集,以试图确定程序如何解密某些数据。到目前为止,我已经确定了IV的提取方法,IV的长度为16个字节,并且解密方法使用了密码块链接。因此,我相信所使用的加密方法是AES-128-CBC。

下一步是尝试识别用于解密的密钥,问题是单个块密码加密的程序集大小约为2.5MB。但是,我观察到的是,它们都是非常相似的形式,例如片段:

在参数(r12)中,如下所示:针对r0(始终为0xff),然后执行某些操作,XOR,OR,ADD或MOV影响另一个寄存器(在示例中为0xff)。

我目前的预感是这可能是具有展开回合的AES-128实现。隐藏钥匙?如果是这样,那么如何对其进行混淆并找到密钥呢?

附加信息。

这是到使用CBC的子例程的链接,并调用上述在主要问题中引用的子例程。

评论

根据以上代码段,对我来说似乎不是AES-128,但是您可以共享更大的代码段还是整个功能?

@ebux这是我相信正在使用CBC的过程,这是问题中提到的分组密码功能的扩展代码段(不完整,因为它是60MB的asm文件)。我认为这些调用的参数如下sub_44d84()和sub_46d554()。

尽管很难在没有地址的情况下遵循代码,但您的CBC假设可能是正确的。但是在密码中,我只能看到它读出了输入缓冲区的第一个字节,并用输入字节的修改后的值填充了缓冲区。同样有趣的是如何生成输出(r3存储输出指针)以及如何稍后在函数上使用生成的缓冲区。

@ebux我已经用地址更新了那些代码片段,如果有帮助的话。如果我上传了完整的ASM文件,对您有帮助吗,那么您可以看一下功能到底如何?

完整的ASM文件就可以了。

#1 楼

我认为您正确地确定了功能的目的及其参数。因此,函数sub_44d84具有四个参数:(<decryptionFunction=0x1>, <IV>, <bytesToDecrypt>, <decryptedBytes>),并使用CBC为每个块调用sub_46d554函数。

sub_46d554函数收到2个参数: /> R0:加密的输入块

R1:加密的输出块在函数的最后部分写出到输出缓冲区。

要了解解密功能,首先要了解混淆的基本组成部分。因此,在从输入块中读取第二个字节后,我获得了一些示例代码(由于编译器的优化,该函数的开头有点混乱)。



在上图中,标有绿色的行读出了输入块的第二个字节,橙色的行初始化了R2寄存器。黄色和蓝色块执行类似的功能。两个块均以加法开始,将结果存储到局部变量,然后检查结果是否等于0xFF。如果结果为0xFF,则更改R2的值。由于仅当加法器为R2并且加法器始终使用0xFF(包含输入的第二个字节)时才更改LR,因此R2寄存器的值只能更改一次。因为新的R2值仅取决于LR,所以这些块实现了一个查找表,该表是一个替换框。因此,在伪代码中,查找表是以以下方式实现的:

if (input == 0xb1) out = 0x5b
if (input == 0x42) out = 0x56
...


要了解将结果存储到局部变量中的原因,让我们检查一下局部变量var_1A8的下一次用法。



它读取局部变量,是加法的结果,并检查是否与以前的情况类似。由于仅当加法的结果在最初存储值的地方为0xFF时,此局部变量的值才为0xFF,因此比较将再次检查输入字节是否等于特定值。

如果在整个函数中搜索局部变量0xFF,我们会反复收到很多带有特定模式(var_1A8STRLDRLDR)的结果。

LDR表示添加的存储,而STR表示此添加的用法。因此,每个字节都要检查四次,然后再使用另一个字节。 br />
i0 = input[0x00]
d0_0 = table0[i0]
id = input[0x0d]
d0_d = table1[id]
ia = input[0x0a]
d0_a = table2[ia]
i7 = input[0x07]
d0_7 = table3[i7]

d1_0 = table4[i0]
d1_d = table5[id]
d1_a = table6[ia]
d1_7 = table7[i7]

d2_0 = table8[i0]
d2_d = table9[id]
d2_a = table10[ia]
d2_7 = table11[i7]

d3_0 = table12[i0]
d3_d = table13[id]
d3_a = table14[ia]
d3_7 = table15[i7]


因此,读出4个字节,执行替换并将结果存储在局部变量中。之后,对接下来的4个字节执行相同的操作,依此类推。在处理完整个块之后,将读取存储的结果并将以前的一些结果的异或值用作新的输入,例如:根据局部变量的用法,可以清楚地看到它使用9轮替换。

基于以上内容,我认为解密功能可以是AES-128实现。因为添加回合键,子字节和移位行步骤操作可以在一个步骤中使用查找表来实现,而混合列操作则可以在另一步骤中实现。因为只有9个回合,所以可以使用一个查找表实现AES的初始回合和第一回合。

因此,密钥(如果确实是AES实现,则为扩展密钥)被混入实现中。尽管我不是一位冷冻医生,但我想您可以通过将查找表的值与Rijndael S-Box值进行异或来检索扩展的AES密钥。但是,这似乎是一个艰巨且耗时的过程,因此,如果您只想解密一些数据,则可以考虑模拟代码。

评论


这是一个很好的答案,非常感谢@ebux。从事物的声音来看,您似乎已经在每个回合中用SubBytes步骤(找到的第一个模式)和MixColumns步骤(第二个模式,对先前的结果进行XOR)标识了中间的9轮AES。那让我想知道ShiftRows和AddRoundKey步骤。在解密过程中,最后一轮(第10轮)将仅使用按位XOR添加原始密钥,您在函数末尾看到过类似的东西吗?

–约书亚
16-2-15在12:27



AES在每个回合中都使用扩展密钥而不是原始密钥。在最后一轮结束时,查找结果存储在输出缓冲区中,这可能意味着AddRoundKey步骤或其他步骤的混合。

– ebux
16 Feb 15'在12:34

的确,除了第一轮加密(最后一轮解密)(它使用原始密钥作为扩展密钥的前16个字节时)之外,它都可以与扩展密钥一起使用,只是加密密钥本身。我明白了,我自己再看一眼。

–约书亚
16-2-15在12:46



没错,但最后的ShiftRows和SubBytes步骤可以与最后的AddRoundKey步骤结合使用。

– ebux
16 Feb 15'在12:57

我知道了-您是否对ShiftRows步骤的执行方式有任何想法?另外,可能在您的问题中错过了它,但是查找表存储在哪里(即``table0`'')?

–约书亚
16-2-15在13:04