Valhalla Legends Forums Archive | Battle.net Bot Development | [C#]CheckRevision

AuthorMessageTime
shout
I am trying to create a check revison algorithum... but it does not give the correct values. I am using the string "A=153298715 B=515653871 C=630933526 4 A=A+S B=B^C C=C^A A=A^B" (which I got from packetlogging brood war), and when I use mine ( from iago's Java) I get 0x44c0733a, but with BNLS I get 0xff887946.

Here is my code (sorry for lack of comments):
[code]
private static uint[] hashcodes = new uint[] { 0xE7F4CB62, 0xF6A14FFC,0xAA5504AF,0x871FCDC2,0x11BF6A18,0xC57292E6,0x7927D27E,0x2FEC8733 };

public static uint CheckRevision(string VersionString, string[] FileNames, string client, int mpqNum)
{
char[] Operations = new char[4];
ulong[] Values = new ulong[4];
int[] opDest = new int[4];
int[] opSrc1 = new int[4];
int[] opSrc2 = new int[4];

SeperateVerString(VersionString, Operations, Values, opDest, opSrc1, opSrc2);

Values[0] ^= hashcodes[mpqNum];

for (int i = 0; i < 3; i++)
{
FileStream fileStream = new FileStream(FileNames[i],FileMode.Open, FileAccess.Read);
FileInfo fileInfo = new FileInfo(FileNames[i]);
int fileLength = (int)fileInfo.Length;
byte[] Buffer = new byte[4];
int roundedLength = (fileLength / 1024) * 1024;

for (int j = 0; j < roundedLength; j += 4)
{
fileStream.Read(Buffer, 0, 4);
Values[3] = BitConverter.ToUInt32(Buffer, 0);
for (int k = 0; k < 4; k++)
{
switch (Operations[k])
{
case '+':
Values[opDest[k]] = Values[opSrc1[k]] + Values[opSrc2[k]];
break;
case '-':
Values[opDest[k]] = Values[opSrc1[k]] - Values[opSrc2[k]];
break;
case '^':
Values[opDest[k]] = Values[opSrc1[k]] ^ Values[opSrc2[k]];
break;
default:
break;
}
}
}
}
return (uint)Values[2];
}

private static void SeperateVerString(string VersionString, char[] Operations, ulong[] Values, int[] opDest, int[] opSrc1, int[] opSrc2)
{
char equals = '=';
char space = ' ';
string[] verString = VersionString.Split(space);
string[] values = new string[4];
string[] tmp = new string[2];

for (int i = 0; i < 4; i++)
{
values[i] = verString[i];
}

for (int i = 0; i < 3; i++)
{
tmp = values[i].Split(equals);
Values[i] = (ulong)int.Parse(tmp[1]);
}

for (int i = 0; i < 3; i++)
{
opDest[i] = getNum((char)verString[i + 4][0]);
opSrc1[i] = getNum((char)verString[i + 4][2]);
opSrc2[i] = getNum((char)verString[i + 4][4]);
Operations[i] = verString[i + 4][3];
}
}
[/code]

Don't ask why I put the chars in a variable in SeperateVerString but I did so oh well.

And just for good measure, iago's code:

[code]
/*
* CheckRevision.java
*
* Created on March 10, 2004, 9:05 AM
*/

package bot.bnet.util;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import java.nio.channels.FileChannel;

import java.nio.MappedByteBuffer;
import java.nio.ByteOrder;

import java.util.StringTokenizer;

import timer.Timer;

/**
*
* @author  iago
*/
public class CheckRevision
{
    private static final int hashcodes[] = { 0xE7F4CB62, 0xF6A14FFC, 0xAA5504AF, 0x871FCDC2, 0x11BF6A18, 0xC57292E6, 0x7927D27E, 0x2FEC8733 };
   
    /** This class simply does the version check on the three main files.
    */
    public static int checkRevision(String versionString, String[] files, int mpqNum) throws FileNotFoundException, IOException
    {
        // First, parse the versionString to name=value pairs and put them
        // in the appropriate place
        int[] values = new int[4];
       
        int[] opValueDest = new int[4];
        int[] opValueSrc1 = new int[4];
        char[] operation = new char[4];
        int[] opValueSrc2 = new int[4];
       
        // Break this apart at the spaces
        StringTokenizer s = new StringTokenizer(versionString, " ");
        int currentFormula = 0;
        while(s.hasMoreTokens())
        {
            String thisToken = s.nextToken();
            // As long as there is an '=' in the string
            if(thisToken.indexOf('=') > 0)
            {
                // Break it apart at the '='
                StringTokenizer nameValue = new StringTokenizer(thisToken, "=");
                if(nameValue.countTokens() != 2)
                    return 0;
               
                int variable = getNum(nameValue.nextToken().charAt(0));
               
                String value = nameValue.nextToken();
               
                //System.out.println((int)variable + " = " + value);
               
                // If it starts with a number, assign that number to the appropriate variable
                if(Character.isDigit(value.charAt(0)))
                {
                    values[variable] = Integer.parseInt(value);
                }
                else
                {
                    opValueDest[currentFormula] = variable;
                   
                    opValueSrc1[currentFormula] = getNum(value.charAt(0));
                    operation[currentFormula] = value.charAt(1);
                    opValueSrc2[currentFormula] = getNum(value.charAt(2));
                   
                    currentFormula++;
                }
            }
        }
       
        // Now we actually do the hashing for each file
        // Start by hashing A by the hashcode
        values[0] ^= hashcodes[mpqNum];
       
        for(int i = 0; i < files.length; i++)
        {
            Timer thisFile = new Timer();
           
            File currentFile = new File(files[i]);
           
            int roundedSize = (int)((currentFile.length() / 1024) * 1024);
           
            // Load the file into memory
            FileInputStream input = new FileInputStream(new File(files[i]));
            MappedByteBuffer file = input.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, roundedSize);
            file.order(ByteOrder.LITTLE_ENDIAN);
            file.load();
           
            //System.out.println("Processing " + currentFile.toString() + " (" + (roundedSize/4) + " DWords)");
            //System.out.print("Processing " + currentFile.toString() + "........");
           
            for(int j = 0; j < roundedSize; j += 4)
            {
                values[3] = file.getInt(j);
                //values[3]  = (file.get() & 0xFF) |
                //            ((file.get() & 0xFF) << 8) |
                //            ((file.get() & 0xFF) << 16) |
                //            ((file.get() & 0xFF) << 24);
                               
                for(int k = 0; k < currentFormula; k++)
                {
                    switch(operation[k])
                    {
                        case '+':
                            values[opValueDest[k]] = values[opValueSrc1[k]] + values[opValueSrc2[k]];
                            break;
                           
                        case '-':
                            values[opValueDest[k]] = values[opValueSrc1[k]] - values[opValueSrc2[k]];
                            break;
                           
                        case '^':
                            values[opValueDest[k]] = values[opValueSrc1[k]] ^ values[opValueSrc2[k]];
                            break;
                           
                        default:
                            return 0;
                    }
                }
            }
           
            //System.out.println(thisFile.getTime() + "ms.");
        }
        //System.out.println(Integer.toHexString(values[0]));
        //System.out.println(Integer.toHexString(values[1]));
        //System.out.println(Integer.toHexString(values[2]));
        return values[2];
    }

    private static int getNum(char c)
    {
        c = Character.toUpperCase(c);
        if(c == 'S')
            return 3;
        else
            return c - 'A';
    }
   
    public static void main(String args[]) throws Exception
    {
        String[] files = { "/home/iago/Projects/Java/bot/starcraft.exe",
                            "/home/iago/Projects/Java/bot/storm.dll",
                            "/home/iago/Projects/Java/bot/battle.snp" } ;
        long totalTime = 0;
        final int MAX = 100;
        long min = -1;
        long max = -1;
        for(int i = 0; i < MAX; i++)
        {
            int val1 = (int) (Math.random() * (double)Integer.MAX_VALUE);
            int val2 = (int) (Math.random() * (double)Integer.MAX_VALUE);
            int val3 = (int) (Math.random() * (double)Integer.MAX_VALUE);
       
            String testString = "A=" + val1 + " B=" + val2 + " C=" + val3 + " 4 A=A^S B=B-C C=C+A A=A+B";

                           
            Timer checkRevision = new Timer();
            checkRevision(testString, files, 6);
            long elapsed = checkRevision.getTime();
            System.out.println("checkRevision took " + elapsed + "ms.");
            totalTime += elapsed;
           
            if(elapsed < min || min == -1)
                min = elapsed;
            if(elapsed > max || max == -1)
                max = elapsed;
        }
       
        System.out.println("For " + MAX + "runs:");
        System.out.println("Total time: " + totalTime + "ms");
        System.out.println("Average time: " + (totalTime / MAX) + "ms");
        System.out.println("Min time: " + min + "ms");
        System.out.println("Max time: " + max + "ms");
       
        //System.out.println(Integer.toHexString(a));
    }
}
[/code]
November 24, 2004, 8:01 PM
Mephisto
Immediately looking at your switch statement I see that you're not doing as you should.  In the case of xor, you're adding, same with the case of subtraction, you still add.
November 24, 2004, 8:12 PM
shout
LOL... I am so FUCKING STUPID!!!

** Hits head on keyboard **

(Crying)Stupid, stupid, stupid...

Fixed that.

Now I get 0xab919d86.

I guess I will have to go through the grueling task of installing java on my machine... **sigh**

It seems although my SeperateVerString method is faulty. I shall fix it.
November 24, 2004, 8:14 PM
Myndfyr
[quote author=shout link=topic=9666.msg89918#msg89918 date=1101327266]
I guess I will have to go through the grueling task of installing java on my machine... **sigh**
[/quote]

Or maybe you could just fix it and get it right...?
November 25, 2004, 2:09 AM
shout
It was more so I could tell exactly what iago's code was doing.

Well, anyway, it works now. It's kind of ugly and it may only work with SC/BW
[code]
public class CheckRevision
{
private static bool SeperateVerString(string VersionString, char[] Operations, ulong[] Values, int[] opDest, int[] opSrc1, int[] opSrc2)
{
string[] verString = VersionString.Split(' '); //Split the string at the spaces
string[] NumericASValues = new string[4]; //The A=320842304 and so fourth

for (int i = 0; i != 4; i++) //Puts the string values into an array
{
NumericASValues[i] = verString[i];
}

string[] tmpstr = new string[2]; //Temp storage for split string of values
for (int i = 0; i != 3; i++)
{
tmpstr = NumericASValues[i].Split('='); //Splits the string at the =
Values[i] = ulong.Parse(tmpstr[1]); //Parses values into ulongs
}
Values[3] = 4;

for (int i = 0; i != 4; i++)
{
opDest[i] = getNum((char)verString[i + 4][0]); //Gets the destination for the calculation
opSrc1[i] = getNum((char)verString[i + 4][2]); //Gets the first source for the calculation
opSrc2[i] = getNum((char)verString[i + 4][4]); //Gets the 2nd source for the calculation
Operations[i] = verString[i + 4][3]; //Gets the operator for the calculation
}
return true;
}
private static uint[] hashcodes = new uint[] { 0xE7F4CB62, 0xF6A14FFC,0xAA5504AF,0x871FCDC2,0x11BF6A18,0xC57292E6,0x7927D27E,0x2FEC8733 };

public static uint CheckRevision(string VersionString, string[] FileNames, string client, int mpqNum)
{
char[] Operations = new char[4];
ulong[] Values = new ulong[4];
int[] opDest = new int[4];
int[] opSrc1 = new int[4];
int[] opSrc2 = new int[4];

SeperateVerString(VersionString, Operations, Values, opDest, opSrc1, opSrc2);

Values[0] ^= hashcodes[mpqNum];

for (int i = 0; i < 3; i++)
{
FileStream fileStream = new FileStream(FileNames[i],FileMode.Open, FileAccess.Read);
FileInfo fileInfo = new FileInfo(FileNames[i]);
int fileLength = (int)fileInfo.Length;
byte[] Buffer = new byte[4];
int roundedLength = (fileLength / 1024) * 1024;

for (int j = 0; j < roundedLength; j += 4)
{
fileStream.Read(Buffer, 0, 4);
Values[3] = BitConverter.ToUInt32(Buffer, 0);
for (int k = 0; k < 4; k++)
{
switch (Operations[k])
{
case '+':
Values[opDest[k]] = Values[opSrc1[k]] + Values[opSrc2[k]];
break;
case '-':
Values[opDest[k]] = Values[opSrc1[k]] - Values[opSrc2[k]];
break;
case '^':
Values[opDest[k]] = Values[opSrc1[k]] ^ Values[opSrc2[k]];
break;
default:
break;
}
}
}
}
return (uint)Values[2];
}
private static int getNum(char c)
{
c = char.ToUpper(c);
if(c == 'S')
{
return 3;
}
else
{
return c - 'A';
}
}
}
[/code]
November 25, 2004, 2:24 AM

Search