0

リバース エンジニアリングしようとしているチェックサムがあります。最初にチェックサムを作成するために使用された元の初期値を知っていれば、チェックサムを生成し続ける方法を既に知っています。

これまでのところ、ダブルデータ型の数式を使用してチェックサムが生成されることがわかっています。

計算されたチェックサムの最終値は符号なし整数ですが、その前に double から unsigned long long 別名 (unsigned __int64) に変換されます。

私がやろうとしているのは、元の初期値を取得するためにチェックサムを元に戻す次のステップに進むために、符号なし整数を double データ型の同じ値に戻すことです。

ここでチェックサムが計算されている間、double データ型で生成される値です。 3083570000.3115764チェックサムを作成する0xB7CB8B50

これは損失の多い会話ではないと思うので、8 バイトの double から 4 バイトの整数チェックサムに変換しても実際には何も失われません。なんで?double値は常に乗算によって作成されるため4294967295.0、シフトのような末尾の 4 バイトを排除するだけだと私は信じています。

したがって、元の double 値を最後の桁に正確に戻すには、double取得しようとしている値を で割る必要があります。4294967295.0

問題は、最後の小数点まで100%正確ではないため、適切に分割できないことです..浮動小数点演算では、IEEE浮動小数点のがらくたで100%正確ではないことを知っていますが、気にしません最初に作成されたのと同じ方法でこれを元に戻そうとしています。

出力 元のチェックサム double は0.71794958809146792
0.71794958809146792 * 4294967295.0 = 3083570000.3115761849416764
、パケットで送信された回答であるとします。0xb7cb8b50

符号なし整数0xb7cb8b50unsigned __int64手動で手動でキャストすると、次のようになります0x00000000b7cb8b50

コードで生成された元の double は次のようになります。最初にチェックサムを作成するために同じ条件を再作成するために、パケットに追加される前に同じキーを使用しました。これは次のようになります。
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(のように)にキャストしようとするのは正しくない操作であり、 (サイズが 4 バイトの場合)*((double*)(void*)&checksum)に属していないメモリにアクセスすることさえあります。checksumint

double表現の詳細については、次のサイトを参照してください。

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

于 2015-11-26T22:39:27.560 に答える