如何从RAM内存中存储和加载类?

时间:2015-09-27 05:00:00

标签: java memory memory-management reverse-engineering cracking

今天有朋友问我是否可以反转jar文件,就像我们可以用IDA反转可执行文件一样。

答案显然是“是”,但我很好奇,我需要尝试。

IDA free不允许我反编译JAR文件,但我终于找到了CFR和JD。

所以我创建了一个crackMe.jar,它向我们提供密码,然后解密2个DLL并读取它们的输出。

第一个DLL的输出是一个类文件,它检查密码是否正确,第二个DLL的输出也是一个类文件,这里用于擦除两个输出 - 目的是让它们不可读裂化器。

但是这个crackMe仍然太容易破解......破解者只需要修改crackMe.jar的Main.class,保留DLL的输出,然后修改tmp.class并删除tmp $ del.class

我想创建另一个DLL来检查Main.class是否被修改......但我们可以轻松破解它。

这就是为什么我第一次需要知道是否可以将文件存储在RAM内存中。

为什么在使用CFR时源代码在java中是可读的?我们有没有办法加密类并以十六进制执行它而不使用外部程序来解密它?

即使我们在java中没有指针,是否有可能在内存中提取内容并保持对它的访问? (在C ++中可能吗?) - 我已经找到了这个主题:https://unix.stackexchange.com/questions/59300/how-to-place-store-a-file-in-memory-on-linux

我们可以管理内存的访问权限吗?因此,如果程序是以管理员身份启动的,那么CPU是否可以将控制权保留在内存的一部分上,只允许程序读取它而不是用户? - https://en.wikipedia.org/wiki/Protection_ring

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);
    }
}

tmp.class和tmp $ del.class

的源代码

它们不在crackMe.jar中,而是在名为data.dll和data_2.dll的同一文件夹中。

此源代码已加密。

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)
            {

            }
        }
    }
}

我用来创建DLL文件的加密器的源代码

此程序永远不会离开我的电脑,因此破解者无法读取它。

我们只是将它用于加密tmp.class和tmp $ del.class到data.dll和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);
    }
}

1 个答案:

答案 0 :(得分:2)

是的,可以从内存资源加载一个Class。您需要编写一个自定义类加载器来执行此操作,但该类加载器可以将字节码加载到byte[]并调用其中一个(protecteddefineClass方法。

但是,我不确定这会给你带来什么:

  • 如果您尝试在计算机上运行代码时保护代码,则完全没有必要。只需阻止饼干进入您的机器。 (但如果你不能这样做,那你就搞砸了;见下文。)

  • 如果您想在密码机的机器上运行时保护您的代码,那么这不会有帮助。所有破解者需要做的就是启动调试器,在byte[]准备调用defineClass的解密字节码处设置断点。

无论你做什么,如果饼干&#34;拥有&#34;他们可以在执行平台上获取在其上运行的应用程序的字节码。 (这同样适用于任何本机代码库。)