我有一个校验和,我正在尝试逆向工程,我已经知道如何在我知道用于创建校验和的原始初始值之后保持校验和生成。
到目前为止,我知道校验和是使用双数据类型数学方程生成的。
计算校验和的最终值是无符号整数,但在此之前它会从double转换为unsigned long long(unsigned __int64)。
我要做的是将无符号整数返回到double数据类型中的相同值,以进入撤消校验和以检索原始初始值的下一步。
虽然校验和计算在这里是它以double数据类型生成的值。
3083570000.3115764
创建校验和0xB7CB8B50
我不认为这是一个有损的对话,所以即使它从8字节双向下转换为4字节整数校验和,也没有真正丢失。为什么?因为double
值总是通过乘以4294967295.0
来创建,我认为这只是为了消除尾随的4个字节,就像一个班次。
因此,我要查找的double
值必须除以4294967295.0
,才能将原始的双精确值恢复到最后一位数。
问题是我无法正确划分它,因为它不是100%准确到最后一个小数点..我知道浮点数学它与IEEE浮点废话不准确100%,但我不关心那个我只是试图以与第一次创建相同的方式来扭转这一现象。
输出
假设原始校验和双倍为0.71794958809146792
0.71794958809146792 * 4294967295.0 = 3083570000.3115761849416764
数据包中发送的答案是0xb7cb8b50
如果我手动手动将无符号整数0xb7cb8b50
投射到unsigned __int64
,它应该如下0x00000000b7cb8b50
原始的双倍如何在代码中生成应该如下所示,我在添加到数据包之前使用了相同的密钥来重新创建相同的条件,以便首先制作校验和,它应该看起来像这样
Real ANSWER = 3083570000.3115764
因此
0x00000000b7cb8b50 should equals = 3083570000.3115764 double
我的反向代码看起来像这样
unsigned int checksum = 0xb7cb8b50;
double test1 = (double)(unsigned __int64)checksum;
double test2 = double(checksum);
double test3 = static_cast<double>(checksum);
double test4 = *((double*)(void*)&checksum);
上面的代码错误了几位小数。
test1 returns = 3083570000.0000000
test2 returns = 3083570000.0000000
test3 returns = 3083570000.0000000
test4 returns = 1.523486003547e-314#DEN
如何获得额外的.3115764
以及我的问题。
答案 0 :(得分:2)
double
数字的小数部分(小数点后)在分配给整数时会丢失。
执行反向操作(将结果int
指定给double
),小数部分将为0.因此无法恢复double
的原始值号。
在以下代码的输出中,可以看到double
值如何存储在内存中(最重要的32位不是0):
double initial = 0.71794958809146792 * 4294967295.0;
uint64_t rawValue = *(uint64_t*)&initial;
uint32_t checksum = (uint32_t)initial;
printf("initial: %f 0x%llx\n", initial, rawValue);
printf("after: %u 0x%x\n", checksum, checksum);
// Prints
// initial: 3083570000.311576 0x41e6f9716a09f86f
// after: 3083570000 0xb7cb8b50
尝试将原始int
值转换为double
(如在*((double*)(void*)&checksum)
中)是不正确的操作,甚至可能访问不属于checksum
的内存(如果如果4个字节,则int
大小。
有关double
表示的更多信息,请访问:
https://en.wikipedia.org/wiki/Double-precision_floating-point_format