Skip to content

Commit

Permalink
Fix String mutation breaking in classes with a lot of strings, fix nu…
Browse files Browse the repository at this point in the history
…ber mutation break in classes with a lot of numbers. Added notifications for missing classes
  • Loading branch information
Simon committed Mar 15, 2021
1 parent cfd20f5 commit 440b1f2
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 13 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ Caesium is a powerful Java bytecode obfuscator written by [sim0n](https://github
* Polymorph
* Reference (invokedynamics)
* String
* Trim (Currently only trims math functions)

## Notes
You have to add every dependency your jar relies on.
Caesium is very optimised and the performance loss shouldn't be more than 5-10% (unless you're using reference mutation)

## Usage
- Run the jar.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>dev.sim0n</groupId>
<artifactId>caesium</artifactId>
<version>1.0.8</version>
<version>1.0.9</version>

<build>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void handle(ClassWrapper wrapper) {
} while ((insn = insn.getNext()) != null);
});

if (numbers > 5000) // this is wayyy too much
if (numbers > 1000) // this is wayyy too much
return;

insns.forEach(instructions -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ public void handle(ClassWrapper wrapper) {

newSig = Type.getMethodDescriptor(origReturnType, args);


switch (opcode) {
case INVOKEVIRTUAL:
case INVOKESTATIC:
Expand Down
14 changes: 9 additions & 5 deletions src/main/java/dev/sim0n/caesium/mutator/impl/StringMutator.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public class StringMutator extends ClassMutator {
private String keyField = getRandomName();
private String decryptMethodName = getRandomName();

private String initName;

private String bsmName = getRandomName();
private String bsmSig = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/Object;";
private Handle bsmHandle = null;
Expand Down Expand Up @@ -60,6 +62,7 @@ public void handle(ClassWrapper wrapper) {
keyField = getRandomName();

decryptMethodName = getRandomName();
initName = getRandomName();

bsmName = getRandomName();
bsmHandle = new Handle(H_INVOKESTATIC, target.name, bsmName, bsmSig);
Expand Down Expand Up @@ -197,7 +200,7 @@ public String encryptString(String s) {

instance.init(Cipher.ENCRYPT_MODE, keyFactory.generateSecret(new DESKeySpec(keys)), new IvParameterSpec(new byte[8]));

return new String(Base64.getEncoder().encode(instance.doFinal(s.getBytes(Charsets.ISO_8859_1))));
return new String(Base64.getEncoder().encode(instance.doFinal(s.getBytes(Charsets.UTF_8))));
} catch (Exception e) {
e.printStackTrace();
}
Expand Down Expand Up @@ -439,13 +442,13 @@ public InsnList getClinitInstructions(ClassNode owner) {

LabelNode l2 = new LabelNode();
instructions.add(l2);
instructions.add(new MethodInsnNode(INVOKESTATIC, owner.name, "_init", "()V", false));
instructions.add(new MethodInsnNode(INVOKESTATIC, owner.name, initName, "()V", false));

return instructions;
}

public MethodNode makeInit(ClassNode owner) {
MethodNode mv = new MethodNode(ACC_PRIVATE + ACC_STATIC, "_init","()V", null,null);
MethodNode mv = new MethodNode(ACC_PRIVATE + ACC_STATIC, initName,"()V", null,null);

mv.visitCode();
Label l0 = new Label();
Expand Down Expand Up @@ -604,8 +607,9 @@ public MethodNode makeInit(ClassNode owner) {
mv.visitLabel(l19);
mv.visitLineNumber(126, l19);
mv.visitFrame(F_SAME, 0, null, 0, null);
// TODO: this can break classes with huge amount of strings
// generate completely random fake strings
for (int i = 0; i < stringCount * ThreadLocalRandom.current().nextInt(5, 20); i++) {
for (int i = 0; i < 1; i++) {
mv.visitFieldInsn(GETSTATIC, owner.name, stringField2, "[Ljava/lang/String;");

ASMUtil.visitOptimisedInt(mv, i);
Expand All @@ -622,7 +626,7 @@ public MethodNode makeInit(ClassNode owner) {
mv.visitLineNumber(130, l21);
mv.visitFrame(F_SAME, 0, null, 0, null);
// generate completely random fake strings
for (int i = 0; i < Math.min(5, stringCount) * ThreadLocalRandom.current().nextInt(5, 20); i++) {
for (int i = 0; i < 1; i++) {
mv.visitFieldInsn(GETSTATIC, owner.name, stringField2, "[Ljava/lang/String;");

ASMUtil.visitOptimisedInt(mv, i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import dev.sim0n.caesium.exception.CaesiumException;
import dev.sim0n.caesium.util.wrapper.impl.ClassWrapper;

import javax.swing.*;

public class CaesiumClassWriter extends ClassWriter {
public CaesiumClassWriter(int flags) {
super(flags);
Expand All @@ -30,13 +32,15 @@ protected String getCommonSuperClass(final String type1, final String type2) {
// TODO Auto-generated catch block
e.printStackTrace();
}

String second = null;
try {
second = deriveCommonSuperName(type2, type1);
} catch (CaesiumException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

if (!"java/lang/Object".equals(first))
return first;

Expand All @@ -49,9 +53,8 @@ protected String getCommonSuperClass(final String type1, final String type2) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "java/lang/Object";


return "java/lang/Object";
}

private String deriveCommonSuperName(String type1, String type2) throws CaesiumException {
Expand All @@ -74,24 +77,28 @@ else if (Modifier.isInterface(first.access) || Modifier.isInterface(second.acces

private ClassNode returnClazz(String ref) throws CaesiumException {
ClassWrapper clazz = PreRuntime.getClassPath().get(ref);
if (clazz == null)
if (clazz == null) {
JOptionPane.showMessageDialog(null, "Couldn't find " + ref + " in classpath.", "Error", JOptionPane.ERROR_MESSAGE);
throw new CaesiumException(ref + " does not exist in classpath!", null);
}

return clazz.node;
}

private boolean isAssignableFrom(String type1, String type2) throws CaesiumException {
if ("java/lang/Object".equals(type1))
return true;

if (type1.equals(type2))
return true;

returnClazz(type1);
returnClazz(type2);
ClassTree firstTree = getTree(type1);
if (firstTree == null) {

if (firstTree == null)
throw new CaesiumException("Could not find " + type1 + " in the built class hierarchy", null);
}

Set<String> allChildren = new HashSet<>();
Deque<String> toProcess = new ArrayDeque<>(firstTree.subClasses);
while (!toProcess.isEmpty()) {
Expand Down

0 comments on commit 440b1f2

Please sign in to comment.