# Analysis object (analysis)

analysis: Analysis

  scripts run inside the Script editor have access to the current analysis result via the `analysis` global variable.

The `malcat.Analysis` class is the entry point of Malcat’s scripting interface. It contains the analysis results for a single file/project. You have access to all of the specialized analyses as well as to the raw file using the File object (analysis.file).

## The Analysis object

class malcat.Analysis

  ### Attributes

  architecture: malcat.Architecture

    The main CPU architecture of the file (only set for programs). This property can be overriden, disabling the automatic file type detection. Note that changing it will also invalidate all previous computations (like a call to `invalidate()`). Setting it to `malcat.Architecture.None` will re-enable the automatic CPU architecture detection.

        a = malcat.analyse("/the/file")

        a.architecture = malcat.FileType.Architecture.X86
        # this is likely to impact a lot of analyses, so evtg was invalidated. re-run all analyses.
        a.run()

  type: str

    The file type as a short string, e.g. “PE”. This comes from the parser’s `FileTypeAnalyzer.name` attribute. This property can be overriden, disabling the automatic file type detection. Note that changing it will also invalidate all previous computations (like a call to `invalidate()`). Setting it to the empty string (`""`) will re-enable the automatic type detection.

        a = malcat.analyse("/the/file")

        a.type = "PE"
        # this is likely to impact a lot of analyses, so evtg was invalidated. re-run all analyses.
        a.run()

  category: malcat.FileType.Category

    The category of the identified file type. This comes from the parser’s `FileTypeAnalyzer.category` attribute.

  imagebase: int

    The virtual address at which the file should be loaded

  entrypoint: int

    The effective address of the entrypoint if any, or None

  metadata: Dict[str, Dict[str, str]]

    The file metadata, as extracted from the File parsers. This is what you see in the Summary view. Metadata are str->str associations sorted into categories (the first dictionnary keys).

  file: malcat.File

    A pointer to the File object (analysis.file).

  history: malcat.UndoRedoManager

    A pointer to the undo/redo list manager for this analysis.

  ### Error management

  ok: bool

    True if the analysis ran without error

  failed: bool

    True if there was an error (analysis result is only partially valid, better to just discard evtg)

  log: List[AnalysisError]

    the complete list of all errors/warning that took place during the last run

  raise_if_failed()

    if the analysis failed (`failed` is `True`), throws a `ValueError` with the most recent error (i.e everything beside `malcat.AnalysisError.Status.WARNING`) seen

  ### Access to annotations / sub-analyses

  entropy: malcat.Entropy

    A pointer to the File entropy (analysis.entropy).

  map: malcat.MappingAnnotation

    A pointer to the Address mapping (analysis.map).

  struct: malcat.FileStructure

    A pointer to the File structures (analysis.struct).

  asm: malcat.Asm

    A pointer to the Disassembly (analysis.asm).

  cfg: malcat.CFG

    A pointer to the Control Flow Graph (analysis.cfg).

  loops: malcat.Loops

    A pointer to the Strongly Connected Components (analysis.loops).

  fns: malcat.Functions

    A pointer to the Functions (analysis.fns).

  strings: malcat.Strings

    A pointer to the Strings (analysis.strings).

  xrefs: malcat.CrossReferences

    A pointer to the Cross References (analysis.xrefs).

  syms: malcat.Symbols

    A pointer to the Symbols (analysis.syms).

  sigs: malcat.Signatures

    A pointer to the Yara signatures (analysis.sigs).

  constants: malcat.Constants

    A pointer to the Known constants (analysis.constants).

  carved: malcat.SubFiles

    A pointer to the Carved files (analysis.carved).

  vfiles: List[malcat.VirtualFile]

    The list of virtual files identified by the File parsers.

  anomalies: malcat.Anomalies

    A pointer to the Anomalies (analysis.anomalies).

  comments: malcat.UserComments

    A pointer to the User comments (analysis.comments).

  highlights: malcat.UserHighlights

    A pointer to the User highlighted regions (analysis.highlights).

  parser: malcat.FileTypeAnalyzer

    A pointer to the parser that was used to parse the file format, cf. Writing new parsers.

  ### Kesakode

  kesakode: malcat.KesakodeResult

    A pointer to the last Kesakode result. This will be the result of the offline kesakode by default (note that this is not available in headless mode), but will be overriden by the most recent online query result if you chose to perform one.

  kesakode_quota(license, endpoint='https://cloud.malcat.fr', ssl_verify=True)

    Queries the Kesakode server specified by endpoint about the remaining quota for the given license key. Doesn’t consume any token. Note that you need to specify the license key since Malcat may not know your license key (e.g. if activated using Offline activation).

    Parameters:

      - license (str) – the Malcat or Kesakode license key that you want to know the quota of.

      - endpoint (str) – which Kesakode endpoint to use

      - ssl_verify (bool) – enforce SSL certificate validity. Set this to false if your company does HTTPS mitm.

    Returns:

      (#calls left for this month, #calls allowed per month)

    Return type:

      (int, int)

  kesakode_lookup(license, endpoint='https://cloud.malcat.fr', ssl_verify=True)

    Performs an online Kesakode lookup query on the current file and get the result back. Consumes one token. Note that you need to specify the license key since Malcat may not know your license key (e.g. if activated using Offline activation). The result is returned and will be available via the `kesakode` attribute.

    Parameters:

      - license (str) – your Malcat license key, or your special keskakode key if you’ve got one with more quota.

      - endpoint (str) – which Kesakode endpoint to use

      - ssl_verify (bool) – enforce SSL certificate validity. Set this to false if your company does HTTPS mitm.

    Returns:

      the Kesakode lookup result: global verdict and function/strings match details

    Return type:

      malcat.KesakodeResult

  ### Computation

  run()

    Some edit operations in Malcat (e.g. `malcat.Functions.force()`) invalidate one ore several sub-analyses. The whole analysis result can also be invalidated manually using `invalidate()`.

    This function re-runs all invalidated/dirty sub-analyses. This call is blocking and can take some time.

    Note

    If you Run a script from the user interface, you don’t have to call this function since the UI will do it for you at the end of your script

    Warning

    This will invalidate all Malcat objects (functions, instructions, etc) that were obtained from the previous state of the analysis. If you keep using them after this call, this could lead to undefined behavior / crashes.

  invalidate()

    Tag all analyses as dirty and needing recomputation. The recomputation can then be triggered via `run()`.

        a = malcat.analyse("/the/file")

        # modify the file
        a.file[10:200] = b"\x00" * 190

        # we don't know what we have modified, so re-run all analyses
        a.invalidate()
        a.run()

        # the different sub-analyses know reflect the new state of the file

  ### I/O

  save(project_file_path)

    Save any user modifications to a Malcat project file (usually ending with a .malcat extension). User modifications include changed flags, user comments, highlighted regions, user labels, forced function starts, etc.

        a = malcat.analyse("/the/file")

        # make some modifications to the analysis
        a.comments[a.p2a(0x100)] = "a comment"

        # save the project
        if a.save("/the/file.malcat"):
            print("changes were saved and will be loaded by the UI")

    Parameters:

      project_file_path (str) – the destination path for the project file. If you wan the UI to load it automatically, it should be `<path of the file>.malcat`.

    Raises:

      RuntimeError – if something went wrong during the save

    Return type:

      bool

    Note

    Everything except the file data is saved. You can save any modification made to the file using `malcat.File.save()`.

  load(project_file_path)

    Load any user modifications from a Malcat project file (usually ending with a .malcat extension). User modifications include changed flags, user comments, highlighted regions, user labels, forced function starts, etc. After loading, the whole analysis is automatically invalidated. Call `run()`

        a = malcat.analyse("/the/file")
        if a.load("/the/file.malcat"):
            print("user changes loaded")
        a.run() # rerun the analysis

    Parameters:

      project_file_path (str) – the path of the project file.

    Raises:

      RuntimeError – if something went wrong during the save

    Return type:

      bool

  ### Helpers

  decompile()

    Decompile whole file, either all functions for machine code, or source script for autoit, vba, excel, etc

    Return type:

      str

  ppa(ea, resolve=True, interactive=False)

    Format the given effective address using the best string representation. If the effective address lies in memory, its virtuall address will be returned (prefixed with `0x`), otherwise its file offset will be returned (prefixed with `#`).

        address = analysis.p2a(0x1000)
        print(analysis.ppa(address, resolve=True))

        # if you run the script from the UI and use gui.print, you can make clickable addresses like this
        gui.print("Click here to go to {}".format(analysis.ppa(address, interactive=True)))

    Parameters:

      - ea (int) – effective address to print

      - resolve (bool) –

        if True, the function will append additional context to the address, e.g.:

        - `(sub_401c4e + 1e)` if the address lies within a function

        - `(<Optional header> + 3c)` if the address lies within a structure

        - `(.section0 + 123c)` if the address lies within a section

      - interactive (bool) – if True, the address will be encosed in markers to make it clickable when printed via `malcat.UI.print()`.

    Return type:

      str

  p2a(offset)

    converts a file offset to an effective address. Shortcut for `malcat.MappingAnnotation.from_phys()`.

  a2p(effective_address)

    converts an effective address to a file offset. Shortcut for `malcat.MappingAnnotation.to_phys()`.

  v2a(virtual_address)

    converts a virtual address to an effective address. Shortcut for `malcat.MappingAnnotation.from_virt()`.

  a2v(effective_address)

    converts an effective address to a virtual address. Shortcut for `malcat.MappingAnnotation.to_virt()`.

  r2a(rva)

    converts a Relative Virtual Address to an effective address. Shortcut for `malcat.MappingAnnotation.from_rva()`.

  a2r(effective_address)

    converts an effective address to a virtual address. Shortcut for `malcat.MappingAnnotation.to_rva()`.

  hex(start, end, exclude_off=False, exclude_disp=False, exclude_reg=False, exclude_imm=False)

    Get the masked out hex bytes at [start,end[ e.g. `558BEC68????????8374??45..`

    Parameters:

      - start (int) – the effective addres of the first byte you want

      - end (int) – the effective addres of the first byte you do not want (i.e. address of last byte + 1)

      - exclude_off (bool) – exclude absolute offsets in valid instructions, e.g. `mov eax, off_15bf34`

      - exclude_disp (bool) – exclude displacements in valid instructions, e.g. `mov eax, [ecx+128]`

      - exclude_reg (bool) – exclude registers in valid instructions, e.g. `push eax`

      - exclude_imm (bool) – exclude immediates in valid instructions, e.g. `mov eax, 0x1223`

    Return type:

      str

  open_vfile(path, password='')

    Helper method to open a virtual file by path. Will return the first vfile found with the given path, or raise an error.

        import hashlib
        vf = analysis.open_vfile("DLG/REPLACEFILEDLG/uk-ua")
        print(hashlib.sha256(vf[:]).hexdigest())

    Parameters:

      - path (str) – the path of the virtual file to open, e.g. “DLG/REPLACEFILEDLG/uk-ua”

      - password (str) – password, in case the archive is password-protected

    Return type:

      malcat.File

### Errors

The `malcat.Analysis.last_error` and `malcat.Analysis.log` attributes both manipulate error objects, which are defined below:

class malcat.AnalysisError

  This class describes an error that took place during analysis

  severity: malcat.AnalysisError.Status

    The severity of the error (see below)

  module: int

    A unique identifier for the sub-analysis module at fault (or 0 if none)

  msg: str

    An explicative error message

  __repr__()

    Error pretty printing

    Return type:

      str

class malcat.AnalysisError.Status
  WARNING

    A warning: something was unusual, but analysis could continue

  ERROR

    An error: something unexepected happened that did prevent the analysis to continue

  SETUP

    An error happened during the analysis setup phase taht prevented the analysis to start at all

  MISSING

    Malcat is missing one dependency (an analysis engine, a library): no result at all

  CRASH

    One of Malcat’s analyses unexpectly crashed. Analysis result is only partial at best

### Category enum

The `malcat.Analysis.category` attribute is an enum which can take the following values:

class FileType.Category

  This enum describes the type/category of the analyzed file. I can has one of the following values:

  UNKNOWN

    No file type could be infered, i.e the file was rejected by all parsers

  PROGRAM

    The file a an executable program (PE, ELF, NSIS script, etc.)

  IMAGE

    The file is an image

  SOUND

    The file is a sound file format

  DOCUMENT

    The file is a document, e.g. an Excel stylesheet

  ARCHIVE

    The file is an archive, e.g. zip or rar

  FILESYSTEM

    The file is a filesystem, e.g. a SquashFS container or a FAT32 image

  DATABASE

    The file is a database, e.g. a SQlite file

### CPU architectures enum

The `malcat.Analysis.architecture` attribute is an enum which can take the following values:

class malcat.Architecture

  This enum describes the main CPU architecture that should be used to interpret the code portion of the file (if any). Note that some file types main contain code for more than one architecture, e.g. Visual Basic Pcode + x86.

  NONE
  X86
  X64
  DOTNET
  PCODE

    Visual Basic Pcode

  AU3

    AutoIt tokens

  BIFF

    Biff8 or Biff12 Excel stylesheet. Stylesheets can contain bytcode formulas, thus the architecture.

  PY36
  PY37
  PY38
  PY39
  PY310
  NSIS

    The NSIS virtual machines is used in the setup scripts of NSIS installers

  PASCALSCRIPT

    Pascalscript is a special VM-based language used in InnoSetup installers

  MSI

    Tells Malcat to parse MSI tables

  VBA

    Tells Malcat to use the VBA decompiler

## Undo/redo manager

Each edit operations in Malcat (e.g. a file write, a new comment or a forced function start) is saved into the list of undoed operations. This list is programmatically available through the `Analysis.history` parameter.

### Undo/redo manager

class malcat.UndoRedoManager

  This class allows you to interact with Malcat’s undo/redo functionnalities for a particular analysis.

  __iter__()

    Iterate over all the undoable operations for this analysis

        for undoable_op in analysis.history:
            print(f"{undoable_op} done at {analysis.ppa(undoable_op.address)}")

    Return type:

      iterator over `UndoableOperation`

  __len__()

    return the number of undoable operations

        if len(analysis.history) == 0:
            raise ValueError("No user edit so far")

    Return type:

      int

  undo()

    undo the last undoable edit operation. Returns falls if nothing can be undone or an error happened

    Return type:

      bool

  undo_all()

    undo all edit operations. Returns true iff no error.

    Return type:

      bool

  redo()

    redo the next redoable edit operation. Returns falls if nothing can be redone or an error happened

    Return type:

      bool

  record(bool enable)

    enable or disable recording subsequent edit operations inside this undo/redo manager

        analysis.history.record(False)
        # ... add your comments, they won't appear in the undo list
        for i in range(malcat.map.end):
             malcat.comments[i] = "..."
        # ... reactivate undo/redo
        analysis.history.record(True)

    Parameters:

      enable (bool) – if True, edit operations for this analysis will be saved inside the undo/redo manager

  group()

    context manager that will group all edit operations in a single undoable operation

        with analysis.history.group()
            # ... add your comments
            for i in range(malcat.map.end):
                 analysis.comments[i] = "..."
        analysis.history.undo()     # <-- will undo all comments in one go

### Undoable operation

Edits which can be undone (which is currently all edits supported by Malcat) are represented in the undo/redo manager by a `UndoableOperation` instance, defined below:

class malcat.UndoableOperation

  An user edit targetting this analysis which can be undo

  address: int (effective address)

    the (first) address where the edit took place

  size: int

    the number of bytes affected by the edit

  label: str

    the content of the comment. May contains newlines.

  __repr__()

    return the value of the `label` property

    Return type:

      str

  __len__()

    return the value of the `size` property

    Return type:

      int