0

我有一个校验和,我正在尝试对其进行逆向工程,我已经知道在我知道最初用于创建校验和的原始初始值之后如何保持校验和生成。

到目前为止,我知道校验和是使用双数据类型数学方程生成的。

计算出的校验和的最终值是一个无符号整数,但在此之前它会从 double 转换为 unsigned long long aka (unsigned __int64)。

我要做的是将一个无符号整数恢复为双数据类型中的相同值,以进入撤消校验和以检索原始初始值的下一步。

当校验和在这里计算时,它以双精度数据类型生成的值。 3083570000.3115764它创建了一个校验和0xB7CB8B50

我不认为这是一个有损的对话,所以即使它从 8 字节双倍转换回 4 字节整数校验和,也没有真正丢失。为什么?因为该double值始终是通过乘以创建的4294967295.0,我认为这只是为了消除尾随的 4 个字节,有点像移位。

因此,double我要检索的值必须除以4294967295.0才能将原始双精度值精确地恢复到最后一位。

问题是我不能正确划分它,因为它不是 100% 准确到最后一个小数点。我知道浮点数学不是 100% 准确的 IEEE 浮点废话,但我不在乎我只是试图以与最初创建相同的方式来扭转这一点。

输出 假设原始校验和双倍是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也是我的问题。

4

1 回答 1

2

double分配给整数时,数字的小数部分(小数点后)会丢失。

进行逆运算(将结果分配int给 a 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(如果int大小为 4 字节)。

有关double代表的更多信息,请访问:

https://en.wikipedia.org/wiki/Double-precision_floating-point_format

于 2015-11-26T22:39:27.560 回答