问题描述
我想知道是否存在任何通过蛮力逆转AND例程的标准方法。 例如,我有以下转换:
MOV(eax,0x5b3e0be0) <- Here we move 0x5b3e0be0 to EDX.
MOV(edx,eax) # Here we copy 0x5b3e0be0 to EAX as well.
SHL(edx,0x7) # Bitshift 0x5b3e0be0 with 0x7 which results in 0x9f05f000
AND(edx,0x9d2c5680) # AND 0x9f05f000 with 0x9d2c5680 which results in 0x9d045000
XOR(edx,eax) # XOR 0x9d045000 with original value 0x5b3e0be0 which results in 0xc63a5be0
我的问题是如何强行使用和反转该例程(即将0xc63a5be0转换回0x5b3e0be0)
我有一个想法(不起作用)是使用PeachPy实现的:
#Input values
MOV(esi,0xffffffff) < Initial value to AND with,which will be decreased by 1 in a loop.
MOV(cl,0x1) < Initial value to SHR with which will be increased by 1 until 0x1f.
MOV(eax,0xc63a5be0) < Target result which I'm looking to get using the below loop.
MOV(edx,0x5b3e0be0) < Input value which will be transformed.
sub_esi = peachpy.x86_64.Label()
with loop:
#End the loop if ESI = 0x0
TEST(esi,esi)
JZ(loop.end)
#Test the routine and check if it matches end result.
MOV(ebx,eax)
SHR(ebx,cl)
TEST(ebx,ebx)
JZ(sub_esi)
AND(ebx,esi)
XOR(ebx,eax)
CMP(ebx,edx)
JZ(loop.end)
#Add to the CL register which is used for SHR.
#Also check if we've reached the last potential value of CL which is 0x1f
ADD(cl,0x1)
CMP(cl,0x1f)
JNZ(loop.begin)
#Decrement ESI by 1,reset CL and restart routine.
peachpy.x86_64.LABEL(sub_esi)
SUB(esi,0x1)
MOV(cl,0x1)
JMP(loop.begin)
#The ESI result here will either be 0x0 or a valid value to AND with and get the necessary result.
RETURN(esi)
也许是您可以推荐的文章或书籍?
解决方法
这不是有损的,最后的操作是XOR。
整个例程可以用C建模为
#define K 0x9d2c5680
uint32_t hash(uint32_t num)
{
return num ^ ( (num << 7) & K);
}
现在,如果我们有两个位 x 和 y 以及操作 x XOR y ,当 y 为零,结果为 x 。
因此,给定两个数字 n1 和 n2 并考虑它们的XOR,在 n2 中与零配对的位或 n1 >会变成结果未更改(其他将被翻转)。
因此,在考虑num ^ ( (num << 7) & K)
时,我们可以将num
标识为 n1 ,将(num << 7) & K
标识为 n2 。
由于 n2 是AND,因此我们可以说它必须至少具有与 K 相同的零位。
这意味着num
的每个与常量 K 中的零位相对应的位都将使其不变为结果。
因此,通过从结果中提取这些位,我们已经有了部分逆函数:
/*hash & ~K extracts the bits of hash that pair with a zero bit in K*/
partial_num = hash & ~K
从技术上讲,num << 7
因子还将在AND结果中引入其他零。我们肯定知道最低的7位必须为零。
但是 K 已经具有最低的7位零,因此我们无法利用此信息。
因此,我们在这里只使用 K ,但是如果其值不同,则需要考虑AND(实际上,这意味着将 K 的低7位清零>)。
这给我们留下了13个未知的位(对应于 K 中设置的位)。
如果我们暂时忘记AND,我们将拥有x ^ (x << 7)
的含义
h i = num i 表示 i ,范围从0到6(含)
h i = num i ^ num i-7 for i 从7到31(含)
(第一行是由于右侧的低7位为零)
从这里开始,从h 7 开始,然后我们可以检索num 7 作为h 7 ^ num 0 = h 7 ^ h 0 。
从第7位开始,等式不起作用,我们需要使用num k (对于合适的 k ),但是幸运的是,我们已经在上一步中计算了其值(这就是为什么我们从低到高开始)。
AND对此所做的只是将索引 i 所运行的值限制在特定范围内,特别是仅将 K 中设置的位限制为该值。
所以要填写剩余的十三位,必须要做的:
part_num 7 = h 7 ^ part_num 0
part_num 9 = h 9 ^ part_num 2
part_num 12 = h 12 ^ part_num 5
...
part_num 31 = h 31 ^ part_num 24
请注意,我们利用了part_num 0..6 = h 0..6 。
这是一个C函数,可以将函数取反:
#include <stdio.h>
#include <stdint.h>
#define BIT(i,hash,result) ( (((result >> i) ^ (hash >> (i+7))) & 0x1) << (i+7) )
#define K 0x9d2c5680
uint32_t base_candidate(uint32_t hash)
{
uint32_t result = hash & ~K;
result |= BIT(0,result);
result |= BIT(2,result);
result |= BIT(3,result);
result |= BIT(5,result);
result |= BIT(7,result);
result |= BIT(11,result);
result |= BIT(12,result);
result |= BIT(14,result);
result |= BIT(17,result);
result |= BIT(19,result);
result |= BIT(20,result);
result |= BIT(21,result);
result |= BIT(24,result);
return result;
}
uint32_t hash(uint32_t num)
{
return num ^ ( (num << 7) & K);
}
int main()
{
uint32_t tester = 0x5b3e0be0;
uint32_t candidate = base_candidate(hash(tester));
printf("candidate: %x,tester %x\n",candidate,tester);
return 0;
}
,
由于最初的问题是如何“蛮力”而不是解决,所以我最终想到了一些同样有效的方法。显然,根据输入,它容易出错(可能会超过1个结果)。
python -m pip install wheel # only first time
python -m pip install wheel_file.whl # for each library you want to install