Skip to content
Browse files

fixed issues about invoke-kind/range

  • Loading branch information...
1 parent 0c8f378 commit 28618d9f1c0450891306f2b898b1ed20b354394f @kelwin committed
Showing with 197 additions and 46 deletions.
  1. +116 −16 apkil/monitor.py
  2. +79 −25 apkil/smali.py
  3. +2 −5 test.py
View
132 apkil/monitor.py
@@ -2,12 +2,80 @@
# -*- coding: utf-8 -*-
import os
+import copy
from logger import log
from smali import ClassNode, MethodNode, FieldNode, InsnNode, \
TypeNode, LabelNode, TryNode, SmaliTree
PKG_PREFIX = "droidbox"
+DEFAULT_HELPER = \
+r'''
+.class public Ldroidbox/apimonitor/Helper;
+.super Ljava/lang/Object;
+.method public constructor <init>()V
+.registers 1
+invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+return-void
+.end method
+.method public static log(Ljava/lang/String;)V
+.registers 3
+const-string v0, "\n"
+const-string v1, "\\\\n"
+invoke-virtual {p0, v0, v1}, Ljava/lang/String;->replaceAll(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+move-result-object p0
+const-string v0, "\r"
+const-string v1, "\\\\r"
+invoke-virtual {p0, v0, v1}, Ljava/lang/String;->replaceAll(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+move-result-object p0
+const-string v0, "DroidBox"
+invoke-static {v0, p0}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
+return-void
+.end method
+.method public static toString(Ljava/lang/Object;)Ljava/lang/String;
+.registers 5
+if-nez p0, :cond_5
+const-string v3, "null"
+:goto_4
+return-object v3
+:cond_5
+invoke-virtual {p0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+move-result-object v3
+invoke-virtual {v3}, Ljava/lang/Class;->isArray()Z
+move-result v3
+if-eqz v3, :cond_3e
+new-instance v2, Ljava/lang/StringBuilder;
+const-string v3, "["
+invoke-direct {v2, v3}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
+invoke-static {p0}, Ljava/lang/reflect/Array;->getLength(Ljava/lang/Object;)I
+move-result v1
+const/4 v0, 0x0
+:goto_1b
+if-lt v0, v1, :cond_27
+const-string v3, "]"
+invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+move-result-object v3
+goto :goto_4
+:cond_27
+invoke-static {p0, v0}, Ljava/lang/reflect/Array;->get(Ljava/lang/Object;I)Ljava/lang/Object;
+move-result-object v3
+invoke-static {v3}, Ldroidbox/apimonitor/Helper;->toString(Ljava/lang/Object;)Ljava/lang/String;
+move-result-object v3
+invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+add-int/lit8 v3, v1, -0x1
+if-ge v0, v3, :cond_3b
+const-string v3, ", "
+invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+:cond_3b
+add-int/lit8 v0, v0, 0x1
+goto :goto_1b
+:cond_3e
+invoke-virtual {p0}, Ljava/lang/Object;->toString()Ljava/lang/String;
+move-result-object v3
+goto :goto_4
+.end method
+'''
class APIMonitor(object):
@@ -16,13 +84,15 @@ def __init__(self, method_descs):
self.stub_classes = {}
self.method_map = {}
self.class_map = {}
+ self.helper = ClassNode(buf=DEFAULT_HELPER)
for m in method_descs:
self.add_stub_method(m)
def __repr__(self):
pass
- def repackage(self, st):
+ def inject(self, smali_tree):
+ st = copy.deepcopy(smali_tree)
for api in self.method_descs:
segs = api.split(':', 1)
method_type = segs[0]
@@ -35,12 +105,22 @@ def repackage(self, st):
insn = m.insns[i]
if insn.fmt == "35c" and \
insn.opcode_name == "invoke-direct" and \
- insn.obj.method_desc == api :
+ insn.obj.method_desc == api:
insn.obj.replace("invoke-static", \
self.method_map[api])
r = insn.obj.registers.pop(0)
m.insert_insn(InsnNode(\
"move-result-object %s" % r), i + 1, 0)
+ if insn.fmt == "3rc" and \
+ insn.opcode_name == "invoke-direct/range" and \
+ insn.obj.method_desc == api:
+ insn.obj.replace("invoke-static/range", \
+ self.method_map[api])
+ r = insn.obj.reg_start
+ nr = r[0] + str(int(r[1:]) + 1)
+ insn.obj.set_reg_start(nr)
+ m.insert_insn(InsnNode(\
+"move-result-object %s" % r), i + 1, 0)
elif method_type == "instance":
for c in st.classes:
for m in c.methods:
@@ -48,9 +128,14 @@ def repackage(self, st):
insn = m.insns[i]
if insn.fmt == "35c" and \
insn.opcode_name == "invoke-virtual" and \
- insn.obj.method_desc == api :
+ insn.obj.method_desc == api:
insn.obj.replace("invoke-static", \
self.method_map[api])
+ if insn.fmt == "3rc" and \
+ insn.opcode_name == "invoke-virtual/range" and \
+ insn.obj.method_desc == api:
+ insn.obj.replace("invoke-static/range", \
+ self.method_map[api])
elif method_type == "static":
for c in st.classes:
for m in c.methods:
@@ -58,14 +143,20 @@ def repackage(self, st):
insn = m.insns[i]
if insn.fmt == "35c" and \
insn.opcode_name == "invoke-static" and \
- insn.obj.method_desc == api :
+ insn.obj.method_desc == api:
insn.obj.replace("invoke-static", \
self.method_map[api])
+ if insn.fmt == "3rc" and \
+ insn.opcode_name == "invoke-static/range" and \
+ insn.obj.method_desc == api:
+ insn.obj.replace("invoke-static/range", \
+ self.method_map[api])
for c in self.stub_classes.values():
st.add_class(c)
- #st.add_class(helper.get_class(HELPER_CLASS))
+ st.add_class(self.helper)
+ return st
def add_stub_method(self, m):
segs = m.split(':', 1)
@@ -116,13 +207,14 @@ def __add_stub_inst(self, stub_class, m):
method.add_access(["public", "static"])
para_num = len(method.paras)
+ reg_num = method.get_paras_reg_num()
ri = 1
- if para_num <= 5:
+ if reg_num <= 5:
i = "invoke-virtual {%s}, %s" % \
- (", ".join(["p%d" % k for k in range(para_num)]), m)
+ (", ".join(["p%d" % k for k in range(reg_num)]), m)
else:
- i = "invoke-virtual/range {p0 .. p%d}, %s" % (opcode, para_num - 1, m)
+ i = "invoke-virtual/range {p0 .. p%d}, %s" % (opcode, reg_num - 1, m)
method.add_insn(InsnNode(i))
@@ -272,18 +364,23 @@ def __add_stub_cons(self, stub_class, m):
method.add_access(["public", "static"])
para_num = len(method.paras)
+ reg_num = method.get_paras_reg_num()
ri = 1
method.add_insn(InsnNode("new-instance v1, %s" % segs[0]))
- if para_num <= 4:
+
+ if reg_num <= 4:
i = "invoke-direct {v1, %s}, %s" % \
- (", ".join(["p%d" % k for k in range(para_num)]), \
+ (", ".join(["p%d" % k for k in range(reg_num)]), \
m)
+ method.add_insn(InsnNode(i))
else:
- print "constructor with more than 4 paras!"
- sys.exit(1)
+ for k in range(reg_num):
+ method.add_insn(InsnNode("move-object v%d, p%d" % (k + 2, k)))
+ i = "invoke-direct/range {v1 .. v%d}, %s" % \
+ (reg_num + 1, )
+ method.add_insn(InsnNode(i))
- method.add_insn(InsnNode(i))
ri += 1
method.add_insn(InsnNode("new-instance \
@@ -418,13 +515,14 @@ def __add_stub_static(self, stub_class, m):
method.add_access(["public", "static"])
para_num = len(method.paras)
+ reg_num = method.get_paras_reg_num()
ri = 1
- if para_num <= 5:
+ if reg_num <= 5:
i = "invoke-static {%s}, %s" % \
- (", ".join(["p%d" % k for k in range(para_num)]), m)
+ (", ".join(["p%d" % k for k in range(reg_num)]), m)
else:
- i = "invoke-static/range {p0 .. p%d}, %s" % (opcode, para_num - 1, m)
+ i = "invoke-static/range {p0 .. p%d}, %s" % (opcode, reg_num - 1, m)
method.add_insn(InsnNode(i))
@@ -563,3 +661,5 @@ def __add_stub_static(self, stub_class, m):
self.method_map[m] = "L" + PKG_PREFIX + "/" + segs[0][1:] + "->" + \
method.get_desc()
+
+
View
104 apkil/smali.py
@@ -4,6 +4,7 @@
import os
import copy
import sys
+import StringIO
from logger import log
@@ -12,7 +13,12 @@
"invoke-super": "35c",
"invoke-direct": "35c",
"invoke-static": "35c",
- "invoke-interface": "35c"
+ "invoke-interface": "35c",
+ "invoke-virtual/range": "3rc",
+ "invoke-super/range": "3rc",
+ "invoke-direct/range": "3rc",
+ "invoke-static/range": "3rc",
+ "invoke-interface/range": "3rc"
}
BASIC_TYPES = {
@@ -84,23 +90,16 @@ def save(self, new_foldername):
def export_apk(self):
self.save("./out")
- """
- def get_insn35c(self, opcode_name, method_desc):
- result = []
- for c in self.classes:
- result.extend(c.get_insn35c(opcode_name, method_desc))
- return result
- """
-
class ClassNode(object):
- def __init__(self, filename=None):
+ def __init__(self, filename=None, buf=None):
self.buf = []
self.filename = ""
self.name = ''
self.super_name= ''
self.source = ''
+ self.implements = ''
self.access = []
self.interfaces = []
self.fields = []
@@ -109,8 +108,8 @@ def __init__(self, filename=None):
self.annotations = []
self.debugs = []
- if filename:
- self.__parse(filename)
+ if filename or buf:
+ self.__parse(filename, buf)
def __repr__(self):
return "Class: %s %s << %s\n%s%s" % \
@@ -118,12 +117,17 @@ def __repr__(self):
''.join([repr(f) for f in self.fields]), \
''.join([repr(m) for m in self.methods]))
- def __parse(self, filename):
- self.filename = filename
- f = open(self.filename, 'r')
+ def __parse(self, filename, buf):
+ if filename:
+ self.filename = filename
+ f = open(self.filename, 'r')
+ elif buf:
+ f = StringIO.StringIO(buf)
+ else:
+ return
+
line = f.readline()
while line:
- # print line
if line.isspace():
line = f.readline()
continue
@@ -143,7 +147,7 @@ def __parse(self, filename):
elif segs[0] == ".interface":
pass
elif segs[0] == ".implements":
- pass
+ self.implements = segs[1]
elif segs[0] == ".field":
self.fields.append(FieldNode(line))
elif segs[0] == ".method":
@@ -175,7 +179,12 @@ def reload(self):
# .super
self.buf.append(".super %s" % (self.super_name, ))
# .source
- # self.buf.append(".source %s" % (self.source, ))
+ if self.source:
+ self.buf.append(".source %s" % (self.source, ))
+ # .implements
+ if self.implements:
+ self.buf.append(".implements %s" % (self.implements, ))
+ # .interfaces
# .field
for f in self.fields:
f.reload()
@@ -218,13 +227,6 @@ def save(self, new_foldername):
f.write('\n'.join(self.buf))
f.close()
- """
- def get_insn35c(self, opcode_name, method_desc):
- result = []
- for m in self.methods:
- result.extend(m.get_insn35c(opcode_name, method_desc))
- return result
- """
class FieldNode(object):
@@ -413,6 +415,12 @@ def get_insn35c(self, opcode_name, method_desc):
def get_desc(self):
return self.descriptor
+ def get_paras_reg_num(self):
+ reg_num = 0
+ for p in self.paras:
+ reg_num += p.words
+ return reg_num
+
def set_name(self, name):
self.name = name
@@ -485,6 +493,8 @@ def __parse(self, line):
if self.fmt == "35c":
self.obj = Insn35c(line)
+ elif self.fmt == "3rc":
+ self.obj = Insn3rc(line)
log("InsnNode: " + self.opcode_name + " parsed!")
@@ -584,6 +594,50 @@ def set_regs(self, registers):
self.registers = registers
+class Insn3rc(object):
+
+ def __init__(self, line):
+ self.buf = ""
+ self.opcode_name = ""
+ self.reg_start = ""
+ self.reg_end = ""
+ # self.reg_num = 0
+ self.method_descriptor = ""
+
+ self.__parse(line)
+
+ def __repr__(self):
+ return "%s\n" % self.buf
+
+ def __parse(self, line):
+ self.buf = line
+ tmp = self.buf
+ tmp = tmp.replace('{', '')
+ tmp = tmp.replace('}', '')
+ tmp = tmp.replace(',', '')
+ tmp = tmp.replace("..", '')
+ segs = tmp.split()
+ self.opcode_name = segs[0]
+ self.reg_start = segs[1]
+ self.reg_end = segs[2]
+ # self.reg_num = int(self.reg_start[1:]) - int(self.reg_end[1:]) + 1
+ self.method_desc = segs[-1]
+
+ def reload(self):
+ self.buf = "%s {%s .. %s}, %s" % \
+ (self.opcode_name, self.reg_start, self.reg_end, \
+ self.method_desc)
+
+ def replace(self, opcode_name, method_desc):
+ self.opcode_name = opcode_name
+ self.method_desc = method_desc
+
+ def set_reg_start(self, register):
+ self.reg_start = register
+
+ def set_reg_end(self, register):
+ self.reg_end = register
+
class TypeNode(object):
def __init__(self, desc):
View
7 test.py
@@ -44,18 +44,15 @@
#API_LIST = [ "Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V"]
API_LIST = [ #"Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V", \
-#"Landroid/content/ContentValues;->put(Ljava/lang/String;Ljava/lang/Integer;)V", \
-#"Landroid/content/ContentValues;->put(Ljava/lang/String;Ljava/lang/String;)V", \
"static:Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;", \
"constructor:Landroid/content/Intent;-><init>(Ljava/lang/String;)V", \
"instance:Lapkil/tests/APKIL;->openFileOutput(Ljava/lang/String;I)Ljava/io/FileOutputStream;", \
"instance:Ljava/io/OutputStreamWriter;->write(Ljava/lang/String;)V", \
"instance:Lapkil/tests/APKIL;->openFileInput(Ljava/lang/String;)Ljava/io/FileInputStream;",
-#"instance:Ljava/io/BufferedReader;->readLine()Ljava/lang/String;", \
+"instance:Ljava/io/BufferedReader;->readLine()Ljava/lang/String;", \
]
mo = monitor.APIMonitor(API_LIST)
-s.add_class(helper.get_class(HELPER_CLASS))
-mo.repackage(s)
+s = mo.inject(s)
s.save(NEW_OUT)
#sys.exit(0)

0 comments on commit 28618d9

Please sign in to comment.
Something went wrong with that request. Please try again.