Etwas Reverse Engineering

Die letzten zwei Tage habe ich damit verbracht, die Daten aus den Dateien eines Programmes herauszukitzeln. Die eigentlichen Daten werden zunächst komprimiert und dann verschlüsselt.

Während es relativ einfach war, den Entschlüsselungsvorgang nachzuvollziehen, hatte mir die Komprimierung zunächst Probleme bereitet.

Letztendlich konnte ich allerdings zwei kleine Javaschnipsel fertigstellen. Das Erste entschlüsselt die Daten, das Zweite macht daraus ein lzh-File. Entpackbar mit jedem handelsüblichen Entpacker, der allerdings Dateien auch entpacken muss, wenn die CRC-16 Summe nicht mit der Originaldatei übereinstimmt.

Zum Entschluesseln:

import java.io.FileInputStream;
import java.io.FileOutputStream;


public class Decrypt {
    public static void main(String[] args) throws Exception {
        String infilename = "original.dat";
        String outfilename = "decrypted.dat";

        FileInputStream fis = new FileInputStream(infilename);
        FileOutputStream fos = new FileOutputStream(outfilename);

        short varA = (short)0xb6f2;
        short var15;
        short eax;
        short edx;

        System.out.println(fis.available());

        while(fis.available() > 0) {
            var15 = (short)fis.read();
            var15 &= 0xff;

            eax = var15;
            edx = varA;

            edx >>>= 8;
            edx &= 0xff;

            var15 = (short)(var15 ^ edx);
            var15 &= 0xffff;

            eax &= 0xff;
            eax += varA;
            eax *= 0xDC1B;
            eax += 0x41A5;
            varA = eax;

            fos.write(var15);
        }

        fis.close();
        fos.flush();
        fos.close();
    }
}

Zum Erstellen der lzh-Datei:

import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Decrypt2LZH {
    public static void main(String[] args) throws Exception {
        String infilename = "decrypted.dat";
        String outfilename = "data.lzh";

        FileInputStream fis = new FileInputStream(infilename);
        FileOutputStream fos = new FileOutputStream(outfilename);

        byte[] header = {
            (byte)0x1b, (byte)0x00, // header size, header checksum
            (byte)'-', (byte)'l', (byte)'h', (byte)'5', (byte)'-', // compression method -lh5-
            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // compressed size
            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, // original size
            (byte)0x00, (byte)0x00, (byte)0x21, (byte)0x00, // msdos last modified date/time
            (byte)0x20, (byte)0x00, // msdos file attributes
            (byte)0x05, // size of filename
            (byte)'x', (byte)'.', (byte)'d', (byte)'a', (byte)'t', // filename x.dat
            (byte)0x00, (byte)0x00 // crc-16 of original file
        };

        int compressed = fis.read();
        int encrypted = fis.read();

        if(compressed != 0x26)
            return;

        if(encrypted == 0x26)
            throw new IllegalArgumentException("blowfish encryption not supported");

        // read original file size from inputfile and put it in the lha header
        header[11] = (byte)fis.read();
        header[12] = (byte)fis.read();
        header[13] = (byte)fis.read();
        header[14] = (byte)fis.read();

        // put the compressed size in the header
        int csize = fis.available();
        header[7]  = (byte)(csize & 0xff);
        header[8]  = (byte)((csize >>> 8 ) & 0xff);
        header[9]  = (byte)((csize >>> 16 ) & 0xff);
        header[10]  = (byte)((csize >>> 24 ) & 0xff);

        // calculate the header checksum
        int sum = 0;
        for(byte b: header)
            sum += b;

        header[1] = (byte)(sum & 0xff);

        // write lzh file
        fos.write(header);

        while(fis.available() > 0)
            fos.write(fis.read());

        fos.flush();
        fos.close();
        fis.close();
    }
}

Contact

Alexander Gitter
contact at agitter net