如何从 RAM 内存中存储和加载 class?
How to store and load a class from the RAM memory?
今天有朋友问我是否可以像用 IDA 反转可执行文件一样反转 jar 文件。
答案显然是"yes",但出于好奇,我需要尝试一下。
IDA free 不允许我反编译 JAR 文件,但我终于找到了 CFR 和 JD。
所以我创建了一个 crackMe.jar 询问我们密码,然后解密 2 个 DLL 并读取它们的输出。
第一个 DLL 的输出是一个 class 文件,用于检查密码是否正确,第二个 DLL 的输出也是一个 class 文件,用于擦除两个输出- 目的是让破解者无法读取它们。
不过这个crackMe还是太容易破解了...破解者只需要修改crackMe.jar的Main.class,保留DLL的输出,然后修改tmp.class 并删除 tmp$del.class.
我想制作另一个 DLL 来检查 Main.class 是否被修改...但我们可以轻松破解它。
这就是为什么我需要在第一时间知道是否可以将文件存储在 RAM 内存中。
为什么我们使用CFR 时源代码在java 中是可读的?我们有没有办法加密 class 并以十六进制执行它而不使用外部程序解密它?
是否可以在内存中提取一些内容并保持对它的访问,即使我们在 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);
}
}
是的,可以从内存资源中加载 Class。您需要编写自定义类加载器来执行此操作,但该类加载器可以将字节码加载到 byte[]
中并调用 (protected
) defineClass
方法之一。
但是,我不确定这会为您带来什么:
如果您试图在代码 运行 在您的计算机上时对其进行保护,则完全没有必要。只需阻止饼干进入您的机器即可。 (但如果你做不到,那你就完蛋了;见下文。)
如果您试图在 运行 在破解者的机器上保护您的代码,那么这将无济于事。破解者需要做的就是启动调试器,在 byte[]
中的解密字节码准备好调用 defineClass
的位置设置断点。
无论你做什么,如果破解者 "owns" 执行平台,他们就可以获得在其上运行的应用程序的字节码。 (这同样适用于任何本机代码库。)
今天有朋友问我是否可以像用 IDA 反转可执行文件一样反转 jar 文件。
答案显然是"yes",但出于好奇,我需要尝试一下。
IDA free 不允许我反编译 JAR 文件,但我终于找到了 CFR 和 JD。
所以我创建了一个 crackMe.jar 询问我们密码,然后解密 2 个 DLL 并读取它们的输出。
第一个 DLL 的输出是一个 class 文件,用于检查密码是否正确,第二个 DLL 的输出也是一个 class 文件,用于擦除两个输出- 目的是让破解者无法读取它们。
不过这个crackMe还是太容易破解了...破解者只需要修改crackMe.jar的Main.class,保留DLL的输出,然后修改tmp.class 并删除 tmp$del.class.
我想制作另一个 DLL 来检查 Main.class 是否被修改...但我们可以轻松破解它。
这就是为什么我需要在第一时间知道是否可以将文件存储在 RAM 内存中。
为什么我们使用CFR 时源代码在java 中是可读的?我们有没有办法加密 class 并以十六进制执行它而不使用外部程序解密它?
是否可以在内存中提取一些内容并保持对它的访问,即使我们在 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);
}
}
是的,可以从内存资源中加载 Class。您需要编写自定义类加载器来执行此操作,但该类加载器可以将字节码加载到 byte[]
中并调用 (protected
) defineClass
方法之一。
但是,我不确定这会为您带来什么:
如果您试图在代码 运行 在您的计算机上时对其进行保护,则完全没有必要。只需阻止饼干进入您的机器即可。 (但如果你做不到,那你就完蛋了;见下文。)
如果您试图在 运行 在破解者的机器上保护您的代码,那么这将无济于事。破解者需要做的就是启动调试器,在
byte[]
中的解密字节码准备好调用defineClass
的位置设置断点。
无论你做什么,如果破解者 "owns" 执行平台,他们就可以获得在其上运行的应用程序的字节码。 (这同样适用于任何本机代码库。)