├── .gitignore ├── Advanced-Binary-Deobfuscation.pdf ├── LICENSE ├── README.md ├── hands-on1 ├── Makefile ├── o-llvm.sh ├── src │ ├── test-add.c │ ├── test-hello.c │ ├── test-mod2-add.c │ └── test-mod2.c └── tigress.sh ├── hands-on2 ├── Makefile ├── deadcode_removal.ipynb ├── deadcode_unremoval.ipynb ├── optimizer.ipynb └── solved │ └── deadcode_unremoval.ipynb ├── hands-on3 ├── Makefile ├── anel.zip ├── opfind.ipynb ├── sat_smt.ipynb ├── simple_explore.ipynb ├── simple_explore_smt.ipynb ├── solved │ └── simple_explore_smt.ipynb └── x-tunnel.zip ├── hands-on4 ├── Makefile ├── asprox.zip ├── eqcheck.ipynb ├── solved │ └── eqcheck.ipynb └── vipasana.zip ├── hands-on5 ├── Makefile ├── solved │ └── zeus_get_ir.ipynb ├── vm_explore.ipynb └── zeusvm.zip ├── hands-on6 ├── Makefile ├── cff_dse.ipynb ├── cff_explore.ipynb ├── flattening_volatile.bin └── test-mod2-fla.bin ├── setup.sh └── tigress-docker ├── Dockerfile └── tigress-Linux-x86_64-unstable.zip /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | # For a library or package, you might want to ignore these files since the code is 86 | # intended to run in multiple environments; otherwise, check them in: 87 | .python-version 88 | 89 | # pipenv 90 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 91 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 92 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 93 | # install all needed dependencies. 94 | #Pipfile.lock 95 | 96 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 97 | __pypackages__/ 98 | 99 | # Celery stuff 100 | celerybeat-schedule 101 | celerybeat.pid 102 | 103 | # SageMath parsed files 104 | *.sage.py 105 | 106 | # Environments 107 | .env 108 | .venv 109 | env/ 110 | venv/ 111 | ENV/ 112 | env.bak/ 113 | venv.bak/ 114 | 115 | # Spyder project settings 116 | .spyderproject 117 | .spyproject 118 | 119 | # Rope project settings 120 | .ropeproject 121 | 122 | # mkdocs documentation 123 | /site 124 | 125 | # mypy 126 | .mypy_cache/ 127 | .dmypy.json 128 | dmypy.json 129 | 130 | # Pyre type checker 131 | .pyre/ 132 | 133 | # pytype static type analyzer 134 | .pytype/ 135 | -------------------------------------------------------------------------------- /Advanced-Binary-Deobfuscation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malrev/ABD/0fe01674a4b0f1879f9c36d7b1e76e3c1d670d26/Advanced-Binary-Deobfuscation.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | SOFTWARE LICENSE AGREEMENT FOR EVALUATION 2 | 3 | This SOFTWARE EVALUATION LICENSE AGREEMENT (this "Agreement") is a legal contract between a person who uses or otherwise accesses or installs the Software (“User(s)”), and Nippon Telegraph and Telephone corporation ("NTT"). 4 | READ THE TERMS AND CONDITIONS OF THIS AGREEMENT CAREFULLY BEFORE INSTALLING OR OTHERWISE ACCESSING OR USING NTT'S PROPRIETARY SOFTWARE ACCOMPANIED BY THIS AGREEMENT (the "SOFTWARE"). THE SOFTWARE IS COPYRIGHTED AND IT IS LICENSED TO USER UNDER THIS AGREEMENT, NOT SOLD TO USER. BY INSTALLING OR OTHERWISE ACCESSING OR USING THE SOFTWARE, USER ACKNOWLEDGES THAT USER HAS READ THIS AGREEMENT, THAT USER UNDERSTANDS IT, AND THAT USER ACCEPTS AND AGREES TO BE BOUND BY ITS TERMS. IF AT ANY TIME USER IS NOT WILLING TO BE BOUND BY THE TERMS OF THIS AGREEMENT, USER SHOULD TERMINATE THE INSTALLATION PROCESS, IMMEDIATELY CEASE AND REFRAIN FROM ACCESSING OR USING THE SOFTWARE AND DELETE ANY COPIES USER MAY HAVE. THIS AGREEMENT REPRESENTS THE ENTIRE AGREEMENT BETWEEN USER AND NTT CONCERNING THE SOFTWARE. 5 | 6 | 7 | BACKGROUND 8 | A. NTT is the owner of all rights, including all patent rights, and copyrights in and to the Software and related documentation listed in Exhibit A to this Agreement. 9 | B. User wishes to obtain a royalty free license to use the Software to enable User to evaluate, and NTT wishes to grant such a license to User, pursuant and subject to the terms and conditions of this Agreement. 10 | C. As a condition to NTT's provision of the Software to User, NTT has required User to execute this Agreement. 11 | In consideration of these premises, and the mutual promises and conditions in this Agreement, the parties hereby agree as follows: 12 | 1. Grant of Evaluation License. NTT hereby grants to User, and User hereby accepts, under the terms and conditions of this Agreement, a royalty free, nontransferable and nonexclusive license to use the Software internally for the purposes of testing, analyzing, and evaluating the methods or mechanisms as shown in "Yuma Kurogome, Advanced Binary Obfuscation, Global Cybersecurity Camp v2.0". User may make a reasonable number of backup copies of the Software solely for User's internal use pursuant to the license granted in this Section 1. 13 | 2. Shipment and Installation. NTT will ship or deliver the Software by any method that NTT deems appropriate. User shall be solely responsible for proper installation of the Software. 14 | 3. Term. This Agreement is effective whichever is earlier (i) upon User’s acceptance of the Agreement, or (ii) upon User’s installing, accessing, and using the Software, even if User has not expressly accepted this Agreement. Without prejudice to any other rights, NTT may terminate this Agreement without notice to User. User may terminate this Agreement at any time by User’s decision to terminate the Agreement to NTT and ceasing use of the Software. Upon any termination or expiration of this Agreement for any reason, User agrees to uninstall the Software and destroy all copies of the Software. 15 | 4. Proprietary Rights 16 | (a) The Software is the valuable and proprietary property of NTT, and NTT shall retain exclusive title to this property both during the term and after the termination of this Agreement. Without limitation, User acknowledges that all patent rights and copyrights in the Software shall remain the exclusive property of NTT at all times. User shall use not less than reasonable care in safeguarding the confidentiality of the Software. 17 | (b) USER SHALL NOT, IN WHOLE OR IN PART, AT ANY TIME DURING THE TERM OF OR AFTER THE TERMINATION OF THIS AGREEMENT: (i) SELL, ASSIGN, LEASE, DISTRIBUTE, OR OTHERWISE TRANSFER THE SOFTWARE TO ANY THIRD PARTY; (ii) EXCEPT AS OTHERWISE PROVIDED HEREIN, COPY OR REPRODUCE THE SOFTWARE IN ANY MANNER; OR (iii) ALLOW ANY PERSON OR ENTITY TO COMMIT ANY OF THE ACTIONS DESCRIBED IN (i) THROUGH (ii) ABOVE. 18 | (c) User shall take appropriate action, by instruction, agreement, or otherwise, with respect to its employees permitted under this Agreement to have access to the Software to ensure that all of User's obligations under this Section 4 shall be satisfied. 19 | 5. Indemnity. User shall defend, indemnify and hold harmless NTT, its agents and employees, from any loss, damage, or liability arising in connection with User's improper or unauthorized use of the Software. NTT SHALL HAVE THE SOLE RIGHT TO CONDUCT DEFEND ANY ACTTION RELATING TO THE SOFTWARE. 20 | 6. Disclaimer. THE SOFTWARE IS LICENSED TO USER "AS IS," WITHOUT ANY TRAINING, MAINTENANCE, OR SERVICE OBLIGATIONS WHATSOEVER ON THE PART OF NTT. NTT MAKES NO EXPRESS OR IMPLIED WARRANTIES OF ANY TYPE WHATSOEVER, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY, OF FITNESS FOR A PARTICULAR PURPOSE AND OF NON-INFRINGEMENT ON COPYRIGHT OR ANY OTHER RIGHT OF THIRD PARTIES. USER ASSUMES ALL RISKS ASSOCIATED WITH ITS USE OF THE SOFTWARE, INCLUDING WITHOUT LIMITATION RISKS RELATING TO QUALITY, PERFORMANCE, DATA LOSS, AND UTILITY IN A PRODUCTION ENVIRONMENT. 21 | 7. Limitation of Liability. IN NO EVENT SHALL NTT BE LIABLE TO USER OR TO ANY THIRD PARTY FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING BUT NOT LIMITED TO DAMAGES FOR PERSONAL INJURY, PROPERTY DAMAGE, LOST PROFITS, OR OTHER ECONOMIC LOSS, ARISING IN CONNECTION WITH USER'S USE OF OR INABILITY TO USE THE SOFTWARE, IN CONNECTION WITH NTT'S PROVISION OF OR FAILURE TO PROVIDE SERVICES PERTAINING TO THE SOFTWARE, OR AS A RESULT OF ANY DEFECT IN THE SOFTWARE. THIS DISCLAIMER OF LIABILITY SHALL APPLY REGARD¬LESS OF THE FORM OF ACTION THAT MAY BE BROUGHT AGAINST NTT, WHETHER IN CONTRACT OR TORT, INCLUDING WITHOUT LIMITATION ANY ACTION FOR NEGLIGENCE. USER'S SOLE REMEDY IN THE EVENT OF ANY BREACH OF THIS AGREEMENT BY NTT SHALL BE TERMINATION PURSUANT TO SECTION 3. 22 | 8. No Assignment or Sublicense. Neither this Agreement nor any right or license under this Agreement, nor the Software, may be sublicensed, assigned, or otherwise transferred by User without NTT's prior written consent. 23 | 9. General 24 | (a) If any provision, or part of a provision, of this Agreement is or becomes illegal, unenforceable, or invalidated, by operation of law or otherwise, that provision or part shall to that extent be deemed omitted, and the remainder of this Agreement shall remain in full force and effect. 25 | (b) This Agreement is the complete and exclusive statement of the agreement between the parties with respect to the subject matter hereof, and supersedes all written and oral contracts, proposals, and other communications between the parties relating to that subject matter. 26 | (c) Subject to Section 8, this Agreement shall be binding on, and shall inure to the benefit of, the respective successors and assigns of NTT and User. 27 | (d) If either party to this Agreement initiates a legal action or proceeding to enforce or interpret any part of this Agreement, the prevailing party in such action shall be entitled to recover, as an element of the costs of such action and not as damages, its attorneys' fees and other costs associated with such action or proceeding. 28 | (e) This Agreement shall be governed by and interpreted under the laws of Japan, without reference to conflicts of law principles. All disputes arising out of or in connection with this Agreement shall be finally settled by arbitration in Tokyo in accordance with the Commercial Arbitration Rules of the Japan Commercial Arbitration Association. The arbitration shall be conducted by three (3) arbitrators and in Japanese. The award rendered by the arbitrators shall be final and binding upon the parties. Judgment upon the award may be entered in any court having jurisdiction thereof. 29 | (f) NTT shall not be liable to the User or to any third party for any delay or failure to perform NTT’s obligation set forth under this Agreement due to any cause beyond NTT’s reasonable control. 30 |   31 | EXHIBIT A 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advanced Binary Deobfuscation 2 | 3 | This repository contains the course materials of Advanced Binary Deobfuscation at the [Global Cybersecurity Camp (GCC) Tokyo](https://www.security-camp.or.jp/event/gcc_tokyo_program.html) and the [Security Camp National Workshop](https://www.security-camp.or.jp/camp/index.html) in 2020. 4 | 5 | ## Course Abstract 6 | 7 | Reverse engineering is not easy, especially if a binary code is obfuscated. Once obfuscation performed, the binary would not be analyzed accurately with naive techniques alone. In this course, you will learn obfuscation principles (especially used by malware), theory and practice of obfuscated code analysis, and how to write your own tool for deobfuscation. In particular, we delve into data-flow analysis and SAT/SMT-based binary analysis (e.g., symbolic execution) to render obfuscation ineffective. 8 | 9 | ## Outline 10 | 11 | This course is about binary deobfuscation, meant for security analysts and researchers (in embryo) looking to add a skill set on writing your own tool to their arsenal. At the end of this class, attendees will be able to: 12 | - Have an in-depth understanding of theory, practice, and behind insights of obfuscation 13 | - Build a custom obfuscated payload with state-of-the-art packers 14 | - Apply compiler optimization techniques to binary analysis tasks 15 | - Design and implement automated binary analysis tools top on a symbolic execution engine 16 | - Even analyze obfuscated malware used in the APT campaign 17 | 18 | Towards this end, the course was held in the form of a combination of classroom learning and hands-on training at GCC. 19 | 20 | ## Prerequisite Knowledge 21 | 22 | Attendees should have: 23 | - Robust skill set in x86/x64 architecture 24 | - Basic experience with C/C++ and Python 25 | - Basic understanding of low-level CS (e.g., OSs, Compilers, interpreters, linkers, and loaders) 26 | 27 | The following links are useful to bridge the gap. 28 | - [Reverse Engineering 101](https://malwareunicorn.org/workshops/re101.html) 29 | - [Modern Binary Exploitation by RPISEC](https://github.com/RPISEC/MBE) 30 | 31 | ## Quick Start 32 | 33 | We assume Ubuntu 18.04 with Miasm, Z3, and Jupyter Notebook. 34 | 35 | 1. Install [VirtualBox](https://www.virtualbox.org/wiki/Linux_Downloads) 36 | 2. Download [Ubuntu 18.04.3 Image](https://sourceforge.net/projects/osboxes/files/v/vb/55-U-u/18.04/18.04.3/18.04.3VB-64bit.7z/download) and install it in VirtualBox 37 | 3. Clone this repository 38 | 4. Execute `./setup.sh ./` 39 | 5. Install [IDA Freeware](https://www.hex-rays.com/products/ida/support/download_freeware.shtml) 40 | 6. Read `Advanced-Binary-Deobfuscation.pdf` and enjoy! 41 | 42 | -------------------------------------------------------------------------------- /hands-on1/Makefile: -------------------------------------------------------------------------------- 1 | CLANG=../obfuscator/build/bin/clang 2 | 3 | .PHONY: all 4 | all: test-hello test-mod2 test-add test-mod2-add 5 | 6 | test-hello: 7 | ${CLANG} -m32 -O0 ./src/test-hello.c -o test-hello 8 | 9 | test-mod2: 10 | ${CLANG} -m32 -O0 ./src/test-mod2.c -o test-mod2 11 | 12 | test-mod2-add: 13 | ${CLANG} -m32 -O0 ./src/test-mod2-add.c -o test-mod2-add 14 | 15 | test-add: 16 | ${CLANG} -m32 -O0 ./src/test-add.c -o test-add 17 | 18 | clean: 19 | rm -Rf test-mod2 20 | rm -Rf test-hello 21 | rm -Rf test-add 22 | rm -Rf test-mod2-add 23 | rm -Rf *.bin *.c *.bc *.idb 24 | 25 | -------------------------------------------------------------------------------- /hands-on1/o-llvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FILENAMES=${1}/*.c 4 | CLANG=${2} 5 | for FILE in ${FILENAMES} 6 | do 7 | FILE_NO_EXT=${FILE%.*} 8 | ${CLANG} -m32 ${FILE} -o "${FILE_NO_EXT##*/}-fla.bin" -mllvm -fla 9 | ${CLANG} -m32 ${FILE} -o "${FILE_NO_EXT##*/}-bcf.bin" -mllvm -bcf -mllvm -bcf_prob=100 10 | ${CLANG} -m32 ${FILE} -o "${FILE_NO_EXT##*/}-sub.bin" -mllvm -sub 11 | done 12 | 13 | 14 | -------------------------------------------------------------------------------- /hands-on1/src/test-add.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned int target_function(int n) 4 | { 5 | int a,b,c,r; 6 | 7 | a = 12; 8 | b = 56; 9 | c = 127; 10 | 11 | r = a + b + c + n; 12 | 13 | return r; 14 | } 15 | 16 | int main(int argc, char* argv[]) 17 | { 18 | unsigned int n = target_function(argc); 19 | 20 | printf("n=%u\n", n); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /hands-on1/src/test-hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void target_function(void) 4 | { 5 | char* msg = "hello world"; 6 | printf("%s\n", msg); 7 | } 8 | 9 | int main(int argc, char* argv[]) 10 | { 11 | target_function(); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /hands-on1/src/test-mod2-add.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int target_function(int n) 4 | { 5 | int a, b; 6 | 7 | a = 0xdeadbeef; 8 | b = 0x8badf00d; 9 | 10 | int c = a + b; 11 | int d = a - b; 12 | int e = c + d + n; 13 | 14 | if(e % 2 == 0){ 15 | return 0; 16 | }else{ 17 | return 1; 18 | } 19 | } 20 | 21 | int main(int argc, char* argv[]) 22 | { 23 | int n = target_function(argc); 24 | printf("n=%d\n", n); 25 | return n; 26 | } 27 | -------------------------------------------------------------------------------- /hands-on1/src/test-mod2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned int target_function(int n) 4 | { 5 | if(n % 2 == 0) 6 | return 0; 7 | else 8 | return 1; 9 | } 10 | 11 | int main(int argc, char* argv[]) 12 | { 13 | unsigned int n = target_function(argc); 14 | 15 | printf("n=%u\n", n); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /hands-on1/tigress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | TMPDIR=`mktemp -d -p .` 4 | TMPSCRIPT=`mktemp -p .` 5 | FILENAMES=${1}/*.c 6 | 7 | cp ${FILENAMES} ${TMPDIR}/ 8 | 9 | 10 | cat << 'EOS' > ${TMPSCRIPT} 11 | #!/bin/bash 12 | NUM=5 13 | 14 | FILENAMES=__TMPDIR__/*.c 15 | for FILE in ${FILENAMES} 16 | do 17 | FILE_NO_EXT=${FILE%.*} 18 | tigress --Transform=EncodeLiterals --Functions=target_function --Environment=x86_64:Darwin:Clang:5.1 -m32 --out=${FILE_NO_EXT##*/}-encodeliteral.c ${FILE} -o ${FILE_NO_EXT##*/}-encodeliteral.bin 19 | tigress --Transform=EncodeArithmetic --Functions=target_function --Environment=x86_64:Darwin:Clang:5.1 -m32 --out=${FILE_NO_EXT##*/}-encodearith.c ${FILE} -o ${FILE_NO_EXT##*/}-encodearith.bin 20 | tigress --Transform=Flatten --Functions=target_function --Environment=x86_64:Darwin:Clang:5.1 -m32 --out=${FILE_NO_EXT##*/}-flatten.c ${FILE} -o ${FILE_NO_EXT##*/}-flatten.bin 21 | tigress --Transform=InitOpaque --Functions=main --Transform=AddOpaque --Functions=target_function --AddOpaqueCount=${NUM} --AddOpaqueKinds=true --Environment=x86_64:Darwin:Clang:5.1 -m32 --out=${FILE_NO_EXT##*/}-opaque.c ${FILE} -o ${FILE_NO_EXT##*/}-opaque.bin 22 | tigress --Environment=x86_64:Darwin:Clang:5.1 -m32 --Seed=0 --Transform=InitEntropy --InitEntropyKinds=vars --Transform=InitOpaque --Functions=main --InitOpaqueCount=2 --InitOpaqueStructs=list,array --Transform=AddOpaque --Functions=target_function --AddOpaqueKinds=question --AddOpaqueCount=1 --out=${FILE_NO_EXT##*/}-q.c ${FILE} -o ${FILE_NO_EXT##*/}-q.bin 23 | tigress --Transform=Virtualize --Functions=target_function --Environment=x86_64:Darwin:Clang:5.1 -m32 --out=${FILE_NO_EXT##*/}-virtualized.c ${FILE} -o ${FILE_NO_EXT##*/}-virtualized.bin 24 | done 25 | EOS 26 | 27 | sed -i -e "s/__TMPDIR__/${TMPDIR/\//\\\/}/g" ${TMPSCRIPT} 28 | 29 | chmod +x ${TMPSCRIPT} 30 | sudo docker run -it --rm -v `pwd`:/mnt -w /mnt tigress-docker ./${TMPSCRIPT} 31 | 32 | rm -rf ${TMPDIR} 33 | rm -f ${TMPSCRIPT} 34 | -------------------------------------------------------------------------------- /hands-on2/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | rm -Rf *.idc 3 | rm -Rf *.bin 4 | rm -Rf *.idb 5 | rm -Rf *.pyc 6 | rm -Rf solved/*.pyc 7 | -------------------------------------------------------------------------------- /hands-on2/deadcode_removal.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.arch.x86.arch import mn_x86\n", 12 | "from miasm.core import parse_asm\n", 13 | "from miasm.core.locationdb import LocationDB\n", 14 | "from future.utils import viewitems\n", 15 | "from miasm.analysis.data_flow import *\n", 16 | "import pydotplus\n", 17 | "from IPython.display import Image, display_png" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": null, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "loc_db = LocationDB()\n", 27 | "asmcfg = parse_asm.parse_txt(mn_x86, 32, ''' \n", 28 | "main:\n", 29 | " PUSH EBP\n", 30 | " MOV EBP, ESP\n", 31 | " MOV ECX, 0x23\n", 32 | " MOV ECX, 0x4\n", 33 | " MOV EAX, ECX\n", 34 | " POP EBP\n", 35 | " RET\n", 36 | "''', loc_db)" 37 | ] 38 | }, 39 | { 40 | "cell_type": "code", 41 | "execution_count": null, 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "loc_db.set_location_offset(loc_db.get_name_location(\"main\"), 0x0)\n", 46 | "\n", 47 | "machine = Machine('x86_32')\n", 48 | "ir_arch = machine.ira(loc_db)\n", 49 | "ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "print('Before Simplification:')\n", 59 | "for lbl, irb in viewitems(ircfg.blocks):\n", 60 | " print(irb)" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "deadrm = DeadRemoval(ir_arch)\n", 70 | "deadrm(ircfg)" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "print('After Simplification:')\n", 80 | "for lbl, irb in viewitems(ircfg.blocks):\n", 81 | " print(irb)" 82 | ] 83 | } 84 | ], 85 | "metadata": { 86 | "kernelspec": { 87 | "display_name": "Python 3", 88 | "language": "python", 89 | "name": "python3" 90 | }, 91 | "language_info": { 92 | "codemirror_mode": { 93 | "name": "ipython", 94 | "version": 3 95 | }, 96 | "file_extension": ".py", 97 | "mimetype": "text/x-python", 98 | "name": "python", 99 | "nbconvert_exporter": "python", 100 | "pygments_lexer": "ipython3", 101 | "version": "3.6.9" 102 | } 103 | }, 104 | "nbformat": 4, 105 | "nbformat_minor": 4 106 | } 107 | -------------------------------------------------------------------------------- /hands-on2/deadcode_unremoval.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.arch.x86.arch import mn_x86\n", 12 | "from miasm.core import parse_asm, asmblock\n", 13 | "from miasm.core.locationdb import LocationDB\n", 14 | "from miasm.analysis.binary import Container\n", 15 | "from future.utils import viewitems\n", 16 | "from miasm.loader.strpatchwork import *\n", 17 | "from miasm.analysis.data_flow import *\n", 18 | "from miasm.jitter.csts import PAGE_READ, PAGE_WRITE" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "# TODO\n", 28 | "# Please add some assemble code to protect 'MOV ECX, 0x23' from dead code elimination\n", 29 | "\n", 30 | "# From Here--------------------------------------------\n", 31 | "\n", 32 | "loc_db = LocationDB()\n", 33 | "asmcfg = parse_asm.parse_txt(mn_x86, 32, ''' \n", 34 | "main:\n", 35 | " PUSH EBP\n", 36 | " MOV EBP, ESP\n", 37 | " MOV ECX, 0x23\n", 38 | " MOV ECX, 0x4\n", 39 | " MOV EAX, ECX\n", 40 | " POP EBP\n", 41 | " RET\n", 42 | "''', loc_db)\n", 43 | "\n", 44 | "# To HERE --------------------------------------------" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "loc_db.set_location_offset(loc_db.get_name_location('main'), 0x0)\n", 54 | "\n", 55 | "patches = asmblock.asm_resolve_final(mn_x86, asmcfg)\n", 56 | "patch_worker = StrPatchwork()\n", 57 | "for offset, raw in patches.items():\n", 58 | " patch_worker[offset] = raw\n", 59 | " \n", 60 | "cont = Container.from_string(array_tobytes(patch_worker.s), loc_db=loc_db)\n", 61 | "machine = Machine('x86_32')\n", 62 | "mdis = machine.dis_engine(cont.bin_stream, loc_db=loc_db)\n", 63 | "asmcfg2 = mdis.dis_multiblock(0)\n", 64 | "ir_arch = machine.ira(loc_db)\n", 65 | "ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg2)" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "print('Before Simplification:')\n", 75 | "for lbl, irb in viewitems(ircfg.blocks):\n", 76 | " print(irb)" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "deadrm = DeadRemoval(ir_arch)\n", 86 | "deadrm(ircfg)" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "print('After Simplification:')\n", 96 | "\n", 97 | "for lbl, irb in viewitems(ircfg.blocks):\n", 98 | " print(irb)" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": null, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "# jitter to confirm that the branch is not actually taken\n", 108 | "def code_sentinelle(jitter):\n", 109 | " jitter.run = False\n", 110 | " jitter.pc = 0\n", 111 | " return True\n", 112 | "\n", 113 | "myjit = Machine('x86_32').jitter(loc_db, 'python')\n", 114 | "myjit.init_stack()\n", 115 | "run_addr = 0x00000000\n", 116 | "myjit.vm.add_memory_page(run_addr, PAGE_READ | PAGE_WRITE, array_tobytes(patch_worker.s))\n", 117 | "myjit.set_trace_log()\n", 118 | "myjit.push_uint32_t(0x1337beef)\n", 119 | "myjit.add_breakpoint(0x1337beef, code_sentinelle)\n", 120 | "myjit.init_run(run_addr)\n", 121 | "myjit.continue_run()" 122 | ] 123 | } 124 | ], 125 | "metadata": { 126 | "kernelspec": { 127 | "display_name": "Python 3", 128 | "language": "python", 129 | "name": "python3" 130 | }, 131 | "language_info": { 132 | "codemirror_mode": { 133 | "name": "ipython", 134 | "version": 3 135 | }, 136 | "file_extension": ".py", 137 | "mimetype": "text/x-python", 138 | "name": "python", 139 | "nbconvert_exporter": "python", 140 | "pygments_lexer": "ipython3", 141 | "version": "3.6.9" 142 | } 143 | }, 144 | "nbformat": 4, 145 | "nbformat_minor": 4 146 | } 147 | -------------------------------------------------------------------------------- /hands-on2/optimizer.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.analysis.binary import Container\n", 12 | "from miasm.analysis.cst_propag import propagate_cst_expr\n", 13 | "from miasm.analysis.data_flow import DeadRemoval, merge_blocks, remove_empty_assignblks\n", 14 | "from miasm.core.locationdb import LocationDB\n", 15 | "from future.utils import viewitems" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "filename = '../hands-on1/test-add-sub.bin'\n", 25 | "addr = 0x8048440" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": { 32 | "scrolled": false 33 | }, 34 | "outputs": [], 35 | "source": [ 36 | "loc_db = LocationDB()\n", 37 | "machine = Machine('x86_32')\n", 38 | "cont = Container.from_stream(open(filename, 'rb'), loc_db)\n", 39 | "mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db)\n", 40 | "ir_arch = machine.ira(mdis.loc_db)\n", 41 | "\n", 42 | "asmcfg = mdis.dis_multiblock(addr)\n", 43 | "ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)\n", 44 | "\n", 45 | "print('Before Simplification:')\n", 46 | "for lbl, irb in viewitems(ircfg.blocks):\n", 47 | " print(irb)" 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": null, 53 | "metadata": {}, 54 | "outputs": [], 55 | "source": [ 56 | "entry_points = set([mdis.loc_db.get_offset_location(addr)])\n", 57 | "init_infos = ir_arch.arch.regs.regs_init\n", 58 | "cst_propag_link = propagate_cst_expr(ir_arch, ircfg, addr, init_infos)\n", 59 | "deadrm = DeadRemoval(ir_arch)\n", 60 | "\n", 61 | "modified = True\n", 62 | "while modified:\n", 63 | " modified = False\n", 64 | " modified |= deadrm(ircfg)\n", 65 | " modified |= remove_empty_assignblks(ircfg)\n", 66 | "\n", 67 | "print('After Simplification:')\n", 68 | "\n", 69 | "for lbl, irb in viewitems(ircfg.blocks):\n", 70 | " print(irb)" 71 | ] 72 | } 73 | ], 74 | "metadata": { 75 | "kernelspec": { 76 | "display_name": "Python 3", 77 | "language": "python", 78 | "name": "python3" 79 | }, 80 | "language_info": { 81 | "codemirror_mode": { 82 | "name": "ipython", 83 | "version": 3 84 | }, 85 | "file_extension": ".py", 86 | "mimetype": "text/x-python", 87 | "name": "python", 88 | "nbconvert_exporter": "python", 89 | "pygments_lexer": "ipython3", 90 | "version": "3.6.9" 91 | } 92 | }, 93 | "nbformat": 4, 94 | "nbformat_minor": 2 95 | } 96 | -------------------------------------------------------------------------------- /hands-on2/solved/deadcode_unremoval.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.arch.x86.arch import mn_x86\n", 12 | "from miasm.core import parse_asm, asmblock\n", 13 | "from miasm.core.locationdb import LocationDB\n", 14 | "from miasm.analysis.binary import Container\n", 15 | "from future.utils import viewitems\n", 16 | "from miasm.loader.strpatchwork import *\n", 17 | "from miasm.analysis.data_flow import *\n", 18 | "from miasm.jitter.csts import PAGE_READ, PAGE_WRITE" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "# TODO\n", 28 | "# Please add some assemble code to protect 'MOV ECX, 0x23' from dead code elimination\n", 29 | "\n", 30 | "# From Here--------------------------------------------\n", 31 | "\n", 32 | "loc_db = LocationDB()\n", 33 | "asmcfg = parse_asm.parse_txt(mn_x86, 32, ''' \n", 34 | "main:\n", 35 | " PUSH EBP\n", 36 | " MOV EBP, ESP\n", 37 | " MOV ECX, 0x23\n", 38 | " MOV EDX, EAX\n", 39 | " MUL EDX\n", 40 | " CMP EAX, -1\n", 41 | " JNZ label\n", 42 | " MOV DWORD PTR [0xDEADBEEF], ECX\n", 43 | "\n", 44 | "label:\n", 45 | " MOV ECX, 0x4\n", 46 | " MOV EAX, ECX\n", 47 | " POP EBP\n", 48 | " RET\n", 49 | "''', loc_db)\n", 50 | "\n", 51 | "# To HERE --------------------------------------------" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "loc_db.set_location_offset(loc_db.get_name_location('main'), 0x0)\n", 61 | "\n", 62 | "patches = asmblock.asm_resolve_final(mn_x86, asmcfg)\n", 63 | "patch_worker = StrPatchwork()\n", 64 | "for offset, raw in patches.items():\n", 65 | " patch_worker[offset] = raw\n", 66 | " \n", 67 | "cont = Container.from_string(array_tobytes(patch_worker.s), loc_db=loc_db)\n", 68 | "machine = Machine('x86_32')\n", 69 | "mdis = machine.dis_engine(cont.bin_stream, loc_db=loc_db)\n", 70 | "asmcfg2 = mdis.dis_multiblock(0)\n", 71 | "ir_arch = machine.ira(loc_db)\n", 72 | "ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg2)" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": null, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "print('Before Simplification:')\n", 82 | "for lbl, irb in viewitems(ircfg.blocks):\n", 83 | " print(irb)" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [ 92 | "deadrm = DeadRemoval(ir_arch)\n", 93 | "deadrm(ircfg)" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "print('After Simplification:')\n", 103 | "\n", 104 | "for lbl, irb in viewitems(ircfg.blocks):\n", 105 | " print(irb)" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "# jitter to confirm that the branch is not actually taken\n", 115 | "def code_sentinelle(jitter):\n", 116 | " jitter.run = False\n", 117 | " jitter.pc = 0\n", 118 | " return True\n", 119 | "\n", 120 | "myjit = Machine('x86_32').jitter(loc_db, 'python')\n", 121 | "myjit.init_stack()\n", 122 | "run_addr = 0x00000000\n", 123 | "myjit.vm.add_memory_page(run_addr, PAGE_READ | PAGE_WRITE, array_tobytes(patch_worker.s))\n", 124 | "myjit.set_trace_log()\n", 125 | "myjit.push_uint32_t(0x1337beef)\n", 126 | "myjit.add_breakpoint(0x1337beef, code_sentinelle)\n", 127 | "myjit.init_run(run_addr)\n", 128 | "myjit.continue_run()" 129 | ] 130 | } 131 | ], 132 | "metadata": { 133 | "kernelspec": { 134 | "display_name": "Python 3", 135 | "language": "python", 136 | "name": "python3" 137 | }, 138 | "language_info": { 139 | "codemirror_mode": { 140 | "name": "ipython", 141 | "version": 3 142 | }, 143 | "file_extension": ".py", 144 | "mimetype": "text/x-python", 145 | "name": "python", 146 | "nbconvert_exporter": "python", 147 | "pygments_lexer": "ipython3", 148 | "version": "3.6.9" 149 | } 150 | }, 151 | "nbformat": 4, 152 | "nbformat_minor": 4 153 | } 154 | -------------------------------------------------------------------------------- /hands-on3/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | rm -Rf *.idc 3 | rm -Rf *.bin 4 | rm -Rf *.idb 5 | rm -Rf *.pyc 6 | rm -Rf solved/*.pyc 7 | -------------------------------------------------------------------------------- /hands-on3/anel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malrev/ABD/0fe01674a4b0f1879f9c36d7b1e76e3c1d670d26/hands-on3/anel.zip -------------------------------------------------------------------------------- /hands-on3/opfind.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.arch.x86.arch import mn_x86\n", 12 | "from miasm.ir.symbexec import SymbolicExecutionEngine\n", 13 | "from miasm.expression.expression import ExprInt, ExprMem, ExprId, LocKey\n", 14 | "from miasm.arch.x86.regs import *\n", 15 | "from miasm.analysis.binary import Container\n", 16 | "from miasm.core.locationdb import LocationDB\n", 17 | "from future.utils import viewitems\n", 18 | "from argparse import ArgumentParser\n", 19 | "import sys, z3" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": null, 25 | "metadata": {}, 26 | "outputs": [], 27 | "source": [ 28 | "!unzip -n -P infected x-tunnel.zip\n", 29 | "!unzip -n -P infected anel.zip" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "metadata": {}, 36 | "outputs": [], 37 | "source": [ 38 | "filename = 'x-tunnel.bin'\n", 39 | "target_addr = 0x405710\n", 40 | "#filename = '../hands-on1/test-add-bcf.bin'\n", 41 | "#target_addr = 0x80483F0\n", 42 | "#filename = '../hands-on1/test-hello-bcf.bin'\n", 43 | "#target_addr = 0x80483F0\n", 44 | "#filename = '../hands-on1/test-mod2-bcf.bin'\n", 45 | "#target_addr = 0x80483F0\n", 46 | "#filename = '../hands-on1/test-add-opaque.bin'\n", 47 | "#target_addr = 0x8048471\n", 48 | "idc = True" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "%run solved/simple_explore_smt.ipynb # from simple_explore_smt import *" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "def to_idc(lockeys, asmcfg):\n", 67 | "\n", 68 | " header = '''\n", 69 | "#include \n", 70 | "static main(){\n", 71 | "'''\n", 72 | " footer = '''\n", 73 | "}\n", 74 | "'''\n", 75 | " body = ''\n", 76 | " f = open('op-color.idc', 'w')\n", 77 | " for lbl in lockeys:\n", 78 | " asmblk = asmcfg.loc_key_to_block(lbl)\n", 79 | " if asmblk:\n", 80 | " for l in asmblk.lines:\n", 81 | " body += 'SetColor(0x%08x, CIC_ITEM, 0xc7c7ff);\\n'%(l.offset)\n", 82 | " \n", 83 | " f.write(header+body+footer)\n", 84 | " f.close()" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": null, 90 | "metadata": {}, 91 | "outputs": [], 92 | "source": [ 93 | "loc_db = LocationDB()\n", 94 | "with open(filename, 'rb') as fstream: \n", 95 | " cont = Container.from_stream(fstream, loc_db)\n", 96 | "\n", 97 | "machine = Machine('x86_32')\n", 98 | "mdis = machine.dis_engine(cont.bin_stream, follow_call=False, loc_db=cont.loc_db)\n", 99 | "ir_arch = machine.ira(mdis.loc_db)\n", 100 | "\n", 101 | "# Disassemble the targeted function\n", 102 | "asmcfg = mdis.dis_multiblock(target_addr)\n", 103 | "\n", 104 | "# IRCFG\n", 105 | "ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)\n", 106 | "for lbl, irblk in viewitems(ircfg.blocks):\n", 107 | " print(irblk)" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": null, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "# Preparing the initial symbols for regs and mems\n", 117 | "symbols_init = {}\n", 118 | "\n", 119 | "# for regs\n", 120 | "for i, r in enumerate(all_regs_ids):\n", 121 | " symbols_init[r] = all_regs_ids_init[i]\n", 122 | "\n", 123 | "# for mems\n", 124 | "# 0xdeadbeef is the mark to stop the exploring\n", 125 | "symbols_init[ExprMem(ExprId('ESP_init', 32), 32)] = ExprInt(0xdeadbeef, 32)\n", 126 | "\n", 127 | "final_states = []" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "metadata": {}, 134 | "outputs": [], 135 | "source": [ 136 | "explore(ir_arch, \n", 137 | " target_addr, \n", 138 | " symbols_init, \n", 139 | " ircfg, \n", 140 | " lbl_stop=0xdeadbeef, \n", 141 | " final_states=final_states)" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": null, 147 | "metadata": {}, 148 | "outputs": [], 149 | "source": [ 150 | "executed_lockey = []\n", 151 | "unexecuted_lockey = []\n", 152 | "\n", 153 | "# The IR nodes which are included in one of paths were executed.\n", 154 | "for final_state in final_states:\n", 155 | " if final_state.result:\n", 156 | " for node in final_state.path_history:\n", 157 | " if isinstance(node, int):\n", 158 | " lbl = ircfg.get_loc_key(node)\n", 159 | " elif isinstance(node, ExprInt):\n", 160 | " lbl = ircfg.get_loc_key(node)\n", 161 | " elif isinstance(node, LocKey):\n", 162 | " lbl = node.loc_key\n", 163 | "\n", 164 | " if lbl not in executed_lockey:\n", 165 | " executed_lockey.append(lbl)\n", 166 | " \n", 167 | "# Otherwise, the IR nodes which are not included in any path were not executed.\n", 168 | "for lbl, irblock in viewitems(ircfg.blocks):\n", 169 | " if lbl not in executed_lockey:\n", 170 | " unexecuted_lockey.append(lbl)" 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": null, 176 | "metadata": {}, 177 | "outputs": [], 178 | "source": [ 179 | "print(executed_lockey)\n", 180 | "print(unexecuted_lockey)\n", 181 | "print('len(executed_lockey):', len(executed_lockey))\n", 182 | "print('len(unexecuted_lockey):', len(unexecuted_lockey))" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": null, 188 | "metadata": {}, 189 | "outputs": [], 190 | "source": [ 191 | "# Generate an IDC script to set color on un-executed basic blocks.\n", 192 | "if idc:\n", 193 | " to_idc(unexecuted_lockey, asmcfg)" 194 | ] 195 | } 196 | ], 197 | "metadata": { 198 | "kernelspec": { 199 | "display_name": "Python 3", 200 | "language": "python", 201 | "name": "python3" 202 | }, 203 | "language_info": { 204 | "codemirror_mode": { 205 | "name": "ipython", 206 | "version": 3 207 | }, 208 | "file_extension": ".py", 209 | "mimetype": "text/x-python", 210 | "name": "python", 211 | "nbconvert_exporter": "python", 212 | "pygments_lexer": "ipython3", 213 | "version": "3.6.9" 214 | } 215 | }, 216 | "nbformat": 4, 217 | "nbformat_minor": 4 218 | } 219 | -------------------------------------------------------------------------------- /hands-on3/sat_smt.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from z3 import *" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "metadata": {}, 17 | "outputs": [], 18 | "source": [ 19 | "malicious, benign = Bools('malicious, benign')\n", 20 | "s = Solver() # Initialize the solver instance\n", 21 | "s.add(Or(malicious, benign), # Add constraints\n", 22 | " Or(Not(malicious), benign), \n", 23 | " Or(Not(malicious), Not(benign)))" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "print(s.sexpr())" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "print(s.check())" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "print(s.model())" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": null, 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "malicious, benign = Bools('malicious, benign')\n", 60 | "x = Int('x')\n", 61 | "s = Solver() # Initialize the solver instance\n", 62 | "s.add(Or(malicious, benign), # Add constraints\n", 63 | " Or(Not(malicious), benign), \n", 64 | " Or(Not(malicious), Not(benign)),\n", 65 | " And(x*x-x==2))" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "print(s.sexpr())" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "print(s.check())" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [ 92 | "print(s.model())" 93 | ] 94 | } 95 | ], 96 | "metadata": { 97 | "kernelspec": { 98 | "display_name": "Python 3", 99 | "language": "python", 100 | "name": "python3" 101 | }, 102 | "language_info": { 103 | "codemirror_mode": { 104 | "name": "ipython", 105 | "version": 3 106 | }, 107 | "file_extension": ".py", 108 | "mimetype": "text/x-python", 109 | "name": "python", 110 | "nbconvert_exporter": "python", 111 | "pygments_lexer": "ipython3", 112 | "version": "3.6.9" 113 | } 114 | }, 115 | "nbformat": 4, 116 | "nbformat_minor": 2 117 | } 118 | -------------------------------------------------------------------------------- /hands-on3/simple_explore.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.arch.x86.arch import mn_x86\n", 12 | "from miasm.ir.symbexec import SymbolicExecutionEngine\n", 13 | "from miasm.expression.expression import ExprCond, ExprId, ExprInt, ExprMem \n", 14 | "from miasm.expression.simplifications import expr_simp\n", 15 | "from miasm.arch.x86.regs import *\n", 16 | "from miasm.core import parse_asm, asmblock\n", 17 | "from miasm.core.locationdb import LocationDB\n", 18 | "from miasm.analysis.binary import Container\n", 19 | "from future.utils import viewitems\n", 20 | "from miasm.loader.strpatchwork import *\n", 21 | "from miasm.ir.translators.translator import Translator\n", 22 | "import warnings\n", 23 | "import z3" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "class FinalState:\n", 33 | " def __init__(self, result, sym, path_conds, path_history):\n", 34 | " self.result = result\n", 35 | " self.sb = sym\n", 36 | " self.path_conds = path_conds\n", 37 | " self.path_history = path_history" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "def explore(ir, start_addr, start_symbols, \n", 47 | " ircfg, cond_limit=30, uncond_limit=100, \n", 48 | " lbl_stop=None, final_states=[]):\n", 49 | "\n", 50 | " def codepath_walk(addr, symbols, conds, depth, final_states, path):\n", 51 | "\n", 52 | " if depth >= cond_limit:\n", 53 | " warnings.warn(\"'depth' is over the cond_limit :%d\"%(depth))\n", 54 | " return \n", 55 | "\n", 56 | " sb = SymbolicExecutionEngine(ir, symbols)\n", 57 | "\n", 58 | " for _ in range(uncond_limit):\n", 59 | "\n", 60 | " if isinstance(addr, ExprInt):\n", 61 | " if addr == lbl_stop:\n", 62 | " final_states.append(FinalState(True, sb, conds, path))\n", 63 | " return\n", 64 | "\n", 65 | " path.append(addr)\n", 66 | "\n", 67 | " pc = sb.run_block_at(ircfg, addr)\n", 68 | "\n", 69 | " if isinstance(pc, ExprCond): \n", 70 | " \n", 71 | " # Calc the condition to take true or false paths\n", 72 | " cond_true = {pc.cond: ExprInt(1, 32)}\n", 73 | " cond_false = {pc.cond: ExprInt(0, 32)}\n", 74 | "\n", 75 | " # The destination addr of the true or false paths\n", 76 | " addr_true = expr_simp(\n", 77 | " sb.eval_expr(pc.replace_expr(cond_true), {}))\n", 78 | "\n", 79 | " addr_false = expr_simp(\n", 80 | " sb.eval_expr(pc.replace_expr(cond_false), {}))\n", 81 | "\n", 82 | " # Need to add the path conditions to reach this point\n", 83 | " conds_true = list(conds) + list(cond_true.items())\n", 84 | " conds_false = list(conds) + list(cond_false.items())\n", 85 | "\n", 86 | " # Recursive call for the true or false path\n", 87 | " codepath_walk(\n", 88 | " addr_true, sb.symbols.copy(), \n", 89 | " conds_true, depth + 1, final_states, list(path))\n", 90 | "\n", 91 | " codepath_walk(\n", 92 | " addr_false, sb.symbols.copy(), \n", 93 | " conds_false, depth + 1, final_states, list(path))\n", 94 | "\n", 95 | " return\n", 96 | " else:\n", 97 | " addr = expr_simp(sb.eval_expr(pc))\n", 98 | "\n", 99 | " final_states.append(FinalState(True, sb, conds, path))\n", 100 | " return \n", 101 | "\n", 102 | " return codepath_walk(start_addr, start_symbols, [], 0, final_states, [])" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "# Assemble code\n", 112 | "loc_db = LocationDB()\n", 113 | "asmcfg = parse_asm.parse_txt(mn_x86, 32, ''' \n", 114 | "main:\n", 115 | " PUSH EBP\n", 116 | " MOV EBP, ESP\n", 117 | " MOV ECX, 0x23\n", 118 | " MOV EDX, EAX\n", 119 | " MUL EDX\n", 120 | " CMP EAX, -1\n", 121 | " JNZ label\n", 122 | " MOV DWORD PTR [0xDEADBEEF], ECX\n", 123 | "\n", 124 | "label:\n", 125 | " MOV ECX, 0x4\n", 126 | " MOV EAX, ECX\n", 127 | " POP EBP\n", 128 | " RET\n", 129 | "''', loc_db)" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": null, 135 | "metadata": {}, 136 | "outputs": [], 137 | "source": [ 138 | "loc_db.set_location_offset(loc_db.get_name_location('main'), 0x0)\n", 139 | "\n", 140 | "patches = asmblock.asm_resolve_final(mn_x86, asmcfg)\n", 141 | "patch_worker = StrPatchwork()\n", 142 | "for offset, raw in patches.items():\n", 143 | " patch_worker[offset] = raw\n", 144 | " print('%08x'%(offset), mn_x86.dis(raw, 32))\n", 145 | "\n", 146 | "cont = Container.from_string(array_tobytes(patch_worker.s), loc_db)\n", 147 | "\n", 148 | "machine = Machine('x86_32')\n", 149 | "mdis = machine.dis_engine(cont.bin_stream, loc_db=loc_db)\n", 150 | "\n", 151 | "asmcfg2 = mdis.dis_multiblock(0)\n", 152 | "\n", 153 | "ir_arch = machine.ira(loc_db)\n", 154 | "ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg2)\n", 155 | "\n", 156 | "for lbl, irb in viewitems(ircfg.blocks):\n", 157 | " print(irb)" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "symbols_init = {\n", 167 | " ExprMem(ExprId('ESP_init', 32), 32) : ExprInt(0xdeadbeef, 32)\n", 168 | "}\n", 169 | "\n", 170 | "for i, r in enumerate(all_regs_ids):\n", 171 | " symbols_init[r] = all_regs_ids_init[i]\n", 172 | "\n", 173 | "final_states = []" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": null, 179 | "metadata": {}, 180 | "outputs": [], 181 | "source": [ 182 | "explore(ir_arch, \n", 183 | " 0, \n", 184 | " symbols_init, \n", 185 | " ircfg, \n", 186 | " lbl_stop=0xdeadbeef, \n", 187 | " final_states=final_states)" 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": null, 193 | "metadata": {}, 194 | "outputs": [], 195 | "source": [ 196 | "# Show results\n", 197 | "print('final states:', len(final_states))\n", 198 | "\n", 199 | "for final_state in final_states:\n", 200 | " if final_state.result:\n", 201 | " print('Feasible path:','->'.join([str(x) for x in final_state.path_history]))\n", 202 | " print('\\t',final_state.path_conds)\n", 203 | " else:\n", 204 | " print('Infeasible path:','->'.join([str(x) for x in final_state.path_history]))\n", 205 | " print('\\t',final_state.path_conds)\n", 206 | "\n", 207 | " final_state.sb.dump(ids=False)\n", 208 | " print('')" 209 | ] 210 | } 211 | ], 212 | "metadata": { 213 | "kernelspec": { 214 | "display_name": "Python 3", 215 | "language": "python", 216 | "name": "python3" 217 | }, 218 | "language_info": { 219 | "codemirror_mode": { 220 | "name": "ipython", 221 | "version": 3 222 | }, 223 | "file_extension": ".py", 224 | "mimetype": "text/x-python", 225 | "name": "python", 226 | "nbconvert_exporter": "python", 227 | "pygments_lexer": "ipython3", 228 | "version": "3.6.9" 229 | } 230 | }, 231 | "nbformat": 4, 232 | "nbformat_minor": 4 233 | } 234 | -------------------------------------------------------------------------------- /hands-on3/simple_explore_smt.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.arch.x86.arch import mn_x86\n", 12 | "from miasm.ir.symbexec import SymbolicExecutionEngine\n", 13 | "from miasm.expression.expression import ExprCond, ExprId, ExprInt, ExprMem \n", 14 | "from miasm.expression.simplifications import expr_simp\n", 15 | "from miasm.arch.x86.regs import *\n", 16 | "from miasm.core import parse_asm, asmblock\n", 17 | "from miasm.core.locationdb import LocationDB\n", 18 | "from miasm.analysis.binary import Container\n", 19 | "from future.utils import viewitems\n", 20 | "from miasm.loader.strpatchwork import *\n", 21 | "from miasm.ir.translators.translator import Translator\n", 22 | "import warnings\n", 23 | "import z3" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "def check_path_feasibility(conds):\n", 33 | " solver = z3.Solver()\n", 34 | " for lval, rval in conds:\n", 35 | " z3_cond = Translator.to_language(\"z3\").from_expr(lval)\n", 36 | " solver.add(z3_cond == int(rval.arg))\n", 37 | "\n", 38 | " rslt = solver.check()\n", 39 | "\n", 40 | " if rslt == z3.sat:\n", 41 | " return True\n", 42 | " else:\n", 43 | " return False" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "class FinalState:\n", 53 | " def __init__(self, result, sym, path_conds, path_history):\n", 54 | " self.result = result\n", 55 | " self.sb = sym\n", 56 | " self.path_conds = path_conds\n", 57 | " self.path_history = path_history" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "def explore(ir, start_addr, start_symbols, \n", 67 | " ircfg, cond_limit=30, uncond_limit=100, \n", 68 | " lbl_stop=None, final_states=[]):\n", 69 | "\n", 70 | " def codepath_walk(addr, symbols, conds, depth, final_states, path):\n", 71 | "\n", 72 | " if depth >= cond_limit:\n", 73 | " warnings.warn(\"'depth' is over the cond_limit :%d\"%(depth))\n", 74 | " return \n", 75 | "\n", 76 | " sb = SymbolicExecutionEngine(ir, symbols)\n", 77 | "\n", 78 | " for _ in range(uncond_limit):\n", 79 | "\n", 80 | " if isinstance(addr, ExprInt): \n", 81 | " if addr == lbl_stop:\n", 82 | " final_states.append(FinalState(True, sb, conds, path))\n", 83 | " return\n", 84 | "\n", 85 | " path.append(addr)\n", 86 | "\n", 87 | " pc = sb.run_block_at(ircfg, addr)\n", 88 | "\n", 89 | " if isinstance(pc, ExprCond): \n", 90 | " \n", 91 | " # Calc the condition to take true or false paths\n", 92 | " cond_true = {pc.cond: ExprInt(1, 32)}\n", 93 | " cond_false = {pc.cond: ExprInt(0, 32)}\n", 94 | "\n", 95 | " # The destination addr of the true or false paths\n", 96 | " addr_true = expr_simp(\n", 97 | " sb.eval_expr(pc.replace_expr(cond_true), {}))\n", 98 | "\n", 99 | " addr_false = expr_simp(\n", 100 | " sb.eval_expr(pc.replace_expr(cond_false), {}))\n", 101 | "\n", 102 | " # Need to add the path conditions to reach this point\n", 103 | " conds_true = list(conds) + list(cond_true.items())\n", 104 | " conds_false = list(conds) + list(cond_false.items())\n", 105 | "\n", 106 | " # TODO:\n", 107 | " # Please add some code to complete the SMT-based path explore\n", 108 | " # Hint1: use check_path_feasibility()\n", 109 | " # Hint2: Do not forget to add the current state to the final_states \n", 110 | " # when the path condition is infeasible. \n", 111 | " # e.g., final_states.append(FinalState(False, sb, conds_true/conds_false, path))\n", 112 | " #\n", 113 | " # From here --------------------------------\n", 114 | " \n", 115 | " codepath_walk(\n", 116 | " addr_true, sb.symbols.copy(), \n", 117 | " conds_true, depth + 1, final_states, list(path))\n", 118 | "\n", 119 | " codepath_walk(\n", 120 | " addr_false, sb.symbols.copy(), \n", 121 | " conds_false, depth + 1, final_states, list(path))\n", 122 | "\n", 123 | " # To here --------------------------------\n", 124 | "\n", 125 | " return\n", 126 | " else:\n", 127 | " addr = expr_simp(sb.eval_expr(pc))\n", 128 | "\n", 129 | " final_states.append(FinalState(True, sb, conds, path))\n", 130 | " return \n", 131 | "\n", 132 | " return codepath_walk(start_addr, start_symbols, [], 0, final_states, [])" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": null, 138 | "metadata": {}, 139 | "outputs": [], 140 | "source": [ 141 | "# Assemble code\n", 142 | "loc_db = LocationDB()\n", 143 | "asmcfg = parse_asm.parse_txt(mn_x86, 32, ''' \n", 144 | "main:\n", 145 | " PUSH EBP\n", 146 | " MOV EBP, ESP\n", 147 | " MOV ECX, 0x23\n", 148 | " MOV EDX, EAX\n", 149 | " MUL EDX\n", 150 | " CMP EAX, -1\n", 151 | " JNZ label\n", 152 | " MOV DWORD PTR [0xDEADBEEF], ECX\n", 153 | "\n", 154 | "label:\n", 155 | " MOV ECX, 0x4\n", 156 | " MOV EAX, ECX\n", 157 | " POP EBP\n", 158 | " RET\n", 159 | "''', loc_db)" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": null, 165 | "metadata": {}, 166 | "outputs": [], 167 | "source": [ 168 | "loc_db.set_location_offset(loc_db.get_name_location('main'), 0x0)\n", 169 | "\n", 170 | "patches = asmblock.asm_resolve_final(mn_x86, asmcfg)\n", 171 | "patch_worker = StrPatchwork()\n", 172 | "for offset, raw in patches.items():\n", 173 | " patch_worker[offset] = raw\n", 174 | " print('%08x'%(offset), mn_x86.dis(raw, 32))\n", 175 | "\n", 176 | "cont = Container.from_string(array_tobytes(patch_worker.s), loc_db)\n", 177 | "\n", 178 | "machine = Machine('x86_32')\n", 179 | "mdis = machine.dis_engine(cont.bin_stream, loc_db=loc_db)\n", 180 | "\n", 181 | "asmcfg2 = mdis.dis_multiblock(0)\n", 182 | "\n", 183 | "ir_arch = machine.ira(loc_db)\n", 184 | "ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg2)\n", 185 | "\n", 186 | "for lbl, irb in viewitems(ircfg.blocks):\n", 187 | " print(irb)" 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": null, 193 | "metadata": {}, 194 | "outputs": [], 195 | "source": [ 196 | "symbols_init = {\n", 197 | " ExprMem(ExprId('ESP_init', 32), 32) : ExprInt(0xdeadbeef, 32)\n", 198 | "}\n", 199 | "\n", 200 | "for i, r in enumerate(all_regs_ids):\n", 201 | " symbols_init[r] = all_regs_ids_init[i]\n", 202 | "\n", 203 | "final_states = []" 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": null, 209 | "metadata": {}, 210 | "outputs": [], 211 | "source": [ 212 | "explore(ir_arch, \n", 213 | " 0, \n", 214 | " symbols_init, \n", 215 | " ircfg, \n", 216 | " lbl_stop=0xdeadbeef, \n", 217 | " final_states=final_states)" 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "execution_count": null, 223 | "metadata": {}, 224 | "outputs": [], 225 | "source": [ 226 | "# Show results\n", 227 | "print('final states:', len(final_states))\n", 228 | "\n", 229 | "for final_state in final_states:\n", 230 | " if final_state.result:\n", 231 | " print('Feasible path:','->'.join([str(x) for x in final_state.path_history]))\n", 232 | " print('\\t',final_state.path_conds)\n", 233 | " else:\n", 234 | " print('Infeasible path:','->'.join([str(x) for x in final_state.path_history]))\n", 235 | " print('\\t',final_state.path_conds)\n", 236 | "\n", 237 | " final_state.sb.dump(ids=False)\n", 238 | " print('')\n", 239 | " \n", 240 | "assert len(final_states) == 2, '# of Final States is incorrect'\n", 241 | "assert len([x for x in final_states if x.result == True]) == 1, '# of feasible is incorrect'\n", 242 | "assert len([x for x in final_states if x.result == False]) == 1, '# of infeasible is incorrect'\n", 243 | "\n", 244 | "print('Congrats!')" 245 | ] 246 | } 247 | ], 248 | "metadata": { 249 | "kernelspec": { 250 | "display_name": "Python 3", 251 | "language": "python", 252 | "name": "python3" 253 | }, 254 | "language_info": { 255 | "codemirror_mode": { 256 | "name": "ipython", 257 | "version": 3 258 | }, 259 | "file_extension": ".py", 260 | "mimetype": "text/x-python", 261 | "name": "python", 262 | "nbconvert_exporter": "python", 263 | "pygments_lexer": "ipython3", 264 | "version": "3.6.9" 265 | } 266 | }, 267 | "nbformat": 4, 268 | "nbformat_minor": 4 269 | } 270 | -------------------------------------------------------------------------------- /hands-on3/solved/simple_explore_smt.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.arch.x86.arch import mn_x86\n", 12 | "from miasm.ir.symbexec import SymbolicExecutionEngine\n", 13 | "from miasm.expression.expression import ExprCond, ExprId, ExprInt, ExprMem \n", 14 | "from miasm.expression.simplifications import expr_simp\n", 15 | "from miasm.arch.x86.regs import *\n", 16 | "from miasm.core import parse_asm, asmblock\n", 17 | "from miasm.core.locationdb import LocationDB\n", 18 | "from miasm.analysis.binary import Container\n", 19 | "from future.utils import viewitems\n", 20 | "from miasm.loader.strpatchwork import *\n", 21 | "from miasm.ir.translators.translator import Translator\n", 22 | "import warnings\n", 23 | "import z3" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "def check_path_feasibility(conds):\n", 33 | " solver = z3.Solver()\n", 34 | " for lval, rval in conds:\n", 35 | " z3_cond = Translator.to_language(\"z3\").from_expr(lval)\n", 36 | " solver.add(z3_cond == int(rval.arg))\n", 37 | "\n", 38 | " rslt = solver.check()\n", 39 | "\n", 40 | " if rslt == z3.sat:\n", 41 | " return True\n", 42 | " else:\n", 43 | " return False" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "metadata": {}, 50 | "outputs": [], 51 | "source": [ 52 | "class FinalState:\n", 53 | " def __init__(self, result, sym, path_conds, path_history):\n", 54 | " self.result = result\n", 55 | " self.sb = sym\n", 56 | " self.path_conds = path_conds\n", 57 | " self.path_history = path_history" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": {}, 64 | "outputs": [], 65 | "source": [ 66 | "def explore(ir, start_addr, start_symbols, \n", 67 | " ircfg, cond_limit=30, uncond_limit=100, \n", 68 | " lbl_stop=None, final_states=[]):\n", 69 | "\n", 70 | " def codepath_walk(addr, symbols, conds, depth, final_states, path):\n", 71 | "\n", 72 | " if depth >= cond_limit:\n", 73 | " warnings.warn(\"'depth' is over the cond_limit :%d\"%(depth))\n", 74 | " return \n", 75 | "\n", 76 | " sb = SymbolicExecutionEngine(ir, symbols)\n", 77 | "\n", 78 | " for _ in range(uncond_limit):\n", 79 | "\n", 80 | " if isinstance(addr, ExprInt): \n", 81 | " if addr == lbl_stop:\n", 82 | " final_states.append(FinalState(True, sb, conds, path))\n", 83 | " return\n", 84 | "\n", 85 | " path.append(addr)\n", 86 | "\n", 87 | " pc = sb.run_block_at(ircfg, addr)\n", 88 | "\n", 89 | " if isinstance(pc, ExprCond): \n", 90 | " \n", 91 | " # Calc the condition to take true or false paths\n", 92 | " cond_true = {pc.cond: ExprInt(1, 32)}\n", 93 | " cond_false = {pc.cond: ExprInt(0, 32)}\n", 94 | "\n", 95 | " # The destination addr of the true or false paths\n", 96 | " addr_true = expr_simp(\n", 97 | " sb.eval_expr(pc.replace_expr(cond_true), {}))\n", 98 | "\n", 99 | " addr_false = expr_simp(\n", 100 | " sb.eval_expr(pc.replace_expr(cond_false), {}))\n", 101 | "\n", 102 | " # Need to add the path conditions to reach this point\n", 103 | " conds_true = list(conds) + list(cond_true.items())\n", 104 | " conds_false = list(conds) + list(cond_false.items())\n", 105 | "\n", 106 | " # TODO:\n", 107 | " # Please add some code to complete the SMT-based path explore\n", 108 | " # Hint1: use check_path_feasibility()\n", 109 | " # Hint2: Do not forget to add the current state to the final_states \n", 110 | " # when the path condition is infeasible. \n", 111 | " # e.g., final_states.append(FinalState(False, sb, conds_true/conds_false, path))\n", 112 | " #\n", 113 | " # From here --------------------------------\n", 114 | " \n", 115 | " if check_path_feasibility(conds_true):\n", 116 | " codepath_walk(\n", 117 | " addr_true, sb.symbols.copy(), \n", 118 | " conds_true, depth + 1, final_states, list(path))\n", 119 | " else:\n", 120 | " final_states.append(FinalState(False, sb, conds_true, path))\n", 121 | " \n", 122 | " if check_path_feasibility(conds_false):\n", 123 | " codepath_walk(\n", 124 | " addr_false, sb.symbols.copy(), \n", 125 | " conds_false, depth + 1, final_states, list(path))\n", 126 | " else:\n", 127 | " final_states.append(FinalState(False, sb, conds_false, path))\n", 128 | "\n", 129 | " # To here --------------------------------\n", 130 | "\n", 131 | " return\n", 132 | " else:\n", 133 | " addr = expr_simp(sb.eval_expr(pc))\n", 134 | "\n", 135 | " final_states.append(FinalState(True, sb, conds, path))\n", 136 | " return \n", 137 | "\n", 138 | " return codepath_walk(start_addr, start_symbols, [], 0, final_states, [])" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": null, 144 | "metadata": {}, 145 | "outputs": [], 146 | "source": [ 147 | "# Assemble code\n", 148 | "loc_db = LocationDB()\n", 149 | "asmcfg = parse_asm.parse_txt(mn_x86, 32, ''' \n", 150 | "main:\n", 151 | " PUSH EBP\n", 152 | " MOV EBP, ESP\n", 153 | " MOV ECX, 0x23\n", 154 | " MOV EDX, EAX\n", 155 | " MUL EDX\n", 156 | " CMP EAX, -1\n", 157 | " JNZ label\n", 158 | " MOV DWORD PTR [0xDEADBEEF], ECX\n", 159 | "\n", 160 | "label:\n", 161 | " MOV ECX, 0x4\n", 162 | " MOV EAX, ECX\n", 163 | " POP EBP\n", 164 | " RET\n", 165 | "''', loc_db)" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": null, 171 | "metadata": {}, 172 | "outputs": [], 173 | "source": [ 174 | "loc_db.set_location_offset(loc_db.get_name_location('main'), 0x0)\n", 175 | "\n", 176 | "patches = asmblock.asm_resolve_final(mn_x86, asmcfg)\n", 177 | "patch_worker = StrPatchwork()\n", 178 | "for offset, raw in patches.items():\n", 179 | " patch_worker[offset] = raw\n", 180 | " print('%08x'%(offset), mn_x86.dis(raw, 32))\n", 181 | "\n", 182 | "cont = Container.from_string(array_tobytes(patch_worker.s), loc_db)\n", 183 | "\n", 184 | "machine = Machine('x86_32')\n", 185 | "mdis = machine.dis_engine(cont.bin_stream, loc_db=loc_db)\n", 186 | "\n", 187 | "asmcfg2 = mdis.dis_multiblock(0)\n", 188 | "\n", 189 | "ir_arch = machine.ira(loc_db)\n", 190 | "ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg2)\n", 191 | "\n", 192 | "for lbl, irb in viewitems(ircfg.blocks):\n", 193 | " print(irb)" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "symbols_init = {\n", 203 | " ExprMem(ExprId('ESP_init', 32), 32) : ExprInt(0xdeadbeef, 32)\n", 204 | "}\n", 205 | "\n", 206 | "for i, r in enumerate(all_regs_ids):\n", 207 | " symbols_init[r] = all_regs_ids_init[i]\n", 208 | "\n", 209 | "final_states = []" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "explore(ir_arch, \n", 219 | " 0, \n", 220 | " symbols_init, \n", 221 | " ircfg, \n", 222 | " lbl_stop=0xdeadbeef, \n", 223 | " final_states=final_states)" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": null, 229 | "metadata": {}, 230 | "outputs": [], 231 | "source": [ 232 | "# Show results\n", 233 | "print('final states:', len(final_states))\n", 234 | "\n", 235 | "for final_state in final_states:\n", 236 | " if final_state.result:\n", 237 | " print('Feasible path:','->'.join([str(x) for x in final_state.path_history]))\n", 238 | " print('\\t',final_state.path_conds)\n", 239 | " else:\n", 240 | " print('Infeasible path:','->'.join([str(x) for x in final_state.path_history]))\n", 241 | " print('\\t',final_state.path_conds)\n", 242 | "\n", 243 | " final_state.sb.dump(ids=False)\n", 244 | " print('')\n", 245 | " \n", 246 | "assert len(final_states) == 2, '# of Final States is incorrect'\n", 247 | "assert len([x for x in final_states if x.result == True]) == 1, '# of feasible is incorrect'\n", 248 | "assert len([x for x in final_states if x.result == False]) == 1, '# of infeasible is incorrect'\n", 249 | "\n", 250 | "print('Congrats!')" 251 | ] 252 | } 253 | ], 254 | "metadata": { 255 | "kernelspec": { 256 | "display_name": "Python 3", 257 | "language": "python", 258 | "name": "python3" 259 | }, 260 | "language_info": { 261 | "codemirror_mode": { 262 | "name": "ipython", 263 | "version": 3 264 | }, 265 | "file_extension": ".py", 266 | "mimetype": "text/x-python", 267 | "name": "python", 268 | "nbconvert_exporter": "python", 269 | "pygments_lexer": "ipython3", 270 | "version": "3.6.9" 271 | } 272 | }, 273 | "nbformat": 4, 274 | "nbformat_minor": 4 275 | } 276 | -------------------------------------------------------------------------------- /hands-on3/x-tunnel.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malrev/ABD/0fe01674a4b0f1879f9c36d7b1e76e3c1d670d26/hands-on3/x-tunnel.zip -------------------------------------------------------------------------------- /hands-on4/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | rm -Rf *.idc 3 | rm -Rf *.bin 4 | 5 | 6 | -------------------------------------------------------------------------------- /hands-on4/asprox.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malrev/ABD/0fe01674a4b0f1879f9c36d7b1e76e3c1d670d26/hands-on4/asprox.zip -------------------------------------------------------------------------------- /hands-on4/eqcheck.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.ir.symbexec import SymbolicExecutionEngine\n", 12 | "from miasm.ir.ir import IRCFG\n", 13 | "from miasm.expression.expression import LocKey\n", 14 | "from miasm.arch.x86.regs import *\n", 15 | "from miasm.core import asmblock\n", 16 | "from miasm.core.locationdb import LocationDB\n", 17 | "from miasm.analysis.binary import Container\n", 18 | "from future.utils import viewitems\n", 19 | "from miasm.ir.translators.translator import Translator\n", 20 | "import networkx as nx\n", 21 | "import random\n", 22 | "import z3" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "!unzip -n -P infected vipasana.zip\n", 32 | "!unzip -n -P infected asprox.zip" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "filename = 'vipasana.bin'\n", 42 | "target_addr = 0x434DF0\n", 43 | "#filename = 'asprox.bin'\n", 44 | "#target_addr = 0x100091AC\n", 45 | "idc = True" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "def syntax_compare(blk0, blk1):\n", 55 | " if len(blk0.lines) != len(blk1.lines):\n", 56 | " return False\n", 57 | "\n", 58 | " for l0, l1 in zip(blk0.lines, blk1.lines):\n", 59 | " if str(l0)[0] == 'J':\n", 60 | " instr0 = str(l0).split(' ')[0]\n", 61 | " instr1 = str(l1).split(' ')[0]\n", 62 | " if instr0 != instr1:\n", 63 | " return False\n", 64 | " else:\n", 65 | " if str(l0) != str(l1):\n", 66 | " return False\n", 67 | "\n", 68 | " return True" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "def semantic_compare(blk0, blk1, ir_arch0, ir_arch1, asmcfg, flag_cmp=False):\n", 78 | " src_ircfg = IRCFG(None, ir_arch0.loc_db)\n", 79 | " try:\n", 80 | " ir_arch0.add_asmblock_to_ircfg(blk0, src_ircfg)\n", 81 | " except NotImplementedError:\n", 82 | " return False\n", 83 | "\n", 84 | " dst_ircfg = IRCFG(None, ir_arch1.loc_db)\n", 85 | " try:\n", 86 | " ir_arch1.add_asmblock_to_ircfg(blk1, dst_ircfg)\n", 87 | " except NotImplementedError:\n", 88 | " return False\n", 89 | "\n", 90 | " if len(src_ircfg.blocks) != len(dst_ircfg.blocks):\n", 91 | " return False\n", 92 | "\n", 93 | " for src_lbl, dst_lbl in zip(src_ircfg.blocks, dst_ircfg.blocks):\n", 94 | "\n", 95 | " src_irb = src_ircfg.blocks.get(src_lbl, None)\n", 96 | " dst_irb = dst_ircfg.blocks.get(dst_lbl, None)\n", 97 | "\n", 98 | " r = execute_symbolic_execution(\n", 99 | " src_irb, dst_irb, \n", 100 | " ir_arch0, ir_arch1, \n", 101 | " src_ircfg, dst_ircfg,\n", 102 | " flag_cmp)\n", 103 | " if r is False:\n", 104 | " return False\n", 105 | "\n", 106 | " return True" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "def execute_symbolic_execution(src_irb, dst_irb, \n", 116 | " ir_arch0, ir_arch1, \n", 117 | " src_ircfg, dst_ircfg,\n", 118 | " flag_cmp):\n", 119 | "\n", 120 | " # Ready for Symbolic Execution\n", 121 | " src_symbols = {}\n", 122 | " dst_symbols = {}\n", 123 | "\n", 124 | " # regs\n", 125 | " for i, r in enumerate(all_regs_ids):\n", 126 | " src_symbols[r] = all_regs_ids_init[i]\n", 127 | " dst_symbols[r] = all_regs_ids_init[i]\n", 128 | "\n", 129 | "\n", 130 | " # Run symbolic execution\n", 131 | " src_sb = SymbolicExecutionEngine(ir_arch0, src_symbols)\n", 132 | "\n", 133 | " for assignblk in src_irb:\n", 134 | " skip_update = False\n", 135 | " for dst, src in viewitems(assignblk):\n", 136 | " if str(dst) in ['EIP', 'IRDst']:\n", 137 | " skip_update = True\n", 138 | "\n", 139 | " if not skip_update:\n", 140 | " src_sb.eval_updt_assignblk(assignblk)\n", 141 | "\n", 142 | " dst_sb = SymbolicExecutionEngine(ir_arch1, dst_symbols)\n", 143 | "\n", 144 | " for assignblk in dst_irb:\n", 145 | " skip_update = False\n", 146 | " for dst, src in viewitems(assignblk):\n", 147 | " if str(dst) in ['EIP', 'IRDst']:\n", 148 | " skip_update = True\n", 149 | "\n", 150 | " if not skip_update:\n", 151 | " dst_sb.eval_updt_assignblk(assignblk)\n", 152 | "\n", 153 | " # Equivalence Checking\n", 154 | "\n", 155 | " src_sb.del_mem_above_stack(ir_arch0.sp)\n", 156 | " dst_sb.del_mem_above_stack(ir_arch1.sp)\n", 157 | "\n", 158 | " all_memory_ids = [k for k, v in dst_sb.symbols.memory()] + [k for k, v in src_sb.symbols.memory()]\n", 159 | "\n", 160 | " for k in all_regs_ids + all_memory_ids:\n", 161 | "\n", 162 | " if str(k) == 'EIP':\n", 163 | " continue\n", 164 | "\n", 165 | " if not flag_cmp and k in [zf, nf, pf, of, cf, af, df, tf]:\n", 166 | " continue\n", 167 | "\n", 168 | " v0 = src_sb.symbols[k]\n", 169 | " v1 = dst_sb.symbols[k]\n", 170 | "\n", 171 | " if v0 == v1:\n", 172 | " continue\n", 173 | "\n", 174 | " solver = z3.Solver()\n", 175 | " try:\n", 176 | " z3_r_cond = Translator.to_language('z3').from_expr(v0)\n", 177 | " except NotImplementedError:\n", 178 | " return False\n", 179 | "\n", 180 | " try:\n", 181 | " z3_l_cond = Translator.to_language('z3').from_expr(v1)\n", 182 | " except NotImplementedError:\n", 183 | " return False\n", 184 | "\n", 185 | " # TODO:\n", 186 | " # Please add just one line of code below to check the equivalence of z3_l_cond and z3_r_cond.\n", 187 | " # Hint: we can add a constraint to 'solver' with 'add' method, e.g., solver.add(A == B).\n", 188 | " # From HERE ------------------------------------------\n", 189 | "\n", 190 | " #solver.add()\n", 191 | "\n", 192 | " # TO HERE ------------------------------------------\n", 193 | "\n", 194 | " r = solver.check()\n", 195 | " if r == z3.unsat:\n", 196 | " continue\n", 197 | "\n", 198 | " else:\n", 199 | " #print(solver.model()) # Counterexample\n", 200 | " return False\n", 201 | "\n", 202 | " return True" 203 | ] 204 | }, 205 | { 206 | "cell_type": "code", 207 | "execution_count": null, 208 | "metadata": {}, 209 | "outputs": [], 210 | "source": [ 211 | "loc_db = LocationDB()\n", 212 | "with open(filename, 'rb') as fstream: \n", 213 | " cont = Container.from_stream(fstream, loc_db)\n", 214 | " \n", 215 | "machine = Machine('x86_32')\n", 216 | "mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db)\n", 217 | "ir_arch0 = machine.ira(mdis.loc_db)\n", 218 | "ir_arch1 = machine.ira(mdis.loc_db)\n", 219 | "\n", 220 | "asmcfg = mdis.dis_multiblock(target_addr)" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": null, 226 | "metadata": {}, 227 | "outputs": [], 228 | "source": [ 229 | "target_blocks = []\n", 230 | "for cn, block in enumerate(asmcfg.blocks):\n", 231 | " target_blocks.append(block)\n", 232 | "\n", 233 | "results = {}\n", 234 | "\n", 235 | "for src_blk in target_blocks:\n", 236 | " src_ldl = src_blk._loc_key\n", 237 | "\n", 238 | " # Skip a basic block containing only single instruction\n", 239 | " if len(src_blk.lines) == 1 and src_blk.lines[0].dstflow():\n", 240 | " continue\n", 241 | "\n", 242 | " for dst_blk in target_blocks:\n", 243 | " dst_ldl = dst_blk._loc_key\n", 244 | "\n", 245 | " # Skip a basic block containing only single instruction\n", 246 | " if len(dst_blk.lines) == 1 and dst_blk.lines[0].dstflow():\n", 247 | " continue\n", 248 | "\n", 249 | " if src_ldl == dst_ldl:\n", 250 | " continue\n", 251 | "\n", 252 | " if (src_ldl, dst_ldl) in results.keys() or \\\n", 253 | " (dst_ldl, src_ldl) in results.keys():\n", 254 | " continue\n", 255 | " \n", 256 | " r_syntax = syntax_compare(src_blk, dst_blk)\n", 257 | "\n", 258 | " if r_syntax:\n", 259 | " # If the syntax of two blocks is same, then the semantics of them is also same.\n", 260 | " r_semantic = True\n", 261 | " else:\n", 262 | " # Otherwise, need to compare the semantics of them\n", 263 | " r_semantic = semantic_compare(src_blk, dst_blk, ir_arch0, ir_arch1, asmcfg)\n", 264 | "\n", 265 | " results[(src_ldl, dst_ldl)] = [(r_syntax, r_semantic)]" 266 | ] 267 | }, 268 | { 269 | "cell_type": "code", 270 | "execution_count": null, 271 | "metadata": {}, 272 | "outputs": [], 273 | "source": [ 274 | "if idc:\n", 275 | " G = nx.Graph()\n", 276 | " G.add_nodes_from(target_blocks)\n", 277 | "\n", 278 | " for k, v in viewitems(results):\n", 279 | " if v[0][0] or v[0][1]:\n", 280 | " G.add_edge(k[0], k[1])\n", 281 | "\n", 282 | " # Return a list containing randomlly generated colors\n", 283 | " def gen_random_color():\n", 284 | "\n", 285 | " ret = []\n", 286 | "\n", 287 | " r = [x for x in range(256)]\n", 288 | " g = [x for x in range(256)]\n", 289 | " b = [x for x in range(256)]\n", 290 | " random.shuffle(r)\n", 291 | " random.shuffle(g)\n", 292 | " random.shuffle(b)\n", 293 | "\n", 294 | " for a2, a1, a0 in zip(r,g,b):\n", 295 | " color = a2 << 16 | a1 << 8 | a0\n", 296 | " ret.append(color)\n", 297 | "\n", 298 | " return ret\n", 299 | "\n", 300 | " random_colors = gen_random_color()\n", 301 | " body = ''\n", 302 | "\n", 303 | " for n, conn_nodes in enumerate(nx.connected_components(G)):\n", 304 | "\n", 305 | " if len(conn_nodes) == 1:\n", 306 | " continue\n", 307 | "\n", 308 | " for node in conn_nodes: # node is asmblk\n", 309 | "\n", 310 | " if isinstance(node, LocKey):\n", 311 | " asmblk = asmcfg.loc_key_to_block(node)\n", 312 | " if asmblk:\n", 313 | " for l in asmblk.lines:\n", 314 | " body += 'SetColor(0x%08x, CIC_ITEM, 0x%x);\\n'%(l.offset, random_colors[n])\n", 315 | " else:\n", 316 | " for l in node.lines:\n", 317 | " body += 'SetColor(0x%08x, CIC_ITEM, 0x%x);\\n'%(l.offset, random_colors[n])\n", 318 | " \n", 319 | " header = '''\n", 320 | "#include \n", 321 | "static main()\n", 322 | "{\n", 323 | "'''\n", 324 | " footer = '''\n", 325 | "}\n", 326 | "'''\n", 327 | "\n", 328 | " f = open('eq-color.idc', 'w')\n", 329 | " f.write(header+body+footer)\n", 330 | " f.close()" 331 | ] 332 | } 333 | ], 334 | "metadata": { 335 | "kernelspec": { 336 | "display_name": "Python 3", 337 | "language": "python", 338 | "name": "python3" 339 | }, 340 | "language_info": { 341 | "codemirror_mode": { 342 | "name": "ipython", 343 | "version": 3 344 | }, 345 | "file_extension": ".py", 346 | "mimetype": "text/x-python", 347 | "name": "python", 348 | "nbconvert_exporter": "python", 349 | "pygments_lexer": "ipython3", 350 | "version": "3.6.9" 351 | } 352 | }, 353 | "nbformat": 4, 354 | "nbformat_minor": 4 355 | } 356 | -------------------------------------------------------------------------------- /hands-on4/solved/eqcheck.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.ir.symbexec import SymbolicExecutionEngine\n", 12 | "from miasm.ir.ir import IRCFG\n", 13 | "from miasm.expression.expression import LocKey\n", 14 | "from miasm.arch.x86.regs import *\n", 15 | "from miasm.core import asmblock\n", 16 | "from miasm.core.locationdb import LocationDB\n", 17 | "from miasm.analysis.binary import Container\n", 18 | "from future.utils import viewitems\n", 19 | "from miasm.ir.translators.translator import Translator\n", 20 | "import networkx as nx\n", 21 | "import random\n", 22 | "import z3" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "!unzip -n -P infected vipasana.zip\n", 32 | "!unzip -n -P infected asprox.zip" 33 | ] 34 | }, 35 | { 36 | "cell_type": "code", 37 | "execution_count": null, 38 | "metadata": {}, 39 | "outputs": [], 40 | "source": [ 41 | "filename = 'vipasana.bin'\n", 42 | "target_addr = 0x434DF0\n", 43 | "#filename = '../asprox.bin'\n", 44 | "#target_addr = 0x100091AC\n", 45 | "idc = True" 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "def syntax_compare(blk0, blk1):\n", 55 | " if len(blk0.lines) != len(blk1.lines):\n", 56 | " return False\n", 57 | "\n", 58 | " for l0, l1 in zip(blk0.lines, blk1.lines):\n", 59 | " if str(l0)[0] == 'J':\n", 60 | " instr0 = str(l0).split(' ')[0]\n", 61 | " instr1 = str(l1).split(' ')[0]\n", 62 | " if instr0 != instr1:\n", 63 | " return False\n", 64 | " else:\n", 65 | " if str(l0) != str(l1):\n", 66 | " return False\n", 67 | "\n", 68 | " return True" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "def semantic_compare(blk0, blk1, ir_arch0, ir_arch1, asmcfg, flag_cmp=False):\n", 78 | " src_ircfg = IRCFG(None, ir_arch0.loc_db)\n", 79 | " try:\n", 80 | " ir_arch0.add_asmblock_to_ircfg(blk0, src_ircfg)\n", 81 | " except NotImplementedError:\n", 82 | " return False\n", 83 | "\n", 84 | " dst_ircfg = IRCFG(None, ir_arch1.loc_db)\n", 85 | " try:\n", 86 | " ir_arch1.add_asmblock_to_ircfg(blk1, dst_ircfg)\n", 87 | " except NotImplementedError:\n", 88 | " return False\n", 89 | "\n", 90 | " if len(src_ircfg.blocks) != len(dst_ircfg.blocks):\n", 91 | " return False\n", 92 | "\n", 93 | " for src_lbl, dst_lbl in zip(src_ircfg.blocks, dst_ircfg.blocks):\n", 94 | "\n", 95 | " src_irb = src_ircfg.blocks.get(src_lbl, None)\n", 96 | " dst_irb = dst_ircfg.blocks.get(dst_lbl, None)\n", 97 | "\n", 98 | " r = execute_symbolic_execution(\n", 99 | " src_irb, dst_irb, \n", 100 | " ir_arch0, ir_arch1, \n", 101 | " src_ircfg, dst_ircfg,\n", 102 | " flag_cmp)\n", 103 | " if r is False:\n", 104 | " return False\n", 105 | "\n", 106 | " return True" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "execution_count": null, 112 | "metadata": {}, 113 | "outputs": [], 114 | "source": [ 115 | "def execute_symbolic_execution(src_irb, dst_irb, \n", 116 | " ir_arch0, ir_arch1, \n", 117 | " src_ircfg, dst_ircfg,\n", 118 | " flag_cmp):\n", 119 | "\n", 120 | " # Ready for Symbolic Execution\n", 121 | " src_symbols = {}\n", 122 | " dst_symbols = {}\n", 123 | "\n", 124 | " # regs\n", 125 | " for i, r in enumerate(all_regs_ids):\n", 126 | " src_symbols[r] = all_regs_ids_init[i]\n", 127 | " dst_symbols[r] = all_regs_ids_init[i]\n", 128 | "\n", 129 | "\n", 130 | " # Run symbolic execution\n", 131 | " src_sb = SymbolicExecutionEngine(ir_arch0, src_symbols)\n", 132 | "\n", 133 | " for assignblk in src_irb:\n", 134 | " skip_update = False\n", 135 | " for dst, src in viewitems(assignblk):\n", 136 | " if str(dst) in ['EIP', 'IRDst']:\n", 137 | " skip_update = True\n", 138 | "\n", 139 | " if not skip_update:\n", 140 | " src_sb.eval_updt_assignblk(assignblk)\n", 141 | "\n", 142 | " dst_sb = SymbolicExecutionEngine(ir_arch1, dst_symbols)\n", 143 | "\n", 144 | " for assignblk in dst_irb:\n", 145 | " skip_update = False\n", 146 | " for dst, src in viewitems(assignblk):\n", 147 | " if str(dst) in ['EIP', 'IRDst']:\n", 148 | " skip_update = True\n", 149 | "\n", 150 | " if not skip_update:\n", 151 | " dst_sb.eval_updt_assignblk(assignblk)\n", 152 | "\n", 153 | " # Equivalence Checking\n", 154 | "\n", 155 | " src_sb.del_mem_above_stack(ir_arch0.sp)\n", 156 | " dst_sb.del_mem_above_stack(ir_arch1.sp)\n", 157 | "\n", 158 | " all_memory_ids = [k for k, v in dst_sb.symbols.memory()] + [k for k, v in src_sb.symbols.memory()]\n", 159 | "\n", 160 | " for k in all_regs_ids + all_memory_ids:\n", 161 | "\n", 162 | " if str(k) == 'EIP':\n", 163 | " continue\n", 164 | "\n", 165 | " if not flag_cmp and k in [zf, nf, pf, of, cf, af, df, tf]:\n", 166 | " continue\n", 167 | "\n", 168 | " v0 = src_sb.symbols[k]\n", 169 | " v1 = dst_sb.symbols[k]\n", 170 | "\n", 171 | " if v0 == v1:\n", 172 | " continue\n", 173 | "\n", 174 | " solver = z3.Solver()\n", 175 | " try:\n", 176 | " z3_r_cond = Translator.to_language('z3').from_expr(v0)\n", 177 | " except NotImplementedError:\n", 178 | " return False\n", 179 | "\n", 180 | " try:\n", 181 | " z3_l_cond = Translator.to_language('z3').from_expr(v1)\n", 182 | " except NotImplementedError:\n", 183 | " return False\n", 184 | "\n", 185 | " # HERE\n", 186 | " solver.add(z3.Not(z3_r_cond == z3_l_cond))\n", 187 | "\n", 188 | " r = solver.check()\n", 189 | " if r == z3.unsat:\n", 190 | " continue\n", 191 | "\n", 192 | " else:\n", 193 | " #print(solver.model()) # Counterexample\n", 194 | " return False\n", 195 | "\n", 196 | " return True" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "metadata": {}, 203 | "outputs": [], 204 | "source": [ 205 | "loc_db = LocationDB()\n", 206 | "with open(filename, 'rb') as fstream: \n", 207 | " cont = Container.from_stream(fstream, loc_db)\n", 208 | " \n", 209 | "machine = Machine('x86_32')\n", 210 | "mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db)\n", 211 | "ir_arch0 = machine.ira(mdis.loc_db)\n", 212 | "ir_arch1 = machine.ira(mdis.loc_db)\n", 213 | "\n", 214 | "asmcfg = mdis.dis_multiblock(target_addr)" 215 | ] 216 | }, 217 | { 218 | "cell_type": "code", 219 | "execution_count": null, 220 | "metadata": {}, 221 | "outputs": [], 222 | "source": [ 223 | "target_blocks = []\n", 224 | "for cn, block in enumerate(asmcfg.blocks):\n", 225 | " target_blocks.append(block)\n", 226 | "\n", 227 | "results = {}\n", 228 | "\n", 229 | "for src_blk in target_blocks:\n", 230 | " src_ldl = src_blk._loc_key\n", 231 | "\n", 232 | " # Skip a basic block containing only single instruction\n", 233 | " if len(src_blk.lines) == 1 and src_blk.lines[0].dstflow():\n", 234 | " continue\n", 235 | "\n", 236 | " for dst_blk in target_blocks:\n", 237 | " dst_ldl = dst_blk._loc_key\n", 238 | "\n", 239 | " # Skip a basic block containing only single instruction\n", 240 | " if len(dst_blk.lines) == 1 and dst_blk.lines[0].dstflow():\n", 241 | " continue\n", 242 | "\n", 243 | " if src_ldl == dst_ldl:\n", 244 | " continue\n", 245 | "\n", 246 | " if (src_ldl, dst_ldl) in results.keys() or \\\n", 247 | " (dst_ldl, src_ldl) in results.keys():\n", 248 | " continue\n", 249 | " \n", 250 | " r_syntax = syntax_compare(src_blk, dst_blk)\n", 251 | "\n", 252 | " if r_syntax:\n", 253 | " # If the syntax of two blocks is same, then the semantics of them is also same.\n", 254 | " r_semantic = True\n", 255 | " else:\n", 256 | " # Otherwise, need to compare the semantics of them\n", 257 | " r_semantic = semantic_compare(src_blk, dst_blk, ir_arch0, ir_arch1, asmcfg)\n", 258 | "\n", 259 | " results[(src_ldl, dst_ldl)] = [(r_syntax, r_semantic)]" 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": null, 265 | "metadata": {}, 266 | "outputs": [], 267 | "source": [ 268 | "if idc:\n", 269 | " G = nx.Graph()\n", 270 | " G.add_nodes_from(target_blocks)\n", 271 | "\n", 272 | " for k, v in viewitems(results):\n", 273 | " if v[0][0] or v[0][1]:\n", 274 | " G.add_edge(k[0], k[1])\n", 275 | "\n", 276 | " # Return a list containing randomlly generated colors\n", 277 | " def gen_random_color():\n", 278 | "\n", 279 | " ret = []\n", 280 | "\n", 281 | " r = [x for x in range(256)]\n", 282 | " g = [x for x in range(256)]\n", 283 | " b = [x for x in range(256)]\n", 284 | " random.shuffle(r)\n", 285 | " random.shuffle(g)\n", 286 | " random.shuffle(b)\n", 287 | "\n", 288 | " for a2, a1, a0 in zip(r,g,b):\n", 289 | " color = a2 << 16 | a1 << 8 | a0\n", 290 | " ret.append(color)\n", 291 | "\n", 292 | " return ret\n", 293 | "\n", 294 | " random_colors = gen_random_color()\n", 295 | " body = ''\n", 296 | "\n", 297 | " for n, conn_nodes in enumerate(nx.connected_components(G)):\n", 298 | "\n", 299 | " if len(conn_nodes) == 1:\n", 300 | " continue\n", 301 | "\n", 302 | " for node in conn_nodes: # node is asmblk\n", 303 | "\n", 304 | " if isinstance(node, LocKey):\n", 305 | " asmblk = asmcfg.loc_key_to_block(node)\n", 306 | " if asmblk:\n", 307 | " for l in asmblk.lines:\n", 308 | " body += 'SetColor(0x%08x, CIC_ITEM, 0x%x);\\n'%(l.offset, random_colors[n])\n", 309 | " else:\n", 310 | " for l in node.lines:\n", 311 | " body += 'SetColor(0x%08x, CIC_ITEM, 0x%x);\\n'%(l.offset, random_colors[n])\n", 312 | " \n", 313 | " header = '''\n", 314 | "#include \n", 315 | "static main()\n", 316 | "{\n", 317 | "'''\n", 318 | " footer = '''\n", 319 | "}\n", 320 | "'''\n", 321 | "\n", 322 | " f = open('eq-color.idc', 'w')\n", 323 | " f.write(header+body+footer)\n", 324 | " f.close()" 325 | ] 326 | } 327 | ], 328 | "metadata": { 329 | "kernelspec": { 330 | "display_name": "Python 3", 331 | "language": "python", 332 | "name": "python3" 333 | }, 334 | "language_info": { 335 | "codemirror_mode": { 336 | "name": "ipython", 337 | "version": 3 338 | }, 339 | "file_extension": ".py", 340 | "mimetype": "text/x-python", 341 | "name": "python", 342 | "nbconvert_exporter": "python", 343 | "pygments_lexer": "ipython3", 344 | "version": "3.6.9" 345 | } 346 | }, 347 | "nbformat": 4, 348 | "nbformat_minor": 4 349 | } 350 | -------------------------------------------------------------------------------- /hands-on4/vipasana.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malrev/ABD/0fe01674a4b0f1879f9c36d7b1e76e3c1d670d26/hands-on4/vipasana.zip -------------------------------------------------------------------------------- /hands-on5/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | rm -Rf *.idc 3 | rm -Rf *.bin 4 | rm -Rf *.idb 5 | rm -Rf *.pyc 6 | rm -Rf solved/*.pyc 7 | 8 | 9 | -------------------------------------------------------------------------------- /hands-on5/solved/zeus_get_ir.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.analysis.binary import Container\n", 12 | "from miasm.expression.expression import *\n", 13 | "from miasm.core.utils import *\n", 14 | "from miasm.core.locationdb import LocationDB\n", 15 | "from miasm.arch.x86 import regs\n", 16 | "from miasm.ir.symbexec import SymbolicExecutionEngine, get_block\n", 17 | "from miasm.expression.simplifications import expr_simp" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": null, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "!unzip -n -P infected zeusvm.zip" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "filename = 'zeusvm.bin'\n", 36 | "\n", 37 | "machine = Machine('x86_32')\n", 38 | "loc_db = LocationDB()\n", 39 | "with open(filename, 'rb') as fstream:\n", 40 | " cont = Container.from_stream(fstream, loc_db)\n", 41 | "bs = cont.bin_stream\n", 42 | "mdis = machine.dis_engine(bs, loc_db=cont.loc_db)\n", 43 | "ir_arch = machine.ir(mdis.loc_db)" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "metadata": { 50 | "scrolled": false 51 | }, 52 | "outputs": [], 53 | "source": [ 54 | "# Error\n", 55 | "mnemonic_array_addr = 0x427018\n", 56 | "\n", 57 | "for i in range(69):\n", 58 | " # Get each handler address from the array\n", 59 | " addr = int(hex(upck32(bs.getbytes(mnemonic_array_addr + i*4, 4))), 16)\n", 60 | " print('*'*40, 'Mnemonic', i, ' addr', addr, '*'*40)\n", 61 | " \n", 62 | " # Generate AsmCFG and IRCFG\n", 63 | " asmcfg = mdis.dis_multiblock(addr)\n", 64 | " ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)\n", 65 | " irblock = ircfg.get_block(addr)\n", 66 | " \n", 67 | " # Initialize symbolic execution engine\n", 68 | " sb = SymbolicExecutionEngine(ir_arch)\n", 69 | " addr = sb.eval_updt_irblock(irblock)\n", 70 | " if not isinstance(addr, ExprInt):\n", 71 | " print('Unknown destination %s' % addr)" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "# Preparing the initial symbols for regs and mems\n", 81 | "symbols_init = dict(regs.regs_init)\n", 82 | "initial_symbols = symbols_init.items()\n", 83 | "ret_addr = ExprId('RET_ADDR', 32)\n", 84 | "vm_pc_init = ExprId('VM_PC_init', 32)\n", 85 | "infos = {}\n", 86 | "infos[expr_simp(ExprMem(regs.ECX_init, 32))] = vm_pc_init\n", 87 | "# Push return addr\n", 88 | "infos[expr_simp(ExprMem(regs.ESP_init-ExprInt(4, 32), 32))] = ret_addr\n", 89 | "infos[regs.ESP] = expr_simp(regs.ESP_init-ExprInt(4, 32))\n", 90 | "\n", 91 | "for i in range(0, 5):\n", 92 | " infos[expr_simp(ExprMem(regs.ECX_init + ExprInt(4*(i+1), 32), 32))] = ExprId('REG%d' % i, 32)\n", 93 | "\n", 94 | "addition_infos = dict(infos)\n", 95 | "\n", 96 | "# imm\n", 97 | "expr_imm8 = expr_simp(ExprMem(vm_pc_init + ExprInt(0x1, 32), 8))\n", 98 | "addition_infos[expr_imm8] = ExprId('imm8' , 8)\n", 99 | "\n", 100 | "expr_imm16 = expr_simp(ExprMem(vm_pc_init + ExprInt(0x1, 32), 16))\n", 101 | "addition_infos[expr_imm16] = ExprId('imm16' , 16)\n", 102 | "\n", 103 | "expr_imm32 = expr_simp(ExprMem(vm_pc_init + ExprInt(0x1, 32), 32))\n", 104 | "addition_infos[expr_imm32] = ExprId('imm32' , 32)\n", 105 | "\n", 106 | "# immb\n", 107 | "expr_imm8b = expr_simp(ExprMem(vm_pc_init + ExprInt(0x2, 32), 8))\n", 108 | "addition_infos[expr_imm8b] = ExprId('imm8b' , 8)\n", 109 | "\n", 110 | "expr_imm16b = expr_simp(ExprMem(vm_pc_init + ExprInt(0x2, 32), 16))\n", 111 | "addition_infos[expr_imm16b] = ExprId('imm16b' , 16)\n", 112 | "\n", 113 | "expr_imm32b = expr_simp(ExprMem(vm_pc_init + ExprInt(0x2, 32), 32))\n", 114 | "addition_infos[expr_imm32b] = ExprId('imm32b' , 32)\n", 115 | "\n", 116 | "imms = set([expr_imm8, expr_imm16, expr_imm32,\n", 117 | " expr_imm8b, expr_imm16b, expr_imm32b])\n", 118 | "\n", 119 | "imm8 = ExprId('imm8', 8)\n", 120 | "\n", 121 | "base_regx = expr_simp(regs.ECX_init + (imm8.zeroExtend(32) & ExprInt(0xF, 32)) * ExprInt(4, 32) + ExprInt(0xC, 32))\n", 122 | "addition_infos[expr_simp(ExprMem(base_regx, 32))] = ExprId('REGX' , 32)\n", 123 | "addition_infos[expr_simp(ExprMem(base_regx, 16))] = ExprId('REGX' , 32)[:16]\n", 124 | "addition_infos[expr_simp(ExprMem(base_regx, 8))] = ExprId('REGX' , 32)[:8]\n", 125 | "\n", 126 | "base_regy = expr_simp(regs.ECX_init + (imm8[4:8].zeroExtend(32)) * ExprInt(4, 32) + ExprInt(0xC, 32))\n", 127 | "addition_infos[expr_simp(ExprMem(base_regy, 32))] = ExprId('REGY' , 32)\n", 128 | "addition_infos[expr_simp(ExprMem(base_regy, 16))] = ExprId('REGY' , 16)[:16]\n", 129 | "addition_infos[expr_simp(ExprMem(base_regy, 8))] = ExprId('REGY' , 8)[:8]" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": null, 135 | "metadata": {}, 136 | "outputs": [], 137 | "source": [ 138 | "def dump_state(sb):\n", 139 | " print('-'*20, 'State', '-'*20)\n", 140 | " out = {}\n", 141 | " for expr, value in sorted(sb.symbols.items()):\n", 142 | " if (expr, value) in initial_symbols:\n", 143 | " continue\n", 144 | " if (expr, value) in addition_infos:\n", 145 | " continue\n", 146 | " if expr in [regs.zf, regs.cf, regs.nf, regs.of, regs.pf, regs.af,\n", 147 | " ir_arch.IRDst, regs.EIP]:\n", 148 | " continue\n", 149 | " expr_s = expr_simp(expr.replace_expr(addition_infos))\n", 150 | " expr = expr_s\n", 151 | " value = expr_simp(value.replace_expr(addition_infos))\n", 152 | " if expr == value:\n", 153 | " continue\n", 154 | " out[expr] = value\n", 155 | "\n", 156 | " out = sorted(out.items())\n", 157 | " x86_regs = []\n", 158 | " mem = []\n", 159 | " other = []\n", 160 | " for expr, value in out:\n", 161 | " if expr in regs.all_regs_ids:\n", 162 | " x86_regs.append((expr, value))\n", 163 | " elif isinstance(expr, ExprMem):\n", 164 | " mem.append((expr, value))\n", 165 | " else:\n", 166 | " other.append((expr, value))\n", 167 | "\n", 168 | " print('Regs:')\n", 169 | " for item in other:\n", 170 | " print('\\t%s = %s' % item)\n", 171 | " print('Mem:')\n", 172 | " for item in mem:\n", 173 | " print('\\t%s = %s' % item)\n", 174 | " print('x86:')\n", 175 | " for item in x86_regs:\n", 176 | " print('\\t%s = %s' % item)\n", 177 | " print('')" 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": null, 183 | "metadata": { 184 | "scrolled": false 185 | }, 186 | "outputs": [], 187 | "source": [ 188 | "mnemonic_array_addr = 0x427018\n", 189 | "\n", 190 | "for i in range(69):\n", 191 | " # Get each handler address from the array\n", 192 | " addr = int(hex(upck32(bs.getbytes(mnemonic_array_addr + 4*i, 4))), 16)\n", 193 | " print('*'*40, 'Mnemonic', i, ' addr', hex(addr), '*'*40)\n", 194 | " \n", 195 | " # Generate AsmCFG and IRCFG\n", 196 | " asmcfg = mdis.dis_multiblock(addr)\n", 197 | " ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)\n", 198 | " irblock = ircfg.get_block(addr)\n", 199 | " \n", 200 | " # Initialize symbolic execution engine\n", 201 | " sb = SymbolicExecutionEngine(ir_arch, symbols_init)\n", 202 | " for k, v in infos.items():\n", 203 | " sb.symbols[k] = v\n", 204 | "\n", 205 | " symbols = frozenset(sb.symbols.items())\n", 206 | " todo = set([(addr, symbols)])\n", 207 | "\n", 208 | " count = 20\n", 209 | " while todo and count > 0:\n", 210 | " count -=1\n", 211 | " \n", 212 | " addr, symbols = todo.pop()\n", 213 | " \n", 214 | " irblock = ircfg.get_block(addr) \n", 215 | " if not irblock:\n", 216 | " print(ValueError('Unknown destination %s' % addr))\n", 217 | " continue\n", 218 | "\n", 219 | " sb.symbols.symbols_id.clear()\n", 220 | " sb.symbols.symbols_mem.clear()\n", 221 | " for k, v in symbols:\n", 222 | " sb.symbols[k] = v\n", 223 | "\n", 224 | " print('Block', addr)\n", 225 | " addr = sb.eval_updt_irblock(irblock)\n", 226 | "\n", 227 | " sb.del_mem_above_stack(ir_arch.sp)\n", 228 | "\n", 229 | " if addr is ret_addr:\n", 230 | " print('Ret addr reached')\n", 231 | " ret_mn = expr_simp(sb.eval_expr(regs.EAX[:8]))\n", 232 | " if ret_mn != ExprInt(1, 8):\n", 233 | " print('Strange return', ret_mn)\n", 234 | " dump_state(sb)\n", 235 | " continue\n", 236 | "\n", 237 | " if isinstance(addr, ExprCond):\n", 238 | " todo.add((addr.src1, frozenset(sb.symbols.items())))\n", 239 | " todo.add((addr.src2, frozenset(sb.symbols.items())))\n", 240 | " continue\n", 241 | " if not isinstance(addr, ExprInt) or isinstance(addr, ExprId):\n", 242 | " print('BAD END', addr)\n", 243 | " break\n", 244 | "\n", 245 | " todo.add((addr, frozenset(sb.symbols.items())))\n", 246 | " if count == 0:\n", 247 | " print('Mnemonic too complex')\n" 248 | ] 249 | } 250 | ], 251 | "metadata": { 252 | "kernelspec": { 253 | "display_name": "Python 3", 254 | "language": "python", 255 | "name": "python3" 256 | }, 257 | "language_info": { 258 | "codemirror_mode": { 259 | "name": "ipython", 260 | "version": 3 261 | }, 262 | "file_extension": ".py", 263 | "mimetype": "text/x-python", 264 | "name": "python", 265 | "nbconvert_exporter": "python", 266 | "pygments_lexer": "ipython3", 267 | "version": "3.6.9" 268 | } 269 | }, 270 | "nbformat": 4, 271 | "nbformat_minor": 4 272 | } 273 | -------------------------------------------------------------------------------- /hands-on5/vm_explore.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.analysis.binary import Container\n", 12 | "from miasm.expression.expression import *\n", 13 | "from miasm.core.utils import *\n", 14 | "from miasm.core.locationdb import LocationDB\n", 15 | "from miasm.arch.x86 import regs\n", 16 | "from miasm.ir.symbexec import SymbolicExecutionEngine, get_block\n", 17 | "from miasm.expression.simplifications import expr_simp" 18 | ] 19 | }, 20 | { 21 | "cell_type": "code", 22 | "execution_count": null, 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "!unzip -n -P infected zeusvm.zip" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "class FinalState:\n", 36 | " def __init__(self, result, sym, path_conds, path_history):\n", 37 | " self.result = result\n", 38 | " self.sb = sym\n", 39 | " self.path_conds = path_conds\n", 40 | " self.path_history = path_history" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": null, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "def explore(ir, start_addr, start_symbols, \n", 50 | " ircfg, cond_limit=30, uncond_limit=100, \n", 51 | " lbl_stop=None, final_states=[]):\n", 52 | "\n", 53 | " def codepath_walk(addr, symbols, conds, depth, final_states, path):\n", 54 | " \n", 55 | " if depth >= cond_limit:\n", 56 | " warnings.warn(\"'depth' is over the cond_limit :%d\"%(depth))\n", 57 | " return \n", 58 | "\n", 59 | " sb = SymbolicExecutionEngine(ir, symbols)\n", 60 | "\n", 61 | " for _ in range(uncond_limit):\n", 62 | "\n", 63 | " if isinstance(addr, ExprInt): \n", 64 | " if addr == ret_addr:\n", 65 | " final_states.append(FinalState(True, sb, conds, path))\n", 66 | " return\n", 67 | "\n", 68 | " path.append(addr)\n", 69 | "\n", 70 | " pc = sb.run_block_at(ircfg, addr)\n", 71 | "\n", 72 | " if isinstance(pc, ExprCond): \n", 73 | " \n", 74 | " # Calc the condition to take true or false paths\n", 75 | " cond_true = {pc.cond: ExprInt(1, 32)}\n", 76 | " cond_false = {pc.cond: ExprInt(0, 32)}\n", 77 | "\n", 78 | " # The destination addr of the true or false paths\n", 79 | " addr_true = expr_simp(\n", 80 | " sb.eval_expr(pc.replace_expr(cond_true), {}))\n", 81 | "\n", 82 | " addr_false = expr_simp(\n", 83 | " sb.eval_expr(pc.replace_expr(cond_false), {}))\n", 84 | "\n", 85 | " # Need to add the path conditions to reach this point\n", 86 | " conds_true = list(conds) + list(cond_true.items())\n", 87 | " conds_false = list(conds) + list(cond_false.items())\n", 88 | "\n", 89 | " # Recursive call for the true or false path\n", 90 | " codepath_walk(\n", 91 | " addr_true, sb.symbols.copy(), \n", 92 | " conds_true, depth + 1, final_states, list(path))\n", 93 | "\n", 94 | " codepath_walk(\n", 95 | " addr_false, sb.symbols.copy(), \n", 96 | " conds_false, depth + 1, final_states, list(path))\n", 97 | "\n", 98 | " return\n", 99 | " else:\n", 100 | " addr = expr_simp(sb.eval_expr(pc))\n", 101 | "\n", 102 | " final_states.append(FinalState(True, sb, conds, path))\n", 103 | " return \n", 104 | "\n", 105 | " return codepath_walk(start_addr, start_symbols, [], 0, final_states, [])" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "# Preparing the initial symbols for regs and mems\n", 115 | "symbols_init = dict(regs.regs_init)\n", 116 | "initial_symbols = symbols_init.items()\n", 117 | "\n", 118 | "# Prepare VM Semantics\n", 119 | "# VM_PC_init and RET_ADDR\n", 120 | "vm_pc_init = ExprId('VM_PC_init', 32)\n", 121 | "ret_addr = ExprId('RET_ADDR', 32)\n", 122 | "\n", 123 | "infos = {}\n", 124 | "infos[expr_simp(ExprMem(regs.ECX_init, 32))] = vm_pc_init\n", 125 | "infos[expr_simp(ExprMem(regs.ESP_init-ExprInt(4, 32), 32))] = ret_addr\n", 126 | "infos[regs.ESP] = expr_simp(regs.ESP_init-ExprInt(4, 32))\n", 127 | "\n", 128 | "# Virtual registers\n", 129 | "for i in range(0, 5):\n", 130 | " infos[expr_simp(ExprMem(regs.ECX_init + ExprInt(4*(i+1), 32), 32))] = ExprId('REG%d' % i, 32)\n", 131 | "\n", 132 | "# Additional info\n", 133 | "addition_infos = dict(infos)\n", 134 | "\n", 135 | "# imm\n", 136 | "expr_imm8 = expr_simp(ExprMem(vm_pc_init + ExprInt(0x1, 32), 8))\n", 137 | "addition_infos[expr_imm8] = ExprId('imm8' , 8)\n", 138 | "\n", 139 | "expr_imm16 = expr_simp(ExprMem(vm_pc_init + ExprInt(0x1, 32), 16))\n", 140 | "addition_infos[expr_imm16] = ExprId('imm16' , 16)\n", 141 | "\n", 142 | "expr_imm32 = expr_simp(ExprMem(vm_pc_init + ExprInt(0x1, 32), 32))\n", 143 | "addition_infos[expr_imm32] = ExprId('imm32' , 32)\n", 144 | "\n", 145 | "# immb\n", 146 | "expr_imm8b = expr_simp(ExprMem(vm_pc_init + ExprInt(0x2, 32), 8))\n", 147 | "addition_infos[expr_imm8b] = ExprId('imm8b' , 8)\n", 148 | "\n", 149 | "expr_imm16b = expr_simp(ExprMem(vm_pc_init + ExprInt(0x2, 32), 16))\n", 150 | "addition_infos[expr_imm16b] = ExprId('imm16b' , 16)\n", 151 | "\n", 152 | "expr_imm32b = expr_simp(ExprMem(vm_pc_init + ExprInt(0x2, 32), 32))\n", 153 | "addition_infos[expr_imm32b] = ExprId('imm32b' , 32)\n", 154 | "\n", 155 | "imms = set([expr_imm8, expr_imm16, expr_imm32,\n", 156 | " expr_imm8b, expr_imm16b, expr_imm32b])\n", 157 | "\n", 158 | "imm8 = ExprId('imm8', 8)\n", 159 | "\n", 160 | "base_regx = expr_simp(regs.ECX_init + (imm8.zeroExtend(32) & ExprInt(0xF, 32)) * ExprInt(4, 32) + ExprInt(0xC, 32))\n", 161 | "addition_infos[expr_simp(ExprMem(base_regx, 32))] = ExprId('REGX' , 32)\n", 162 | "addition_infos[expr_simp(ExprMem(base_regx, 16))] = ExprId('REGX' , 32)[:16]\n", 163 | "addition_infos[expr_simp(ExprMem(base_regx, 8))] = ExprId('REGX' , 32)[:8]\n", 164 | "\n", 165 | "base_regy = expr_simp(regs.ECX_init + (imm8[4:8].zeroExtend(32)) * ExprInt(4, 32) + ExprInt(0xC, 32))\n", 166 | "addition_infos[expr_simp(ExprMem(base_regy, 32))] = ExprId('REGY' , 32)\n", 167 | "addition_infos[expr_simp(ExprMem(base_regy, 16))] = ExprId('REGY' , 16)[:16]\n", 168 | "addition_infos[expr_simp(ExprMem(base_regy, 8))] = ExprId('REGY' , 8)[:8]" 169 | ] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "metadata": {}, 175 | "outputs": [], 176 | "source": [ 177 | "def dump_state(sb):\n", 178 | " print('-'*20, 'State', '-'*20)\n", 179 | " out = {}\n", 180 | " for expr, value in sorted(sb.symbols.items()):\n", 181 | " if (expr, value) in initial_symbols:\n", 182 | " continue\n", 183 | " if (expr, value) in addition_infos:\n", 184 | " continue\n", 185 | " if expr in [regs.zf, regs.cf, regs.nf, regs.of, regs.pf, regs.af,\n", 186 | " ir_arch.IRDst, regs.EIP]:\n", 187 | " continue\n", 188 | " expr_s = expr_simp(expr.replace_expr(addition_infos))\n", 189 | " expr = expr_s\n", 190 | " value = expr_simp(value.replace_expr(addition_infos))\n", 191 | " if expr == value:\n", 192 | " continue\n", 193 | " out[expr] = value\n", 194 | "\n", 195 | " out = sorted(out.items())\n", 196 | " x86_regs = []\n", 197 | " mem = []\n", 198 | " other = []\n", 199 | " for expr, value in out:\n", 200 | " if expr in regs.all_regs_ids:\n", 201 | " x86_regs.append((expr, value))\n", 202 | " elif isinstance(expr, ExprMem):\n", 203 | " mem.append((expr, value))\n", 204 | " else:\n", 205 | " other.append((expr, value))\n", 206 | "\n", 207 | " print('Regs:')\n", 208 | " for item in other:\n", 209 | " print('\\t%s = %s' % item)\n", 210 | " print('Mem:')\n", 211 | " for item in mem:\n", 212 | " print('\\t%s = %s' % item)\n", 213 | " print('x86:')\n", 214 | " for item in x86_regs:\n", 215 | " print('\\t%s = %s' % item)\n", 216 | " print('')" 217 | ] 218 | }, 219 | { 220 | "cell_type": "code", 221 | "execution_count": null, 222 | "metadata": {}, 223 | "outputs": [], 224 | "source": [ 225 | "filename = 'zeusvm.bin'\n", 226 | "\n", 227 | "machine = Machine('x86_32')\n", 228 | "loc_db = LocationDB()\n", 229 | "with open(filename, 'rb') as fstream:\n", 230 | " cont = Container.from_stream(fstream, loc_db)\n", 231 | "bs = cont.bin_stream\n", 232 | "mdis = machine.dis_engine(bs, loc_db=cont.loc_db)\n", 233 | "ir_arch = machine.ir(mdis.loc_db)" 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "execution_count": null, 239 | "metadata": { 240 | "scrolled": false 241 | }, 242 | "outputs": [], 243 | "source": [ 244 | "mnemonic_array_addr = 0x427018\n", 245 | "\n", 246 | "for i in range(69):\n", 247 | " # Get each handler address from the array\n", 248 | " addr = int(hex(upck32(bs.getbytes(mnemonic_array_addr + 4*i, 4))), 16)\n", 249 | " print('*'*40, 'Mnemonic', i, ' addr', hex(addr), '*'*40)\n", 250 | " \n", 251 | " # Generate AsmCFG and IRCFG\n", 252 | " asmcfg = mdis.dis_multiblock(addr)\n", 253 | " ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)\n", 254 | " irblock = ircfg.get_block(addr)\n", 255 | "\n", 256 | " final_states = []\n", 257 | " \n", 258 | " explore(ir_arch, \n", 259 | " addr, \n", 260 | " symbols_init, \n", 261 | " ircfg, \n", 262 | " final_states=final_states)\n", 263 | " \n", 264 | " # Show results\n", 265 | " print('final states:', len(final_states))\n", 266 | "\n", 267 | " for final_state in final_states:\n", 268 | " if final_state.result:\n", 269 | " ret_mn = expr_simp(final_state.sb.eval_expr(regs.EAX[:8]))\n", 270 | " if ret_mn != ExprInt(1, 8):\n", 271 | " print('Strange return', ret_mn)\n", 272 | " # Show state after expr_simp\n", 273 | " dump_state(final_state.sb)\n", 274 | "\n", 275 | " #final_state.sb.dump(ids=False) # Show state before expr_simp\n", 276 | " print('')" 277 | ] 278 | } 279 | ], 280 | "metadata": { 281 | "kernelspec": { 282 | "display_name": "Python 3", 283 | "language": "python", 284 | "name": "python3" 285 | }, 286 | "language_info": { 287 | "codemirror_mode": { 288 | "name": "ipython", 289 | "version": 3 290 | }, 291 | "file_extension": ".py", 292 | "mimetype": "text/x-python", 293 | "name": "python", 294 | "nbconvert_exporter": "python", 295 | "pygments_lexer": "ipython3", 296 | "version": "3.6.9" 297 | } 298 | }, 299 | "nbformat": 4, 300 | "nbformat_minor": 4 301 | } 302 | -------------------------------------------------------------------------------- /hands-on5/zeusvm.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malrev/ABD/0fe01674a4b0f1879f9c36d7b1e76e3c1d670d26/hands-on5/zeusvm.zip -------------------------------------------------------------------------------- /hands-on6/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | rm -Rf *.dot 3 | rm -Rf *.png 4 | 5 | 6 | -------------------------------------------------------------------------------- /hands-on6/cff_dse.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.sandbox import Sandbox_Linux_x86_64\n", 11 | "from miasm.analysis.binary import Container\n", 12 | "from miasm.os_dep.linux_stdlib import linobjs\n", 13 | "from miasm.core.utils import hexdump\n", 14 | "from miasm.core.locationdb import LocationDB\n", 15 | "from miasm.analysis.dse import DSEPathConstraint\n", 16 | "from miasm.analysis.machine import Machine\n", 17 | "from miasm.expression.expression import ExprMem, ExprId, ExprInt, ExprAssign\n", 18 | "from future.utils import viewitems\n", 19 | "from miasm.jitter.csts import PAGE_READ, PAGE_WRITE\n", 20 | "import sys" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": null, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "parser = Sandbox_Linux_x86_64.parser(description='ELF sandboxer')\n", 30 | "options = parser.parse_args(args=[])\n", 31 | "options.filename = 'flattening_volatile.bin'\n", 32 | "options.strategy = 'code-cov'\n", 33 | "options.mimic_env = True" 34 | ] 35 | }, 36 | { 37 | "cell_type": "code", 38 | "execution_count": null, 39 | "metadata": {}, 40 | "outputs": [], 41 | "source": [ 42 | "# Need to adjust the context of dse to the one of concrete\n", 43 | "def xxx_printf_symb(dse):\n", 44 | "\n", 45 | " regs = dse.ir_arch.arch.regs\n", 46 | " ret_addr = ExprInt(dse.jitter.get_stack_arg(0), regs.RIP.size)\n", 47 | "\n", 48 | " dse.update_state({\n", 49 | " regs.RSP: dse.symb.eval_expr(regs.RSP + ExprInt(8, regs.RSP.size)),\n", 50 | " dse.ir_arch.IRDst: ret_addr,\n", 51 | " regs.RAX: ExprInt(6, regs.RAX.size),\n", 52 | " regs.RIP: ret_addr,\n", 53 | " })" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": null, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "def code_sentinelle(jitter):\n", 63 | " jitter.run = False\n", 64 | " return False" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "loc_db = LocationDB()\n", 74 | "sb = Sandbox_Linux_x86_64(loc_db, options.filename, options, globals())\n", 75 | "\n", 76 | "with open(options.filename, 'rb') as fstream:\n", 77 | " cont = Container.from_stream(fstream, loc_db)\n", 78 | " \n", 79 | "machine = Machine('x86_64')\n", 80 | "\n", 81 | "ret_addr = 0x000000001337beef\n", 82 | "sb.jitter.add_breakpoint(ret_addr, code_sentinelle)\n", 83 | "sb.jitter.push_uint64_t(ret_addr)" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [ 92 | "# init_run need to be placed before DSE is attacked\n", 93 | "sb.jitter.init_run(0x1040)\n", 94 | "\n", 95 | "MEM_ARGV_ADDR = 0x7ff70000\n", 96 | "MEM_ARGV1_ADDR = 0x7ff80000\n", 97 | "\n", 98 | "# argv\n", 99 | "sb.jitter.vm.add_memory_page(\n", 100 | " MEM_ARGV_ADDR,\n", 101 | " PAGE_READ | PAGE_WRITE,\n", 102 | " b'\\x42\\x42\\x42\\x42\\x42\\x42\\x42\\x42' + \n", 103 | " b'\\x00\\x00\\xf8\\x7f\\x00\\x00\\x00\\x00', \n", 104 | " 'Binary'\n", 105 | " )\n", 106 | "\n", 107 | "# argv[1]\n", 108 | "sb.jitter.vm.add_memory_page(\n", 109 | " MEM_ARGV1_ADDR,\n", 110 | " PAGE_READ | PAGE_WRITE,\n", 111 | " b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00',\n", 112 | " 'Binary'\n", 113 | " )\n", 114 | "\n", 115 | "sb.jitter.cpu.RDI = 0x2 # argc\n", 116 | "sb.jitter.cpu.RSI = MEM_ARGV_ADDR # argv\n" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": null, 122 | "metadata": {}, 123 | "outputs": [], 124 | "source": [ 125 | "# Convert strategy to the correct value\n", 126 | "strategy = {\n", 127 | " 'code-cov': DSEPathConstraint.PRODUCE_SOLUTION_CODE_COV,\n", 128 | " 'branch-cov': DSEPathConstraint.PRODUCE_SOLUTION_BRANCH_COV,\n", 129 | " 'path-cov': DSEPathConstraint.PRODUCE_SOLUTION_PATH_COV,\n", 130 | "}[options.strategy]" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": null, 136 | "metadata": {}, 137 | "outputs": [], 138 | "source": [ 139 | "# Init a DSE instance with a given strategy\n", 140 | "dse = DSEPathConstraint(machine, loc_db, produce_solution=strategy)\n", 141 | "dse.attach(sb.jitter)\n", 142 | "dse.update_state_from_concrete()\n", 143 | "dse.add_lib_handler(sb.libs, globals())" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": null, 149 | "metadata": {}, 150 | "outputs": [], 151 | "source": [ 152 | "# Symbolize the argument\n", 153 | "regs = sb.jitter.ir_arch.arch.regs\n", 154 | "\n", 155 | "argv1 = [] \n", 156 | "for i in range(8):\n", 157 | " # Create an ExprId for argv[1][x]\n", 158 | " argv1.append(ExprId('Argv[1][%d]'%(i), 8))\n", 159 | "\n", 160 | " # Add constraints because argv1[x] is a readable ascii\n", 161 | " const = dse.z3_trans.from_expr(argv1[i])\n", 162 | " dse.cur_solver.add(31 < const) \n", 163 | " dse.cur_solver.add(const < 127)\n", 164 | "\n", 165 | "argv1_addr = []\n", 166 | "for i in range(8):\n", 167 | " argv1_addr.append(ExprMem(ExprInt(MEM_ARGV1_ADDR + i, 64), 8))\n", 168 | "\n", 169 | "s = {}\n", 170 | "for addr, argv in zip(argv1_addr, argv1):\n", 171 | " s[addr] = argv\n", 172 | " \n", 173 | "dse.update_state(s)" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": null, 179 | "metadata": {}, 180 | "outputs": [], 181 | "source": [ 182 | "todo = set([(ExprInt(0x42, 8), \n", 183 | " ExprInt(0x41, 8),\n", 184 | " ExprInt(0x41, 8),\n", 185 | " ExprInt(0x41, 8),\n", 186 | " ExprInt(0x41, 8),\n", 187 | " ExprInt(0x41, 8),\n", 188 | " ExprInt(0x41, 8),\n", 189 | " ExprInt(0x41, 8))])\n", 190 | "done = set()\n", 191 | "\n", 192 | "snapshot = dse.take_snapshot()" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": null, 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [ 201 | "while todo:\n", 202 | " arg_value = todo.pop()\n", 203 | "\n", 204 | " if arg_value in done:\n", 205 | " continue\n", 206 | "\n", 207 | " done.add(arg_value)\n", 208 | "\n", 209 | " for i in range(8):\n", 210 | " print('Run with ARG = %s' % (arg_value[i]))\n", 211 | "\n", 212 | " print('---start---')\n", 213 | "\n", 214 | " dse.restore_snapshot(snapshot, keep_known_solutions=True)\n", 215 | "\n", 216 | " for i in range(8):\n", 217 | " sb.jitter.eval_expr(ExprAssign(argv1_addr[i], arg_value[i]))\n", 218 | "\n", 219 | " sb.jitter.init_run(0x1040)\n", 220 | " sb.jitter.set_trace_log(trace_regs=True, trace_new_blocks=False)\n", 221 | " sb.jitter.continue_run(step=False)\n", 222 | "\n", 223 | " print('---end---')\n", 224 | "\n", 225 | " if sb.jitter.cpu.RAX == 0:\n", 226 | " print('FOUND!!!')\n", 227 | " argv1_str = ''.join([chr(x) for x in arg_value])\n", 228 | " print(argv1_str)\n", 229 | " break\n", 230 | "\n", 231 | " for sol_ident, model in viewitems(dse.new_solutions):\n", 232 | "\n", 233 | " print('Found a solution to reach: %s' % str(sol_ident))\n", 234 | " print('model', model)\n", 235 | "\n", 236 | " sol_expr = []\n", 237 | " for i in range(8):\n", 238 | " # Get the argument to use as a Miasm Expr\n", 239 | " try:\n", 240 | " sol_value = model.eval(dse.z3_trans.from_expr(argv1[i])).as_long()\n", 241 | " except AttributeError:\n", 242 | " sol_value = 0\n", 243 | "\n", 244 | " sol_expr.append(ExprInt(sol_value, argv1[i].size))\n", 245 | "\n", 246 | " print('\\tARG[1][%d] = %s' % (i, sol_expr[i]))\n", 247 | "\n", 248 | " todo.add((sol_expr[0], \n", 249 | " sol_expr[1], \n", 250 | " sol_expr[2], \n", 251 | " sol_expr[3], \n", 252 | " sol_expr[4],\n", 253 | " sol_expr[5], \n", 254 | " sol_expr[6], \n", 255 | " sol_expr[7]))" 256 | ] 257 | } 258 | ], 259 | "metadata": { 260 | "kernelspec": { 261 | "display_name": "Python 3", 262 | "language": "python", 263 | "name": "python3" 264 | }, 265 | "language_info": { 266 | "codemirror_mode": { 267 | "name": "ipython", 268 | "version": 3 269 | }, 270 | "file_extension": ".py", 271 | "mimetype": "text/x-python", 272 | "name": "python", 273 | "nbconvert_exporter": "python", 274 | "pygments_lexer": "ipython3", 275 | "version": "3.6.9" 276 | } 277 | }, 278 | "nbformat": 4, 279 | "nbformat_minor": 4 280 | } 281 | -------------------------------------------------------------------------------- /hands-on6/cff_explore.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# -*- coding: utf-8 -*-\n", 10 | "from miasm.analysis.machine import Machine\n", 11 | "from miasm.arch.x86.arch import mn_x86\n", 12 | "from miasm.ir.symbexec import SymbolicExecutionEngine\n", 13 | "from miasm.expression.expression import ExprCond, ExprId, ExprInt, ExprMem \n", 14 | "from miasm.expression.simplifications import expr_simp\n", 15 | "from miasm.arch.x86.regs import *\n", 16 | "from miasm.core import parse_asm, asmblock\n", 17 | "from miasm.core.locationdb import LocationDB\n", 18 | "from miasm.analysis.binary import Container\n", 19 | "from miasm.analysis.simplifier import IRCFGSimplifierCommon\n", 20 | "from future.utils import viewitems\n", 21 | "from miasm.loader.strpatchwork import *\n", 22 | "from miasm.ir.translators.translator import Translator\n", 23 | "import warnings\n", 24 | "import z3\n", 25 | "import pydotplus\n", 26 | "from IPython.display import Image, display_png" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "class FinalState:\n", 36 | " def __init__(self, result, sym, path_conds, path_history):\n", 37 | " self.result = result\n", 38 | " self.sb = sym\n", 39 | " self.path_conds = path_conds\n", 40 | " self.path_history = path_history" 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": null, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "def explore(ir, start_addr, start_symbols, \n", 50 | " ircfg, cond_limit=30, uncond_limit=100, \n", 51 | " lbl_stop=None, final_states=[]):\n", 52 | "\n", 53 | " def codepath_walk(addr, symbols, conds, depth, final_states, path):\n", 54 | "\n", 55 | " if depth >= cond_limit:\n", 56 | " warnings.warn(\"'depth' is over the cond_limit :%d\"%(depth))\n", 57 | " return \n", 58 | "\n", 59 | " sb = SymbolicExecutionEngine(ir, symbols)\n", 60 | "\n", 61 | " for _ in range(uncond_limit):\n", 62 | "\n", 63 | " if isinstance(addr, ExprInt): \n", 64 | " if addr == lbl_stop:\n", 65 | " final_states.append(FinalState(True, sb, conds, path))\n", 66 | " return\n", 67 | "\n", 68 | " path.append(addr)\n", 69 | "\n", 70 | " pc = sb.run_block_at(ircfg, addr)\n", 71 | "\n", 72 | " if isinstance(pc, ExprCond): \n", 73 | " \n", 74 | " # Calc the condition to take true or false paths\n", 75 | " cond_true = {pc.cond: ExprInt(1, 32)}\n", 76 | " cond_false = {pc.cond: ExprInt(0, 32)}\n", 77 | "\n", 78 | " # The destination addr of the true or false paths\n", 79 | " addr_true = expr_simp(\n", 80 | " sb.eval_expr(pc.replace_expr(cond_true), {}))\n", 81 | "\n", 82 | " addr_false = expr_simp(\n", 83 | " sb.eval_expr(pc.replace_expr(cond_false), {}))\n", 84 | "\n", 85 | " # Need to add the path conditions to reach this point\n", 86 | " conds_true = list(conds) + list(cond_true.items())\n", 87 | " conds_false = list(conds) + list(cond_false.items())\n", 88 | "\n", 89 | " # Recursive call for the true or false path\n", 90 | " codepath_walk(\n", 91 | " addr_true, sb.symbols.copy(), \n", 92 | " conds_true, depth + 1, final_states, list(path))\n", 93 | "\n", 94 | " codepath_walk(\n", 95 | " addr_false, sb.symbols.copy(), \n", 96 | " conds_false, depth + 1, final_states, list(path))\n", 97 | "\n", 98 | " return\n", 99 | " else:\n", 100 | " addr = expr_simp(sb.eval_expr(pc))\n", 101 | "\n", 102 | " final_states.append(FinalState(True, sb, conds, path))\n", 103 | " return \n", 104 | "\n", 105 | " return codepath_walk(start_addr, start_symbols, [], 0, final_states, [])" 106 | ] 107 | }, 108 | { 109 | "cell_type": "code", 110 | "execution_count": null, 111 | "metadata": {}, 112 | "outputs": [], 113 | "source": [ 114 | "filename = 'test-mod2-fla.bin'\n", 115 | "target_addr = 0x8048440 \n", 116 | "\n", 117 | "loc_db = LocationDB()\n", 118 | "with open(filename, 'rb') as fstream:\n", 119 | " cont = Container.from_stream(fstream, loc_db)\n", 120 | "machine = Machine(cont.arch)\n", 121 | "\n", 122 | "mdis = machine.dis_engine(cont.bin_stream, loc_db=cont.loc_db)\n", 123 | "asmcfg = mdis.dis_multiblock(target_addr)\n", 124 | "ir_arch = machine.ira(mdis.loc_db)\n", 125 | "ircfg = ir_arch.new_ircfg_from_asmcfg(asmcfg)" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "# Apply simplifier\n", 135 | "common_simplifier = IRCFGSimplifierCommon(ir_arch)\n", 136 | "common_simplifier.simplify(ircfg, target_addr)" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [ 145 | "# Visualize the CFG\n", 146 | "with open('cfg.dot', 'w') as f:\n", 147 | " f.write(ircfg.dot())\n", 148 | "graph = pydotplus.graphviz.graph_from_dot_file('cfg.dot')\n", 149 | "graph.write_png('cfg.png')\n", 150 | "display_png(Image(graph.create_png()))" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": null, 156 | "metadata": {}, 157 | "outputs": [], 158 | "source": [ 159 | "symbols_init = {\n", 160 | " ExprMem(ExprId('ESP_init', 32), 32) : ExprInt(0xdeadbeef, 32)\n", 161 | "}\n", 162 | "\n", 163 | "for i, r in enumerate(all_regs_ids):\n", 164 | " symbols_init[r] = all_regs_ids_init[i]\n", 165 | "\n", 166 | "final_states = []" 167 | ] 168 | }, 169 | { 170 | "cell_type": "code", 171 | "execution_count": null, 172 | "metadata": {}, 173 | "outputs": [], 174 | "source": [ 175 | "explore(ir_arch, \n", 176 | " target_addr, \n", 177 | " symbols_init, \n", 178 | " ircfg, \n", 179 | " lbl_stop=0xdeadbeef, \n", 180 | " final_states=final_states)" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": null, 186 | "metadata": {}, 187 | "outputs": [], 188 | "source": [ 189 | "# Show results\n", 190 | "print('final states:', len(final_states))\n", 191 | "\n", 192 | "for final_state in final_states:\n", 193 | " if final_state.result:\n", 194 | " print('Feasible path:','->'.join([str(x) for x in final_state.path_history]))\n", 195 | " print('\\t',final_state.path_conds)\n", 196 | " else:\n", 197 | " print('Infeasible path:','->'.join([str(x) for x in final_state.path_history]))\n", 198 | " print('\\t',final_state.path_conds)\n", 199 | "\n", 200 | " final_state.sb.dump(ids=False)\n", 201 | " print('')" 202 | ] 203 | } 204 | ], 205 | "metadata": { 206 | "kernelspec": { 207 | "display_name": "Python 3", 208 | "language": "python", 209 | "name": "python3" 210 | }, 211 | "language_info": { 212 | "codemirror_mode": { 213 | "name": "ipython", 214 | "version": 3 215 | }, 216 | "file_extension": ".py", 217 | "mimetype": "text/x-python", 218 | "name": "python", 219 | "nbconvert_exporter": "python", 220 | "pygments_lexer": "ipython3", 221 | "version": "3.6.9" 222 | } 223 | }, 224 | "nbformat": 4, 225 | "nbformat_minor": 4 226 | } 227 | -------------------------------------------------------------------------------- /hands-on6/flattening_volatile.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malrev/ABD/0fe01674a4b0f1879f9c36d7b1e76e3c1d670d26/hands-on6/flattening_volatile.bin -------------------------------------------------------------------------------- /hands-on6/test-mod2-fla.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malrev/ABD/0fe01674a4b0f1879f9c36d7b1e76e3c1d670d26/hands-on6/test-mod2-fla.bin -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eux 4 | 5 | DIR=$(readlink -f $1) 6 | 7 | FILES_DIR=$DIR 8 | 9 | cd $HOME 10 | #sudo apt update && sudo apt upgrade -y 11 | 12 | # obfuscator 13 | ## https://github.com/obfuscator-llvm/obfuscator/wiki/Installation 14 | sudo apt install cmake make gcc g++ gcc-multilib git -y 15 | git clone -b llvm-4.0 https://github.com/obfuscator-llvm/obfuscator.git $FILES_DIR/obfuscator 16 | cd $FILES_DIR/obfuscator 17 | mkdir build 18 | cd build 19 | cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_INCLUDE_TESTS=OFF .. 20 | NUM_JOBS=$((`nproc`/2 )) 21 | make -j$(( NUM_JOBS > 1 ? NUM_JOBS : 1 )) 22 | sudo make install 23 | 24 | # pip 25 | sudo apt install curl python3-distutils python3-testresources -y 26 | cd /tmp 27 | curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py 28 | python3 get-pip.py 29 | source ~/.profile # for adding path to ~/.local/bin 30 | 31 | # additional required packages 32 | pip install notebook future networkx z3-solver pyparsing pydotplus 33 | 34 | # miasm 35 | ## as of fc6bb3ce49ea44012a762b207a39301825e9648a 36 | git clone https://github.com/cea-sec/miasm $FILES_DIR/miasm 37 | sudo apt install python3 libpython3-dev python3-distutils graphviz jupyter-notebook -y 38 | cd $FILES_DIR/miasm 39 | python3 setup.py build 40 | sudo python3 setup.py install 41 | 42 | # docker 43 | ## https://docs.docker.com/install/linux/docker-ce/ubuntu/ 44 | sudo apt install \ 45 | apt-transport-https \ 46 | ca-certificates \ 47 | curl \ 48 | gnupg-agent \ 49 | software-properties-common 50 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 51 | sudo add-apt-repository \ 52 | "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ 53 | $(lsb_release -cs) \ 54 | stable" 55 | sudo apt update 56 | sudo apt install docker-ce docker-ce-cli containerd.io -y 57 | 58 | # tigress 59 | cd $FILES_DIR/tigress-docker 60 | export DOCKER_BUILDKIT=1 61 | sudo docker build . -t tigress-docker 62 | 63 | -------------------------------------------------------------------------------- /tigress-docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:experimental 2 | FROM ubuntu:16.04 as base 3 | RUN apt update && apt install sudo 4 | RUN useradd -u 1000 -m user 5 | RUN gpasswd -a user sudo 6 | RUN echo 'user:user' | chpasswd 7 | 8 | FROM base 9 | RUN apt update && apt install gcc unzip libdata-dumper-concise-perl libc6-dev-i386 -y 10 | ADD ./tigress-Linux-x86_64-unstable.zip /opt/ 11 | RUN unzip /opt/tigress-Linux-x86_64-unstable.zip -d /opt/ 12 | RUN chown -R user:user /opt/tigress-unstable 13 | 14 | USER user 15 | ENV TIGRESS_HOME "/opt/tigress-unstable" 16 | ENV PATH $PATH:"/opt/tigress-unstable" 17 | -------------------------------------------------------------------------------- /tigress-docker/tigress-Linux-x86_64-unstable.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malrev/ABD/0fe01674a4b0f1879f9c36d7b1e76e3c1d670d26/tigress-docker/tigress-Linux-x86_64-unstable.zip --------------------------------------------------------------------------------