├── .github ├── FUNDING.yml └── workflows │ ├── deploy.yml │ └── pull.yml ├── .gitignore ├── LICENSE ├── README.md ├── algorithms ├── __init__.py ├── add1501_shl5.py ├── add_65599.py ├── add_hiword_add_lowword.py ├── add_rol5_hash_again.py ├── add_ror13.py ├── add_ror13_hash_again.py ├── add_ror4.py ├── adler32_666.py ├── babbleloader.py ├── babbleloader_0125.py ├── blister2.py ├── brc4_1_4_5.py ├── brc4_joaat.py ├── carbanak.py ├── ch_add_rol8.py ├── conti.py ├── conti_5b2d.py ├── conti_b801fcda.py ├── conti_e9ff0077.py ├── conti_mm3.py ├── crc32.py ├── crc32_bzip2.py ├── crc32_mpeg_2.py ├── crc64_ecma_182.py ├── cryptbot_ror13_add_10.py ├── d0nut.py ├── danabot.py ├── deedrat.py ├── deedrat_export_name.py ├── djb2_lowercase.py ├── djb2_nokoyawa.py ├── djb2_uppercase.py ├── djb2_vohuk_ransomware_dec_2022.py ├── dualacc_modfff1.py ├── emotet.py ├── emotet_mul_65599_xor_19ad760.py ├── fnv1.py ├── fnv1_64.py ├── fnv1_xor67f.py ├── fnv1a.py ├── fnv1a_64.py ├── guloader_3C389ABC.py ├── lockbit3_C8B32494_s0.py ├── lockbit3_C8B32494_string.py ├── lockbit4_0225.py ├── lokibot.py ├── lumma_fnv1a.py ├── mamon_hash.py ├── metasploit.py ├── mul21_add.py ├── mul21_add_seed_8952.py ├── mul7_add.py ├── mul83_add.py ├── mult21_add.py ├── mult21_add_170f.py ├── mult3_add_init_9C.py ├── murmur2_lummas_v3.py ├── mythic_unknown.py ├── or20_xor_rol19.py ├── or21_xor_rol11.py ├── or23_xor_rol17.py ├── paradise_murmurhash3.py ├── permutations_82f63b78.py ├── permutations_e8677835.py ├── revil_010F.py ├── rol3_xor.py ├── rol3_xor_eax.py ├── rol5_add.py ├── rol5_xor.py ├── rol7_add.py ├── rol7_add_xor2.py ├── rol7_xor.py ├── rol8_xor_b0d4d06.py ├── rol9_add.py ├── rol9_xor.py ├── ror11_add.py ├── ror13_add.py ├── ror13_add_negative_seed.py ├── ror13_add_sub1.py ├── ror13_add_sub20.py ├── ror7_add.py ├── ror8_add_xor_ab832e83.py ├── ror9_add.py ├── sdbm_65599_x64.py ├── shl1_add.py ├── shl7_shr19_xor.py ├── shl7_sub.py ├── shr1_shl7_2326.py ├── shr2_shl5_xor.py ├── shr2_shl5_xor_init_c4d5a97a_stealbit.py ├── smokeloader_rol8_xor.py ├── tonepipeshell.py ├── tonepipeshell_alt.py ├── tonepipeshell_feb_2025.py ├── xor_rol9.py ├── xor_shr8.py └── zloader_bot.py ├── hashdb.py └── tests └── test_algorithms.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: oalabs 2 | 3 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: AWS Lambda Deploy 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | workflow_dispatch: 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | 16 | - name: Setup distribution package 17 | run: | 18 | echo "Building distribution package" 19 | mkdir ./dist 20 | mkdir ./dist/python 21 | mkdir ./dist/python/algorithms 22 | cp *.py ./dist/python 23 | cp -r ./algorithms/* ./dist/python/algorithms/ 24 | cd ./dist 25 | zip -r hashdb.zip ./python 26 | 27 | - name: Set up Python 3.9 28 | uses: actions/setup-python@v2 29 | with: 30 | python-version: 3.9 31 | 32 | - name: Install AWS CLI and tools 33 | run: | 34 | python -m pip install --upgrade pip 35 | pip install awscli 36 | sudo apt-get update 37 | sudo apt-get install -y jq 38 | 39 | - name: Publish to AWS Lambda Layer 40 | env: 41 | AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} 42 | AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 43 | LAMBDA_LAYER_ARN: ${{ secrets.LAMBDA_LAYER_ARN }} 44 | AWS_DEFAULT_REGION: ${{ secrets.AWS_REGION }} 45 | HASHDB_WORKER_LAMBDA_ARN: ${{ secrets.HASHDB_WORKER_LAMBDA_ARN }} 46 | HASHDB_API_LAMBDA_ARN: ${{ secrets.HASHDB_API_LAMBDA_ARN }} 47 | run: | 48 | echo "Publishing as a layer..." 49 | RESULT_DATA=$(aws lambda publish-layer-version --layer-name "$LAMBDA_LAYER_ARN" --zip-file fileb://dist/hashdb.zip) 50 | LAYER_VERSION=$(jq '.Version' <<< "$RESULT_DATA") 51 | echo "Updating hashdb worker to use layer version $LAYER_VERSION..." 52 | UPDATE_RESULT_DATA1=$(aws lambda update-function-configuration --function-name "$HASHDB_WORKER_LAMBDA_ARN" --layers "$LAMBDA_LAYER_ARN:$LAYER_VERSION") 53 | UPDATE_RESULT_DATA2=$(aws lambda update-function-configuration --function-name "$HASHDB_API_LAMBDA_ARN" --layers "$LAMBDA_LAYER_ARN:$LAYER_VERSION") 54 | echo '::set-output name=SELECTED_COLOR::green' 55 | echo "Done" 56 | 57 | 58 | -------------------------------------------------------------------------------- /.github/workflows/pull.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Pull request filtering algorithms 5 | 6 | on: 7 | pull_request: 8 | branches: [ main ] 9 | 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: Set up Python 3.9 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: 3.9 23 | - name: Install dependencies 24 | run: | 25 | python -m pip install --upgrade pip 26 | pip install flake8 pytest 27 | - name: Lint with flake8 28 | run: | 29 | # stop the build if there are Python syntax errors or undefined names 30 | flake8 ./algorithms --count --select=E9,F63,F7,F82 --show-source --statistics 31 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 32 | flake8 ./algorithms --count --exit-zero --max-complexity=15 --max-line-length=127 --statistics --show-source 33 | - name: Test with pytest 34 | run: | 35 | python -m pytest 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Apple crap 2 | .DS_Store 3 | .AppleDouble 4 | .LSOverride 5 | 6 | # Byte-compiled / optimized / DLL files 7 | __pycache__/ 8 | *.py[cod] 9 | *$py.class 10 | 11 | # C extensions 12 | *.so 13 | 14 | # Distribution / packaging 15 | .Python 16 | build/ 17 | develop-eggs/ 18 | dist/ 19 | downloads/ 20 | eggs/ 21 | .eggs/ 22 | lib/ 23 | lib64/ 24 | parts/ 25 | sdist/ 26 | var/ 27 | wheels/ 28 | pip-wheel-metadata/ 29 | share/python-wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | MANIFEST 34 | 35 | # PyInstaller 36 | # Usually these files are written by a python script from a template 37 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 38 | *.manifest 39 | *.spec 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | htmlcov/ 47 | .tox/ 48 | .nox/ 49 | .coverage 50 | .coverage.* 51 | .cache 52 | nosetests.xml 53 | coverage.xml 54 | *.cover 55 | *.py,cover 56 | .hypothesis/ 57 | .pytest_cache/ 58 | 59 | # Translations 60 | *.mo 61 | *.pot 62 | 63 | # Django stuff: 64 | *.log 65 | local_settings.py 66 | db.sqlite3 67 | db.sqlite3-journal 68 | 69 | # Flask stuff: 70 | instance/ 71 | .webassets-cache 72 | 73 | # Scrapy stuff: 74 | .scrapy 75 | 76 | # Sphinx documentation 77 | docs/_build/ 78 | 79 | # PyBuilder 80 | target/ 81 | 82 | # Jupyter Notebook 83 | .ipynb_checkpoints 84 | 85 | # IPython 86 | profile_default/ 87 | ipython_config.py 88 | 89 | # pyenv 90 | .python-version 91 | 92 | # pipenv 93 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 94 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 95 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 96 | # install all needed dependencies. 97 | #Pipfile.lock 98 | 99 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 100 | __pypackages__/ 101 | 102 | # Celery stuff 103 | celerybeat-schedule 104 | celerybeat.pid 105 | 106 | # SageMath parsed files 107 | *.sage.py 108 | 109 | # Environments 110 | .env 111 | .venv 112 | env/ 113 | venv/ 114 | ENV/ 115 | env.bak/ 116 | venv.bak/ 117 | 118 | # Spyder project settings 119 | .spyderproject 120 | .spyproject 121 | 122 | # Rope project settings 123 | .ropeproject 124 | 125 | # mkdocs documentation 126 | /site 127 | 128 | # mypy 129 | .mypy_cache/ 130 | .dmypy.json 131 | dmypy.json 132 | 133 | # Pyre type checker 134 | .pyre/ 135 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | overview_hashdb 2 | 3 | ![AWS Deploy](https://github.com/OALabs/hashdb/actions/workflows/deploy.yml/badge.svg) [![Chat](https://img.shields.io/badge/chat-Discord-blueviolet)](https://discord.gg/cw4U3WHvpn) [![Support](https://img.shields.io/badge/Support-Patreon-FF424D)](https://www.patreon.com/oalabs) 4 | # HashDB 5 | 6 | HashDB is a community-sourced library of hashing algorithms used in malware. 7 | 8 | ## How To Use HashDB 9 | 10 | HashDB can be used as a stand alone hashing library, but it also feeds the [HashDB Lookup Service](https://hashdb.openanalysis.net) run by OALabs. This service allows analysts to reverse hashes and retrieve hashed API names and string values. 11 | 12 | ### Stand Alone Module 13 | 14 | HashDB can be cloned and used in your reverse engineering scripts like any standard Python module. Some example code follows. 15 | ```python 16 | >>> import hashdb 17 | >>> hashdb.list_algorithms() 18 | ['crc32'] 19 | >>> hashdb.algorithms.crc32.hash(b'test') 20 | 3632233996 21 | ``` 22 | 23 | ### HashDB Lookup Service 24 | 25 | OALabs run a free [HashDB Lookup Service](https://hashdb.openanalysis.net) that can be used to query a hash table for any hash listed in the HashDb library. Included in the hash tables are the complete set of Windows APIs as well as a many common strings used in malware. You can even add your own strings! 26 | 27 | #### HashDB IDA Plugin 28 | 29 | The HashDB lookup service has an IDA Pro plugin that can be used to automate hash lookups directly from IDA! 30 | The client can be downloaded from GitHub [here](https://github.com/OALabs/hashdb-ida). 31 | 32 | ## How To Add New Hashes 33 | 34 | HashDB relies on community support to keep our hash library current! Our goal is to have contributors spend **no more than five minutes** adding a new hash, from first commit, to PR. To achieve this goal we offer the following streamlined process. 35 | 36 | 1. Make sure the hash algorithm doesn’t already exist… we know that seems silly but just double check. 37 | 38 | 2. Create a branch with a descriptive name. 39 | 40 | 3. Add a new Python file to the `/algorithms` directory with the name of your hash algorithm. Try to use the official name of the algorithm, or if it is unique, use the name of the malware that it is unique to. 41 | 42 | 4. Use the following template to setup your new hash algorithm. All fields are mandatory and case sensitive. 43 | 44 | ```python 45 | #!/usr/bin/env python 46 | 47 | DESCRIPTION = "your hash description here" 48 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 49 | TYPE = 'unsigned_int' 50 | # Test must match the exact hash of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 51 | TEST_1 = hash_of_string_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 52 | 53 | 54 | def hash(data): 55 | # your hash code here 56 | ``` 57 | 58 | 5. Double check your Python style, we use Flake8 on Python 3.9. You can try the following lint commands locally from the root of the git repository. 59 | 60 | ``` 61 | pip install flake8 62 | flake8 ./algorithms --count --select=E9,F63,F7,F82 --show-source --statistics 63 | ``` 64 | 65 | 6. Test your code locally using our test suite. Run the following commands locally from the root of the git repository. Note that you must run pytest as a module rather than directly or it won't pick up our test directory. 66 | 67 | ``` 68 | pip install pytest 69 | python -m pytest 70 | ``` 71 | 72 | 7. Issue a pull request — your new algorithm will be automatically queued for testing and if successful it will be merged. 73 | 74 | That’s it! Not only will your new hash be available in the HashDB library but a new hash table will be generated for the [HashDB Lookup Service](https://hashdb.openanalysis.net) and you can start reversing hashes immediately! 75 | 76 | ### ❗Rules For New Hashes 77 | 78 | PRs with changes outside of the `/algorithms` directory are not part of our automated CI and will be subjected to extra scrutiny. 79 | 80 | All hashes must have a valid description in the `DESCRIPTION` field. 81 | 82 | All hashes must have a type of either `unsigned_int` or `unsigned_long` in the `TYPE` field. HashDB currently only accepts unsigned 32bit or 64bit hashes. 83 | 84 | All hashes must have the hash of the string __ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789__ in the `TEST_1` field. 85 | 86 | All hashes must include a function `hash(data)` that accepts a byte string and returns a hash of the string. 87 | 88 | ### Adding Custom API Hashes 89 | 90 | Some hash algorithms hash the module name and API separately and combine the hashes to create a single module+API hash. An example of this is the standard [Metasploit ROR13 hash](https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x86/src/hash.py). These algorithms will not work with the standard wordlist and require a custom wordlist that includes both the module name and API. To handle these we allow custom algorithms that will only return a valid hash for some words. 91 | 92 | Adding a custom API hash requires the following additional components. 93 | 94 | 1. The `TEST_1` field must be set to 4294967294 (-1). 95 | 96 | 2. The hash algorithm must return the value 4294967294 for all invalid hashes. 97 | 98 | 3. An additional `TEST_API_DATA_1` field must be added with an example word that is valid for the algorithm. 99 | 100 | 4. An additional `TEST_API_1` field must be added with the hash of the `TEST_API_DATA_1` field. 101 | 102 | ## Standing On The Shoulders of Giants 103 | 104 | A big shout out to the FLARE team for their efforts with [shellcode_hashes](https://github.com/fireeye/flare-ida/tree/master/shellcode_hashes). Many years ago this project set the bar for quick and easy malware hash reversing and it’s still an extremely useful tool. So why duplicate it? 105 | 106 | Frankly, it’s all about the wordlist and accessibility. We have seen a dramatic shift towards using hashes for all sorts of strings in malware now, and the old method of hashing all the Windows’ DLL exports just isn’t good enough. We wanted a solution that could continuously process millions of registry keys and values, filenames, and process names. And we wanted that data available via a REST API so that we could use it our automation workflows, not just our static analysis tools. That being said, we wouldn’t exist without shellcode_hashes, so credit where credit is due 🙌 107 | 108 | --- 109 |

110 | 111 |

112 | -------------------------------------------------------------------------------- /algorithms/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Stores a list of module string names in __all__ 5 | import os 6 | import glob 7 | from importlib import import_module 8 | files = glob.glob(os.path.dirname(__file__) + "/*.py") 9 | __all__ = [os.path.basename(f)[:-3] for f in files if "__init__" not in f] 10 | modules = {} 11 | for module_name in __all__: 12 | modules[module_name] = import_module(f"{__name__}.{module_name}") 13 | -------------------------------------------------------------------------------- /algorithms/add1501_shl5.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ADD 0x1505 and SHIFT LEFT 5" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 205455184 26 | 27 | 28 | def hash(data): 29 | val = 0x1505 30 | for ch in data: 31 | val += (val << 5) 32 | val &= 0xFFFFFFFF 33 | val += ch 34 | val &= 0xFFFFFFFF 35 | return val 36 | -------------------------------------------------------------------------------- /algorithms/add_65599.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | DESCRIPTION = "ADD 65599 and MULTIPLY" 3 | TYPE = 'unsigned_int' 4 | TEST_1 = 2480409887 5 | 6 | def hash(data): 7 | result = 0 8 | for c in data: 9 | tmp = c + 32 10 | if(((c - ord('A')) & 0xFFFF) > 26): 11 | tmp = c 12 | result = (tmp + 0x1003F * result) & 0xFFFFFFFF 13 | 14 | return result 15 | -------------------------------------------------------------------------------- /algorithms/add_hiword_add_lowword.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | Sum of characters in hi word and low word combined to DWORD. 5 | Used in Darkside ransomware API hash.""" 6 | TYPE = 'unsigned_int' 7 | TEST_1 = 2383353113 8 | 9 | 10 | def hash(data): 11 | hash_high = 0xffff 12 | hash_low = 0xffff 13 | for ptr in range(len(data)): 14 | hash_low = (hash_low + data[ptr]) 15 | hash_high = (hash_high + hash_low) 16 | hash_high %= 0xFFF1 17 | hash_low %= 0xFFF1 18 | return (hash_high << 16) + hash_low 19 | -------------------------------------------------------------------------------- /algorithms/add_rol5_hash_again.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ADD and ROL 5 and ROL 5 the result" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 3853345759 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val += i 52 | val = rol(val, 0x5, 32) 53 | val = rol(val, 0x5, 32) 54 | return val 55 | -------------------------------------------------------------------------------- /algorithms/add_ror13.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ADD and ROR 13" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 3953483048 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def ror(inVal, numShifts, dataSize=32): 37 | '''rotate right instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val += i 52 | val = ror(val, 0xd, 32) 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/add_ror13_hash_again.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ADD and ROR 13 and ROR 13 the result" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 3913768234 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def ror(inVal, numShifts, dataSize=32): 37 | '''rotate right instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val += i 52 | val = ror(val, 0xd, 32) 53 | val = ror(val, 0xd, 32) 54 | return val 55 | -------------------------------------------------------------------------------- /algorithms/add_ror4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ADD and ROR 4" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 234261009 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def ror(inVal, numShifts, dataSize=32): 37 | '''rotate right instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = (val & 0xffffff00) + ((val + i) & 0xff) 52 | val = ror(val, 0x4, 32) 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/adler32_666.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | import zlib 24 | 25 | DESCRIPTION = "Adler-32 checksum with 666 seed." 26 | TYPE = 'unsigned_int' 27 | TEST_1 = 737679269 28 | 29 | 30 | def hash(data): 31 | return zlib.adler32(data, 666) & 0xffffffff 32 | -------------------------------------------------------------------------------- /algorithms/babbleloader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | 5 | Author = 0x0d4y 6 | 7 | This hashing algorithm was found during my analysis of a BabbleLoader sample, with the goal of validating that the correct API function was obtained. 8 | 9 | Sample MD5:FA3D03C319A7597712EEFF1338DABF92 10 | 11 | Reference: https://0x0d4y.blog/babbleloader-deep-dive-into-edr-and-machine-learning-based-endpoint-protection-evasion/ 12 | 13 | """ 14 | TYPE = 'unsigned_int' 15 | 16 | TEST_1 = 4238996181 17 | 18 | def hash(data): 19 | if isinstance(data, bytes): 20 | data = data.decode('utf-8') 21 | 22 | final_hash = 0 23 | for char in data: 24 | char_orded = ord(char) 25 | final_hash = (final_hash + char_orded) * (char_orded + 0x4af1e366) 26 | final_hash &= 0xFFFFFFFF 27 | 28 | return final_hash 29 | 30 | -------------------------------------------------------------------------------- /algorithms/babbleloader_0125.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | 5 | Author = 0x0d4y 6 | 7 | Description = This new algorithm was discovered during ongoing monitoring of BabbleLoader, which implements it to obfuscate APIs. 8 | 9 | Sample_I MD5: 06e1c0ee8a7f340d77c95be867c49284 10 | Sample_II MD5: 7d1a15fd3c17ad226b3516bea26d7a94 11 | 12 | Reference: https://0x0d4y.blog/babbleloader-deep-dive-into-edr-and-machine-learning-based-endpoint-protection-evasion/ 13 | 14 | """ 15 | TYPE = 'unsigned_int' 16 | 17 | TEST_1 = 3847507269 18 | 19 | def hash(data): 20 | if isinstance(data, bytes): 21 | data = data.decode('utf-8') 22 | 23 | final_hash = 0 24 | for char in data: 25 | char_orded = ord(char) 26 | final_hash = (final_hash + char_orded) * (char_orded + 0x1c9943d2) 27 | final_hash &= 0xFFFFFFFF 28 | 29 | return final_hash 30 | 31 | -------------------------------------------------------------------------------- /algorithms/blister2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Blister loader v2 api hash" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 0x6d223692 6 | 7 | 8 | def hash(data): 9 | h = 0x78f1e5bf 10 | for c in data: 11 | h = (((c ^ h) & 0xffffffff) * 0x5bd1e995) & 0xffffffff 12 | h = (h ^ ((h >> 15) & 0xffffffff)) & 0xffffffff 13 | return h 14 | -------------------------------------------------------------------------------- /algorithms/brc4_1_4_5.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Hash algorithm used in BRC4 1.4.5" 4 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 5 | TYPE = 'unsigned_int' 6 | # Test must match the exact hash of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 7 | TEST_1 = 3471553803 8 | 9 | 10 | def hash(data): 11 | result = 0 12 | for c in data: 13 | temp = 2049 * result 14 | temp |= 0x2800000 15 | temp += c 16 | result = temp & 0xFFFFFFFF 17 | 18 | return result 19 | -------------------------------------------------------------------------------- /algorithms/brc4_joaat.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Jenkins One At A Time (JOAAT) Hashing Algorithm Used by BRC4" 4 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 5 | TYPE = 'unsigned_int' 6 | # Test must match the exact hash of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 7 | TEST_1 = 4059668722 8 | 9 | 10 | def hash(data): 11 | val = 0 12 | for c in data: 13 | v1 = c + val 14 | v2 = (1025 * v1) & 0xffffffff 15 | v3 = v2 >> 6 16 | val = v2 ^ v3 17 | 18 | val = (val + val * 8) & 0xffffffff 19 | r1 = val >> 11 20 | r2 = val ^ r1 21 | result = r2 * 32769 & 0xffffffff 22 | 23 | return result 24 | -------------------------------------------------------------------------------- /algorithms/carbanak.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "Carbanak API hashing used by CARBON SPIDER aka FIN7" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 204821865 26 | 27 | 28 | def hash(data): 29 | ctr = 0 30 | for i in data: 31 | ctr = (ctr << 4) + i 32 | if (ctr & 0xF0000000): 33 | ctr = (((ctr & 0xF0000000) >> 24) ^ ctr) & 0x0FFFFFFF 34 | return ctr 35 | -------------------------------------------------------------------------------- /algorithms/ch_add_rol8.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "XOR and ROL 8 and SLICE hex" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 377121536 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = val ^ (i * 256) 52 | val = rol(val, 0x8, 32) 53 | val_hex = "%08x" % val 54 | valh_str = val_hex[4:6] 55 | valh = int(valh_str, 16) 56 | val = val ^ valh 57 | return val 58 | -------------------------------------------------------------------------------- /algorithms/conti.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "Conti ransomware api hash" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2524534739 26 | 27 | 28 | def hash(data): 29 | API_buffer = [] 30 | 31 | i = len(data) >> 3 32 | 33 | count = 0 34 | while i != 0: 35 | for index in range(0, 8): 36 | API_buffer.append(data[index + count]) 37 | count += 8 38 | i -= 1 39 | 40 | if len(data) & 7 != 0: 41 | v8 = len(data) & 7 42 | 43 | while v8 != 0: 44 | API_buffer.append(data[count]) 45 | count += 1 46 | v8 -= 1 47 | 48 | hash_val = 0 49 | 50 | for i in range(0, len(API_buffer)): 51 | API_buffer[i] = ord(chr(API_buffer[i])) 52 | 53 | v15 = 0xFF889912 54 | string_length_2 = len(data) 55 | API_buffer_count = 0 56 | if len(data) >= 4: 57 | count = string_length_2 >> 2 58 | string_length_2 = (string_length_2 - 4 * 59 | (string_length_2 >> 2)) & 0xFFFFFFFF 60 | 61 | while True: 62 | temp_buffer_val = API_buffer[API_buffer_count + 63 | 3] << 24 | API_buffer[API_buffer_count + 64 | 2] << 16 | API_buffer[API_buffer_count + 65 | 1] << 8 | API_buffer[API_buffer_count] 66 | 67 | temp = (0x5BD1E995 * temp_buffer_val) & 0xFFFFFFFF 68 | API_buffer_count += 4 69 | v15 = ((0x5BD1E995 * (temp ^ 70 | (temp >> 0x18))) & 0xFFFFFFFF) ^ ((0x5BD1E995 * v15) & 0xFFFFFFFF) 71 | count -= 1 72 | if count == 0: 73 | break 74 | 75 | v18 = string_length_2 - 1 76 | 77 | v19 = v18 - 1 78 | 79 | if v18 == 0: 80 | hash_val ^= API_buffer[API_buffer_count] 81 | elif v19 == 0: 82 | hash_val ^= API_buffer[API_buffer_count + 1] << 8 83 | hash_val ^= API_buffer[API_buffer_count] 84 | elif v19 == 1: 85 | hash_val ^= API_buffer[API_buffer_count + 2] << 16 86 | hash_val ^= API_buffer[API_buffer_count + 1] << 8 87 | hash_val ^= API_buffer[API_buffer_count] 88 | 89 | v20 = (0x5BD1E995 * hash_val) & 0xFFFFFFFF 90 | edi = (0x5BD1E995 * len(data)) & 0xFFFFFFFF 91 | 92 | eax = v20 >> 0x18 93 | eax ^= v20 94 | 95 | ecx = (0x5BD1E995 * eax) & 0xFFFFFFFF 96 | eax = (0x5BD1E995 * v15) & 0xFFFFFFFF 97 | 98 | ecx ^= eax 99 | 100 | eax = edi 101 | eax >>= 0x18 102 | eax ^= edi 103 | 104 | edx = (0x5BD1E995 * ecx) & 0xFFFFFFFF 105 | eax = (0x5BD1E995 * eax) & 0xFFFFFFFF 106 | edx ^= eax 107 | eax = edx 108 | 109 | eax >>= 0xD 110 | eax ^= edx 111 | 112 | ecx = (0x5BD1E995 * eax) & 0xFFFFFFFF 113 | eax = ecx 114 | eax >>= 0xF 115 | eax ^= ecx 116 | 117 | return eax 118 | -------------------------------------------------------------------------------- /algorithms/conti_5b2d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Conti ransomware api hash with seed 0x5B2D" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 3350281850 6 | 7 | 8 | def hash(data): 9 | API_buffer = [] 10 | 11 | i = len(data) >> 3 12 | 13 | count = 0 14 | while i != 0: 15 | for index in range(0, 8): 16 | API_buffer.append(data[index + count]) 17 | count += 8 18 | i -= 1 19 | 20 | if len(data) & 7 != 0: 21 | v8 = len(data) & 7 22 | 23 | while v8 != 0: 24 | API_buffer.append(data[count]) 25 | count += 1 26 | v8 -= 1 27 | 28 | hash_val = 0 29 | 30 | for i in range(0, len(API_buffer)): 31 | API_buffer[i] = ord(chr(API_buffer[i])) 32 | 33 | v15 = 0x5B2D 34 | string_length_2 = len(data) 35 | API_buffer_count = 0 36 | if len(data) >= 4: 37 | count = string_length_2 >> 2 38 | string_length_2 = (string_length_2 - 4 * 39 | (string_length_2 >> 2)) & 0xFFFFFFFF 40 | 41 | while True: 42 | temp_buffer_val = API_buffer[API_buffer_count + 43 | 3] << 24 | API_buffer[API_buffer_count + 44 | 2] << 16 | API_buffer[API_buffer_count + 45 | 1] << 8 | API_buffer[API_buffer_count] 46 | 47 | temp = (0x5BD1E995 * temp_buffer_val) & 0xFFFFFFFF 48 | API_buffer_count += 4 49 | v15 = ((0x5BD1E995 * (temp ^ 50 | (temp >> 0x18))) & 0xFFFFFFFF) ^ ((0x5BD1E995 * v15) & 0xFFFFFFFF) 51 | count -= 1 52 | if count == 0: 53 | break 54 | 55 | v18 = string_length_2 - 1 56 | 57 | v19 = v18 - 1 58 | 59 | if v18 == 0: 60 | hash_val ^= API_buffer[API_buffer_count] 61 | elif v19 == 0: 62 | hash_val ^= API_buffer[API_buffer_count + 1] << 8 63 | hash_val ^= API_buffer[API_buffer_count] 64 | elif v19 == 1: 65 | hash_val ^= API_buffer[API_buffer_count + 2] << 16 66 | hash_val ^= API_buffer[API_buffer_count + 1] << 8 67 | hash_val ^= API_buffer[API_buffer_count] 68 | 69 | v20 = (0x5BD1E995 * hash_val) & 0xFFFFFFFF 70 | edi = (0x5BD1E995 * len(data)) & 0xFFFFFFFF 71 | 72 | eax = v20 >> 0x18 73 | eax ^= v20 74 | 75 | ecx = (0x5BD1E995 * eax) & 0xFFFFFFFF 76 | eax = (0x5BD1E995 * v15) & 0xFFFFFFFF 77 | 78 | ecx ^= eax 79 | 80 | eax = edi 81 | eax >>= 0x18 82 | eax ^= edi 83 | 84 | edx = (0x5BD1E995 * ecx) & 0xFFFFFFFF 85 | eax = (0x5BD1E995 * eax) & 0xFFFFFFFF 86 | edx ^= eax 87 | eax = edx 88 | 89 | eax >>= 0xD 90 | eax ^= edx 91 | 92 | ecx = (0x5BD1E995 * eax) & 0xFFFFFFFF 93 | eax = ecx 94 | eax >>= 0xF 95 | eax ^= ecx 96 | 97 | return eax 98 | -------------------------------------------------------------------------------- /algorithms/conti_b801fcda.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Conti ransomware api hash with seed 0xB801FCDA" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 384343055 6 | 7 | 8 | def hash(data): 9 | API_buffer = [] 10 | 11 | i = len(data) >> 3 12 | 13 | count = 0 14 | while i != 0: 15 | for index in range(0, 8): 16 | API_buffer.append(data[index + count]) 17 | count += 8 18 | i -= 1 19 | 20 | if len(data) & 7 != 0: 21 | v8 = len(data) & 7 22 | 23 | while v8 != 0: 24 | API_buffer.append(data[count]) 25 | count += 1 26 | v8 -= 1 27 | 28 | hash_val = 0 29 | 30 | for i in range(0, len(API_buffer)): 31 | API_buffer[i] = ord(chr(API_buffer[i])) 32 | 33 | v15 = 0xB801FCDA 34 | string_length_2 = len(data) 35 | API_buffer_count = 0 36 | if len(data) >= 4: 37 | count = string_length_2 >> 2 38 | string_length_2 = (string_length_2 - 4 * 39 | (string_length_2 >> 2)) & 0xFFFFFFFF 40 | 41 | while True: 42 | temp_buffer_val = API_buffer[API_buffer_count + 43 | 3] << 24 | API_buffer[API_buffer_count + 44 | 2] << 16 | API_buffer[API_buffer_count + 45 | 1] << 8 | API_buffer[API_buffer_count] 46 | 47 | temp = (0x5BD1E995 * temp_buffer_val) & 0xFFFFFFFF 48 | API_buffer_count += 4 49 | v15 = ((0x5BD1E995 * (temp ^ 50 | (temp >> 0x18))) & 0xFFFFFFFF) ^ ((0x5BD1E995 * v15) & 0xFFFFFFFF) 51 | count -= 1 52 | if count == 0: 53 | break 54 | 55 | v18 = string_length_2 - 1 56 | 57 | v19 = v18 - 1 58 | 59 | if v18 == 0: 60 | hash_val ^= API_buffer[API_buffer_count] 61 | elif v19 == 0: 62 | hash_val ^= API_buffer[API_buffer_count + 1] << 8 63 | hash_val ^= API_buffer[API_buffer_count] 64 | elif v19 == 1: 65 | hash_val ^= API_buffer[API_buffer_count + 2] << 16 66 | hash_val ^= API_buffer[API_buffer_count + 1] << 8 67 | hash_val ^= API_buffer[API_buffer_count] 68 | 69 | v20 = (0x5BD1E995 * hash_val) & 0xFFFFFFFF 70 | edi = (0x5BD1E995 * len(data)) & 0xFFFFFFFF 71 | 72 | eax = v20 >> 0x18 73 | eax ^= v20 74 | 75 | ecx = (0x5BD1E995 * eax) & 0xFFFFFFFF 76 | eax = (0x5BD1E995 * v15) & 0xFFFFFFFF 77 | 78 | ecx ^= eax 79 | 80 | eax = edi 81 | eax >>= 0x18 82 | eax ^= edi 83 | 84 | edx = (0x5BD1E995 * ecx) & 0xFFFFFFFF 85 | eax = (0x5BD1E995 * eax) & 0xFFFFFFFF 86 | edx ^= eax 87 | eax = edx 88 | 89 | eax >>= 0xD 90 | eax ^= edx 91 | 92 | ecx = (0x5BD1E995 * eax) & 0xFFFFFFFF 93 | eax = ecx 94 | eax >>= 0xF 95 | eax ^= ecx 96 | 97 | return eax 98 | -------------------------------------------------------------------------------- /algorithms/conti_e9ff0077.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Conti ransomware api hash with seed 0xE9FF0077" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 3760887415 6 | 7 | 8 | def hash(data): 9 | API_buffer = [] 10 | 11 | i = len(data) >> 3 12 | 13 | count = 0 14 | while i != 0: 15 | for index in range(0, 8): 16 | API_buffer.append(data[index + count]) 17 | count += 8 18 | i -= 1 19 | 20 | if len(data) & 7 != 0: 21 | v8 = len(data) & 7 22 | 23 | while v8 != 0: 24 | API_buffer.append(data[count]) 25 | count += 1 26 | v8 -= 1 27 | 28 | hash_val = 0 29 | 30 | for i in range(0, len(API_buffer)): 31 | API_buffer[i] = ord(chr(API_buffer[i])) 32 | 33 | v15 = 0xE9FF0077 34 | string_length_2 = len(data) 35 | API_buffer_count = 0 36 | if len(data) >= 4: 37 | count = string_length_2 >> 2 38 | string_length_2 = (string_length_2 - 4 * 39 | (string_length_2 >> 2)) & 0xFFFFFFFF 40 | 41 | while True: 42 | temp_buffer_val = API_buffer[API_buffer_count + 43 | 3] << 24 | API_buffer[API_buffer_count + 44 | 2] << 16 | API_buffer[API_buffer_count + 45 | 1] << 8 | API_buffer[API_buffer_count] 46 | 47 | temp = (0x5BD1E995 * temp_buffer_val) & 0xFFFFFFFF 48 | API_buffer_count += 4 49 | v15 = ((0x5BD1E995 * (temp ^ 50 | (temp >> 0x18))) & 0xFFFFFFFF) ^ ((0x5BD1E995 * v15) & 0xFFFFFFFF) 51 | count -= 1 52 | if count == 0: 53 | break 54 | 55 | v18 = string_length_2 - 1 56 | 57 | v19 = v18 - 1 58 | 59 | if v18 == 0: 60 | hash_val ^= API_buffer[API_buffer_count] 61 | elif v19 == 0: 62 | hash_val ^= API_buffer[API_buffer_count + 1] << 8 63 | hash_val ^= API_buffer[API_buffer_count] 64 | elif v19 == 1: 65 | hash_val ^= API_buffer[API_buffer_count + 2] << 16 66 | hash_val ^= API_buffer[API_buffer_count + 1] << 8 67 | hash_val ^= API_buffer[API_buffer_count] 68 | 69 | v20 = (0x5BD1E995 * hash_val) & 0xFFFFFFFF 70 | edi = (0x5BD1E995 * len(data)) & 0xFFFFFFFF 71 | 72 | eax = v20 >> 0x18 73 | eax ^= v20 74 | 75 | ecx = (0x5BD1E995 * eax) & 0xFFFFFFFF 76 | eax = (0x5BD1E995 * v15) & 0xFFFFFFFF 77 | 78 | ecx ^= eax 79 | 80 | eax = edi 81 | eax >>= 0x18 82 | eax ^= edi 83 | 84 | edx = (0x5BD1E995 * ecx) & 0xFFFFFFFF 85 | eax = (0x5BD1E995 * eax) & 0xFFFFFFFF 86 | edx ^= eax 87 | eax = edx 88 | 89 | eax >>= 0xD 90 | eax ^= edx 91 | 92 | ecx = (0x5BD1E995 * eax) & 0xFFFFFFFF 93 | eax = ecx 94 | eax >>= 0xF 95 | eax ^= ecx 96 | 97 | return eax 98 | -------------------------------------------------------------------------------- /algorithms/conti_mm3.py: -------------------------------------------------------------------------------- 1 | ''' 2 | pymmh3 was written by Fredrik Kihlander and enhanced by Swapnil Gusani, and is placed in the public 3 | domain. The authors hereby disclaim copyright to this source code. 4 | 5 | pure python implementation of the murmur3 hash algorithm 6 | 7 | https://code.google.com/p/smhasher/wiki/MurmurHash3 8 | 9 | This was written for the times when you do not want to compile c-code and install modules, 10 | and you only want a drop-in murmur3 implementation. 11 | 12 | As this is purely python it is FAR from performant and if performance is anything that is needed 13 | a proper c-module is suggested! 14 | 15 | This module is written to have the same format as mmh3 python package found here for simple conversions: 16 | 17 | https://pypi.python.org/pypi/mmh3/2.3.1 18 | ''' 19 | 20 | DESCRIPTION = "Conti ransomware Murmur3 API hashing" 21 | TYPE = 'unsigned_int' 22 | TEST_1 = 60915229 23 | 24 | import sys as _sys 25 | if (_sys.version_info > (3, 0)): 26 | def xrange( a, b, c ): 27 | return range( a, b, c ) 28 | def xencode(x): 29 | if isinstance(x, bytes) or isinstance(x, bytearray): 30 | return x 31 | else: 32 | return x.encode() 33 | else: 34 | def xencode(x): 35 | return x 36 | del _sys 37 | 38 | 39 | def hash( key ): 40 | seed = 0xe9ff0077 41 | ''' Implements 32bit murmur3 hash. ''' 42 | 43 | key = bytearray( xencode(key.lower()) ) 44 | 45 | def fmix( h ): 46 | h ^= h >> 16 47 | h = ( h * 0x85ebca6b ) & 0xFFFFFFFF 48 | h ^= h >> 13 49 | h = ( h * 0xc2b2ae35 ) & 0xFFFFFFFF 50 | h ^= h >> 16 51 | return h 52 | 53 | length = len( key ) 54 | nblocks = int( length / 4 ) 55 | 56 | h1 = seed 57 | 58 | c1 = 0xcc9e2d51 59 | c2 = 0x1b873593 60 | 61 | # body 62 | for block_start in xrange( 0, nblocks * 4, 4 ): 63 | # ??? big endian? 64 | k1 = key[ block_start + 3 ] << 24 | \ 65 | key[ block_start + 2 ] << 16 | \ 66 | key[ block_start + 1 ] << 8 | \ 67 | key[ block_start + 0 ] 68 | 69 | k1 = ( c1 * k1 ) & 0xFFFFFFFF 70 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32 71 | k1 = ( c2 * k1 ) & 0xFFFFFFFF 72 | 73 | h1 ^= k1 74 | h1 = ( h1 << 13 | h1 >> 19 ) & 0xFFFFFFFF # inlined ROTL32 75 | h1 = ( h1 * 5 + 0xe6546b64 ) & 0xFFFFFFFF 76 | 77 | # tail 78 | tail_index = nblocks * 4 79 | k1 = 0 80 | tail_size = length & 3 81 | 82 | if tail_size >= 3: 83 | k1 ^= key[ tail_index + 2 ] << 16 84 | if tail_size >= 2: 85 | k1 ^= key[ tail_index + 1 ] << 8 86 | if tail_size >= 1: 87 | k1 ^= key[ tail_index + 0 ] 88 | 89 | if tail_size > 0: 90 | k1 = ( k1 * c1 ) & 0xFFFFFFFF 91 | k1 = ( k1 << 15 | k1 >> 17 ) & 0xFFFFFFFF # inlined ROTL32 92 | k1 = ( k1 * c2 ) & 0xFFFFFFFF 93 | h1 ^= k1 94 | 95 | #finalization 96 | unsigned_val = fmix( h1 ^ length ) 97 | 98 | # convert to unsigned int 99 | return unsigned_val & 0xffffffff 100 | 101 | 102 | -------------------------------------------------------------------------------- /algorithms/crc32.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import zlib 3 | 4 | DESCRIPTION = "Standard crc32 hash." 5 | TYPE = 'unsigned_int' 6 | TEST_1 = 532866770 7 | 8 | 9 | def hash(data): 10 | return 0xffffffff & zlib.crc32(data) 11 | -------------------------------------------------------------------------------- /algorithms/crc32_bzip2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | # def gen_table(): 22 | # crc32_table = [0] * 256 23 | # for i in range(256): 24 | # v = i << 24 25 | # for j in range(8): 26 | # if (v & 0x80000000) == 0: 27 | # v = (2 * v) & 0xffffffff 28 | # else: 29 | # v = ((2 * v) ^ 0x4C11DB7) & 0xffffffff 30 | # crc32_table[i] = v 31 | # return crc32_table 32 | # 33 | ######################################################################## 34 | 35 | DESCRIPTION = "bzip2 version of crc32" 36 | TYPE = 'unsigned_int' 37 | TEST_1 = 2691965320 38 | 39 | 40 | def hash(data): 41 | crc32_table = [0, 79764919, 159529838, 222504665, 319059676, 398814059, 445009330, 507990021, 638119352, 583659535, 797628118, 726387553, 890018660, 835552979, 1015980042, 944750013, 1276238704, 1221641927, 1167319070, 1095957929, 1595256236, 1540665371, 1452775106, 1381403509, 1780037320, 1859660671, 1671105958, 1733955601, 2031960084, 2111593891, 1889500026, 1952343757, 2552477408, 2632100695, 2443283854, 2506133561, 2334638140, 2414271883, 2191915858, 2254759653, 3190512472, 3135915759, 3081330742, 3009969537, 2905550212, 2850959411, 2762807018, 2691435357, 3560074640, 3505614887, 3719321342, 3648080713, 3342211916, 3287746299, 3467911202, 3396681109, 4063920168, 4143685023, 4223187782, 4286162673, 3779000052, 3858754371, 3904687514, 3967668269, 881225847, 809987520, 1023691545, 969234094, 662832811, 591600412, 771767749, 717299826, 311336399, 374308984, 453813921, 533576470, 25881363, 88864420, 134795389, 214552010, 2023205639, 2086057648, 1897238633, 1976864222, 1804852699, 1867694188, 1645340341, 1724971778, 1587496639, 1516133128, 1461550545, 1406951526, 1302016099, 1230646740, 1142491917, 1087903418, 2896545431, 2825181984, 2770861561, 2716262478, 3215044683, 3143675388, 3055782693, 3001194130, 2326604591, 2389456536, 2200899649, 2280525302, 2578013683, 2640855108, 2418763421, 2498394922, 3769900519, 3832873040, 3912640137, 3992402750, 4088425275, 4151408268, 4197601365, 4277358050, 3334271071, 3263032808, 3476998961, 3422541446, 3585640067, 3514407732, 3694837229, 3640369242, 1762451694, 1842216281, 1619975040, 1682949687, 2047383090, 2127137669, 1938468188, 2001449195, 1325665622, 1271206113, 1183200824, 1111960463, 1543535498, 1489069629, 1434599652, 1363369299, 622672798, 568075817, 748617968, 677256519, 907627842, 853037301, 1067152940, 995781531, 51762726, 131386257, 177728840, 240578815, 269590778, 349224269, 429104020, 491947555, 4046411278, 4126034873, 4172115296, 4234965207, 3794477266, 3874110821, 3953728444, 4016571915, 3609705398, 3555108353, 3735388376, 3664026991, 3290680682, 3236090077, 3449943556, 3378572211, 3174993278, 3120533705, 3032266256, 2961025959, 2923101090, 2868635157, 2813903052, 2742672763, 2604032198, 2683796849, 2461293480, 2524268063, 2284983834, 2364738477, 2175806836, 2238787779, 1569362073, 1498123566, 1409854455, 1355396672, 1317987909, 1246755826, 1192025387, 1137557660, 2072149281, 2135122070, 1912620623, 1992383480, 1753615357, 1816598090, 1627664531, 1707420964, 295390185, 358241886, 404320391, 483945776, 43990325, 106832002, 186451547, 266083308, 932423249, 861060070, 1041341759, 986742920, 613929101, 542559546, 756411363, 701822548, 3316196985, 3244833742, 3425377559, 3370778784, 3601682597, 3530312978, 3744426955, 3689838204, 3819031489, 3881883254, 3928223919, 4007849240, 4037393693, 4100235434, 4180117107, 4259748804, 2310601993, 2373574846, 2151335527, 2231098320, 2596047829, 2659030626, 2470359227, 2550115596, 2947551409, 2876312838, 2788305887, 2733848168, 3165939309, 3094707162, 3040238851, 2985771188] 42 | result = 0xffffffff 43 | for c in data: 44 | result = (crc32_table[c ^ ((result >> 24) & 0xff)] ^ (result << 8)) & 0xffffffff 45 | return (result ^ 0xffffffff) & 0xffffffff 46 | -------------------------------------------------------------------------------- /algorithms/crc32_mpeg_2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "MPEG-2 version of CRC-32." 4 | TYPE = "unsigned_int" 5 | TEST_1 = 1603001975 6 | 7 | 8 | def hash(data): 9 | crc = 0xFFFFFFFF 10 | for val in data: 11 | crc ^= val << 24 12 | for _ in range(8): 13 | crc = crc << 1 if (crc & 0x80000000) == 0 else (crc << 1) ^ 0x104C11DB7 14 | return crc 15 | -------------------------------------------------------------------------------- /algorithms/crc64_ecma_182.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from ctypes import c_uint64 3 | from ctypes import c_ubyte 4 | 5 | DESCRIPTION = "crc64 has crc64_ecma_182" 6 | TYPE = 'unsigned_long' 7 | TEST_1 = 6674762932123621561 8 | 9 | 10 | def bytes_to_int(data): 11 | 12 | """ 13 | Convert bytes to integer 14 | :param data: bytes of data 15 | :return: result int 16 | """ 17 | 18 | result = 0 19 | for b in data: 20 | result = result * 256 + int(b) 21 | return result 22 | 23 | 24 | def ref_bits(x): 25 | 26 | """ 27 | :param x: byte to reverse 28 | :return: reversed byte 29 | """ 30 | 31 | b = bin(x)[2::].zfill(8) 32 | b = b[8::-1] 33 | return int(b, 2) 34 | 35 | 36 | def ref(data): 37 | 38 | """ 39 | :param data: input bytes to reverse 40 | :return: reversed data bytes 41 | """ 42 | 43 | tmp = [] 44 | for byte in data: 45 | byte_r = ref_bits(byte) 46 | tmp.append(byte_r) 47 | 48 | data = bytes(tmp) 49 | return data 50 | 51 | 52 | TABLE_42F0E1EBA9EA3693 = [ 53 | 0x0000000000000000, 0x42F0E1EBA9EA3693, 0x85E1C3D753D46D26, 0xC711223CFA3E5BB5, 0x493366450E42ECDF, 0x0BC387AEA7A8DA4C, 54 | 0xCCD2A5925D9681F9, 0x8E224479F47CB76A, 0x9266CC8A1C85D9BE, 0xD0962D61B56FEF2D, 0x17870F5D4F51B498, 0x5577EEB6E6BB820B, 55 | 0xDB55AACF12C73561, 0x99A54B24BB2D03F2, 0x5EB4691841135847, 0x1C4488F3E8F96ED4, 0x663D78FF90E185EF, 0x24CD9914390BB37C, 56 | 0xE3DCBB28C335E8C9, 0xA12C5AC36ADFDE5A, 0x2F0E1EBA9EA36930, 0x6DFEFF5137495FA3, 0xAAEFDD6DCD770416, 0xE81F3C86649D3285, 57 | 0xF45BB4758C645C51, 0xB6AB559E258E6AC2, 0x71BA77A2DFB03177, 0x334A9649765A07E4, 0xBD68D2308226B08E, 0xFF9833DB2BCC861D, 58 | 0x388911E7D1F2DDA8, 0x7A79F00C7818EB3B, 0xCC7AF1FF21C30BDE, 0x8E8A101488293D4D, 0x499B3228721766F8, 0x0B6BD3C3DBFD506B, 59 | 0x854997BA2F81E701, 0xC7B97651866BD192, 0x00A8546D7C558A27, 0x4258B586D5BFBCB4, 0x5E1C3D753D46D260, 0x1CECDC9E94ACE4F3, 60 | 0xDBFDFEA26E92BF46, 0x990D1F49C77889D5, 0x172F5B3033043EBF, 0x55DFBADB9AEE082C, 0x92CE98E760D05399, 0xD03E790CC93A650A, 61 | 0xAA478900B1228E31, 0xE8B768EB18C8B8A2, 0x2FA64AD7E2F6E317, 0x6D56AB3C4B1CD584, 0xE374EF45BF6062EE, 0xA1840EAE168A547D, 62 | 0x66952C92ECB40FC8, 0x2465CD79455E395B, 0x3821458AADA7578F, 0x7AD1A461044D611C, 0xBDC0865DFE733AA9, 0xFF3067B657990C3A, 63 | 0x711223CFA3E5BB50, 0x33E2C2240A0F8DC3, 0xF4F3E018F031D676, 0xB60301F359DBE0E5, 0xDA050215EA6C212F, 0x98F5E3FE438617BC, 64 | 0x5FE4C1C2B9B84C09, 0x1D14202910527A9A, 0x93366450E42ECDF0, 0xD1C685BB4DC4FB63, 0x16D7A787B7FAA0D6, 0x5427466C1E109645, 65 | 0x4863CE9FF6E9F891, 0x0A932F745F03CE02, 0xCD820D48A53D95B7, 0x8F72ECA30CD7A324, 0x0150A8DAF8AB144E, 0x43A04931514122DD, 66 | 0x84B16B0DAB7F7968, 0xC6418AE602954FFB, 0xBC387AEA7A8DA4C0, 0xFEC89B01D3679253, 0x39D9B93D2959C9E6, 0x7B2958D680B3FF75, 67 | 0xF50B1CAF74CF481F, 0xB7FBFD44DD257E8C, 0x70EADF78271B2539, 0x321A3E938EF113AA, 0x2E5EB66066087D7E, 0x6CAE578BCFE24BED, 68 | 0xABBF75B735DC1058, 0xE94F945C9C3626CB, 0x676DD025684A91A1, 0x259D31CEC1A0A732, 0xE28C13F23B9EFC87, 0xA07CF2199274CA14, 69 | 0x167FF3EACBAF2AF1, 0x548F120162451C62, 0x939E303D987B47D7, 0xD16ED1D631917144, 0x5F4C95AFC5EDC62E, 0x1DBC74446C07F0BD, 70 | 0xDAAD56789639AB08, 0x985DB7933FD39D9B, 0x84193F60D72AF34F, 0xC6E9DE8B7EC0C5DC, 0x01F8FCB784FE9E69, 0x43081D5C2D14A8FA, 71 | 0xCD2A5925D9681F90, 0x8FDAB8CE70822903, 0x48CB9AF28ABC72B6, 0x0A3B7B1923564425, 0x70428B155B4EAF1E, 0x32B26AFEF2A4998D, 72 | 0xF5A348C2089AC238, 0xB753A929A170F4AB, 0x3971ED50550C43C1, 0x7B810CBBFCE67552, 0xBC902E8706D82EE7, 0xFE60CF6CAF321874, 73 | 0xE224479F47CB76A0, 0xA0D4A674EE214033, 0x67C58448141F1B86, 0x253565A3BDF52D15, 0xAB1721DA49899A7F, 0xE9E7C031E063ACEC, 74 | 0x2EF6E20D1A5DF759, 0x6C0603E6B3B7C1CA, 0xF6FAE5C07D3274CD, 0xB40A042BD4D8425E, 0x731B26172EE619EB, 0x31EBC7FC870C2F78, 75 | 0xBFC9838573709812, 0xFD39626EDA9AAE81, 0x3A28405220A4F534, 0x78D8A1B9894EC3A7, 0x649C294A61B7AD73, 0x266CC8A1C85D9BE0, 76 | 0xE17DEA9D3263C055, 0xA38D0B769B89F6C6, 0x2DAF4F0F6FF541AC, 0x6F5FAEE4C61F773F, 0xA84E8CD83C212C8A, 0xEABE6D3395CB1A19, 77 | 0x90C79D3FEDD3F122, 0xD2377CD44439C7B1, 0x15265EE8BE079C04, 0x57D6BF0317EDAA97, 0xD9F4FB7AE3911DFD, 0x9B041A914A7B2B6E, 78 | 0x5C1538ADB04570DB, 0x1EE5D94619AF4648, 0x02A151B5F156289C, 0x4051B05E58BC1E0F, 0x87409262A28245BA, 0xC5B073890B687329, 79 | 0x4B9237F0FF14C443, 0x0962D61B56FEF2D0, 0xCE73F427ACC0A965, 0x8C8315CC052A9FF6, 0x3A80143F5CF17F13, 0x7870F5D4F51B4980, 80 | 0xBF61D7E80F251235, 0xFD913603A6CF24A6, 0x73B3727A52B393CC, 0x31439391FB59A55F, 0xF652B1AD0167FEEA, 0xB4A25046A88DC879, 81 | 0xA8E6D8B54074A6AD, 0xEA16395EE99E903E, 0x2D071B6213A0CB8B, 0x6FF7FA89BA4AFD18, 0xE1D5BEF04E364A72, 0xA3255F1BE7DC7CE1, 82 | 0x64347D271DE22754, 0x26C49CCCB40811C7, 0x5CBD6CC0CC10FAFC, 0x1E4D8D2B65FACC6F, 0xD95CAF179FC497DA, 0x9BAC4EFC362EA149, 83 | 0x158E0A85C2521623, 0x577EEB6E6BB820B0, 0x906FC95291867B05, 0xD29F28B9386C4D96, 0xCEDBA04AD0952342, 0x8C2B41A1797F15D1, 84 | 0x4B3A639D83414E64, 0x09CA82762AAB78F7, 0x87E8C60FDED7CF9D, 0xC51827E4773DF90E, 0x020905D88D03A2BB, 0x40F9E43324E99428, 85 | 0x2CFFE7D5975E55E2, 0x6E0F063E3EB46371, 0xA91E2402C48A38C4, 0xEBEEC5E96D600E57, 0x65CC8190991CB93D, 0x273C607B30F68FAE, 86 | 0xE02D4247CAC8D41B, 0xA2DDA3AC6322E288, 0xBE992B5F8BDB8C5C, 0xFC69CAB42231BACF, 0x3B78E888D80FE17A, 0x7988096371E5D7E9, 87 | 0xF7AA4D1A85996083, 0xB55AACF12C735610, 0x724B8ECDD64D0DA5, 0x30BB6F267FA73B36, 0x4AC29F2A07BFD00D, 0x08327EC1AE55E69E, 88 | 0xCF235CFD546BBD2B, 0x8DD3BD16FD818BB8, 0x03F1F96F09FD3CD2, 0x41011884A0170A41, 0x86103AB85A2951F4, 0xC4E0DB53F3C36767, 89 | 0xD8A453A01B3A09B3, 0x9A54B24BB2D03F20, 0x5D45907748EE6495, 0x1FB5719CE1045206, 0x919735E51578E56C, 0xD367D40EBC92D3FF, 90 | 0x1476F63246AC884A, 0x568617D9EF46BED9, 0xE085162AB69D5E3C, 0xA275F7C11F7768AF, 0x6564D5FDE549331A, 0x279434164CA30589, 91 | 0xA9B6706FB8DFB2E3, 0xEB46918411358470, 0x2C57B3B8EB0BDFC5, 0x6EA7525342E1E956, 0x72E3DAA0AA188782, 0x30133B4B03F2B111, 92 | 0xF7021977F9CCEAA4, 0xB5F2F89C5026DC37, 0x3BD0BCE5A45A6B5D, 0x79205D0E0DB05DCE, 0xBE317F32F78E067B, 0xFCC19ED95E6430E8, 93 | 0x86B86ED5267CDBD3, 0xC4488F3E8F96ED40, 0x0359AD0275A8B6F5, 0x41A94CE9DC428066, 0xCF8B0890283E370C, 0x8D7BE97B81D4019F, 94 | 0x4A6ACB477BEA5A2A, 0x089A2AACD2006CB9, 0x14DEA25F3AF9026D, 0x562E43B4931334FE, 0x913F6188692D6F4B, 0xD3CF8063C0C759D8, 95 | 0x5DEDC41A34BBEEB2, 0x1F1D25F19D51D821, 0xD80C07CD676F8394, 0x9AFCE626CE85B507] 96 | 97 | 98 | def crc64_fast(data: bytes, table: list, init_val=0, final_xor=0, in_ref=False, out_ref=False): 99 | """ 100 | Function to calculating CRC16 with values from pre-calculated table 101 | :param data: Input data as bytes 102 | :param table: Pre-calculated table for polynomial used 103 | :param init_val: CRC initial value 104 | :param final_xor: Value that will be XORed to result crc 105 | :param in_ref: Flag to reflect input 106 | :param out_ref: Flag to reflect output 107 | :return: CRC as unsigned int32 value 108 | """ 109 | if not isinstance(data, bytes): 110 | raise TypeError("Expected bytes, got %s" % (type(data),)) 111 | if not isinstance(table, list): 112 | raise TypeError("Expected list, got %s" % (type(table),)) 113 | if not isinstance(init_val, int): 114 | raise TypeError("Expected int, got %s" % (type(init_val),)) 115 | if not isinstance(final_xor, int): 116 | raise TypeError("Expected int, got %s" % (type(final_xor),)) 117 | if not isinstance(in_ref, bool): 118 | raise TypeError("Expected bool, got %s" % (type(in_ref),)) 119 | if not isinstance(out_ref, bool): 120 | raise TypeError("Expected bool, got %s" % (type(out_ref),)) 121 | crc = c_uint64(0) if init_val == 0 else c_uint64(init_val) 122 | if in_ref: 123 | data = ref(data) 124 | for b in data: 125 | p = c_ubyte((crc.value ^ (b << 56)) >> 56) 126 | crc.value = (crc.value << 8) ^ table[p.value] 127 | if (out_ref): 128 | crc_bytes = bytes(crc) 129 | crc_bytes = ref(crc_bytes) 130 | return c_uint64(bytes_to_int(crc_bytes)).value ^ final_xor 131 | else: 132 | return crc.value ^ final_xor 133 | 134 | 135 | def crc64_ecma_182(data: bytes): 136 | return crc64_fast(data=data, table=TABLE_42F0E1EBA9EA3693) 137 | 138 | 139 | def hash(data): 140 | return crc64_ecma_182(data) 141 | -------------------------------------------------------------------------------- /algorithms/cryptbot_ror13_add_10.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python 2 | 3 | DESCRIPTION = "Add 10 to ror13 shift on data" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 3425182094 6 | 7 | 8 | rol = lambda val, r_bits, max_bits: \ 9 | (val << r_bits%max_bits) & (2**max_bits-1) | \ 10 | ((val & (2**max_bits-1)) >> (max_bits-(r_bits%max_bits))) 11 | 12 | ror = lambda val, r_bits, max_bits: \ 13 | ((val & (2**max_bits-1)) >> r_bits%max_bits) | \ 14 | (val << (max_bits-(r_bits%max_bits)) & (2**max_bits-1)) 15 | 16 | def hash(data): 17 | 18 | 19 | GENERATED_HASH = 0 20 | for character in data: 21 | 22 | segment_1 = ror(GENERATED_HASH, 13, 32) & 0xffffffff 23 | segment_2 = character 24 | if segment_2 >= 97: 25 | segment_2 -= 32 26 | GENERATED_HASH = segment_1 + segment_2 27 | return GENERATED_HASH + 10 28 | 29 | -------------------------------------------------------------------------------- /algorithms/d0nut.py: -------------------------------------------------------------------------------- 1 | DESCRIPTION = 'API Hashing as used by d0nut' 2 | 3 | TYPE = 'unsigned_int' 4 | TEST_1 = 2349756695 5 | 6 | rol = lambda val, r_bits, max_bits: \ 7 | (val << r_bits % max_bits) & (2 ** max_bits-1) | \ 8 | ((val & (2 ** max_bits-1)) >> (max_bits-(r_bits % max_bits))) 9 | 10 | 11 | def hash(data): 12 | hashcalc = 75569 13 | 14 | for pointer in range(0, len(data), 4): 15 | if len(data) - pointer < 4: 16 | break 17 | shift_calc = data[pointer+0] | (data[pointer+1] << 8) | (data[pointer+2] << 16) | data[pointer+3] << 24 18 | hashcalc = (5 * rol(hashcalc ^ (0x27D4EB4F * ((0xE5438000 * shift_calc) | ((0x85EBCA87 * shift_calc & 0xFFFFFFFF) >> 17))), 13, 32))-1640531463 & 0xFFFFFFFF 19 | else: 20 | pointer = len(data) 21 | remainder = len(data) - pointer 22 | 23 | if remainder: 24 | remainder_bytes = int.from_bytes(data[-remainder:], 'little') 25 | else: 26 | remainder_bytes = 0 27 | 28 | rem_or = (0x27D4EB4F * ((0xE5438000 * remainder_bytes & 0xFFFFFFFF) | ((0x85EBCA87 * remainder_bytes & 0xFFFFFFFF) >> 17))) & 0xFFFFFFFF ^ (hashcalc ^ len(data)) 29 | 30 | rem_hash = (0x165667C5 * ((0xC2B2AE63 * (rem_or ^ (rem_or >> 16)) & 0xFFFFFFFF) ^ ((0xC2B2AE63 * (rem_or ^ (rem_or >> 16)) & 0xFFFFFFFF) >> 13)) & 0xFFFFFFFF) 31 | rem_hash = rem_hash ^ (rem_hash >> 16) 32 | 33 | return rem_hash -------------------------------------------------------------------------------- /algorithms/danabot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | Danabot API hashing algorithm. 5 | 6 | Reference: https://malwareandstuff.com/deobfuscating-danabots-api-hashing/ 7 | """ 8 | TYPE = 'unsigned_int' 9 | TEST_1 = 41476489 10 | 11 | 12 | def hash(data): 13 | hash_val = 0 14 | 15 | i = 0 16 | data_len = len(data) 17 | while i < data_len: 18 | begin_chr = data[i] 19 | begin_chr_upper = ord(chr(begin_chr).upper()) 20 | 21 | if i == data_len - 1: 22 | end_chr = data[0] 23 | else: 24 | end_chr = data[data_len - i - 2] 25 | end_chr_upper = ord(chr(end_chr).upper()) 26 | 27 | v16 = (begin_chr ^ data_len) & 0xffffffff 28 | v18 = (end_chr ^ data_len) & 0xffffffff 29 | v17 = (begin_chr_upper ^ data_len) & 0xffffffff 30 | v15 = (end_chr_upper ^ data_len) & 0xffffffff 31 | 32 | hash_val = (v15 ^ (hash_val + v17 * v18 * v16)) & 0xffffffff 33 | 34 | i += 1 35 | 36 | return hash_val 37 | -------------------------------------------------------------------------------- /algorithms/deedrat.py: -------------------------------------------------------------------------------- 1 | # Created by Still Hsu 2 | 3 | DESCRIPTION = "Hashing algorithm used by newer variants of DeedRAT." 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 1761596967 6 | 7 | 8 | def hash(data): 9 | i = 0 10 | ecx = 0 11 | eax = 0 12 | edi = 0 13 | esi = 0 14 | for c in data: 15 | i = i+1 16 | if c < 0x61: 17 | edi = c+0x20 18 | else: 19 | edi = c 20 | ecx = esi 21 | eax = esi 22 | if i & 1 != 0: 23 | ecx = (ecx << 0x5) & 0xffffffff 24 | eax = (eax >> 0x1) & 0xffffffff 25 | ecx = ecx ^ eax 26 | ecx = ecx ^ edi 27 | else: 28 | ecx = (ecx << 0x9) & 0xffffffff 29 | eax = (eax >> 0x3) & 0xffffffff 30 | ecx = ecx ^ eax 31 | ecx = ecx ^ edi 32 | ecx = ~(ecx) & 0xffffffff 33 | esi = esi ^ ecx 34 | return esi 35 | -------------------------------------------------------------------------------- /algorithms/deedrat_export_name.py: -------------------------------------------------------------------------------- 1 | # Created by Still Hsu 2 | 3 | DESCRIPTION = "Hashing algorithm for library export name used by DeedRAT." 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 1493252751 6 | 7 | 8 | def hash(data): 9 | i = 0 10 | ecx = 0 11 | eax = 0 12 | edi = 0 13 | esi = 0 14 | for c in data: 15 | i = i+1 16 | edi = c 17 | ecx = esi 18 | eax = esi 19 | if i & 1 != 0: 20 | ecx = (ecx << 0x5) & 0xffffffff 21 | eax = (eax >> 0x1) & 0xffffffff 22 | ecx = ecx ^ eax 23 | ecx = ecx ^ edi 24 | else: 25 | ecx = (ecx << 0x9) & 0xffffffff 26 | eax = (eax >> 0x3) & 0xffffffff 27 | ecx = ecx ^ eax 28 | ecx = ecx ^ edi 29 | ecx = ~(ecx) & 0xffffffff 30 | esi = esi ^ ecx 31 | return esi & 0x7fffffff 32 | -------------------------------------------------------------------------------- /algorithms/djb2_lowercase.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "A variant of the DJB2 hash algorithm that converts uppercase letters to lowercase" 4 | 5 | TYPE = 'unsigned_int' 6 | 7 | TEST_1 = 0xd87d4bef 8 | 9 | 10 | def hash(data): 11 | hash_value = 0x624 12 | for char in data: 13 | if 0x41 <= char <= 0x5A: 14 | char += 0x20 15 | hash_value = (hash_value * 33 + char) & 0xFFFFFFFF 16 | return hash_value 17 | -------------------------------------------------------------------------------- /algorithms/djb2_nokoyawa.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Variant of djb2 hash in use by Nokoyawa ransomware" 4 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 5 | TYPE = 'unsigned_int' 6 | # Test must match the exact has of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 7 | TEST_1 = 3792689168 8 | 9 | 10 | def hash(data): 11 | generated_hash = 5381 12 | for b in data: 13 | generated_hash = (generated_hash * 33 + (b if b < 0x61 else (b - 0x20))) & 0xFFFFFFFF 14 | return generated_hash 15 | -------------------------------------------------------------------------------- /algorithms/djb2_uppercase.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "A variant of the DJB2 hash algorithm that converts lowercase letters to uppercase" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 0x07AB31C2 6 | 7 | def hash(data): 8 | hash_value = 4919 9 | for char in data: 10 | if isinstance(char, int): 11 | char = chr(char) 12 | if ord('a') <= ord(char) <= ord('z'): 13 | char = chr(ord(char) - 32) 14 | hash_value = (hash_value * 33) + ord(char) 15 | return hash_value & 0xFFFFFFFF 16 | -------------------------------------------------------------------------------- /algorithms/djb2_vohuk_ransomware_dec_2022.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Vohuk Ransomware's variant of DJB2 as of December 2022" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 1274984080 6 | 7 | 8 | def hash(data: bytearray) -> int: 9 | hash = 0x1505 10 | for b in data: 11 | if ((b - 0x41) & 0xFFFFFFFF) < 0x20: 12 | b += 0x20 13 | hash += b + ((0x20 * hash) & 0xFFFFFFFF) 14 | hash &= 0xFFFFFFFF 15 | return hash 16 | -------------------------------------------------------------------------------- /algorithms/dualacc_modfff1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "DUALACC and MOD 0xfff1" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2329613580 26 | 27 | 28 | def hash(data): 29 | v4, v8 = 0, 1 30 | for ltr in data: 31 | v8 = (ltr + v8) % 0x0FFF1 32 | v4 = (v4 + v8) % 0x0FFF1 33 | return (v4 << 0x10) | v8 34 | -------------------------------------------------------------------------------- /algorithms/emotet.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | DESCRIPTION = "Emotet November 2021" 3 | TYPE = 'unsigned_int' 4 | TEST_1 = 3172443423 5 | 6 | 7 | def hash(data): 8 | hash_value = 0 9 | for i in range(len(data)): 10 | hash_value = (((hash_value << 16) & 0xffffffff) 11 | + ((hash_value << 6) & 0xffffffff) 12 | + data[i] - hash_value) & 0xffffffff 13 | return hash_value 14 | -------------------------------------------------------------------------------- /algorithms/emotet_mul_65599_xor_19ad760.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | 5 | Author = rfLENtlr 6 | 7 | This algorithm was used by Emotet. 8 | 9 | Sample SHA256: 5d267403191a8786db2062584f298478ba59aa7b4d23adcf850a2c14a55c6d97 10 | 11 | """ 12 | TYPE = 'unsigned_int' 13 | TEST_1 = 3163386495 14 | 15 | def hash(data): 16 | hash_value = 0 17 | for c in data: 18 | hash_value = (c + hash_value * 0x1003f) & 0xFFFFFFFF 19 | return hash_value ^ 0x19ad760 -------------------------------------------------------------------------------- /algorithms/fnv1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | DESCRIPTION = "FNV1 hash" 3 | TYPE = 'unsigned_int' 4 | TEST_1 = 116207608 5 | 6 | 7 | def hash(data): 8 | val = 0x811c9dc5 9 | for c in data: 10 | val = ((0x1000193 * val) ^ c) & 0xffffffff 11 | return val 12 | -------------------------------------------------------------------------------- /algorithms/fnv1_64.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | DESCRIPTION = "FNV1 hash (64-bit)" 3 | TYPE = 'unsigned_long' 4 | TEST_1 = 10612290624328353880 5 | 6 | 7 | def hash(data): 8 | val = 0xcbf29ce484222325 9 | for c in data: 10 | val = ((0x100000001b3 * val) ^ c) & 0xffffffffffffffff 11 | return val 12 | -------------------------------------------------------------------------------- /algorithms/fnv1_xor67f.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "FNV1 and XOR 67 observed in Neutrino Bot launcher" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2603337777 26 | 27 | 28 | def hash(data): 29 | val = 0x811c9dc5 30 | for c in data: 31 | val = (0x1000193 * (c ^ val)) & 0xffffffff 32 | return val ^ 0x67f 33 | -------------------------------------------------------------------------------- /algorithms/fnv1a.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | DESCRIPTION = "FNV1a hash" 3 | TYPE = 'unsigned_int' 4 | TEST_1 = 2603339342 5 | 6 | 7 | def hash(data): 8 | val = 0x811c9dc5 9 | for c in data: 10 | val = (0x1000193 * (c ^ val)) & 0xffffffff 11 | return val 12 | -------------------------------------------------------------------------------- /algorithms/fnv1a_64.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | DESCRIPTION = "FNV1a hash (64-bit)" 3 | TYPE = 'unsigned_long' 4 | TEST_1 = 14074705352429455374 5 | 6 | 7 | def hash(data): 8 | val = 0xcbf29ce484222325 9 | for c in data: 10 | val = (0x100000001b3 * (c ^ val)) & 0xffffffffffffffff 11 | return val 12 | -------------------------------------------------------------------------------- /algorithms/guloader_3C389ABC.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Guloader hash with seed 0x1505 and XOR 0x3C389ABC" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 2819429408 6 | 7 | 8 | def hash(data): 9 | out_hash = 0x1505 10 | for c in data: 11 | out_hash = ((c + 33 * out_hash) ^ 0x3C389ABC) & 0xffffffff 12 | return out_hash 13 | -------------------------------------------------------------------------------- /algorithms/lockbit3_C8B32494_s0.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | Modified ROR13 add algo used in the Lockbit 3.0 with a seed of 0x0 5 | and a hard coded hash start of 0xC8B32494 6 | 7 | Reference: https://c3rb3ru5d3d53c.github.io/malware-blog/lockbit-v3-api-hashing/ 8 | """ 9 | TYPE = 'unsigned_int' 10 | TEST_1 = 4294967294 11 | TEST_API_DATA_1 = b'kernel32.dllFindFirstFileExW' 12 | TEST_API_1 = 0xaae0cefb ^ 0x29009fe6 13 | 14 | 15 | def ror(n, rotations=1, width=32): 16 | return (2**width-1) & (n >> rotations | n << (width-rotations)) 17 | 18 | 19 | def hash_algo(string, seed): 20 | string = string + b'\x00' 21 | result = 0xC8B32494 ^ seed 22 | for c in string: 23 | result = ror(result, rotations=0x0d, width=32) 24 | result = (result + c) & 0xffffffff 25 | if c == 0x00: 26 | break 27 | return result 28 | 29 | 30 | def hash(data): 31 | # This selects for only the wordlist in hashdb with 32 | # the format _ 33 | if len(data.split(b'.dll')) != 2: 34 | return 0xfffffffe 35 | dll_name, api_name = data.split(b'.dll') 36 | dll_name = dll_name + b'.dll' 37 | print(f"dll: {dll_name}, api: {api_name}") 38 | seed = 0 39 | dll_hash = hash_algo(dll_name, seed) 40 | tmp_hash = hash_algo(api_name, dll_hash) 41 | return ~tmp_hash & 0xffffffff 42 | -------------------------------------------------------------------------------- /algorithms/lockbit3_C8B32494_string.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | Modified ROR13 add algo used in the Lockbit 3.0 with a seed of 0x0 5 | and a hard coded hash start of 0xC8B32494 this is for strings only 6 | 7 | Reference: https://c3rb3ru5d3d53c.github.io/malware-blog/lockbit-v3-api-hashing/ 8 | """ 9 | TYPE = 'unsigned_int' 10 | TEST_1 = 1345844799 11 | 12 | 13 | def ror(n, rotations=1, width=32): 14 | return (2**width-1) & (n >> rotations | n << (width-rotations)) 15 | 16 | 17 | def hash_algo(string, seed): 18 | result = 0xC8B32494 ^ seed 19 | string += b'\x00' 20 | for c in string: 21 | result = ror(result, rotations=0x0d, width=32) 22 | result = (result + c) & 0xffffffff 23 | if c == 0x00: 24 | break 25 | return result 26 | 27 | 28 | def hash(data): 29 | seed = 0 30 | string_hash = hash_algo(data, seed) 31 | return string_hash 32 | -------------------------------------------------------------------------------- /algorithms/lockbit4_0225.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | Author = 0x0d4y 5 | Description: This is the Hash algorithm that was implemented in the new version of Lockbit, Lockbit Green or Lockbit4.0, with the aim of resolving DLLs and APIs dynamically. 6 | Sample MD5: 15796971D60F9D71AD162060F0F76A02 7 | The value of the Hash contained in TEST_1, was the result of the string: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" 8 | Reference: https://0x0d4y.blog/lockbit4-0-evasion-tales/ 9 | """ 10 | TYPE = 'unsigned_int' 11 | TEST_1 = 3370265577 12 | 13 | def hash(data): 14 | if isinstance(data, bytes): 15 | data = data.decode('utf-8') 16 | 17 | MASK_32BIT = 0xffffffff 18 | hash_value = 0x14bf 19 | char_index = 0 20 | 21 | for char in data: 22 | char_code = ord(char) 23 | 24 | if 0x41 <= char_code <= 0x5A: 25 | normalized_char = (char_code + 0x20) & MASK_32BIT 26 | else: 27 | normalized_char = char_code 28 | 29 | if char_index == 0: 30 | index_modifier = 0 31 | else: 32 | index_modifier = (char_index ^ 0x14bf) & MASK_32BIT 33 | 34 | hash_value = (index_modifier * (((char_index + 0x14bf) * normalized_char + (hash_value ^ normalized_char)) & MASK_32BIT) + normalized_char) & MASK_32BIT 35 | 36 | char_index += 1 37 | 38 | return hash_value -------------------------------------------------------------------------------- /algorithms/lokibot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | Author= IlFranz 5 | 6 | This algorithm was used by Loki/LokiBot for API hashing 7 | 8 | Sample SHA256: 75af30d10a4a60bb1b260a0f4f9e3410448bd81328737678937145aa88eee108 9 | """ 10 | TYPE = 'unsigned_int' 11 | 12 | TEST_1 = 4064566081 13 | 14 | 15 | def hash(data): 16 | hash_value = 0xFFFFFFFF 17 | for char in data: 18 | hash_value ^= char 19 | for _ in range(8): 20 | if hash_value & 1: 21 | hash_value ^= 0x4358AD54 22 | hash_value >>= 1 23 | return ~hash_value & 0xFFFFFFFF -------------------------------------------------------------------------------- /algorithms/lumma_fnv1a.py: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "FNV1a hash with LummaStealer offset, seen in 0cf55c7e1a19a0631b0248fb0e699bbec1d321240208f2862e37f6c9e75894e7" 2 | TYPE = 'unsigned_int' 3 | TEST_1 = 2983287169 4 | 5 | def hash(data): 6 | val = 0x268c190a 7 | for c in data: 8 | val = ((val ^ c) * 0x1000193) & 0xffffffff 9 | 10 | return val 11 | -------------------------------------------------------------------------------- /algorithms/mamon_hash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | DESCRIPTION = "Custom hash used in mamon ransomware" 3 | TYPE = 'unsigned_int' 4 | TEST_1 = 3726794573 5 | 6 | def hash(data): 7 | hash_value = 0x42 8 | 9 | for b in data: 10 | hash_value = ((hash_value * 33) + b) & 0xFFFFFFFF # Keep it 32-bit 11 | 12 | return hash_value 13 | -------------------------------------------------------------------------------- /algorithms/metasploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | Metasploit ROR13 hash used in a lot of shellcode. 5 | Reference https://github.com/rapid7/metasploit-framework/blob/master/external/source/shellcode/windows/x86/src/hash.py 6 | """ 7 | TYPE = 'unsigned_int' 8 | TEST_1 = 4294967294 9 | TEST_API_DATA_1 = 'K\x00E\x00R\x00N\x00E\x00L\x003\x002\x00.\x00D\x00L\x00L\x00\x00\x00LoadLibraryA\x00' 10 | TEST_API_1 = 119961420 11 | 12 | 13 | def ror(dword, bits): 14 | return (dword >> bits | dword << (32 - bits)) & 0xFFFFFFFF 15 | 16 | 17 | def hash(data): 18 | if b'\x00\x00\x00' not in data: 19 | return 0xfffffffe 20 | module, api = data.split(b'\x00\x00\x00') 21 | module += b'\x00\x00\x00' 22 | module_hash = 0 23 | api_hash = 0 24 | for c in module: 25 | module_hash = ror(module_hash, 13) 26 | module_hash += c 27 | for c in api: 28 | api_hash = ror(api_hash, 13) 29 | api_hash += c 30 | h = module_hash + api_hash & 0xFFFFFFFF 31 | return h 32 | -------------------------------------------------------------------------------- /algorithms/mul21_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "MULTIPLY 21 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 1555243728 26 | 27 | 28 | def hash(data): 29 | val = 0x1505 30 | for i in data: 31 | val = (val * 0x21) & 0xFFFFFFFF 32 | val = (val + (i & 0xFFFFFFDF)) & 0xFFFFFFFF 33 | return val 34 | -------------------------------------------------------------------------------- /algorithms/mul21_add_seed_8952.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "MULTIPLY 0x21 and ADD (seed 8952), used in PikaBot in February 2024" 4 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 5 | TYPE = 'unsigned_int' 6 | # Test must match the exact hash of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 7 | TEST_1 = 0xDD4DE543 8 | 9 | 10 | def hash(data): 11 | h = 8952 12 | for c in data: 13 | if c > 96: 14 | c -= 0x20 15 | h = (c + 0x21*h) & 0xFFFFFFFF 16 | return h 17 | -------------------------------------------------------------------------------- /algorithms/mul7_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2022 quangnh89 4 | # 5 | # Win32/Tinba API hashing algorithm. 6 | # 7 | # https://www.virustotal.com/gui/file/ce9483f6284903d8d76d60f1a96b3ade33c77ded0cac1d1c2dc8979879d6f91e 8 | # 9 | ######################################################################## 10 | 11 | DESCRIPTION = """ 12 | MULTIPLY 7 and ADD. 13 | Used in Darkside Win32/Tinba API hash.""" 14 | TYPE = 'unsigned_int' 15 | TEST_1 = 2894658687 16 | 17 | 18 | def hash(data): 19 | val = 0x0 20 | for i in data: 21 | val = (val * 0x7) & 0xFFFFFFFF 22 | val = (val + (i & 0xFF)) & 0xFFFFFFFF 23 | return val 24 | -------------------------------------------------------------------------------- /algorithms/mul83_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "MULTIPLY 0x83 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 150583839 26 | 27 | 28 | def hash(data): 29 | val = 0 30 | for i in data: 31 | val = val * 131 32 | val += i 33 | val = val & 0xFFFFFFFF 34 | return val 35 | -------------------------------------------------------------------------------- /algorithms/mult21_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "MULTIPLY 21 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 749094795 26 | 27 | 28 | def hash(data): 29 | acc = 0 30 | for i in data: 31 | acc = 0xffffffff & (acc * 0x21) 32 | acc = 0xffffffff & (acc + i) 33 | return acc 34 | -------------------------------------------------------------------------------- /algorithms/mult21_add_170f.py: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "MULTIPLY 21 and ADD (0x170F base)" 2 | TYPE = 'unsigned_int' 3 | TEST_1 = 4233774810 4 | 5 | 6 | def hash(data): 7 | hash_value = 0x170F 8 | for byte in data: 9 | hash_value = (hash_value * 0x21 + byte) & 0xFFFFFFFF 10 | return hash_value 11 | -------------------------------------------------------------------------------- /algorithms/mult3_add_init_9C.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "MULTIPLY 3 and ADD, starting key 0x9C" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 3481051867 6 | 7 | 8 | def hash(data): 9 | key = 0x9C 10 | for byte in data: 11 | dword = byte & 0xffffffff 12 | key = (key * 3) & 0xffffffff 13 | key = (key + dword) & 0xffffffff 14 | return key 15 | -------------------------------------------------------------------------------- /algorithms/murmur2_lummas_v3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = """ 4 | MurMurhash2 used in LummaStealer v3.0 5 | seed 0x20 6 | Reference: https://github.com/abrandoned/murmur2/blob/master/MurmurHash2.c" 7 | """ 8 | 9 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 10 | TYPE = 'unsigned_int' 11 | # Test must match the exact hash of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 12 | TEST_1 = 1874473983 13 | 14 | 15 | def hash(data): 16 | fun_len = len(data) 17 | seed = 0x20 18 | new_index = 0 19 | i = 0 20 | seeded_len = (fun_len ^ seed) 21 | if fun_len > 4: 22 | shifted_len = fun_len >> 2 & 0xFFFFFFFF 23 | fun_len = fun_len - (4 * (fun_len >> 2)) & 0xFFFFFFFF 24 | for i in range(0, len(data), 4): 25 | if shifted_len != 0: 26 | shifted_len = shifted_len - 1 27 | seeded_len = (seeded_len * 0x5BD1E995) & 0xFFFFFFFF 28 | ecx = ((((((data[i+3] << 8) | data[i+2]) << 8) | data[i+1]) << 8 | data[i]) * 0x5BD1E995) & 0xFFFFFFFF 29 | eax = ecx 30 | eax = eax >> 0x18 & 0xFFFFFFFF 31 | eax = (eax ^ ecx) & 0xFFFFFFFF 32 | ecx = (eax * 0x5BD1E995) & 0xFFFFFFFF 33 | seeded_len = (seeded_len ^ ecx) & 0xFFFFFFFF 34 | new_index = i 35 | if (fun_len - 1) == 0: 36 | eax = (data[new_index] ^ seeded_len) & 0xFFFFFFFF 37 | seeded_len = (eax * 0x5BD1E995) & 0xFFFFFFFF 38 | return eax 39 | elif (fun_len - 2) == 0: 40 | eax = (data[new_index+1] << 8) & 0xFFFFFFFF 41 | seeded_len = seeded_len ^ eax 42 | eax = data[new_index] 43 | eax = eax ^ seeded_len 44 | seeded_len = (eax * 0x5BD1E995) & 0xFFFFFFFF 45 | 46 | elif (fun_len - 3) != 0: 47 | pass 48 | else: 49 | eax = data[new_index+2] 50 | eax = eax << 0x10 & 0xFFFFFFFF 51 | seeded_len = (seeded_len ^ eax) & 0xFFFFFFFF 52 | eax = data[new_index+1] 53 | eax = (eax << 8) & 0xFFFFFFFF 54 | seeded_len = (seeded_len ^ eax) & 0xFFFFFFFF 55 | eax = data[new_index] 56 | eax = eax ^ seeded_len 57 | seeded_len = (eax * 0x5BD1E995) & 0xFFFFFFFF 58 | eax = seeded_len 59 | eax = eax >> 0xD & 0xFFFFFFFF 60 | eax = eax ^ seeded_len 61 | ecx = (eax * 0x5BD1E995) & 0xFFFFFFFF 62 | eax = ecx 63 | eax = (eax >> 0xF) & 0xFFFFFFFF 64 | eax = eax ^ ecx 65 | return eax 66 | -------------------------------------------------------------------------------- /algorithms/mythic_unknown.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "API hash find in an unknown Mythic agent, need a XOR key" 4 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 5 | TYPE = "unsigned_int" 6 | # Test must match the exact has of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 7 | TEST_1 = 3762100525 8 | 9 | 10 | def hash(data): 11 | crc = 0xffffffff 12 | for val in data: 13 | for _ in range(8): 14 | tmp = crc 15 | crc = crc >> 1 & 0xffffffff 16 | if (val ^ tmp) & 1 != 0: 17 | crc ^= 0xedb88320 18 | val = val >> 1 & 0xffffffff 19 | return crc 20 | -------------------------------------------------------------------------------- /algorithms/or20_xor_rol19.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "OR 0x20 and XOR and ROL 19" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 0x186f3f38 6 | 7 | 8 | ROTATE_BITMASK = { 9 | 8: 0xff, 10 | 16: 0xffff, 11 | 32: 0xffffffff, 12 | 64: 0xffffffffffffffff, 13 | } 14 | 15 | 16 | def rol(inVal, numShifts, dataSize=32): 17 | '''rotate left instruction emulation''' 18 | if numShifts == 0: 19 | return inVal 20 | if (numShifts < 0) or (numShifts > dataSize): 21 | raise ValueError('Bad numShifts') 22 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 23 | raise ValueError('Bad dataSize') 24 | bitMask = ROTATE_BITMASK[dataSize] 25 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 26 | 27 | 28 | def hash(data): 29 | val = 0xffffffff 30 | ors = 0 31 | for i in data: 32 | ors = i | 32 33 | val = ors ^ rol(val, 19, 32) 34 | return val 35 | -------------------------------------------------------------------------------- /algorithms/or21_xor_rol11.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "OR 0x21 and XOR and ROL 11" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 1303693098 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | ors = 0 51 | for i in data: 52 | ors = i | 33 53 | val = val ^ ors 54 | val = rol(val, 0xb, 32) 55 | return val 56 | -------------------------------------------------------------------------------- /algorithms/or23_xor_rol17.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "OR 0x23 and XOR and ROL 17" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2135044757 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | ors = 0 51 | for i in data: 52 | ors = i | 35 53 | val = val ^ ors 54 | val = rol(val, 0x11, 32) 55 | return val 56 | -------------------------------------------------------------------------------- /algorithms/paradise_murmurhash3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Paradise ransomware implementation of MurmurHash3 with custom seed (0xDEADC0DE) - adapted from https://github.com/wc-duck/pymmh3" 4 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 5 | TYPE = 'unsigned_int' 6 | # Test must match the exact has of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 7 | TEST_1 = 1653390361 8 | 9 | 10 | def hash(data): 11 | 12 | import sys as _sys 13 | if (_sys.version_info > (3, 0)): 14 | def xrange(a, b, c): 15 | return range(a, b, c) 16 | 17 | def xencode(x): 18 | if isinstance(x, bytes) or isinstance(x, bytearray): 19 | return x 20 | else: 21 | return x.encode() 22 | else: 23 | 24 | def xencode(x): 25 | return x 26 | del _sys 27 | 28 | data = bytearray(xencode(data)) 29 | 30 | def fmix(h): 31 | h ^= h >> 16 32 | h = (h * 0x85ebca6b) & 0xFFFFFFFF 33 | h ^= h >> 13 34 | h = (h * 0xc2b2ae35) & 0xFFFFFFFF 35 | h ^= h >> 16 36 | return h 37 | 38 | length = len(data) 39 | nblocks = int(length / 4) 40 | 41 | seed = 0xDEADC0DE 42 | h1 = seed 43 | 44 | c1 = 0xcc9e2d51 45 | c2 = 0x1b873593 46 | 47 | # body 48 | for block_start in xrange(0, nblocks * 4, 4): 49 | # ??? big endian? 50 | k1 = data[block_start + 3] << 24 | \ 51 | data[block_start + 2] << 16 | \ 52 | data[block_start + 1] << 8 | \ 53 | data[block_start + 0] 54 | 55 | k1 = (c1 * k1) & 0xFFFFFFFF 56 | k1 = (k1 << 15 | k1 >> 17) & 0xFFFFFFFF # inlined ROTL32 57 | k1 = (c2 * k1) & 0xFFFFFFFF 58 | 59 | h1 ^= k1 60 | h1 = (h1 << 13 | h1 >> 19) & 0xFFFFFFFF # inlined ROTL32 61 | h1 = (h1 * 5 + 0xe6546b64) & 0xFFFFFFFF 62 | 63 | # tail 64 | tail_index = nblocks * 4 65 | k1 = 0 66 | tail_size = length & 3 67 | 68 | if tail_size >= 3: 69 | k1 ^= data[tail_index + 2] << 16 70 | if tail_size >= 2: 71 | k1 ^= data[tail_index + 1] << 8 72 | if tail_size >= 1: 73 | k1 ^= data[tail_index + 0] 74 | 75 | if tail_size > 0: 76 | k1 = (k1 * c1) & 0xFFFFFFFF 77 | k1 = (k1 << 15 | k1 >> 17) & 0xFFFFFFFF # inlined ROTL32 78 | k1 = (k1 * c2) & 0xFFFFFFFF 79 | h1 ^= k1 80 | 81 | unsigned_val = fmix(h1 ^ length) 82 | return unsigned_val 83 | -------------------------------------------------------------------------------- /algorithms/permutations_82f63b78.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "SHIFT and XOR with 0x82F63B78" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 1838188878 26 | 27 | 28 | def hash(data): 29 | val = 0 30 | for i in data: 31 | v1 = ((((i | 0x20) ^ val) >> 1) ^ (0x82F63B78 * (((i | 0x20) ^ val) & 1))) & 0xffffffff 32 | v2 = ((((v1 >> 1) ^ (0x82F63B78 * (v1 & 1))) >> 1) ^ (0x82F63B78 * (((v1 >> 1) ^ (0x78 * (v1 & 1))) & 1))) & 0xffffffff 33 | v3 = ((((v2 >> 1) ^ (0x82F63B78 * (v2 & 1))) >> 1) ^ (0x82F63B78 * (((v2 >> 1) ^ (0x78 * (v2 & 1))) & 1))) & 0xffffffff 34 | v4 = ((((v3 >> 1) ^ (0x82F63B78 * (v3 & 1))) >> 1) ^ (0x82F63B78 * (((v3 >> 1) ^ (0x78 * (v3 & 1))) & 1))) & 0xffffffff 35 | val = ((v4 >> 1) ^ (0x82F63B78 * (v4 & 1))) & 0xffffffff 36 | return val ^ 0xBC 37 | -------------------------------------------------------------------------------- /algorithms/permutations_e8677835.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "Multiple permutations of 0xe8677835" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 3113210072 26 | 27 | 28 | def hash(data): 29 | val = 0xFFFFFFFF 30 | for i in data: 31 | val ^= i 32 | for j in range(0, 8): 33 | if (val & 0x1) == 1: 34 | val ^= 0xe8677835 35 | val >>= 1 36 | return val ^ 0xFFFFFFFF 37 | -------------------------------------------------------------------------------- /algorithms/revil_010F.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # REvil API hashing observed in the following samples: 3 | # 12d8bfa1aeb557c146b98f069f3456cc8392863a2f4ad938722cd7ca1a773b39 4 | # 5f56d5748940e4039053f85978074bde16d64bd5ba97f6f0026ba8172cb29e93 5 | # This highly complex Python code is generously placed in the public domain. 6 | # The authors Lars Wallenborn and Jesko Huettenhain yield all copyrights. 7 | # Please use this code responsibly. 8 | 9 | DESCRIPTION = "Lower 21 bits of an LFS with seed 0x2B and multiplier 0x10F" 10 | TYPE = 'unsigned_int' 11 | TEST_1 = 385258 12 | 13 | 14 | def hash(data): 15 | result = 0x2b 16 | for byte in data: 17 | result = result * 0x010F + byte 18 | return result & 0x1fffff 19 | -------------------------------------------------------------------------------- /algorithms/rol3_xor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 3 and XOR" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 831512572 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = rol(val, 0x3, 32) 52 | val = val ^ i 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/rol3_xor_eax.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 3 and XOR EAX" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 1420031752 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | ecx = 0 50 | eax = 0 51 | for i in data: 52 | eax = eax | i 53 | ecx = ecx ^ eax 54 | ecx = rol(ecx, 0x3, 32) 55 | ecx += 1 56 | eax = 0xffffffff & (eax << 8) 57 | return ecx 58 | -------------------------------------------------------------------------------- /algorithms/rol5_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 5 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 4160318296 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = rol(val, 0x5, 32) 52 | val += i 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/rol5_xor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 5 and XOR" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2079179548 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = rol(val, 0x5, 32) 52 | ors = i | 32 53 | val = val ^ ors 54 | return val 55 | -------------------------------------------------------------------------------- /algorithms/rol7_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 7 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2379854656 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = rol(val, 0x7, 32) 52 | val += i 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/rol7_add_xor2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 7 and ADD and XOR 2" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2445849446 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = rol(val, 0x7, 32) 52 | val += (i ^ 2) 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/rol7_xor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 7 and XOR" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2845590054 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = rol(val, 0x7, 32) 52 | val = val ^ (0xff & i) 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/rol8_xor_b0d4d06.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 8 and XOR 0xB0D4D06 used in smoke bot" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2567160022 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = val ^ (i & 0xDF) 52 | val = rol(val, 0x8, 32) 53 | val = val + (i & 0xDF) 54 | return (val ^ 0xB0D4D06) & 0xffffffff 55 | -------------------------------------------------------------------------------- /algorithms/rol9_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 9 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 1175244391 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = rol(val, 0x9, 32) 52 | val += i 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/rol9_xor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 9 and XOR" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 433466918 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = rol(val, 0x9, 32) 52 | val = val ^ i 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/ror11_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROR 11 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 1347818236 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def ror(inVal, numShifts, dataSize=32): 37 | '''rotate right instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = ror(val, 0xb, 32) 52 | val += i 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/ror13_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROR 13 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2879724916 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def ror(inVal, numShifts, dataSize=32): 37 | '''rotate right instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = ror(val, 0xd, 32) 52 | val += i 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/ror13_add_negative_seed.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "ROR 13 and ADD with negative seed" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 2879724788 6 | 7 | 8 | def ROR4(val, r_bits, max_bits): 9 | return ((val & (2**max_bits - 1)) >> r_bits % max_bits) | (val << (max_bits - (r_bits % max_bits)) & (2**max_bits - 1)) 10 | 11 | 12 | def hash(data): 13 | val = 0xffffffff 14 | for i in data: 15 | val = ROR4(val, 0xd, 32) 16 | val += i 17 | return val 18 | -------------------------------------------------------------------------------- /algorithms/ror13_add_sub1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROR 13 and ADD and SUB 1" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2879724915 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def ror(inVal, numShifts, dataSize=32): 37 | '''rotate right instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = ror(val, 0xd, 32) 52 | val += i 53 | return (val - 1) & 0xffffffff 54 | -------------------------------------------------------------------------------- /algorithms/ror13_add_sub20.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROR 13 and ADD and SUB 0x20" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 3425182084 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def ror(inVal, numShifts, dataSize=32): 37 | '''rotate right instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = ror(val, 0xd, 32) 52 | if i < 97: 53 | val = (val & 0xffffffff) + i 54 | else: 55 | val = ((val & 0xffffffff) + i - 32) & 0xffffffff 56 | return val 57 | -------------------------------------------------------------------------------- /algorithms/ror7_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROR 7 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 1892787106 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def ror(inVal, numShifts, dataSize=32): 37 | '''rotate right instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = ror(val, 0x7, 32) 52 | val += i 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/ror8_add_xor_ab832e83.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Hash based on ror8, add, xor with initial state 0x832E83AB" 4 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 5 | TYPE = 'unsigned_int' 6 | # Test must match the exact has of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 7 | TEST_1 = 0x828E7DBD 8 | 9 | 10 | ROTATE_BITMASK = { 11 | 8: 0xff, 12 | 16: 0xffff, 13 | 32: 0xffffffff, 14 | 64: 0xffffffffffffffff, 15 | } 16 | 17 | 18 | def ror(inVal, numShifts, dataSize=32): 19 | '''rotate right instruction emulation''' 20 | if numShifts == 0: 21 | return inVal 22 | if (numShifts < 0) or (numShifts > dataSize): 23 | raise ValueError('Bad numShifts') 24 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 25 | raise ValueError('Bad dataSize') 26 | bitMask = ROTATE_BITMASK[dataSize] 27 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 28 | 29 | 30 | def hash(data): 31 | state = 0x832E83AB 32 | for i in range(len(data)): 33 | val = ror(state, 8) 34 | if i < len(data) - 1: 35 | val += data[i] | data[i + 1] << 8 36 | else: 37 | val += data[i] 38 | state ^= val 39 | return state 40 | -------------------------------------------------------------------------------- /algorithms/ror9_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROR 9 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 3168699451 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def ror(inVal, numShifts, dataSize=32): 37 | '''rotate right instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal >> numShifts) | (inVal << (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = ror(val, 0x9, 32) 52 | val += i 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/sdbm_65599_x64.py: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "The original SDBM hash function with the constant 65599. Used by Emotet malware." 2 | TYPE = 'unsigned_long' 3 | TEST_1 = 18326187587583583519 4 | 5 | 6 | def hash(data): 7 | hsh = 0 8 | for d in data: 9 | hsh = d + 0x1003f * hsh 10 | return hsh & 0xffffffffffffffff 11 | -------------------------------------------------------------------------------- /algorithms/shl1_add.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "SHIFT LEFT 1 and ADD" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 4294944522 26 | 27 | 28 | def hash(data): 29 | val = 0 30 | for i in data: 31 | b = i 32 | b = 0xff & (b | 0x60) 33 | val = val + b 34 | val = val << 1 35 | val = 0xffffffff & val 36 | return val 37 | -------------------------------------------------------------------------------- /algorithms/shl7_shr19_xor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "SHIFT LEFT 7 and SHIFT RIGHT 19 and XOR" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 1112293927 26 | 27 | 28 | def hash(data): 29 | val = 0 30 | for i in data: 31 | edx = 0xffffffff & (val << 7) 32 | ecx = 0xffffffff & (val >> 0x19) 33 | eax = edx | ecx 34 | t = 0xff & (i ^ 0xf4) 35 | val = eax ^ t 36 | return val 37 | -------------------------------------------------------------------------------- /algorithms/shl7_sub.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "SHIFT LEFT 7 and SUB used in DoublePulsar backdoor" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2493113697 26 | 27 | 28 | def hash(data): 29 | eax = 0 30 | edi = 0 31 | for i in data: 32 | edi = 0xffffffff & (eax << 7) 33 | eax = 0xffffffff & (edi - eax) 34 | eax = eax + (0xff & i) 35 | edi = 0xffffffff & (eax << 7) 36 | eax = 0xffffffff & (edi - eax) 37 | return eax 38 | -------------------------------------------------------------------------------- /algorithms/shr1_shl7_2326.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "Seed 0x2326 shift right 1 shift left 7" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 0x9bfc4734 6 | 7 | 8 | def hash(data): 9 | out = 0x2326 10 | for c in data: 11 | out = (out + c + ((out >> 1) | (out << 7))) & 0xffffffff 12 | return out 13 | -------------------------------------------------------------------------------- /algorithms/shr2_shl5_xor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "SHIFT RIGHT 2 and SHIFT LEFT 5 and XOR" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 629383115 26 | 27 | 28 | def hash(data): 29 | result = 0x4e67c6a7 30 | if data.startswith(b"Nt") or data.startswith(b"Zw"): 31 | data = data[2:] 32 | for i in data: 33 | result ^= (i + (result >> 2) + (result << 5)) & 0xffffffff 34 | return result 35 | -------------------------------------------------------------------------------- /algorithms/shr2_shl5_xor_init_c4d5a97a_stealbit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "SHIFT RIGHT 2 and SHIFT LEFT 5 and XOR with initialization constant 0xc4d5a97a used in Stealbit malware." 4 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 5 | TYPE = 'unsigned_int' 6 | # Test must match the exact has of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 7 | TEST_1 = 4099635895 8 | 9 | 10 | def hash(data): 11 | 12 | # Initialize the hash value to 0xc4d5a97a 13 | func_hash = 0xc4d5a97a 14 | 15 | # Iterate through input string bytes and update the 16 | # hash value 17 | for b in data: 18 | func_hash ^= ((func_hash >> 2) + ((func_hash << 5) + b)) & 0xFFFFFFFF 19 | 20 | return func_hash 21 | -------------------------------------------------------------------------------- /algorithms/smokeloader_rol8_xor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "ROL 8 and XOR used in smoke bot" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2450427344 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = val ^ (i & 0xDF) 52 | val = rol(val, 0x8, 32) 53 | val = val + (i & 0xDF) 54 | return val & 0xffffffff 55 | -------------------------------------------------------------------------------- /algorithms/tonepipeshell.py: -------------------------------------------------------------------------------- 1 | # Created by Still Hsu 2 | 3 | DESCRIPTION = "TOnePipeShell hash with seed 0xC85E31 (13131313)" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 3454880715 6 | 7 | def hash(data): 8 | out_hash = 0 9 | for c in data: 10 | out_hash = (c + 0xC85E31 * out_hash) & 0xffffffff 11 | return out_hash -------------------------------------------------------------------------------- /algorithms/tonepipeshell_alt.py: -------------------------------------------------------------------------------- 1 | # Created by Still Hsu 2 | 3 | DESCRIPTION = "TOnePipeShell hash with seed 0x4E44CB31 (1313131313)" 4 | TYPE = 'unsigned_int' 5 | TEST_1 = 3702427595 6 | 7 | def hash(data): 8 | out_hash = 0 9 | for c in data: 10 | out_hash = (c + 0x4E44CB31 * out_hash) & 0xffffffff 11 | return out_hash 12 | -------------------------------------------------------------------------------- /algorithms/tonepipeshell_feb_2025.py: -------------------------------------------------------------------------------- 1 | DESCRIPTION = "TOnePipeShell hash with seed 0x14096B (1313131)" 2 | TYPE = 'unsigned_int' 3 | TEST_1 = 734769215 4 | 5 | def hash(data): 6 | out_hash = 0 7 | for c in data: 8 | out_hash = (c + 0x14096B * out_hash) & 0xffffffff 9 | return out_hash -------------------------------------------------------------------------------- /algorithms/xor_rol9.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "XOR and ROL 9" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 2891729971 26 | 27 | 28 | ROTATE_BITMASK = { 29 | 8: 0xff, 30 | 16: 0xffff, 31 | 32: 0xffffffff, 32 | 64: 0xffffffffffffffff, 33 | } 34 | 35 | 36 | def rol(inVal, numShifts, dataSize=32): 37 | '''rotate left instruction emulation''' 38 | if numShifts == 0: 39 | return inVal 40 | if (numShifts < 0) or (numShifts > dataSize): 41 | raise ValueError('Bad numShifts') 42 | if (dataSize != 8) and (dataSize != 16) and (dataSize != 32) and (dataSize != 64): 43 | raise ValueError('Bad dataSize') 44 | bitMask = ROTATE_BITMASK[dataSize] 45 | return bitMask & ((inVal << numShifts) | (inVal >> (dataSize-numShifts))) 46 | 47 | 48 | def hash(data): 49 | val = 0 50 | for i in data: 51 | val = val ^ i 52 | val = rol(val, 0x9, 32) 53 | return val 54 | -------------------------------------------------------------------------------- /algorithms/xor_shr8.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ######################################################################## 3 | # Copyright 2012 Mandiant 4 | # Copyright 2014 FireEye 5 | # 6 | # Mandiant licenses this file to you under the Apache License, Version 7 | # 2.0 (the "License"); you may not use this file except in compliance with the 8 | # License. You may obtain a copy of the License at: 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 | # implied. See the License for the specific language governing 16 | # permissions and limitations under the License. 17 | # 18 | # Reference: 19 | # https://github.com/mandiant/flare-ida/blob/master/shellcode_hashes/make_sc_hash_db.py 20 | # 21 | ######################################################################## 22 | 23 | DESCRIPTION = "XOR and SHIFT RIGHT 21" 24 | TYPE = 'unsigned_int' 25 | TEST_1 = 1054536684 26 | 27 | 28 | def hash(data): 29 | val = 0xFFFFFFFF 30 | for i in data: 31 | ci = i 32 | ci = ci ^ val 33 | ci = ci * val 34 | ci_hex = "%16x" % ci 35 | ci_hex = ci_hex[8:16] 36 | ci_hex = int(ci_hex, 16) 37 | shr8 = val >> 8 38 | val = ci_hex ^ shr8 39 | return val & 0xffffffff 40 | -------------------------------------------------------------------------------- /algorithms/zloader_bot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | DESCRIPTION = "API hashing used by the zloader bot on 2021-10-21" 4 | # Type can be either 'unsigned_int' (32bit) or 'unsigned_long' (64bit) 5 | TYPE = 'unsigned_int' 6 | # Test must match the exact has of the string 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' 7 | TEST_1 = 3694482793 8 | 9 | 10 | def hash(data): 11 | generated_hash = 0 12 | for i in range(len(data)): 13 | current_char = data[i] 14 | v17 = (current_char + (generated_hash << 4)) & 0xFFFFFFFF 15 | if v17 & 0xF0000000 != 0: 16 | v10 = (v17 & 0xF0000000) >> 0x18 17 | v18 = v17 & 0xFFFFFFFF 18 | v11 = v18 ^ 0x0FFFFFFF 19 | generated_hash = (v18 & ~v10) | (v10 & v11) 20 | else: 21 | generated_hash = v17 22 | 23 | return generated_hash 24 | -------------------------------------------------------------------------------- /hashdb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """Malware hash library. 5 | """ 6 | import algorithms 7 | 8 | class AlgorithmError(Exception): 9 | pass 10 | 11 | def list_algorithms(): 12 | return list(algorithms.modules.keys()) 13 | 14 | def hash(algorithm_name, data): 15 | if algorithm_name not in list(algorithms.modules.keys()): 16 | raise AlgorithmError("Algorithm not found") 17 | if type(data) == str: 18 | data = data.encode('utf-8') 19 | return algorithms.modules[algorithm_name].hash(data) 20 | -------------------------------------------------------------------------------- /tests/test_algorithms.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def test_sanity(): 5 | import hashdb 6 | 7 | 8 | def test_algorithm_attributes(): 9 | from hashdb import algorithms 10 | for algorithm_name in list(algorithms.modules.keys()): 11 | assert(algorithms.modules[algorithm_name].DESCRIPTION != None) 12 | assert(algorithms.modules[algorithm_name].DESCRIPTION != '') 13 | assert(algorithms.modules[algorithm_name].TYPE != None) 14 | assert(algorithms.modules[algorithm_name].TYPE != '') 15 | assert(algorithms.modules[algorithm_name].TEST_1 != None) 16 | assert(algorithms.modules[algorithm_name].TEST_1 != '') 17 | 18 | 19 | def test_algorithm_hash(): 20 | from hashdb import algorithms 21 | for algorithm_name in list(algorithms.modules.keys()): 22 | assert(algorithms.modules[algorithm_name].TEST_1 == algorithms.modules[algorithm_name].hash(b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')) 23 | 24 | 25 | def test_algorithm_duplicates(): 26 | from hashdb import algorithms 27 | hash_list = [] 28 | for algorithm_name in list(algorithms.modules.keys()): 29 | # Skip custom API hashes 30 | if 'TEST_API_1' not in dir(algorithms.modules[algorithm_name]): 31 | hash_list.append(algorithms.modules[algorithm_name].TEST_1) 32 | assert(len(hash_list) == len(set(hash_list))) 33 | 34 | 35 | def test_custom_api_algorithms(): 36 | from hashdb import algorithms 37 | hash_list = [] 38 | for algorithm_name in list(algorithms.modules.keys()): 39 | # Custom API hashes must have a custom hash and data field 40 | if 'TEST_API_1' in dir(algorithms.modules[algorithm_name]): 41 | assert(algorithms.modules[algorithm_name].TEST_API_1 != None) 42 | assert(algorithms.modules[algorithm_name].TEST_API_1 != '') 43 | assert(algorithms.modules[algorithm_name].TEST_API_DATA_1 != None) 44 | assert(algorithms.modules[algorithm_name].TEST_API_DATA_1 != '') 45 | assert((type(algorithms.modules[algorithm_name].TEST_API_DATA_1) == bytes) or 46 | (type(algorithms.modules[algorithm_name].TEST_API_DATA_1) == str)) 47 | if type(algorithms.modules[algorithm_name].TEST_API_DATA_1) == str: 48 | data = algorithms.modules[algorithm_name].TEST_API_DATA_1.encode('utf-8') 49 | else: 50 | data = algorithms.modules[algorithm_name].TEST_API_DATA_1 51 | assert(algorithms.modules[algorithm_name].TEST_API_1 == algorithms.modules[algorithm_name].hash(data)) 52 | --------------------------------------------------------------------------------