def _add_stub_class(self, className, superClassName, st ): """ @param className: Name of new class; example: Lcom/test; @param superClassName: Name of super class; example: Ljava/lang/Object; @param st: Smali tree to save class """ stub_class = ClassNode() stub_class.set_name("L" + PKG_PREFIX + "/" + className[1:]) stub_class.add_access("public") stub_class.set_super_name(superClassName) self.stub_classes[className] = stub_class self.class_map[className] = "L" + PKG_PREFIX + "/" + className[1:] method = MethodNode() method.set_desc("<init>()V") method.add_access(["public", "constructor"]) method.set_registers(1) # i1 = InsnNode("invoke-direct {p0}, Ljava/lang/Object;-><init>()V") #Error! Must not create instance of Object, but of superclass i1 = InsnNode("invoke-direct {p0}, "+superClassName+"-><init>()V") i2 = InsnNode("return-void") method.add_insn([i1, i2]) stub_class.add_method(method) st.add_class(stub_class)
def __add_stub_inst(self, stub_class, on, m, regs=1): segs = m.rsplit("->", 1) method = MethodNode() method.set_desc(segs[1]) method.add_para(TypeNode(segs[0])) method.add_access(["public", "static"]) method.set_registers(regs) stub_class.add_method(method) i = m.find('(') self.method_map[m] = "L" + PKG_PREFIX + "/" + segs[0][1:] + "->" + \ method.get_desc()
def __add_stub_cons(self, stub_class, m, regs=1): segs = m.rsplit("->", 1) desc = segs[1].replace("<init>", "droidbox_cons") i = desc.find(')') desc = desc[:i + 1] + segs[0] method = MethodNode() method.set_desc(desc) method.add_access(["public", "static"]) method.set_registers(regs) stub_class.add_method(method) i = m.find('(') self.method_map[m] = "L" + PKG_PREFIX + "/" + segs[0][1:] + "->" + \ method.get_desc()
def __add_stub_static(self, stub_class, m, regs=1): segs = m.rsplit("->", 1) method = MethodNode() method.set_desc(segs[1]) method.add_access(["public", "static"]) para_num = len(method.paras) reg_num = method.get_paras_reg_num() ri = 1 method.set_registers(regs) stub_class.add_method(method) i = m.find('(') self.method_map[m] = "L" + PKG_PREFIX + "/" + segs[0][1:] + "->" + \ method.get_desc()
def add_stub_method(self, on, m, parent_class, parent_method, package): #segs = m.split(':', 1) #method_type = segs[0] #m = segs[1] #print on,m method_type = METHOD_TYPE_BY_OPCODE[on] segs = m.rsplit("->", 1) #print on,m,method_type,segs #print parent_class.name, segs[0] # if package in parent_class.name: # print "removing",parent_class.name,package,segs[0] # self.stub_classes.pop(segs[0],None) if self.stub_classes.has_key(segs[0]): stub_class = self.stub_classes[segs[0]] else: stub_class = ClassNode() #stub_class.set_name = "Ldroidbox/java/lang/String" for Ljava/lang/String;->format(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String; invoke-static stub_class.set_name("L" + PKG_PREFIX + "/" + segs[0][1:]) stub_class.add_access("public") stub_class.set_super_name("Ljava/lang/Object;") self.stub_classes[segs[0]] = stub_class self.class_map[segs[0]] = "L" + PKG_PREFIX + "/" + segs[0][1:] #.method public constructor <init>()V # .registers 1 # invoke-direct {p0}, Ljava/lang/Object;-><init>()V # return-void #.end method method = MethodNode() method.set_desc("<init>()V") method.add_access(["public", "constructor"]) method.set_registers(1) i1 = InsnNode("invoke-direct {p0}, Ljava/lang/Object;-><init>()V") i2 = InsnNode("return-void") method.add_insn([i1, i2]) stub_class.add_method(method) method_name = segs[1][:segs[1].find("(")] #print stub_class.name,method_name,method_type,parent_class.name if method_type == "constructor": self.__add_stub_cons2(stub_class, m, parent_class, parent_method) elif method_type == "instance": self.__add_stub_inst(stub_class, on, m, parent_class, parent_method) elif method_type == "static": self.__add_stub_static(stub_class, m, parent_class, parent_method)
def add_stub_method(self, on, m): #segs = m.split(':', 1) #method_type = segs[0] #m = segs[1] method_type = METHOD_TYPE_BY_OPCODE[on] segs = m.rsplit("->", 1) if self.stub_classes.has_key(segs[0]): stub_class = self.stub_classes[segs[0]] else: stub_class = ClassNode() stub_class.set_name("L" + PKG_PREFIX + "/" + segs[0][1:]) stub_class.add_access("public") stub_class.set_super_name("Ljava/lang/Object;") self.stub_classes[segs[0]] = stub_class self.class_map[segs[0]] = "L" + PKG_PREFIX + "/" + segs[0][1:] #.method public constructor <init>()V # .registers 1 # invoke-direct {p0}, Ljava/lang/Object;-><init>()V # return-void #.end method method = MethodNode() method.set_desc("<init>()V") method.add_access(["public", "constructor"]) method.set_registers(1) i1 = InsnNode("invoke-direct {p0}, Ljava/lang/Object;-><init>()V") i2 = InsnNode("return-void") method.add_insn([i1, i2]) stub_class.add_method(method) method_name = segs[1][:segs[1].find("(")] if method_type == "constructor": self.__add_stub_cons2(stub_class, m) elif method_type == "instance": self.__add_stub_inst(stub_class, on, m) elif method_type == "static": self.__add_stub_static(stub_class, m)
def __add_stub_static(self, stub_class, m): segs = m.rsplit("->", 1) method = MethodNode() method.set_desc(segs[1]) method.add_access(["public", "static"]) para_num = len(method.paras) reg_num = method.get_paras_reg_num() ri = 1 if reg_num <= 5: i = "invoke-static {%s}, %s" % \ (", ".join(["p%d" % k for k in range(reg_num)]), m) else: i = "invoke-static/range {p0 .. p%d}, %s" % (reg_num - 1, m) method.add_insn(InsnNode(i)) if not method.ret.void: if method.ret.basic and method.ret.dim == 0: if method.ret.words == 1: method.add_insn(InsnNode("move-result v1")) ri += 1 else: method.add_insn(InsnNode("move-result-wide v1")) ri += 2 else: method.add_insn(InsnNode("move-result-object v1")) ri += 1 method.add_insn(InsnNode("new-instance \ v%d, Ljava/lang/StringBuilder;" % ri)) method.add_insn(InsnNode("invoke-direct \ {v%d}, Ljava/lang/StringBuilder;-><init>()V" % ri)) method.add_insn(InsnNode("const-string v%d,\"%s(\"" % \ (ri + 1, m.split('(', 1)[0]))) append_i = InsnNode("invoke-virtual \ {v%d, v%d}, Ljava/lang/StringBuilder;->\ append(Ljava/lang/String;)Ljava/lang/StringBuilder;" % \ (ri, ri + 1)) method.add_insn(append_i) # print parameters pi = 0 for k in range(0, para_num): p = method.paras[k] method.add_insn(InsnNode("const-string v%d, \"%s=\"" % (ri + 1, p.get_desc()))) method.add_insn(append_i) if p.basic and p.dim == 0: if p.words == 1: method.add_insn(InsnNode("invoke-static {p%d}, \ Ljava/lang/String;->valueOf(%s)Ljava/lang/String;" % \ (pi, p.get_desc()))) pi += 1 else: method.add_insn(InsnNode("invoke-static \ {p%d, p%d}, Ljava/lang/String;->valueOf(%s)Ljava/lang/String;" % \ (pi, pi + 1, p.get_desc()))) pi += 2 method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(append_i) else: method.add_insn(InsnNode("invoke-static {p%d}, \ Ldroidbox/apimonitor/Helper;->toString(Ljava/lang/Object;)Ljava/lang/String;" % (pi, ))) pi += 1 method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(append_i) if k < para_num - 1: method.add_insn(InsnNode("const-string v%d, \" | \"" % \ (ri + 1))) method.add_insn(append_i) method.add_insn(InsnNode("const-string v%d, \")\"" % (ri + 1))) method.add_insn(append_i) # print return value p = method.ret if p.void: method.add_insn(InsnNode("const-string v%d, \"%s\"" % (ri + 1, p.get_desc()))) method.add_insn(append_i) else: method.add_insn(InsnNode("const-string v%d, \"%s=\"" % (ri + 1, p.get_desc()))) method.add_insn(append_i) if p.basic and p.dim == 0: if p.words == 1: method.add_insn(InsnNode("invoke-static {v1}, \ Ljava/lang/String;->valueOf(%s)Ljava/lang/String;" % \ p.get_desc())) else: method.add_insn(InsnNode("invoke-static \ {v1, v2}, Ljava/lang/String;->valueOf(%s)Ljava/lang/String;" % \ p.get_desc())) method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(append_i) else: method.add_insn(InsnNode("invoke-static {v1}, \ Ldroidbox/apimonitor/Helper;->toString(Ljava/lang/Object;)Ljava/lang/String;")) method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(append_i) method.add_insn(InsnNode("invoke-virtual {v%d}, \ Ljava/lang/StringBuilder;->toString()Ljava/lang/String;" % ri)) method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(InsnNode("invoke-static {v%d}, \ Ldroidbox/apimonitor/Helper;->log(Ljava/lang/String;)V" % \ (ri + 1, ))) if not method.ret.void: if method.ret.basic and method.ret.dim == 0: if method.ret.words == 1: method.add_insn(InsnNode("return v1")) else: method.add_insn(InsnNode("return-wide v1")) else: method.add_insn(InsnNode("return-object v1")) else: method.add_insn(InsnNode("return-void")) start = LabelNode(":droidbox_try_start", 0) end = LabelNode(":droidbox_try_end", 1) index = len(method.insns) ret = LabelNode(":droidbox_return", index - 1) handler = LabelNode(":droidbox_handler", index) line = ".catch Ljava/lang/Exception; {:droidbox_try_start .. \ :droidbox_try_end} :droidbox_handler" TryNode(line, start, end, handler) method.add_label([start, end, ret, handler]) method.add_insn(InsnNode("move-exception v0")) method.add_insn(InsnNode("invoke-virtual {v0}, \ Ljava/lang/Exception;->printStackTrace()V")) if not method.ret.void: if method.ret.basic and method.ret.dim == 0: if method.ret.words == 1: method.add_insn(InsnNode("const/4 v1, 0x0")) else: method.add_insn(InsnNode("const-wide/16 v1, 0x0")) else: method.add_insn(InsnNode("const/4 v1, 0x0")) method.add_insn(InsnNode("goto :droidbox_return")) method.set_registers(reg_num + ri + 2) stub_class.add_method(method) i = m.find('(') self.method_map[m] = "L" + PKG_PREFIX + "/" + segs[0][1:] + "->" + \ method.get_desc()
def __add_stub_cons2(self, stub_class, m): segs = m.rsplit("->", 1) desc = segs[1].replace("<init>", "droidbox_cons") i = desc.find(')') desc = desc[:i + 1] + 'V' method = MethodNode() method.set_desc(desc) method.add_access(["public", "static"]) para_num = len(method.paras) reg_num = method.get_paras_reg_num() ri = 0 method.add_insn(InsnNode("new-instance \ v%d, Ljava/lang/StringBuilder;" % ri)) method.add_insn(InsnNode("invoke-direct \ {v%d}, Ljava/lang/StringBuilder;-><init>()V" % ri)) method.add_insn(InsnNode("const-string v%d,\"%s(\"" % \ (ri + 1, m.split('(', 1)[0]))) append_i = InsnNode("invoke-virtual \ {v%d, v%d}, Ljava/lang/StringBuilder;->\ append(Ljava/lang/String;)Ljava/lang/StringBuilder;" % \ (ri, ri + 1)) method.add_insn(append_i) # print parameters pi = 0 for k in range(0, para_num): p = method.paras[k] method.add_insn(InsnNode("const-string v%d, \"%s=\"" % (ri + 1, p.get_desc()))) method.add_insn(append_i) if p.basic and p.dim == 0: if p.words == 1: method.add_insn(InsnNode("invoke-static {p%d}, \ Ljava/lang/String;->valueOf(%s)Ljava/lang/String;" % \ (pi, p.get_desc()))) pi += 1 else: method.add_insn(InsnNode("invoke-static \ {p%d, p%d}, Ljava/lang/String;->valueOf(%s)Ljava/lang/String;" % \ (pi, pi + 1, p.get_desc()))) pi += 2 method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(append_i) else: method.add_insn(InsnNode("invoke-static {p%d}, \ Ldroidbox/apimonitor/Helper;->toString(Ljava/lang/Object;)Ljava/lang/String;" % (pi, ))) pi += 1 method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(append_i) if k < para_num - 1: method.add_insn(InsnNode("const-string v%d, \" | \"" % \ (ri + 1))) method.add_insn(append_i) method.add_insn(InsnNode("const-string v%d, \")\"" % (ri + 1))) method.add_insn(append_i) # print return value p = method.ret if p.void: method.add_insn(InsnNode("const-string v%d, \"%s\"" % (ri + 1, p.get_desc()))) method.add_insn(append_i) else: method.add_insn(InsnNode("const-string v%d, \"%s=\"" % (ri + 1, p.get_desc()))) method.add_insn(append_i) if p.basic and p.dim == 0: if p.words == 1: method.add_insn(InsnNode("invoke-static {v1}, \ Ljava/lang/String;->valueOf(%s)Ljava/lang/String;" % \ p.get_desc())) else: method.add_insn(InsnNode("invoke-static \ {v1, v2}, Ljava/lang/String;->valueOf(%s)Ljava/lang/String;" % \ p.get_desc())) method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(append_i) else: method.add_insn(InsnNode("invoke-static {v1}, \ Ldroidbox/apimonitor/Helper;->toString(Ljava/lang/Object;)Ljava/lang/String;")) method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(append_i) method.add_insn(InsnNode("invoke-virtual {v%d}, \ Ljava/lang/StringBuilder;->toString()Ljava/lang/String;" % ri)) method.add_insn(InsnNode("move-result-object v%d" % (ri + 1))) method.add_insn(InsnNode("invoke-static {v%d}, \ Ldroidbox/apimonitor/Helper;->log(Ljava/lang/String;)V" % \ (ri + 1, ))) if not method.ret.void: if method.ret.basic and method.ret.dim == 0: if method.ret.words == 1: method.add_insn(InsnNode("return v1")) else: method.add_insn(InsnNode("return-wide v1")) else: method.add_insn(InsnNode("return-object v1")) else: method.add_insn(InsnNode("return-void")) method.set_registers(reg_num + ri + 2) stub_class.add_method(method) i = m.find('(') self.method_map[m] = "L" + PKG_PREFIX + "/" + segs[0][1:] + "->" + \ method.get_desc()