├── README.md
├── pom.xml
└── src
└── main
├── java
└── me
│ └── javapacker
│ ├── Main.java
│ ├── app
│ ├── api
│ │ └── PackerApplication.java
│ └── impl
│ │ └── JavaPacker.java
│ ├── config
│ └── PackerConfiguration.java
│ ├── file
│ ├── api
│ │ ├── Encryptable.java
│ │ ├── PackerFile.java
│ │ └── PackerFilesManager.java
│ └── impl
│ │ ├── EncryptableImpl.java
│ │ ├── FactoryPackerFiles.java
│ │ ├── PackerFileImpl.java
│ │ └── PackerFilesManagerImpl.java
│ ├── steps
│ ├── api
│ │ ├── PackerRepository.java
│ │ └── PackerStep.java
│ └── impl
│ │ ├── PackerRepositoryImpl.java
│ │ ├── S01ReadingJar.java
│ │ ├── S02EncryptClasses.java
│ │ ├── S03TrashingResource.java
│ │ ├── S04SavingKey.java
│ │ ├── S05JoinLoader.java
│ │ └── S06AttachManifest.java
│ └── utils
│ ├── JarUtil.java
│ ├── RandomUtil.java
│ └── StringUtil.java
└── resources
└── MANIFEST.MF
/README.md:
--------------------------------------------------------------------------------
1 | # JavaPacker
2 |
3 | Semester project for studies using GoF design patterns - sometimes they are used by force :D
4 |
5 |
6 | ## Getting Started
7 |
8 | The goal of the project is to encrypt another JAR executable based on the key provided by the user, save it to a file and create a decryptor and put it into the loader (I used ow2 asm to generate bytecode).
9 | After launching the program and going through all the steps, you will get the default - output.jar in jar file location (configurable) file which is ready to run. Nothing hard! :)
10 |
11 | ## Configuration
12 |
13 | ```
14 | #Mon Jan 11 10:08:37 CET 2021
15 | useNullByteName=true
16 | outputPath=output.jar
17 | fakeDirectory=true
18 | inputPath=input.jar
19 | encryptionKey=ABCDEFGHIJKLMNPA
20 | ```
21 |
22 | Property name | expected value | Description
23 | ------------- | ------------- | -------------
24 | inputPath | Path to input jar file | Define input jar location
25 | outputPath | Path to output jar file | Define output jar location
26 | encryptionKey | 16 bytes(length) key | Key used to AES encryption
27 | useNullByteName | true/false | Method add \u0000 to the beginning of the class name. This method allows you to hide class names and prevent them from unpacking by popular archivers like WinRar
28 | fakeDirectory | true/false | https://github.com/x4e/fakedirectory - completely unavailable to anyone using WinRAR, Luyten and every other zip viewer.
29 |
30 | ## My comment
31 |
32 | Such a packer is not a protection you can rely on. It can only come in handy against total noobs. If you already want to use it somewhere to add extra protection to your application - Please obfuscate the loader.
33 | Remember that there are tons of ways to get around this - memory dump, defineClass hook, javaagent ... etc
34 |
35 |
36 | ## Screenshots
37 |
38 | 
39 | 
40 |
41 | ## Credits
42 | x4e - https://github.com/x4e/fakedirectory
43 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | JavaPacker
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-compiler-plugin
15 |
16 | 8
17 | 8
18 |
19 |
20 |
21 | maven-assembly-plugin
22 |
23 |
24 | package
25 |
26 | single
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | me.javapacker.Main
35 |
36 |
37 |
38 | jar-with-dependencies
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | commons-io
50 | commons-io
51 | 2.8.0
52 |
53 |
54 |
55 | org.ow2.asm
56 | asm
57 | 9.0
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/Main.java:
--------------------------------------------------------------------------------
1 | package me.javapacker;
2 |
3 | import me.javapacker.app.api.PackerApplication;
4 | import me.javapacker.app.impl.JavaPacker;
5 |
6 | public class Main {
7 |
8 |
9 | public static void main(String[] args)
10 | {
11 | new JavaPacker().enableApp();
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/app/api/PackerApplication.java:
--------------------------------------------------------------------------------
1 | package me.javapacker.app.api;
2 |
3 | public abstract class PackerApplication {
4 |
5 | public abstract void enableApp();
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/app/impl/JavaPacker.java:
--------------------------------------------------------------------------------
1 | package me.javapacker.app.impl;
2 |
3 | import me.javapacker.app.api.PackerApplication;
4 | import me.javapacker.config.PackerConfiguration;
5 | import me.javapacker.file.api.PackerFilesManager;
6 | import me.javapacker.file.impl.FactoryPackerFiles;
7 | import me.javapacker.steps.api.PackerRepository;
8 | import me.javapacker.steps.api.PackerStep;
9 | import me.javapacker.steps.impl.*;
10 |
11 | public class JavaPacker extends PackerApplication {
12 |
13 | public static JavaPacker INSTANCE;
14 | private PackerRepository packerRepository;
15 |
16 | @Override
17 | public void enableApp() {
18 | INSTANCE = this;
19 |
20 | try {
21 | PackerConfiguration.INSTANCE.readConfiguration();
22 | } catch (Exception e) {
23 | e.printStackTrace();
24 | }
25 | this.packerRepository = new PackerRepositoryImpl();
26 | final PackerFilesManager packerFilesManager = FactoryPackerFiles.createPackerFilesManager(PackerConfiguration.INSTANCE.getInputPath(), PackerConfiguration.INSTANCE.getOutputPath());
27 | final PackerStep packerStep = new S01ReadingJar(packerFilesManager);
28 | packerStep.linkWith(new S02EncryptClasses(packerFilesManager))
29 | .linkWith(new S03TrashingResource(packerFilesManager))
30 | .linkWith(new S04SavingKey(packerFilesManager))
31 | .linkWith(new S05JoinLoader(packerFilesManager))
32 | .linkWith(new S06AttachManifest(packerFilesManager));
33 | this.packerRepository.setPackerStep(packerStep);
34 | this.packerRepository.packApplication();
35 | }
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/config/PackerConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.javapacker.config;
2 |
3 | import me.javapacker.steps.api.PackerStep;
4 |
5 | import java.io.*;
6 | import java.util.Properties;
7 |
8 | public class PackerConfiguration {
9 |
10 | public static PackerConfiguration INSTANCE = new PackerConfiguration();
11 | final Properties properties = new Properties();
12 | private static String encryptionKey;
13 | private static String inputPath;
14 | private static String outputPath;
15 | private static boolean useNullByteName;
16 | private static boolean fakeDirectory;
17 |
18 | private PackerConfiguration() { }
19 |
20 | public void readConfiguration() throws Exception {
21 | final File f = new File("javapacker.properties");
22 | if(!f.exists())
23 | {
24 | properties.setProperty("inputPath", "input.jar");
25 | properties.setProperty("outputPath", "output.jar");
26 | properties.setProperty("encryptionKey", "ABCDEFGHIJKLMNPA");
27 | properties.setProperty("useNullByteName", "true");
28 | properties.setProperty("fakeDirectory", "true");
29 | properties.store(new FileOutputStream(f), "");
30 | }
31 | loadConfiguration(f);
32 | }
33 |
34 | private void loadConfiguration(final File f) throws IOException {
35 | properties.load(new FileInputStream(f));
36 | inputPath = properties.getProperty("inputPath");
37 | outputPath = properties.getProperty("outputPath");
38 | encryptionKey = properties.getProperty("encryptionKey");
39 | useNullByteName = Boolean.parseBoolean(properties.getProperty("useNullByteName"));
40 | fakeDirectory = Boolean.parseBoolean(properties.getProperty("fakeDirectory"));
41 | if(encryptionKey.length() != 16)
42 | {
43 | throw new RuntimeException("EncryptionKey length must be 16 bytes!");
44 | }
45 | }
46 |
47 | public String getEncryptionKey() {
48 | return encryptionKey;
49 | }
50 |
51 | public String getInputPath() {
52 | return inputPath;
53 | }
54 |
55 | public String getOutputPath() {
56 | return outputPath;
57 | }
58 |
59 | public boolean isUseNullByteName() {
60 | return useNullByteName;
61 | }
62 |
63 | public boolean isFakeDirectory() {
64 | return fakeDirectory;
65 | }
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/file/api/Encryptable.java:
--------------------------------------------------------------------------------
1 | package me.javapacker.file.api;
2 |
3 | public interface Encryptable {
4 |
5 | String getEncryptableConfig();
6 |
7 | String getEncryptableFile();
8 |
9 | void setEncryptableConfigName(final String name);
10 |
11 | void setEncryptableFileName(final String name);
12 |
13 | String getEncryptionKey();
14 |
15 | byte[] getEncryptionIV();
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/file/api/PackerFile.java:
--------------------------------------------------------------------------------
1 | package me.javapacker.file.api;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.jar.JarFile;
6 |
7 | public interface PackerFile {
8 |
9 | File getFile();
10 |
11 | default JarFile asJarFile() throws IOException {
12 | return new JarFile(getFile());
13 | }
14 |
15 | String getMainClassName();
16 |
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/file/api/PackerFilesManager.java:
--------------------------------------------------------------------------------
1 | package me.javapacker.file.api;
2 |
3 | import java.util.zip.ZipOutputStream;
4 |
5 | public interface PackerFilesManager {
6 |
7 | PackerFile getInputFile();
8 |
9 | PackerFile getOutputFile();
10 |
11 | ZipOutputStream asZipOutputStream();
12 |
13 | Encryptable getEncryptable();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/file/impl/EncryptableImpl.java:
--------------------------------------------------------------------------------
1 | package me.javapacker.file.impl;
2 |
3 | import me.javapacker.file.api.Encryptable;
4 |
5 | import java.util.Random;
6 |
7 | public class EncryptableImpl implements Encryptable {
8 |
9 | private String encryptableConfig;
10 | private String encryptableFileName;
11 | private final String encryptionKey;
12 | private final byte[] encryptionIV;
13 |
14 | public EncryptableImpl(String encryptionKey) {
15 | this.encryptionKey = encryptionKey;
16 | final byte[] iv = new byte[16];
17 | new Random().nextBytes(iv);
18 | this.encryptionIV = iv;
19 | }
20 |
21 | @Override
22 | public String getEncryptableConfig() {
23 | return this.encryptableConfig;
24 | }
25 |
26 | @Override
27 | public String getEncryptableFile() {
28 | return this.encryptableFileName;
29 | }
30 |
31 | @Override
32 | public void setEncryptableConfigName(String name) {
33 | this.encryptableConfig = name;
34 | }
35 |
36 | @Override
37 | public void setEncryptableFileName(String name) {
38 | this.encryptableFileName = name;
39 | }
40 |
41 | @Override
42 | public String getEncryptionKey() {
43 | return this.encryptionKey;
44 | }
45 |
46 | @Override
47 | public byte[] getEncryptionIV() {
48 | return this.encryptionIV;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/file/impl/FactoryPackerFiles.java:
--------------------------------------------------------------------------------
1 | package me.javapacker.file.impl;
2 |
3 | import me.javapacker.file.api.PackerFilesManager;
4 |
5 | import java.io.File;
6 |
7 | public class FactoryPackerFiles {
8 |
9 | public static PackerFilesManager createPackerFilesManager(final String inputPath, final String outputPath)
10 | {
11 | return new PackerFilesManagerImpl(new PackerFileImpl(new File(inputPath), true),
12 | new PackerFileImpl(new File(outputPath), false)
13 | );
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/me/javapacker/file/impl/PackerFileImpl.java:
--------------------------------------------------------------------------------
1 | package me.javapacker.file.impl;
2 |
3 | import me.javapacker.file.api.PackerFile;
4 |
5 | import java.io.File;
6 | import java.io.IOException;
7 | import java.util.Map;
8 | import java.util.jar.JarFile;
9 |
10 | public class PackerFileImpl implements PackerFile {
11 |
12 | private final File file;
13 | private String mainClassName;
14 |
15 | public PackerFileImpl(File file, boolean readMain) {
16 | this.file = file;
17 | if(!readMain)
18 | {
19 | return;
20 | }
21 | try {
22 | final JarFile jarFile = asJarFile();
23 | Map