当前位置: 首页 > 知识库问答 >
问题:

microsoft与Java/Linux正弦函数差异的结果

越英韶
2023-03-14

initial_value_generator将计算一个值,稍后由random_value_generator函数使用该值。该值由一个FILETIME对象和三个常量生成。正在发生缓冲区溢出,但未处理。random_value_generator每次使用时都会修改DWORD64 prng_initial_value。

我成功地构建了initial_value_generator函数。

我想我不能完成这项任务,但任何帮助都很感激。

DWORD64 prng_initial_value = 0;

DWORD64 CON1_RVG = 0x4F3D859E;
double CON2_RVG = 0.946270391;

DWORD64 CON1_PRNG = 0x2682D10B7;
DWORD64 CON2_PRNG = 0x19254D38000;
DWORD64 CON3_PRNG = 0x0F1E34A09;
void initial_value_generator ()
{
    SYSTEMTIME systime;
    FILETIME filetime;

    // Systemzeit zu GMT-Format umwandeln
    SystemTimeToFileTime(&systime,&filetime);

    prng_initial_value = (*(DWORD64*)&filetime) * CON1_PRNG / CON2_PRNG + CON3_PRNG;
}
int random_value_generator () 
{
    double sin_value;
    double copy_of_prng_initial_value;
    DWORD64 prng_con1;
    double result;

    // Initialen Wert aus dem initial_random_generator in lokaler Variable speichern
    copy_of_prng_initial_value = prng_initial_value;

    // Sinus vom initialen Wert 
    sin_value = sin(copy_of_prng_initial_value);

    // Initialen Wert mulipikation mit einem konstanten Wert (0x4F3D859E)
    prng_con1 = prng_initial_value * CON1_RVG;
    result = prng_con1 + sin_value;
    result = result * copy_of_prng_initial_value;
    result = result + CON2_RVG;
    result = result * copy_of_prng_initial_value;

    // Das Ergebnis aus der Logarithmus Rechnung addieren
    result += log(copy_of_prng_initial_value);

    // Das Ergebnis aus den Berechnungen als Pointer in die
    // Speicheradresse von prng_initial_value als double Pointer speichern.
    *(double*)&prng_initial_value = result;

    // Rueckgabe des Berechneten Wert als Integer
    return prng_initial_value;
}

为了参考,我发布了我的Java代码(所有评论都是英文的)。随机函数看起来有点疯狂,因为我测试了很多东西。对此我很抱歉。但重点在于math.sin(双x)函数的使用,这与math.h中的sin函数在Microsoft C++编译器中的使用不同。

private final long initialValue;
private long randomValue;
final BigInteger uint64MaxValue = new BigInteger("18446744073709551616");   //2^64

public ConfickerC() {
    this.initialValue = this.generateInitialValue();
    this.randomValue = this.initialValue;
}

private long generateInitialValue() {
    //We need the actual date without the time from GMT +0 timezone
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);

    long systemtimeAsFiletime = cal.getTimeInMillis();

    /*
     * Goal is to get the above created date into Windows FileTime format.
     * The Windows FileTime format has got 100 nano seconds per tick.
     * So one increment of the long value results further 100 nano seconds.
     * Instead of Unix the FileTime format begins with 1st January 1601 - not 1970.
     * 11644473600 is the interval between 1601 and 1970 in seconds.
     * Java has got a resolution of 1 ms per tick unix have got 1 second per
     * tick. So first devide the time by 1000. Then add the interval. 
     * After this we multiply by 10 million to get a resolution of 100
     * nano seconds per tick.
     */
    systemtimeAsFiletime /= 1000;        //divide by 1000 to get seconds instead of milliseconds
    systemtimeAsFiletime += 11644473600L; //add x seconds to add the interval between 1601 and 1970
    systemtimeAsFiletime *= 10000000L;   //Windows FileTime has a resolution of 100 nano seconds per tick; so multiply by 10M

    /*
     * The virus is calulating for getting the initial value: time * con1 / con2 + con3
     * Originaly there occurs a buffer overflow which is not handled in the C++ code.
     * The funny thing is that Java does not have a DWORD64 (unsinged _int64). So because of this bit missing (and so the overflow is different) we need BigInteger. 
     * Because BigInteger has no 2^64 limitation we need the maximul value of DWORD64.
     * This is used to "simulate" the buffer overflow by calculating ((time * con1) % 2^64) / con2 + con3
     * modulo 2^64 will result a value which is equal to the C++ calculation
     */

    final BigInteger CONSTANT_1 = new BigInteger("10337718455");                //Original: 0x2682D10B7
    final BigInteger CONSTANT_2 = new BigInteger("1728000000000");              //Original: 0x19254D38000
    final BigInteger CONSTANT_3 = new BigInteger("4058204681");                 //Original: 0x0F1E34A09

    BigInteger bigIntSystemTime = BigInteger.valueOf(systemtimeAsFiletime);

    //Return as long value: ((time * con1) % 2^64) / con2 + con3
    return bigIntSystemTime.multiply(CONSTANT_1).divideAndRemainder(uint64MaxValue)[1].divide(CONSTANT_2).add(CONSTANT_3).longValue();
}

private int generateRandomValue() {
    final long CONSTANT_1 = 1329431966L;
    final double CONSTANT_2 = 0.946270391;
    double result = 0.0;
    double copyOfInit = this.randomValue;

    System.out.println(System.getProperty("line.separator") + "Copy of init: " + copyOfInit);
    System.out.printf("Copy of init: %f\n", copyOfInit);
    double sinInit = Math.sin(copyOfInit); System.out.println("Sinus: " + sinInit);  
    System.out.printf("Sinus: %f\n", sinInit);
    System.out.println("Sinus gerundet: " + Math.round(sinInit*1000000)/1000000.0d);
    BigInteger b =        BigInteger.valueOf(this.randomValue).multiply(BigInteger.valueOf(CONSTANT_1)).divideAndRemainder(uint64MaxValue)[1];

    System.out.println("Init * Konstante 1: " + b);
    BigDecimal bd = new BigDecimal(b.toString());
    //bd.add(BigDecimal.valueOf(sinInit));

    //result = t + sinInit; System.out.println("Multi + Sinus: " + result);
    result = bd.add(BigDecimal.valueOf(sinInit)).doubleValue(); System.out.println("Multi + Sinus: " + result);
    result *= (long) this.randomValue; System.out.println("Zwischenergebnis * init: " + result);
    result += CONSTANT_2; System.out.println("Konstante 2 addiert: " + result);
    System.out.printf("BigD: %s", BigDecimal.valueOf(result).multiply(BigDecimal.valueOf(randomValue)));
    result *= this.randomValue; System.out.printf("Erneut mit init multipliziert: %f", result);
    double l = Math.log((long)this.randomValue); System.out.println("Log von init: " + l);
    result += l; System.out.printf("+= mit Log: %f\n", result);

    this.randomValue = (long)result; System.out.printf("Ende: %d\n", this.randomValue);

    this.randomValue = Double.doubleToRawLongBits(result);

    return (int)this.randomValue;   
}

共有1个答案

骆雅昶
2023-03-14

三角函数是库函数,具有合理的模糊规范。例如,以下是C标准对这个主题(7.12.4.6):

罪恶的功能

提要

#include <math.h>
double sin(double x);
float sinf(float x);
long double sinl(long double x);

sin函数返回sinx

因此,他们将使用不同的算法和不同的精确度,也就是说,使用库版本你不会得到完全相同的结果。例如,不同的库可能会在精度和计算速度之间做出不同的权衡。即使库实现完全相同,您也可能不会在不同的系统上得到完全相同的结果,因为在整个计算过程中,值可能会在不同的地方四舍五入。为了在不同平台之间获得相当接近的结果,您可能需要在这些平台上实现相同的算法。

注意,sin(x)显然提供了[0,π/2]范围内的最佳结果。将一个巨大的数字传递给sin(x)可能会产生一个相当糟糕的近似值,尽管我希望大多数实现在进行任何计算之前将x映射到上面给出的范围。理想情况下,从一开始就避免使用大值,而是用π的倍数表示它们。但是,即使x在上面的范围内,您也可能从不同的实现中得到不同的结果。

 类似资料:
  • 本文向大家介绍函数与程序之间的差异,包括了函数与程序之间的差异的使用技巧和注意事项,需要的朋友参考一下 函数 在计算机编程语言环境中,功能是一组指令,这些指令需要一些输入并执行某些任务。在SQL中,函数返回一个值。 程序 过程也是一组指令,它们接受输入并执行某些任务。在SQL中,过程不返回值。在Java中,过程和函数是相同的,也称为子例程。 以下是SQL函数和SQL过程之间的重要区别。 序号 键

  • 我被问到这个面试问题。我不确定它的正确答案是什么(以及答案背后的推理):

  • 本文向大家介绍C语言中计算正弦的相关函数总结,包括了C语言中计算正弦的相关函数总结的使用技巧和注意事项,需要的朋友参考一下 C语言sin()函数:正弦函数 头文件:  sin() 函数用来求给定值的正弦值,其原型为: 【参数】给定的值(弧度)。 【返回值】返回-1 至1 之间的计算结果。 弧度与角度的关系为: 弧度 = 180 / π 角度 角度 = π / 180 弧度 使用 rtod( ) 函

  • 问题内容: 做一个简单的测试时,我就在用Java编写正则表达式 但是在JavaScript中 这里发生了什么?我可以使我的Java regex模式“ q”的行为与JavaScript相同吗? 问题答案: 在JavaScript中,返回与使用的正则表达式匹配的子字符串。在Java中,检查整个字符串是否与正则表达式匹配。 如果要查找与正则表达式匹配的子字符串,请使用Pattern和Matcher类,例

  • 箭头函数: 正规函数 这两个结果应该是相同的,但是看起来像上面定义的arrowFunc考虑第一个arg列表,而normalFunc考虑第二组arg列表。

  • 本文向大家介绍MySQL与Oracle差异比较之三 函数,包括了MySQL与Oracle差异比较之三 函数的使用技巧和注意事项,需要的朋友参考一下 函数 编号 类别 ORACLE MYSQL 注释 1 数字函数 round(1.23456,4) round(1.23456,4) 一样: ORACLE:select round(1.23456,4) value from dual MYSQL:sel