Example #1
0
    def inject(self, smali_tree, level):
        # get a copy of smali tree
        st = copy.deepcopy(smali_tree)

        # load api database
        print "Loading and processing API database..."
        level = self.load_api(level)
        print "Target API Level: %d" % level
        # check and fix apis in API_LIST
        method_descs = []
        for m in self.entries:
            c = ""
            api_name = ""
            method_name = ""

            ia = m.find("->")
            ilb = m.find('(')

            if ia >= 0:
                c = m[:ia]
                if ilb >= 0:
                    method_name = m[ia + 2:ilb]
                    api_name = m[ia + 2:]
                else:
                    method_name = m[ia + 2:]
            else:
                c = m

            if not self.android_api.classes.has_key(c):
                print "[Warn] Class not found in API-%d db: %s" % (level, m)
                continue
            # just class name
            if not method_name:
                ms = self.android_api.classes[c].methods.keys()
                method_descs.extend(ms)
            # full signature
            elif api_name:
                if not self.android_api.classes[c].methods.has_key(m):
                    if method_name == "<init>":
                        print "[Warn] Method not found in API-%d db: %s" % (level, m)
                        continue
                    c_obj = self.android_api.classes[c]
                    existed = False
                    q = c_obj.supers
                    while q:
                        cn = q.pop(0)
                        c_obj = self.android_api.classes[cn]
                        nm = c_obj.desc + "->" + api_name
                        if c_obj.methods.has_key(nm):
                            existed = True
                            if not nm in self.entries:
                                print "[Warn] Inferred API: %s" % (nm, )
                                method_descs.append(nm)
                        else:
                            q.extend(self.android_api.classes[cn].supers)

                    if not existed:
                        print "[Warn] Method not found in API-%d db: %s" % (level, m)
                else:
                    method_descs.append(m)
            # signature without parameters
            else:
                own = False
                if self.android_api.classes[c].methods_by_name.has_key(method_name):
                    ms = self.android_api.classes[c].methods_by_name[method_name]
                    method_descs.extend(ms)
                    own = True

                if method_name == "<init>":
                    continue
                c_obj = self.android_api.classes[c]
                existed = False
                q = c_obj.supers
                while q:
                    cn = q.pop(0)
                    c_obj = self.android_api.classes[cn]
                    if c_obj.methods_by_name.has_key(method_name):
                        existed = True
                        inferred = "%s->%s" % (c_obj.desc, method_name)
                        if not inferred in self.entries:
                            print "[Warn] Inferred API: %s" % inferred
                            method_descs.extend(c_obj.methods_by_name[method_name])
                    else:
                        q.extend(self.android_api.classes[cn].supers)

                if (not own) and (not existed):
                    print "[Warn] Method not found in API-%d db: %s" % (level, m)

        self.method_descs = list(set(method_descs))

        """ 
        print "**************************"
        self.method_descs.sort()
        print "\n".join(self.method_descs)
        print "**************************"
        """
        for m in self.method_descs:
            self.api_dict[m] = ""
            ia = m.find("->")
            ilb = m.find('(')
            if m[ia + 2:ilb] != "<init>":
                self.api_name_dict[m[ia + 2:]] = m[:ia]
        print "Done!"

        print "Injecting..."
        for c in st.classes:
            class_ = AndroidClass()
            class_.isAPI = False

            class_.desc = c.name
            class_.name= c.name[1:-1].replace('/', '.')
            class_.access = c.access
            if "interface" in c.access:
                class_.supers.extend(c.implements)
            else:
                class_.implements = c.implements
                class_.supers.append(c.super_name)

            for m in c.methods:
                method = AndroidMethod()
                method.isAPI = False
                method.desc = "%s->%s" % (c.name, m.descriptor)
                method.name = m.descriptor.split('(', 1)[0]
                #print method.desc
                method.sdesc = method.desc[:method.desc.rfind(')') + 1]
                method.access = m.access
                class_.methods[method.sdesc] = method 
            self.android_api.add_class(class_)
        self.android_api.build_connections(False)
        #self.android_api.show_not_API()

        for c in st.classes:
            for m in c.methods:
                i = 0
                while i < len(m.insns):
                    insn = m.insns[i]
                    if insn.fmt == "35c":
                        md = insn.obj.method_desc
                        on = insn.opcode_name
                        irb = md.find(')')
                        smd = md[:irb + 1]
                        if self.api_dict.has_key(smd):
                            method_type = METHOD_TYPE_BY_OPCODE[on]
                            new_on = OPCODE_MAP[on]
                            if not self.method_map.has_key(md):
                                self.add_stub_method(on, md)
                            if method_type == "constructor":
                                insn_m = copy.deepcopy(insn)
                                insn_m.obj.replace(new_on, \
                                        self.method_map[md])
                                r = insn_m.obj.registers.pop(0)
                                m.insert_insn(insn_m, i , 0)
                                i += 1
                                """
                                insn.obj.replace(new_on, \
                                        self.method_map[md])
                                r = insn.obj.registers.pop(0)
                                m.insert_insn(InsnNode(\
"move-result-object %s" % r), i + 1, 0)
                                i += 1
                                """
                            else:
                                insn.obj.replace(new_on, \
                                                 self.method_map[md])
                        else:
                            ia = md.find("->")
                            cn = md[:ia]
                            api_name = smd[ia + 2:]
                            if self.api_name_dict.has_key(api_name):
                                if self.android_api.classes.has_key(cn):
                                    if not self.android_api.classes[cn].methods.has_key(smd):
                                        api_cn = self.api_name_dict[api_name]
                                        if api_cn in self.android_api.classes[cn].ancestors:
                                            self.api_dict[smd] = ""
                                            i -= 1

                    elif insn.fmt == "3rc":
                        md = insn.obj.method_desc
                        on = insn.opcode_name
                        smd = md[:md.rfind(')') + 1]
                        if self.api_dict.has_key(smd):
                            method_type = METHOD_TYPE_BY_OPCODE[on]
                            new_on = OPCODE_MAP[on]
                            if not self.method_map.has_key(md):
                                self.add_stub_method(on, md)
                            if method_type == "constructor":
                                insn_m = copy.deepcopy(insn)
                                insn_m.obj.replace(new_on, \
                                        self.method_map[md])
                                r = insn_m.obj.reg_start
                                nr = r[0] + str(int(r[1:]) + 1)
                                insn_m.obj.set_reg_start(nr)
                                m.insert_insn(insn_m, i , 0)
                                i += 1
                                """
                                insn.obj.replace(new_on, \
                                        self.method_map[md])
                                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)
                                i += 1
                                """
                            else:
                                insn.obj.replace(new_on, \
                                                 self.method_map[md])
                        else:
                            ia = md.find("->")
                            cn = md[:ia]
                            api_name = smd[ia + 2:]
                            if self.api_name_dict.has_key(api_name):
                                if self.android_api.classes.has_key(cn):
                                    if not self.android_api.classes[cn].methods.has_key(smd):
                                        api_cn = self.api_name_dict[api_name]
                                        if api_cn in self.android_api.classes[cn].ancestors:
                                            self.api_dict[smd] = ""
                                            i -= 1
                    i += 1

        for c in self.stub_classes.values():
            st.add_class(c)

        st.add_class(self.helper)
        print "Done!"

        return st