Skip to content

Commit 0102391

Browse files
authored
Create FridaCodeGenerator.py
1 parent 780ee12 commit 0102391

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed

scripts/FridaCodeGenerator.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#?shortcut=Mod1+Shift+Z
2+
#!/usr/bin/env python3
3+
# -*- coding: utf-8 -*-
4+
5+
from com.pnfsoftware.jeb.client.api import IScript
6+
from com.pnfsoftware.jeb.core import RuntimeProjectUtil
7+
from com.pnfsoftware.jeb.core.units.code.android import IDexUnit
8+
from subprocess import Popen, PIPE
9+
10+
11+
def arg_format(i):
12+
return 'arg_%d' % i
13+
14+
15+
def generate_body_code(types, retval, method_name, orig_method_name, class_name):
16+
body_code = "\n\tconsole.log('[{}#{}] ' + JSON.strigify({{\n\t".format(
17+
FridaCodeGenerator.to_canonical_name(class_name), method_name)
18+
for i, typ in enumerate(types):
19+
body_code += '\t{}: {}, // {}\n\t'.format('a%d' % i, arg_format(i), typ)
20+
21+
if retval != 'void':
22+
body_code = '\n\tvar retval = this.{}.apply(this, arguments);{}\tretv: retval\n\t}});'.format(
23+
orig_method_name, body_code)
24+
else:
25+
body_code += '}});\n\tthis.{}.apply(this, arguments);'.format(method_name)
26+
27+
return body_code + '\n'
28+
29+
30+
class JavaMethod(object):
31+
def __init__(self):
32+
self.class_name = None
33+
self.class_orig_name = None
34+
self.name = None
35+
self.orig_name = None
36+
self.arg = []
37+
self.retType = None
38+
39+
def get_parameters(self):
40+
return self.arg
41+
42+
def get_return_type(self):
43+
return self.retType
44+
45+
def get_name(self):
46+
return self.name
47+
48+
def get_orig_name(self):
49+
return self.orig_name
50+
51+
def get_class_orig_name(self):
52+
return self.class_orig_name
53+
54+
def get_class_name(self):
55+
return self.class_name
56+
57+
def __str__(self):
58+
return 'JavaMethod[name: %s, orig_name: %s, args: %s, return type: %s]' % (
59+
self.name, self.orig_name, self.arg, self.retType)
60+
61+
62+
class FridaCodeGenerator(IScript):
63+
64+
@staticmethod
65+
def to_canonical_name(mname):
66+
mname = mname.replace('/', '.')
67+
return {
68+
'C': 'char',
69+
'I': 'int',
70+
'B': 'byte',
71+
'Z': 'boolean',
72+
'F': 'float',
73+
'D': 'double',
74+
'S': 'short',
75+
'J': 'long',
76+
'V': 'void',
77+
'L': mname[1:-1],
78+
'[': mname
79+
}[mname[0]]
80+
81+
def run(self, ctx):
82+
project = ctx.getEnginesContext().getProjects()[0] # Get current project(IRuntimeProject)
83+
self.dexunit = RuntimeProjectUtil.findUnitsByType(project, IDexUnit, False)[0] # Get dex context, needs >=V2.2.1
84+
try:
85+
self.current_unit = ctx.getFocusedView().getActiveFragment().getUnit() # Get current Source Tab in Focus
86+
java_class = self.current_unit.getClassElement().getName()
87+
current_addr = ctx.getFocusedView().getActiveFragment().getActiveAddress()
88+
m = FridaCodeGenerator.get_decompiled_method(self.dexunit, current_addr, java_class)
89+
method_name = m.get_name()
90+
class_name = FridaCodeGenerator.to_canonical_name(m.get_class_orig_name())
91+
return_type = FridaCodeGenerator.to_canonical_name(str(m.get_return_type()))
92+
if method_name == '<clinit>':
93+
raise Exception('Class initializer')
94+
args_code = ', '.join([arg_format(i) for i in range(len(m.get_parameters()))])
95+
96+
if method_name == '<init>': method_name = '$init'
97+
98+
types = [FridaCodeGenerator.to_canonical_name(param) for param in m.get_parameters()]
99+
# TODO get original type class names
100+
type_code = ', '.join(["'{0}'".format(t) for t in types])
101+
body_code = generate_body_code(types, return_type, method_name, m.get_orig_name(), m.get_class_name())
102+
hook = "Java.use('{class_name}').{method}.overload({sig}).implementation = function({args}) {{{body}}}".format(
103+
class_name=class_name,
104+
method=m.get_orig_name() if method_name != '$init' else method_name,
105+
sig=type_code,
106+
args=args_code,
107+
body=body_code
108+
)
109+
print(hook)
110+
# copy to system's clipboard
111+
Popen(['xclip', '-sel', 'c', '-i'], stdin=PIPE).communicate(input=(hook.encode()))
112+
except Exception as e:
113+
print(e)
114+
ctx.displayMessageBox(None, 'Place the cursor in the function you want to generate the Frida code', None, None)
115+
116+
@staticmethod
117+
def get_decompiled_method(dex, addr, class_orig_name):
118+
method_info = JavaMethod()
119+
method_info.orig_name = dex.getMethod(addr).getName(False)
120+
msig = addr.split('+')[0]
121+
infos = str(msig).split('->')
122+
if len(infos) == 2:
123+
method_info.class_name = infos[0]
124+
method_info.class_orig_name = class_orig_name
125+
if len(infos[1].split('(')) == 2:
126+
method_info.name = infos[1].split('(')[0]
127+
if len(infos[1].split(')')) == 2:
128+
method_info.retType = infos[1].split(')')[1]
129+
if len(infos[1].split('(')) == 2 and len(infos[1].split(')')) == 2:
130+
args = infos[1].split('(')[-1].split(')')[0]
131+
while args:
132+
if args[0] in ['C', 'I', 'B', 'Z', 'F', 'D', 'S', 'J', 'V']:
133+
method_info.arg.append(str(args[0]))
134+
args = args[1:]
135+
elif args[0] == '[':
136+
if args[1] == 'L':
137+
offset = args.find(';')
138+
method_info.arg.append(str(args[0:offset + 1]))
139+
args = args[offset + 1:]
140+
else:
141+
method_info.arg.append(str(args[0:2]))
142+
args = args[2:]
143+
elif args[0] == 'L':
144+
offset = args.find(";")
145+
method_info.arg.append(str(args[0:offset + 1]))
146+
args = args[offset + 1:]
147+
print(method_info)
148+
return method_info

0 commit comments

Comments
 (0)