{"id":13387533,"url":"https://github.com/calebfenton/simplify","last_synced_at":"2025-05-14T20:07:34.944Z","repository":{"id":13273145,"uuid":"15958676","full_name":"CalebFenton/simplify","owner":"CalebFenton","description":"Android virtual machine and deobfuscator","archived":false,"fork":false,"pushed_at":"2022-04-30T12:20:33.000Z","size":103553,"stargazers_count":4527,"open_issues_count":32,"forks_count":448,"subscribers_count":131,"default_branch":"master","last_synced_at":"2025-04-13T14:07:03.176Z","etag":null,"topics":["android","android-malware","dalvik","deobfuscation","deobfuscator","emulator","java","malware","malware-analysis","malware-analyzer","malware-research","optimization","reverse-engineer-apk","reverse-engineering","virtual-machine"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CalebFenton.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.COMMERCIAL","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-01-16T05:14:02.000Z","updated_at":"2025-04-12T09:31:55.000Z","dependencies_parsed_at":"2022-08-07T07:01:12.496Z","dependency_job_id":null,"html_url":"https://github.com/CalebFenton/simplify","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CalebFenton%2Fsimplify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CalebFenton%2Fsimplify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CalebFenton%2Fsimplify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CalebFenton%2Fsimplify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CalebFenton","download_url":"https://codeload.github.com/CalebFenton/simplify/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248724639,"owners_count":21151561,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-malware","dalvik","deobfuscation","deobfuscator","emulator","java","malware","malware-analysis","malware-analyzer","malware-research","optimization","reverse-engineer-apk","reverse-engineering","virtual-machine"],"created_at":"2024-07-30T12:01:22.109Z","updated_at":"2025-04-13T14:07:09.095Z","avatar_url":"https://github.com/CalebFenton.png","language":"Java","readme":"# Simplify\n\n[![Build Status](https://travis-ci.org/CalebFenton/simplify.svg?branch=master)](https://travis-ci.org/CalebFenton/simplify) [![Coverage Status](https://img.shields.io/coveralls/CalebFenton/simplify.svg)](https://coveralls.io/r/CalebFenton/simplify) [![Coverity Scan Build Status](https://img.shields.io/coverity/scan/7022.svg)](https://scan.coverity.com/projects/calebfenton-simplify)\n\n## Generic Android Deobfuscator\n\nSimplify virtually executes an app to understand its behavior and then tries to optimize the code so that it behaves identically but is easier for a human to understand. Each optimization type is simple and generic, so it doesn't matter what the specific type of obfuscation is used.\n\n### Before and After\n\nThe code on the left is a decompilation of an obfuscated app, and the code on the right has been deobfuscated.\n\u003csection\u003e\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://cloud.githubusercontent.com/assets/1356658/5331911/1e790c86-7df4-11e4-91e7-aba1d2c63b98.png\" alt=\"Lots of method calls, no clear meaning\" height=\"380px\" align=\"center\" /\u003e\n\u003cimg src=\"https://cloud.githubusercontent.com/assets/1356658/5331912/1ecc6d7c-7df4-11e4-9572-bc3d41303842.png\" alt=\"Wow, such literal, much meaning\" height=\"380px\" align=\"center\" /\u003e\n\u003c/p\u003e\n\u003c/section\u003e\n\n## Overview\n\nThere are three parts to the project: smalivm, simplify, and the demo app.\n\n1. **smalivm**: Provides a virtual machine sandbox for executing Dalvik methods. After executing a method, it returns a graph containing all possible register and class values for every execution path. It works even if some values are unknown, such as file and network I/O. For example, any `if` or `switch` conditional with an unknown value results in both branches being taken.\n2. **simplify**: Analyzes the execution graphs from **smalivm** and applies optimizations such as constant propagation, dead code removal, unreflection, and some peephole optimizations. These are fairly simple, but when applied together repeatedly, they'll decrypt strings, remove reflection, and greatly simplify code. It does *not* rename methods and classes.\n3. **demoapp**: Contains simple, heavily commented examples for using **smalivm** in your own project. If you're building something that needs to execute Dalvik code, check it out.\n\n## Usage\n\n```\nusage: java -jar simplify.jar \u003cinput\u003e [options]\ndeobfuscates a dalvik executable\n -et,--exclude-types \u003cpattern\u003e   Exclude classes and methods which include REGEX, eg: \"com/android\", applied after include-types\n -h,--help                       Display this message\n -ie,--ignore-errors             Ignore errors while executing and optimizing methods. This may lead to unexpected behavior.\n    --include-support            Attempt to execute and optimize classes in Android support library packages, default: false\n -it,--include-types \u003cpattern\u003e   Limit execution to classes and methods which include REGEX, eg: \";-\u003etargetMethod\\(\"\n    --max-address-visits \u003cN\u003e     Give up executing a method after visiting the same address N times, limits loops, default: 10000\n    --max-call-depth \u003cN\u003e         Do not call methods after reaching a call depth of N, limits recursion and long method chains, default: 50\n    --max-execution-time \u003cN\u003e     Give up executing a method after N seconds, default: 300\n    --max-method-visits \u003cN\u003e      Give up executing a method after executing N instructions in that method, default: 1000000\n    --max-passes \u003cN\u003e             Do not run optimizers on a method more than N times, default: 100\n -o,--output \u003cfile\u003e              Output simplified input to FILE\n    --output-api-level \u003cLEVEL\u003e   Set output DEX API compatibility to LEVEL, default: 15\n -q,--quiet                      Be quiet\n    --remove-weak                Remove code even if there are weak side effects, default: true\n -v,--verbose \u003cLEVEL\u003e            Set verbosity to LEVEL, default: 0\n```\n\n## Building\n\nBuilding requires the [Java Development Kit 8 (JDK)](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html) to be installed.\n\nBecause this project contains submodules for Android frameworks, either clone with `--recursive`:\n\n```bash\ngit clone --recursive https://github.com/CalebFenton/simplify.git\n```\n\nOr update submodules at any time with:\n\n```bash\ngit submodule update --init --recursive\n```\n\nThen, to build a single jar which contains all dependencies:\n\n```bash\n./gradlew fatjar\n```\n\nThe Simplify jar will be in `simplify/build/libs/`. You can test it's working by simplifying the provided [obfuscated example app](/simplify/ObfuscatedApp). Here's how you'd run it (you may need to change `simplify.jar`):\n\n```bash\njava -jar simplify/build/libs/simplify.jar -it \"org/cf/obfuscated\" -et \"MainActivity\" simplify/obfuscated-app.apk\n```\n\nTo understand what's getting deobfuscated, check out [Obfuscated App's README](/simplify/ObfuscatedApp/README.md).\n\n## Troubleshooting\n\nIf Simplify fails, try these recommendations, in order:\n\n1. Only target a few methods or classes by using `-it` option.\n2. If failure is because of maximum visits exceeded, try using higher `--max-address-visits`, `--max-call-depth`, and `--max-method-visits`.\n3. Try with `-v` or `-v 2` and report the issue with the logs and a hash of the DEX or APK.\n4. Try again, but do not break eye contact. Simplify can sense fear.\n\nIf building on Windows, and building fails with an error similar to:\n\n\u003e Could not find tools.jar. Please check that C:\\Program Files\\Java\\jre1.8.0_151 contains a valid JDK installation.\n\nThis means Gradle is unable to find a proper JDK path. Make sure the JDK is installed, set the `JAVA_HOME` environment variable to your JDK path, and make sure to close and re-open the command prompt you use to build.\n\n## Contributing\n\nDon't be shy. I think virtual execution and deobfuscation are fascinating problems. Anyone who's interested is automatically cool and contributions are welcome, even if it's just to fix a typo. Feel free to ask questions in the issues and submit pull requests.\n\n### Reporting Issues\n\nPlease include a link to the APK or DEX and the full command you're using. This makes it much easier to reproduce (and thus _fix_) your issue.\n\nIf you can't share the sample, *please* include the file hash (SHA1, SHA256, etc).\n\n## Optimization Strategies\n\n### Constant Propagation\n\nIf an op places a value of a type which can be turned into a constant such as a string, number, or boolean, this optimization will replace that op with the constant. For example:\n\n```smali\nconst-string v0, \"VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4=\"\ninvoke-static {v0}, Lmy/string/Decryptor;-\u003edecrypt(Ljava/lang/String;)Ljava/lang/String;\n# Decrypts to: \"Tell me of your homeworld, Usul.\"\nmove-result v0\n```\n\nIn this example, an encrypted string is decrypted and placed into `v0`. Since strings are \"constantizable\", the `move-result v0` can be replaced with a `const-string`:\n\n```smali\nconst-string v0, \"VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4=\"\ninvoke-static {v0}, Lmy/string/Decryptor;-\u003edecrypt(Ljava/lang/String;)Ljava/lang/String;\nconst-string v0, \"Tell me of your homeworld, Usul.\"\n```\n\n### Dead Code Removal\n\nCode is dead if removing it cannot possibly alter the behavior of the app. The most obvious case is if the code is unreachable, e.g. `if (false) { // dead }`). If code is reachable, it may be considered dead if it doesn't affect any state outside of the method, i.e. it has no _side effect_. For example, code may not affect the return value for the method, alter any class variables, or perform any IO. This is a difficult to determine in static analysis. Luckily, smalivm doesn't have to be clever. It just stupidly executes everything it can and assumes there are side effects if it can't be sure. Consider the example from Constant Propagation:\n\n```smali\nconst-string v0, \"VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4=\"\ninvoke-static {v0}, Lmy/string/Decryptor;-\u003edecrypt(Ljava/lang/String;)Ljava/lang/String;\nconst-string v0, \"Tell me of your homeworld, Usul.\"\n```\n\nIn this code, the `invoke-static` no longer affects the return value of the method and let's assume it doesn't do anything weird like write bytes to the file system or a network socket so it has no side effects. It can simply be removed.\n\n```smali\nconst-string v0, \"VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4=\"\nconst-string v0, \"Tell me of your homeworld, Usul.\"\n```\n\nFinally, the first `const-string` assigns a value to a register, but that value is never used, i.e. the assignment is dead. It can also be removed.\n\n```smali\nconst-string v0, \"Tell me of your homeworld, Usul.\"\n```\n\nHuzzah!\n\n### Unreflection\n\nOne major challenge with static analysis of Java is reflection. It's just not possible to know the arguments are for reflection methods without doing careful data flow analysis. There are smart, clever ways of doing this, but smalivm does it by just executing the code. When it finds a reflected method invocation such as:\n\n```smali\ninvoke-virtual {v0, v1, v2}, Ljava/lang/reflect/Method;-\u003einvoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;\n```\n\nIt can know the values of `v0`, `v1`, and `v2`. If it's sure what the values are, it can replace the call to `Method.invoke()` with an actual non-reflected method invocation. The same applies for reflected field and class lookups.\n\n### Peephole\n\nFor everything that doesn't fit cleanly into a particular category, there's peephole optimizations. This includes removing useless `check-cast` ops, replacing `Ljava/lang/String;-\u003e\u003cinit\u003e` calls with `const-string`, and so on.\n\n## Deobfuscation Example\n\n### Before Optimization\n\n```smali\n.method public static test1()I\n    .locals 2\n\n    new-instance v0, Ljava/lang/Integer;\n    const/4 v1, 0x1\n    invoke-direct {v0, v1}, Ljava/lang/Integer;-\u003e\u003cinit\u003e(I)V\n\n    invoke-virtual {v0}, Ljava/lang/Integer;-\u003eintValue()I\n    move-result v0\n\n    return v0\n.end method\n```\n\nAll this does is `v0 = 1`.\n\n### After Constant Propagation\n\n```smali\n.method public static test1()I\n    .locals 2\n\n    new-instance v0, Ljava/lang/Integer;\n    const/4 v1, 0x1\n    invoke-direct {v0, v1}, Ljava/lang/Integer;-\u003e\u003cinit\u003e(I)V\n\n    invoke-virtual {v0}, Ljava/lang/Integer;-\u003eintValue()I\n    const/4 v0, 0x1\n\n    return v0\n.end method\n```\n\nThe `move-result v0` is replaced with `const/4 v0, 0x1`. This is because there is only one possible return value for `intValue()I` and the return type can be made a constant. The arguments `v0` and `v1` are unambiguous and do not change. That is to say, there's a consensus of values for every possible execution path at `intValue()I`. Other types of values that can be turned into constants:\n\n* numbers - `const/4`, `const/16`, etc.\n* strings - `const-string`\n* classes - `const-class`\n\n### After Dead Code Removal\n\n```smali\n.method public static test1()I\n    .locals 2\n\n    const/4 v0, 0x1\n\n    return v0\n.end method\n```\n\nBecause the code above `const/4 v0, 0x1` does not affect state outside of the method (no side-effects), it can be removed without changing behavior. If there was a method call that wrote something to the file system or network, it couldn't be removed because it affects state outside the method. Or if `test()I` took a mutable argument, such as a `LinkedList`, any instructions that accessed it couldn't be considered dead.\n\nOther examples of dead code:\n\n* unreferenced assignments - assigning registers and not using them\n* unreached / unreachable instructions - `if (false) { dead_code(); }`\n\n# License\n\nThis tool is available under a dual license: a commercial one suitable for closed source projects and a GPL license that can be used in open source software.\n\nDepending on your needs, you must choose one of them and follow its policies. A detail of the policies and agreements for each license type are available in the [LICENSE.COMMERCIAL](LICENSE.COMMERCIAL) and [LICENSE.GPL](LICENSE.GPL) files.\n\n# Further Reading\n\n* [Dalvik Virtual Execution with SmaliVM](http://calebfenton.github.io/2016/04/30/dalvik-virtual-execution-with-smalivm/)\n* [Guillot, Yoann, and Alexandre Gazet. \"Automatic Binary Deobfuscation.\" Journal in Computer Virology 6.3 (2010): 261-76](http://metasm.cr0.org/docs/sstic09-metasm-jcv.pdf)\n* [Unicorn - The ultimate CPU emulator](http://www.unicorn-engine.org/)\n* [Babak Yadegari, Saumya Debray. \"Symbolic Execution of Obfuscated Code\"](https://www.cs.arizona.edu/people/debray/Publications/ccs2015-symbolic.pdf)\n* Success stories:\n    * [Android Dynamic Class Loading with \"AES/CFB/NoPadding\" encryption. Take a peek before \u0026 after. Tool used: #simplify. #Android #obfuscation #classencryption #dex](https://twitter.com/enovella_/status/946899042973437952)\n    * [Decrypting Malware String Encryption](https://twitter.com/caleb_fenton/status/850400605340262400)\n\n","funding_links":[],"categories":["\u003ca id=\"2110ded2aa5637fa933cc674bc33bf21\"\u003e\u003c/a\u003e工具"],"sub_categories":["\u003ca id=\"1d83ca6d8b02950be10ac8e4b8a2d976\"\u003e\u003c/a\u003eObfuscate\u0026\u0026混淆"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalebfenton%2Fsimplify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcalebfenton%2Fsimplify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalebfenton%2Fsimplify/lists"}