mirror of
https://github.com/EchoStretch/kstuff.git
synced 2026-10-22 11:42:27 -05:00
porting_tool: add shellcore offsets
These are in userspace, but I decided to add them anyway, because more automation is nice.
This commit is contained in:
1 parent
743dd62679
commit
91273eaf2f
2 files changed
+121
-26
No files matched your search
+13
-9
@@ -375,6 +375,7 @@ static struct shellcore_patch shellcore_patches_403[] = {
|
||||
{0x974ba9, "\xe8\x22\x00\x00\x00\x58\xc3", 7}, //call 0x974bd0; pop rax; ret
|
||||
{0x5307f9, "\xeb\x04", 2}, //jmp 0x5307ff
|
||||
{0x26f35c, "\xeb\x04", 2}, //jmp 0x26f362
|
||||
{0x26f76c, "\xeb\x04", 2}, //jmp 0x26f772
|
||||
{0x54e1f0, "\xeb", 1}, //jmp (destination unchanged)
|
||||
{0x536e1d, "\x90\xe9", 2}, //nop; jmp (destination unchanged)
|
||||
{0x54db8f, "\xeb", 1}, //jmp (destination unchanged)
|
||||
@@ -475,10 +476,10 @@ void patch_app_db(void);
|
||||
static struct PARASITES(100) parasites_empty = {};
|
||||
#endif
|
||||
|
||||
static struct PARASITES(13) parasites_403 = {
|
||||
static struct PARASITES(14) parasites_403 = {
|
||||
.lim_syscall = 3,
|
||||
.lim_fself = 11,
|
||||
.lim_total = 13,
|
||||
.lim_fself = 12,
|
||||
.lim_total = 14,
|
||||
.parasites = {
|
||||
/* syscall parasites */
|
||||
{-0x80284d, RDI},
|
||||
@@ -490,6 +491,7 @@ static struct PARASITES(13) parasites_403 = {
|
||||
{-0x2cd150, RAX},
|
||||
{-0x2cce73, RAX},
|
||||
{-0x2ccbfd, RAX},
|
||||
{-0x2cc88e, RDX},
|
||||
{-0x2cc882, RCX},
|
||||
{-0x990b10, RDI},
|
||||
{-0x2ccd36, R10},
|
||||
@@ -499,10 +501,10 @@ static struct PARASITES(13) parasites_403 = {
|
||||
}
|
||||
};
|
||||
|
||||
static struct PARASITES(13) parasites_450 = {
|
||||
static struct PARASITES(14) parasites_450 = {
|
||||
.lim_syscall = 3,
|
||||
.lim_fself = 11,
|
||||
.lim_total = 13,
|
||||
.lim_fself = 12,
|
||||
.lim_total = 14,
|
||||
.parasites = {
|
||||
/* syscall parasites */
|
||||
{-0x80281d, RDI},
|
||||
@@ -514,6 +516,7 @@ static struct PARASITES(13) parasites_450 = {
|
||||
{-0x2ccfa0, RAX},
|
||||
{-0x2cccc3, RAX},
|
||||
{-0x2cca4d, RAX},
|
||||
{-0x2cc6de, RDX},
|
||||
{-0x2cc6d2, RCX},
|
||||
{-0x990b10, RDI},
|
||||
{-0x2ccb86, R10},
|
||||
@@ -523,10 +526,10 @@ static struct PARASITES(13) parasites_450 = {
|
||||
}
|
||||
};
|
||||
|
||||
static struct PARASITES(13) parasites_451 = {
|
||||
static struct PARASITES(14) parasites_451 = {
|
||||
.lim_syscall = 3,
|
||||
.lim_fself = 11,
|
||||
.lim_total = 13,
|
||||
.lim_fself = 12,
|
||||
.lim_total = 14,
|
||||
.parasites = {
|
||||
/* syscall parasites */
|
||||
{-0x80281d, RDI},
|
||||
@@ -538,6 +541,7 @@ static struct PARASITES(13) parasites_451 = {
|
||||
{-0x2ccc00, RAX},
|
||||
{-0x2cc923, RAX},
|
||||
{-0x2cc6ad, RAX},
|
||||
{-0x2cc33e, RDX},
|
||||
{-0x2cc332, RCX},
|
||||
{-0x990b10, RDI},
|
||||
{-0x2cc7e6, R10},
|
||||
|
||||
+108
-17
@@ -1,4 +1,4 @@
|
||||
import sys, json, threading, functools, os.path, collections, tarfile, io
|
||||
import sys, json, threading, functools, os.path, collections, tarfile, io, re
|
||||
|
||||
if 'linux' not in sys.platform:
|
||||
print('This tool only supports GNU/Linux! Use Docker or WSL on other OSes.')
|
||||
@@ -591,15 +591,19 @@ def dr2gpr_start():
|
||||
@derive_symbols('malloc', 'M_something')
|
||||
@retry_on_error
|
||||
def malloc():
|
||||
use_r0gdb_trace(16777216)
|
||||
kdata_base = gdb.ieval('kdata_base')
|
||||
# use the ipv6 rthdr allocation to find malloc
|
||||
# 1224 is a valid size for rthdr, and prosper0gdb already has set_rthdr_size function that wraps the raw ioctl
|
||||
remote_sock = gdb.ieval('(int)socket(28, 2, 0)') # udpv6
|
||||
assert remote_sock >= 0
|
||||
trace = traces.Trace(r0gdb.trace('trace_skip_scheduler_only', 'set_rthdr_size', remote_sock, 1224))
|
||||
assert gdb.ieval('$rax') == 0
|
||||
malloc_call, = (i for i in range(len(trace)) if trace.is_jump(i) and trace[i+1].rsp == trace[i].rsp-8 and trace[i].rdi == 1224 and trace[i].rdx == 1)
|
||||
while True:
|
||||
use_r0gdb_trace(16777216)
|
||||
kdata_base = gdb.ieval('kdata_base')
|
||||
# use the ipv6 rthdr allocation to find malloc
|
||||
# 1224 is a valid size for rthdr, and prosper0gdb already has set_rthdr_size function that wraps the raw ioctl
|
||||
remote_sock = gdb.ieval('(int)socket(28, 2, 0)') # udpv6
|
||||
assert remote_sock >= 0
|
||||
trace = traces.Trace(r0gdb.trace('trace_skip_scheduler_only', 'set_rthdr_size', remote_sock, 1224))
|
||||
assert gdb.ieval('$rax') == 0
|
||||
malloc_calls = [i for i in range(len(trace)) if trace.is_jump(i) and trace[i+1].rsp == trace[i].rsp-8 and trace[i].rdi == 1224 and trace[i].rdx == 1]
|
||||
if len(malloc_calls) == 1: break
|
||||
gdb.kill()
|
||||
malloc_call = malloc_calls[0]
|
||||
malloc = trace[malloc_call+1].rip
|
||||
M_something = trace[malloc_call+1].rsi
|
||||
return malloc - kdata_base, M_something - kdata_base
|
||||
@@ -803,13 +807,7 @@ def run_make_fself(elf_data, auth_info):
|
||||
self.save(self_file)
|
||||
return self_file.getvalue()
|
||||
|
||||
def make_fself_and_upload(name, path):
|
||||
full_name = name
|
||||
name = name.split('.', 1)[0]
|
||||
fd = gdb.ieval('(int)open("/data/%s", 0)'%full_name)
|
||||
if fd >= 0:
|
||||
assert not gdb.ieval('(int)close(%d)'%fd)
|
||||
return True
|
||||
def dump_self(name, path):
|
||||
use_self_dumper()
|
||||
assert not gdb.ieval('($self_file_%s = &*(struct memfd[1]){dump_elf("%s")}, 0)'%(name, path))
|
||||
assert not gdb.ieval('($self_auth_info_%s = &*(struct memfd[1]){dump_elf_auth_info("%s")}, 0)'%(name, path))
|
||||
@@ -827,6 +825,16 @@ def make_fself_and_upload(name, path):
|
||||
elf_data = files['binary.elf']
|
||||
auth_info = files['binary.elf.auth_info']
|
||||
assert elf_data and len(auth_info) == 0x88
|
||||
return elf_data, auth_info
|
||||
|
||||
def make_fself_and_upload(name, path):
|
||||
full_name = name
|
||||
name = name.split('.', 1)[0]
|
||||
fd = gdb.ieval('(int)open("/data/%s", 0)'%full_name)
|
||||
if fd >= 0:
|
||||
assert not gdb.ieval('(int)close(%d)'%fd)
|
||||
return True
|
||||
elf_data, auth_info = dump_self(name, path)
|
||||
self_data = run_make_fself(elf_data, auth_info)
|
||||
with gdb_rpc.BlobSender(gdb, self_data, 'writing fself file to /data/%s'%full_name) as addr:
|
||||
remote_fd = gdb.ieval('r0gdb_open_socket("%s", %d)'%addr)
|
||||
@@ -838,6 +846,7 @@ def make_fself_and_upload(name, path):
|
||||
return False
|
||||
|
||||
def ensure_fselfs(fn):
|
||||
fn_run = False
|
||||
if gdb.popen == None:
|
||||
fn()
|
||||
fn_run = True
|
||||
@@ -991,6 +1000,88 @@ def loadSelfSegment_watchpoint():
|
||||
assert len(watchpoints) == 1
|
||||
return (min(next(iter(watchpoints))),)+tuple(rest)
|
||||
|
||||
@derive_symbol
|
||||
@retry_on_error
|
||||
def fself_parasites():
|
||||
ensure_fselfs(use_kstuff)
|
||||
init_kstuff()
|
||||
kdata_base = gdb.ieval('kdata_base')
|
||||
assert gdb.ieval('(int)dlopen("/data/libScePlayerInvitationDialog.sprx", 0)') > 0
|
||||
fd = gdb.ieval('(int)open("/data/libSceLibcInternal.sprx", 0)')
|
||||
assert fd >= 0
|
||||
mapping = gdb.ieval('(void*)mmap(0, 65536, 1, 0x80001, %d, 0)'%fd)
|
||||
assert mapping != 2**64-1
|
||||
gdb.ieval('{void*}%d'%mapping)
|
||||
assert not gdb.ieval('(int)mlock(%d, 16384)'%mapping)
|
||||
assert not gdb.ieval('(int)mlock(%d, 65536)'%mapping)
|
||||
assert not gdb.ieval('(int)munmap(%d, 65536)'%mapping)
|
||||
assert not gdb.ieval('(int)close(%d)'%fd)
|
||||
ans = get_parasites(kdata_base)
|
||||
assert len(ans) == 10
|
||||
return [(i, j) for i, j in ans if not (j == 10 and (i, 7) in ans)]
|
||||
|
||||
def elf_to_flat(data):
|
||||
assert data.startswith(b'\x7fELF') and len(data) >= 64
|
||||
ans = bytearray()
|
||||
phoff = int.from_bytes(data[32:40], 'little')
|
||||
phnum = int.from_bytes(data[56:58], 'little')
|
||||
assert len(data) >= phoff+56*phnum
|
||||
for i in range(phoff, phoff+56*phnum, 56):
|
||||
ptype = int.from_bytes(data[i:i+4], 'little')
|
||||
if ptype != 1: continue
|
||||
offset = int.from_bytes(data[i+8:i+16], 'little')
|
||||
vaddr = int.from_bytes(data[i+16:i+24], 'little')
|
||||
filesz = int.from_bytes(data[i+32:i+40], 'little')
|
||||
memsz = int.from_bytes(data[i+40:i+48], 'little')
|
||||
assert memsz >= filesz
|
||||
assert len(data) >= offset + filesz
|
||||
ans[vaddr:vaddr+filesz] = data[offset:offset+filesz]
|
||||
ans[vaddr+filesz:vaddr+memsz] = bytes(memsz-filesz)
|
||||
return ans
|
||||
|
||||
@derive_symbol
|
||||
@retry_on_error
|
||||
def shellcore_offsets():
|
||||
shellcore = elf_to_flat(dump_self('SceShellCore', '/system/vsh/SceShellCore.elf')[0])
|
||||
shellcore_txt = shellcore.decode('latin-1').replace('\n', '\u010a')
|
||||
def get_offsets(regexp):
|
||||
return [shellcore_txt.find(i) for i in re.compile(regexp).findall(shellcore_txt)]
|
||||
ans = []
|
||||
offset, = get_offsets(r'\x80\x3d....\x01\x75\u010a\x48\x89\xd1\x31\xd2\xe9....\xb8\x01\x00\xe9\x80\xc3\xcc{7}')
|
||||
target_fn = int.from_bytes(shellcore[offset+15:offset+19], 'little', signed=True)+offset+19
|
||||
ans.append((offset+14, '52eb086690'))
|
||||
ans.append((offset+25, (b'\xe8'+(target_fn-offset-30).to_bytes(4, 'little', signed=True)+b'\x58\xc3').hex()))
|
||||
offset, = get_offsets(r'\xcc{7}\x80\x3d....\x01\x75\x0d\x48\x89\xd1\xba\x01\x00\x00\x00\xe9....\xb8\x01\x00\xe9\x80\xc3')
|
||||
target_fn = int.from_bytes(shellcore[offset+25:offset+29], 'little', signed=True)+offset+29
|
||||
ans.append((offset+24, '31c050ebe3'))
|
||||
ans.append((offset, (b'\xe8'+(target_fn-offset-5).to_bytes(4, 'little', signed=True)+b'\x58\xc3').hex()))
|
||||
offset, = get_offsets(r'\x44\x89\xe0\xff\xc8\x83\xf8\x02\x0f\x83')
|
||||
ans.append((offset+8, 'eb04'))
|
||||
offset1, offset2 = get_offsets(r'\xe8....\x85\xc0\x0f\x88....\x49\x8b\x46\x20\x48\xba\x00\xff\x00\xff\x00\xff\x00\xff')
|
||||
ans.append((offset1+7, 'eb04'))
|
||||
ans.append((offset2+7, 'eb04'))
|
||||
offset, = get_offsets(r'\x41\x39\xdc\x74.\x48\x8d\x3d....')
|
||||
ans.append((offset+3, 'eb'))
|
||||
offset, = get_offsets(r'\x83\xbb....\x03\x0f\x84')
|
||||
ans.append((offset+7, '90e9'))
|
||||
offset, = get_offsets(r'\x41\x81\xff\x60\x00\x02\x80\x0f\x85....\x80\x7c\x24.\x00\x74.')
|
||||
ans.append((offset+18, 'eb'))
|
||||
offset, = get_offsets(r'\x83\xfb\x01\x0f\x84....\x83\xfb\x02\x0f\x85....')
|
||||
target = int.from_bytes(shellcore[offset+5:offset+9], 'little', signed=True)+offset+9
|
||||
ans.append((offset+14, (target-offset-18).to_bytes(4, 'little', signed=True).hex()))
|
||||
for offset, data in ans:
|
||||
data = bytes.fromhex(data)
|
||||
shellcore[offset:offset+len(data)] = data
|
||||
offset, = get_offsets(r'\xeb.\x48\x8b\x32\x48\x89\xdf\xe8....\xeb.\x48\x8b\x02\x49\x8b\x37')
|
||||
target = int.from_bytes(shellcore[offset+9:offset+13], 'little', signed=True)+offset+13
|
||||
target2 = int.from_bytes(shellcore[offset+14:offset+15], 'little', signed=True)+offset+15
|
||||
cave1 = shellcore.find(b'\xcc'*14, offset)
|
||||
cave2 = shellcore.find(b'\xcc'*11, cave1+14)
|
||||
ans.append((cave1, (b'\xe8'+(target-cave1-5).to_bytes(4, 'little', signed=True)+b'\x31\xc9\xff\xc1\xe9'+(cave2-cave1-14).to_bytes(4, 'little', signed=True)).hex()))
|
||||
ans.append((cave2, (b'\x83\xf8\x02\x0f\x43\xc1\xe9'+(target2-cave2-11).to_bytes(4, 'little', signed=True)).hex()))
|
||||
ans.append((offset+8, (b'\xe9'+(cave1-offset-13).to_bytes(4, 'little', signed=True)).hex()))
|
||||
return ans
|
||||
|
||||
print(len(symbols), 'offsets currently known')
|
||||
print(sum(sum(j not in symbols for j in i[1]) if isinstance(i, tuple) else (i.__name__ not in symbols) for i in derivations), 'offsets to be found')
|
||||
|
||||
|
||||
Reference in new issue
Block a user