Search code examples
javamemorymemory-managementreverse-engineeringcracking

How to store and load a class from the RAM memory?


Today a friend asked me if it was possible to reverse a jar file like we can reverse an executable with IDA.

The answer was obviously "yes", but as I am curious, I needed to try.

IDA free didn't allow me to decompile a JAR file but I finally find CFR and JD.

So I created a crackMe.jar which ask us a password, then decrypt 2 DLLs and read their output.

The output of the first DLL is a class file which check if the password is right and the output of the second DLL is also a class file which is here for erase the both output - the aim is to keep them unreadable by the cracker.

But this crackMe is still too easy the crack... The cracker just have to modify the Main.class of crackMe.jar, keep the output of the DLLs, then modify the tmp.class and delete tmp$del.class.

I have think to make another DLL for check if the Main.class was modify... But we can crack it easily.

This is why I need to know on a first time if it is possible to store a file on the RAM memory.

Why the source code is readable in java when we use CFR? Have we a way to encrypt the class and execute it in hexadecimal without use an external program for decrypt it?

Is it possible to extract something on the memory and keep the access on it even if we didn't have the pointer in java? (is it possible in C++?) - I already find this topic: https://unix.stackexchange.com/questions/59300/how-to-place-store-a-file-in-memory-on-linux

Can we manage the access rights of the memory? So if the program is launch as administrator, does the CPU can keep the control on a part of the memory for only allow the program to read it and not the user? - https://en.wikipedia.org/wiki/Protection_ring

The source code of crackMe.jar:

public class Main
{
    public static void main(String[] args) throws Exception
    {
        if (new java.io.File(fct("yju!ibq+hifpx")).exists() || new java.io.File(fct("yju+hifpx")).exists())
        {
            new java.io.File(fct("i^y^3aqi")).delete();
            new java.io.File(fct("i^y^d/3aqi")).delete();
            javax.swing.JOptionPane.showMessageDialog(null, fct("Zkf_qb%qttsjo|onqjyju+hifpxto%qrm)aji3`q^xp"));
        }
        String str = javax.swing.JOptionPane.showInputDialog(fct("Jkybw~lzo%mfpxttoi7"));
        byte[] keyBytes = fct("o^{^").getBytes();
        javax.crypto.spec.SecretKeySpec secretKeySpec = new javax.crypto.spec.SecretKeySpec(keyBytes, fct("Gittkfxe"));
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance(fct("Gittkfxe"));
        cipher.init(javax.crypto.Cipher.DECRYPT_MODE, secretKeySpec);
        java.io.File fileTmp1 = new java.io.File(fct("yju!ibq+hifpx"));
        java.io.BufferedInputStream bufferedInputStream = new java.io.BufferedInputStream(new java.io.FileInputStream(fct("i^y^d/3aqi")));
        javax.crypto.CipherOutputStream cipherOutputStream = new javax.crypto.CipherOutputStream(new java.io.BufferedOutputStream(new java.io.FileOutputStream(fileTmp1)), cipher);
        int i;
        if (str != null && str != "")
        {
            do
            {
                i = bufferedInputStream.read();
                if (i != -1)
                    cipherOutputStream.write(i);
            }while (i != -1);
        }
        bufferedInputStream.close();
        cipherOutputStream.close();
        java.io.File fileTmp2 = new java.io.File(fct("yju+hifpx"));
        bufferedInputStream = new java.io.BufferedInputStream(new java.io.FileInputStream(fct("i^y^3aqi")));
        cipherOutputStream = new javax.crypto.CipherOutputStream(new java.io.BufferedOutputStream(new java.io.FileOutputStream(fileTmp2)), cipher);
        if (str != null && str != "")
        {
            do
            {
                i = bufferedInputStream.read();
                if (i != -1)
                    cipherOutputStream.write(i);
            }while (i != -1);
        }
        bufferedInputStream.close();
        cipherOutputStream.close();
        Runtime.getRuntime().exec(fct("o^{^%qrm%") + str);
        Thread.sleep(200);
        fileTmp1.delete();
        fileTmp2.delete();
    }

    private static String fct(String str)
    {
        char[] strC = str.toCharArray();
        for (int i = 0, j = str.length(); i < j; i++)
        {
            if (i % 2 == 0)
                strC[i] -= 5;
            else
                strC[i] += 3;
        }
        return String.valueOf(strC);
    }
}

The source code of tmp.class and tmp$del.class

They are not inside crackMe.jar but on the same folder with the name data.dll and data_2.dll.

This source code is encrypted.

class tmp
{
    private static String str1, str2 = "Iivfv1$Nvfr^$:Ho\\}%", str3 = "EGq\"", str4 = "W\\xltwkeix\\h%";
    private static boolean bool;

    protected static void setBool(boolean b)
    {
        bool = b;
    }

    protected static boolean getBool()
    {
        return bool;
    }

    public static void main(String[] args)
    {
        new tmp(true, args[0]);
    }

    private static void fct1(int index)
    {
        if (index == 0)
            javax.swing.JOptionPane.showMessageDialog(null, fct5(str2));
    }

    private static void fct2(int index)
    {
        if (index == 0)
            javax.swing.JOptionPane.showMessageDialog(null, fct5(str4));
    }

    private static void fct3(int index)
    {
        new del().start();
        if (index == 0 && getBool())
        {
            fct1(0);
        }
        else if (index == 1 && !getBool())
        {
            fct2(0);
        }
    }

    private static boolean fct4()
    {
        return !bool&&!(fct5(str3).equals(str1));
    }

    private static String fct5(String str)
    {
        char[] strC = str.toCharArray();
        for (int i = 0, j = str.length(); i < j; i++)
        {
            if (i % 2 == 0)
                strC[i] -= 4;
            else
                strC[i] += 9;
        }
        return String.valueOf(strC);
    }

    protected tmp(boolean bool, String arg)
    {
        str1 = arg;
        setBool(false);
        if (fct4())
        {
            setBool(true);
            fct3(0);
        }
        else
        {
            fct3(1);
        }
    }

    static class del extends Thread
    {
        public void run()
        {
            try
            {
                Thread.sleep(50);
                byte[] keyBytes = "erase".getBytes();
                javax.crypto.spec.SecretKeySpec secretKeySpec = new javax.crypto.spec.SecretKeySpec(keyBytes, "Blowfish");
                javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("Blowfish");
                cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, secretKeySpec);
                java.io.BufferedInputStream bufferedInputStream = new java.io.BufferedInputStream(new java.io.FileInputStream("tmp.class"));
                javax.crypto.CipherOutputStream cipherOutputStream = new javax.crypto.CipherOutputStream(new java.io.BufferedOutputStream(new java.io.FileOutputStream("tmp.class")), cipher);
                int i;
                do
                {
                    i = bufferedInputStream.read();
                    if (i != -1)
                        cipherOutputStream.write(i);
                }while (i != -1);
                bufferedInputStream.close();
                cipherOutputStream.close();
                bufferedInputStream = new java.io.BufferedInputStream(new java.io.FileInputStream("tmp$del.class"));
                cipherOutputStream = new javax.crypto.CipherOutputStream(new java.io.BufferedOutputStream(new java.io.FileOutputStream("tmp$del.class")), cipher);
                do
                {
                    i = bufferedInputStream.read();
                    if (i != -1)
                        cipherOutputStream.write(i);
                }while (i != -1);
                bufferedInputStream.close();
                cipherOutputStream.close();
            }
            catch (Exception e)
            {

            }
        }
    }
}

The source code of the encryptor which I have use to create the DLLs files

This program never leave my computer so the cracker cannot read it.

We use it just for encrypt tmp.class and tmp$del.class into data.dll and data_2.dll.

public class encrypt
{
    public static void main(String[] args) throws Exception
    {
        byte[] keyBytes = "java".getBytes();
        javax.crypto.spec.SecretKeySpec secretKeySpec = new javax.crypto.spec.SecretKeySpec(keyBytes, "Blowfish");
        javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("Blowfish");
        cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, secretKeySpec);

        java.io.BufferedInputStream bufferedInputStream = new java.io.BufferedInputStream(new java.io.FileInputStream("tmp.class"));
        javax.crypto.CipherOutputStream cipherOutputStream = new javax.crypto.CipherOutputStream(new java.io.BufferedOutputStream(new java.io.FileOutputStream("data.dll")), cipher);
        int i;
        do
        {
            i = bufferedInputStream.read();
            if (i != -1)
                cipherOutputStream.write(i);
        }while (i != -1);
        bufferedInputStream.close();
        cipherOutputStream.close();

        bufferedInputStream = new java.io.BufferedInputStream(new java.io.FileInputStream("tmp$del.class"));
        cipherOutputStream = new javax.crypto.CipherOutputStream(new java.io.BufferedOutputStream(new java.io.FileOutputStream("data_2.dll")), cipher);
        do
        {
            i = bufferedInputStream.read();
            if (i != -1)
                cipherOutputStream.write(i);
        }while (i != -1);
        bufferedInputStream.close();
        cipherOutputStream.close();

        System.exit(0);
    }
}

Solution

  • Yes, it is possible to load a Class from an in-memory resource. You need to write a custom classloader to do it, but that classloader can load the bytecodes into a byte[] and call one of the (protected) defineClass methods.

    However, I'm not sure what this will achieve for you:

    • If you are trying to protect your code while it is running on your machine, this is all unnecessary. Just stop the cracker getting into your machine. (But if you can't do that, you are screwed; see below.)

    • If you are trying to protect your code while it is running on on the cracker's machine, then this won't help. All the cracker needs to do is to start a debugger, set a breakpoint at the point where you have the decrypted bytecodes in a byte[] ready to call defineClass.

    No matter what you do, if the cracker "owns" the execution platform they can get hold of the bytcodes of an application that runs on it. (And the same applies to any native code libraries.)