[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/pnfsoftware/jeb-samplecode/master/scripts/DecompileFile.py [Back]  [Original]

#?description=Decompile a file provided to JEB
#?shortcut=
import getopt
import os
import sys
import time
from com.pnfsoftware.jeb.util.io import IO
from com.pnfsoftware.jeb.util.logging import GlobalLog
from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
from com.pnfsoftware.jeb.core.units import INativeCodeUnit, UnitUtil
from com.pnfsoftware.jeb.core.units.code import ICodeUnit, ICodeItem
from com.pnfsoftware.jeb.core.output.text import ITextDocument
from com.pnfsoftware.jeb.core.util import DecompilerHelper
from com.pnfsoftware.jeb.core.units.code.asm.decompiler import INativeSourceUnit
from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, DexDecompilerExporter
from com.pnfsoftware.jeb.core.output.text import TextDocumentUtil
"""
Sample script for JEB Decompiler.
- This script decompiles some or all code units of the project
- If run on the command line, the provided input file will be analyzed
- It makes use of the 'decompiler exporter' objects to provide fast decompilation.

How to run & options: see usage() below.

For additional details, refer to:
https://www.pnfsoftware.com/jeb/manual/faq/#can-i-execute-a-jeb-python-script-from-the-command-line
"""
class DecompileFile:
  # IMPORTANT NOTE (JEB >=5.40): Notice that this script class does not inherit IScript!
  #
  # to allow running the script with "Java Embedded Python" instead of Jython
  # - advantage: you get to use your cpython (modern Python 3)
  # - drawback: you cannot create sub-classes of JEB types
  #
  # if your script requires the creation of sub-types of JEB types, you have two options:
  # - have your script extend IScript and revert to using Jython
  # - or write a full-blown plugin in Java
  #
  # The same thing applies to the majority of the sample scripts in this repository.

  def usage(self):
    print('''DecompileFile.py -- demo how to use JEB to decompile code for automation purposes.

How to run:
  $  -c --script=DecompileFile.py -- [options] INPUT_FILE OUTPUT_DIR

Options:
  -h            : display help and exit
  -v            : increase verbosity
  --mtimeout=T  : decompilation timeout for individual methods, in seconds
  --decompile=L : comma-separated list of targets to decompile, e.g. 'dalvik,arm64'
                  Supported targets:
                  dalvik    : decompile x86 32-bit code
                  x86       : decompile x86 32-bit code
                  x64       : decompile x86 64-bit code
                  arm       : decompile Arm code
                  arm64     : decompile Arm 64-bit (aarch64) code
                  all       : decompile all code decompilable by your JEB instance
    ''')
    return


  def run(self, ctx):
    # for messages issued by JEB, limit ourselves to warn and above
    GlobalLog.setCutoffLevel(GlobalLog.LEVEL_WARN);

    self.ctx = ctx

    self.verbose = False
    self.inputFile = None
    self.inputDir = None
    self.method_timeout = -1
    self.decomp_dalvik = False
    self.decomp_x86 = False
    self.decomp_x64 = False
    self.decomp_arm = False
    self.decomp_arm64 = False
    self.decomp_all = False

    args = ctx.getArguments()
    iarg = 0
    for arg in args:
      if not arg.startswith('-'):
        break
      if arg == '-h':
        self.usage()
        return
      elif arg == '-v':
        self.verbose = True
      elif arg.startswith('--mtimeout='):
        self.method_timeout = int(arg[11:])
      elif arg.startswith('--decompile='):
        for elt in arg[12:].split(','):
          elt = elt.strip().lower()
          if elt in ('dalvik', 'dex'):
            self.decomp_dalvik = True
          elif elt == 'x86':
            self.decomp_x86 = True
          elif elt in ('x64', 'x86_64', 'x86-64', 'amd64'):
            self.decomp_x64 = True
          elif elt == 'arm':
            self.decomp_arm = True
          elif elt in ('arm64', 'aarch64'):
            self.decomp_x64 = True
          elif elt == 'all':
            self.decomp_all = True
          else:
            print('Unknown processor for decompilation: %s' % elt)
            self.usage()
            return
      else:
        print('Unknown option: %s' % arg)
        self.usage()
        return
      iarg += 1

    if iarg >= len(args):
        print('Provide an input file')
        return
    self.inputFile = args[iarg]
    iarg += 1

    if iarg >= len(args):
        print('Provide the output folder')
        return
    self.outputDir = args[iarg]
    iarg += 1

    if self.method_timeout: print('Method decompilation timeout: %ds' % self.method_timeout)
    if self.decomp_all: print('Decompiling all')
    if self.decomp_dalvik: print('Decompiling Dalvik')
    if self.decomp_x86: print('Decompiling x86')
    if self.decomp_x64: print('Decompiling x64')
    if self.decomp_arm: print('Decompiling Arm')
    if self.decomp_arm64: print('Decompiling Arm64')

    print('Processing file: %s...' % self.inputFile)
    ctx.open(self.inputFile)

    prj = ctx.getMainProject()
    assert prj, 'Need a project'

    t0 = time.time()
    for codeUnit in prj.findUnits(ICodeUnit):
      self.decompileCodeUnit(codeUnit)

    exectime = time.time() - t0
    print('Exectime: %f' % exectime)


  def decompileCodeUnit(self, codeUnit):
    upath = UnitUtil.buildFullyQualifiedUnitPath(codeUnit)

    proceed = False
    if self.decomp_all:
      proceed = True
    elif isinstance(codeUnit, IDexUnit) and self.decomp_dalvik:
      proceed = True
    elif isinstance(codeUnit, INativeCodeUnit):
      procname = codeUnit.getProcessorName()
      if procname == 'x86' and self.decomp_x86:
        proceed = True
      elif procname == 'x86_64' and self.decomp_x64:
        proceed = True
      elif procname == 'arm' and self.decomp_arm:
        proceed = True
      elif procname == 'arm64' and self.decomp_arm64:
        proceed = True
    if not proceed:
      print('Skipping code: filtered out: %s' % upath)
      return

    # make sure the code unit is processed
    if not codeUnit.isProcessed():
      if not codeUnit.process():
        print('Skipping code: cannot be processed: %s' % upath)
        return

    decomp = DecompilerHelper.getDecompiler(codeUnit)
    if not decomp:
      print('Skipping code: no decompiler available: %s' % upath)
      return

    print('Decompiling code: %s' % upath)

    outdir = os.path.join(self.outputDir, UnitUtil.buildFullyQualifiedUnitPath(codeUnit, True, '_').replace(' ', '-'))
    print('Output folder: %s' % outdir)  # created only if necessary, i.e. some contents was exported

    # DecompilerExporter object
    exp = decomp.getExporter()

    exp.setOutputFolder(IO.createFolder(outdir))

    if self.method_timeout > 0:
      exp.setMethodTimeout(self.method_timeout * 1000)
    #if ...
    #  exp.setTotalTimeout(...)
    if self.verbose:
      exp.setCallback(DecompilerHelper.createProgressLogger())

    # decompile & export
    if not exp.export():
      cnt = len(exp.getErrors())
      i = 1
      for sig, err in exp.getErrors().items():
        print('%d/%d DECOMPILATION ERROR: METHOD %s: %s' % (i, cnt, sig, err))
        i += 1

Web Proxy Viewer  |  New URL  |  Original Page