forked from n0llptr/remote_lua_loader
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathelf_loader.lua
More file actions
257 lines (184 loc) · 9.12 KB
/
Copy pathelf_loader.lua
File metadata and controls
257 lines (184 loc) · 9.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
-- rudimentary elf loader
-- only expected to load john tornblom's elfldr.elf
-- credit to nullptr for porting and specter for the original code
elf_loader = {}
elf_loader.__index = elf_loader
elf_loader.shadow_mapping_addr = uint64(0x920100000)
elf_loader.mapping_addr = uint64(0x926100000)
function elf_loader:load_from_file(filepath)
if not file_exists(filepath) then
errorf("file not exist: %s", filepath)
end
local self = setmetatable({}, elf_loader)
self.filepath = filepath
self.elf_data = file_read(filepath)
self.parse(self)
return self
end
function elf_loader:parse()
-- ELF sizes and offsets
local SIZE_ELF_HEADER = 0x40
local SIZE_ELF_PROGRAM_HEADER = 0x38
local SIZE_ELF_SECTION_HEADER = 0x40
local OFFSET_ELF_HEADER_ENTRY = 0x18
local OFFSET_ELF_HEADER_PHOFF = 0x20
local OFFSET_ELF_HEADER_SHOFF = 0x28
local OFFSET_ELF_HEADER_PHNUM = 0x38
local OFFSET_ELF_HEADER_SHNUM = 0x3c
local OFFSET_PROGRAM_HEADER_TYPE = 0x00
local OFFSET_PROGRAM_HEADER_FLAGS = 0x04
local OFFSET_PROGRAM_HEADER_OFFSET = 0x08
local OFFSET_PROGRAM_HEADER_VADDR = 0x10
local OFFSET_PROGRAM_HEADER_FILESZ = 0x20
local OFFSET_PROGRAM_HEADER_MEMSZ = 0x28
local OFFSET_SECTION_HEADER_TYPE = 0x4
local OFFSET_SECTION_HEADER_OFFSET = 0x18
local OFFSET_SECTION_HEADER_SIZE = 0x20
local OFFSET_RELA_OFFSET = 0x00
local OFFSET_RELA_INFO = 0x08
local OFFSET_RELA_ADDEND = 0x10
local SHT_RELA = 0x4
local RELA_ENTSIZE = 0x18
local PF_X = 1
-- ELF program header types
local ELF_PT_LOAD = 0x01
local ELF_PT_DYNAMIC = 0x02
-- ELF dynamic table types
local ELF_DT_NULL = 0x00
local ELF_DT_RELA = 0x07
local ELF_DT_RELASZ = 0x08
local ELF_DT_RELAENT = 0x09
local ELF_R_AMD64_RELATIVE = 0x08
local elf_store = lua.resolve_value(self.elf_data)
local elf_entry = memory.read_dword(elf_store + OFFSET_ELF_HEADER_ENTRY):tonumber()
self.elf_entry_point = elf_loader.mapping_addr + elf_entry
local elf_program_headers_offset = memory.read_dword(elf_store + OFFSET_ELF_HEADER_PHOFF):tonumber()
local elf_program_headers_num = memory.read_word(elf_store + OFFSET_ELF_HEADER_PHNUM):tonumber()
local elf_section_headers_offset = memory.read_dword(elf_store + OFFSET_ELF_HEADER_SHOFF):tonumber()
local elf_section_headers_num = memory.read_word(elf_store + OFFSET_ELF_HEADER_SHNUM):tonumber()
local executable_start = 0
local executable_end = 0
-- parse program headers
for i = 0, elf_program_headers_num-1 do
local phdr_offset = elf_program_headers_offset + (i * SIZE_ELF_PROGRAM_HEADER)
local p_type = memory.read_dword(elf_store + phdr_offset + OFFSET_PROGRAM_HEADER_TYPE):tonumber()
local p_flags = memory.read_dword(elf_store + phdr_offset + OFFSET_PROGRAM_HEADER_FLAGS):tonumber()
local p_offset = memory.read_dword(elf_store + phdr_offset + OFFSET_PROGRAM_HEADER_OFFSET):tonumber()
local p_vaddr = memory.read_dword(elf_store + phdr_offset + OFFSET_PROGRAM_HEADER_VADDR):tonumber()
local p_filesz = memory.read_dword(elf_store + phdr_offset + OFFSET_PROGRAM_HEADER_FILESZ):tonumber()
local p_memsz = memory.read_dword(elf_store + phdr_offset + OFFSET_PROGRAM_HEADER_MEMSZ):tonumber()
local aligned_memsz = bit32.band(p_memsz + 0x3FFF, 0xFFFFC000)
if p_type == ELF_PT_LOAD then
local PROT_RW = bit32.bor(PROT_READ, PROT_WRITE)
local PROT_RWX = bit32.bor(PROT_READ, PROT_WRITE, PROT_EXECUTE)
if bit32.band(p_flags, PF_X) == PF_X then
executable_start = p_vaddr
executable_end = p_vaddr + p_memsz
-- create shm with exec permission
local exec_handle = syscall.jitshm_create(0, aligned_memsz, 0x7)
-- create shm alias with write permission
local write_handle = syscall.jitshm_alias(exec_handle, 0x3)
-- map shadow mapping and write into it
syscall.mmap(elf_loader.shadow_mapping_addr, aligned_memsz, PROT_RW, 0x11, write_handle, 0)
memory.memcpy(elf_loader.shadow_mapping_addr, elf_store + p_offset, p_memsz)
-- map executable segment
syscall.mmap(elf_loader.mapping_addr + p_vaddr, aligned_memsz, PROT_RWX, 0x11, exec_handle, 0)
else
-- copy regular data segment
syscall.mmap(elf_loader.mapping_addr + p_vaddr, aligned_memsz, PROT_RW, 0x1012, 0xFFFFFFFF, 0)
memory.memcpy(elf_loader.mapping_addr + p_vaddr, elf_store + p_offset, p_memsz)
end
end
end
-- apply relocations
for i = 0, elf_section_headers_num-1 do
local shdr_offset = elf_section_headers_offset + (i * SIZE_ELF_SECTION_HEADER)
local sh_type = memory.read_dword(elf_store + shdr_offset + OFFSET_SECTION_HEADER_TYPE):tonumber()
local sh_offset = memory.read_qword(elf_store + shdr_offset + OFFSET_SECTION_HEADER_OFFSET):tonumber()
local sh_size = memory.read_qword(elf_store + shdr_offset + OFFSET_SECTION_HEADER_SIZE):tonumber()
if sh_type == SHT_RELA then
local rela_table_count = sh_size / RELA_ENTSIZE
-- Parse relocs and apply them
for i = 0, rela_table_count-1 do
local r_offset = memory.read_qword(elf_store + sh_offset + (i * RELA_ENTSIZE) + OFFSET_RELA_OFFSET):tonumber()
local r_info = memory.read_qword(elf_store + sh_offset + (i * RELA_ENTSIZE) + OFFSET_RELA_INFO):tonumber()
local r_addend = memory.read_qword(elf_store + sh_offset + (i * RELA_ENTSIZE) + OFFSET_RELA_ADDEND):tonumber()
if bit32.band(r_info, 0xFF) == ELF_R_AMD64_RELATIVE then
local reloc_addr = elf_loader.mapping_addr + r_offset
local reloc_value = elf_loader.mapping_addr + r_addend
-- If the relocation falls in the executable section, we need to redirect the write to the
-- writable shadow mapping or we'll crash
if executable_start <= r_offset and r_offset < executable_end then
reloc_addr = elf_loader.shadow_mapping_addr + r_offset
end
memory.write_qword(reloc_addr, reloc_value)
end
end
end
end
return
end
function elf_loader:run()
local Thrd_create = fcall(libc_addrofs.Thrd_create)
local rwpipe = memory.alloc(8)
local rwpair = memory.alloc(8)
local args = memory.alloc(0x30)
local thr_handle_addr = memory.alloc(8)
memory.write_dword(rwpipe, ipv6_kernel_rw.data.pipe_read_fd)
memory.write_dword(rwpipe + 0x4, ipv6_kernel_rw.data.pipe_write_fd)
memory.write_dword(rwpair, ipv6_kernel_rw.data.master_sock)
memory.write_dword(rwpair + 0x4, ipv6_kernel_rw.data.victim_sock)
local syscall_wrapper = dlsym(0x2001, "getpid")
self.payloadout = memory.alloc(4)
memory.write_qword(args + 0x00, syscall_wrapper) -- arg1 = syscall wrapper
memory.write_qword(args + 0x08, rwpipe) -- arg2 = int *rwpipe[2]
memory.write_qword(args + 0x10, rwpair) -- arg3 = int *rwpair[2]
memory.write_qword(args + 0x18, ipv6_kernel_rw.data.pipe_addr) -- arg4 = uint64_t kpipe_addr
memory.write_qword(args + 0x20, kernel.addr.data_base) -- arg5 = uint64_t kdata_base_addr
memory.write_qword(args + 0x28, self.payloadout) -- arg6 = int *payloadout
printf("spawning %s", self.filepath)
-- spawn elf in new thread
local ret = Thrd_create(thr_handle_addr, self.elf_entry_point, args):tonumber()
if ret ~= 0 then
error("Thrd_create() error: " .. hex(ret))
end
self.thr_handle = memory.read_qword(thr_handle_addr)
end
function elf_loader:wait_for_elf_to_exit()
local Thrd_join = fcall(libc_addrofs.Thrd_join)
-- will block until elf terminates
local ret = Thrd_join(self.thr_handle, 0):tonumber()
if ret ~= 0 then
error("Thrd_join() error: " .. hex(ret))
end
local out = memory.read_dword(self.payloadout)
printf("out = %s", hex(out))
end
function main()
if PLATFORM ~= "ps5" then
error("this payload only targets ps5")
end
check_jailbroken()
syscall.resolve({
jitshm_create = 0x215,
jitshm_alias = 0x216,
})
run_with_ps5_syscall_enabled(function()
local elfldr_data_path = "/data/elfldr.elf"
local elfldr_savedata_path = string.format("/mnt/sandbox/%s_000/savedata0/elfldr.elf", get_title_id())
local existing_path = ""
if file_exists(elfldr_data_path) then
existing_path = elfldr_data_path
elseif file_exists(elfldr_savedata_path) then
existing_path = elfldr_savedata_path
else
errorf("file not exist: %s", existing_path)
end
printf("loading elfldr from: %s", existing_path)
local elf = elf_loader:load_from_file(existing_path)
elf:run()
elf:wait_for_elf_to_exit()
end)
print("done")
end
main()