preface
What is code obfuscation
Code confusion refers to 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 and method names to meaningless strings. The shorter the new name generated, the smaller the bytecode. In bytecode with confused names, package, class, field and method names have been renamed and can never be restored. Unfortunately, the control process is still clearly visible. Therefore, stream confusion is required
2. Stream confusion
It is used for keywords such as if, switch, while and for to slightly modify the bytecode and fuzzy control the flow without changing the behavior of the code at run time. In general, logical constructs such as selection and loop will be changed, so they no longer have direct equivalent Java source code. Stream obfuscated bytecode usually forces the decompiler to insert a series of tags and illegal goto statements into the source code they generate. The source code is sometimes blurred by decompilation errors
other
Exception confusion, string encryption confusion, reference confusion, etc
Role of code obfuscation
Not only does it protect the code, it also reduces the size of the compiled program. Due to the shortening of variable and function names and the loss of some information, the volume of compiled jar files can be reduced by about 25%, which is of certain significance to the current expensive wireless network transmission
Possible problems caused by code confusion
Confused code is difficult to understand, so debugging and debugging become difficult. Developers often need to keep the original unambiguous code for debugging. For languages that support reflection, code obfuscation may conflict with reflection. Code obfuscation does not really stop reverse engineering, but only makes it more difficult. Therefore, for occasions with high security requirements, only using code obfuscation can not ensure the security of source code.
Common confusion tools
1,yGuard
yGuard is a free Java obfuscator (non open source), which has java and NET. yGuard is completely free, runs based on Ant tasks, and provides highly configurable confusion rules.
Official website address: https://www.yworks.com/products/yguard
2,proguard
proguard is a free Java class file compression, optimization and mixer. It deletes useless classes, fields, methods and properties. Maximize bytecode optimization by 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 confuse fields, but also realize stream obfuscation.
Allatori has the following protection methods: naming confusion, stream confusion, debugging information confusion, string coding, and watermarking technology. This obfuscator is free for educational and non-commercial projects. Support war and jar formats, and add effective dates to applications that need to confuse code.
Official website address: http://www.allatori.com/
This paper mainly introduces how to confuse based on allatori
Getting started with allatori
Because allatori does not provide maven GAV coordinates, you need to download jar s from the official website.
1. The downloaded jar s can be placed where the project can be read. For example, the project root directory is shown in the figure below
2. Write obfuscated configuration allatori xml
Example configuration:
<?xml version="1.0" encoding="utf-8"?> <!--Obfuscate plug-in configuration file--> <config> <!-- Input and output jar to configure, out It points to the encrypted jar --> <input> <jar in="${project.build.finalName}.jar" out="${project.build.finalName}.jar"/> </input> <!--Configuration obfuscated name--> <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"/> <!--The method parameter name remains unchanged to avoid public api The interface is abnormal --> <property name="local-variables-naming" value="keep-parameters"/> <!-- <keep-names> <!– protected/public All reserved names –> <class access="protected+"> <field access="protected+" /> <method access="protected+" /> </class> </keep-names>--> <!--keep-names and ignore-classes The difference is, keep-names If only specified class,Then class No confusion class Lower method,field Will be confused. ignore-classes Is specified class include method,field Will not include confusion --> <keep-names> <class template="class com.github.lybgeek.autoconfigure.HelloServiceAutoConfiguration"></class> </keep-names> <ignore-classes> <!-- be careful: spring Files related to the framework need to be excluded to avoid error reporting during startup --> <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>
See the following link for detailed configuration
http://www.allatori.com/doc.html
In fact, there is a more complete example posted in the documents on the official website. Basically, you can refer to the configuration of the official website.
Sample configuration of official website
<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,pom.xml adds the plug-ins needed to copy and run allatori
<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 jar names before and after the confusion are the same, the confused jars will overwrite the non confused jars. We can see what the confused code looks like through the 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 even the mother of the code can hardly recognize the code
summary
Since I know allatori, I basically don't use proguard. However, there are also some fine nodes in the use of confusion tools. For example, do not confuse the open source packages used, otherwise it may lead to project errors. It is better not to confuse some externally provided API s. Allatori is a recommended obfuscation tool because it's really out of the box. He provided many examples
Because allatori does not provide plug-ins, in fact, when we use it, we can make it into a maven plug-in. How to make a maven plug-in can refer to my previous article
Talk about how to customize the implementation of maven plug-in
In fact, using allatori in the spring boot project also encountered a small pit. What is this pit? Leave a suspense. The next article is water. If the confusion tool described above cannot meet the requirements, you can see the following link
https://www.oschina.net/project/tag/167/code-confusion
. This link provides an introduction to many confusing tools
demo link
https://github.com/lyb-geek/springboot-learning/tree/master/springboot-proguard