examineMethodResult(long reqid, IDImm result) {
38 | logger.info("IR: examineMethodResult: id=%d: ret=%s", reqid, result);
39 | // TODO: add custom code
40 | return null;
41 | }
42 | });
43 | }
44 | return 0;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/plugins/scripts/DOptEmuSandboxHooksExample.py:
--------------------------------------------------------------------------------
1 | from com.pnfsoftware.jeb.core.units.code.android.ir import AbstractDOptimizer, IDSandboxHooks
2 | from com.pnfsoftware.jeb.util.base import Wrapper
3 | '''
4 | dexdec IR plugin showing how to set up an emulator sandbox hooks for external methods.
5 | The plugin below is an IR optimizer repeatedly invoked during the IR optimization phase of decompilation.
6 | API reference: see IDSandboxHooks
7 | '''
8 | class DOptEmuSandboxHooksExample(AbstractDOptimizer):
9 | def perform(self):
10 | # retrieve or create the current decompiler thread emulator
11 | emu = self.g.getEmulator()
12 | # create and register a hooks object
13 | # in this sample code, the emulator's sandbox will hooks field accesses to
14 | # android.os.Build.VERSION and provide an alternate value (27) to the caller
15 | hooks_id = emu.registerSandboxHooks(SandboxHooks(emu))
16 | try:
17 | # do some work using the emulator
18 | # when/if the sandbox executes external dex methods, the hooks routines will be called
19 | pass
20 | finally:
21 | assert emu.unregisterSandboxHooks(hooks_id)
22 |
23 | # alternatively, you may want to set up global hooks to customize how other optimizers do their work
24 | # in this case, you want to make sure to not re-register the same hooks every time this optimizer is called
25 | # and also not unregister the hooks object when done
26 | '''
27 | emu = self.g.getEmulator()
28 | if not emu.getData('sandboxHooksSet'):
29 | emu.setData('sandboxHooksSet', True)
30 | emu.registerSandboxHooks(SandboxHooks(emu))
31 | '''
32 | return 0
33 |
34 | class SandboxHooks(IDSandboxHooks):
35 | def __init__(self, emu):
36 | self.emu = emu
37 |
38 | def getField(reqid, addr, fsig, obj):
39 | if fsig == 'Landroid/os/Build$VERSION;->SDK_INT:I':
40 | # force-return the Android Oreo API level
41 | return Wrapper.wrap(27)
42 | return None
43 |
44 | # additional hook methods (for field setting, post-access checks, method invocation,
45 | # object construction, class loading) can be implemented: refer to IDSandboxHooks
46 | # in the API reference documentation
--------------------------------------------------------------------------------
/plugins/scripts/DOptEvalFolder.java:
--------------------------------------------------------------------------------
1 | import com.pnfsoftware.jeb.core.units.code.android.controlflow.BasicBlock;
2 | import com.pnfsoftware.jeb.core.units.code.android.ir.AbstractDOptimizer;
3 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDExpression;
4 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDImm;
5 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDInstruction;
6 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDOperation;
7 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDPredicate;
8 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDVisitor;
9 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.IVisitResults;
10 |
11 | /**
12 | * (NOTE: Sample IR optimizer plugin for JEB's dexdec. A variant of this plugin is shipping as a dexdec built-in.
13 | * As such, there is no need to enable this sample as it is. Its goal is to showcase parts of dexdec IR API for
14 | * learning and experimental purposes.)
15 | *
16 | * Simple expression evaluator and folder.
17 | *
18 | * Example:
19 | *
20 | *
21 | * 4 + 5 => 9
22 | * 1 & 6 => 0
23 | * ...
24 | *
25 | *
26 | *
27 | * Note: this source file is a sample IR optimizer for JEB's dexdec. A variant of this optimizer is
28 | * already shipping with dexdec as a built-in optimizer.
29 | *
30 | * @author Nicolas Falliere
31 | *
32 | */
33 | public class DOptEvalFolder extends AbstractDOptimizer {
34 | private int totalcnt = 0;
35 |
36 | @Override
37 | public int perform() {
38 | totalcnt = 0;
39 |
40 | for(BasicBlock b: cfg) {
41 | for(IDInstruction insn: b) {
42 | insn.visitInstruction(new IDVisitor() {
43 | @Override
44 | public void process(IDExpression e, IDExpression parent, IVisitResults results) {
45 | if(e instanceof IDOperation) {
46 | IDExpression repl = null;
47 | try {
48 | IDImm cst = e.evaluate(ctx);
49 | if(cst != null && !cst.isRef()) {
50 | // IDPredicate (type inhering IDOperation) need special handling to be replaced
51 | if(e instanceof IDPredicate) {
52 | repl = g.createPredicate(cst);
53 | // we may have created an IR identical to the source, watch for this
54 | if(repl.equalsEx(e, false)) {
55 | repl = null;
56 | }
57 | }
58 | else {
59 | repl = cst;
60 | }
61 | if(repl != null && parent.replaceSubExpression(e, repl)) {
62 | results.setReplacedNode(repl);
63 | totalcnt++;
64 | }
65 | }
66 | }
67 | catch(Exception ex0) {
68 | // neuter eval() exceptions
69 | }
70 | }
71 | }
72 | }, true);
73 | }
74 | }
75 |
76 | if(totalcnt > 0) {
77 | // just in case, since some expressions containing variables may have been reduced, example: 0*x => 0 (-> x is no longer used)
78 | cfg.invalidateDataFlowAnalysis();
79 | }
80 | return totalcnt;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/plugins/scripts/DOptRemoveNops.java:
--------------------------------------------------------------------------------
1 | import com.pnfsoftware.jeb.core.units.code.android.controlflow.BasicBlock;
2 | import com.pnfsoftware.jeb.core.units.code.android.ir.AbstractDOptimizer;
3 | import com.pnfsoftware.jeb.core.units.code.android.ir.DOpcodeType;
4 | import com.pnfsoftware.jeb.core.units.code.android.ir.DUtil;
5 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDInstruction;
6 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDSwitchData;
7 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDTarget;
8 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDTryData;
9 |
10 | /**
11 | * (NOTE: Sample IR optimizer plugin for JEB's dexdec. A variant of this plugin is shipping as a dexdec built-in.
12 | * As such, there is no need to enable this sample as it is. Its goal is to showcase parts of dexdec IR API for
13 | * learning and experimental purposes.)
14 | *
15 | * Remove NOP assignments. Blocks made entirely of nops are removed as well.
16 | *
17 | * Note: this source file is a sample IR optimizer for JEB's dexdec. A variant of this optimizer is
18 | * already shipping with dexdec as a built-in optimizer.
19 | *
20 | * @author Nicolas Falliere
21 | *
22 | */
23 | public class DOptRemoveNops extends AbstractDOptimizer {
24 |
25 | @Override
26 | public int perform() {
27 | IDTryData exdata = ctx.getExceptionData();
28 | int cnt = 0;
29 |
30 | // nop removal in multi-instruction blocks, never end-up with empty blocks (no block deletion)
31 | // (i.e., at most, reduce the entire block to a single nop)
32 | if(true) {
33 | for(BasicBlock b: cfg) {
34 | int i = 0;
35 | while(i < b.size()) {
36 | if(b.size() >= 2 && b.get(i).getOpcode() == DOpcodeType.IR_NOP) {
37 | cnt++;
38 | if(DUtil.removeInstruction(b, i)) {
39 | continue;
40 | }
41 | }
42 | i++;
43 | }
44 | }
45 | }
46 |
47 | // nop block removal: since it takes place after the above, those blocks would have been reduced to a single-instruction NOP
48 | // caveat: to keep things simple, we bail if the fall-through block is a handler
49 | int i = 0;
50 | while(i < cfg.size()) {
51 | BasicBlock b = cfg.get(i);
52 | if(b.size() != 1) {
53 | i++;
54 | continue;
55 | }
56 |
57 | // single-instruction NOP block
58 | IDInstruction insn = b.getLast();
59 | if(insn.getOpcode() != DOpcodeType.IR_NOP) {
60 | i++;
61 | continue;
62 | }
63 |
64 | // we will remove the block if the fall-through block is not a handler
65 | BasicBlock b1 = b.getOutputBlock(0);
66 | if(b1.irrinsize() > 0) {
67 | i++;
68 | continue;
69 | }
70 |
71 | cfg.deleteIrregularOutEdges(b);
72 | if(exdata != null) {
73 | exdata.unprotectBlock((int)b.getAddress());
74 | }
75 |
76 | cfg.deleteEdge(b, b1);
77 |
78 | IDInstruction newFirstInsn = b1.get(0);
79 | int oldOffset = (int)newFirstInsn.getOffset();
80 | int newOffset = (int)insn.getOffset();
81 | for(BasicBlock src: b1.getInputBlocks()) {
82 | updateTargets(src.getLast(), oldOffset, newOffset);
83 | }
84 |
85 | for(BasicBlock src: b.getInputBlocks()) {
86 | cfg.reconnectEdges(src, b, b1);
87 | cfg.removeDuplicateEdges(src, b1);
88 | }
89 |
90 | for(BasicBlock src: b.getIrregularInputBlocks()) {
91 | cfg.reconnectIrregularEdges(src, b, b1);
92 | }
93 | if(exdata != null) {
94 | exdata.moveProtectedBlock((int)b1.getAddress(), (int)b.getAddress());
95 | }
96 |
97 | newFirstInsn.setOffset(insn.getOffset());
98 | newFirstInsn.adjustSize(insn.getSize());
99 |
100 | cfg.removeBlock(b);
101 |
102 | cnt++;
103 | }
104 |
105 | if(cnt > 0) {
106 | cleanGraph();
107 | cfg.invalidateDataFlowAnalysis();
108 | }
109 | return cnt;
110 | }
111 |
112 | private void updateTargets(IDInstruction insn, int oldOffset, int newOffset) {
113 | if(insn.isJump() || insn.isJcond()) {
114 | int offset = insn.getBranchTarget();
115 | if(offset == oldOffset) {
116 | insn.setBranchTarget(newOffset);
117 | }
118 | }
119 | else if(insn.isSwitch()) {
120 | IDSwitchData data = insn.getSwitchData();
121 | for(IDTarget target: data.getTargets(false)) {
122 | if(target.getOffset() == oldOffset) {
123 | target.setOffset(newOffset);
124 | }
125 | }
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/plugins/scripts/DOptSampleJava.java:
--------------------------------------------------------------------------------
1 | import com.pnfsoftware.jeb.core.Version;
2 | import com.pnfsoftware.jeb.core.units.code.android.ir.AbstractDOptimizer;
3 |
4 | /**
5 | * A sample IR optimizer.
6 | *
7 | * @author Nicolas Falliere
8 | *
9 | */
10 | public class DOptSampleJava extends AbstractDOptimizer {
11 |
12 | public DOptSampleJava() {
13 | super();
14 | }
15 |
16 | @Override
17 | public int perform() {
18 | logger.debug("The optimizer is running");
19 | return 0;
20 | }
21 | }
--------------------------------------------------------------------------------
/plugins/scripts/DOptSamplePython.py:
--------------------------------------------------------------------------------
1 | from com.pnfsoftware.jeb.core.units.code.android.ir import AbstractDOptimizer
2 |
3 | '''
4 | Sample Intermediate Representation (IR) optimizer plugin for dexdec, JEB's DEX/Dalvik Decompiler.
5 |
6 | This Python plugin is executed during the decompilation pipeline of a method.
7 | Needs JEB 4.2 or above.
8 |
9 | NOTE: it is recommended to write non-trivial dexdec IR optimizers in Java
10 |
11 | How to use:
12 | - Drop this file in your JEB's coreplugins/scripts/ sub-directory
13 | - Make sure to have the setting `.LoadPythonPlugins = true` in your JEB's bin/jeb-engines.cfg file
14 |
15 | For additional information regarding dexdec IR optimizer plugins, refer to:
16 | - the Manual (www.pnfsoftware.com/jeb/manual)
17 | - the API documentation: https://www.pnfsoftware.com/jeb/apidoc/reference/com/pnfsoftware/jeb/core/units/code/android/ir/package-summary.html
18 | '''
19 | class DOptSamplePython(AbstractDOptimizer): # note that we extend AbstractDOptimizer for convenience, instead of implementing IDOptimizer from scratch
20 | def __init__(self):
21 | # default super constructor is called, will set the plugin type to NORMAL (see DOptimizerType constant)
22 | self.logger.debug('DexDecIROptimizerSample: instantiated')
23 |
24 | def perform(self):
25 | # commonly needed objects for IR optimizers are provided as attributes AbstractDOptimizer:
26 | # - ctx: the IDMethodContext
27 | # - cfg: the IR CFG (control flow graph)
28 | # - irb: IR element builder
29 | # - tf: a type factory
30 | # - of: an operator factory
31 | # - g: the global IR context, referring to other important decompiler objects
32 | # - dex: the underlying dex file
33 | # ...
34 | # as well as useful methods, such as:
35 | # - cleanGraph(): to be called in structural modifications of teh CFG were made
36 | # - analyzeChains(): to perform DFA (data flow analysis) if data chains are needed by the optimizer
37 | # ...
38 | # and more: refer to the API documentation
39 | #
40 | # another commonly used class by IR optimizers is DUtil, containing many utitily routines to access and manipulate the IR
41 |
42 | # print the IR CFG
43 | self.logger.debug('DexDecIROptimizerSample: executed: %s', self.cfg.format())
44 |
45 | # some random work...
46 | for blk in self.cfg: # BasicBlock (of IDInstruction)
47 | for insn in blk: # IDInstruction
48 | if insn.isJcond():
49 | # we found a JCOND instruction, do something
50 | pass
51 |
52 | # if a value >0 is returned, the decompiler will assume that IR is being transformed and this IR optimizer will be called again
53 | return 0 # no optimization is performed
--------------------------------------------------------------------------------
/plugins/scripts/DOptStringSimplifier.java:
--------------------------------------------------------------------------------
1 | import com.pnfsoftware.jeb.core.units.code.android.controlflow.BasicBlock;
2 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDVisitor;
3 | import com.pnfsoftware.jeb.core.units.code.android.ir.AbstractDOptimizer;
4 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDCallInfo;
5 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDExpression;
6 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDImm;
7 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDInstruction;
8 | import com.pnfsoftware.jeb.core.units.code.android.ir.IDOperation;
9 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.IVisitResults;
10 | import com.pnfsoftware.jeb.core.units.code.java.JavaOperatorType;
11 |
12 | /**
13 | * (NOTE: Sample IR optimizer plugin for JEB's dexdec. A variant of this plugin is shipping as a dexdec built-in.
14 | * As such, there is no need to enable this sample as it is. Its goal is to showcase parts of dexdec IR API for
15 | * learning and experimental purposes.)
16 | *
17 | * Simplify useless calls to {@code String.valueOf}.
18 | *
19 | *
20 | * String.valueOf(some_string)
21 | *
22 | * => (simplified to)
23 | *
24 | * some_string
25 | *
26 | *
27 | * @author Nicolas Falliere
28 | *
29 | */
30 | public class DOptStringSimplifier extends AbstractDOptimizer {
31 | private static final String msig0 = "Ljava/lang/String;->valueOf(Ljava/lang/Object;)Ljava/lang/String;";
32 |
33 | private int totalcnt;
34 |
35 | @Override
36 | public int perform() {
37 | totalcnt = 0;
38 |
39 | for(int iblk = 0; iblk < cfg.size(); iblk++) {
40 | BasicBlock b = cfg.get(iblk);
41 |
42 | for(int i = 0; i < b.size(); i++) {
43 | IDInstruction insn = b.get(i);
44 |
45 | insn.visitDepthPost(new IDVisitor() {
46 | @Override
47 | public void process(IDExpression e, IDExpression parent, IVisitResults results) {
48 | if(e instanceof IDCallInfo && msig0.equals(((IDCallInfo)e).getMethodSignature())) {
49 | IDExpression arg0 = ((IDCallInfo)e).getArgument(0);
50 | boolean proceed = false;
51 | if(arg0 instanceof IDImm && ((IDImm)arg0).isString()) {
52 | proceed = true;
53 | }
54 | else if(arg0 instanceof IDOperation
55 | && ((IDOperation)arg0).getOperator().is(JavaOperatorType.CONCAT)) {
56 | proceed = true;
57 | }
58 | if(arg0 instanceof IDCallInfo
59 | && ((IDCallInfo)arg0).getMethodSignature().endsWith(")Ljava/lang/String;")) {
60 | proceed = true;
61 | }
62 | if(proceed) {
63 | if(parent.replaceSubExpression(e, arg0)) {
64 | totalcnt++;
65 | }
66 | }
67 | }
68 | }
69 | });
70 | }
71 | }
72 |
73 | return totalcnt;
74 | }
75 | }
--------------------------------------------------------------------------------
/plugins/scripts/GarbageCleaner.java:
--------------------------------------------------------------------------------
1 | //?type=gendec-ir
2 | import com.pnfsoftware.jeb.core.units.code.asm.cfg.BasicBlock;
3 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.ir.IEAssign;
4 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.ir.IEGeneric;
5 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.ir.IEImm;
6 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.ir.IEMem;
7 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.ir.IEOperation;
8 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.ir.IEStatement;
9 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.ir.IEVar;
10 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.ir.OperationType;
11 | import com.pnfsoftware.jeb.core.units.code.asm.decompiler.ir.opt.AbstractEOptimizer;
12 | import com.pnfsoftware.jeb.core.units.code.asm.items.INativeContinuousItem;
13 |
14 | /**
15 | * This file is an IR optimizer plugin for JEB's gendec.
16 | * Drop this file in your JEB's coreplugins/scripts/ folder.
17 | *
18 | * This optimizer is a garbage array assigment cleaner.
19 | * Any statement writing an immediate value to a global array
20 | * whose name starts with 'garbage' will be discarded.
21 | */
22 | public class GarbageCleaner extends AbstractEOptimizer {
23 |
24 | @Override
25 | public int perform() {
26 | int cnt = 0;
27 |
28 | for (BasicBlock b : cfg) {
29 | for (int i = 0; i < b.size(); i++) {
30 | IEStatement stm = b.get(i);
31 | if (stm instanceof IEAssign && stm.asAssign().getDstOperand() instanceof IEMem
32 | && stm.asAssign().getSrcOperand() instanceof IEImm) {
33 | IEMem dst = stm.asAssign().getDstOperand().asMem();
34 | IEGeneric e = dst.getReference();
35 | // [xxx + offset] = immediate
36 | if (e.isOperation(OperationType.ADD)) {
37 | IEOperation op = e.asOperation();
38 | if (op.getOperand1().isVar() && op.getOperand2().isImm()) {
39 | IEVar v = op.getOperand1().asVar();
40 | IEImm off = op.getOperand2().asImm();
41 | if (v.isGlobalReference()) {
42 | long addr = v.getAddress();
43 | INativeContinuousItem item = ectx.getNativeContext().getNativeItemAt(addr);
44 | // logger.info("FOUND ITEM %s", item.getName());
45 | if (item != null && item.getName().startsWith("garbage")) {
46 | long itemsize = item.getMemorySize();
47 | if (off.canReadAsLong() && off.getValueAsLong() + dst.getBitsize() / 8 < itemsize) {
48 | logger.info("FOUND GARBAGE CODE");
49 | b.set(i, ectx.createNop(stm));
50 | cnt++;
51 | }
52 | }
53 | }
54 | }
55 | }
56 | }
57 | }
58 | }
59 |
60 | if (cnt > 0) {
61 | cfg.invalidateDataFlowAnalysis();
62 | }
63 | return cnt;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/plugins/scripts/JOptSampleJava.java:
--------------------------------------------------------------------------------
1 | //?type=dexdec-ast
2 | import com.pnfsoftware.jeb.core.Version;
3 | import com.pnfsoftware.jeb.core.units.code.java.AbstractJOptimizer;
4 |
5 | /**
6 | * A sample dexdec AST optimizer plugin. Requires JEB 4.23+.
7 | *
8 | * @author Nicolas Falliere
9 | *
10 | */
11 | public class JOptSampleJava extends AbstractJOptimizer {
12 |
13 | public JOptSampleJava() {
14 | super();
15 | }
16 |
17 | @Override
18 | public int perform() {
19 | //logger.debug("The Java AST optimizer is running");
20 | return 0;
21 | }
22 | }
--------------------------------------------------------------------------------
/plugins/scripts/JOptSamplePython.py:
--------------------------------------------------------------------------------
1 | #?type=dexdec-ast
2 | from com.pnfsoftware.jeb.core.units.code.java import AbstractJOptimizer
3 |
4 | '''
5 | Skeleton for an Java Abstract Syntax Tree (AST) optimizer plugin for dexdec, JEB's DEX/Dalvik Decompiler.
6 | This Python plugin is executed during the decompilation pipeline of a method.
7 |
8 | How to use:
9 | - Drop this file in your JEB's coreplugins/scripts/ sub-directory
10 | - Make sure to have the setting `.LoadPythonPlugins = true` in your JEB's bin/jeb-engines.cfg file
11 |
12 | For additional information regarding dexdec AST optimizer plugins, refer to:
13 | - the Manual (www.pnfsoftware.com/jeb/manual)
14 | - the API documentation: https://www.pnfsoftware.com/jeb/apidoc/reference/com/pnfsoftware/jeb/core/units/code/java/package-summary.html
15 |
16 | Requires JEB 4.23+.
17 | '''
18 | class JOptSamplePython(AbstractJOptimizer):
19 | # note: Python script optimizers are singleton instances!
20 | # the engine will instantiate and provide a single instance for all decompilation threads
21 | # therefore, if you are using object attributes, make sure to provide support for concurrency
22 | # (this restriction does not apply to Java script optimizers, as well as full-blown jar optimizers;
23 | # each decompilation thread has its own unique instance of such optimizer objects)
24 | # for this reason (as well as others), moderately complex AST optimizers should be written in Java
25 |
26 | def __init__(self):
27 | # default super constructor is called, will set the plugin type to NORMAL (see JOptimizerType constant)
28 | self.logger.debug('DexDecASTOptimizerSample: instantiated')
29 |
30 | def perform(self):
31 | # commonly needed objects for AST optimizers are provided as attributes AbstractJOptimizer and sub-classes
32 | # if the optimizer is about to work on a IJavaMethod, the AST method object is in attribute `m`
33 | # if the optimizer is about to work on a IJavaClass, the AST class object is in attribute `c`
34 |
35 | # another commonly used class by IR optimizers is JUtil, containing many utitily routines to access and manipulate the AST
36 | # more: refer to the API documentation
37 |
38 | # UNCOMMENT: message the developer
39 | #self.logger.debug('DexDecASTOptimizerSample: executed')
40 |
41 | # if a value >0 is returned, the decompiler will assume that AST is being transformed and this AST optimizer will be called again
42 | return 0 # no optimization is performed
43 |
--------------------------------------------------------------------------------
/plugins/scripts/README.md:
--------------------------------------------------------------------------------
1 | Sample back-end script plugins (java, python) for JEB.
2 |
3 | Back-end script plugins go in the `coreplugins/scripts/` folder.
4 |
--------------------------------------------------------------------------------
/plugins/src/com/pnf/jebauto/AutoClient.java:
--------------------------------------------------------------------------------
1 | /*
2 | * JEB Copyright PNF Software, Inc.
3 | *
4 | * https://www.pnfsoftware.com
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package com.pnf.jebauto;
20 |
21 | import java.io.File;
22 | import java.util.List;
23 |
24 | import org.apache.commons.configuration2.BaseConfiguration;
25 |
26 | import com.pnfsoftware.jeb.core.Artifact;
27 | import com.pnfsoftware.jeb.core.ICoreContext;
28 | import com.pnfsoftware.jeb.core.IEnginesContext;
29 | import com.pnfsoftware.jeb.core.ILiveArtifact;
30 | import com.pnfsoftware.jeb.core.IRuntimeProject;
31 | import com.pnfsoftware.jeb.core.JebCoreService;
32 | import com.pnfsoftware.jeb.core.dao.IDataProvider;
33 | import com.pnfsoftware.jeb.core.dao.IFileDatabase;
34 | import com.pnfsoftware.jeb.core.dao.IFileStore;
35 | import com.pnfsoftware.jeb.core.dao.impl.DataProvider;
36 | import com.pnfsoftware.jeb.core.dao.impl.JEB2FileDatabase;
37 | import com.pnfsoftware.jeb.core.dao.impl.SimpleFSFileStore;
38 | import com.pnfsoftware.jeb.core.input.FileInput;
39 | import com.pnfsoftware.jeb.core.properties.IConfiguration;
40 | import com.pnfsoftware.jeb.core.properties.impl.CommonsConfigurationWrapper;
41 | import com.pnfsoftware.jeb.core.units.IUnit;
42 | import com.pnfsoftware.jeb.util.logging.GlobalLog;
43 | import com.pnfsoftware.jeb.util.logging.ILogger;
44 |
45 | /**
46 | * Skeleton for a JEB2 headless client (eg, for automation/bulk processing) !! IMPORTANT !! The
47 | * areas marked "TODO: customize" must be edited prior to executing this code
48 | *
49 | * @author Nicolas Falliere
50 | *
51 | */
52 | public class AutoClient {
53 | static final ILogger logger = GlobalLog.getLogger(AutoClient.class);
54 | static {
55 | GlobalLog.addDestinationStream(System.out);
56 | }
57 |
58 | // TODO: customize (should be replaced by the LicenseKey entry in your bin/jeb-client.cfg file)
59 | private static final String licenseKey = "...";
60 |
61 | // TODO: customize
62 | private static final String baseDir = "...";
63 |
64 | public static void main(String[] argv) throws Exception {
65 | if(argv.length <= 0) {
66 | return;
67 | }
68 |
69 | long t0 = System.currentTimeMillis();
70 | String location = argv[0];
71 | List files = AutoUtil.retrieveFiles(location);
72 | test(files);
73 | logger.info("Done in %ds", (System.currentTimeMillis() - t0) / 1000);
74 | }
75 |
76 | /**
77 | * Initialize a core. Create a context within that core. Then, for each input artifact, a
78 | * project is created and the artifact is loaded within that project.
79 | *
80 | * @param files
81 | * @throws Exception
82 | */
83 | public static void test(List files) throws Exception {
84 | // create or retrieve a core context (engines container)
85 | ICoreContext core = JebCoreService.getInstance(licenseKey);
86 |
87 | // create an engines context (project container)
88 | IFileDatabase projectdb = new JEB2FileDatabase(baseDir);
89 | IFileStore filestore = new SimpleFSFileStore(baseDir);
90 | BaseConfiguration cfg = new BaseConfiguration();
91 |
92 | // TODO: customize (alternative is to read your configuration from .cfg file)
93 | cfg.setProperty(".DevPluginClasspath", "...");
94 |
95 | // TODO: customize
96 | cfg.setProperty(".DevPluginClassnames", "...");
97 |
98 | IConfiguration config = new CommonsConfigurationWrapper(cfg);
99 | IDataProvider dataProvider = new DataProvider(null, projectdb, filestore, null, null, config);
100 | IEnginesContext engctx = core.createEnginesContext(dataProvider, null);
101 |
102 | int i = 0;
103 | for(File file: files) {
104 | i++;
105 | logger.info("Testing file %d/%d : %s ...", i, files.size(), file.getName());
106 |
107 | // create or load a project (artifact container)
108 | IRuntimeProject prj = engctx.loadProject("ProjectTest" + i);
109 |
110 | // process the artifact, get units
111 | ILiveArtifact art = prj.processArtifact(new Artifact(file.getName(), new FileInput(file)));
112 |
113 | // proceed with the units
114 | List units = art.getUnits();
115 |
116 | // TODO: CUSTOMIZE -- this is the important part
117 | // Basic tests go here
118 | // example:
119 | for(IUnit unit: units) {
120 | logger.info("Unit: %s", unit);
121 | //if(unit instanceof Xyz) {
122 | // ...
123 | //}
124 | }
125 |
126 | engctx.unloadProject(prj.getKey());
127 | }
128 |
129 | // close the engines
130 | JebCoreService.getInstance().closeEnginesContext(engctx);
131 | }
132 | }
--------------------------------------------------------------------------------
/plugins/src/com/pnf/jebauto/AutoUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * JEB Copyright PNF Software, Inc.
3 | *
4 | * https://www.pnfsoftware.com
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package com.pnf.jebauto;
20 |
21 | import java.io.File;
22 | import java.io.IOException;
23 | import java.util.ArrayList;
24 | import java.util.List;
25 |
26 | import org.apache.commons.configuration2.PropertiesConfiguration;
27 | import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
28 | import org.apache.commons.configuration2.builder.fluent.Parameters;
29 | import org.apache.commons.configuration2.ex.ConfigurationException;
30 |
31 | /**
32 | * Utility methods for headless JEB2 clients.
33 | *
34 | * @author Nicolas Falliere
35 | *
36 | */
37 | public class AutoUtil {
38 |
39 | /**
40 | * List all files recursively.
41 | *
42 | * @param location root directory
43 | * @return a list of files
44 | */
45 | public static List retrieveFiles(String location) {
46 | List results = new ArrayList<>();
47 | retrieveFilesRecurse(new File(location), results);
48 | return results;
49 | }
50 |
51 | private static void retrieveFilesRecurse(File f, List results) {
52 | if(f.isFile()) {
53 | results.add(f);
54 | }
55 | else {
56 | for(String name: f.list()) {
57 | File f1 = new File(f, name);
58 | retrieveFilesRecurse(f1, results);
59 | }
60 | }
61 | }
62 |
63 | /**
64 | * Create an Apache properties object out of a JEB2 configuration file.
65 | *
66 | * @param path path to a JEB2 configuration file, such as jeb-client.cfg or jeb-engines.cfg
67 | * @return
68 | */
69 | public static PropertiesConfiguration createPropertiesConfiguration(String path) {
70 | File configfile = new File(path);
71 |
72 | if(!configfile.isFile()) {
73 | try {
74 | configfile.createNewFile();
75 | }
76 | catch(IOException e) {
77 | throw new RuntimeException(e);
78 | }
79 | }
80 |
81 | Parameters params = new Parameters();
82 | FileBasedConfigurationBuilder builder = new FileBasedConfigurationBuilder<>(
83 | PropertiesConfiguration.class).configure(params.properties().setFileName(path));
84 | builder.setAutoSave(true);
85 |
86 | try {
87 | return builder.getConfiguration();
88 | }
89 | catch(ConfigurationException e) {
90 | throw new RuntimeException(e);
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/plugins/src/com/pnf/plugintest/SampleEnginesPlugin.java:
--------------------------------------------------------------------------------
1 | package com.pnf.plugintest;
2 |
3 | import java.util.List;
4 | import java.util.Map;
5 |
6 | import com.pnfsoftware.jeb.core.IEnginesContext;
7 | import com.pnfsoftware.jeb.core.IEnginesPlugin;
8 | import com.pnfsoftware.jeb.core.IOptionDefinition;
9 | import com.pnfsoftware.jeb.core.IPluginInformation;
10 | import com.pnfsoftware.jeb.core.PluginInformation;
11 | import com.pnfsoftware.jeb.core.Version;
12 | import com.pnfsoftware.jeb.util.logging.GlobalLog;
13 | import com.pnfsoftware.jeb.util.logging.ILogger;
14 |
15 | /**
16 | * Sample plugin.
17 | *
18 | * @author Nicolas Falliere
19 | */
20 | public class SampleEnginesPlugin implements IEnginesPlugin {
21 | private static final ILogger logger = GlobalLog.getLogger(SampleEnginesPlugin.class);
22 |
23 | @Override
24 | public IPluginInformation getPluginInformation() {
25 | return new PluginInformation("Sample Engines Plugin", "A sample JEB back-end plugin", "PNF Software",
26 | Version.create(1, 0, 1));
27 | }
28 |
29 | @Override
30 | public void load(IEnginesContext context) {
31 | logger.info("Sample plugin is loaded");
32 | }
33 |
34 | @Override
35 | public List extends IOptionDefinition> getExecutionOptionDefinitions() {
36 | return null;
37 | }
38 |
39 | @Override
40 | public void execute(IEnginesContext context) {
41 | execute(context, null);
42 | }
43 |
44 | @Override
45 | public void execute(IEnginesContext engctx, Map executionOptions) {
46 | logger.info("Executing sample plugin");
47 | }
48 |
49 | @Override
50 | public void dispose() {
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/plugins/src/com/pnf/pommePlugin/MetaUnit.java:
--------------------------------------------------------------------------------
1 | package com.pnf.pommePlugin;
2 |
3 | import java.util.List;
4 |
5 | import com.pnfsoftware.jeb.core.output.AbstractUnitRepresentation;
6 | import com.pnfsoftware.jeb.core.output.IGenericDocument;
7 | import com.pnfsoftware.jeb.core.output.IUnitDocumentPresentation;
8 | import com.pnfsoftware.jeb.core.output.IUnitFormatter;
9 | import com.pnfsoftware.jeb.core.output.UnitFormatterAdapter;
10 | import com.pnfsoftware.jeb.core.units.AbstractUnit;
11 | import com.pnfsoftware.jeb.core.units.code.ICodeUnit;
12 |
13 | /*
14 | *
15 | * */
16 | public class MetaUnit extends AbstractUnit{
17 |
18 |
19 | private IUnitDocumentPresentation presentation_;
20 |
21 | public MetaUnit(String name, String description, IUnitDocumentPresentation presentation, ICodeUnit codeUnit) {
22 | super(name, description, codeUnit);
23 | presentation_ = presentation;
24 |
25 | }
26 |
27 | @Override
28 | public boolean process() {
29 | setProcessed(true);
30 | return true;
31 | }
32 |
33 | @Override
34 | public IUnitFormatter getFormatter() {
35 | UnitFormatterAdapter adapter = new UnitFormatterAdapter(new AbstractUnitRepresentation("API Use", true) {
36 | public IGenericDocument getDocument() {
37 | return presentation_.getDocument();
38 | }
39 | });
40 | return adapter;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/plugins/src/com/pnf/pommePlugin/PommePlugin.java:
--------------------------------------------------------------------------------
1 | package com.pnf.pommePlugin;
2 |
3 | import java.util.List;
4 | import java.util.Map;
5 |
6 | import com.pnfsoftware.jeb.core.IEnginesContext;
7 | import com.pnfsoftware.jeb.core.IEnginesPlugin;
8 | import com.pnfsoftware.jeb.core.IOptionDefinition;
9 | import com.pnfsoftware.jeb.core.IPluginInformation;
10 | import com.pnfsoftware.jeb.core.IRuntimeProject;
11 | import com.pnfsoftware.jeb.core.PluginInformation;
12 | import com.pnfsoftware.jeb.core.RuntimeProjectUtil;
13 | import com.pnfsoftware.jeb.core.Version;
14 | import com.pnfsoftware.jeb.core.units.INativeCodeUnit;
15 | import com.pnfsoftware.jeb.core.units.code.ICodeUnit;
16 | import com.pnfsoftware.jeb.core.units.code.IInstruction;
17 | import com.pnfsoftware.jeb.util.logging.GlobalLog;
18 | import com.pnfsoftware.jeb.util.logging.ILogger;
19 |
20 |
21 | public class PommePlugin implements IEnginesPlugin {
22 |
23 | private static final ILogger logger = GlobalLog.getLogger(PommePlugin.class);
24 |
25 | @Override
26 | public IPluginInformation getPluginInformation() {
27 |
28 | return new PluginInformation("Pomme Plugin", "Finds API usage in multiple files.", "PNF Software", Version.create(0, 1));
29 | }
30 |
31 | @Override
32 | public void dispose() {
33 | logger.info("Dispose");
34 | }
35 |
36 | @Override
37 | public void execute(IEnginesContext engctx) {
38 |
39 | execute(engctx, null);
40 |
41 | }
42 |
43 | public void execute(IEnginesContext engctx, Map arg1) {
44 |
45 | List projects = engctx.getProjects();
46 | if (projects == null){
47 | logger.info("There is no opened project");
48 | return;
49 |
50 | }
51 | IRuntimeProject prj = projects.get(0);
52 | logger.info("Decompiling code units of %s", prj.toString());
53 |
54 | List codeUnits = RuntimeProjectUtil.findUnitsByType(prj, ICodeUnit.class, false);
55 |
56 | if (codeUnits == null) {
57 |
58 | logger.warn("No code units found.");
59 |
60 | }
61 |
62 | new PommeTask(codeUnits);
63 |
64 | logger.info("Done.");
65 |
66 | }
67 |
68 | public List extends IOptionDefinition> getExecutionOptionDefinitions() {
69 | return null;
70 | }
71 | }
--------------------------------------------------------------------------------
/plugins/src/com/pnf/pommePlugin/functionList.json:
--------------------------------------------------------------------------------
1 | ["cpy", "gets"]
2 |
--------------------------------------------------------------------------------
/scripts/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | .project
3 | .classpath
4 | .pydevproject
5 | temp
--------------------------------------------------------------------------------
/scripts/AdbDemo.py:
--------------------------------------------------------------------------------
1 | #?description=Create and use adb (Android Debug Bridge) wrappers and adb utility objects
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code.android.adb import AdbWrapperFactory, AdbWrapperFactory, AndroidDeviceUtil
5 | """
6 | Sample script for JEB Decompiler.
7 | """
8 | class AdbDemo(IScript):
9 | def run(self, ctx):
10 | # factory object wraps adb, not tied to a specific device
11 | adbf = AdbWrapperFactory() # see javadoc for a list of methods
12 | adbf.initialize()
13 | print('adb version: %s' %adbf.getVersion())
14 |
15 | for dev in adbf.listDevices():
16 | # an AdbWrapper object is tied to a debuggable device
17 | adb = adbf.createWrapper(dev.getSerial())
18 | break
19 | else:
20 | print 'no android device found'
21 | return
22 | print(adb) # see javadoc for a list of methods
23 | #adb.listPackages()
24 | #adb.listProcesses()
25 | #adb.readProperty("ro.build.version.release")
26 | #adb....
27 |
28 | # higher-level wrappers: see AndroidDeviceUtil
29 |
--------------------------------------------------------------------------------
/scripts/AddArtifact.py:
--------------------------------------------------------------------------------
1 | #?description=Add and analyze an additional artifact into an existing project
2 | #?shortcut=
3 | from java.io import File
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core import Artifact
6 | from com.pnfsoftware.jeb.core.input import FileInput
7 | import os
8 | """
9 | Sample script for JEB Decompiler.
10 | """
11 | class AddArtifact(IScript):
12 |
13 | def run(self, ctx):
14 | prj = ctx.getMainProject()
15 | assert prj, 'Need a project'
16 |
17 | path = ctx.displayFileOpenSelector('Select a file to be added to the project')
18 | assert path and os.path.isfile(path), 'Need a valid artifact file path'
19 |
20 | artifactFile = File(path)
21 | a = Artifact(artifactFile.getName(), FileInput(artifactFile))
22 | print('Adding: %s' % a)
23 |
24 | la = prj.processArtifact(a)
25 | print(la)
26 |
--------------------------------------------------------------------------------
/scripts/AddCustomNativeTypes.py:
--------------------------------------------------------------------------------
1 | #?description=Create and add custom native structure types to a project
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units import INativeCodeUnit
5 | from com.pnfsoftware.jeb.core.units.code.asm.type import TypeUtil
6 | """
7 | Sample script for JEB Decompiler.
8 | """
9 | class AddCustomNativeTypes(IScript):
10 | def run(self, ctx):
11 | prj = ctx.getMainProject()
12 | assert prj, 'Need a project'
13 |
14 | unit = prj.findUnit(INativeCodeUnit)
15 | assert unit, 'Need a native code unit'
16 |
17 | print('Will create type for native unit: %s' % unit)
18 | ''' create the following type:
19 | // Size: 10, Padding: 1, Alignment: 1
20 | struct MyStruct1 {
21 | int a;
22 | unsigned char[3][2] b;
23 | };
24 | '''
25 | typeman = unit.getTypeManager()
26 |
27 | # method 1: craft the type manually, using the ITypeManager
28 | tInt = typeman.getType('int')
29 | tS1 = typeman.createStructure('MyStruct1')
30 | typeman.addStructureField(tS1, 'a', tInt)
31 | typeman.addStructureField(tS1, 'b', TypeUtil.buildArrayType(typeman, 'unsigned char', 2, 3))
32 | print('Added type: %s' % tS1)
33 |
34 | # method 2: parse a C-type, using a typeman-provided parser
35 | buf = 'enum SomeEnum {A,B,C};'
36 | tSomeEnum = typeman.getParser().parseTypesRaw(buf)
37 | print('Added type: %s' % tSomeEnum)
38 |
--------------------------------------------------------------------------------
/scripts/AndroidDbgAddAllDex.py:
--------------------------------------------------------------------------------
1 | #?description=Search for DEX units in the project and register them to the current Android debugging session
2 | #?shortcut=
3 | #?deprecated
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
6 | from com.pnfsoftware.jeb.core.units import UnitUtil
7 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDalvikDebuggerUnit
8 | """
9 | Sample script for JEB Decompiler.
10 | """
11 | class AndroidDbgAddAllDex(IScript):
12 | def run(self, ctx):
13 | prj = ctx.getMainProject()
14 | assert prj, 'Need a project'
15 |
16 | dbg = prj.findUnit(IDalvikDebuggerUnit)
17 | assert dbg, 'Need a dalvik debugger'
18 |
19 | dexlist = RuntimeProjectUtil.findUnitsByType(prj, IDexUnit, False)
20 | for dex in dexlist:
21 | if dbg.registerDebuggee(dex):
22 | print('Added to debuggees list: %s', UnitUtil.buildFullyQualifiedUnitPath(dex))
23 |
--------------------------------------------------------------------------------
/scripts/AndroidDbgCreate.py:
--------------------------------------------------------------------------------
1 | #?description=Create a debugger unit for an APK object
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code.android import IApkUnit, IDexUnit
5 | from com.pnfsoftware.jeb.core.units.code.debug.impl import DebuggerSetupInformation
6 | from com.pnfsoftware.jeb.core.util import DebuggerHelper
7 | """
8 | Sample script for JEB Decompiler.
9 | """
10 | class AndroidDbgCreate(IScript):
11 | def run(self, ctx):
12 | prj = ctx.getMainProject()
13 | assert prj, 'Need a project'
14 |
15 | # let's retrieve the primary apk unit loaded in the project, if there is one
16 | apk = prj.findUnit(IApkUnit)
17 | assert apk, 'Need an APK unit'
18 |
19 | # a debugger unit is the child of another unit
20 | dbg = DebuggerHelper.getDebugger(apk, True)
21 | if not dbg:
22 | print 'Cannot create or retrieve debugger'
23 | return
24 |
25 | # after creation, the debugger unit is not attached to any target
26 | print(dbg)
27 |
28 | if not dbg.isAttached():
29 | # we will find a matching compatible target on the devices that can be enumerated by the debugger unit
30 | setup = findTarget(dbg, apk)
31 | if not setup:
32 | print 'Target not found'
33 | return
34 | # UNCOMMENT below to request all threads to be stopped before attaching
35 | #setup.setSuspendThreads(True)
36 | # UNCOMMENT below to allow the creation of a child debugger for APK's native code
37 | #setup.setUseChildrenDebuggers(True)
38 | dbg.attach(setup)
39 |
40 | print 'Debugger found and attached: %s' % dbg
41 |
42 |
43 | def findTarget(dbg, apk):
44 | # here, we use the un-attached debugger unit to enumerate compatible targets,
45 | # enumerate processes on those targets, and find one that matches our apk
46 | # this process may seem convoluted, but keep in mind that IDebuggerUnit are
47 | # not specific to android, they are a generic interface for any type of debugger
48 | te = dbg.getTargetEnumerator()
49 | for m in te.listMachines():
50 | for p in m.getProcesses():
51 | # match by exact package name
52 | if p.getName() == apk.getPackageName():
53 | return DebuggerSetupInformation.create(m, p)
54 | return None
55 |
--------------------------------------------------------------------------------
/scripts/AndroidGlobalAnalysis.py:
--------------------------------------------------------------------------------
1 | #?description=Perform a global analysis on a dex unit and display decompilation events
2 | #?shortcut=
3 |
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core.units.code import DecompilationOptions, DecompilationContext
6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit
7 |
8 | """
9 | Sample script for JEB Decompiler.
10 |
11 | Retrieve a dex decompiler (dexdec) instance to decompile all methods,
12 | and retrieve and display interesting decompilation events.
13 | """
14 | class AndroidGlobalAnalysis(IScript):
15 |
16 | def run(self, ctx):
17 | prj = ctx.getMainProject()
18 | dex = prj.findUnit(IDexUnit)
19 | dexdec = dex.getDecompiler()
20 |
21 | dexdec.resetGlobalDecompilationEvents()
22 |
23 | f = (IDexDecompilerUnit.FLAG_BATCH_DECOMPILATION
24 | | IDexDecompilerUnit.FLAG_NO_METHOD_AST_GENERATION
25 | | IDexDecompilerUnit.FLAG_NO_DEFERRED_DECOMPILATION
26 | | IDexDecompilerUnit.FLAG_NO_INNER_DECOMPILATION
27 | | IDexDecompilerUnit.FLAG_TEMP_FORCED_REDECOMPILATIONS)
28 | ctx = DecompilationContext(DecompilationOptions.Builder.newInstance()
29 | .maxTimePerMethod(1 * 60 * 1000)
30 | .maxTimeTotal(5 * 60 * 1000)
31 | .flags(f)
32 | .build())
33 |
34 | success = dexdec.decompileAllMethods(ctx);
35 | print(success)
36 |
37 | # see DexDecompilerEvent
38 | for e in dexdec.getGlobalDecompilationEvents():
39 | print(e)
--------------------------------------------------------------------------------
/scripts/AndroidXrefResId.py:
--------------------------------------------------------------------------------
1 | #?description=Android APK cross-reference navigation from Resource XML units to DEX Disassembly unit
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.core import IPlugin
5 | from com.pnfsoftware.jeb.core.units.code.android import IApkUnit, IDexUnit
6 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDalvikInstruction
7 | from com.pnfsoftware.jeb.util.encoding import Conversion
8 | """
9 | Sample script for JEB Decompiler.
10 |
11 | Usage:
12 | - Position the caret on a resource id in XML (eg, ' list_of_usage_addresses
50 | # opti: to avoid rebuilding the map each time the script is called, we cache it in the client transient store
51 | immdb = ctx.getTransientStore().get('intImmDb')
52 | if immdb == None:
53 | immdb = {}
54 | ctx.getTransientStore().put('intImmDb', immdb)
55 | for m in dex.getMethods():
56 | if m.isInternal():
57 | ci = m.getData().getCodeItem()
58 | if ci:
59 | for insn in ci.getInstructions():
60 | for param in insn.getParameters():
61 | if param.getType() == IDalvikInstruction.TYPE_IMM:
62 | val = param.getValue()
63 | addr = '%s+%Xh' % (m.getSignature(False), insn.getOffset())
64 | if val not in immdb:
65 | immdb[val] = []
66 | immdb[val].append(addr)
67 | #print(immdb)
68 |
69 | candidate_addresses = immdb.get(resid)
70 | if not candidate_addresses:
71 | print('No location found')
72 | return
73 |
74 | # pick the best candidate xref; if there are multiple, pop-up a dialog and let the user pick
75 | if len(candidate_addresses) == 1:
76 | addr = candidate_addresses[0]
77 | else:
78 | rows = []
79 | for candidate_address in candidate_addresses:
80 | rows.append([candidate_address])
81 | print 'Found %d locations: %s' % (len(candidate_address), candidate_address)
82 | index = ctx.displayList('Select a location (%d candidates)' % len(candidate_addresses), None, ['Addresses'], rows)
83 | if index < 0:
84 | return
85 | addr = candidate_addresses[index]
86 | print('Navigating to: %s' % addr)
87 |
88 | # find, bring up, and focus on the DEX unit Disassembly fragment
89 | for view in ctx.getViews(dex):
90 | for fragment in view.getFragments():
91 | if view.getFragmentLabel(fragment) == 'Disassembly':
92 | view.setFocus()
93 | view.setActiveFragment(fragment)
94 | fragment.setActiveAddress(addr)
95 | return
96 | print('Assembly fragment was not found?')
97 |
--------------------------------------------------------------------------------
/scripts/ApkManifestView.py:
--------------------------------------------------------------------------------
1 | #?description=Retrieve the object representing an Android Manifest
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code.android import IApkUnit
5 | from com.pnfsoftware.jeb.core.output.text import TextDocumentUtil
6 | """
7 | Sample script for JEB Decompiler.
8 | """
9 | class ApkManifestView(IScript):
10 |
11 | def run(self, ctx):
12 | # current IRuntimeProject
13 | prj = ctx.getMainProject()
14 | assert prj, 'Need a project'
15 |
16 | # find the first IApkUnit in the project
17 | apk = prj.findUnit(IApkUnit)
18 | assert apk, 'Need an apk unit'
19 |
20 | # retrieve the IXmlUnit representing the Android Manifest
21 | man = apk.getManifest()
22 | assert man, 'The Manifest was not found'
23 |
24 | # 1) print the manifest (first presentation offered by the unit)
25 | doc = man.getFormatter().getPresentation(0).getDocument()
26 | print(TextDocumentUtil.getText(doc))
27 |
28 | # 2) retrieve the org.w3c.dom.Document
29 | xmldoc = man.getDocument()
30 | # ...
31 |
32 | doc.dispose() # always dispose unit-generated documents
33 |
--------------------------------------------------------------------------------
/scripts/AutorunTest1.py.DISABLED:
--------------------------------------------------------------------------------
1 | #?description=This client script will be autorun at start-up (1), project creation (2), and project reloaded (3)
2 | #?autorun=1,2,3
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | """
5 | *** TO ENABLE THIS SCRIPT, REMOVE THE .DISABLED extension ***
6 |
7 | Sample script for JEB Decompiler..
8 |
9 | Values for the metadata key autorun (CSL):
10 | 0 (no autorun), 1 (after start-up), 2 (after project creation), 3 (after project reloaded) [default:0]
11 | Values for the metadata key autorun_priority:
12 | any floating value, a high value means a high priority [default:0]
13 |
14 | NOTE the priority of this script: it was left to use the implicit default (0).
15 | At start-up, this script will be run after AutorunTest2, whose priority is a 5.
16 |
17 | Requires JEB 4.22+
18 | """
19 | class AutorunTest1(IScript):
20 | def run(self, ctx):
21 | print('AutorunTest1: This script was automatically executed by the client')
22 |
--------------------------------------------------------------------------------
/scripts/AutorunTest2.py.DISABLED:
--------------------------------------------------------------------------------
1 | #?description=This client script will be autorun at start-up (1) with priority 5
2 | #?autorun=1
3 | #?autorun_priority=5
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | """
6 | *** TO ENABLE THIS SCRIPT, REMOVE THE .DISABLED extension ***
7 |
8 | Sample script for JEB Decompiler..
9 |
10 | Values for the metadata key autorun (CSL):
11 | 0 (no autorun), 1 (after start-up), 2 (after project creation), 3 (after project reloaded) [default:0]
12 | Values for the metadata key autorun_priority:
13 | any floating value, a high value means a high priority [default:0]
14 |
15 | NOTE the priority of this script: it was set to 5.
16 | It will be executed before AutorunTest1, whose priority is a default 0.
17 |
18 | Requires JEB 4.22+
19 | """
20 | class AutorunTest2(IScript):
21 | def run(self, ctx):
22 | print('AutorunTest2: This script was automatically executed by the client')
23 |
--------------------------------------------------------------------------------
/scripts/BookmarkList.py:
--------------------------------------------------------------------------------
1 | #?description=List custom bookmarks saved by BookmarkSet
2 | #?shortcut=
3 | #?deprecated
4 | import datetime
5 | import json
6 | import time
7 | from com.pnfsoftware.jeb.client.api import IScript, IconType, ButtonGroupType
8 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
9 | from BookmarkSet import BookmarkSet
10 | """
11 | Sample script for JEB Decompiler.
12 |
13 | For demo purposes only, this script should not be used to list bookmarks.
14 | JEB uses its own bookmarks facility for projects.
15 | """
16 | class BookmarkList(IScript):
17 |
18 | def run(self, ctx):
19 | prj = ctx.getMainProject()
20 | assert prj, 'Need a project'
21 |
22 | bmstr = prj.getData(BookmarkSet.BMKEY)
23 | if not bmstr:
24 | ctx.displayMessageBox('Bookmarks', 'No recorded boolmarks yet!', IconType.INFORMATION, None)
25 | return
26 |
27 | bm = json.loads(bmstr)
28 | log('Current bookmarks (%d): %s' % (len(bm), bm))
29 |
30 | headers = ['Timestamp', 'Full Unit Path', 'Name', 'Fragment', 'Address', 'Comment']
31 | rows = []
32 | for uid, labelmap in bm.items():
33 | for label, addrmap in labelmap.items():
34 | for addr, e in addrmap.items():
35 | unitpath, unitname, comment, ts = e
36 | # note we're appended uid, but it won't be displayed (per the header's spec above, which specifies 6 columns - not 7)
37 | rows.append([datetime.datetime.fromtimestamp(ts).ctime(), unitpath, unitname, label, addr, comment, uid])
38 |
39 | index = ctx.displayList('Bookmarks', 'List of currently set bookmarks in the active project', headers, rows)
40 | if index < 0:
41 | return
42 |
43 | sel = rows[index]
44 | uid, label, addr = int(sel[6]), sel[3], sel[4]
45 | log('Selected: uid=%d,fragment=%s,addr=%s' % (uid, label, addr))
46 |
47 | unit = RuntimeProjectUtil.findUnitByUid(prj, uid)
48 | if not unit:
49 | print('Unit with uid=%d was not found in the project or no longer exists!' % uid)
50 | return
51 |
52 | if not ctx.openView(unit):
53 | print('Could not open view for unit!')
54 | else:
55 | f = ctx.findFragment(unit, label, True)
56 | if not f:
57 | print('Fragment "%s" not found!' % label)
58 | elif addr:
59 | f.setActiveAddress(addr)
60 |
61 | def log(s):
62 | print(s)
63 |
--------------------------------------------------------------------------------
/scripts/BookmarkSet.py:
--------------------------------------------------------------------------------
1 | #?description=Set and reset custom bookmarks
2 | #?shortcut=
3 | #?deprecated
4 | import datetime
5 | import json
6 | import time
7 | from com.pnfsoftware.jeb.client.api import IScript
8 | from com.pnfsoftware.jeb.core.units import UnitUtil
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | For demo purposes only, this script should not be used to list bookmarks.
13 | JEB uses its own bookmarks facility for projects.
14 | """
15 | class BookmarkSet(IScript):
16 | BMKEY = 'BOOKMARKS'
17 |
18 | def run(self, ctx):
19 | f = ctx.getFocusedFragment()
20 | if not f:
21 | print('Set the focus on a UI fragment, and position the caret at the location you would like to bookmark.')
22 | return
23 |
24 | label = ctx.getFocusedView().getFragmentLabel(f)
25 | addr = f.getActiveAddress()
26 | unit = f.getUnit()
27 | uid = unit.getUid()
28 | unitname = unit.getName()
29 | unitpath = UnitUtil.buildFullyQualifiedUnitPath(unit)
30 |
31 | log('Unit: %d (%s)' % (uid, unitpath))
32 | log('Address: %s' % addr)
33 | log('Fragment: %s' % label)
34 |
35 | prj = ctx.getMainProject()
36 | bmstr = prj.getData(BookmarkSet.BMKEY)
37 | if bmstr != None:
38 | bm = json.loads(bmstr)
39 | else:
40 | bm = {}
41 |
42 | #log('Current bookmarks (%d): %s' % (len(bm), bm))
43 | log('Current bookmarks: %d' % len(bm))
44 |
45 | labelmap = bm.get(str(uid))
46 | if labelmap == None:
47 | labelmap = {}
48 | bm[uid] = labelmap
49 |
50 | addrmap = labelmap.get(label)
51 | if addrmap == None:
52 | addrmap = {}
53 | labelmap[label] = addrmap
54 |
55 | e = addrmap.get(addr)
56 | if e:
57 | log('Found existing entry')
58 | comment = e[2]
59 | savedts = e[3]
60 | title = 'Update a bookmark'
61 | caption = 'Current comment. (Clear to delete the bookmark.)\nSet on ' + datetime.datetime.fromtimestamp(savedts).ctime()
62 | else:
63 | comment = 'bookmarked'
64 | title = 'Add a bookmark'
65 | caption = 'Optional comment.'
66 |
67 | comment = ctx.displayQuestionBox(title, caption, comment)
68 | if comment == None:
69 | return
70 |
71 | ts = time.time()
72 | if comment == '':
73 | log('Removing entry')
74 | if addr in addrmap:
75 | del addrmap[addr]
76 | else:
77 | log('Adding/modifying entry')
78 | addrmap[addr] = [unitpath, unitname, comment, ts]
79 |
80 | prj.setData(BookmarkSet.BMKEY, json.dumps(bm), True)
81 |
82 | def log(s):
83 | pass#print(s)
84 |
--------------------------------------------------------------------------------
/scripts/BreakpointsLoad.py:
--------------------------------------------------------------------------------
1 | #?description=Reload previously saved breakpoints onto the current debugging session. (The session must be started first.)
2 | #?shortcut=
3 | import json
4 | import os
5 | import time
6 | from com.pnfsoftware.jeb.client.api import IScript
7 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
8 | from com.pnfsoftware.jeb.core.units.code.debug import IDebuggerUnit
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | Reload previously saved breakpoints onto the current debugging session. The session must be started first.
13 | - Breakpoints file: [JEB]/bin/breakpoints.txt
14 | - See converse script to save breakpoints ot a file: BreakpointsSave.py
15 | """
16 | class BreakpointsLoad(IScript):
17 |
18 | def run(self, ctx):
19 | prj = ctx.getMainProject()
20 | assert prj, 'Need a project'
21 |
22 | prjname = prj.getName()
23 |
24 | prgdir = ctx.getProgramDirectory()
25 | bpfile = os.path.join(prgdir, 'breakpoints.txt')
26 | with open(bpfile, 'r+') as f:
27 | try:
28 | bpdict = json.load(f)
29 | except:
30 | bpdict = {}
31 | #print('Current breakpoints file:', bpdict)
32 |
33 | d = bpdict.get(prjname, None)
34 | if not d:
35 | print('Nothing to reload')
36 | return
37 |
38 | # get the first code unit available (code units re interactive units)
39 | units = RuntimeProjectUtil.findUnitsByType(prj, IDebuggerUnit, False)
40 | if not units:
41 | print('No unit available')
42 | return
43 |
44 | cnt = 0
45 | for dbg in units:
46 | a = d.get(dbg.getName(), None)
47 | if a:
48 | print(a)
49 | for entry in a:
50 | address = entry['address']
51 | enabled = entry['enabled']
52 | #print('- Debugger: %s (for %s): %s (%s)' % (dbg.getName(), dbg.getPotentialDebuggees(), address, 'enabled' if enabled else 'disabled'))
53 | bp = dbg.getBreakpoint(address, None)
54 | if not bp: # do not overwrite an already-set breakpoint
55 | bp = dbg.setBreakpoint(address, None)
56 | if bp:
57 | if not enabled:
58 | bp.setEnabled(False)
59 | cnt += 1
60 | else:
61 | print('Cannot restore breakpoint at address: %s' % address)
62 |
63 | print('Breakpoints reloaded: %d.' % cnt)
64 |
--------------------------------------------------------------------------------
/scripts/BreakpointsSave.py:
--------------------------------------------------------------------------------
1 | #?description=Save breakpoints (location and state) of the current debugging session to a file
2 | #?shortcut=
3 | import json
4 | import os
5 | import time
6 | from com.pnfsoftware.jeb.client.api import IScript
7 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
8 | from com.pnfsoftware.jeb.core.units.code.debug import IDebuggerUnit
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | Save (persist) the breakpoints (location and state) of the current debugging session to a file.
13 | - Breakpoints file: [JEB]/bin/breakpoints.txt
14 | - See converse script to reload breakpoints onto a debugging session: BreakpointsLoad.py
15 |
16 | The breakpoints file is JSON formatted and can be edited manually as well. Structure
17 |
18 | ProjectName:
19 | DebuggerName:
20 | BreakpointsList: (= dictionary with "address" and "enabled" keys)
21 |
22 | Example:
23 |
24 | {
25 | "/analysis/appcheck-debug.apk.jdb2": {
26 | "VM": [
27 | {
28 | "address": "Lcom/xyz/appcheck/AppCheck$1;->(Lcom/xyz/appcheck/AppCheck;)V+4h",
29 | "enabled": true
30 | },
31 | {
32 | "address": "Lcom/xyz/appcheck/AppCheck$1;->run()V+2h",
33 | "enabled": true
34 | }
35 | ]
36 | }
37 | "/analysis/malware_yil1.apk.jdb2": {
38 | "VM": [
39 | {
40 | "address": "Lcom/malyy/a/b/c;->f()V+0h",
41 | "enabled": false
42 | }
43 | ]
44 | }
45 | }
46 | """
47 | class BreakpointsSave(IScript):
48 |
49 | def run(self, ctx):
50 | prj = ctx.getMainProject()
51 | assert prj, 'Need a project'
52 |
53 | prjname = prj.getName()
54 |
55 | prgdir = ctx.getProgramDirectory()
56 | bpfile = os.path.join(prgdir, 'breakpoints.txt')
57 | with open(bpfile, 'r+') as f:
58 | try:
59 | bpdict = json.load(f)
60 | except:
61 | bpdict = {}
62 | #print('Current breakpoints file:', bpdict)
63 |
64 | units = RuntimeProjectUtil.findUnitsByType(prj, IDebuggerUnit, False)
65 | if not units:
66 | print('No unit available')
67 | return
68 |
69 | d = {}
70 | cnt = 0
71 | for dbg in units:
72 | # may be null for a detached debugger
73 | bplist = dbg.getBreakpoints()
74 | if bplist:
75 | a = []
76 | for bp in bplist:
77 | address = bp.getAddress()
78 | enabled = bp.isEnabled()
79 | #print('- Debugger: %s (for %s): %s (%s)' % (dbg.getName(), dbg.getPotentialDebuggees(), address, 'enabled' if enabled else 'disabled'))
80 | a.append({'address': address, 'enabled': enabled})
81 | cnt += 1
82 | d[dbg.getName()] = a
83 | bpdict[prjname] = d
84 |
85 | with open(bpfile, 'w') as f:
86 | try:
87 | json.dump(bpdict, f, indent=True)
88 | except Exception as e:
89 | print('ERROR: Cannot save to breakpoints file: %s' % e)
90 |
91 | print('Breakpoints saved: %d.' % cnt)
92 |
--------------------------------------------------------------------------------
/scripts/CodeLoad.py:
--------------------------------------------------------------------------------
1 | #?description=Reload and apply basic refactoring data on loaded code units
2 | #?shortcut=
3 | import json
4 | import os
5 | import time
6 | from com.pnfsoftware.jeb.client.api import IScript
7 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
8 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | JEB script to reload and apply basic refactoring data onto loaded code units.
13 | - Data file: [JEB]/bin/codedata.txt
14 | - See converse script to persist such data on disk: CodeSave.py
15 | """
16 | class CodeLoad(IScript):
17 |
18 | def run(self, ctx):
19 | prj = ctx.getMainProject()
20 | assert prj, 'Need a project'
21 |
22 | prjname = prj.getName()
23 |
24 | prgdir = ctx.getProgramDirectory()
25 | datafile = os.path.join(prgdir, 'codedata.txt')
26 | data = {}
27 | if os.path.exists(datafile):
28 | with open(datafile, 'r') as f:
29 | try:
30 | data = json.load(f)
31 | except:
32 | pass
33 | print('Current data:', data)
34 |
35 | d = data.get(prjname, None)
36 | if not d:
37 | print('Nothing to reload')
38 | return
39 |
40 | units = RuntimeProjectUtil.findUnitsByType(prj, ICodeUnit, False)
41 | if not units:
42 | print('No code unit available')
43 | return
44 |
45 | for unit in units:
46 | if not unit.isProcessed():
47 | continue
48 |
49 | a = d.get(unit.getName(), None)
50 | if a:
51 | renamed_classes = a['renamed_classes']
52 | renamed_fields = a['renamed_fields']
53 | renamed_methods = a['renamed_methods']
54 | comments = a['comments']
55 | for sig, name in renamed_classes.items():
56 | unit.getClass(sig).setName(name)
57 | for sig, name in renamed_fields.items():
58 | unit.getField(sig).setName(name)
59 | for sig, name in renamed_methods.items():
60 | unit.getMethod(sig).setName(name)
61 | # note: comments are applied last since `addr` can be a refactored one here
62 | for addr, comment in comments.items():
63 | unit.setInlineComment(addr, comment)
64 |
65 | print('Basic refactoring data was applied')
66 |
--------------------------------------------------------------------------------
/scripts/CodeSave.py:
--------------------------------------------------------------------------------
1 | #?description=Save basic refactoring data of the project's code units into a file
2 | #?shortcut=
3 | import json
4 | import os
5 | import time
6 | from com.pnfsoftware.jeb.client.api import IScript
7 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
8 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | - Data file: [JEB]/bin/codedata.txt
13 | - See converse script to load and apply that data onto a fresh project: CodeLoad.py
14 | """
15 | class CodeSave(IScript):
16 |
17 | def run(self, ctx):
18 | prj = ctx.getMainProject()
19 | assert prj, 'Need a project'
20 |
21 | prjname = prj.getName()
22 |
23 | prgdir = ctx.getProgramDirectory()
24 | datafile = os.path.join(prgdir, 'codedata.txt')
25 | data = {}
26 | if os.path.exists(datafile):
27 | with open(datafile, 'r') as f:
28 | try:
29 | data = json.load(f)
30 | except:
31 | pass
32 | #print('Current data:', data)
33 |
34 | units = RuntimeProjectUtil.findUnitsByType(prj, ICodeUnit, False)
35 | if not units:
36 | print('No code unit available')
37 | return
38 |
39 | d = {}
40 | for unit in units:
41 | if not unit.isProcessed():
42 | continue
43 |
44 | a = {}
45 | d[unit.getName()] = a
46 |
47 | a['renamed_classes'] = {}
48 | a['renamed_fields'] = {}
49 | a['renamed_methods'] = {}
50 | a['comments'] = {}
51 |
52 | for c in unit.getClasses():
53 | name0 = c.getName(False)
54 | name1 = c.getName(True)
55 | if name0 != name1:
56 | a['renamed_classes'][c.getSignature(False)] = name1
57 |
58 | for f in unit.getFields():
59 | name0 = f.getName(False)
60 | name1 = f.getName(True)
61 | if name0 != name1:
62 | a['renamed_fields'][f.getSignature(False)] = name1
63 |
64 | for m in unit.getMethods():
65 | name0 = m.getName(False)
66 | name1 = m.getName(True)
67 | if name0 != name1:
68 | a['renamed_methods'][m.getSignature(False)] = name1
69 |
70 | for addr, comment in unit.getInlineComments().items():
71 | a['comments'][addr] = comment
72 |
73 | data[prjname] = d
74 |
75 | with open(datafile, 'w') as f:
76 | try:
77 | json.dump(data, f, indent=True)
78 | except Exception as e:
79 | print('ERROR: Cannot save to file: %s' % e)
80 |
81 | print('Basic refactoring data recorded to file: %s' % datafile)
82 |
--------------------------------------------------------------------------------
/scripts/CreateEmptyClass.py:
--------------------------------------------------------------------------------
1 | #?description=Create a native code class into the first found native code unit
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units import INativeCodeUnit
5 | from com.pnfsoftware.jeb.core.units.code.asm.type import TypeUtil
6 | """
7 | Script for JEB Decompiler.
8 | """
9 | class CreateEmptyClass(IScript):
10 |
11 | def run(self, ctx):
12 | prj = ctx.getMainProject()
13 | assert prj, 'Need a project'
14 |
15 | unit = prj.findUnit(INativeCodeUnit)
16 | assert unit, 'Need a native code unit'
17 |
18 | # class type (abstract)
19 | cname = 'Class001'
20 | typeman = unit.getTypeManager()
21 | #tInt = typeman.getType('int')
22 | ctype = typeman.getType(cname)
23 | if not ctype:
24 | ctype = typeman.createClassType(cname, 1, 0)
25 | typeman.completeClassTypeInitialization(ctype)
26 | print(ctype)
27 |
28 | # class item (concrete)
29 | classman = unit.getClassManager()
30 | c = classman.createClass(ctype)
31 | classman.completeClassInitialization(c)
32 | print(c)
33 |
34 | # make the first routine found in the code a static method of that class
35 | m = unit.getInternalMethods().get(0)
36 | if m:
37 | classman.addStaticMethod(c, m)
38 |
39 | unit.notifyGenericChange()
40 |
41 | #tS1 = typeman.createStructure('MyStruct1')
42 | #typeman.addStructureField(tS1, 'a', tInt)
43 | #typeman.addStructureField(tS1, 'b', TypeUtil.buildArrayType(typeman, 'unsigned char', 2, 3))
44 |
--------------------------------------------------------------------------------
/scripts/CreateExtraDocument.py:
--------------------------------------------------------------------------------
1 | #?description=Generate an extra document for the first found interactive unit
2 | #?shortcut=
3 | from java.util import ArrayList
4 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
5 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
6 | from com.pnfsoftware.jeb.core.output import AbstractUnitRepresentation, UnitRepresentationAdapter
7 | from com.pnfsoftware.jeb.core.output.text.impl import Line, StaticTextDocument
8 | from com.pnfsoftware.jeb.core.units import IInteractiveUnit
9 | """
10 | Sample script JEB Decompiler.
11 |
12 | The newly-created document is called 'Quotes'.
13 | """
14 | class CreateExtraDocument(IScript):
15 | def run(self, ctx):
16 | prj = ctx.getMainProject()
17 | assert prj, 'Need a project'
18 |
19 | # pick the first interactive unit
20 | unit = prj.findUnit(IInteractiveUnit)
21 | assert unit, 'Need a unit'
22 | print('Unit: %s' % unit)
23 |
24 | # retrieve the formatter, which is a producer of unit representations
25 | formatter = unit.getFormatter()
26 |
27 | # create an extra document (text document), wrap it in a representtion
28 | lines = ArrayList()
29 | lines.add(Line('There are two hard problems in computer science: cache invalidation, naming things, and off-by-one errors.'))
30 | lines.add(Line(' - Phil Karlton (and others)'))
31 | extraDoc = StaticTextDocument(lines)
32 | extraPres = UnitRepresentationAdapter(100, 'Quotes', False, extraDoc)
33 |
34 | # add the newly created representation to our unit, and notify clients
35 | # the second argument indicates that the presentation should be persisted when saving the project
36 | formatter.addPresentation(extraPres, True)
37 | unit.notifyGenericChange()
38 |
39 | # done - if you are running a UI client, the additional document should be displayed
40 | # in a fragment view (eg, sub-tab in the case of the official RCP client)
41 |
--------------------------------------------------------------------------------
/scripts/CreateExtraDocumentTableTree.py:
--------------------------------------------------------------------------------
1 | #?description=Generate extra table and tree documents for the first found interactive unit
2 | #?shortcut=
3 | from java.util import ArrayList, Arrays
4 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
5 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
6 | from com.pnfsoftware.jeb.core.output import AbstractUnitRepresentation, UnitRepresentationAdapter, ItemClassIdentifiers
7 | from com.pnfsoftware.jeb.core.output.table.impl import StaticTableDocument, TableRow, Cell
8 | from com.pnfsoftware.jeb.core.output.tree.impl import StaticTreeDocument, Node, KVNode
9 | from com.pnfsoftware.jeb.core.units import IInteractiveUnit
10 | """
11 | Sample script for JEB Decompiler.
12 |
13 | Will create 2 documents named 'Demo Tree' and 'Demo Table'
14 | """
15 | class CreateExtraDocumentTableTree(IScript):
16 | def run(self, ctx):
17 | prj = ctx.getMainProject()
18 | assert prj, 'Need a project'
19 |
20 | unit = prj.findUnit(IInteractiveUnit)
21 | assert unit, 'Need a unit'
22 | print('Unit: %s' % unit)
23 |
24 | # retrieve the formatter, which is a producer of unit representations
25 | formatter = unit.getFormatter()
26 |
27 | # create a table document
28 | columnLabels = Arrays.asList('Key', 'Value', 'Comment')
29 | rows = ArrayList()
30 | rows.add(TableRow(Arrays.asList(Cell('foo'), Cell('bar'), Cell('none'))))
31 | rows.add(TableRow(Arrays.asList(Cell('type'), Cell('integer'), Cell('unset'))))
32 | extraDoc = StaticTableDocument(columnLabels, rows)
33 | extraPres0 = UnitRepresentationAdapter(101, 'Demo Table', False, extraDoc)
34 |
35 | # create a tree document
36 | columnLabels = Arrays.asList('Key', 'Value')
37 | root = KVNode('foo', 'bar')
38 | roots = Arrays.asList(root)
39 | root.addChild(KVNode('quantified', 'self'))
40 | root.addChild(KVNode('galaxy', 'milky way'))
41 | node = KVNode('black hole', '42')
42 | node.setClassId(ItemClassIdentifiers.INFO_DANGEROUS)
43 | root.addChild(node)
44 | extraDoc = StaticTreeDocument(roots, columnLabels, -1)
45 | extraPres1 = UnitRepresentationAdapter(102, 'Demo Tree', False, extraDoc)
46 |
47 | # add the newly created presentations to our unit, and notify clients
48 | # the second argument indicates that the presentation should be persisted when saving the project
49 | formatter.addPresentation(extraPres0, True)
50 | formatter.addPresentation(extraPres1, True)
51 | unit.notifyGenericChange()
52 |
53 | # done - if you are running a UI client, the additional document should be displayed
54 | # in a fragment view (eg, sub-tab in the case of the official RCP client)
55 |
--------------------------------------------------------------------------------
/scripts/CreateNativeStruct.py:
--------------------------------------------------------------------------------
1 | #?description=Create a native structure type of the provided size, filled with integer primitives
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
5 | from com.pnfsoftware.jeb.core.units import INativeCodeUnit
6 | from com.pnfsoftware.jeb.core.units.code.asm.type import TypeUtil
7 | from com.pnfsoftware.jeb.util.encoding import Conversion
8 | """
9 | Sample script for JEB Decompiler.
10 |
11 | This script is a UI helper to quickly create a native structure type of a given size.
12 | The structure will be filled with int32 primitives, and padded with one optional int16 and optional int8, if necessary.
13 | """
14 | class CreateNativeStruct(IScript):
15 | def run(self, ctx):
16 | if not isinstance(ctx, IGraphicalClientContext):
17 | print('This script must be run within a graphical client')
18 | return
19 |
20 | if not ctx.getFocusedView():
21 | print('Set the focus on a native disassembly fragment')
22 | return
23 | unit = ctx.getFocusedView().getUnit()
24 | if not isinstance(unit, INativeCodeUnit):
25 | print('Set the focus on a native disassembly fragment')
26 | return
27 |
28 | value = ctx.displayQuestionBox('Structure Name', 'Name:', '')
29 | if not value:
30 | print('Provide a structure name')
31 | return
32 | _name = value
33 |
34 | typeman = unit.getTypeManager()
35 |
36 | tS = typeman.getType(_name)
37 | if tS:
38 | print('A type with the following name already exists: %s' % tS)
39 | return
40 |
41 | value = ctx.displayQuestionBox('Structure Size', 'Size (in bytes):', '')
42 | if not value:
43 | print('Provide a structure size')
44 | return
45 |
46 | _sizebytes = Conversion.toInt(value)
47 | if _sizebytes <= 0:
48 | print('Provide a valid structure size')
49 | return
50 |
51 | # create an empty structure type
52 | tS = typeman.createStructure(_name)
53 |
54 | # determine how many fields are needed to fill it up
55 | cnt4 = _sizebytes / 4
56 | pad2, pad1 = 0, 0
57 | r = _sizebytes % 4
58 | if r != 0:
59 | pad2 = _sizebytes / 2
60 | pad1 = _sizebytes % 2
61 |
62 | # fill up the type
63 | tInt32 = typeman.getType('int')
64 | for i in range(cnt4):
65 | typeman.addStructureField(tS, None, tInt32)
66 | if pad2:
67 | tInt16 = typeman.getType('short')
68 | typeman.addStructureField(tS, None, tInt16)
69 | if pad1:
70 | tInt8 = typeman.getType('char')
71 | typeman.addStructureField(tS, None, tInt8)
72 |
73 | print('Newly created structure type: %s' % tS)
74 |
--------------------------------------------------------------------------------
/scripts/CustomizeMetadata.py:
--------------------------------------------------------------------------------
1 | #?description=Customize the metadata of a code unit (and see rendering in the metadata overview bar in GUI)
2 | #?shortcut=
3 | import time
4 | from java.util import ArrayList
5 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
6 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
7 | from com.pnfsoftware.jeb.core.units import IInteractiveUnit, MetadataGroup, MetadataGroupType
8 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit
9 | """
10 | Sample script JEB Decompiler.
11 |
12 | Customize the metadata of a code unit (and see rendering in the metadata overview bar in GUI).
13 | The beginning of every class will be marked and rendered as a light green in the navigation bar.
14 | """
15 | class CustomizeMetadata(IScript):
16 |
17 | def run(self, ctx):
18 | prj = ctx.getMainProject()
19 | assert prj, 'Need a project'
20 |
21 | # pick the first code unit offered by the project
22 | unit = prj.findUnit(ICodeUnit)
23 | print('Unit: %s' % unit)
24 |
25 | # the metadata manager is optional (a unit may choose to not provide one)
26 | mm = unit.getMetadataManager()
27 | if not mm:
28 | print('The unit does not have a metadata manager')
29 | return
30 |
31 | # create a new metadata group that will hold RGB color values
32 | g = mm.getGroupByName('custom')
33 | if not g:
34 | print('Creating new metadata group (type: RGB) ...')
35 | g = MetadataGroup('custom', MetadataGroupType.RGB)
36 | mm.addGroup(g)
37 | print('Done')
38 |
39 | # mark the beginning of every class; they will be rendered in the overview bar in the client
40 | for iclass, c in enumerate(unit.getClasses()):
41 | targetAddress = c.getAddress()
42 |
43 | print('Adding a piece of metadata at address "%s" ...' % targetAddress)
44 | g.setData(targetAddress, 0x00FF30)
45 | print('Done')
46 |
47 | print('If the unit has a text document representation with a an Overview bar, do a Refresh to visualize the metadata')
48 |
49 | print('Listing all metadata for this unit (if possible) ...')
50 | for g1 in mm.getGroups():
51 | print('- Group %s (type: %s)' % (g1.getName(), g1.getType()))
52 | alldata = g1.getAllData()
53 | if alldata == None:
54 | print('(This group manager does not allow metadata enumeration)')
55 | else:
56 | for k in alldata:
57 | print(' - at "%s" -> %s' % (k, alldata[k]))
58 |
59 | unit.notifyGenericChange()
60 |
--------------------------------------------------------------------------------
/scripts/DalvikDataFlow.py:
--------------------------------------------------------------------------------
1 | #?description=Examine Dalvik method Control Flow Graph (CFG) and perform data flow analysis on the graph to look at register definition locations and their uses, and register use locations and their definitions
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
5 | """
6 | Sample script for JEB Decompiler.
7 |
8 | This script is showing how to examine Dalvik method Control Flow Graph (CFG) and perform
9 | data flow analysis (DFA) on the graph to look at register definition locations and their
10 | uses, and register use locations and their definitions.
11 |
12 | What is Data Flow Analysis: a starting point at https://en.wikipedia.org/wiki/Data-flow_analysis
13 | API documentation: start with https://www.pnfsoftware.com/jeb/apidoc/reference/com/pnfsoftware/jeb/core/units/code/IDFA3.html
14 |
15 | How to use this sample script:
16 | - open a DEX file
17 | - position the caret somewhere on a Dalvik instruction in the Disassembly view
18 | - run the script to see the uses and/or definitions of the registers manipulated by the instruction
19 | """
20 | class DalvikDataFlow(IScript):
21 |
22 | def run(self, ctx):
23 | prj = ctx.getMainProject()
24 | assert prj, 'Need a project'
25 |
26 | dex = prj.findUnit(IDexUnit)
27 | assert prj, 'Need a dex unit'
28 |
29 | addr = ctx.getFocusedView().getActiveFragment().getActiveAddress()
30 | pos = addr.find('+')
31 | if pos >= 0:
32 | mname = addr[0:pos]
33 | off = int(addr[pos + 1:].rstrip('h'), 16)
34 | else:
35 | mname = addr
36 | off = 0
37 |
38 | m = dex.getMethod(mname)
39 | if not m:
40 | print('No method found at address: %s' % addr)
41 | return
42 |
43 | print('Method: %s, Offset: 0x%X' % (mname, off))
44 |
45 | cfg = m.getData().getCodeItem().getControlFlowGraph()
46 | dfa = cfg.doDataFlowAnalysis()
47 | print('CFG for method was retrieved, DFA was performed')
48 |
49 | insn = cfg.getInstructionAt(off)
50 | print('Instruction on caret: %s' % insn)
51 |
52 | # DU-map: instruction -> map(register, list(instructions using the defined register))
53 | dumap = dfa.getDefUseChains(insn.getOffset())
54 | for regid, addrlist in dumap.items():
55 | print('[du] r%d: used at %s' % (regid, ','.join(['0x%X ' % (addr) for addr in addrlist])))
56 |
57 | # UD-map: instruction -> map(register, list(instructions using the defined register))
58 | udmap = dfa.getUseDefChains(insn.getOffset())
59 | for regid, addrlist in udmap.items():
60 | print('[ud] r%d: defined at %s' % (regid, ','.join(['0x%X ' % (addr) for addr in addrlist])))
61 |
--------------------------------------------------------------------------------
/scripts/DecompileSingleMethod.py:
--------------------------------------------------------------------------------
1 | #?description=Decompile a single method.
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.util import DecompilerHelper
5 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit, IDecompilerUnit, DecompilationContext, DecompilationOptions
6 | """
7 | Sample script for JEB Decompiler.
8 |
9 | The class containing the target method is itself not decompiled; inner classes of the method, if any, are not decompiled either.
10 | The decompiled code is displayed in a text box.
11 | """
12 | class DecompileSingleMethod(IScript):
13 |
14 | def run(self, ctx):
15 | self.ctx = ctx
16 |
17 | f = ctx.getFocusedFragment()
18 | if not f:
19 | print('Set the focus on a UI fragment, and position the caret somewhere in the method you would like to decompile.')
20 | return
21 |
22 | addr = f.getActiveAddress()
23 | unit = f.getUnit()
24 | if not isinstance(unit, ICodeUnit):
25 | print('Not a code unit: %s' % unit)
26 | return
27 |
28 | m = unit.getMethod(addr)
29 | if not m:
30 | print('Not a method at address: %s' % addr)
31 | return
32 |
33 | decomp = DecompilerHelper.getDecompiler(unit)
34 | if not decomp:
35 | print('Cannot acquire decompiler for unit: %s' % decomp)
36 | return
37 |
38 | # *** decompilation Options and Context are optional ***
39 | # here, we're creating an Options object to:
40 | # - override the decompiler settings (if any), and cap method decompilation to 30 seconds
41 | # - prevent the decompilation of inner classes or any deferred decompilations: we decompile the target and only the target
42 | opt = DecompilationOptions.Builder.newInstance().flags(IDecompilerUnit.FLAG_NO_INNER_DECOMPILATION|IDecompilerUnit.FLAG_NO_DEFERRED_DECOMPILATION).maxTimePerMethod(30000).build()
43 | if not decomp.decompileMethod(m.getSignature(), DecompilationContext(opt)):
44 | print('Failed decompiling method')
45 | return
46 |
47 | text = decomp.getDecompiledMethodText(m.getSignature())
48 | #print(text)
49 | r = ctx.displayText("Decompiled Method: %s" % m.getName(), text, True)
50 | #print(r)
51 |
--------------------------------------------------------------------------------
/scripts/DexClassRefactor.py:
--------------------------------------------------------------------------------
1 | #?description=Refactor a dex class, i.e. rename and repackage automatically (if necessary)
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit
5 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDexClass
6 | """
7 | Sample script for JEB Decompiler.
8 | """
9 | class DexClassRefactor(IScript):
10 | def run(self, ctx):
11 | prj = ctx.getMainProject()
12 | if not isinstance(ctx, IGraphicalClientContext):
13 | return
14 |
15 | dex = ctx.getFocusedUnit()
16 | assert dex, 'Need focus on dex'
17 | item = ctx.getFocusedItem()
18 | assert item, 'Need caret on item'
19 | o = dex.getObjectById(item.getItemId())
20 | assert isinstance(o, IDexClass), 'Not a class item'
21 |
22 | r = ctx.displayQuestionBox('Rename', 'Input the new type descriptor:', o.getSignature())
23 | if not r:
24 | return # user aborted
25 | if not (r.startswith('L') and r.endswith(';')):
26 | return # illegal descriptor
27 | if r == o.getSignature():
28 | return # nothing to do
29 |
30 | pos = r.rfind('/')
31 | if pos < 0:
32 | psig = ''
33 | cname = r[1:-1]
34 | else:
35 | psig = r[0:pos+1]
36 | cname = r[pos+1:-1]
37 |
38 | print('Renaming class to: %s' % cname)
39 | o.setName(cname)
40 |
41 | pkg = dex.getPackage(psig)
42 | if not pkg:
43 | print('Creating package: %s' % psig)
44 | # note: addPackage() has a glitch, only accepts high-level (dot-separated) forms
45 | pkg = dex.addPackage(psig[1:-1].replace('/', '.'))
46 | if not pkg:
47 | print('Cannot create package: %s' % psig)
48 | return
49 | print('Moving: %s to %s' % (o, pkg))
50 |
51 | success = dex.moveToPackage(o, pkg)
52 | if success:
53 | dex.notifyGenericChange()
54 |
--------------------------------------------------------------------------------
/scripts/DexColorArtificialStrings.py:
--------------------------------------------------------------------------------
1 | #?description=Visualize artificial (e.g. decrypted) strings in the navbar
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
5 | from com.pnfsoftware.jeb.core.output import ItemClassIdentifiers
6 | from com.pnfsoftware.jeb.core.units import MetadataGroup, MetadataGroupType, AddressPrefixMetadataGroup
7 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
8 | from com.pnfsoftware.jeb.core.units.code.android.dex import DexPoolType
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | This script will update the navbar and generate colors where artificial strings are being used.
13 | Artificial strings are strings that were not originally present in the dex pool(s), e.g. auto-decrypted strings.
14 |
15 | Demo:
16 | - open com.parental.control.v4.apk
17 | - run a Global Analysis
18 | - execute the script
19 | """
20 | class DexColorArtificialStrings(IScript):
21 | def run(self, ctx):
22 | f = ctx.getFocusedFragment()
23 | if not f:
24 | print('Set the focus on a UI fragment, and position the caret on a valid address')
25 | return
26 |
27 | unit = f.getUnit()
28 | if not isinstance(unit, IDexUnit):
29 | print('Focus a fragment representing a dex unit')
30 | return
31 |
32 | mm = unit.getMetadataManager()
33 | if not mm:
34 | print('The unit does not have a metadata manager')
35 | return
36 |
37 | g = mm.getGroupByName('astrings')
38 | if not g:
39 | g = AddressPrefixMetadataGroup(unit, 'astrings')
40 | mm.addGroup(g)
41 |
42 | for s in unit.getStrings():
43 | if s.isArtificial():
44 | #print('String: %s' % s)
45 | refs = unit.getReferenceManager().getReferences(DexPoolType.STRING, s.getIndex())
46 | for ref in refs:
47 | a = ref.getInternalAddress()
48 | #print('Coloring at: %s' % a)
49 | pos = a.find('+')
50 | if pos >= 0: a = a[:pos]
51 | success = g.setData(a, ItemClassIdentifiers.STRING_GENERATED)
52 |
53 | unit.notifyGenericChange()
54 |
--------------------------------------------------------------------------------
/scripts/DexColorPackage.py:
--------------------------------------------------------------------------------
1 | #?description=
2 | #?shortcut=
3 | #?nolist
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
6 | from com.pnfsoftware.jeb.core.output import ItemClassIdentifiers
7 | from com.pnfsoftware.jeb.core.units import MetadataGroup, MetadataGroupType, AddressPrefixMetadataGroup
8 | """
9 | Sample script for JEB Decompiler.
10 |
11 | Package/Class/Method coloring scrip.
12 | We use the AddressPrefixMetadataGroup object to store metadata information, displayed in a text navbar.
13 | """
14 | class DexColorPackage(IScript):
15 | def run(self, ctx):
16 | f = ctx.getFocusedFragment()
17 | if not f:
18 | print('Set the focus on a UI fragment, and position the caret on a valid address')
19 | return
20 |
21 | addr = f.getActiveAddress()
22 | unit = f.getUnit()
23 | if not unit or not addr:
24 | print('No unit or no address at current location')
25 | return
26 |
27 | mm = unit.getMetadataManager()
28 | if not mm:
29 | print('The unit does not have a metadata manager')
30 | return
31 | g = mm.getGroupByName(AddressPrefixMetadataGroup.DEFAULT_NAME)
32 | if not g:
33 | g = AddressPrefixMetadataGroup(unit)
34 | mm.addGroup(g)
35 |
36 | addr = unit.getCanonicalAddress(addr)
37 | addrlist = [addr]
38 | # hack: include inner classes if addr is a class address
39 | if addr.find('->') < 0 and addr.endswith(';'):
40 | addrlist.append(addr[:-1] + '$')
41 |
42 | for a in addrlist:
43 | if g.getAllData().get(a) != None:
44 | success = g.setData(a, None)
45 | else:
46 | success = g.setData(a, ItemClassIdentifiers.INFO_NORMAL)
47 | print('%s: %s' % (a, success))
48 |
49 | unit.notifyGenericChange()
50 |
--------------------------------------------------------------------------------
/scripts/DexJumpToActivity.py:
--------------------------------------------------------------------------------
1 | #?description=Jump from an activity name (selected in the Android XML Manifest) to its corresponding bytecode definition in the DEX disassembly fragment
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext, IUnitView
4 | from com.pnfsoftware.jeb.core.units import IUnit, IXmlUnit
5 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
6 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
7 | """
8 | Sample script for JEB Decompiler.
9 |
10 | This JEB UI script allows the user to jump from an activity name (selected in the Android XML
11 | Manifest) to its corresponding bytecode definition in the DEX disassembly fragment.
12 | """
13 | class DexJumpToActivity(IScript):
14 |
15 | def run(self, ctx):
16 | prj = ctx.getMainProject()
17 | assert prj, 'Need a project'
18 |
19 | if not isinstance(ctx, IGraphicalClientContext):
20 | print('This script must be run within a graphical client')
21 | return
22 |
23 | fragment = ctx.getFocusedView().getActiveFragment()
24 | if type(fragment.getUnit()) is IXmlUnit:
25 | print('Select the Manifest XML view')
26 | return
27 |
28 | # make sure that the fragment has the focus, els the item would not be considered active
29 | aname = fragment.getActiveItemAsText()
30 | if not aname:
31 | print('Select the activity name')
32 | return
33 |
34 | # activity name is relative to the package name
35 | if aname.startswith('.'):
36 | # unit is the Manifest, of type IXmlUnit; we can retrieve the XML document
37 | # note: an alternate way would be to retrieve the top-level IApkUnit, and use getPackageName()
38 | dom = fragment.getUnit().getDocument()
39 | pname = dom.getElementsByTagName("manifest").item(0).getAttribute("package")
40 | #print('Package name: %s' % pname)
41 | aname = pname + aname
42 |
43 | print('Activity name: %s' % aname)
44 |
45 | addr = 'L' + aname.replace('.', '/') + ';'
46 | print('Target address: %s' % addr)
47 |
48 | unit = RuntimeProjectUtil.findUnitsByType(prj, IDexUnit, False).get(0)
49 | if not unit:
50 | print('The DEX unit was not found')
51 | return
52 |
53 | ctx.openView(unit)
54 | # this code assumes that the active fragment is the disassembly (it may not be; strong script should focus the assembly fragment)
55 | ctx.getFocusedView().getActiveFragment().setActiveAddress(addr)
56 |
--------------------------------------------------------------------------------
/scripts/DexJumpToFileOffset.py:
--------------------------------------------------------------------------------
1 | #?description= Jump to method code providing a dex file offset
2 | #?shortcut=
3 |
4 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
5 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
6 | """
7 | Sample script for JEB Decompiler.
8 |
9 | Providing a file offset and an optional classesN.dex index, find the corresponding method and the
10 | bytecode location, and jump to that location in the disassembly view.
11 | """
12 | class DexJumpToFileOffset(IScript):
13 | def run(self, ctx):
14 | assert isinstance(ctx, IGraphicalClientContext), 'Must run in GUI'
15 |
16 | prj = ctx.getMainProject()
17 | assert prj, 'Need an opened project'
18 |
19 | dex = prj.findUnit(IDexUnit)
20 | assert dex, 'Need a processed dex'
21 |
22 | val = ctx.displayQuestionBox('Provide a dex file offset',
23 | 'Offset (hex), followed by optional classes.dex file. Examples:\n'
24 | + '1000 => offset 0x1000 in classes.dex; 2000,2 => offset 0x2000 in classes2.dex', '')
25 | if not val: return
26 | val = val.strip()
27 | if val == '': return
28 | elts = val.split(',')
29 | offset = int(elts[0].strip(), 16)
30 | dexidx = 1 if len(elts) < 2 else int(elts[1].strip(), 16)
31 | print('Searching for method bytecode at: offset 0x%X in classes%s.dex' % (offset, '' if dexidx == 1 else str(dexidx)))
32 |
33 | target_addr = None
34 | for m in dex.getMethods():
35 | if m.isInternal():
36 | code = m.getData().getCodeItem()
37 | if code:
38 | if code.getDexFileIndex() + 1 == dexidx:
39 | start = code.getInstructionsOffset()
40 | if offset >= start and offset < start + code.getInstructionsSize():
41 | target_addr = m.getAddress()
42 | moff = offset - start
43 | for insn in code.getInstructions():
44 | insn_offset = insn.getOffset()
45 | if moff >= insn_offset and moff < insn_offset + insn.getSize():
46 | target_addr += '+%Xh' % insn_offset
47 |
48 | if not target_addr:
49 | print('Not found.')
50 | return
51 |
52 | print('Found: %s' % target_addr)
53 | f = ctx.findFragment(dex, 'Disassembly', True)
54 | f.setActiveAddress(target_addr)
55 |
--------------------------------------------------------------------------------
/scripts/DexJumpToResource.py:
--------------------------------------------------------------------------------
1 | #?description=Jump to or display an Android target resource (string, XML, etc.) referenced by an active resource ID item (interactive number)
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext, IUnitView
4 | from com.pnfsoftware.jeb.core.units import IUnit, IXmlUnit
5 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil, IUnitFilter
6 | import org.w3c.dom.Document
7 | """
8 | Sample script for JEB Decompiler.
9 |
10 | This JEB script jumps to or displays an Android target resource (string, XML, etc.)
11 | referenced by an active resource ID item (interactive number).
12 |
13 | Open an APK; in a Dalvik or Java view, set the caret on a resource id; execute the script.
14 | """
15 | class DexJumpToResource(IScript):
16 |
17 | def run(self, ctx):
18 | prj = ctx.getMainProject()
19 | assert prj, 'Need a project'
20 |
21 | self.activeItemValue = self.getActiveItem(ctx)
22 | if self.activeItemValue:
23 | self.name = None
24 | self.typeC = None
25 |
26 | doc = self.getTargetDoc(prj, 'public.xml')
27 | if not doc:
28 | print('Cannot find public.xml')
29 | return
30 |
31 | self.getValue(doc, 'public.xml', ctx)
32 |
33 | if self.name and self.typeC:
34 | if self.typeC == "string" or self.typeC == "id":
35 | self.value = None
36 | doc = self.getTargetDoc(prj, self.typeC + 's.xml')
37 | self.getValue(doc, self.typeC + 's.xml', ctx)
38 | ctx.displayText("Id: " + self.activeItemValue, "Value: " + self.value, False)
39 | else:
40 | self.jumpToTargetFile(prj, ctx) # Open the target file
41 |
42 | # TODO: dispose docs
43 |
44 |
45 | def getActiveItem(self, ctx):
46 | curItem = ctx.getFocusedView().getActiveFragment().getActiveItem()
47 | if curItem == None:
48 | return None
49 | # hack: only work for 32-bit numbers, may be disabled in the future
50 | activeItemVal = str(hex(curItem.getItemId() & 0xFFFFFFFF))[:-1]
51 | return activeItemVal.lower()
52 |
53 |
54 | def getTargetDoc(self, prj, targetXML):
55 | units = RuntimeProjectUtil.findUnitsByType(prj, IXmlUnit, False)
56 | for unit in units:
57 | if not unit.isProcessed():
58 | unit.process()
59 | if unit.getName() == targetXML:
60 | doc = unit.getDocument()
61 | return doc
62 | return None
63 |
64 |
65 | def getValue(self, doc, targetXML, ctx):
66 | #print(targetXML)
67 | if (targetXML == 'public.xml'):
68 | xmlLists = doc.getElementsByTagName('public');
69 | for i in range(xmlLists.getLength()):
70 | node = xmlLists.item(i)
71 | if(self.activeItemValue == str(node.getAttribute('id'))):
72 | self.name = node.getAttribute('name')
73 | self.typeC = node.getAttribute('type')
74 | return
75 | if (targetXML == 'ids.xml'):
76 | xmlLists = doc.getElementsByTagName('item');
77 | for i in range(xmlLists.getLength()):
78 | node = xmlLists.item(i)
79 | if(self.name == str(node.getAttribute('name'))):
80 | self.value = node.getTextContent()
81 | return
82 | if (targetXML == 'strings.xml'):
83 | xmlLists = doc.getElementsByTagName('string');
84 | for i in range(xmlLists.getLength()):
85 | node = xmlLists.item(i)
86 | if(self.name == str(node.getAttribute('name'))):
87 | self.value = node.getTextContent()
88 | return
89 | print('Cannot find target XML file')
90 |
91 |
92 | def jumpToTargetFile(self, prj, ctx):
93 | unitFilter = UnitFilterByName(self.name + '.xml')
94 | unit = RuntimeProjectUtil.filterUnits(prj, unitFilter).get(0)
95 | if unit:
96 | ctx.openView(unit)
97 | return
98 |
99 |
100 | class UnitFilterByName(IUnitFilter):
101 | def __init__(self, name):
102 | self.name = name
103 | def check(self, unit):
104 | return unit.getName() == self.name
105 |
--------------------------------------------------------------------------------
/scripts/DexListDecompilationEvents.py:
--------------------------------------------------------------------------------
1 | #?description=List a dexdec object (IDexDecompilerUnit) decompilation events stored in the global event queue
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit
4 | from com.pnfsoftware.jeb.core.util import DecompilerHelper
5 | from com.pnfsoftware.jeb.client.api import IScript, IconType, ButtonGroupType
6 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
7 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit, ICodeItem
8 | from com.pnfsoftware.jeb.core.output.text import ITextDocument
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | Note that dexdec's events can be seen in a Decompiler's unit node (Project Explorer view), "Events" tab
13 | """
14 | class DexListDecompilationEvents(IScript):
15 | def run(self, ctx):
16 | prj = ctx.getMainProject()
17 | assert prj, 'Need a project'
18 | for dexdec in prj.findUnits(IDexDecompilerUnit):
19 | print('Listing events for %s:' % dexdec)
20 | for e in dexdec.getGlobalDecompilationEvents():
21 | print(e)
22 |
--------------------------------------------------------------------------------
/scripts/DexListMethods.py:
--------------------------------------------------------------------------------
1 | #?description=List methods of all dex units found in the current project
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
5 | """
6 | Sample script for JEB Decompiler.
7 | """
8 | class DexListMethods(IScript):
9 |
10 | def run(self, ctx):
11 | prj = ctx.getMainProject()
12 | assert prj, 'Need a project'
13 |
14 | # replace IDexUnit by ICodeUnit to find all code units (that includes dex units as well)
15 | for codeUnit in prj.findUnits(IDexUnit):
16 | self.processDex(codeUnit)
17 |
18 | def processDex(self, unit):
19 | for m in unit.getMethods():
20 | print m.getSignature()
21 |
--------------------------------------------------------------------------------
/scripts/DexdecDisableEmulation.py:
--------------------------------------------------------------------------------
1 | #?description=Change the propertis of a dexdec instance programmatically
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code.android import IDexDecompilerUnit
5 | """
6 | Sample script for JEB Decompiler.
7 |
8 | Reference doc to review:
9 | - IPropertyDefinitionManager
10 | - IPropertyManager
11 | """
12 | class DexdecDisableEmulation(IScript):
13 | def run(self, ctx):
14 | prj = ctx.getMainProject()
15 | assert prj, 'Need a project'
16 | u = prj.findUnit(IDexDecompilerUnit)
17 | if u:
18 | # the associated PDM (property definition manager) of a PM (property manager) lists the properties, their types, legal values, etc.
19 | # they are also listed here for reference: https://www.pnfsoftware.com/jeb/manual/engines-configuration/
20 | # other objects can be configured via a PM, including JEB's engines context and its primary GUI client
21 | u.getPropertyManager().setInteger('EmulationSupport', 0) # disable the emulator!
22 |
--------------------------------------------------------------------------------
/scripts/DumpBinaryUnits.py:
--------------------------------------------------------------------------------
1 | #?description=Dump all binary units of the opened project to files on disk
2 | #?shortcut=
3 | import os
4 | from java.io import File
5 | from com.pnfsoftware.jeb.client.api import IScript
6 | from com.pnfsoftware.jeb.core.units import IBinaryUnit
7 | from com.pnfsoftware.jeb.util.io import IO
8 | """
9 | Sample script for JEB Decompiler.
10 |
11 | Dump all binary units of a JEB opened project to files on disk.
12 | Output folder= [HOME]/JEB_PROJECT_BINARY_EXTRACTED
13 | """
14 | class DumpBinaryUnits(IScript):
15 |
16 | def run(self, ctx):
17 | prj = ctx.getMainProject()
18 | assert prj, 'Need a project'
19 |
20 | #OUTDIR = IO.expandPath('~/JEB_PROJECT_BINARY_EXTRACTED')
21 | OUTDIR = ctx.displayFolderSelector('Target folder where the dumped files will be written')
22 | print('=> Dumping binary units of project to directory: %s' % OUTDIR)
23 |
24 | for art in prj.getLiveArtifacts():
25 | for unit in art.getUnits():
26 | self.checkUnit(unit, OUTDIR+'/'+art.getArtifact().getName())
27 |
28 | def checkUnit(self, unit, basename, level=0):
29 | basename2 = basename+'/'+unit.getName()
30 |
31 | unitsize = -1
32 | if isinstance(unit, IBinaryUnit):
33 | unitinput = unit.getInput()
34 | print('Creating dir: %s' % basename)
35 | if not os.path.exists(basename):
36 | os.makedirs(basename)
37 | try:
38 | print('Writing file: %s (%db)' % (basename2, unitinput.getCurrentSize()))
39 | f = File(basename2)
40 | data = IO.readInputStream(unitinput.getStream())
41 | IO.writeFile(f, data, 0, len(data))
42 | except Exception as e:
43 | print('An error occurred: %s' % e)
44 | basename2 = basename2 + '_sub'
45 |
46 | # recurse over children units
47 | for c in unit.getChildren():
48 | self.checkUnit(c, basename2, level + 1)
49 |
--------------------------------------------------------------------------------
/scripts/EditNativeBytes.py:
--------------------------------------------------------------------------------
1 | #?description=Write memory bytes of a native unit
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.util.encoding import Conversion
5 | from com.pnfsoftware.jeb.core.units import INativeCodeUnit
6 | """
7 | Sample script for JEB Decompiler
8 | """
9 | class EditNativeBytes(IScript):
10 |
11 | # ctx:IGraphicalClientContext
12 | def run(self, ctx):
13 | f = ctx.getFocusedFragment()
14 | assert f, 'Need a focused fragment'
15 |
16 | text = ctx.displayQuestionBox("Write byte", "Address:", "")
17 | if not text:
18 | return
19 | addr = int(text, 16)
20 |
21 | text = ctx.displayQuestionBox("Write byte", "Value to write at 0x%X:" % addr, "")
22 | if not text:
23 | return
24 | val = int(text, 16)
25 |
26 | u = f.getUnit()
27 | if not isinstance(u, INativeCodeUnit):
28 | return
29 |
30 | u.undefineItem(addr)
31 | u.getMemory().writeByte(addr, val)
32 | u.notifyGenericChange()
33 |
--------------------------------------------------------------------------------
/scripts/FindMain.py:
--------------------------------------------------------------------------------
1 | #?description=Attempt to find the high-level entry-point of a binary file
2 | #?shortcut=
3 |
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core.units import INativeCodeUnit
6 |
7 | '''
8 | Sample script for JEB Decompiler.
9 |
10 | Search for the high-level entry-point (the main() or similar) of a compiled binary file.
11 | Currently supported: MSVC WinMain/wWinMain x86 and x64
12 |
13 | Requirement: JEB 5.7+
14 | '''
15 | class FindMain(IScript):
16 | def run(self, ctx):
17 | prj = ctx.getMainProject()
18 | u = prj.findUnit(INativeCodeUnit)
19 | if not u:
20 | print('No native code unit')
21 | return
22 |
23 | hlep = u.getHighLevelEntryPointAddress()
24 | if hlep != -1:
25 | print('[NOTE] A high-level entry-point is already set: 0x%X' % hlep)
26 |
27 | # each detection routine returns either None or a tuple (br_to_hlep, hlep, wanted_name)
28 | r = None
29 | if not r:
30 | r = find_hlep_msvc_x86(u)
31 | if not r:
32 | r = find_hlep_msvc_x64(u)
33 | # NOTE: add more detection code here
34 | if not r:
35 | print('Nothing found')
36 | return
37 |
38 | br_to_hlep, hlep, wanted_name = r[0], r[1], r[2]
39 | print('Found high-level entry-point at 0x%X (branched from 0x%X)' % (hlep, br_to_hlep))
40 |
41 | cm = u.getCommentManager()
42 | cm.setInlineComment(cm.memoryToAddress(br_to_hlep), 'Jump to high-level entry-point')
43 |
44 | m = u.getInternalMethod(hlep)
45 | if m and wanted_name:
46 | print('Renaming entry-point to \'%s\'' % wanted_name)
47 | m.setName(wanted_name)
48 |
49 | #------------------------------------------------------------------------------
50 | def find_hlep_msvc_x86(u):
51 | if u.getProcessorName() != 'x86':
52 | return None
53 |
54 | # call __security_init_cookie
55 | # jmp next
56 | ep = u.getEntryPointAddress()
57 | if not check_bytes(u, ep, 'e8 ?? ?? ?? ?? e9 ?? ?? ?? ??'):
58 | return None
59 |
60 | # resolve the jmp target
61 | addr = ep + 5
62 | addr += 5 + u.getMemory().readLEInt(addr + 1)
63 |
64 | # the previous instructions may not have been associated to the routine at addr
65 | m = u.getInternalMethod(addr, False)
66 | if not m:
67 | return None
68 |
69 | cfg = m.getData().getCFG()
70 | br_to_hlep, hlep = -1, -1
71 | for b in cfg:
72 | if b.size() >= 2:
73 | i = b.size() - 2
74 | if b.get(i).getMnemonic() == 'push' and b.get(i + 1).getMnemonic() == 'call':
75 | addr, insn = b.getAddressOfInstruction(i), b.get(i)
76 | if check_bytes(u, addr, '68 ?? ?? ?? ??'):
77 | addr = u.getMemory().readLEInt(addr + 1)
78 | if addr == u.getVirtualImageBase():
79 | addr, insn = b.getAddressOfInstruction(i+1), b.get(i+1)
80 | hlep = insn.getPrimaryBranchAddress(addr)
81 | br_to_hlep = addr
82 | break
83 | if hlep == -1:
84 | return None
85 | return (br_to_hlep, hlep, 'winmain')
86 |
87 | #------------------------------------------------------------------------------
88 | def find_hlep_msvc_x64(u):
89 | if u.getProcessorName() != 'x86_64':
90 | return None
91 |
92 | # sub rsp, xxx
93 | # call _security_init_cookie
94 | # add rsp, xxx
95 | # jmp next
96 | ep = u.getEntryPointAddress()
97 | if not check_bytes(u, ep, '48 83 ec ?? e8 ?? ?? ?? ?? 48 83 c4 ?? e9 ?? ?? ?? ??'):
98 | return None
99 |
100 | # resolve the jmp target
101 | addr = ep + 13
102 | addr += 5 + u.getMemory().readLEInt(addr + 1)
103 |
104 | # the previous instructions may not have been associated to the routine at addr
105 | m = u.getInternalMethod(addr, False)
106 | if not m:
107 | return None
108 |
109 | # search for basic block ending with: lea rcx, [IMAGE_BASE] / call
110 | cfg = m.getData().getCFG()
111 | br_to_hlep, hlep = -1, -1
112 | for b in cfg:
113 | if b.size() >= 2:
114 | i = b.size() - 2
115 | if b.get(i).getMnemonic() == 'lea' and b.get(i + 1).getMnemonic() == 'call':
116 | addr, insn = b.getAddressOfInstruction(i), b.get(i)
117 | if check_bytes(u, addr, '48 8d 0d ?? ?? ?? ??'):
118 | addr += 7 + u.getMemory().readLEInt(addr + 3)
119 | if addr == u.getVirtualImageBase():
120 | addr, insn = b.getAddressOfInstruction(i+1), b.get(i+1)
121 | hlep = insn.getRoutineCall(addr).getTargets().get(0).getAddress()
122 | br_to_hlep = addr
123 | break
124 | if hlep == -1:
125 | return None
126 | return (br_to_hlep, hlep, 'winmain')
127 |
128 | #------------------------------------------------------------------------------
129 | def check_bytes(u, addr, pattern):
130 | pattern = pattern.replace(' ', '')
131 | pattern2 = ''
132 | mask = ''
133 | if len(pattern) % 2 != 0: raise Exception()
134 | for c in pattern:
135 | if c == '?':
136 | mask += '0'
137 | pattern2 += '0'
138 | else:
139 | mask += 'f'
140 | pattern2 += c
141 | import binascii
142 | binpattern = binascii.unhexlify(pattern2)
143 | binmask = binascii.unhexlify(mask)
144 | size = len(binpattern)
145 | data = [-1] * size
146 | for bval, bmask in zip(binpattern, binmask):
147 | x = u.getMemory().readByte(addr)
148 | if (x & ord(bmask)) != ord(bval):
149 | return False
150 | addr += 1
151 | return True
152 |
--------------------------------------------------------------------------------
/scripts/FocusDisassembly.py:
--------------------------------------------------------------------------------
1 | #?description=Focus the first view found that contains a fragment named 'Disassembly', and select and focus that fragment.
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | """
5 | Sample script for JEB Decompiler.
6 | """
7 | class FocusDisassembly(IScript):
8 | def run(self, ctx):
9 | success = focusDisassemblyFragment(ctx)
10 | print('Focused Disassembly fragment: %s' % success)
11 |
12 | def getDisassemblyFragment(view):
13 | for fragment in view.getFragments():
14 | if view.getFragmentLabel(fragment) == 'Disassembly':
15 | return fragment
16 |
17 | def focusDisassemblyFragment(ctx):
18 | for view in ctx.getViews():
19 | fragment = getDisassemblyFragment(view)
20 | if fragment:
21 | view.setFocus()
22 | view.setActiveFragment(fragment)
23 | return True
24 | return False
25 |
--------------------------------------------------------------------------------
/scripts/GUIActionScriptDemo.py:
--------------------------------------------------------------------------------
1 | #?description=Demo how to chain GUI actions without blocking the UI thread.
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from java.lang import Runnable
5 | """
6 | Sample script for JEB Decompiler.
7 |
8 | Demo how to chain GUI actions without blocking the UI thread.
9 |
10 | Refer to GUIActionScriptSkeleton.py for details about scripting GUI actions.
11 | """
12 | CTX = None
13 |
14 | class GUIActionScriptDemo(IScript):
15 | def run(self, ctx):
16 | # globals to be used by all GUI action stubs
17 | global CTX
18 | CTX = ctx
19 |
20 | path = ctx.displayFileOpenSelector('Select a file')
21 | assert path, 'Need a valid file path'
22 |
23 | # close any existing project
24 | if ctx.getMainProject():
25 | ctx.closeMainProject()
26 |
27 | # create a new project, analyze one artifact file
28 | ctx.open(path)
29 |
30 | # give some time for GUI fragments (e.g. disass) to be created and focused
31 | CTX.uiExecuteWithDelay(2000, T1())
32 |
33 | class T1(Runnable):
34 | def run(self):
35 | print(CTX.getViews())
36 |
--------------------------------------------------------------------------------
/scripts/GUIActionScriptSkeleton.py:
--------------------------------------------------------------------------------
1 | #?description=Demo how to chain GUI actions without blocking the UI thread.
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from java.lang import Runnable
5 | """
6 | Sample script for JEB Decompiler.
7 |
8 | Demo how to chain GUI actions without blocking the UI thread.
9 |
10 | Background: the UI thread of the GUI client for JEB is an event-based executor for stubs of code.
11 | Client scripts are meant to execute relatively short actions on the UI thread, and terminate, or
12 | execute more heavy-weight processing on worker threads (e.g. via ctx.executeAsync) and then
13 | terminate. In either scenario, the UI thread is hogged or blocked for the duration of the action.
14 |
15 | How to chain UI actions to mimic behaviors to what higher-level macro programs would do?
16 | Example: we want to create a project, add an artifact, wait for it to be loaded, wait for the
17 | client to create various views and fragments, then select a fragment and navigate to it.
18 |
19 | Although the JEB scripting API is not truly designed to chain UI actions, it is relatively
20 | straight-forward to obtain the behavior by encapsulating chunks of code, and scheduling them on
21 | the UI thread for execution, when required.
22 | """
23 |
24 | CTX = None # com.pnfsoftware.jeb.client.api.IGraphicalClientContext
25 |
26 | class GUIActionScriptSkeleton(IScript):
27 | def run(self, ctx):
28 | global CTX
29 | CTX = ctx
30 | # --> ENTRY POINT
31 | print('A0')
32 | CTX.uiExecute(T1()) # execute A1 asap, return before the execution is finished
33 |
34 | class T1(Runnable):
35 | def run(self):
36 | # --> ACTION 1
37 | print('A1')
38 | CTX.uiExecuteWithDelay(3000, T2()) # execute A2 in +3 seconds, return asap
39 |
40 | class T2(Runnable):
41 | def run(self):
42 | # --> ACTION 2
43 | print('A2')
44 | CTX.uiExecuteBlocking(T3()) # CAREFUL, will block until T3 is fully executed!
45 |
46 | class T3(Runnable):
47 | def run(self):
48 | # --> ACTION 3
49 | print('A3') # done
50 |
--------------------------------------------------------------------------------
/scripts/GenerateFridaSnippetForDex.py:
--------------------------------------------------------------------------------
1 | #?description=Create a Frida hook for the selected Dex method
2 | #?shortcut=
3 |
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core import Artifact
6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, IDexDecompilerUnit
7 |
8 | '''
9 | Python script for JEB Decompiler.
10 |
11 | Frida hook generator for Dex methods. Respect original method names, display effective (renamed) names.
12 |
13 | Forked from https://github.com/cryptax/misc-code/blob/master/jeb/Jeb2Frida.py
14 | '''
15 | class GenerateFridaSnippetForDex(IScript):
16 |
17 | def run(self, ctx):
18 | addr = ctx.getFocusedAddress()
19 | unit = ctx.getFocusedUnit()
20 | if not addr or not unit:
21 | print("Position the caret on a Dex method inside a text fragment")
22 | return
23 |
24 | if isinstance(unit.getParent(), IDexDecompilerUnit):
25 | unit = unit.getParent().getParent() # the parent of dexdec is a dex
26 | elif not isinstance(unit, IDexUnit):
27 | print("Canot retrieve the Dex unit")
28 | return
29 |
30 | # clear the bytecode position if the caret inside a method (as opposed to being on the method's header)
31 | pos = addr.find('+')
32 | if pos >= 0:
33 | addr = addr[:pos]
34 | # retrieve the method object, we'll need that to collect the original and effective (current) names
35 | m = unit.getMethod(addr)
36 | if not m:
37 | print("The selected address does not resolve to a Dex method")
38 | return
39 |
40 | print("Generating Frida snippet for method: %s" % m.getSignature())
41 | addr = m.getSignature(False) # original names
42 |
43 | # original type name (used in the binary)
44 | cl = m.getClassType().getSignature(False, False)
45 |
46 | # original method name (used in the binary)
47 | mname = m.getName(False)
48 | if mname == "":
49 | mname = "$init"
50 |
51 | # original parameter types (used in the binary)
52 | partypes = []
53 | parnames = []
54 | for i, partype in enumerate(m.getParameterTypes()):
55 | partypes.append(partype.getSignature(False, False))
56 | parnames.append("arg%d" % i) # TODO: retrieve the decompiler-provided param names
57 |
58 | no_return = m.getReturnType().isVoid()
59 |
60 | # the tag rendered in the console will use the method's actual names (i.e. the renames if any), not the original names
61 | tag = "%s.%s" % (m.getClassType().getSignature(True, False, False), m.getName(True))
62 |
63 | hook = self.generate(tag, cl, mname, partypes, parnames, no_return)
64 |
65 | snippet = "// Frida hook for %s:\nJava.perform(function() {\n%s});\n" % (m.getSignature(), hook)
66 | print(snippet)
67 |
68 | def generate(self, tag, cl, mname, partypes, parnames, no_return):
69 | hook = ""
70 | hook += " var cl = Java.use('%s');\n" % cl
71 | hook += " var m = cl.%s" % mname
72 |
73 | if partypes:
74 | hook += ".overload("
75 | for i, partype in enumerate(partypes):
76 | if i > 0:
77 | hook += ", "
78 | hook += "'%s'" % partype
79 | hook += ")"
80 | hook += ";\n"
81 |
82 | hook += " m.implementation = function(%s) {\n" % (', '.join(parnames))
83 |
84 | hook += " console.log('[%s] called with:" % tag
85 | if parnames:
86 | for i, parname in enumerate(parnames):
87 | if i > 0:
88 | hook += ", "
89 | hook += " arg%d=' + %s + '" % (i, parname)
90 | hook += "'"
91 | hook += ");\n"
92 |
93 | if no_return:
94 | hook += " this.%s(%s);" % (mname, ', '.join(parnames))
95 | else:
96 | hook += " var ret = this.%s(%s);\n" % (mname, ', '.join(parnames))
97 | hook += " console.log('[%s] returned: ' + ret);\n" % tag
98 | hook += " return ret;"
99 |
100 | hook += "\n };\n"
101 | return hook
102 |
--------------------------------------------------------------------------------
/scripts/GraphDemo1.py:
--------------------------------------------------------------------------------
1 | #?description=Basic use of the displayGraph() API method, which does not make use of the graph extension
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.util.graph import Digraph
5 | """
6 | Sample script for JEB Decompiler.
7 | """
8 | class GraphDemo1(IScript):
9 | def run(self, ctx):
10 | g = Digraph.create().e(0, 1).e(0, 2).e(0, 3).e(1, 0).e(3, 4).e(3, 5).e(4, 6).e(5, 7).done()
11 | ctx.displayGraph('Sample Graph', g)
12 |
--------------------------------------------------------------------------------
/scripts/GraphDemo2.py:
--------------------------------------------------------------------------------
1 | #?description=Advanced use of displayGraph() to display the callgraph
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext, GraphDialogExtensions
4 | from com.pnfsoftware.jeb.core.units import UnitAddress
5 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit, CodeUtil
6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, DalvikCallgraphBuilder
7 | from com.pnfsoftware.jeb.util.graph import Digraph
8 | """
9 | Sample script for JEB Decompiler.
10 | """
11 | class GraphDemo2(IScript):
12 |
13 | def run(self, ctx):
14 | prj = ctx.getMainProject()
15 | assert prj, 'Need a project'
16 |
17 | code = prj.findUnit(ICodeUnit)
18 | assert code, 'Need a code unit'
19 |
20 | b = CodeUtil.createCallgraphBuilder(code)
21 | g = b.buildModel()
22 |
23 | class Ext(GraphDialogExtensions):
24 | #def getLayoutMode(self):
25 | # return GraphDialogExtensions.LayoutMode.FDC_NO_WEIGHT
26 | #def getVertexShape(self, vertexId):
27 | # return GraphDialogExtensions.VertexShape.SQUARE
28 | #def getVertexColor(self, vertexId):
29 | # return 0x0080A0
30 | def processNewVertexName(self, vertexId, newName):
31 | addr = b.getAddressForVertexId(vertexId)
32 | return code.getMethod(addr).setName(newName)
33 | def getUnitAddress(self, vertexId):
34 | addr = b.getAddressForVertexId(vertexId)
35 | if not addr:
36 | return None
37 | return UnitAddress(code, addr)
38 | def getVertexMark(self, vertexId):
39 | addr = b.getAddressForVertexId(vertexId)
40 | return code.getInlineComment(addr) == 'MARKED'
41 | def processVertexMark(self, vertexId, mark):
42 | addr = b.getAddressForVertexId(vertexId)
43 | code.setInlineComment(addr, 'MARKED' if mark else '')
44 | return True
45 |
46 | ctx.displayGraph('Callgraph', g, Ext())
47 |
--------------------------------------------------------------------------------
/scripts/GraphPackagesRelationships.py:
--------------------------------------------------------------------------------
1 | #?description=Build callgraph between user routines and routines belonging to specific packages
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext, GraphDialogExtensions
4 | from com.pnfsoftware.jeb.core.units import UnitAddress, INativeCodeUnit
5 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit, CodeUtil
6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit, DalvikCallgraphBuilder
7 | from com.pnfsoftware.jeb.util.graph import Digraph
8 | """
9 | Sample script for JEB Decompiler.
10 |
11 | Build callgraph between unknown routines (whose name start with 'sub_')
12 | and routines from specific packages (whose names are prefixed by known package names).
13 |
14 | This serves to see relationships between user code and library code.
15 |
16 | Modify PACKAGES_OF_INTEREST below to suit your needs.
17 | """
18 | PACKAGES_OF_INTEREST = ['OpenSSL', 'cURL']
19 |
20 | class GraphPackagesRelationships(IScript):
21 |
22 | def getRootModule(self, label):
23 | if '::' in label:
24 | return label.split('::')[0]
25 | return None
26 |
27 | def run(self, ctx):
28 | prj = ctx.getMainProject()
29 | assert prj, 'Need a project'
30 |
31 | code = prj.findUnit(INativeCodeUnit)
32 | assert code, 'Need a native code unit'
33 |
34 | g = Digraph.create()
35 | model = code.getCodeModel()
36 | cg = model.getCallGraphManager().getGlobalCallGraph()
37 | routines = code.getInternalMethods()
38 |
39 | for srcRtn in routines:
40 | srcName = srcRtn.getName(True)
41 | srcModule = self.getRootModule(srcName)
42 | srcIndex = routines.indexOf(srcRtn)
43 | callees = cg.getCallees(srcRtn, False)
44 | for target in callees:
45 | if not target.isInternal():
46 | continue
47 | targetRtn = code.getInternalMethod(target.getInternalAddress().getAddress(), True)
48 | if not targetRtn:
49 | continue
50 |
51 | targetName = targetRtn.getName(True)
52 | dstModule = self.getRootModule(targetName)
53 | if (srcModule != dstModule) \
54 | and (srcName.startswith('sub_') or targetName.startswith('sub_')) \
55 | and (srcModule in PACKAGES_OF_INTEREST or dstModule in PACKAGES_OF_INTEREST):
56 | targetIndex = routines.indexOf(targetRtn)
57 |
58 | if not g.getVertex(srcIndex):
59 | g.v(srcIndex, None, srcName)
60 | if not g.getVertex(targetIndex):
61 | g.v(targetIndex, None, targetName)
62 | if not g.getEdge(srcIndex, targetIndex):
63 | g.e(srcIndex, targetIndex)
64 |
65 | g.done()
66 |
67 | class Ext(GraphDialogExtensions):
68 | def getUnitAddress(self, vertexId):
69 | # implement navigation
70 | rtn = routines[vertexId]
71 | if not rtn:
72 | return None
73 | addr = rtn.getAddress()
74 | if not addr:
75 | return None
76 | return UnitAddress(code, addr)
77 |
78 | ctx.displayGraph('Packages Callgraph', g, Ext())
79 |
--------------------------------------------------------------------------------
/scripts/GraphRtti.py:
--------------------------------------------------------------------------------
1 | #?description=Display Run-Time Type Information as a graph showing inheritance relationships between classes
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, GraphDialogExtensions
4 | from com.pnfsoftware.jeb.client.api.GraphDialogExtensions import EdgeStyle, VertexShape
5 | from com.pnfsoftware.jeb.core.units import IBinaryUnit
6 | from com.pnfsoftware.jeb.util.graph import Digraph
7 | from com.pnfsoftware.jeb.core.input import IInput
8 | from com.pnfsoftware.jeb.util.io import IO
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | Display class inheritance graph built from Run-Time Type Information extracted by JEB.
13 | This script parses JEB's RTTI text output, provided as 'run-time type information' unit.
14 | Each line follows the pattern:
15 | class BaseClassName : public|private [virtual] ParentClassName1, ...;
16 | """
17 | IGNORE_STD = True # True to ignore C++ std classes (when used as base class)
18 | CLASS_SEPARATOR = ' : '
19 | PARENT_SEPARATOR = ', '
20 |
21 | class GraphRtti(IScript):
22 | def run(self, ctx):
23 |
24 | # retrieve RTTI unit
25 | prj = ctx.getMainProject()
26 | if not prj:
27 | print('Need a project')
28 | return
29 |
30 | units = prj.findUnits(IBinaryUnit)
31 | if not units or len(units) == 0:
32 | print('Need RTTI unit')
33 | return
34 |
35 | rttiUnit = None
36 | for unit in units:
37 | if unit.getName() == 'run-time type information':
38 | rttiUnit = unit
39 | if not rttiUnit:
40 | print('Need RTTI unit')
41 |
42 | data = IO.readInputStream(rttiUnit.getInput().getStream())
43 | rttiText = ''.join(chr(c) for c in data)
44 |
45 | # parsing
46 | g = Digraph.create()
47 | curId = 0
48 | classToId = dict()
49 | virtualEdges = list() # [[childId, parentId]]
50 | lines = rttiText.splitlines()[2:] # skip header
51 | for line in lines:
52 | line = line.strip()[:-1] # beautify
53 | if not line.startswith('class'):
54 | continue
55 | classes = line.split(CLASS_SEPARATOR)
56 | if len(classes) > 2:
57 | print('error: malformed line (%s)' % line)
58 | continue
59 |
60 | # register base class id
61 | baseClassName = classes[0][6:]
62 | if IGNORE_STD and baseClassName.startswith('std::'):
63 | continue
64 | if baseClassName not in classToId.keys():
65 | g.v(curId, None, baseClassName)
66 | classToId[baseClassName] = curId
67 | curId+=1
68 | print('baseClassName=%s' % baseClassName)
69 |
70 | # add edges for each parent, if any
71 | if len(classes) == 1:
72 | continue
73 | for parent in classes[1].split(PARENT_SEPARATOR):
74 | parentStr = parent.split()
75 | if len(parentStr) < 2:
76 | print('error: malformed line (%s)' % line)
77 | continue
78 | isPublic = parentStr[0] == 'public'
79 | isVirtual = parentStr[1] == 'virtual'
80 | parentStartIndex = 7 if isPublic else 8
81 | parentStartIndex += 8 if isVirtual else 0
82 | parentName = parent[parentStartIndex:]
83 |
84 | print(' parentName=%s, isPublic = %d, isVirtual = %d' % (parentName, isPublic, isVirtual))
85 |
86 | if parentName not in classToId.keys():
87 | g.v(curId, None, parentName)
88 | classToId[parentName] = curId
89 | curId+=1
90 |
91 | g.e(classToId[baseClassName], classToId[parentName])
92 | if isVirtual:
93 | virtualEdges.append([classToId[baseClassName], classToId[parentName]])
94 |
95 | class Ext(GraphDialogExtensions):
96 | def getEdgeStyle(self, vertexId0, vertexId1):
97 | if [vertexId0, vertexId1] in virtualEdges:
98 | # dashed edges to represent virtual inheritance
99 | return EdgeStyle.DASHED
100 | return EdgeStyle.SOLID
101 | def getVertexShape(self, vertexId):
102 | return VertexShape.SQUARE_FILLED
103 |
104 | g.done()
105 | ctx.displayGraph('RTTI Class Relationship Graph', g, Ext())
106 |
--------------------------------------------------------------------------------
/scripts/JavaASTCreateMethodRef.py:
--------------------------------------------------------------------------------
1 | #?description=Show how the Java AST API can be used to modify and create elements in a decompiled syntax tree
2 | #?shortcut=
3 | import time
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit
6 | """
7 | Sample script for JEB Decompiler.
8 |
9 | The script shows how to use the Java factory to create an external method reference (also available for fields),
10 | create a new statement (here, a call to 'new String("...")'), and replace an arbitrary selected statement
11 | (index 0 in the currently selected method) by the new statement.
12 |
13 | - Open an APK/DEX, decompile any class or method
14 | - In the Decompiled view, position the caret somewhere in a method
15 | - Execute the script
16 | """
17 | class JavaASTCreateMethodRef(IScript):
18 |
19 | def run(self, ctx):
20 | # retrieve the currently active UI fragment (make sure to select a Decompiled Java fragment)
21 | f = ctx.getFocusedFragment()
22 | assert f, 'Need a focused fragment'
23 |
24 | unit = f.getUnit()
25 | assert isinstance(unit, IJavaSourceUnit), 'Need a java unit'
26 |
27 | # a DEX-style address: TYPENAME->METHODNAME(PARAMTYPES)RETTYPE+OFFSET
28 | addr = f.getActiveAddress()
29 |
30 | # IDexDecompilerUnit
31 | dexdec = unit.getParent()
32 |
33 | pos = addr.find('+')
34 | if pos >= 0: addr = addr[:pos]
35 |
36 | # retrieve the already decompiled IJavaMethod on caret
37 | _m = dexdec.getMethod(addr)
38 |
39 | # method body...
40 | _blk = _m.getBody()
41 | # we pick the first statement
42 | _stm0 = _blk.get(0)
43 | print('Will replace statement: "%s"' % _stm0)
44 |
45 | # IJavaFactories
46 | self.jfactory = unit.getFactories()
47 |
48 | # now, replace that first method statement by a call to 'new String("...")'
49 | if self.replaceStatement(_blk, _stm0):
50 | unit.notifyGenericChange()
51 |
52 |
53 | def replaceStatement(self, parent, e):
54 | m = self.jfactory.createMethodReference('Ljava/lang/String;->(Ljava/lang/String;)V', False)
55 | t = self.jfactory.getTypeFactory().createType('Ljava/lang/String;')
56 | args = [self.jfactory.getConstantFactory().createString('FOOBAR__' + str(time.time()))]
57 | stm = self.jfactory.createNew(t, m, args)
58 | return parent.replaceSubElement(e, stm)
59 |
--------------------------------------------------------------------------------
/scripts/JavaASTDemo.py:
--------------------------------------------------------------------------------
1 | #?description=Show how to navigate and dump Java AST trees
2 | #?shortcut=
3 | import os
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit
6 | """
7 | Sample script for JEB Decompiler.
8 | """
9 | class JavaASTDemo(IScript):
10 | def run(self, ctx):
11 | prj = ctx.getMainProject()
12 | assert prj, 'Need a project'
13 |
14 | for unit in prj.findUnits(IJavaSourceUnit):
15 | c = unit.getClassElement()
16 | for m in c.getMethods():
17 | self.displayTree(m)
18 |
19 | def displayTree(self, e, level=0):
20 | print('%s%s @ 0x%X' % (level*' ', e.getElementType(), e.getPhysicalOffset()))
21 | if e:
22 | elts = e.getSubElements()
23 | for e in elts:
24 | self.displayTree(e, level+1)
25 |
--------------------------------------------------------------------------------
/scripts/JavaASTTags.py:
--------------------------------------------------------------------------------
1 | #?description=Show how to "tag" elements of an AST tree, and later on retrieve those tags from the Java text document output (referred to as "marks").
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IconType, ButtonGroupType
4 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
5 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit
6 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit, ICodeItem
7 | from com.pnfsoftware.jeb.core.output.text import ITextDocument
8 | from com.pnfsoftware.jeb.core.units.code.java import IJavaConstant
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | This script shows how to "tag" elements of an AST tree, and later on retrieve
13 | those tags from the Java text document output (referred to as "marks").
14 |
15 | This code looks for Java units, and tags String contants containing the word
16 | 'html'. Output example:
17 |
18 | ...
19 |
20 | ...
21 | => Marks:
22 | 17:59 - htmlTag (Potential HTML code found)
23 |
24 | Tags are persisted in JDB2 database files.
25 |
26 | Note: tags are specific to Java units. However, marks are not (they are
27 | specific to text documents). The Java plugin simply renders tags as text
28 | marks. This example demonstrates usage of tags in that context.
29 |
30 | Marks are not displayed by the desktop GUI client.
31 | It is up to third-party code (clients, plugins, or scripts) to display them.
32 |
33 | Revision note: Script updated on April 12 2022.
34 | """
35 | class JavaASTTags(IScript):
36 |
37 | def run(self, ctx):
38 | prj = ctx.getMainProject()
39 | assert prj, 'Need a project'
40 |
41 | for unit in prj.findUnits(IJavaSourceUnit):
42 | self.processClassTree(unit.getClassElement())
43 | doc = unit.getSourceDocument()
44 | javaCode, formattedMarks = self.formatTextDocument(doc)
45 | #print(javaCode)
46 | if(formattedMarks):
47 | print('=> Marks:')
48 | print(formattedMarks)
49 |
50 | def processClassTree(self, e_class):
51 | for e in e_class.getMethods():
52 | self.processEltTree(e)
53 |
54 | def processEltTree(self, e):
55 | if e:
56 | self.analyzeNode(e)
57 | elts = e.getSubElements()
58 | for e in elts:
59 | self.processEltTree(e)
60 |
61 | # demo
62 | def analyzeNode(self, e):
63 | if isinstance(e, IJavaConstant):
64 | if e.isString():
65 | if e.getString().find('html') >= 0:
66 | print('TAGGING: %s' % e)
67 | e.addTag('htmlTag', 'Potential HTML code found')
68 |
69 | def formatTextDocument(self, doc):
70 | javaCode, formattedMarks = '', ''
71 | # retrieve the entire document -it's a source file,
72 | # no need to buffer individual parts. 10 MLoC is enough
73 | alldoc = doc.getDocumentPart(0, 10000000)
74 | for lineIndex, line in enumerate(alldoc.getLines()):
75 | javaCode += line.getText().toString() + '\n'
76 | for mark in line.getMarks():
77 | # the mark name is the tag attribute's key
78 | if mark.getName() == 'htmlTag':
79 | # 0-based line and column indexes
80 | # the mark object is the tag attribute's value
81 | formattedMarks += '%d:%d %s\n' % (lineIndex, mark.getOffset(), mark.getObject())
82 | return javaCode, formattedMarks
83 |
--------------------------------------------------------------------------------
/scripts/JavaListIdentifiers.py:
--------------------------------------------------------------------------------
1 | #?description=Enumerate the IJavaIdentifiers (parameters, local vars) of IJavaMethod objects of a decompiled IJavaClass. Rename some identifiers. List all identifiers.
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit
5 | """
6 | Sample script for JEB Decompiler.
7 |
8 | Enumerate the IJavaIdentifiers (parameters, local vars) of IJavaMethod objects of a decompiled IJavaClass. Rename some identifiers. List all identifiers
9 | """
10 | class JavaListIdentifiers(IScript):
11 |
12 | def run(self, ctx):
13 | prj = ctx.getMainProject()
14 | assert prj, 'Need a project'
15 |
16 | f = ctx.getFocusedFragment()
17 | assert f, 'Need a focused fragment'
18 |
19 | # assume a fragment is focused, assumed it is backed by an IUnit
20 | unit = f.getUnit()
21 | if not isinstance(unit, IJavaSourceUnit): return
22 |
23 | # assume the unit is an IJavaSourceUnit
24 | c = unit.getClassElement()
25 |
26 | # 1) DEMO: rename some method identifiers
27 | # enumerate all methods in the class (NOTE: nested classes are not enumerated, this is just a demo script)
28 | idx = 0
29 | for m in c.getMethods():
30 | identifiers = m.getIdentifierManager().getIdentifiers()
31 | print('METHOD: %s: identifiers=%s' % (m, identifiers))
32 | for ident in identifiers:
33 | print(' current=%s original=%s debug=%s' % (unit.getIdentifierName(ident), ident.getName(), ident.getDebugName()))
34 |
35 | # rename all non-this identifiers (including param names) that do not carry a debug name
36 | if ident.getName() != 'this' and ident.getDebugName() == None:
37 | newName = 'RENAMED_%d' % idx
38 | idx += 1
39 | print(' -> renaming to %s' % newName)
40 | unit.setIdentifierName(ident, newName)
41 |
42 | # 2) DEMO: note that all identifiers are uniquely identified by their CodeCoordinates
43 | # they can be enumerated via IDexUnit (the parent of an IDexDecompilerUnit, itself parent of all IJavaSourceUnit)
44 | dexdec = unit.getParent()
45 | dex = dexdec.getParent()
46 | print('All renamed identifiers: %s' % dex.getRenamedIdentifiers())
47 |
--------------------------------------------------------------------------------
/scripts/JavaRenameField1.py:
--------------------------------------------------------------------------------
1 | #?description=Rename a Java field to its source variable's name, in a field assignment statement.
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDexField
5 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit
6 | from com.pnfsoftware.jeb.core.units.code.java import IJavaInstanceField, IJavaAssignment, IJavaIdentifier
7 | """
8 | Sample script for JEB Decompiler.
9 |
10 | Rename a Java field to its source variable's name, in a field assignment statement.
11 |
12 | In a decompiled Java method, place the caret on the target object field.
13 | Example: this.field3 = blah;
14 | ^^^^ caret here
15 | """
16 | class JavaRenameField1(IScript):
17 | def run(self, ctx):
18 | # must be a GUI client
19 | prj = ctx.getMainProject()
20 | if not isinstance(ctx, IGraphicalClientContext):
21 | return
22 |
23 | # retrieve the focused text fragment
24 | fragment = ctx.getFocusedFragment()
25 | if not fragment:
26 | return
27 |
28 | # focused fragment must be decompiled Java, underlying unit is of type IJavaSourceUnit
29 | ast_unit = fragment.getUnit()
30 | if not isinstance(ast_unit, IJavaSourceUnit):
31 | return
32 | self.dex = ast_unit.getDecompiler().getDex()
33 |
34 | # retrieve the active (highlighted) item, which must be an object field
35 | item = fragment.getActiveItem()
36 | if not item:
37 | return
38 |
39 | # retrieve the underlying IDexField object
40 | o = ast_unit.getItemObject(item.getItemId())
41 | if not isinstance(o, IDexField):
42 | return
43 | self.target_field = o
44 |
45 | # walk the methods's AST tree, look for assignments to the target field
46 | for m in ast_unit.getClassElement().getMethods():
47 | self.processASTMethod(None, m)
48 |
49 | def processASTMethod(self, parent, e):
50 | if isinstance(e, IJavaAssignment) and isinstance(e.getRight(), IJavaIdentifier) and isinstance(e.getLeft(), IJavaInstanceField):
51 | dst, src = e.getLeft(), e.getRight()
52 | # perform the renaming
53 | ident_name = src.getName()
54 | fsig = dst.getField().getSignature()
55 | if self.dex.getField(fsig) == self.target_field:
56 | self.target_field.setName(ident_name)
57 | for subelt in e.getSubElements():
58 | self.processASTMethod(e, subelt)
59 |
--------------------------------------------------------------------------------
/scripts/JavaRenameField2.py:
--------------------------------------------------------------------------------
1 | #?description=Rename a Java field to its source variable's name, in a field assignment statement.
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit
5 | from com.pnfsoftware.jeb.core.units.code.java import IJavaInstanceField, IJavaAssignment, IJavaIdentifier
6 | """
7 | Sample script for JEB Decompiler.
8 |
9 | Rename a Java field to its source variable's name, in a field assignment statement.
10 |
11 | Demo for ITextFragment.getDocumentObjectsAtCaret()
12 | Requires JEB 4.21 or above
13 | """
14 | class JavaRenameField2(IScript):
15 | def run(self, ctx):
16 | # must be a GUI client
17 | prj = ctx.getMainProject()
18 | if not isinstance(ctx, IGraphicalClientContext):
19 | return
20 |
21 | # retrieve the focused text fragment
22 | fragment = ctx.getFocusedFragment()
23 | if not fragment:
24 | return
25 |
26 | # focused fragment must be decompiled Java, underlying unit is of type IJavaSourceUnit
27 | ast_unit = fragment.getUnit()
28 | if not isinstance(ast_unit, IJavaSourceUnit):
29 | return
30 | dex = ast_unit.getDecompiler().getDex()
31 |
32 | # ITextFragment.getDocumentObjectsAtCaret() is key to this demo script
33 | # this API function retrieves a stack of unit objects relating to the text element where the caret is currently positioned
34 | # these objects are unit-specific; in the case of an IJavaSourceUnit object, they are IJavaElement objects (AST objects)
35 | astobjstk = fragment.getDocumentObjectsAtCaret()
36 | if len(astobjstk) < 2:
37 | return
38 | ast0 = astobjstk[-1]
39 | ast1 = astobjstk[-2]
40 |
41 | # we want: some_object.some_field = some_var
42 | # ^ (the caret is supposed to highlight the field item)
43 | if not isinstance(ast0, IJavaInstanceField):
44 | return
45 | if not isinstance(ast1, IJavaAssignment):
46 | return
47 | if not isinstance(ast1.getRight(), IJavaIdentifier):
48 | return
49 |
50 | # perform the renaming
51 | ident_name = ast1.getRight().getName()
52 | fsig = ast0.getField().getSignature()
53 | dex.getField(fsig).setName(ident_name)
54 |
--------------------------------------------------------------------------------
/scripts/JumpTo.py:
--------------------------------------------------------------------------------
1 | #?description=
2 | #?shortcut=
3 | #?nolist
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
6 | """
7 | Sample script for JEB Decompiler.
8 |
9 | - how a script can be invoked after a cmdline-provided file has been processed by the JEB UI client
10 | - currently, this script simply searches for a Dex code unit, attempts to find a disassembly fragment for it, and navigate to the cmdline-provided address
11 |
12 | How to use:
13 | $ jeb_startup_script --script=ScriptPath -- InputFile AddressToJumpTo
14 |
15 | This script can also be used when invoking the JEB UI client via the URI handler 'jeb:'
16 | Example:
17 | - drop this script in your JEB folder scripts/ directory
18 | - open a browser and navigate to the URL: jeb:--script%3DJumpTo.py+--+https%3A%2F%2Fwww.pnfsoftware.com%2Fz.apk+Lcom%2Fpnfsoftware%2Fraasta%2FCoordinatesE6%3B
19 | """
20 | class JumpTo(IScript):
21 | def run(self, ctx):
22 | if len(ctx.getArguments()) < 2:
23 | return
24 |
25 | prj = ctx.getMainProject()
26 | assert prj, 'Need a project'
27 |
28 | # arg[0] is the InputFile
29 | addr = ctx.getArguments()[1]
30 | print('Will jump to: %s' % addr)
31 |
32 | dexunit = prj.findUnit(IDexUnit)
33 | if dexunit:
34 | f = ctx.findFragment(dexunit, 'Disassembly', True)
35 | if f:
36 | f.setActiveAddress(addr)
37 |
--------------------------------------------------------------------------------
/scripts/JumpToAndroidComponent.py:
--------------------------------------------------------------------------------
1 | #?description=Jump from an activity name (selected in the Android XML Manifest) to its corresponding bytecode definition in the DEX disassembly fragment.
2 | #?shortcut=
3 | #?nolist
4 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext, IUnitView
5 | from com.pnfsoftware.jeb.core.units import IUnit, IXmlUnit
6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
7 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
8 | """
9 | Sample script for JEB Decompiler.
10 |
11 | !!! SAME AS DexJumpToActivity.py !!!
12 |
13 | This JEB UI script allows the user to jump from an activity name (selected in the Android XML
14 | Manifest) to its corresponding bytecode definition in the DEX disassembly fragment.
15 | """
16 | class JumpToAndroidComponent(IScript):
17 | def run(self, ctx):
18 | if not isinstance(ctx, IGraphicalClientContext):
19 | print('This script must be run within a graphical client')
20 | return
21 |
22 | fragment = ctx.getFocusedView().getActiveFragment()
23 | if type(fragment.getUnit()) is IXmlUnit:
24 | print('Select the Manifest XML view')
25 | return
26 |
27 | aname = fragment.getActiveItemAsText()
28 | if not aname:
29 | print('Select the activity name')
30 | return
31 |
32 | # activity name is relative to the package name
33 | if aname.startswith('.'):
34 | # unit is the Manifest, of type IXmlUnit; we can retrieve the XML document
35 | # note: an alternate way would be to retrieve the top-level IApkUnit, and use getPackageName()
36 | pname = fragment.getUnit().getDocument().getElementsByTagName("manifest").item(0).getAttribute("package")
37 | #print('Package name: %s' % pname)
38 | aname = pname + aname
39 |
40 | print('Activity name: %s' % aname)
41 |
42 | addr = 'L' + aname.replace('.', '/') + ';'
43 | print('Target address: %s' % addr)
44 |
45 | dexunit = ctx.getMainProject().findUnit(IDexUnit)
46 |
47 | f = ctx.findFragment(dexunit, 'Disassembly', True)
48 | if f:
49 | f.setActiveAddress(addr)
50 |
--------------------------------------------------------------------------------
/scripts/ListCrossReferences.py:
--------------------------------------------------------------------------------
1 | #?description=Lists all cross-references to the currently active item using a generic ActionXrefsData object
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.actions import ActionContext
5 | from com.pnfsoftware.jeb.core.actions import ActionXrefsData
6 | from com.pnfsoftware.jeb.core.actions import Actions
7 | """
8 | Sample script for JEB Decompiler.
9 |
10 | This script lists xrefs using the most generic way, that is, via Actions.QUERY_XREFS.
11 | Note that some units offer specialized ways to query cross-reference.
12 | Example: IDexUnit's getCrossReferences() and getReferenceManager()
13 | """
14 | class ListCrossReferences(IScript):
15 | def run(self, ctx):
16 | unit = ctx.getFocusedUnit()
17 | assert unit, 'Need a focused unit fragment'
18 | print(unit.getFormatType())
19 |
20 | current_addr = ctx.getFocusedAddress()
21 | print(current_addr)
22 |
23 | current_item = ctx.getFocusedItem()
24 | print(current_item)
25 |
26 | data = ActionXrefsData()
27 | if unit.prepareExecution(ActionContext(unit, Actions.QUERY_XREFS, 0 if not current_item else current_item.getItemId(), current_addr), data):
28 | for xref_addr in data.getAddresses():
29 | print(xref_addr)
30 |
--------------------------------------------------------------------------------
/scripts/ListDexMethodsWithXor.py:
--------------------------------------------------------------------------------
1 | #?description=List dex methods making use of xor instructions
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
5 | """
6 | Sample script for JEB Decompiler.
7 | """
8 | class ListDexMethodsWithXor(IScript):
9 |
10 | def run(self, ctx):
11 | prj = ctx.getMainProject()
12 | assert prj, 'Need a project'
13 |
14 | dex = prj.findUnit(IDexUnit)
15 | assert dex, 'Need a dex unit'
16 |
17 | cnt = 0
18 | for m in dex.getMethods():
19 | if m.isInternal():
20 | ci = m.getData().getCodeItem()
21 | if ci and self.checkMethod(ci):
22 | print(m.getSignature(True, False))
23 | cnt += 1
24 | print('Found %d methods' % cnt)
25 |
26 | def checkMethod(self, ci):
27 | for insn in ci.getInstructions():
28 | if insn.toString().find('xor-') >= 0:
29 | return True
30 | return False
31 |
--------------------------------------------------------------------------------
/scripts/ListOverrides.py:
--------------------------------------------------------------------------------
1 | #?description=Lists overrides (in the generic terms) of the currently active method or field using a generic ActionOverridesData object
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.actions import Actions, ActionContext, ActionOverridesData
5 | """
6 | Sample script for JEB Decompiler.
7 | """
8 | class ListOverrides(IScript):
9 | def run(self, ctx):
10 | unit = ctx.getFocusedUnit()
11 | assert unit, 'Need a focused unit fragment'
12 |
13 | current_item = ctx.getFocusedItem()
14 | assert current_item, 'Need a focused item'
15 |
16 | data = ActionOverridesData()
17 | if unit.prepareExecution(ActionContext(unit, Actions.QUERY_OVERRIDES, current_item.getItemId(), None), data):
18 | for a in data.getAddresses():
19 | print('Found method: %s' % a)
20 |
--------------------------------------------------------------------------------
/scripts/ListRenamedCodeItems.py:
--------------------------------------------------------------------------------
1 | #?description=List renamed code items (classes, methods, fields)
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit
5 | """
6 | Sample script JEB Decompiler.
7 | """
8 | class ListRenamedCodeItems(IScript):
9 | def run(self, ctx):
10 | prj = ctx.getMainProject()
11 | assert prj, 'Need a project'
12 | units = prj.findUnits(ICodeUnit)
13 | cnt = 0
14 | for unit in units:
15 | for o in unit.getClasses():
16 | if o.isRenamed():
17 | print('Class renamed: %s from %s' % (o.getName(), o.getName(False)))
18 | cnt += 1
19 | for o in unit.getMethods():
20 | if o.isRenamed():
21 | print('Method renamed: %s from %s' % (o.getName(), o.getName(False)))
22 | cnt += 1
23 | for o in unit.getFields():
24 | if o.isRenamed():
25 | print('Field renamed: %s from %s' % (o.getName(), o.getName(False)))
26 | cnt += 1
27 | print('Items renamed: %d' % cnt)
28 |
--------------------------------------------------------------------------------
/scripts/ListUnits.py:
--------------------------------------------------------------------------------
1 | #?description=List all units of the currently opened project
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units import IBinaryUnit
5 | """
6 | Sample script for JEB Decompiler.
7 | """
8 | class ListUnits(IScript):
9 |
10 | def run(self, ctx):
11 | prj = ctx.getMainProject()
12 | assert prj, 'Need a project'
13 |
14 | print('=> Listing units int project "%s":' % prj.getName())
15 | for art in prj.getLiveArtifacts():
16 | for unit in art.getUnits():
17 | self.checkUnit(unit)
18 |
19 | def checkUnit(self, unit, level=0):
20 | unitsize = -1
21 | if isinstance(unit, IBinaryUnit):
22 | unitinput = unit.getInput()
23 | # use the input
24 | # ...
25 | unitsize = unitinput.getCurrentSize()
26 | s = ' ' * level + unit.getName()
27 | if unitsize >= 0:
28 | s += ' (%d bytes)' % unitsize
29 | print(s)
30 |
31 | # recurse over children units
32 | for c in unit.getChildren():
33 | self.checkUnit(c, level + 1)
34 |
--------------------------------------------------------------------------------
/scripts/ListenToDexChangeEvents.py:
--------------------------------------------------------------------------------
1 | #?description=Listen to IDexUnit-emitted change events, and report comment updates in a pop-up window
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.events import JebEvent, J
5 | from com.pnfsoftware.jeb.core.units import IUnit, UnitChangeEventData
6 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
7 | from com.pnfsoftware.jeb.util.events import IEventListener
8 | """
9 | Sample script JEB Decompiler.
10 |
11 | This script shows how to listen to unit-emitted UnitChange events.
12 | Specifically, the script sets up a listener for changes emitted by a DEX unit.
13 | Refer to IDexUnit and UnitChangeEventData API documentation for details.
14 |
15 | Run the script a second time to remove all listeners
16 | """
17 | class ListenToDexChangeEvents(IScript):
18 |
19 | def run(self, ctx):
20 | prj = ctx.getMainProject()
21 | assert prj, 'Need a project'
22 |
23 | dex = prj.findUnit(IDexUnit)
24 | assert dex, 'Need a dex unit'
25 |
26 | # remove stale listeners a previous execution of this script may have added
27 | for listener in dex.getListeners():
28 | # note: a check isinstance(listener, SampleListener) will not work here
29 | # since class objects are different every time the script is run
30 | if hasattr(listener, 'IN_SCRIPT'):
31 | dex.removeListener(listener)
32 | print('Stopped listening to UnitChange events on: %s' % dex)
33 | return
34 |
35 | # add a fresh listener
36 | dex.addListener(SampleListener(ctx))
37 | print('Listening to UnitChange events on: %s' % dex)
38 |
39 |
40 | class SampleListener(IEventListener):
41 | def __init__(self, ctx):
42 | self.ctx = ctx
43 | self.IN_SCRIPT = 1
44 |
45 | def onEvent(self, e):
46 | if isinstance(e, JebEvent) and e.type == J.UnitChange and e.data != None:
47 | print('++++ %s' % e.data)
48 | # demo: pick out CommentUpdate changes - refer to UnitChangeEventData for other types
49 | if e.data.type == UnitChangeEventData.CommentUpdate:
50 | msg = 'New comment at %s (unit %s):\nValue:"%s"\nPrevious:"%s"' % (e.data.location, e.data.target, e.data.value, e.data.previousValue)
51 | self.ctx.displayMessageBox('Comment update', msg, None, None)
52 |
--------------------------------------------------------------------------------
/scripts/PdfListStreams.py:
--------------------------------------------------------------------------------
1 | #?description=Use the PDF plugin to enumerate and dump decoded stream documents stored in the Stream sub-units of a parsed PDF unit
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units import UnitUtil, WellKnownUnitTypes
5 | from com.pnfsoftware.jeb.core.output.text import TextDocumentUtil
6 | """
7 | Sample script for JEB Decompiler.
8 |
9 | This script relies on the PDF plugin to enumerate and dump decoded stream documents stored in the Stream sub-units of a parsed PDF unit.
10 | The PDF plugin does not implement a specific sub-interface of IUnit (API), mostly because it is an open-source plugin, available on GitHub.
11 | The script below uses hardcoded unit types and document types to retrieve the objects to be dumped.
12 | An alternative is to use proper PDF plugin types directly, eg, com.pnf.plugin.pdf.unit.IPdfUnit
13 | """
14 | class PdfListStreams(IScript):
15 |
16 | def run(self, ctx):
17 | # retrieve the primary unit (first unit of first artifact, assume it exists)
18 | prj = ctx.getMainProject()
19 | assert prj, 'Need a project'
20 |
21 | unit = prj.getLiveArtifact(0).getUnits().get(0)
22 | if unit.getFormatType() != WellKnownUnitTypes.typePdf:
23 | raise Exception('Expected a PDF file')
24 |
25 | # [OPTIONAL] refer to https://github.com/pnfsoftware/jeb-plugin-pdf/tree/master/src/main/java/com/pnf/plugin/pdf
26 | # the unit retrieved is of the IPdfUnit type, and has additional methods, eg getStatistics() provide a PdfSTatistics object
27 | print 'Encrypted:', unit.getStatistics().isEncrypted()
28 |
29 | # process all PDF Stream units
30 | for unit in UnitUtil.findDescendantsByFormatType(unit, 'Stream'):
31 | # the pdf plugin is lazy, make sure to process sub-units before retrieving data
32 | if not unit.isProcessed():
33 | unit.process()
34 |
35 | # retrieve the 'Decoded Stream' text document
36 | for pres in unit.getFormatter().getDocumentPresentations():
37 | if pres.getLabel() == 'Decoded Stream':
38 | doc = pres.getDocument()
39 | text = TextDocumentUtil.getText(doc)
40 | print '%s: %s' % (unit.getName(), text[:50] + '...') # TODO: eg, dump text to file(s)
41 | doc.dispose()
42 |
--------------------------------------------------------------------------------
/scripts/PrintNativeRoutineIR.py:
--------------------------------------------------------------------------------
1 | #?description=Retrieve and print out the IR (Intermediate Representation) of a routine decompiled by GENDEC
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units import INativeCodeUnit
5 | from com.pnfsoftware.jeb.core.units.code import IDecompilerUnit, DecompilationContext
6 | from com.pnfsoftware.jeb.core.units.code.asm.decompiler import INativeSourceUnit
7 | from com.pnfsoftware.jeb.core.util import DecompilerHelper
8 | """
9 | Sample script for JEB Decompiler.
10 |
11 | ===> How to use:
12 | Two modes:
13 | - Using the UI desktop client:
14 | - load a binary file into JEB
15 | - make sure GlobalAnalysis for code plugins is enabled (it is by default)
16 | - then run the script: File, Scripts, Run...
17 | - the script will process your loaded executable
18 | - Using the command line:
19 | - run like: jeb_wincon.bat -c --script= --
20 | - the script will create a JEB project and process the file provided on the command line
21 |
22 | ===> What is it:
23 | This script demonstrates how to retrieve and print out the Intermediate Representation of a decompiled routine.
24 |
25 | ===> Additional references:
26 | - reference blog post: https://www.pnfsoftware.com/blog/jeb-native-pipeline-intermediate-representation/
27 | - highly recommended (else you will have much difficulty building upon the code below): follow the tutorials on www.pnfsoftware.com/jeb/devportal
28 | - for Native code and Native Decompilers: the com.pnfsoftware.jeb.core.units.code.asm package and sub-packages
29 | - see API documentation at www.pnfsoftware.com/jeb/apidoc: Native code unit and co, Native decompiler unit and co.
30 |
31 | Comments, questions, needs more details? message on us on Slack or support@pnfsoftware.com -- Nicolas Falliere
32 | """
33 | class PrintNativeRoutineIR(IScript):
34 | def run(self, ctx):
35 | # retrieve the current project or create one and load the input file
36 | prj = ctx.getMainProject()
37 | if not prj:
38 | argv = ctx.getArguments()
39 | if len(argv) < 1:
40 | print('No project found, please provide an input binary')
41 | return
42 |
43 | self.inputFile = argv[0]
44 | print('Processing ' + self.inputFile + '...')
45 | ctx.open(self.inputFile)
46 | prj.getMainProject()
47 |
48 | # retrieve the primary code unit (must be the result of an EVM contract analysis)
49 | unit = prj.findUnit(INativeCodeUnit)
50 | if not unit:
51 | print('No native code unit found')
52 | return
53 | print('Native code unit: %s' % unit)
54 |
55 | # GlobalAnalysis is assumed to be on (default)
56 | decomp = DecompilerHelper.getDecompiler(unit)
57 | if not decomp:
58 | print('No decompiler unit found')
59 | return
60 |
61 | # retrieve a handle on the method we wish to examine
62 | method = unit.getInternalMethods().get(0)
63 |
64 | ctx = DecompilationContext(IDecompilerUnit.FLAG_KEEP_IR);
65 | decm = decomp.decompile(method, ctx)
66 | if not decm:
67 | print('Routine was not decompiled')
68 | return
69 |
70 | # IDecompiledMethod
71 | print(decm)
72 |
73 | ircfg = decm.getIRContext().getCfg()
74 | # CFG object reference, see package com.pnfsoftware.jeb.core.units.code.asm.cfg
75 | print("+++ IR-CFG for %s +++" % method)
76 | print(ircfg.format())
77 |
--------------------------------------------------------------------------------
/scripts/PrintOutDartInfo.py:
--------------------------------------------------------------------------------
1 | #?description=Basic demo for the API to access processed Dart AOT snapshots unit
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit
5 | from com.pnfsoftware.jeb.core.units.code.dart import IDartAotUnit
6 | """
7 | Sample script for JEB Decompiler.
8 |
9 | Find a Dart AOT Snapshots unit (generated by the Dart AOT Snapshots processor plugin),
10 | and use the API to print out basic snapshot information and generate the primary pool.
11 | """
12 | class PrintOutDartInfo(IScript):
13 | def run(self, ctx):
14 | prj = ctx.getMainProject()
15 | u = prj.findUnit(IDartAotUnit)
16 | if not u: return
17 | print('Found a Dart AOT unit: %s' % u)
18 |
19 | # snapshot is of type IDartAotSnapshotInfo
20 | snap = u.getIsolateSnapshotInfo()
21 | print('Used Dart SDK version %s' % snap.getVersionTag())
22 | print('Isolate: %s' % snap)
23 |
24 | # pool= list of nulls, longs, and IDartInternalObject
25 | pool = u.generatePrimaryPool()
26 | print('%d entries in the main pool' % len(pool))
27 |
--------------------------------------------------------------------------------
/scripts/ProcessFile.py:
--------------------------------------------------------------------------------
1 | #?description=Open and process a file into a JEB project.
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | """
5 | Sample script for JEB Decompiler.
6 | """
7 | class ProcessFile(IScript):
8 | def run(self, ctx):
9 | # if run in headless mode, you could instead use ctx.getArguments() to retrieve the input file
10 | # if ctx is IGraphicalClientContext (assumed to be the case here), we display a file selector
11 | path = ctx.displayFileOpenSelector('Select a file for processing')
12 | if not path:
13 | return
14 | # if no project exists, one will be created and the input file processed as the primary artifact
15 | # if a project exists, the input file will be added to the project and processed
16 | ctx.open(path)
17 |
--------------------------------------------------------------------------------
/scripts/README.md:
--------------------------------------------------------------------------------
1 | Sample scripts for JEB Decompiler.
2 |
3 | Currently, client scripts must be written with a Python 2.7 syntax.
4 |
5 | Scripts can be run in a GUI client or in headless mode.
--------------------------------------------------------------------------------
/scripts/ReloadNativeTypelibsAndSiglibs.py:
--------------------------------------------------------------------------------
1 | #?description=Scan and register newly-added native type libvraries (typelibs) and signature libraries (siglibs)
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | """
5 | Sample script for JEB Decompiler.
6 | """
7 | class ReloadNativeTypelibsAndSiglibs(IScript):
8 | def run(self, ctx):
9 | engctx = ctx.getEnginesContext()
10 | engctx.getTypeLibraryService().rescan()
11 | engctx.getNativeSignatureDBManager().rescan()
12 |
--------------------------------------------------------------------------------
/scripts/RenameDexClassesToDebugNames.py:
--------------------------------------------------------------------------------
1 | #?description=Rename dex classes to the optionl names provided in the debug metadata
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
5 | """
6 | Sample script for JEB Decompiler.
7 | """
8 | class RenameDexClassesToDebugNames(IScript):
9 |
10 | def run(self, ctx):
11 | prj = ctx.getMainProject()
12 | assert prj, 'Need a project'
13 |
14 | for unit in prj.findUnits(IDexUnit):
15 | self.process(unit)
16 |
17 | def process(self, dex):
18 | cnt = 0
19 | for c in dex.getClasses():
20 | name = c.getName()
21 | idx = c.getSourceStringIndex()
22 | if idx >= 0:
23 | debugName = dex.getString(idx).getValue()
24 | #print(debugName)
25 | if debugName:
26 | debugName = debugName.replace('.java', '')
27 | if debugName != name and c.setName(debugName):
28 | print('Renamed class %s to %s' % (name, debugName))
29 | cnt += 1
30 | if cnt > 0:
31 | dex.notifyGenericChange()
32 |
--------------------------------------------------------------------------------
/scripts/RenameJavaMethodParameters.py:
--------------------------------------------------------------------------------
1 | #?description=Rename method parameters of decompiled Java methods based on their types
2 | #?shortcut=
3 | import os
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core import IPlugin
6 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit, JavaElementType
7 | """
8 | Sample script for JEB Decompiler.
9 |
10 | This script demonstrates how to rename method parameters of decompiled Java methods.
11 | In the example below, generic parameter names ('argX') are renamed based on their type.
12 | """
13 | class RenameJavaMethodParameters(IScript):
14 |
15 | def run(self, ctx):
16 | prj = ctx.getMainProject()
17 | assert prj, 'Need a project'
18 |
19 | # process all Java decompiled source units
20 | for unit in prj.findUnits(IJavaSourceUnit):
21 | for m in unit.getClassElement().getMethods():
22 | self.process(unit, m)
23 |
24 | def process(self, unit, e):
25 | if not e.isExternal():
26 | print 'Method: %s' % e
27 | namemap = {}
28 | params = e.getParameters()
29 | for param in e.getParameters():
30 | ident = param.getIdentifier()
31 | original_name = ident.getName()
32 | if original_name != 'this':
33 | debug_name = ident.getDebugName()
34 | effective_name = unit.getIdentifierName(ident)
35 | print ' Parameter: %s (debug name: %s) (effective: %s)' % (param, debug_name, effective_name)
36 | if not effective_name and not debug_name and original_name.startswith('arg') and param.getType().isClassOrInterface():
37 | t = str(param.getType())
38 | simplename = t[t.rfind('.') + 1:].lower()
39 | v = namemap.get(simplename, 0)
40 | namemap[simplename] = v + 1
41 | effective_name = '%s%d' % (simplename , v)
42 | print ' -> Renaming to: %s' % effective_name
43 | unit.setIdentifierName(ident, effective_name)
44 |
--------------------------------------------------------------------------------
/scripts/ReplaceStringsInDex.py:
--------------------------------------------------------------------------------
1 | #?description=Use the specialized IDexUnit interface to replace all dex strings 'text/html' by 'foobar'.
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | from com.pnfsoftware.jeb.core.units.code import ICodeUnit, ICodeItem
5 | from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
6 | from com.pnfsoftware.jeb.core.units.code.android.dex import IDexString
7 | """
8 | Sample script for JEB Decompiler.
9 | """
10 | class ReplaceStringsInDex(IScript):
11 |
12 | def run(self, ctx):
13 | prj = ctx.getMainProject()
14 | assert prj, 'Need a project'
15 |
16 | for dex in prj.findUnits(IDexUnit):
17 | self.processDex(dex)
18 |
19 | def processDex(self, dex):
20 | # replace DEX strings
21 | cnt = 0
22 | for s in dex.getStrings():
23 | if s.getValue().startswith('text/html'):
24 | s.setValue('foobar')
25 | cnt += 1
26 | print('String replaced')
27 | if cnt > 0:
28 | dex.notifyGenericChange()
29 |
--------------------------------------------------------------------------------
/scripts/ReplaceStringsInJavaAST.py:
--------------------------------------------------------------------------------
1 | #?description=Find the first decompiled Java unit and replace String immediates by random string
2 | #?shortcut=
3 | import time
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit, IJavaConstant
6 | """
7 | Sample script for JEB Decompiler.
8 | """
9 | class ReplaceStringsInJavaAST(IScript):
10 |
11 | def run(self, ctx):
12 | prj = ctx.getMainProject()
13 | assert prj, 'Need a project'
14 |
15 | src = prj.findUnit(IJavaSourceUnit)
16 | assert src, 'Need a java source unit (decompiled)'
17 |
18 | print('Processing %s' % src)
19 |
20 | self.replcnt = 0
21 | self.cstbuilder = src.getFactories().getConstantFactory()
22 | for m in src.getClassElement().getMethods():
23 | self.checkElement(None, m)
24 |
25 | print('Replaced %d strings' % self.replcnt)
26 | src.notifyGenericChange()
27 |
28 | def checkElement(self, parent, e):
29 | if isinstance(e, IJavaConstant) and e.isString():
30 | parent.replaceSubElement(e, self.cstbuilder.createString('blah_' + str(time.time())))
31 | self.replcnt += 1
32 | for subelt in e.getSubElements():
33 | self.checkElement(e, subelt)
34 |
--------------------------------------------------------------------------------
/scripts/RequestUserInput.py:
--------------------------------------------------------------------------------
1 | #?description=Demo how to invoke common dialog boxes
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.client.api import IconType, ButtonGroupType
5 | """
6 | Sample script for JEB Decompiler.
7 | """
8 | class RequestUserInput(IScript):
9 | def run(self, ctx):
10 | if not isinstance(ctx, IGraphicalClientContext):
11 | print('This script must be run within a graphical client')
12 | return
13 |
14 | value = ctx.displayQuestionBox('Input', 'Enter a random string', '3')
15 | if value != None:
16 | ctx.displayMessageBox('Information', 'The value was %s' % value, IconType.INFORMATION, ButtonGroupType.OK)
17 |
18 | # other dialogs: see IGraphicalClientContext.displayXxx() methods
19 |
--------------------------------------------------------------------------------
/scripts/RequestUserInputWithComplexForm.py:
--------------------------------------------------------------------------------
1 | #?description=Demo how to generate a UI form to request for complex multiple inputs
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.client.api import FormEntry
5 | from java.util.function import Predicate
6 | """
7 | Sample script for JEB Decompiler.
8 | """
9 | class RequestUserInputWithComplexForm(IScript):
10 | def run(self, ctx):
11 | if not isinstance(ctx, IGraphicalClientContext):
12 | print('This script must be run within a graphical client')
13 | return
14 |
15 | # used to validate first name and last name entries
16 | class NameValidator(Predicate):
17 | def __init__(self, minlen):
18 | self.minlen = minlen
19 | def test(self, val):
20 | return len(val) >= self.minlen
21 |
22 | # a more complicated form with multi-line field, inline headers, and a validator
23 | values = ctx.displayForm('Form 2', 'Please provide your full details',
24 | FormEntry.Text('First name', '', FormEntry.INLINE, NameValidator(3), 0, 0),
25 | FormEntry.Text('Last name', '', FormEntry.INLINE, NameValidator(6), 0, 0),
26 | FormEntry.Text('Address', 'default address', 0, None, 40, 5),
27 | )
28 | if values:
29 | print(values)
30 |
31 |
--------------------------------------------------------------------------------
/scripts/RequestUserInputWithForm.py:
--------------------------------------------------------------------------------
1 | #?description=Demo how to generate a simple UI form to request for multiple inputs
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | """
5 | Sample script for JEB Decompiler.
6 | """
7 | class RequestUserInputWithForm(IScript):
8 | def run(self, ctx):
9 | if not isinstance(ctx, IGraphicalClientContext):
10 | print('This script must be run within a graphical client')
11 | return
12 |
13 | # a simple form
14 | values = ctx.displaySimpleForm('Form 1', 'Please provide your details', 'First name', '', 'Last name', '')
15 | if values:
16 | print('Info: %s, %s' % (values[1], values[0]))
17 |
--------------------------------------------------------------------------------
/scripts/RestoreMissingBookmarksFromComments.py:
--------------------------------------------------------------------------------
1 | #?description=Restore missing bookmarks from special comments
2 | #?shortcut=
3 |
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core.units import IInteractiveUnit
6 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil
7 |
8 | class RestoreMissingBookmarksFromComments(IScript):
9 | def run(self, ctx):
10 | prj = ctx.getMainProject()
11 | if not prj:
12 | return
13 | favcomments = []
14 | for unit in RuntimeProjectUtil.getAllUnits(prj):
15 | self.retrieve(unit, favcomments)
16 | print('Retrieved %d bookmarks (stored as special meta-comments)' % len(favcomments))
17 | bm = prj.getBookmarkManager()
18 | cnt = 0
19 | for unit, addr, desc in favcomments:
20 | if not bm.get(unit, addr):
21 | print('Restoring: \'%s\' (@ %s in %s' % (desc, addr, unit))
22 | bm.set(unit, addr, desc)
23 | cnt += 1
24 | print('Restored %d bookmarks' % cnt)
25 |
26 | def retrieve(self, unit, li):
27 | if not isinstance(unit, IInteractiveUnit):
28 | return
29 | cm = unit.getCommentManager()
30 | if not cm:
31 | return
32 | for e in cm.getComments().entrySet():
33 | addr = e.getKey()
34 | com = e.getValue()
35 | for mc in com.getMetaComments():
36 | s = mc.toString()
37 | if s.endswith(' (FAVORITE)'):
38 | li.append((unit, addr, s[:-11]))
39 |
--------------------------------------------------------------------------------
/scripts/SampleScript.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | #?description=A sample script explictly specifying a UTF-8 encoding
4 | #?shortcut=
5 | from com.pnfsoftware.jeb.client.api import IScript
6 | """
7 | Sample script for JEB Decompiler..
8 | """
9 | class SampleScript(IScript):
10 | def run(self, ctx):
11 | # For non-ASCII characters, remember to specify the encoding in the script header (here, UTF-8),
12 | # and do not forget to prefix all Unicode strings with "u", whether they're encoded (using \u or else) or not
13 | print('~~~\n' + u'Hello, 안녕하세요, 你好, こんにちは, Здравствуйте!\n' + 'This line was generated by a JEB Python script\n~~~')
14 |
--------------------------------------------------------------------------------
/scripts/SampleScriptDebugging.py:
--------------------------------------------------------------------------------
1 | #?description=How to use pydevd to debug JEB Python scripts inside Eclipse IDE or PyCharm
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript
4 | """
5 | Sample script for JEB Decompiler..
6 | """
7 | class SampleScriptDebugging(IScript):
8 | def run(self, ctx):
9 |
10 | # To debug inside Eclipse IDE:
11 | # 1) Install Eclipse IDE and the PyDev plugin to make it a full-fledged Python IDE
12 | # 2) Git-clone https://github.com/fabioz/PyDev.Debugger into your JEB folder
13 | # To debug inside PyCharm:
14 | # 1) Install JetBrains PyCharm
15 | # 2) Download pydevd-pycharm from https://pypi.org/project/pydevd-pycharm/#files and
16 | # unpack the pydevd-pycharm-xxx directory buried in the tarball to a newly
17 | # created `pydevd-pycharm` folder into your JEB folder
18 |
19 | # Now get ready to debug a script:
20 | # 1) Fire up the IDE, switch to the Debug perspective/layout and start the PyDev Debug Server.
21 | # 2) In the script to be debugged, import the appropriate pydevd module:
22 |
23 | # ... with Eclipse:
24 | import sys
25 | sys.path.append(ctx.getBaseDirectory() + '/PyDev.Debugger')
26 | import pydevd
27 | # ... or with PyCharm: (uncomment below and comment above)
28 | #sys.path.append(ctx.getBaseDirectory() + '/pydevd-pycharm')
29 | #import pydevd_pycharm
30 |
31 | # 3) Wherever the breakpoint is to be placed, call settrace()
32 | # note: additional parameters may be specified, such as the debugger server hostname/port, etc.
33 | # refer to pydevd documentation for details
34 | pydevd.settrace(stdoutToServer=True, stderrToServer=True)
35 |
36 | # 4) Now, run your script (e.g. within JEB GUI, press F2, then select or browse for your script, and execute it)
37 | # With settrace invoked just above, when the script is run, the debugger will be brought up when execution reaches
38 | # the statement that follows it, in the case of this example, that one:
39 | a = 1
40 |
41 | # 5) Switch to your IDE; your script should have been brought up in the editor, with the current on-breakpoint line
42 | # highlighted in green. Debug as expected (tracing, variable views/writes, etc.). Note that rendering of print() statements
43 | # will be delayed in JEB's logger; you can see them if JEB was started from a shell rendering stdout
44 |
45 | # some random code that can be stepped over...
46 | b = 100L
47 | c = 'strings and primitives can be viewed and changed when debugging'
48 | print('Hello, JEB script debugging: %d %d %s' % (a, b, c))
49 |
--------------------------------------------------------------------------------
/scripts/SearchAll.py:
--------------------------------------------------------------------------------
1 | #?description=Search for a string pattern across all text documents produced by all units under the project root
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext, IconType, ButtonGroupType
4 | from com.pnfsoftware.jeb.core.output.text import ITextDocument
5 | import re
6 | """
7 | Sample script for JEB Decompiler.
8 |
9 | Note that better search facilities exist in the GUI client,
10 | such as the Omnibox (F3) or Quick-Search (CTR+Q or CMD+Q).
11 | """
12 | class SearchAll(IScript):
13 |
14 | def run(self, ctx):
15 | if not isinstance(ctx, IGraphicalClientContext):
16 | print('This script must be run within a graphical client')
17 | return
18 |
19 | prj = ctx.getMainProject()
20 | assert prj, 'Need a project'
21 |
22 | searchstring = ctx.displayQuestionBox('Search All Existing Units', 'Regex pattern to be searched across all units: ', '')
23 | self.pattern = re.compile(searchstring, re.I)
24 | if not self.pattern:
25 | print('Please provide a search string')
26 | return
27 |
28 | print('Searching "%s" ...' % searchstring)
29 | for art in prj.getLiveArtifacts():
30 | for unit in art.getUnits():
31 | self.checkUnit(unit)
32 | print('Done')
33 |
34 |
35 | def checkUnit(self, unit, level=0):
36 | if not unit.isProcessed():
37 | unit.process()
38 | for doc in self.getTextDocuments(unit):
39 | searchResults = self.searchTextDocument(doc, self.pattern)
40 | for lineIndex, matchText, fullText in searchResults:
41 | print('Found in unit: %s (%s) on line %d : "%s" (full text: "%s")' % (unit.getName(), unit.getFormatType(), lineIndex, matchText, fullText))
42 | doc.dispose()
43 |
44 | # recurse over children units
45 | for c in unit.getChildren():
46 | self.checkUnit(c, level + 1)
47 |
48 |
49 | def getTextDocuments(self, srcUnit):
50 | r = []
51 | formatter = srcUnit.getFormatter()
52 | if formatter and formatter.getDocumentPresentations():
53 | for pres in formatter.getPresentations():
54 | doc = pres.getDocument()
55 | if isinstance(doc, ITextDocument):
56 | r.append(doc)
57 | return r
58 |
59 |
60 | def searchTextDocument(self, doc, pattern):
61 | r = []
62 | alldoc = doc.getDocumentPart(0, 10000000)
63 | for i, line in enumerate(alldoc.getLines()):
64 | s = line.getText().toString()
65 | matches = pattern.findall(s)
66 | for match in matches:
67 | r.append((i + 1, match, s))
68 | return r
69 |
--------------------------------------------------------------------------------
/scripts/TaskInWorkerThread.py:
--------------------------------------------------------------------------------
1 | #?description=Run an interruptible task in a worker thread
2 | #?shortcut=
3 | import time
4 | from java.lang import Runnable, Thread
5 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
6 | """
7 | Sample script for JEB Decompiler.
8 | """
9 | class TaskInWorkerThread(IScript):
10 | def run(self, ctx):
11 | if not isinstance(ctx, IGraphicalClientContext):
12 | print('This script must be run within a graphical client')
13 | return
14 | # will start a worker thread and run the task; a pop-up will be shown to provide a way to interrupt the task
15 | ctx.executeAsync('Counting...', SimpleTask())
16 | print('Done.')
17 |
18 | class SimpleTask(Runnable):
19 | def run(self):
20 | for i in range(10):
21 | # react to user pressing Cancel
22 | if Thread.interrupted():
23 | print('The task was interrupted')
24 | break
25 | print('Counter: %d' % i)
26 | time.sleep(1)
27 |
--------------------------------------------------------------------------------
/scripts/TaskWithReturnInWorkerThread.py:
--------------------------------------------------------------------------------
1 | #?description=Run an interruptible task in a worker thread
2 | #?shortcut=
3 | import time
4 | from java.lang import Thread
5 | from java.util.concurrent import Callable
6 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
7 | """
8 | Sample script for JEB Decompiler.
9 | """
10 | class TaskWithReturnInWorkerThread(IScript):
11 | def run(self, ctx):
12 | if not isinstance(ctx, IGraphicalClientContext):
13 | print('This script must be run within a graphical client')
14 | return
15 | # will start a worker thread and run the task; a pop-up will be shown to provide a way to interrupt the task
16 | r = ctx.executeAsyncWithReturn('Counting... and returning a value', SimpleTask())
17 | print r
18 |
19 | # note the use of Callable here
20 | class SimpleTask(Callable):
21 | def call(self):
22 | for i in range(5):
23 | # react to user pressing Cancel
24 | if Thread.interrupted():
25 | print('The task was interrupted')
26 | break
27 | print('Counter: %d' % i)
28 | time.sleep(1)
29 | return 123
30 |
--------------------------------------------------------------------------------
/scripts/TranslateString.py:
--------------------------------------------------------------------------------
1 | #?description=Localize the selected string to English. Optionally use GCP to perform the translation (see the script to set up your API key).
2 | #?shortcut=
3 | import json
4 | import os
5 | import traceback
6 | import urllib2
7 | import webbrowser
8 | from com.pnfsoftware.jeb.client.api import IScript
9 | from com.pnfsoftware.jeb.util.net import Net
10 | from com.pnfsoftware.jeb.core.units import IInteractiveUnit
11 | """
12 | Sample script for JEB Decompiler.
13 |
14 | Localize strings to English. The translated string is also registered as a comment if the unit supports it.
15 | Optionally use Google services to perform the translation: GCP key is expected to be found in the GCP_API_KEY env.var.
16 | """
17 | class TranslateString(IScript):
18 | def run(self, ctx):
19 | f = ctx.getFocusedFragment()
20 | if not f:
21 | return
22 |
23 | sel = f.getSelectedText() or f.getActiveItemAsText()
24 | if not sel:
25 | return
26 |
27 | print('Text: %s' % sel)
28 | text = sel.strip(' \'\"')
29 |
30 | # if you have set up a Google Cloud Engine API key, use the web Service and add the translated string as a comment
31 | # else, open up a browser and navigate to Google Translate
32 |
33 | key = os.environ.get('GCP_API_KEY')
34 | if not key:
35 | url = 'https://translate.google.com/#view=home&op=translate&sl=auto&tl=en&text=%s' % urllib2.quote(text.encode('utf8'))
36 | print('Query: %s' % url)
37 | webbrowser.open(url)
38 | return
39 |
40 | url = 'https://translation.googleapis.com/language/translate/v2?key=%s' % key
41 | try:
42 | r = Net().query(url, {'target': 'en', 'q': text})
43 | tt = json.loads(r)['data']['translations'][0]['translatedText']
44 | except Exception as e:
45 | traceback.print_exc(e)
46 | return
47 |
48 | print('Translation: %s' % tt)
49 |
50 | a = f.getActiveAddress()
51 | if a and isinstance(f.getUnit(), IInteractiveUnit):
52 | comment0 = f.getUnit().getComment(a)
53 | comment = tt + '\n' + comment0 if comment0 else tt
54 | f.getUnit().setComment(a, comment)
55 |
--------------------------------------------------------------------------------
/scripts/UIDemo.py:
--------------------------------------------------------------------------------
1 | #?description=Demo on how to use the JEB UI-API to query views and fragments (when run in the GUI client)
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | from com.pnfsoftware.jeb.core import RuntimeProjectUtil, IUnitFilter
5 | from com.pnfsoftware.jeb.core.units import IUnit
6 | """
7 | Sample script for JEB Decompiler.
8 |
9 | This script demonstrates how to use the UI API to query views and fragments generated by JEB GUI.
10 | """
11 | class UIDemo(IScript):
12 | def run(self, ctx):
13 | if not isinstance(ctx, IGraphicalClientContext):
14 | print('This script must be run within a graphical client')
15 | return
16 |
17 | # show which unit view is currently focused
18 | v = ctx.getFocusedView()
19 | print('Focused view: %s' % v)
20 |
21 | # enumerate all unit views (views representing units) and fragments within those views
22 | print('Views and fragments:')
23 | views = ctx.getViews()
24 | for view in views:
25 | print('- %s' % view.getLabel())
26 | fragments = view.getFragments()
27 | for fragment in fragments:
28 | print(' - %s' % view.getFragmentLabel(fragment))
29 |
30 | # focus test
31 | if len(views) >= 2:
32 | print('Focusing the second Unit view (if any)')
33 | views[1].setFocus()
34 |
35 | # opening the first certificate unit we find (in an APK, there should be one)
36 | prj = ctx.getMainProject()
37 | if prj:
38 | unitFilter = UnitFilter('cert')
39 | units = RuntimeProjectUtil.filterUnits(prj, unitFilter)
40 | if units:
41 | ctx.openView(units.get(0))
42 |
43 |
44 | class UnitFilter(IUnitFilter):
45 | def __init__(self, formatType):
46 | self.formatType = formatType
47 | def check(self, unit):
48 | return unit.getFormatType() == self.formatType
49 |
--------------------------------------------------------------------------------
/scripts/WalkEvmDecomp.py:
--------------------------------------------------------------------------------
1 | #?description=Retrieve the decompiled EVM code of an Ethereum contract
2 | #?shortcut=
3 | #?deprecated=refer to PrintNativeRoutineIR.py to see how GENDEC's IR can be navigated
4 | from com.pnfsoftware.jeb.client.api import IScript
5 | from com.pnfsoftware.jeb.core.units import INativeCodeUnit
6 | from com.pnfsoftware.jeb.core.units.code.asm.type import TypeUtil
7 | from com.pnfsoftware.jeb.core.units.code.asm.decompiler import INativeSourceUnit
8 | from com.pnfsoftware.jeb.core.util import DecompilerHelper
9 | """
10 | Sample script for JEB Decompiler.
11 |
12 | !!! DEPRECATED !!! see note above.
13 |
14 | ===> How to use:
15 | Two modes:
16 | - Using the UI desktop client:\
17 | - load an Ethereum EVM contract
18 | - make sure the GlobalAnalysis for EVM modules is enabled (it is by default)
19 | - then run the script: File, Scripts, Run...
20 | - the script will process your loaded contract
21 | - Using the command line:
22 | - run like: jeb_wincon.bat -c --script= --
23 | - the script will create a JEB project and process the contract file provided on the command line
24 | - (make sure the contract file ends with the 'evm-bytecode' extension)
25 |
26 | ===> What is it:
27 | This script demonstrates how to retrieve the decompiled EVM code of an Ethereum contract.
28 | - The decompiled contract's Abstract Syntax Tree (AST) is walked and its node types are printed
29 | (reference: https://www.pnfsoftware.com/jeb/apidoc/reference/com/pnfsoftware/jeb/core/units/code/asm/decompiler/ast/package-summary.html)
30 | - The individual methods of the contract are retrieved: their AST is also displayed
31 | - The most refined Intermediate Representation (IR) code of each individual method is also displayed
32 | (reference: https://www.pnfsoftware.com/jeb/apidoc/reference/com/pnfsoftware/jeb/core/units/code/asm/decompiler/ir/package-summary.html)
33 |
34 | ===> Additional references:
35 | - highly recommended (else you will have much difficulty building upon the code below): follow the tutorials on www.pnfsoftware.com/jeb/devportal
36 | - for Native code and Native Decompilers: the com.pnfsoftware.jeb.core.units.code.asm package and sub-packages
37 | - see apidoc at www.pnfsoftware.com/jeb/apidoc: Native code unit and co, Native decompiler unit and co.
38 |
39 | More to be published on the blog and technical papers.
40 |
41 | Comments, questions, needs more details? message on us on Slack or support@pnfsoftware.com -- Nicolas Falliere
42 | """
43 | class WalkEvmDecomp(IScript):
44 |
45 | def run(self, ctx):
46 | prj = ctx.getMainProject()
47 | if not prj:
48 | argv = ctx.getArguments()
49 | if len(argv) < 1:
50 | print('Please provide an input contract file')
51 | return
52 | self.inputFile = argv[0]
53 | print('Processing ' + self.inputFile + '...')
54 | if not self.inputFile.endswith('.evm-bytecode'):
55 | print('Warning: it is recommended your contract file has the evm-bytecode extension in order to guarantee processing by the EVM modules')
56 | ctx.open(self.inputFile)
57 | prj = ctx.getMainProject()
58 |
59 | # retrieve the primary code unit (must be the result of an EVM contract analysis)
60 | unit = prj.findUnit(INativeCodeUnit)
61 | print('EVM unit: %s' % unit)
62 |
63 | # GlobalAnalysis is assumed to be on: the contract is already decompiled
64 | # we retrieve a handle on the EVM decompiler ...
65 | decomp = DecompilerHelper.getDecompiler(unit)
66 | if not decomp:
67 | print('No decompiler unit found')
68 | return
69 |
70 | # ... and retrieve a handle on the decompiled contract's INativeSourceUnit
71 | src = decomp.decompile("DecompiledContract")
72 | print(src)
73 |
74 | #targets = src.getDecompilationTargets()
75 | #print(targets)
76 |
77 | # let's get the contract's AST
78 | astDecompClass = src.getRootElement()
79 | # the commented line below will output the entire decompiled source code
80 | #print(astDecompClass)
81 | # here, we walk the AST tree and print the type of each element in the tree
82 | print("*** AST of contract")
83 | self.displayASTTree(astDecompClass)
84 |
85 | # now, let's retrieve the individual methods implemented in the contract
86 | methods = unit.getInternalMethods()
87 | for method in methods:
88 | # retrieve the INativeSourceUnit of the method
89 | r = decomp.decompileMethod(method)
90 | print("*** AST for method: %s" % method.getName(True))
91 | self.displayASTTree(r.getRootElement())
92 |
93 | # list of INativeDecompilationTarget for a decompiled method
94 | decompTargets = r.getDecompilationTargets()
95 | if decompTargets:
96 | # get the first (generally, only) target object
97 | decompTarget = decompTargets.get(0)
98 | # an INativeDecompilationTarget object aggregates many useful objects resulting from the decompilation of a method
99 | # here, we retrieve the most refined CFG of the Intermediate Representation for the method
100 | ircfg = decompTarget.getContext().getCfg()
101 | # CFG object reference, see package com.pnfsoftware.jeb.core.units.code.asm.cfg
102 | print("++++ IR-CFG for method: %s" % method.getName(True))
103 | print(ircfg.formatSimple())
104 |
105 | # end of demo, we have enough with one method, uncomment to print out the AST and IR of all methods
106 | break
107 |
108 |
109 | def displayASTTree(self, e0, level=0):
110 | print('%s%s' % (level*' ', e0.getElementType()))
111 | if e0:
112 | elts = e0.getSubElements()
113 | for e in elts:
114 | self.displayASTTree(e, level+1)
115 |
--------------------------------------------------------------------------------
/scripts/WidgetList.py:
--------------------------------------------------------------------------------
1 | #?description=Display a sample list box
2 | #?shortcut=
3 | from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
4 | """
5 | Sample script for JEB Decompiler.
6 | """
7 | class WidgetList(IScript):
8 | def run(self, ctx):
9 | if not isinstance(ctx, IGraphicalClientContext):
10 | print('This script must be run within a graphical client')
11 | return
12 | value = ctx.displayList('Input', 'foo', ['Col1', 'Col2'], [['abc', 'def'], ['ffff', '']])
13 | print(value)
14 |
--------------------------------------------------------------------------------
/scripts/cluster/cluster.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | '''
4 | Simple graph community detection using edge-betweenness method.
5 | Dependency: igraph
6 |
7 | Input file format:
8 |
9 | # vertices (160)
10 | v,449
11 | v,475
12 | ...
13 | # edges (322)
14 | e,376,391,2
15 | e,519,478,3
16 | ...
17 |
18 | Output file format:
19 |
20 | # clusters
21 | 449,711,684,344,497,...
22 | 475,340,633,324,527,...
23 |
24 | Author: Nicolas Falliere
25 | '''
26 |
27 | import sys
28 | from igraph import *
29 |
30 |
31 | class TypeGraph:
32 |
33 | def __init__(self, filename):
34 | self.nodes = []
35 | self.edges = []
36 | self.idToIndex = {}
37 |
38 | with open(filename) as f:
39 | lines = f.readlines()
40 | for line in lines:
41 | line = line.strip()
42 | if not line or line.startswith('#'):
43 | continue
44 | elts = line.split(',')
45 | if elts[0] == 'v':
46 | nodeId = int(elts[1])
47 | nodeLabel = elts[2] if len(elts) > 2 else None
48 | self.idToIndex[nodeId] = len(self.nodes)
49 | self.nodes.append((nodeId, nodeLabel))
50 | if elts[0] == 'e':
51 | src = int(elts[1])
52 | dst = int(elts[2])
53 | weight = int(elts[3]) if len(elts) > 3 else 1
54 | if weight == 0:
55 | raise Exception('Weight cannot be 0')
56 | self.edges.append((src, dst, weight))
57 |
58 | self.g = self.__createGraph()
59 |
60 | def __createGraph(self):
61 | g = Graph()
62 | g.add_vertices(len(self.nodes))
63 | _edges = []
64 | _weights = []
65 | for src, dst, weight in self.edges:
66 | _edge = (self.idToIndex[src], self.idToIndex[dst])
67 | if _edge in _edges or src == dst:
68 | raise Exception('Error in input graph: edge %d->%d' % (src, dst))
69 | _edges.append(_edge)
70 | _weights.append(weight)
71 | g.add_edges(_edges)
72 | g.es['weight'] = _weights
73 | return g
74 |
75 | def getGraph(self):
76 | return self.g
77 |
78 | def getNodeId(self, index):
79 | return self.nodes[index][0]
80 |
81 | def getNodeLabel(self, index):
82 | return self.nodes[index][1]
83 |
84 |
85 | if __name__ == '__main__':
86 | if len(sys.argv) != 3:
87 | sys.exit(-1)
88 |
89 | typeGraph = TypeGraph(sys.argv[1])
90 | g = typeGraph.getGraph()
91 | print(g)
92 |
93 | dendro = g.community_edge_betweenness(directed=True, weights='weight')
94 | print(dendro)
95 |
96 | clusters = dendro.as_clustering()
97 | print(clusters)
98 |
99 | output = '# clusters\n'
100 | for cluster in clusters:
101 | _cluster = []
102 | for i in cluster:
103 | _cluster.append(str(typeGraph.getNodeId(i)))
104 | output += '%s\n' % ','.join(_cluster)
105 |
106 | with open(sys.argv[2], 'w') as f:
107 | f.write(output)
108 |
--------------------------------------------------------------------------------