{"id":40917075,"url":"https://github.com/afjoseph/decrypticon","last_synced_at":"2026-01-22T03:16:54.196Z","repository":{"id":44862315,"uuid":"260891032","full_name":"afjoseph/decrypticon","owner":"afjoseph","description":"Java-layer Android Malware Simplifier","archived":false,"fork":false,"pushed_at":"2022-01-21T20:22:33.000Z","size":182,"stargazers_count":22,"open_issues_count":2,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-01-30T00:43:02.774Z","etag":null,"topics":["android","android-malware","deobfuscation","deobfuscator","emulator","malware","malware-analysis","malware-analyzer","malware-research","optimization","python3","reverse-engineer-apk","reverse-engineering"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/afjoseph.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-05-03T11:08:10.000Z","updated_at":"2023-11-17T11:51:47.000Z","dependencies_parsed_at":"2022-09-19T03:00:21.729Z","dependency_job_id":null,"html_url":"https://github.com/afjoseph/decrypticon","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/afjoseph/decrypticon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afjoseph%2Fdecrypticon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afjoseph%2Fdecrypticon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afjoseph%2Fdecrypticon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afjoseph%2Fdecrypticon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/afjoseph","download_url":"https://codeload.github.com/afjoseph/decrypticon/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/afjoseph%2Fdecrypticon/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28652056,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T01:17:37.254Z","status":"online","status_checked_at":"2026-01-22T02:00:07.137Z","response_time":144,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","deobfuscation","deobfuscator","emulator","malware","malware-analysis","malware-analyzer","malware-research","optimization","python3","reverse-engineer-apk","reverse-engineering"],"created_at":"2026-01-22T03:16:53.790Z","updated_at":"2026-01-22T03:16:54.188Z","avatar_url":"https://github.com/afjoseph.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Decrypticon: A Generic Android Simplifier\n=========================================\n\n- [Dependencies](#dependencies)\n- [Usage](#usage)\n    + [Offline Mode](#offline-mode)\n- [Tests](#tests)\n- [Real-life Use Case](#real-life-use-case)\n- [Special Thanks](#special-thanks)\n\n`Decrypticon` **monitors an Android app's execution** and then **annotates the disassembled codebase with the results of the marked functions' execution**. This allows the analyst to go through the annotated codebase and understand:\n\n        * Input:\n            * Android APK\n            * A bunch of functions to mark\n        * Processing:\n            * Run the app and observe the marked functions\n        * Output:\n            * A disassembled codebase that annotates the arguments and returns values of each marked function\n\nDependencies\n------------\n* `ANDROID_HOME` must be in PATH, along with any verison of `build_tools`. Something like this should exist in your `.profile`:\n\n    ```\n    export ANDROID_HOME=$HOME/Library/Android/sdk\n    export PATH=\"$ANDROID_HOME/platform-tools:$PATH\"\n    export PATH=\"$ANDROID_HOME/build-tools/27.0.3:$PATH\"\n    ```\n\n* `jarsigner`\n* `apktool` 2.4.+ (if you're running OSX: `brew install apktool` is good enough)\n* `Python3` 3.7.+\n* `virtualenv` 20.+\n\nUsage\n-----\n* Make a `hooks` file that consists of the functions you want to monitor. [An example exists here](https://github.com/afjoseph/decrypticon/blob/c1173ed/example/test_project/hooks#L1). You can find signture using either `apktool` or `radare2`:\n\n    ```\n    Lcom/afjoseph/test/Cryptor;-\u003eget(III)Ljava/lang/String;\n    Lcom/afjoseph/test/Cryptor;-\u003esecond(III)Ljava/lang/String;\n    Lcom/afjoseph/test/Cryptor;-\u003ethird(III)Ljava/lang/String;\n    ```\n\n* Run an emulator. I recommend using my own `scripts/run_avd.sh`\n* Run and install frida-server on the test device. I recommend using my own `scripts/install_frida_server.rb`\n* A sample workflow should look like this\n\n\n    ```\n    $ cat hooks\n    Lcom/afjoseph/test/Cryptor;-\u003eget(III)Ljava/lang/String;\n    Lcom/afjoseph/test/Cryptor;-\u003esecond(III)Ljava/lang/String;\n    Lcom/afjoseph/test/Cryptor;-\u003ethird(III)Ljava/lang/String;\n\n    # Run an emulator\n    $ ./scripts/run_avd.sh --android_api_level=28\n\n    # Install Frida server on it\n    $ ./scripts/install_frida_server\n\n    # Initialize virtualenv\n    $ virtualenv -p python3 venv\n    $ venv/bin/pip3 install -r requirements.txt\n\n    # Run Decrypticon\n    venv/bin/python3 decrypticon.py \\\n      --mode online \\\n      --apk example/test_project/love.apk \\\n      --hooks hooks \\\n      --out example/test_project/annotated \\\n      --focus_pkg com/afjoseph/test\n    ```\n\nThe above flow is exactly how the [test script](https://github.com/afjoseph/decrypticon/blob/c1173ed/#L1) looks like.\n\n#### Offline Mode\nSometimes, you'd want to save the results of the marked functions (which the project identifies as _recorded invocations_). The `--pickle_to` flag can _pickle_ (Python term for \"serialize\") all recorded invocations in a file, which you can replay at any time later.\n\nLet's assume you ran `Decrypticon` using `--mode=online` before and used `--pickle_to` flag to save all recorded invocations in `my_tender_pickles` file. You can reply those invocations to annotate the codebase again using the following:\n\n    venv/bin/python3 decrypticon.py \\\n      --mode offline \\\n      --apk example/test_project/love.apk \\\n      --out example/test_project/annotated \\\n      --focus_pkg com/afjoseph/test --pickle_from my_tender_pickles\n\nThis would take `love.apk`, annotate it using the recorded invocations in `my_tender_pickles`, and then write the annotated codebase to `example/test_project/annotated`.\n\nTests\n-----\nRun `./scripts/run_test_suite.rb`. This is also a good location to see how the project is supposed to run.\n\n\nReal-life Use Case\n------------------\nTake the [following Java code](https://github.com/afjoseph/decrypticon/blob/c1173ed/example/test_project/app/src/main/java/com/afjoseph/test/MainActivity.java#L25):\n\n    Map\u003cString, String\u003e params = new HashMap\u003c\u003e();\n    String address_1 = Cryptor.get(30, 20, 100);\n    String enc_address_1 = Encryptor.Encrypt(address_1);\n    params.put(\"address_1\", enc_address_1);\n\n    String country_1 = Cryptor.get(100, 200, 300);\n    String enc_country_1 = Encryptor.Encrypt(address_1);\n    params.put(\"country_1\", enc_country_1);\n\n    String token_1 = Cryptor.get(99, 66, 99);\n    String enc_token_1 = Encryptor.Encrypt(token_1);\n    params.put(\"token_1\", enc_token_1);\n\n    String address_2 = Cryptor.get(55, 22, 32);\n    String enc_address_2 = Encryptor.Encrypt(address_2);\n    params.put(\"address_2\", enc_address_2);\n\n    String country_2 = Cryptor.get(92, 22, 55);\n    String enc_country_2 = Encryptor.Encrypt(address_2);\n    params.put(\"country_2\", enc_country_2);\n\n    String token_2 = Cryptor.get(88, 72, 86);\n    String enc_token_2 = Encryptor.Encrypt(token_2);\n    params.put(\"token_2\", enc_token_2);\n\nAn easier way to write this would be:\n\n    params.put(\"address_1\", \"neverwhere\");\n\nWhere `neverwhere` would be the value of the address, but this makes analysis pretty easy since `neverwhere` exists verbatim in the source code.\n\nA common obfuscation scheme is to rely on layers of abstraction to \"hide\" the value of `neverwhere`. `Cryptor.get()` could look like this (this is a hypothetical function. The code is not compilable):\n\n    public final class Cryptor {\n      private static char[] arr = new char[]{'\\ucad9', '\\ue9a1', '\\u1a1c', '\\u00a9', '\\u591c', '\\u9e7e', '\\u751c', '\\u9cc9', '\\u1191', '\\ua7e5', '\\ucd9e', '\\ueca5', '\\u1119', '\\ucae5', '\\u591e', '\\u9a5c', '\\u5cc0', '\\u791a', '\\u1ea1', '\\u55d5', '\\uccca' '\\u70d1', '\\u9ec1', '\\ucc97', '\\ua5ac', '\\uc1ae', '\\ue191', '\\u177a', '\\ucd1c', '\\u5c51', '\\u99ce', '\\ueea9', '\\u95d1', '\\ucca9', '\\u5199', '\\uc711', '\\u9daa', '\\uac9e', '\\uc9c7', '\\u5e50', '\\uc571', 'e', '\\ue915', '\\u51c1', '\\uc7e5', '\u0026', '\\uaeee', '\\uc0e0', '\\u5e59', '\\u7c99', '\\u05ec', '\\u510c', '\\ucaac', '\\ud9cc', '\\ueaaa', '\\u101a', '\\ua75c', '\\u9d05'};\n      privage static int field_99 = 0;\n      privage static int field_91 = 2;\n      privage static int field_92 = 4;\n\n      private static String get(int var0, int var1, int var2) {\n        while(var5 \u003c var8) {\n          var10000 = field_91 + 1;\n          field_92 = var10000 % 128;\n          if (var10000 % 2 == 0) {\n          }\n\n          var4[var5] = (char)((int)((long)arr[var9 + var5] ^ (long)var5 * field_90 ^ (long)var7));\n          ++var5;\n        }\n\n        int var10000 = 2 % 2;\n        char var7 = var0;\n        int var8 = var1;\n        int var9 = var2;\n        char[] var4 = new char[var1];\n        int var5 = 0;\n        var10000 = field_92 + 99;\n        field_91 = var10000 % 128;\n        switch(var10000 % 2 != 0 ? 66 : 35) {\n          case 35:\n          default:\n            var10000 = 2 % 2;\n            break;\n          case 66:\n            var10000 = 5 * 3;\n        }\n\n        String var12 = new String(var4);\n        int var10001 = field_91 + 49;\n        field_92 = var10001 % 128;\n        switch(var10001 % 2 == 0 ? 28 : 47) {\n          case 28:\n          default:\n            try {\n              var10001 = ((Object[])null).length;\n              return var12;\n            } catch (Throwable var11) {\n              throw var11;\n            }\n          case 47:\n            return var12;\n        }\n      }\n    }\n\nIn that case, there is no easy way of understanding what is the output of `Cryptor.get()`. An easy way of handling this would be to execute `Cryptor.get()` and monitor its value. That is what `Decrypticon` does, plus annotate the disassembled codebase with the args and return value. The _annotated_ smali code will have a bunch of `\u003e\u003e\u003e DECRYPTICON` directives on the marked functions that reveal the execution flow:\n\nAfter executing `Decrypticon`\n\n    \u003e\u003e\u003e DECRYPTICON:: func(30, 20, 100) = neverwhere\n        invoke-static {v1, v2, v3}, Lcom/afjoseph/test/Cryptor;-\u003eget(III)Ljava/lang/String;\n\n    ...\n\n    \u003e\u003e\u003e DECRYPTICON:: func(100, 200, 300) = usa\n        invoke-static {v3, v4, v5}, Lcom/afjoseph/test/Cryptor;-\u003eget(III)Ljava/lang/String;\n\n    ...\n\n    \u003e\u003e\u003e DECRYPTICON:: func(99, 66, 99) = 12341234\n        invoke-static {v6, v5, v6}, Lcom/afjoseph/test/Cryptor;-\u003eget(III)Ljava/lang/String;\n\n    ...\n\n    \u003e\u003e\u003e DECRYPTICON:: func(55, 22, 32) = baldurs_gate\n        invoke-static {v9, v8, v7}, Lcom/afjoseph/test/Cryptor;-\u003eget(III)Ljava/lang/String;\n\n    ...\n\n    \u003e\u003e\u003e DECRYPTICON:: func(92, 22, 55) = temeria\n        invoke-static {v11, v8, v9}, Lcom/afjoseph/test/Cryptor;-\u003eget(III)Ljava/lang/String;\n\n    ...\n\n    \u003e\u003e\u003e DECRYPTICON:: func(88, 72, 86) = abcdabcd\n        invoke-static {v11, v12, v13}, Lcom/afjoseph/test/Cryptor;-\u003eget(III)Ljava/lang/String;\n\nSpecial Thanks\n--------------\nI'd like to thank the following projects and their contributors. They were a **major** part of this project:\n* [**Frida**](https://github.com/frida/frida/): Decrypticon relies on it.\n* [**Radare2**](https://github.com/radareorg/radare2/): 99% of the analysis done here was made using `r2`\n* [**dex-oracle**](https://github.com/CalebFenton/dex-oracle) and [**Simplify**](https://github.com/CalebFenton/simplify): Mr. Fenton's work was the reason I made this project: I encountered some obfuscated malware and ran it through both with good results. There was still quite a bit of manual work I needed to do, though. After checking both codebases, the problem I found was that `dex-oracle` was too simplistic since it **relied on heuristics and specific argument positioning**, which the malware didn't follow. `simplify` went **into an endless loop** trying to execute the marked instructions. After checking the GH issues on both, I realized that they were made with different ideas in mind. I thought that a solution in the middle must exist, to which `decrypticon` was my humble answer.\n* My company, [Adjust](https://www.adjust.com/), for giving me the time and space to work on such a project.\n* To all the future contributors who will help me make `decrypticon` better. Please reach out to me through Twitter (`@MalwareCheese`) or in the _Issues_ section in this repo.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fafjoseph%2Fdecrypticon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fafjoseph%2Fdecrypticon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fafjoseph%2Fdecrypticon/lists"}