Module refinery.units.formats.archive.innopwd

Expand source code Browse git
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations

from refinery.units import Unit

from refinery.lib.inno.archive import InnoArchive, InvalidPassword
from refinery.lib.inno.emulator import InnoSetupEmulator
from refinery.lib.inno.ifps import IFPSFile


class innopwd(Unit):
    """
    This unit emulates an InnoSetup installer in an attempt to determine the installer password.
    This works only when the password is contained within the script, but several malware samples
    are known to use this technique.
    """
    def process(self, data: bytearray):
        if data.startswith(IFPSFile.Magic):
            inno = IFPSFile(data)
            self.log_info('running in script-only mode; cannot check passwords')
            can_check = False
        else:
            inno = InnoArchive(data, self)
            file = min(inno.files, key=lambda f: (not f.encrypted, f.size))
            if not file.encrypted:
                self.log_info('the archive is not password-protected, password is empty')
                return None
            self.log_info('password type:', file.password_type.name)
            self.log_info('password hash:', file.password_hash)
            self.log_info('password salt:', file.password_salt)
            can_check = True

        iemu = InnoSetupEmulator(inno)
        iemu.emulate_installation()

        for password in iemu.passwords:
            if can_check:
                try:
                    inno.read_chunk(file, password, check_only=True)
                except InvalidPassword:
                    self.log_info('discarding password:', password)
                    continue
            yield password.encode(self.codec)
            if can_check:
                break

    @classmethod
    def handles(self, data):
        import re
        if data[:2] != B'MZ':
            return False
        if re.search(re.escape(InnoArchive.ChunkPrefix), data) is None:
            return False
        return bool(
            re.search(BR'Inno Setup Setup Data \(\d+\.\d+\.', data))

Classes

class innopwd

This unit emulates an InnoSetup installer in an attempt to determine the installer password. This works only when the password is contained within the script, but several malware samples are known to use this technique.

Expand source code Browse git
class innopwd(Unit):
    """
    This unit emulates an InnoSetup installer in an attempt to determine the installer password.
    This works only when the password is contained within the script, but several malware samples
    are known to use this technique.
    """
    def process(self, data: bytearray):
        if data.startswith(IFPSFile.Magic):
            inno = IFPSFile(data)
            self.log_info('running in script-only mode; cannot check passwords')
            can_check = False
        else:
            inno = InnoArchive(data, self)
            file = min(inno.files, key=lambda f: (not f.encrypted, f.size))
            if not file.encrypted:
                self.log_info('the archive is not password-protected, password is empty')
                return None
            self.log_info('password type:', file.password_type.name)
            self.log_info('password hash:', file.password_hash)
            self.log_info('password salt:', file.password_salt)
            can_check = True

        iemu = InnoSetupEmulator(inno)
        iemu.emulate_installation()

        for password in iemu.passwords:
            if can_check:
                try:
                    inno.read_chunk(file, password, check_only=True)
                except InvalidPassword:
                    self.log_info('discarding password:', password)
                    continue
            yield password.encode(self.codec)
            if can_check:
                break

    @classmethod
    def handles(self, data):
        import re
        if data[:2] != B'MZ':
            return False
        if re.search(re.escape(InnoArchive.ChunkPrefix), data) is None:
            return False
        return bool(
            re.search(BR'Inno Setup Setup Data \(\d+\.\d+\.', data))

Ancestors

Class variables

var required_dependencies
var optional_dependencies

Inherited members