foreword
What is code obfuscation
Code obfuscation is the act of converting the code of a computer program into a form that is functionally equivalent but difficult to read and understand.
Common means of code obfuscation
1. Name confusion
Change meaningful class, field, method names to meaningless strings. The shorter the new name generated, the smaller the byte code. In name-obfuscated byte code, package, class, field and method names are renamed and the original names can never be restored. Unfortunately, the control flow is still clearly visible. Hence the need for stream obfuscation
2. Stream Confusion
Used for keywords such as if, switch, while, for, etc. to make minor modifications to the bytecode, obfuscating the flow of control, without changing the behavior of the code at runtime. Often, logical constructs like selection and looping are changed so that they no longer have a direct Java source equivalent. Streaming obfuscated bytecode often forces decompilers to insert a series of labels and illegal goto statements into the source code they generate. Source code is sometimes obscured by decompilation errors
other
Exception confusion, string encryption confusion, reference confusion, etc.
The role of code obfuscation
Not only does it protect the code, it also has the effect of reducing the size of the compiled program. Due to the shortening of variable and function names and the loss of some information, the volume of the jar file after compilation can be reduced by about 25%, which is meaningful for the current expensive wireless network transmission.
Possible problems with code obfuscation
Obfuscated code is harder to understand, and therefore harder to debug and debug. Developers often need to keep the original unobfuscated code for debugging. For languages that support reflection, code obfuscation has the potential to conflict with reflection. Code obfuscation doesn't really prevent reverse engineering, it only makes it harder. Therefore, for occasions with high security requirements, just using code obfuscation cannot guarantee the security of source code.
Commonly used obfuscation tools
1、yGuard
yGuard is a free Java obfuscator (not open source), it has two versions for Java and .NET. yGuard is completely free, runs on Ant tasks, and provides highly configurable obfuscation rules.
Official website address: https://www.yworks.com/products/yguard
2、proguard
proguard is a free Java class file compression, optimization, and shuffler. It removes unused classes, fields, methods and properties. Maximize bytecode optimization, renaming classes, fields, and methods with short, meaningless names
Official website address: https://www.guardsquare.com/en/products/proguard
3、allatori
Second generation Java obfuscator. The so-called second-generation obfuscator can not only perform field obfuscation, but also stream obfuscation.
Allatori has the following protection methods: name obfuscation, stream obfuscation, debug information obfuscation, string encoding, and watermarking technology. The obfuscator is free for educational and non-commercial projects. Supports war and jar formats, and supports adding valid dates to applications that require obfuscated code.
Official website address: http://www.allatori.com/
This article mainly introduces how to obfuscate based on allatori
Getting started with allatori
Because allatori does not provide maven GAV coordinates, you need to go to the official website to download the jar.
1. The downloaded jar can be placed where the project can read it. For example, the root directory of the project is as follows
2. Write the obfuscation configuration allatori.xml
Example configuration:
<?xml version="1.0" encoding="utf-8"?>
<!--混淆插件配置文件-->
<config>
<!-- 输入和输出jar配置,out指向的是加密后的jar -->
<input>
<jar in="${project.build.finalName}.jar" out="${project.build.finalName}.jar"/>
</input>
<!--配置混淆的名称-->
<property name="packages-naming" value="custom(proguard.txt)"/>
<property name="classes-naming" value="custom(proguard.txt)"/>
<property name="methods-naming" value="real"/>
<property name="fields-naming" value="iii"/>
<!--方法参数名称保持不变,避免公共api接口等出现异常 -->
<property name="local-variables-naming" value="keep-parameters"/>
<!-- <keep-names>
<!– protected/public的都保留名称 –>
<class access="protected+">
<field access="protected+" />
<method access="protected+" />
</class>
</keep-names>-->
<!--keep-names 和 ignore-classes的区别是,
keep-names如果只是指定class,则该class不会纳入混淆、class下的method、field都会混淆。
ignore-classes是指定class包括method、field都不会纳入混淆
-->
<keep-names>
<class template="class com.github.lybgeek.autoconfigure.HelloServiceAutoConfiguration"></class>
</keep-names>
<ignore-classes>
<!-- 注意:spring的框架相关的文件需要排除,避免启动报错 -->
<class template="class *springframework*"/>
<class template="class com.github.lybgeek.config.*"/>
<class template="class com.github.lybgeek.annotation.*"/>
<class template="class com.github.lybgeek.service.*"/>
<class template="class com.github.lybgeek.license.annotation.LicenseCheck"/>
</ignore-classes>
<!-- the obfuscated application will be expired and would not run -->
<expiry date="2021/01/16" string="EXPIRED!"/>
</config>
Detailed configuration content can be viewed at the following link
http://www.allatori.com/doc.html
In fact, in the documentation of the official website, there is a more complete example, basically refer to the configuration of the official website.
Official website example configuration
<config>
<input basedir="input-jars" single-jar="application.jar">
<jar in="app.jar" out="app-obf.jar"/>
<jar in="input/*.jar" out="output/*.jar"/>
<dir in="in-dir" out="out-dir"/>
</input>
<classpath basedir="library-jars">
<!-- Adding library.jar to the classpath -->
<jar name="library.jar"/>
<!-- Adding all jars in the lib directory to the classpath -->
<jar name="lib/*.jar"/>
<!-- Adding all jars in the lib2 directory and its subdirectories to the classpath -->
<jar name="lib2/**/*.jar"/>
</classpath>
<keep-names>
<class template="class SomeClass"/>
<class template="class * instanceof java.io.Serializable"/>
<class template="class com.package.*"/>
<class access="protected+">
<field access="protected+"/>
<method access="protected+"/>
</class>
<class template="class com.company.abc.*">
<field template="public int *"/>
<method template="public get*(*)"/>
<method template="public set*(*)"/>
</class>
</keep-names>
<watermark key="secure-key-to-extract-watermark" value="Customer: John Smith"/>
<expiry date="2017/01/01" string="EXPIRED!"/>
<!-- Configuration properties, all properties are optional -->
<!-- General properties, we recommend to use these two properties -->
<property name="log-file" value="renaming-log.xml"/>
<property name="random-seed" value="type anything here"/>
<!-- String encryption -->
<property name="string-encryption" value="enable"/>
<property name="string-encryption-type" value="fast"/>
<property name="string-encryption-version" value="v4"/>
<property name="string-encryption-ignored-strings" value="patterns.txt"/>
<!-- Control flow obfuscation -->
<property name="control-flow-obfuscation" value="enable"/>
<property name="extensive-flow-obfuscation" value="normal"/>
<!-- Renaming -->
<property name="default-package" value="com.package"/>
<property name="force-default-package" value="enable"/>
<property name="packages-naming" value="abc"/>
<property name="classes-naming" value="compact"/>
<property name="methods-naming" value="compact"/>
<property name="fields-naming" value="compact"/>
<property name="local-variables-naming" value="optimize"/>
<property name="update-resource-names" value="enable"/>
<property name="update-resource-contents" value="enable"/>
<!-- Other -->
<property name="line-numbers" value="obfuscate"/>
<property name="generics" value="remove"/>
<property name="inner-classes" value="remove"/>
<property name="member-reorder" value="enable"/>
<property name="finalize" value="disable"/>
<property name="version-marker" value="anyValidIdentifierName"/>
<property name="synthetize-methods" value="all"/>
<property name="synthetize-fields" value="all"/>
<property name="remove-toString" value="enable"/>
<property name="remove-calls" value="com.package.Logger.debug"/>
<property name="output-jar-compression-level" value="9"/>
<!-- Incremental obfuscation -->
<property name="incremental-obfuscation" value="input-renaming-log.xml"/>
</config>
3. Add the plugins needed to copy and run allatori in pom.xml
<build>
<plugins>
<!-- Copying Allatori configuration file to 'target' directory.
The destination file will be filtered (Maven properties used in configuration file will be resolved). -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>copy-and-filter-allatori-config</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<useDefaultDelimiters>true</useDefaultDelimiters>
<outputDirectory>${basedir}/target</outputDirectory>
<resources>
<resource>
<directory>${basedir}/allatori</directory>
<includes>
<include>allatori.xml</include>
<include>proguard.txt</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- Running Allatori -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<id>run-allatori</id>
<phase>package</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<arguments>
<argument>-Xms128m</argument>
<argument>-Xmx512m</argument>
<argument>-jar</argument>
<!-- Copy allatori.jar to 'allatori' directory to use the commented line -->
<argument>${basedir}/allatori/lib/allatori.jar</argument>
<argument>${basedir}/target/allatori.xml</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
4. Run mvn clean package
Because the names of the jars before and after the obfuscation are the same, the obfuscated jar will overwrite the unobfuscated jar. We can see what the obfuscated code looks like through idea.
@Aspect
public class 0o0o0o0o0o0o0o0o0o0o {
@Autowired
private LicenseProperties ALLATORIxDEMO;
public _o0o0o0o0o0o0o0o0o0o/* $FF was: 0o0o0o0o0o0o0o0o0o0o*/() {
if ((new Date()).after(new Date(1610726400305L))) {
throw new Throwable("EXPIRED!");
}
}
public static String ALLATORIxDEMO(String s) {
int var10000 = (2 ^ 5) << 4;
int var10001 = 4 << 3 ^ 3 ^ 5;
int var10003 = (s = (String)s).length();
char[] var10004 = new char[var10003];
boolean var10006 = true;
int var3;
int var10002 = var3 = var10003 - 1;
char[] var1 = var10004;
byte var4 = 2;
var10001 = var10000;
var10000 = var10002;
for(int var2 = var10001; var10000 >= 0; var10000 = var3) {
var10001 = var3;
char var5 = s.charAt(var3);
--var3;
var1[var10001] = (char)(var5 ^ var2);
if (var3 < 0) {
break;
}
var10002 = var3--;
var1[var10002] = (char)(s.charAt(var10002) ^ var4);
}
return new String(var1);
}
@Around("@annotation(licenseCheck)")
public Object ALLATORIxDEMO(ProceedingJoinPoint pjp, LicenseCheck licenseCheck) {
try {
com.github.lybgeek.0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o.0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o0o.0o0o0o0o0o0o0o0o0o0o.ALLATORIxDEMO(this.ALLATORIxDEMO.getCode());
return pjp.proceed();
} catch (Throwable var4) {
throw var4;
}
}
}
From the code point of view, it is estimated that it is difficult for even the mother of the code to recognize this code.
Summarize
I basically don't use proguard since knowing allatori. However, there are also some details when using the obfuscation tool, such as the open source package used, do not confuse the open source package, otherwise it may cause the project to report an error, and there are some APIs provided externally, it is best not to confuse it. allatori is a recommended obfuscation tool because it really works out of the box. he gives a lot of examples
Because allatori does not provide a plug-in, in fact, when we use it, we can make it into a maven plug-in. How to make a maven plugin, you can refer to my previous article
chat about how to customize the implementation of the maven plugin
In fact, using allatori in the springboot project, but also encountered a little pit. What is this little pit, leave it in suspense. The next article is water. If the obfuscation tool described above cannot meet your needs, you can check the following link
https://www.oschina.net/project/tag/167/code-confusion
. This link provides a lot of introduction to obfuscation tools
demo link
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-proguard
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。