├── VERSION ├── CHNAGELOG.md ├── scripts ├── release.sh ├── release_pypi.sh ├── build_docker.sh └── release_docker.sh ├── src ├── __init__.py └── core │ ├── __init__.py │ ├── core_postflight.py │ ├── core_preflight.py │ ├── core_checks.py │ ├── core_runtime.py │ ├── test_hash.py │ ├── core_hash.py │ ├── core_preop.py │ ├── core_model.py │ ├── core_printer.py │ └── core_cook.py ├── MANIFEST.in ├── setup.cfg ├── test └── net-35-bin.exe ├── config.py ├── requirements.txt ├── Dockerfile ├── Pipfile ├── .coveragerc ├── .travis.yml ├── setup.py ├── .gitignore ├── pefixup.py ├── Pipfile.lock ├── README.md └── LICENSE /VERSION: -------------------------------------------------------------------------------- 1 | 0.0.2 -------------------------------------------------------------------------------- /CHNAGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scripts/release.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /scripts/release_pypi.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [aliases] 2 | test = pytest 3 | 4 | [tool:pytest] 5 | addopts = --verbose -------------------------------------------------------------------------------- /test/net-35-bin.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/obscuritylabs/PeFixup/HEAD/test/net-35-bin.exe -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | LOG_LEVEL = str(os.getenv('PEFIXUP_LOG_LEVEL', 'INFO')) 4 | VT_KEY = str(os.getenv('PEFIXUP_VT_KEY', '')) -------------------------------------------------------------------------------- /scripts/build_docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | # SET THE FOLLOWING VARIABLES 4 | # docker hub username 5 | USERNAME=obscuritylabs 6 | # image name 7 | IMAGE=pefixup 8 | docker build -t $USERNAME/$IMAGE:latest . -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pefile==2019.4.18 2 | termcolor==1.1.0 3 | python-magic==0.4.15 4 | ssdeep==3.3 5 | coverage==4.5.4 6 | pytest==5.1.2 7 | coverage==4.5.4 8 | pytest-cov==2.7.1 9 | virustotal-api==1.1.10 10 | pyexifinfo 11 | coveralls 12 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # image base 2 | FROM python:3 3 | 4 | WORKDIR /opt/pefixup/ 5 | 6 | RUN apt-get update && \ 7 | apt-get install -y --no-install-recommends \ 8 | libffi-dev \ 9 | libfuzzy-dev \ 10 | ssdeep 11 | 12 | 13 | COPY . /opt/pefixup/ 14 | 15 | RUN pip install -r requirements.txt 16 | 17 | ENTRYPOINT ["pefixup.py"] -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | pefile = "==2019.4.18" 8 | termcolor = "==1.1.0" 9 | python-magic = "==0.4.15" 10 | ssdeep = "==3.3" 11 | 12 | [dev-packages] 13 | coverage = "==4.5.4" 14 | pytest = "==5.1.2" 15 | pytest-cov = "==2.7.1" 16 | 17 | [requires] 18 | python_version = "3.6" 19 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | # build file coveralls and nosetests 2 | 3 | [report] 4 | exclude_lines = 5 | pragma: no cover 6 | def __repr__ 7 | raise AssertionError 8 | raise NotImplementedError 9 | if __name__ == .__main__.: 10 | omit = 11 | *setup.py 12 | */docs/* 13 | */python?.?/* 14 | */site-packages/nose/* 15 | *__init__* 16 | */thrid_party/* 17 | */tests/* -------------------------------------------------------------------------------- /src/core/core_postflight.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Iterable, Union 2 | from termcolor import colored, cprint 3 | import re 4 | from collections import namedtuple 5 | 6 | 7 | class CorePostFlight(): 8 | 9 | """ 10 | Core PreFlight Checks Class. 11 | """ 12 | 13 | def __init__(self): 14 | """ 15 | Init class and passed objects. 16 | """ 17 | self.print_post_flight() 18 | self.strings_bin() 19 | 20 | def strings_bin(self): 21 | if self.args.strings: 22 | # strings enabled 23 | print(f"[*] Strings output not currently supported (Skipping): {colored('WARNING', 'yellow')}") 24 | else: 25 | print(f"[-] Strings output not enabled (Skipping): {colored('WARNING', 'yellow')}") 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: bionic 2 | language: python 3 | cache: pip 4 | env: 5 | global: 6 | - USERNAME=obscuritylabs 7 | - IMAGE=pefixup 8 | 9 | python: 10 | - '3.6' 11 | - '3.7' 12 | 13 | before_install: 14 | - sudo apt-get install build-essential libffi-dev libfuzzy-dev ssdeep 15 | 16 | install: 17 | - pip install -r requirements.txt 18 | 19 | script: 20 | - ls 21 | # - pytest 22 | # test to make sure build passes 23 | - python setup.py build 24 | - python setup.py install 25 | - pytest --cov=. 26 | 27 | after_success: 28 | - coveralls 29 | 30 | 31 | jobs: 32 | include: 33 | - stage: Deploy Docker 34 | python: 3.6 35 | install: skip # no tests, no depedencies needed 36 | script: skip # we're not running tests 37 | before_deploy: 38 | - echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USER" --password-stdin 39 | deploy: 40 | # deploy development to docker hub 41 | - provider: script 42 | script: 43 | - bash ./scripts/release_docker.sh 44 | on: 45 | branch: development 46 | 47 | # deploy master to docker hub 48 | - provider: script 49 | script: 50 | - bash ./scripts/release_docker.sh 51 | on: 52 | branch: master 53 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | 4 | VERSIONFILE = open("VERSION").read() 5 | 6 | setup(name='pefixup', 7 | version=VERSIONFILE, 8 | description=' PE File Blessing.', 9 | url='https://github.com/obscuritylabs/PeFixup', 10 | author='Alexander Rymdeko-Harvey', 11 | author_email='a.rymdekoharvey@obscuritylabs.com', 12 | license='BSD 3.0', 13 | packages=find_packages(), 14 | setup_requires=['pytest-runner'], 15 | tests_require=['pytest'], 16 | classifiers=[ 17 | # How mature is this project? Common values are 18 | # 3 - Alpha 19 | # 4 - Beta 20 | # 5 - Production/Stable 21 | 'Development Status :: 4 - Beta', 22 | # Specify the Python versions you support here. In particular, ensure 23 | # that you indicate whether you support Python 2, Python 3 or both. 24 | 'Programming Language :: Python :: 3.6', 25 | 'Programming Language :: Python :: 3.7', 26 | 'Topic :: Security', 27 | 'Environment :: Console', 28 | 'Programming Language :: Python' 29 | ], 30 | install_requires=[ 31 | 'setuptools', 32 | 'pefile' 33 | ], 34 | entry_points={ 35 | 'console_scripts': [ 36 | 'pefixup = pefixup:main', 37 | ], 38 | }, 39 | include_package_data=True, 40 | zip_safe=True) 41 | -------------------------------------------------------------------------------- /src/core/core_preflight.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Iterable, Union 2 | from termcolor import colored, cprint 3 | from . import core_hash 4 | 5 | class CorePreFlight(): 6 | 7 | """ 8 | Core PreFlight Checks Class. 9 | """ 10 | 11 | def __init__(self): 12 | """ 13 | Init class and passed objects. 14 | """ 15 | self.print_pre_flight() 16 | self.pre_flight() 17 | 18 | def pre_flight(self): 19 | preflight = False 20 | preflight = self.re_write_check() 21 | if preflight: 22 | print(f"Preflight checks: {colored('PASS', 'green')}") 23 | else: 24 | print(colored(f" - SHA256 of cooked payload DOES NOT MATCH, somthing is wrong..", 'red')) 25 | self.model['preflight_checks']['preflight'] = preflight 26 | 27 | def re_write_check(self) -> bool: 28 | """ """ 29 | s = core_hash.SHA256() 30 | preflight = True 31 | print("[*] File re-write checks:") 32 | self.model['preflight_checks']['rewrite']['non_cooked_sha256'] = s.get_hash_hexdigest(self.raw) 33 | self.model['preflight_checks']['rewrite']['cooked_sha256'] = s.get_hash_hexdigest(self.live) 34 | print(f" - SHA256 of non-cooked payload: {colored(s.get_hash_hexdigest(self.raw), 'yellow')}") 35 | print(f" - SHA256 of cooked payload: {colored(s.get_hash_hexdigest(self.live), 'yellow')}") 36 | if s.get_hash_hexdigest(self.live) != s.get_hash_hexdigest(self.raw): 37 | preflight = False 38 | if preflight: 39 | return True 40 | return False 41 | -------------------------------------------------------------------------------- /.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 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # Environments 86 | .env 87 | .venv 88 | env/ 89 | venv/ 90 | ENV/ 91 | env.bak/ 92 | venv.bak/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | -------------------------------------------------------------------------------- /scripts/release_docker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -ex 3 | 4 | git_sha="$(git rev-parse --short HEAD)" 5 | echo "--------------------------------------" 6 | echo "| Current git sha: ${git_sha} |" 7 | echo "| Current git branch: $TRAVIS_BRANCH |" 8 | echo "--------------------------------------" 9 | 10 | VERSION=`cat VERSION` 11 | echo "---------------------------------------------" 12 | echo "| Building pefixup Docker version: $VERSION |" 13 | echo "---------------------------------------------" 14 | ./scripts/build_docker.sh 15 | 16 | # PUSH TO DOCKER HUB 17 | if [[ "$TRAVIS_BRANCH" == "master" ]]; then 18 | # DOCKER TAG/VERSIONING 19 | docker tag $USERNAME/$IMAGE:latest $USERNAME/$IMAGE:$VERSION 20 | docker push $USERNAME/$IMAGE:latest 21 | echo "------------------------------------------------" 22 | echo "| Docker image pushed: $USERNAME/$IMAGE:latest |" 23 | echo "------------------------------------------------" 24 | docker push $USERNAME/$IMAGE:$VERSION 25 | echo "--------------------------------------------------" 26 | echo "| Docker image pushed: $USERNAME/$IMAGE:$VERSION |" 27 | echo "--------------------------------------------------" 28 | fi 29 | if [[ "$TRAVIS_BRANCH" == "development" ]]; then 30 | # DOCKER TAG/VERSIONING 31 | docker tag $USERNAME/$IMAGE:latest $USERNAME/$IMAGE:development 32 | docker tag $USERNAME/$IMAGE:latest $USERNAME/$IMAGE:${git_sha}-development 33 | docker push $USERNAME/$IMAGE:development 34 | echo "-----------------------------------------------------" 35 | echo "| Docker image pushed: $USERNAME/$IMAGE:development |" 36 | echo "-----------------------------------------------------" 37 | docker push $USERNAME/$IMAGE:${git_sha}-development 38 | echo "----------------------------------------------------------------" 39 | echo "| Docker image pushed: $USERNAME/$IMAGE:${git_sha}-development |" 40 | echo "----------------------------------------------------------------" 41 | fi -------------------------------------------------------------------------------- /src/core/core_checks.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import Tuple, Iterable, IO 3 | import time 4 | from virus_total_apis import PublicApi as VirusTotalPublicApi 5 | 6 | 7 | class Checks(ABC): 8 | """ abstract class for burnt checks with in PeFixup.""" 9 | def __init__(self, sha256, api_key: str = ''): 10 | """ 11 | Init class and passed objects. 12 | """ 13 | self.sha256 = str(sha256) 14 | self.api_key = str(api_key) 15 | self.results = self._check() 16 | 17 | # abstract method def 18 | def check_seen(self) -> bool: 19 | """ """ 20 | pass 21 | 22 | # abstract method def 23 | def check_safe(self) -> bool: 24 | """ """ 25 | pass 26 | 27 | def _check(self): 28 | """ """ 29 | pass 30 | 31 | class VT(Checks): 32 | """ VT checks""" 33 | def __init__(self, sha256: str, api_key: str = ''): 34 | """ 35 | Init class and passed objects. 36 | """ 37 | self.sha256 = sha256 38 | self.api_key = str(api_key) 39 | self.vt = VirusTotalPublicApi(self.api_key) 40 | self.results = self._check() 41 | 42 | def check_seen(self) -> bool: 43 | """ """ 44 | if self.results['results']['response_code'] == 0: 45 | # if response 0: we have NOT been seen 46 | return False 47 | if self.results['results']['response_code'] == 1: 48 | # if response 1: we have been seen 49 | return True 50 | 51 | def check_safe(self) -> bool: 52 | if not self.results['results'].get('positives', False): 53 | # we are marked safe 54 | return True 55 | if self.results['results'].get('positives', True): 56 | # we are marked mal 57 | return False 58 | 59 | def _check(self): 60 | while True: 61 | results = self.vt.get_file_report(self.sha256) 62 | if results['response_code'] == 204: 63 | time.sleep(10) 64 | continue 65 | break 66 | return results 67 | 68 | -------------------------------------------------------------------------------- /src/core/core_runtime.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import pefile 4 | from pefile import debug_types 5 | from termcolor import colored 6 | import json 7 | 8 | 9 | from . import core_printer 10 | from . import core_preop 11 | from . import core_model 12 | from . import core_preflight 13 | from . import core_cook 14 | from . import core_postflight 15 | 16 | 17 | class CoreRuntime(core_printer.CorePrinters, 18 | core_preop.CorePerOp, 19 | core_preflight.CorePreFlight, 20 | core_cook.CoreCook, 21 | core_postflight.CorePostFlight 22 | ): 23 | 24 | """ 25 | Core Runtime Class. 26 | """ 27 | 28 | def __init__(self, config, args): 29 | """ 30 | Init class and passed objects. 31 | """ 32 | self.config = config 33 | self.args = args 34 | self.pe = pefile.PE(args.INPUT) 35 | self.model = core_model._core_schema 36 | self.dirty_imports_model = core_model._dirty_imports_model 37 | self.warn_level = core_model._warn_level 38 | self.warn_color = core_model._warn_color 39 | self.raw = self.setup_raw() 40 | self.live = self.setup_live() 41 | self.taint = None 42 | self.cooked = None 43 | core_printer.CorePrinters.__init__(self) 44 | core_preop.CorePerOp.__init__(self) 45 | core_preflight.CorePreFlight.__init__(self) 46 | core_cook.CoreCook.__init__(self) 47 | core_postflight.CorePostFlight.__init__(self) 48 | 49 | def fix_up(self): 50 | #print(json.dumps(self.model, indent=2)) 51 | pass 52 | 53 | def setup_raw(self): 54 | with open(self.args.INPUT, 'rb') as f: 55 | raw = f.read() 56 | return raw 57 | 58 | def setup_live(self): 59 | with open(self.args.LIVE, 'wb') as f: 60 | f.write(self.raw) 61 | with open(self.args.LIVE, 'rb') as f: 62 | live_raw = f.read() 63 | return live_raw 64 | 65 | def setup_taint(self): 66 | self.taint = open(self.args.LIVE, 'r+b') 67 | 68 | def setup_cooked(self): 69 | with open(self.args.LIVE, 'r+b') as f: 70 | self.cooked = f.read() 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /src/core/test_hash.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from . import core_hash 3 | 4 | class TestHashMethods(unittest.TestCase): 5 | 6 | def test_md5(self): 7 | x = bytes(0x00) 8 | m = core_hash.MD5() 9 | self.assertEqual(m.get_hash_hexdigest(x), 'd41d8cd98f00b204e9800998ecf8427e') 10 | self.assertEqual(m.get_hash_digest(x), b'\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\t\x98\xec\xf8B~') 11 | self.assertEqual(m.get_digest_size(x), 16) 12 | 13 | def test_sha1(self): 14 | x = bytes(0x00) 15 | m = core_hash.SHA1() 16 | self.assertEqual(m.get_hash_hexdigest(x), 'da39a3ee5e6b4b0d3255bfef95601890afd80709') 17 | self.assertEqual(m.get_hash_digest(x), b'\xda9\xa3\xee^kK\r2U\xbf\xef\x95`\x18\x90\xaf\xd8\x07\t') 18 | self.assertEqual(m.get_digest_size(x), 20) 19 | 20 | def test_sha256(self): 21 | x = bytes(0x00) 22 | m = core_hash.SHA256() 23 | self.assertEqual(m.get_hash_hexdigest(x), 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855') 24 | # TODO: Fix this test case: 25 | self.assertEqual(m.get_hash_digest(x), m.get_hash_digest(x)) 26 | self.assertEqual(m.get_digest_size(x), 32) 27 | 28 | def test_sha512(self): 29 | x = bytes(0x00) 30 | m = core_hash.SHA512() 31 | self.assertEqual(m.get_hash_hexdigest(x), 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e') 32 | # TODO: Fix this test case: 33 | self.assertEqual(m.get_hash_digest(x), m.get_hash_digest(x)) 34 | self.assertEqual(m.get_digest_size(x), 64) 35 | 36 | def test_imp(self): 37 | m = core_hash.IMP() 38 | self.assertEqual(m.get_hash_hexdigest('test/net-35-bin.exe'), 'f34d5f2d4577ed6d9ceec516c1f5a744') 39 | # TODO: Fix this test case: 40 | self.assertEqual(m.get_hash_digest('test/net-35-bin.exe'), b'f34d5f2d4577ed6d9ceec516c1f5a744') 41 | self.assertEqual(m.get_digest_size('test/net-35-bin.exe'), 32) 42 | 43 | def test_ssdeep(self): 44 | m = core_hash.SSDEEP() 45 | self.assertEqual(m.get_hash_hexdigest('test/net-35-bin.exe'), '3:HVRhqJ:H7wJ') 46 | # TODO: Fix this test case: 47 | self.assertEqual(m.get_hash_digest('test/net-35-bin.exe'), b'3:HVRhqJ:H7wJ') 48 | self.assertEqual(m.get_digest_size('test/net-35-bin.exe'), 13) 49 | 50 | if __name__ == '__main__': 51 | unittest.main() -------------------------------------------------------------------------------- /pefixup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3.7 2 | import argparse 3 | import config 4 | import json 5 | import logging 6 | import os 7 | import sys 8 | 9 | from src.core import core_runtime 10 | from src.core import core_printer 11 | 12 | pr = core_printer.CorePrinters() 13 | 14 | def cli_parse(): 15 | """ 16 | Parse the CLI args passed to the script. 17 | :return: args 18 | """ 19 | # required 20 | pr.print_entry() 21 | parser = argparse.ArgumentParser() 22 | parser.add_argument("INPUT", help="input file to process") 23 | parser.add_argument("LIVE", help="output file name") 24 | # opts 25 | parser.add_argument("-c", "--compile-time", type=int, 26 | help="Cooked payload epoc compile time to taint", default=1454680254) 27 | 28 | parser.add_argument("-p", "--pdb", type=str, 29 | help="Cooked payload PDB (Ex. fun)", default='pefixup') 30 | 31 | parser.add_argument("-ma", "--major-linker-version", type=int, 32 | help="Cooked payload major linker version to taint(Ex. 10)", default=10) 33 | 34 | parser.add_argument("-mi", "--minor-linker-version", type=int, 35 | help="Cooked payload minor linker version to taint(Ex. 10)", default=2) 36 | 37 | parser.add_argument("-json", "--json", 38 | help="output json to stdout",action="store_true") 39 | 40 | parser.add_argument("-s", "--strings", 41 | help="Enable output file with strings (Ex. FunTimes.exe -> FunTimes.txt)", action="store_true") 42 | 43 | parser.add_argument("-vt", "--vt-api-key", type=str, 44 | help="VirusTotal API Key", default='') 45 | 46 | parser.add_argument("-v", "--verbose", help="increase output verbosity", 47 | action="store_true") 48 | 49 | parser.add_argument("-d", "--debug", help="enable debug logging to .pefixup.log file, default WARNING only", 50 | action="store_true") 51 | args = parser.parse_args() 52 | if args.verbose: 53 | print("[!] Verbosity turned on") 54 | if args.debug: 55 | print("[!] Debug turned on:") 56 | for x in vars(args): 57 | print(f" arg: ({x}) key: ({vars(args)[x]})") 58 | if not config.VT_KEY: 59 | config.VT_KEY = args.vt_api_key 60 | return args, parser 61 | 62 | 63 | def main(): 64 | """ 65 | Print entry screen and pass execution to CLI, 66 | and task core. 67 | :return: 68 | """ 69 | args, parser = cli_parse() 70 | c = core_runtime.CoreRuntime(config, args) 71 | c.fix_up() 72 | 73 | 74 | 75 | if __name__ == "__main__": 76 | try: 77 | main() 78 | except KeyboardInterrupt: 79 | print('Interrupted') 80 | try: 81 | sys.exit(0) 82 | except SystemExit: 83 | os._exit(0) -------------------------------------------------------------------------------- /src/core/core_hash.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from typing import Tuple, Iterable, IO 3 | import hashlib 4 | import pefile 5 | import magic 6 | import ssdeep 7 | 8 | class Hashing(ABC): 9 | """ abstract class for hashing with in PeFixup.""" 10 | 11 | # abstract method def 12 | @staticmethod 13 | def get_hash_digest(file_handle: IO[bytes]) -> bytes: 14 | """ Like digest() except the digest is returned as a 15 | string of double length, containing only hexadecimal digits. 16 | This may be used to exchange the value safely in email or 17 | other non-binary environments.""" 18 | pass 19 | 20 | # abstract method def 21 | @staticmethod 22 | def get_hash_hexdigest(file_handle: IO[bytes]) -> str: 23 | """ Like digest() except the digest is returned as a 24 | string of double length, containing only hexadecimal 25 | digits. This may be used to exchange the value safely 26 | in email or other non-binary environments.""" 27 | pass 28 | 29 | # abstract method def 30 | @staticmethod 31 | def get_digest_size(file_handle: IO[bytes]) -> int: 32 | """ The size of the resulting hash in bytes.""" 33 | pass 34 | 35 | class MD5(Hashing): 36 | """ MD5 hashing""" 37 | 38 | @staticmethod 39 | def get_hash_digest(file_handle: IO[bytes]) -> bytes: 40 | return hashlib.md5(file_handle).digest() 41 | 42 | @staticmethod 43 | def get_hash_hexdigest(file_handle: IO[bytes]) -> str: 44 | return hashlib.md5(file_handle).hexdigest() 45 | 46 | @staticmethod 47 | def get_digest_size(file_handle: IO[bytes]) -> int: 48 | return hashlib.md5(file_handle).digest_size 49 | 50 | class SHA1(Hashing): 51 | """ SHA1 hashing""" 52 | 53 | @staticmethod 54 | def get_hash_digest(file_handle: IO[bytes]) -> bytes: 55 | return hashlib.sha1(file_handle).digest() 56 | 57 | @staticmethod 58 | def get_hash_hexdigest(file_handle: IO[bytes]) -> str: 59 | return hashlib.sha1(file_handle).hexdigest() 60 | 61 | @staticmethod 62 | def get_digest_size(file_handle: IO[bytes]) -> int: 63 | return hashlib.sha1(file_handle).digest_size 64 | 65 | class SHA256(Hashing): 66 | """ SHA256 hashing""" 67 | 68 | @staticmethod 69 | def get_hash_digest(file_handle: IO[bytes]) -> bytes: 70 | return hashlib.sha256(file_handle).digest() 71 | 72 | @staticmethod 73 | def get_hash_hexdigest(file_handle: IO[bytes]) -> str: 74 | return hashlib.sha256(file_handle).hexdigest() 75 | 76 | @staticmethod 77 | def get_digest_size(file_handle: IO[bytes]) -> int: 78 | return hashlib.sha256(file_handle).digest_size 79 | 80 | class SHA512(Hashing): 81 | """ SHA512 hashing""" 82 | 83 | @staticmethod 84 | def get_hash_digest(file_handle: IO[bytes]) -> bytes: 85 | return hashlib.sha512(file_handle).digest() 86 | 87 | @staticmethod 88 | def get_hash_hexdigest(file_handle: IO[bytes]) -> str: 89 | return hashlib.sha512(file_handle).hexdigest() 90 | 91 | @staticmethod 92 | def get_digest_size(file_handle: IO[bytes]) -> int: 93 | return hashlib.sha512(file_handle).digest_size 94 | 95 | class IMP(Hashing): 96 | """ IMP hashing""" 97 | 98 | @staticmethod 99 | def get_hash_digest(file_handle: str) -> bytes: 100 | pe = pefile.PE(file_handle) 101 | return bytes(str.encode(pe.get_imphash())) 102 | 103 | @staticmethod 104 | def get_hash_hexdigest(file_handle: str) -> str: 105 | pe = pefile.PE(file_handle) 106 | return pe.get_imphash() 107 | 108 | @staticmethod 109 | def get_digest_size(file_handle: str) -> int: 110 | pe = pefile.PE(file_handle) 111 | x = bytes(str.encode(pe.get_imphash())) 112 | return len(x) 113 | 114 | class SSDEEP(Hashing): 115 | """ SSDEEP hashing""" 116 | 117 | @staticmethod 118 | def get_hash_digest(file_handle: IO[bytes]) -> bytes: 119 | return bytes(str.encode(ssdeep.hash(file_handle))) 120 | 121 | @staticmethod 122 | def get_hash_hexdigest(file_handle: IO[bytes]) -> str: 123 | return ssdeep.hash(file_handle) 124 | 125 | @staticmethod 126 | def get_digest_size(file_handle: IO[bytes]) -> int: 127 | x = bytes(str.encode(ssdeep.hash(file_handle))) 128 | return len(x) 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /src/core/core_preop.py: -------------------------------------------------------------------------------- 1 | import magic 2 | import datetime 3 | from typing import Tuple, Iterable, Union 4 | from pefile import debug_types 5 | from termcolor import colored 6 | 7 | from . import core_hash 8 | 9 | class CorePerOp(): 10 | 11 | """ 12 | Core PreOp Checks Class. 13 | """ 14 | 15 | def __init__(self): 16 | """ 17 | Init class and passed objects. 18 | """ 19 | self.print_pre_op() 20 | self.pre_op_metadata() 21 | self.pre_op_file_header() 22 | self.pre_op_image_opt_header() 23 | self.print_line_br() 24 | self.pre_op_debug_info() 25 | self.pre_op_dll_info() 26 | 27 | def pre_op_metadata(self): 28 | """ """ 29 | s = core_hash.IMP() 30 | nc = self.model['non_cooked_payload'] 31 | nc['metadata']['file_name'] = self.args.INPUT 32 | nc['metadata']['e_magic'] = hex(self.pe.DOS_HEADER.e_magic) 33 | nc['metadata']['signature'] = hex(self.pe.NT_HEADERS.Signature) 34 | nc['metadata']['imphash'] = s.get_hash_hexdigest(self.args.INPUT) 35 | nc['metadata']['executable_code_size'] = int(self.pe.OPTIONAL_HEADER.SizeOfCode) / 1024 36 | nc['metadata']['executable_image_size'] = int(self.pe.OPTIONAL_HEADER.SizeOfImage) / 1024 37 | self.print_pre_op_metadata() 38 | 39 | def pre_op_file_header(self): 40 | """ """ 41 | nc = self.model['non_cooked_payload'] 42 | nc['file_header']['machine_type'] = hex(self.pe.FILE_HEADER.Machine) 43 | nc['file_header']['timedatestamp'] = datetime.datetime.fromtimestamp(int(self.pe.FILE_HEADER.TimeDateStamp)).strftime('%c') 44 | self.print_pre_op_file_header() 45 | 46 | def pre_op_image_opt_header(self): 47 | """ """ 48 | nc = self.model['non_cooked_payload'] 49 | nc['image_optional_header64']['magic'] = hex(self.pe.OPTIONAL_HEADER.Magic) 50 | nc['image_optional_header64']['major_linker_version'] = hex(self.pe.OPTIONAL_HEADER.MajorImageVersion) 51 | nc['image_optional_header64']['minor_linker_version'] = hex(self.pe.OPTIONAL_HEADER.MajorLinkerVersion) 52 | nc['image_optional_header64']['major_os_version'] = hex(self.pe.OPTIONAL_HEADER.MajorOperatingSystemVersion) 53 | nc['image_optional_header64']['minor_os_version'] = hex(self.pe.OPTIONAL_HEADER.MinorOperatingSystemVersion) 54 | self.print_pre_op_image_opt_header() 55 | 56 | def pre_op_debug_info(self): 57 | """ """ 58 | _t = {} 59 | try: 60 | for x in self.pe.DIRECTORY_ENTRY_DEBUG: 61 | _t['entry'] = {} 62 | _t['type'] = debug_types[x.struct.Type][1] 63 | _t['type_name'] = debug_types[x.struct.Type][0] 64 | _t['timedatestamp'] = datetime.datetime.fromtimestamp(int(x.struct.TimeDateStamp)).strftime('%c') 65 | if x.entry: 66 | if x.entry.name == 'CV_INFO_PDB70': 67 | _t['entry']['pdbfilename'] = x.entry.PdbFileName 68 | _t['entry']['type'] = 'CV_INFO_PDB70' 69 | self.model['non_cooked_payload']['directory_entry_debug'].append(_t) 70 | self.print_pre_op_debug_info() 71 | except AttributeError as e: 72 | print(colored(f'[!] {e}','yellow')) 73 | 74 | def pre_op_dll_info(self): 75 | """ """ 76 | print("[*] Listing imported DLLs...") 77 | try: 78 | for entry in self.pe.DIRECTORY_ENTRY_IMPORT: 79 | _val = {} 80 | print('\t' + colored(entry.dll.decode('utf-8'), 'magenta')) 81 | self.model['non_cooked_payload']['directory_entry_import'][entry.dll.decode('utf-8')] = [] 82 | 83 | for entry in self.pe.DIRECTORY_ENTRY_IMPORT: 84 | _val = {} 85 | dll_name = entry.dll.decode('utf-8') 86 | if 'api' not in dll_name: 87 | print(f"[*] {colored(dll_name, 'magenta')} imports:") 88 | for func in entry.imports: 89 | func_name = func.name.decode('utf-8') 90 | self.model['non_cooked_payload']['directory_entry_import'][dll_name].append({ 91 | 'function_name': func_name, 92 | 'function_address': func.address 93 | }) 94 | _s, _m = self.pre_op_dll_status(dll_name, func_name) 95 | print("\t%s at 0x%08x <-- [%s] = %s" % (colored(func_name, 'blue'), 96 | func.address, colored(self.warn_level[_s], self.warn_color[_s]), 97 | colored(_m, self.warn_color[_s]))) 98 | else: 99 | print(f"[-] Not printing imports of {dll_name} no need..") 100 | except AttributeError as e: 101 | print(colored(f'[!] {e}','yellow')) 102 | 103 | def pre_op_dll_status(self, imp: str, func: str) -> Tuple[str, str]: 104 | """ """ 105 | i = self.dirty_imports_model.get(imp, {}) 106 | f = i.get(func, {}) 107 | status = f.get('status', 1) 108 | message = f.get('message', 'Please submit PR') 109 | return(status, message) 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /src/core/core_model.py: -------------------------------------------------------------------------------- 1 | _core_schema = { 2 | 'non_cooked_payload': { 3 | 'metadata': { 4 | 'file_name': '', 5 | 'e_magic': '', 6 | 'signature': '', 7 | 'imphash': '', 8 | 'executable_code_size': '', 9 | 'executable_image_size': '', 10 | }, 11 | 'file_header': { 12 | 'machine_type': '', 13 | 'timedatestamp': '', 14 | }, 15 | 'image_optional_header64': { 16 | 'magic': '', 17 | 'major_linker_version': '', 18 | 'minor_linker_version': '', 19 | 'major_os_version': '', 20 | 'minor_os_version': '' 21 | }, 22 | 'directory_entry_debug': [], 23 | 'directory_entry_import': {} 24 | }, 25 | 'preflight_checks': { 26 | 'rewrite': { 27 | 'non_cooked_sha256': '', 28 | 'cooked_sha256': '', 29 | }, 30 | 'preflight': False, 31 | }, 32 | 'cooked_payload': { 33 | 'metadata': { 34 | 'file_name': '', 35 | 'md5': '', 36 | 'sha1': '', 37 | 'sha256': '', 38 | 'sha512': '', 39 | 'imphash': '', 40 | 'ssdeep': '', 41 | 'magic': '', 42 | 'exif': {} 43 | } 44 | } 45 | } 46 | 47 | # This section can be broken down into a few destinct sections: 48 | # 5: ALERT: Check your self 49 | # 4: DANGER: This isnt a NOGO but should be removed if at all possible 50 | # 3: WARNING: May be worth looking into 51 | # 2: OK: Move forward 52 | # 1: UNCLASSIFIED: Unkown submit a PR and c 53 | 54 | _warn_level = { 55 | 5: 'ALERT', 56 | 4: 'DANGER', 57 | 3: 'WARNING', 58 | 2: 'OK', 59 | 1: 'UNKNOWN' 60 | } 61 | 62 | _warn_color = { 63 | 5: 'red', 64 | 4: 'yellow', 65 | 3: 'cyan', 66 | 2: 'green', 67 | 1: 'white' 68 | } 69 | 70 | _dirty_imports_model = { 71 | 'KERNEL32.dll': { 72 | 'CreateRemoteThread': {'status': 5, 'message': 'This import is often flagged for remote process injection.'}, 73 | 'GetCurrentProcess': {'status': 3, 'message': 'This import can be concerning, but only with other imports of concern.'}, 74 | 'IsDebuggerPresent': {'status': 5, 'message': 'Import offten flagged for sandbox / analysis evasion'}, 75 | 'RtlVirtualUnwind': {'status': 2, 'message': 'Exception handling'}, 76 | 'RtlLookupFunctionEntry': {'status': 2, 'message': 'Exception handling'}, 77 | 'RtlCaptureContext': {'status': 2, 'message': 'Exception handling'}, 78 | 'InitializeSListHead': {'status': 2, 'message': 'Compiler optimization'}, 79 | 'SetUnhandledExceptionFilter': {'status': 2, 'message': 'Exception handling'}, 80 | 'GetLastError': {'status': 2, 'message': 'Exception handling'}, 81 | 'UnhandledExceptionFilter': {'status': 2, 'message': 'Exception handling'}, 82 | 'VirtualAllocEx': {'status': 4, 'message': 'Import is often flagged for shellcode injection.'}, 83 | 'GetProcAddress': {'status': 4, 'message': 'Import is often flagged for shellcode injection.'}, 84 | 'CreateEventW': {'status': 2, 'message': 'Various OS interaction'}, 85 | 'TerminateProcess': {'status': 2, 'message': 'Various OS interaction'}, 86 | 'IsProcessorFeaturePresent': {'status': 3, 'message': 'This import can be concerning, but only with other imports of concern.'}, 87 | 'DeleteCriticalSection': {'status': 2, 'message': 'Various OS interaction'}, 88 | # http://demin.ws/blog/russian/2009/03/05/queryperformancecounter-on-multicore-and-virtual-systems/ 89 | 'QueryPerformanceCounter': {'status': 4, 'message': 'Import offten flagged for sandbox / analysis evasion'}, 90 | 'GetCurrentProcessId': {'status': 3, 'message': 'This import can be concerning, but only with other imports of concern.'}, 91 | 'GetCurrentThreadId': {'status': 3, 'message': 'This import can be concerning, but only with other imports of concern.'}, 92 | 'ReadFile': {'status': 2, 'message': 'Various OS interaction'}, 93 | 'GetSystemTimeAsFileTime': {'status': 2, 'message': 'Various OS interaction'}, 94 | 'CreateProcessW': {'status': 5, 'message': 'This import is often flagged for remote process injection.'}, 95 | 'GetModuleHandleW': {'status': 4, 'message': 'Import offten flagged for dynamic function location'}, 96 | 'OpenProcess': {'status': 4, 'message': 'Import offten flagged for dynamic function location'}, 97 | 'WriteProcessMemory': {'status': 4, 'message': 'Import offten flagged for dynamic function location'}, 98 | 'CloseHandle': {'status': 2, 'message': 'Various OS interaction'}, 99 | 'EnterCriticalSection': {'status': 2, 'message': 'Exception handling'}, 100 | 'InitializeCriticalSection': {'status': 2, 'message': 'Exception handling'}, 101 | 'GetTickCount': {'status': 4, 'message': 'Import offten flagged for sandbox / analysis evasion'}, 102 | 'Sleep': {'status': 4, 'message': 'Import offten flagged for sandbox / analysis evasion'}, 103 | 'TlsGetValue': {'status': 2, 'message': 'Exception handling'}, 104 | 'ConnectNamedPipe': {'status': 3, 'message': 'This import can be concerning, but only with other imports of concern.'}, 105 | 'CreateNamedPipeA': {'status': 3, 'message': 'This import can be concerning, but only with other imports of concern.'}, 106 | 'CreateThread': {'status': 3, 'message': 'This import can be concerning, but only with other imports of concern.'}, 107 | 'CreateFileA': {'status': 2, 'message': 'Various OS interaction'}, 108 | }, 109 | 'mscoree.dll': { 110 | '_CorExeMain': {'status':2, 'message': 'Managed executable entry for assemblies'} 111 | }, 112 | 'ADVAPI32.dll': { 113 | 'AdjustTokenPrivileges': {'status': 4, 'message': 'Import used for token manipulation'}, 114 | 'OpenProcessToken': {'status': 3, 'message': 'Import used for token manipulation'}, 115 | 'LookupPrivilegeValueW': {'status': 3, 'message': 'Import used for token manipulation'}, 116 | }, 117 | 'VCRUNTIME140.dll': { 118 | 'memcpy': {'status': 2, 'message': 'Various OS interaction'}, 119 | 'memmove': {'status': 2, 'message': 'Various OS interaction'}, 120 | '__std_terminate': {'status': 2, 'message': 'Various OS interaction'}, 121 | '__std_exception_copy': {'status': 2, 'message': 'Various OS interaction'}, 122 | '__std_exception_destroy': {'status': 2, 'message': 'Various OS interaction'}, 123 | '_CxxThrowException': {'status': 2, 'message': 'Various OS interaction'}, 124 | '__CxxFrameHandler3': {'status': 2, 'message': 'Various OS interaction'}, 125 | 'memset': {'status': 2, 'message': 'Various OS interaction'}, 126 | '__C_specific_handler': {'status': 2, 'message': 'Various OS interaction'}, 127 | '__vcrt_InitializeCriticalSectionEx': {'status': 2, 'message': 'Various OS interaction'}, 128 | } 129 | } 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /src/core/core_printer.py: -------------------------------------------------------------------------------- 1 | from termcolor import colored, cprint 2 | import json 3 | import pprint 4 | import magic 5 | from . import core_hash 6 | 7 | class CorePrinters(object): 8 | """ 9 | Core class: handles all data output within the project. 10 | """ 11 | 12 | _branding_screen = """ 13 | *----------------------------------* 14 | | 15 | *----------------------------------* 16 | """ 17 | 18 | __title_screen = """ 19 | ------------------------------- 20 | █▀▀█ █▀▀ █▀▀ ░▀░ █░█ █░░█ █▀▀█ 21 | █░░█ █▀▀ █▀▀ ▀█▀ ▄▀▄ █░░█ █░░█ 22 | █▀▀▀ ▀▀▀ ▀░░ ▀▀▀ ▀░▀ ░▀▀▀ █▀▀▀ 23 | ------------------------------- 24 | """ 25 | 26 | def __init__(self): 27 | """ 28 | INIT class object and define 29 | statics. 30 | """ 31 | self.print_green = lambda x: cprint(x, 'green') 32 | self.print_green_on_bold = lambda x: cprint(x, 'green', attrs=['bold']) 33 | self.print_yellow = lambda x: cprint(x, 'yellow') 34 | self.print_yellow_on_bold = lambda x: cprint( 35 | x, 'yellow', attrs=['bold']) 36 | self.print_red = lambda x: cprint(x, 'red') 37 | self.print_red_on_bold = lambda x: cprint(x, 'red', attrs=['bold']) 38 | self.print_white = lambda x: cprint(x, 'white') 39 | 40 | def blue_text(self, msg): 41 | """ 42 | Return green text obj. 43 | :param msg: TEXT 44 | :return: OBJ 45 | """ 46 | s = colored(' [*] ', color='blue') 47 | msg = s + msg 48 | return msg 49 | 50 | def green_text(self, msg): 51 | """ 52 | Return green text obj. 53 | :param msg: TEXT 54 | :return: OBJ 55 | """ 56 | s = colored(' [+] ', color='green') 57 | msg = s + msg 58 | return msg 59 | 60 | def print_model(self): 61 | """ """ 62 | pprint.pprint(self.model) 63 | 64 | def print_entry(self): 65 | """ """ 66 | self.print_green_on_bold(self.__title_screen) 67 | 68 | def print_pre_op(self): 69 | """ """ 70 | print("============= ORIGINAL FILE DATA =============") 71 | print("|-* IF LIVE OPS SAVE THIS DATA TO OP SHARE *-|") 72 | print("==============================================") 73 | 74 | def print_pre_flight(self): 75 | """ """ 76 | print("============= PRE-FLIGHT CHECKS ==============") 77 | print("|-* IF LIVE OPS SAVE THIS DATA TO OP SHARE *-|") 78 | print("==============================================") 79 | 80 | def print_post_flight(self): 81 | """ """ 82 | print("============ POST-FLIGHT CHECKS ==============") 83 | print("|-* IF LIVE OPS SAVE THIS DATA TO OP SHARE *-|") 84 | print("==============================================") 85 | 86 | def print_line_br(self): 87 | """ .""" 88 | print("-----------------------------------------------") 89 | 90 | def print_pre_op_metadata(self): 91 | """ """ 92 | print("[*] EXE metadata:") 93 | print(f" - File Name: {colored(self.model['non_cooked_payload']['metadata']['file_name'], 'yellow')}") 94 | print(f" - e_magic value: {self.model['non_cooked_payload']['metadata']['e_magic']}") 95 | print(f" - Signature value: {self.model['non_cooked_payload']['metadata']['signature']}") 96 | print(f" - Imphash: {self.model['non_cooked_payload']['metadata']['imphash']}") 97 | print(f" - Size of executable code: {self.model['non_cooked_payload']['metadata']['executable_code_size']}KB") 98 | print(f" - Size of executable image : {self.model['non_cooked_payload']['metadata']['executable_image_size']}KB") 99 | 100 | def print_pre_op_file_header(self): 101 | """ """ 102 | print("[*] FILE_HEADER:") 103 | print(f" - Machine type value: {self.model['non_cooked_payload']['file_header']['machine_type']}") 104 | print(f" - TimeDateStamp value: '{self.model['non_cooked_payload']['file_header']['timedatestamp']}' ") 105 | 106 | def print_pre_op_image_opt_header(self): 107 | """ """ 108 | print("[*] IMAGE_OPTIONAL_HEADER64:") 109 | print(f" - Magic value: {self.model['non_cooked_payload']['image_optional_header64']['magic']}") 110 | print(f" - Major Linker Version: {self.model['non_cooked_payload']['image_optional_header64']['major_linker_version']}") 111 | print(f" - Minor Linker Version: {self.model['non_cooked_payload']['image_optional_header64']['minor_linker_version']}") 112 | print(f" - Major OS Version: {self.model['non_cooked_payload']['image_optional_header64']['major_os_version']}") 113 | print(f" - Minor OS Version: {self.model['non_cooked_payload']['image_optional_header64']['minor_os_version']}") 114 | 115 | def print_pre_op_debug_info(self): 116 | """ """ 117 | print("[*] Listing DEBUG Info:") 118 | for x in self.model['non_cooked_payload']['directory_entry_debug']: 119 | print(f"\t[*] Type Name: {x['type_name']}") 120 | print(f"\t\t- Type: {x['type']}") 121 | print(f"\t\t- TimeDateStamp value: '{x['timedatestamp']}'") 122 | if x.get('entry'): 123 | if x['entry'].get('type') == 'CV_INFO_PDB70': 124 | # print debug strings 125 | print(f"\t\t- PdbFileName type: '{x['entry']['type']}'") 126 | print(f"\t\t- PdbFileName value: '{colored(x['entry'],'red')}'") 127 | self.print_line_br() 128 | 129 | def print_taint_payload(self): 130 | print("============= TAINTED FILE DATA ==============") 131 | print("|-* IF LIVE OPS SAVE THIS DATA TO OP SHARE *-|") 132 | print("==============================================") 133 | 134 | def print_runtime_sanity_checks(self): 135 | print("==============================================") 136 | print("|-* RUNTIME SANITY CHECKS *-|") 137 | print("==============================================") 138 | 139 | def print_runtime_burnt_checks(self): 140 | print("==============================================") 141 | print("|-* RUNTIME BURNT CHECKS *-|") 142 | print("==============================================") 143 | 144 | def print_cooked_payload_metadata(self): 145 | """ """ 146 | _md = self.model['cooked_payload']['metadata'] 147 | print("==============================================") 148 | print("|-* COOKED PAYLOAD METADATA *-|") 149 | print("==============================================") 150 | print(f"[*] Filename of cooked payload: {colored(_md['file_name'], 'green')}") 151 | print(f"[*] MD5 of cooked payload: {colored(_md['md5'], 'green')}") 152 | print(f"[*] SHA1 of cooked payload: {colored(_md['sha1'], 'green')}") 153 | print(f"[*] SHA256 of cooked payload: {colored(_md['sha256'], 'green')}") 154 | print(f"[*] SHA512 of cooked payload: {colored(_md['sha512'], 'green')}") 155 | print(f"[*] Imphash of cooked payload: {colored(_md['imphash'], 'green')}") 156 | print(f"[*] SSDeep of cooked payload: {colored(_md['ssdeep'], 'green')}") 157 | print(f"[*] Magic of cooked payload: {colored(_md['magic'], 'green')}") 158 | print(f"[*] EXIF Data follows of cooked payload:") 159 | for x in _md['exif']: 160 | print(f"\t{x}: { colored(_md['exif'][x],'green')}") 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "012714d86b463c2725e751f115756d9d1490da503fab0b312e895437dbfce55c" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.6" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "cffi": { 20 | "hashes": [ 21 | "sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774", 22 | "sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d", 23 | "sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90", 24 | "sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b", 25 | "sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63", 26 | "sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45", 27 | "sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25", 28 | "sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3", 29 | "sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b", 30 | "sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647", 31 | "sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016", 32 | "sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4", 33 | "sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb", 34 | "sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753", 35 | "sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7", 36 | "sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9", 37 | "sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f", 38 | "sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8", 39 | "sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f", 40 | "sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc", 41 | "sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42", 42 | "sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3", 43 | "sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909", 44 | "sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45", 45 | "sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d", 46 | "sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512", 47 | "sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff", 48 | "sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201" 49 | ], 50 | "version": "==1.12.3" 51 | }, 52 | "future": { 53 | "hashes": [ 54 | "sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8" 55 | ], 56 | "version": "==0.17.1" 57 | }, 58 | "pefile": { 59 | "hashes": [ 60 | "sha256:a5d6e8305c6b210849b47a6174ddf9c452b2888340b8177874b862ba6c207645" 61 | ], 62 | "index": "pypi", 63 | "version": "==2019.4.18" 64 | }, 65 | "pycparser": { 66 | "hashes": [ 67 | "sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3" 68 | ], 69 | "version": "==2.19" 70 | }, 71 | "python-magic": { 72 | "hashes": [ 73 | "sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375", 74 | "sha256:f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5" 75 | ], 76 | "index": "pypi", 77 | "version": "==0.4.15" 78 | }, 79 | "six": { 80 | "hashes": [ 81 | "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", 82 | "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" 83 | ], 84 | "version": "==1.12.0" 85 | }, 86 | "ssdeep": { 87 | "hashes": [ 88 | "sha256:255de1f034652b3ed21920221017e70e570b1644f9436fea120ae416175f4ef5" 89 | ], 90 | "index": "pypi", 91 | "version": "==3.3" 92 | }, 93 | "termcolor": { 94 | "hashes": [ 95 | "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b" 96 | ], 97 | "index": "pypi", 98 | "version": "==1.1.0" 99 | } 100 | }, 101 | "develop": { 102 | "atomicwrites": { 103 | "hashes": [ 104 | "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", 105 | "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6" 106 | ], 107 | "version": "==1.3.0" 108 | }, 109 | "attrs": { 110 | "hashes": [ 111 | "sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79", 112 | "sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399" 113 | ], 114 | "version": "==19.1.0" 115 | }, 116 | "coverage": { 117 | "hashes": [ 118 | "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", 119 | "sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650", 120 | "sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5", 121 | "sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d", 122 | "sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351", 123 | "sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755", 124 | "sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef", 125 | "sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca", 126 | "sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca", 127 | "sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9", 128 | "sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc", 129 | "sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5", 130 | "sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f", 131 | "sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe", 132 | "sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888", 133 | "sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5", 134 | "sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce", 135 | "sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5", 136 | "sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e", 137 | "sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e", 138 | "sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9", 139 | "sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437", 140 | "sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1", 141 | "sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c", 142 | "sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24", 143 | "sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47", 144 | "sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2", 145 | "sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28", 146 | "sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c", 147 | "sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7", 148 | "sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0", 149 | "sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025" 150 | ], 151 | "index": "pypi", 152 | "version": "==4.5.4" 153 | }, 154 | "importlib-metadata": { 155 | "hashes": [ 156 | "sha256:0c505102757e7fa28b9f0958d8bc81301159dea16e2649858c92edc158b78a83", 157 | "sha256:9a9f75ce32e78170905888acbf2376a81d3f21ecb3bb4867050413411d3ca7a9" 158 | ], 159 | "markers": "python_version < '3.8'", 160 | "version": "==0.21" 161 | }, 162 | "more-itertools": { 163 | "hashes": [ 164 | "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", 165 | "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" 166 | ], 167 | "version": "==7.2.0" 168 | }, 169 | "packaging": { 170 | "hashes": [ 171 | "sha256:a7ac867b97fdc07ee80a8058fe4435ccd274ecc3b0ed61d852d7d53055528cf9", 172 | "sha256:c491ca87294da7cc01902edbe30a5bc6c4c28172b5138ab4e4aa1b9d7bfaeafe" 173 | ], 174 | "version": "==19.1" 175 | }, 176 | "pluggy": { 177 | "hashes": [ 178 | "sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", 179 | "sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34" 180 | ], 181 | "version": "==0.13.0" 182 | }, 183 | "py": { 184 | "hashes": [ 185 | "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", 186 | "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53" 187 | ], 188 | "version": "==1.8.0" 189 | }, 190 | "pyparsing": { 191 | "hashes": [ 192 | "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", 193 | "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4" 194 | ], 195 | "version": "==2.4.2" 196 | }, 197 | "pytest": { 198 | "hashes": [ 199 | "sha256:95d13143cc14174ca1a01ec68e84d76ba5d9d493ac02716fd9706c949a505210", 200 | "sha256:b78fe2881323bd44fd9bd76e5317173d4316577e7b1cddebae9136a4495ec865" 201 | ], 202 | "index": "pypi", 203 | "version": "==5.1.2" 204 | }, 205 | "pytest-cov": { 206 | "hashes": [ 207 | "sha256:2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6", 208 | "sha256:e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a" 209 | ], 210 | "index": "pypi", 211 | "version": "==2.7.1" 212 | }, 213 | "six": { 214 | "hashes": [ 215 | "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", 216 | "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73" 217 | ], 218 | "version": "==1.12.0" 219 | }, 220 | "wcwidth": { 221 | "hashes": [ 222 | "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", 223 | "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" 224 | ], 225 | "version": "==0.1.7" 226 | }, 227 | "zipp": { 228 | "hashes": [ 229 | "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", 230 | "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335" 231 | ], 232 | "version": "==0.6.0" 233 | } 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/core/core_cook.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Iterable, Union 2 | from termcolor import colored, cprint 3 | from . import core_hash 4 | from . import core_checks 5 | import datetime 6 | import magic 7 | import pyexifinfo as exif 8 | from struct import * 9 | from pefile import debug_types 10 | 11 | class CoreCook(): 12 | 13 | """ 14 | Core Cook Class. 15 | """ 16 | 17 | def __init__(self): 18 | """ 19 | Init class and passed objects. 20 | """ 21 | self.cook_taint() 22 | self.sanity_check() 23 | self.populate_metadata() 24 | self.runtime_burnt_check() 25 | 26 | def cook_taint(self): 27 | self.print_taint_payload() 28 | self.setup_taint() 29 | if self.taint: 30 | self.dos_header() 31 | self.image_file_header() 32 | self.image_optional_header() 33 | self.directory_entry_debug() 34 | self.taint.close() 35 | 36 | def dos_header(self): 37 | """ 38 | typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header 39 | USHORT e_magic; // Magic number 40 | USHORT e_cblp; // Bytes on last page of file 41 | USHORT e_cp; // Pages in file 42 | USHORT e_crlc; // Relocations 43 | USHORT e_cparhdr; // Size of header in paragraphs 44 | USHORT e_minalloc; // Minimum extra paragraphs needed 45 | USHORT e_maxalloc; // Maximum extra paragraphs needed 46 | USHORT e_ss; // Initial (relative) SS value 47 | USHORT e_sp; // Initial SP value 48 | USHORT e_csum; // Checksum 49 | USHORT e_ip; // Initial IP value 50 | USHORT e_cs; // Initial (relative) CS value 51 | USHORT e_lfarlc; // File address of relocation table 52 | USHORT e_ovno; // Overlay number 53 | USHORT e_res[4]; // Reserved words 54 | USHORT e_oemid; // OEM identifier (for e_oeminfo) 55 | USHORT e_oeminfo; // OEM information; e_oemid specific 56 | USHORT e_res2[10]; // Reserved words 57 | LONG e_lfanew; // File address of new exe header 58 | } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; 59 | """ 60 | print("[*] Walking DOS_HEADER:") 61 | print(f" - Target e_lfanew offset value: {hex(self.pe.DOS_HEADER.e_lfanew)}") 62 | self.target_offset = self.pe.DOS_HEADER.e_lfanew + 4 63 | print(f" - Set e_lfanew offset + PE bytes: {hex(self.pe.DOS_HEADER.e_lfanew+4)}") 64 | 65 | def image_file_header(self) -> bool: 66 | """ 67 | typedef struct _IMAGE_FILE_HEADER { 68 | USHORT Machine; 69 | USHORT NumberOfSections; 70 | ULONG TimeDateStamp; 71 | ULONG PointerToSymbolTable; 72 | ULONG NumberOfSymbols; 73 | USHORT SizeOfOptionalHeader; 74 | USHORT Characteristics; 75 | } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; 76 | """ 77 | # now add 4 bytes to the value for the ASCII string 'PE' 78 | try: 79 | print("[*] Walking IMAGE_FILE_HEADER:") 80 | self.ifh_tds = self.target_offset + 4 81 | print(f" - TimeDateStamp offset value: {hex(self.ifh_tds)}") 82 | print(f" - TimeDateStamp hex value: {hex(unpack('L', self.raw[self.ifh_tds:self.ifh_tds+0x8])[0])}") 83 | print(f" - TimeDateStamp int value: {unpack('L', self.raw[self.ifh_tds:self.ifh_tds+0x8])[0]}") 84 | print(f" - TimeDateStamp time date value: {datetime.datetime.fromtimestamp(int(unpack( 'L', self.raw[self.ifh_tds:self.ifh_tds+0x8])[0]))}") 85 | self.taint.seek(self.ifh_tds, 0) 86 | self.taint.write(pack('L', self.args.compile_time)) 87 | print(colored(f" ==> TimeDateStamp stomped start write location: {hex(self.ifh_tds)}", "cyan")) 88 | print(colored(f" ==> Setting TimeDateStamp stomped int value to: {self.args.compile_time}", "cyan")) 89 | print(colored(f" ==> Setting TimeDateStamp stomped hex value to: {hex(self.args.compile_time)}", "cyan")) 90 | print(colored(f" ==> TimeDateStamp time date value: {datetime.datetime.fromtimestamp(int(self.args.compile_time))}", "cyan")) 91 | except Exception as e: 92 | # return false so we can alert process of bad stomp 93 | print(colored(f"[!] (image_file_header()-{datetime.datetime.now()}) [ERROR]: {e}",'red')) 94 | return False 95 | return True 96 | 97 | def image_optional_header(self) -> bool: 98 | """ 99 | typedef struct _IMAGE_OPTIONAL_HEADER { 100 | // 101 | // Standard fields. 102 | // 103 | USHORT Magic; 104 | UCHAR MajorLinkerVersion; 105 | UCHAR MinorLinkerVersion; 106 | ULONG SizeOfCode; 107 | ULONG SizeOfInitializedData; 108 | ULONG SizeOfUninitializedData; 109 | ULONG AddressOfEntryPoint; 110 | ULONG BaseOfCode; 111 | ULONG BaseOfData; 112 | // 113 | // NT additional fields. 114 | // 115 | ULONG ImageBase; 116 | ULONG SectionAlignment; 117 | ULONG FileAlignment; 118 | USHORT MajorOperatingSystemVersion; 119 | USHORT MinorOperatingSystemVersion; 120 | USHORT MajorImageVersion; 121 | USHORT MinorImageVersion; 122 | USHORT MajorSubsystemVersion; 123 | USHORT MinorSubsystemVersion; 124 | ULONG Reserved1; 125 | ULONG SizeOfImage; 126 | ULONG SizeOfHeaders; 127 | ULONG CheckSum; 128 | USHORT Subsystem; 129 | USHORT DllCharacteristics; 130 | ULONG SizeOfStackReserve; 131 | ULONG SizeOfStackCommit; 132 | ULONG SizeOfHeapReserve; 133 | ULONG SizeOfHeapCommit; 134 | ULONG LoaderFlags; 135 | ULONG NumberOfRvaAndSizes; 136 | IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; 137 | } IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; 138 | """ 139 | try: 140 | print("[*] Walking IMAGE_OPTIONAL_HEADER:") 141 | print(f" - Magic offset value: {hex(self.pe.OPTIONAL_HEADER.__file_offset__)}") 142 | print(f" - Magic hex value: {hex(unpack('H', self.raw[self.pe.OPTIONAL_HEADER.__file_offset__:self.pe.OPTIONAL_HEADER.__file_offset__+0x2])[0])}") 143 | print(f" - MajorLinkerVersion offset value: {hex(self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MajorLinkerVersion'])}") 144 | print(f" - MajorLinkerVersion hex value: {hex(unpack('B', self.raw[self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MajorLinkerVersion']:self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MajorLinkerVersion']+0x1])[0])}") 145 | print(f" - MajorLinkerVersion int value: {unpack('B', self.raw[self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MajorLinkerVersion']:self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MajorLinkerVersion']+0x1])[0]}") 146 | print(f" - MinorLinkerVersion offset value: {hex(self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MinorLinkerVersion'])}") 147 | print(f" - MinorLinkerVersion hex value: {hex(unpack('B', self.raw[self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MinorLinkerVersion']:self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MinorLinkerVersion']+0x1])[0])}") 148 | print(f" - MinorLinkerVersion int value: {unpack('B', self.raw[self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MinorLinkerVersion']:self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MinorLinkerVersion']+0x1])[0]}") 149 | 150 | print(colored(f" ==> MajorLinkerVersion stomped start write location: {hex(self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MajorLinkerVersion'])}", "cyan")) 151 | print(colored(f" ==> Setting MajorLinkerVersion stomped int value to: {self.args.major_linker_version}", "cyan")) 152 | print(colored(f" ==> Setting MajorLinkerVersion stomped hex value to: {hex(self.args.major_linker_version)}", "cyan")) 153 | self.taint.seek(self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MajorLinkerVersion'], 0) 154 | self.taint.write(pack('B', self.args.major_linker_version)) 155 | 156 | print(colored(f" ==> MinorLinkerVersion stomped start write location: {hex(self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MinorLinkerVersion'])}", "cyan")) 157 | print(colored(f" ==> Setting MinorLinkerVersion stomped int value to: {self.args.minor_linker_version}", "cyan")) 158 | print(colored(f" ==> Setting MinorLinkerVersion stomped hex value to: {hex(self.args.minor_linker_version)}", "cyan")) 159 | self.taint.seek(self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MinorLinkerVersion'], 0) 160 | self.taint.write(pack('B', self.args.minor_linker_version)) 161 | except Exception as e: 162 | # return false so we can alert process of bad stomp 163 | print(colored(f"[!] (image_optional_header()-{datetime.datetime.now()}) [ERROR]: {e}",'red')) 164 | return False 165 | return True 166 | 167 | def directory_entry_debug(self) -> bool: 168 | """ 169 | // Directory Entries 170 | // Export Directory 171 | #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 172 | // Import Directory 173 | #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 174 | // Resource Directory 175 | #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 176 | // Exception Directory 177 | #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 178 | // Security Directory 179 | #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 180 | // Base Relocation Table 181 | #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 182 | // Debug Directory 183 | #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 184 | // Description String 185 | #define IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 186 | // Machine Value (MIPS GP) 187 | #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 188 | // TLS Directory 189 | #define IMAGE_DIRECTORY_ENTRY_TLS 9 190 | // Load Configuration Directory 191 | #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 192 | 193 | typedef struct _IMAGE_DATA_DIRECTORY { 194 | ULONG VirtualAddress; 195 | ULONG Size; 196 | } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; 197 | 198 | typedef struct _IMAGE_DEBUG_DIRECTORY { 199 | ULONG Characteristics; 200 | ULONG TimeDateStamp; 201 | USHORT MajorVersion; 202 | USHORT MinorVersion; 203 | ULONG Type; 204 | ULONG SizeOfData; 205 | ULONG AddressOfRawData; 206 | ULONG PointerToRawData; 207 | } IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY; 208 | """ 209 | print("[*] DEBUG INFO:") 210 | status = True 211 | for x in self.pe.DIRECTORY_ENTRY_DEBUG: 212 | try: 213 | print(f"\t[*] Type: {debug_types[x.struct.Type]}") 214 | print(f"\t\t- Debug TimeDateStamp offset value: {hex(x.struct.get_field_absolute_offset('TimeDateStamp'))}") 215 | print(f"\t\t- TimeDateStamp hex value: {hex(unpack('L', self.raw[x.struct.get_field_absolute_offset('TimeDateStamp'):x.struct.get_field_absolute_offset('TimeDateStamp')+0x8])[0])}") 216 | print(f"\t\t- TimeDateStamp int value: {unpack('L', self.raw[x.struct.get_field_absolute_offset('TimeDateStamp'):x.struct.get_field_absolute_offset('TimeDateStamp')+0x8])[0]}") 217 | print(f"\t\t- TimeDateStamp time date value: {datetime.datetime.fromtimestamp(int(unpack('L', self.raw[x.struct.get_field_absolute_offset('TimeDateStamp'):x.struct.get_field_absolute_offset('TimeDateStamp')+0x8])[0]))}") 218 | self.taint.seek(x.struct.get_field_absolute_offset('TimeDateStamp'), 0) 219 | self.taint.write(pack('L', self.args.compile_time)) 220 | print(colored(f"\t\t==> TimeDateStamp stomped start write location: {hex(x.struct.get_field_absolute_offset('TimeDateStamp'))}", "cyan")) 221 | print(colored(f"\t\t==> Setting TimeDateStamp stomped int value to: {self.args.compile_time}", "cyan")) 222 | print(colored(f"\t\t==> Setting TimeDateStamp stomped hex value to: {hex(self.args.compile_time)}", "cyan")) 223 | print(colored(f"\t\t==> TimeDateStamp time date value: {datetime.datetime.fromtimestamp(int(self.args.compile_time))}", "cyan")) 224 | if x.entry: 225 | if x.entry.name == 'CV_INFO_PDB70': 226 | # print debug strings 227 | print(f"\t\t- PdbFileName offset value: {hex(x.entry.__file_offset__ + x.entry.__field_offsets__['PdbFileName'])}") 228 | print(f"\t\t- PdbFileName value: '{colored(x.entry.PdbFileName,'red')}'") 229 | self.taint.seek(x.entry.__file_offset__ + x.entry.__field_offsets__['PdbFileName'], 0) 230 | p = self.taint.read() 231 | chars = [] 232 | for y in p: 233 | chars.append(chr(y)) 234 | if y == 0: 235 | break 236 | clean_chars = b'' 237 | for y in chars: 238 | clean_chars += b'\x00' 239 | print(f"\t\t- PdbFileName null-term string: '{colored(chars,'red')}'") 240 | print(colored(f"\t\t==> PdbFileName stomped start write location: {hex(x.entry.__file_offset__ + x.entry.__field_offsets__['PdbFileName'])}", "cyan")) 241 | print(colored(f"\t\t==> PdbFifleName stomped end write location: {hex(x.entry.__file_offset__ + x.entry.__field_offsets__['PdbFileName'] + len(chars))}", "cyan")) 242 | print(colored(f"\t\t==> Setting PdbFifleName stomped hex value to: {clean_chars}", "cyan")) 243 | self.taint.seek(x.entry.__file_offset__ + x.entry.__field_offsets__['PdbFileName'], 0) 244 | self.taint.write(clean_chars) 245 | except Exception as e: 246 | print(colored(f"[!] (directory_entry_debug()-{datetime.datetime.now()}) [ERROR]: {x} = {e}",'red')) 247 | status = False 248 | return status 249 | 250 | 251 | def sanity_check(self): 252 | """ Perform some basic checks to make sure we have completed all stomps.""" 253 | # setup new file handle 254 | self.setup_cooked() 255 | # conduct analysis 256 | self.print_runtime_sanity_checks() 257 | if not core_hash.SHA256.get_hash_hexdigest(self.cooked) == core_hash.SHA256.get_hash_hexdigest(self.raw): 258 | print(f"[*] SHA256 do not match, we have proper write: {colored('PASS', 'green')}") 259 | else: 260 | print(f"[*] SHA256 MATCH, we DONT have proper write: {colored('FAIL', 'red')}") 261 | if int(unpack('L', self.cooked[self.ifh_tds:self.ifh_tds+0x8])[0]) == self.args.compile_time: 262 | print(f"[*] TimeDateStamp stomped properly: {colored('PASS', 'green')}") 263 | else: 264 | print(f"[*] TimeDateStamp stomped: {colored('FAIL', 'red')}") 265 | # test case for major linker version 266 | if int(unpack('B', self.cooked[self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MajorLinkerVersion']:self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MajorLinkerVersion']+0x1])[0]) == self.args.major_linker_version: 267 | print(f"[*] MajorLinkerVersion stomped properly: {colored('PASS', 'green')}") 268 | else: 269 | print(f"[*] MajorLinkerVersion stomped properly: {colored('FAIL', 'red')}") 270 | # test case for minor linker version 271 | if int(unpack('B', self.cooked[self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MinorLinkerVersion']:self.pe.OPTIONAL_HEADER.__file_offset__+self.pe.OPTIONAL_HEADER.__field_offsets__['MinorLinkerVersion']+0x1])[0]) == self.args.minor_linker_version: 272 | print(f"[*] MinorLinkerVersion stomped properly: {colored('PASS', 'green')}") 273 | else: 274 | print(f"[*] MinorLinkerVersion stomped properly: {colored('FAIL', 'red')}") 275 | # test to make sure debug dir are solid 276 | for x in self.pe.DIRECTORY_ENTRY_DEBUG: 277 | if unpack('L', self.cooked[x.struct.get_field_absolute_offset('TimeDateStamp'):x.struct.get_field_absolute_offset('TimeDateStamp')+0x8])[0] == self.args.compile_time: 278 | print(f"[*] TimeDateStamp stomped properly for {debug_types[x.struct.Type]}: {colored('PASS', 'green')}") 279 | 280 | def populate_metadata(self): 281 | """ Populate cooked metadata into our JSON model""" 282 | _md = self.model['cooked_payload']['metadata'] 283 | _md['file_name'] = self.args.LIVE 284 | _md['md5'] = core_hash.MD5.get_hash_hexdigest(self.cooked) 285 | _md['sha1'] = core_hash.SHA1.get_hash_hexdigest(self.cooked) 286 | _md['sha256'] = core_hash.SHA256.get_hash_hexdigest(self.cooked) 287 | _md['sha512'] = core_hash.SHA512.get_hash_hexdigest(self.cooked) 288 | _md['imphash'] = core_hash.IMP.get_hash_hexdigest(self.args.LIVE) 289 | _md['ssdeep'] = core_hash.SSDEEP.get_hash_hexdigest(self.cooked) 290 | _md['magic'] = magic.from_file(self.args.LIVE) 291 | ex = exif.get_json(self.args.LIVE)[0] 292 | _md['exif'] = ex 293 | self.print_cooked_payload_metadata() 294 | 295 | def runtime_burnt_check(self) -> bool: 296 | self.print_runtime_burnt_checks() 297 | if not self.config.VT_KEY: 298 | # no key set for VT skip 299 | print(f"[*] No VirusTotal API key loaded (Skipping): {colored('WARNING', 'yellow')}") 300 | return False 301 | print(f"[*] Starting checks VirusTotal HASH ONLY checks") 302 | vt = core_checks.VT(core_hash.SHA256.get_hash_hexdigest(self.raw), api_key=self.config.VT_KEY) 303 | # check non-cooked payload 304 | if not vt.check_seen() and vt.check_safe(): 305 | # we are safe bin has not been seen in wild 306 | print(f" - SHA256 of non-cooked payload is SAFE and NOT SEEN in VirusTotal: {colored(core_hash.SHA256.get_hash_hexdigest(self.raw), 'green')}") 307 | if vt.check_seen() and vt.check_safe(): 308 | # TODO: warning for seen and alert for flagged 309 | print(f" - SHA256 of non-cooked payload is SAFE and SEEN in VirusTotal: {colored(core_hash.SHA256.get_hash_hexdigest(self.raw), 'yellow')}") 310 | if vt.check_seen() and not vt.check_safe(): 311 | # TODO: warning for seen and alert for flagged 312 | print(f" - SHA256 of non-cooked payload is NOT-SAFE and SEEN in VirusTotal: {colored(core_hash.SHA256.get_hash_hexdigest(self.raw), 'red')}") 313 | 314 | # check new live payload 315 | vt = core_checks.VT(core_hash.SHA256.get_hash_hexdigest(self.cooked), api_key=self.config.VT_KEY) 316 | if not vt.check_seen() and vt.check_safe(): 317 | # we are safe bin has not been seen in wild 318 | print(f" - SHA256 of cooked payload is SAFE and NOT SEEN in VirusTotal: {colored(core_hash.SHA256.get_hash_hexdigest(self.cooked), 'green')}") 319 | if vt.check_seen() and vt.check_safe(): 320 | # TODO: warning for seen and alert for flagged 321 | print(f" - SHA256 of cooked payload is SAFE and SEEN in VirusTotal: {colored(core_hash.SHA256.get_hash_hexdigest(self.cooked), 'yellow')}") 322 | if vt.check_seen() and not vt.check_safe(): 323 | # TODO: warning for seen and alert for flagged 324 | print(f" - SHA256 of cooked payload is NOT-SAFE and SEEN in VirusTotal: {colored(core_hash.SHA256.get_hash_hexdigest(self.cooked), 'red')}") 325 | 326 | # check of non-cooked payload sections (PE Sections) 327 | for x in self.pe.sections: 328 | name = x.Name.rstrip(b'\x00').decode("utf-8") 329 | sha256 = x.get_hash_sha256() 330 | vt = core_checks.VT(sha256, api_key=self.config.VT_KEY) 331 | if not vt.check_seen() and vt.check_safe(): 332 | print(f" - SHA256 PE Section {name} of non-cooked payload is SAFE and NOT SEEN in VirusTotal: {colored(sha256, 'green')}") 333 | if vt.check_seen() and vt.check_safe(): 334 | print(f" - SHA256 PE Section {name} of non-cooked payload is SAFE and SEEN in VirusTotal: {colored(sha256, 'yellow')}") 335 | if vt.check_seen() and not vt.check_safe(): 336 | print(f" - SHA256 PE Section {name} of non-cooked payload is NOT-SAFE and SEEN in VirusTotal: {colored(sha256, 'red')}") 337 | 338 | 339 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.com/obscuritylabs/PeFixup.svg?branch=master)](https://travis-ci.com/obscuritylabs/PeFixup) 2 | # PeFixup 3 | PE File Blessing - A PE tainting tool 4 | - [PeFixup](#pefixup) 5 | * [Install PeFixup](#install-pefixup) 6 | + [Installl from source](#installl-from-source) 7 | + [Installl from PYPI (Under Dev)](#installl-from-pypi--under-dev-) 8 | + [Installl from DockerHub](#installl-from-dockerhub) 9 | * [Features](#features) 10 | * [Help & examples](#help---examples) 11 | + [Examples](#examples) 12 | + [Example Output](#example-output) 13 | 14 | ## Install PeFixup 15 | ### Required Packages 16 | #### Ubuntu 18.04+ 17 | ```bash 18 | apt-get update && \ 19 | apt-get install -y --no-install-recommends \ 20 | libffi-dev \ 21 | libfuzzy-dev \ 22 | ssdeep \ 23 | exiftool 24 | ``` 25 | 26 | ### Install from source 27 | ```bash 28 | $ git clone https://github.com/obscuritylabs/PeFixup.git 29 | $ cd Pefixup 30 | $ pip3 install -r requirements.txt 31 | $ python3 pefixup.py -h 32 | ``` 33 | **or using pipenv** 34 | ```bash 35 | $ https://github.com/obscuritylabs/PeFixup.git 36 | $ cd Pefixup 37 | $ pipenv install 38 | $ pipenv shell 39 | (PeFixup) bash-3.2$ 40 | ``` 41 | ### Install from PYPI (Under Dev) 42 | ``` 43 | $ pip install --user pefixup 44 | $ pefixup -h 45 | ``` 46 | ### Install from DockerHub 47 | ``` 48 | $ docker pull obscuritylabs/pefixup:latest 49 | $ docker pull obscuritylabs/pefixup:0.0.1 50 | $ docker pull obscuritylabs/pefixup:development 51 | ``` 52 | 53 | ## Features 54 | Currently we have implemented the following tainting capabilities: 55 | * taint compile times within `IMAGE_FILE_HEADER` 56 | * taint major & minor compiler versions within `_IMAGE_OPTIONAL_HEADER` 57 | * taint multiple compile times within `DIRECTORY_ENTRY_DEBUG` 58 | * taint multiple pdb headers within `DIRECTORY_ENTRY_DEBUG & CV_INFO_PDB70` 59 | 60 | Currently we have implemented the following metadata capabilities: 61 | * Hashing 62 | * MD5 63 | * SHA1 64 | * SHA256 65 | * SHA512 66 | * imphash 67 | * ssdeep 68 | * Imports 69 | * All binary imports within `DIRECTORY_ENTRY_IMPORT` 70 | * All binary import function name & addr 71 | * Import function name checks to alert on potentially dangerous imports (AV/Analysis) 72 | * Binary metadata 73 | * PE header data 74 | * Binary Magic values 75 | * EXIF data 76 | * Runtime Checks 77 | * pre-flight checks 78 | * sanity checks 79 | * post-flight checks 80 | * burnt checks 81 | * Burnt checks 82 | * providers 83 | * VirusTotal (Checks Hash ONLY) 84 | * binary sections (dynamic sections) 85 | * non-cooked payload 86 | * cooked payload 87 | * .text 88 | * .rdata 89 | * .data 90 | * .pdata 91 | * .tls 92 | * .rsrc 93 | 94 | ## Help & examples 95 | 96 | ```bash 97 | $ python3 pefixup.py --help 98 | 99 | 100 | ------------------------------- 101 | █▀▀█ █▀▀ █▀▀ ░▀░ █░█ █░░█ █▀▀█ 102 | █░░█ █▀▀ █▀▀ ▀█▀ ▄▀▄ █░░█ █░░█ 103 | █▀▀▀ ▀▀▀ ▀░░ ▀▀▀ ▀░▀ ░▀▀▀ █▀▀▀ 104 | ------------------------------- 105 | 106 | usage: pefixup.py [-h] [-c COMPILE_TIME] [-p PDB] [-ma MAJOR_LINKER_VERSION] 107 | [-mi MINOR_LINKER_VERSION] [-o OUTPUT] [-json JSON] [-s] 108 | [-vt VT_API_KEY] [-v] [-d] 109 | INPUT LIVE 110 | 111 | positional arguments: 112 | INPUT input file to process 113 | LIVE output file name 114 | 115 | optional arguments: 116 | -h, --help show this help message and exit 117 | -c COMPILE_TIME, --compile-time COMPILE_TIME 118 | Cooked payload epoc compile time to taint 119 | -p PDB, --pdb PDB Cooked payload PDB (Ex. fun) 120 | -ma MAJOR_LINKER_VERSION, --major-linker-version MAJOR_LINKER_VERSION 121 | Cooked payload major linker version to taint(Ex. 10) 122 | -mi MINOR_LINKER_VERSION, --minor-linker-version MINOR_LINKER_VERSION 123 | Cooked payload minor linker version to taint(Ex. 10) 124 | -o OUTPUT, --output OUTPUT 125 | output filename (Ex. FunTimes.exe) 126 | -json JSON, --json JSON 127 | output json to stdout 128 | -s, --strings Enable output file with strings (Ex. FunTimes.exe -> 129 | FunTimes.txt) 130 | -vt VT_API_KEY, --vt-api-key VT_API_KEY 131 | VirusTotal API Key 132 | -v, --verbose increase output verbosity 133 | -d, --debug enable debug logging to .pefixup.log file, default 134 | WARNING only 135 | ``` 136 | 137 | ### Examples 138 | ```bash 139 | python3 pefixup.py ~/Desktop/RickJames.exe officeupdate.exe 140 | python3 pefixup.py ~/Desktop/RickJames.exe officeupdate.exe -c 1568192888 -p funtimes -ma 10 -mi 1 141 | python3 pefixup.py ~/Desktop/RickJames.exe officeupdate.exe -c 1568192888 -p funtimes -ma 10 -mi 1 -vt 1G23212FT 142 | or we can export the VT key 143 | export PEFIXUP_VT_KEY=1G23212FT && python3 pefixup.py ~/Desktop/RickJames.exe officeupdate.exe 144 | ``` 145 | 146 | ### Example Output 147 | ```bash 148 | alexanders-MacBook-Pro-9:PeFixup alexanderrymdeko-harvey$ python3 pefixup.py ~/Desktop/RickJames.exe jj.exe -vt XXX 149 | 150 | ------------------------------- 151 | █▀▀█ █▀▀ █▀▀ ░▀░ █░█ █░░█ █▀▀█ 152 | █░░█ █▀▀ █▀▀ ▀█▀ ▄▀▄ █░░█ █░░█ 153 | █▀▀▀ ▀▀▀ ▀░░ ▀▀▀ ▀░▀ ░▀▀▀ █▀▀▀ 154 | ------------------------------- 155 | 156 | ============= ORIGINAL FILE DATA ============= 157 | |-* IF LIVE OPS SAVE THIS DATA TO OP SHARE *-| 158 | ============================================== 159 | [*] EXE metadata: 160 | - File Name: /Users/alexanderrymdeko-harvey/Desktop/RickJames.exe 161 | - e_magic value: 0x5a4d 162 | - Signature value: 0x4550 163 | - Imphash: 8d02d075ece1e0e4d14116cb66fb54ae 164 | - Size of executable code: 8.5KB 165 | - Size of executable image : 300.0KB 166 | [*] FILE_HEADER: 167 | - Machine type value: 0x8664 168 | - TimeDateStamp value: 'Tue Feb 26 23:03:24 2019' 169 | [*] IMAGE_OPTIONAL_HEADER64: 170 | - Magic value: 0x20b 171 | - Major Linker Version: 0x0 172 | - Minor Linker Version: 0xe 173 | - Major OS Version: 0x6 174 | - Minor OS Version: 0x0 175 | ----------------------------------------------- 176 | [*] Listing DEBUG Info: 177 | [*] Type Name: IMAGE_DEBUG_TYPE_ILTCG 178 | - Type: 14 179 | - TimeDateStamp value: 'Tue Feb 26 23:03:24 2019' 180 | [*] Type Name: IMAGE_DEBUG_TYPE_ILTCG 181 | - Type: 14 182 | - TimeDateStamp value: 'Tue Feb 26 23:03:24 2019' 183 | [*] Type Name: IMAGE_DEBUG_TYPE_ILTCG 184 | - Type: 14 185 | - TimeDateStamp value: 'Tue Feb 26 23:03:24 2019' 186 | [*] Type Name: IMAGE_DEBUG_TYPE_ILTCG 187 | - Type: 14 188 | - TimeDateStamp value: 'Tue Feb 26 23:03:24 2019' 189 | ----------------------------------------------- 190 | [*] Listing imported DLLs... 191 | KERNEL32.dll 192 | ADVAPI32.dll 193 | MSVCP140.dll 194 | VCRUNTIME140.dll 195 | api-ms-win-crt-runtime-l1-1-0.dll 196 | api-ms-win-crt-stdio-l1-1-0.dll 197 | api-ms-win-crt-string-l1-1-0.dll 198 | api-ms-win-crt-heap-l1-1-0.dll 199 | api-ms-win-crt-math-l1-1-0.dll 200 | api-ms-win-crt-locale-l1-1-0.dll 201 | [*] KERNEL32.dll imports: 202 | CloseHandle at 0x140004020 <-- [OK] = Various OS interaction 203 | GetLastError at 0x140004028 <-- [OK] = Exception handling 204 | GetCurrentProcess at 0x140004030 <-- [WARNING] = This import can be concerning, but only with other imports of concern. 205 | CreateRemoteThread at 0x140004038 <-- [ALERT] = This import is often flagged for remote process injection. 206 | OpenProcess at 0x140004040 <-- [DANGER] = Import offten flagged for dynamic function location 207 | VirtualAllocEx at 0x140004048 <-- [DANGER] = Import is often flagged for shellcode injection. 208 | WriteProcessMemory at 0x140004050 <-- [DANGER] = Import offten flagged for dynamic function location 209 | GetModuleHandleW at 0x140004058 <-- [DANGER] = Import offten flagged for dynamic function location 210 | GetProcAddress at 0x140004060 <-- [DANGER] = Import is often flagged for shellcode injection. 211 | CreateProcessW at 0x140004068 <-- [ALERT] = This import is often flagged for remote process injection. 212 | GetSystemTimeAsFileTime at 0x140004070 <-- [OK] = Various OS interaction 213 | GetCurrentThreadId at 0x140004078 <-- [WARNING] = This import can be concerning, but only with other imports of concern. 214 | GetCurrentProcessId at 0x140004080 <-- [WARNING] = This import can be concerning, but only with other imports of concern. 215 | QueryPerformanceCounter at 0x140004088 <-- [DANGER] = Import offten flagged for sandbox / analysis evasion 216 | IsDebuggerPresent at 0x140004090 <-- [ALERT] = Import offten flagged for sandbox / analysis evasion 217 | CreateEventW at 0x140004098 <-- [OK] = Various OS interaction 218 | DeleteCriticalSection at 0x1400040a0 <-- [OK] = Various OS interaction 219 | IsProcessorFeaturePresent at 0x1400040a8 <-- [WARNING] = This import can be concerning, but only with other imports of concern. 220 | TerminateProcess at 0x1400040b0 <-- [OK] = Various OS interaction 221 | SetUnhandledExceptionFilter at 0x1400040b8 <-- [OK] = Exception handling 222 | UnhandledExceptionFilter at 0x1400040c0 <-- [OK] = Exception handling 223 | RtlVirtualUnwind at 0x1400040c8 <-- [OK] = Exception handling 224 | RtlLookupFunctionEntry at 0x1400040d0 <-- [OK] = Exception handling 225 | RtlCaptureContext at 0x1400040d8 <-- [OK] = Exception handling 226 | InitializeSListHead at 0x1400040e0 <-- [OK] = Compiler optimization 227 | [*] ADVAPI32.dll imports: 228 | AdjustTokenPrivileges at 0x140004000 <-- [DANGER] = Import used for token manipulation 229 | OpenProcessToken at 0x140004008 <-- [WARNING] = Import used for token manipulation 230 | LookupPrivilegeValueW at 0x140004010 <-- [WARNING] = Import used for token manipulation 231 | [*] MSVCP140.dll imports: 232 | ?_Xbad_alloc@std@@YAXXZ at 0x1400040f0 <-- [UNKNOWN] = Please submit PR 233 | ?_Xlength_error@std@@YAXPEBD@Z at 0x1400040f8 <-- [UNKNOWN] = Please submit PR 234 | ?_Xout_of_range@std@@YAXPEBD@Z at 0x140004100 <-- [UNKNOWN] = Please submit PR 235 | [*] VCRUNTIME140.dll imports: 236 | memcpy at 0x140004110 <-- [OK] = Various OS interaction 237 | __std_terminate at 0x140004118 <-- [OK] = Various OS interaction 238 | memmove at 0x140004120 <-- [OK] = Various OS interaction 239 | __std_exception_copy at 0x140004128 <-- [OK] = Various OS interaction 240 | __std_exception_destroy at 0x140004130 <-- [OK] = Various OS interaction 241 | _CxxThrowException at 0x140004138 <-- [OK] = Various OS interaction 242 | __CxxFrameHandler3 at 0x140004140 <-- [OK] = Various OS interaction 243 | memset at 0x140004148 <-- [OK] = Various OS interaction 244 | __C_specific_handler at 0x140004150 <-- [OK] = Various OS interaction 245 | __vcrt_InitializeCriticalSectionEx at 0x140004158 <-- [OK] = Various OS interaction 246 | [-] Not printing imports of api-ms-win-crt-runtime-l1-1-0.dll no need.. 247 | [-] Not printing imports of api-ms-win-crt-stdio-l1-1-0.dll no need.. 248 | [-] Not printing imports of api-ms-win-crt-string-l1-1-0.dll no need.. 249 | [-] Not printing imports of api-ms-win-crt-heap-l1-1-0.dll no need.. 250 | [-] Not printing imports of api-ms-win-crt-math-l1-1-0.dll no need.. 251 | [-] Not printing imports of api-ms-win-crt-locale-l1-1-0.dll no need.. 252 | ============= PRE-FLIGHT CHECKS ============== 253 | |-* IF LIVE OPS SAVE THIS DATA TO OP SHARE *-| 254 | ============================================== 255 | [*] File re-write checks: 256 | - SHA256 of non-cooked payload: a0ad72b91585f485e91f8a9c46a8c4e4c49cc404acc1055051071fd9762ee505 257 | - SHA256 of cooked payload: a0ad72b91585f485e91f8a9c46a8c4e4c49cc404acc1055051071fd9762ee505 258 | Preflight checks: PASS 259 | ============= TAINTED FILE DATA ============== 260 | |-* IF LIVE OPS SAVE THIS DATA TO OP SHARE *-| 261 | ============================================== 262 | [*] Walking DOS_HEADER: 263 | - Target e_lfanew offset value: 0x108 264 | - Set e_lfanew offset + PE bytes: 0x10c 265 | [*] Walking IMAGE_FILE_HEADER: 266 | - TimeDateStamp offset value: 0x110 267 | - TimeDateStamp hex value: 0x5c759b8c 268 | - TimeDateStamp int value: 1551211404 269 | - TimeDateStamp time date value: 2019-02-26 23:03:24 270 | ==> TimeDateStamp stomped start write location: 0x110 271 | ==> Setting TimeDateStamp stomped int value to: 1454680254 272 | ==> Setting TimeDateStamp stomped hex value to: 0x56b4a8be 273 | ==> TimeDateStamp time date value: 2016-02-05 16:50:54 274 | [*] Walking IMAGE_OPTIONAL_HEADER: 275 | - Magic offset value: 0x120 276 | - Magic hex value: 0x20b 277 | - MajorLinkerVersion offset value: 0x122 278 | - MajorLinkerVersion hex value: 0xe 279 | - MajorLinkerVersion int value: 14 280 | - MinorLinkerVersion offset value: 0x123 281 | - MinorLinkerVersion hex value: 0xa 282 | - MinorLinkerVersion int value: 10 283 | ==> MajorLinkerVersion stomped start write location: 0x122 284 | ==> Setting MajorLinkerVersion stomped int value to: 10 285 | ==> Setting MajorLinkerVersion stomped hex value to: 0xa 286 | ==> MinorLinkerVersion stomped start write location: 0x123 287 | ==> Setting MinorLinkerVersion stomped int value to: 2 288 | ==> Setting MinorLinkerVersion stomped hex value to: 0x2 289 | [*] DEBUG INFO: 290 | [*] Type: ('IMAGE_DEBUG_TYPE_CODEVIEW', 2) 291 | - Debug TimeDateStamp offset value: 0x2c04 292 | - TimeDateStamp hex value: 0x5c759b8c 293 | - TimeDateStamp int value: 1551211404 294 | - TimeDateStamp time date value: 2019-02-26 23:03:24 295 | ==> TimeDateStamp stomped start write location: 0x2c04 296 | ==> Setting TimeDateStamp stomped int value to: 1454680254 297 | ==> Setting TimeDateStamp stomped hex value to: 0x56b4a8be 298 | ==> TimeDateStamp time date value: 2016-02-05 16:50:54 299 | - PdbFileName offset value: 0x2f44 300 | - PdbFileName value: 'b'C:\\Users\\rt\\Desktop\\RickJames\\RickJames\\x64\\Release\\RickJames.pdb\x00'' 301 | - PdbFileName null-term string: '['C', ':', '\\', 'U', 's', 'e', 'r', 's', '\\', 'r', 't', '\\', 'D', 'e', 's', 'k', 't', 'o', 'p', '\\', 'R', 'i', 'c', 'k', 'J', 'a', 'm', 'e', 's', '\\', 'R', 'i', 'c', 'k', 'J', 'a', 'm', 'e', 's', '\\', 'x', '6', '4', '\\', 'R', 'e', 'l', 'e', 'a', 's', 'e', '\\', 'R', 'i', 'c', 'k', 'J', 'a', 'm', 'e', 's', '.', 'p', 'd', 'b', '\x00']' 302 | ==> PdbFileName stomped start write location: 0x2f44 303 | ==> PdbFifleName stomped end write location: 0x2f86 304 | ==> Setting PdbFifleName stomped hex value to: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' 305 | [*] Type: ('IMAGE_DEBUG_TYPE_VC_FEATURE', 12) 306 | - Debug TimeDateStamp offset value: 0x2c20 307 | - TimeDateStamp hex value: 0x5c759b8c 308 | - TimeDateStamp int value: 1551211404 309 | - TimeDateStamp time date value: 2019-02-26 23:03:24 310 | ==> TimeDateStamp stomped start write location: 0x2c20 311 | ==> Setting TimeDateStamp stomped int value to: 1454680254 312 | ==> Setting TimeDateStamp stomped hex value to: 0x56b4a8be 313 | ==> TimeDateStamp time date value: 2016-02-05 16:50:54 314 | [*] Type: ('IMAGE_DEBUG_TYPE_POGO', 13) 315 | - Debug TimeDateStamp offset value: 0x2c3c 316 | - TimeDateStamp hex value: 0x5c759b8c 317 | - TimeDateStamp int value: 1551211404 318 | - TimeDateStamp time date value: 2019-02-26 23:03:24 319 | ==> TimeDateStamp stomped start write location: 0x2c3c 320 | ==> Setting TimeDateStamp stomped int value to: 1454680254 321 | ==> Setting TimeDateStamp stomped hex value to: 0x56b4a8be 322 | ==> TimeDateStamp time date value: 2016-02-05 16:50:54 323 | [*] Type: ('IMAGE_DEBUG_TYPE_ILTCG', 14) 324 | - Debug TimeDateStamp offset value: 0x2c58 325 | - TimeDateStamp hex value: 0x5c759b8c 326 | - TimeDateStamp int value: 1551211404 327 | - TimeDateStamp time date value: 2019-02-26 23:03:24 328 | ==> TimeDateStamp stomped start write location: 0x2c58 329 | ==> Setting TimeDateStamp stomped int value to: 1454680254 330 | ==> Setting TimeDateStamp stomped hex value to: 0x56b4a8be 331 | ==> TimeDateStamp time date value: 2016-02-05 16:50:54 332 | ============================================== 333 | |-* RUNTIME SANITY CHECKS *-| 334 | ============================================== 335 | [*] SHA256 do not match, we have proper write: PASS 336 | [*] TimeDateStamp stomped properly: PASS 337 | [*] MajorLinkerVersion stomped properly: PASS 338 | [*] MinorLinkerVersion stomped properly: PASS 339 | [*] TimeDateStamp stomped properly for ('IMAGE_DEBUG_TYPE_CODEVIEW', 2): PASS 340 | [*] TimeDateStamp stomped properly for ('IMAGE_DEBUG_TYPE_VC_FEATURE', 12): PASS 341 | [*] TimeDateStamp stomped properly for ('IMAGE_DEBUG_TYPE_POGO', 13): PASS 342 | [*] TimeDateStamp stomped properly for ('IMAGE_DEBUG_TYPE_ILTCG', 14): PASS 343 | ============================================== 344 | |-* COOKED PAYLOAD METADATA *-| 345 | ============================================== 346 | [*] Filename of cooked payload: jj.exe 347 | [*] MD5 of cooked payload: 65231460be8482cd6297b0ff47a07cd7 348 | [*] SHA1 of cooked payload: 13f0ba395f0d3e1df486941f46a9406fa779aaa9 349 | [*] SHA256 of cooked payload: 79bb44d9a1365bfca1dd9b23e2f7220b9fc8202ba2004be256bf53458bf27e10 350 | [*] SHA512 of cooked payload: 68becb3ba12850727543f2a092b52077122e673a24f44e994234f9925139fe9f031930751e12c0ee5e8bd45ed12de1e13e21668fdb06a01130188f4871a7e067 351 | [*] Imphash of cooked payload: 8d02d075ece1e0e4d14116cb66fb54ae 352 | [*] SSDeep of cooked payload: 6144:7HTMqK4TA1SjnNVAOKqWCQsKIR2ZIIt+M5co6N+3fv5RUAZ8nE:LTM14TA18nvKqtgzZIE5cnaRUO8 353 | [*] Magic of cooked payload: PE32+ executable (console) x86-64, for MS Windows 354 | [*] EXIF Data follows of cooked payload: 355 | SourceFile: /Users/alexanderrymdeko-harvey/tools/PeFixup/jj.exe 356 | ExifTool:ExifToolVersion: 11.2 357 | File:Directory: /Users/alexanderrymdeko-harvey/tools/PeFixup 358 | File:FileAccessDate: 2019:09:11 13:14:38+03:00 359 | File:FileInodeChangeDate: 2019:09:11 13:14:38+03:00 360 | File:FileModifyDate: 2019:09:11 13:14:38+03:00 361 | File:FileName: jj.exe 362 | File:FilePermissions: rw-r--r-- 363 | File:FileSize: 277 kB 364 | File:FileType: Win64 EXE 365 | File:FileTypeExtension: exe 366 | File:MIMEType: application/octet-stream 367 | EXE:CodeSize: 8704 368 | EXE:EntryPoint: 0x2794 369 | EXE:ImageFileCharacteristics: Executable, Large address aware 370 | EXE:ImageVersion: 0.0 371 | EXE:InitializedDataSize: 275456 372 | EXE:LinkerVersion: 10.2 373 | EXE:MachineType: AMD AMD64 374 | EXE:OSVersion: 6.0 375 | EXE:PEType: PE32+ 376 | EXE:Subsystem: Windows command line 377 | EXE:SubsystemVersion: 6.0 378 | EXE:TimeStamp: 2016:02:05 16:50:54+03:00 379 | EXE:UninitializedDataSize: 0 380 | ============================================== 381 | |-* RUNTIME BURNT CHECKS *-| 382 | ============================================== 383 | [*] Starting checks VirusTotal HASH ONLY checks 384 | - SHA256 of non-cooked payload is SAFE and NOT SEEN in VirusTotal: a0ad72b91585f485e91f8a9c46a8c4e4c49cc404acc1055051071fd9762ee505 385 | - SHA256 of cooked payload is SAFE and NOT SEEN in VirusTotal: 79bb44d9a1365bfca1dd9b23e2f7220b9fc8202ba2004be256bf53458bf27e10 386 | - SHA256 PE Section .text of non-cooked payload is SAFE and NOT SEEN in VirusTotal: 20287460a047d605355994e26aa552de2172ed3d8e43febb8d27ac52db99e1d3 387 | - SHA256 PE Section .rdata of non-cooked payload is SAFE and NOT SEEN in VirusTotal: 70ee18d4fca2c12b5183025d48e21caf4db2b98fc0d9a56460c9f064bc176468 388 | - SHA256 PE Section .data of non-cooked payload is SAFE and NOT SEEN in VirusTotal: cf7f2cff0f91c1d832a734f94a2ec76a52d2fc3846b4804d68e990ae536d89f6 389 | - SHA256 PE Section .pdata of non-cooked payload is SAFE and NOT SEEN in VirusTotal: cb5add40cc6afb7aae92d96f759d932cf97ec4087b65698f79b5430d4f40a22c 390 | - SHA256 PE Section .tls of non-cooked payload is SAFE and SEEN in VirusTotal: 4c6474903705cb450bb6434c29e8854f17d8324efca1fdb9ee9008599060883a 391 | - SHA256 PE Section .rsrc of non-cooked payload is SAFE and NOT SEEN in VirusTotal: 511460000232d2f733ea1ba0b43600e12b3d79d466afb7b12d3a196dc207472e 392 | - SHA256 PE Section .reloc of non-cooked payload is SAFE and NOT SEEN in VirusTotal: 987d59fb32feb52ed375d5dc31dfd1d9fb0748f4e3d39c39786c7a2a30369373 393 | ============ POST-FLIGHT CHECKS ============== 394 | |-* IF LIVE OPS SAVE THIS DATA TO OP SHARE *-| 395 | ============================================== 396 | [-] Strings output not enabled (Skipping): WARNING 397 | ``` 398 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------