Files
etaHEN/Source Code/libelfldr/src/elfldr.c
LightningMods 0fe0407b3a etaHEN 2.4B
etaHEN 2.4B

etaHEN 2.4B Change log

- Updated to support the latest PS5 Payload SDK
- Fixed etaHEN and Cheats support for 8.40-10.01
- Added a Game Overlay menu to show CPU/GPU Temp and utilization, Local IP Address and other future states
- Added a Kstuff menu for options like downloading the latest kstuff from github, turning off kstufff autoload and more
- Added a Custom Background Package Installer for installing PKGs from internal storage from any directory (Requires DPIv2 enabled for 5.50+)
- DPIv2 can now download local files via url example http://192.xxx.xxx.xxx:12800/data/etaHEN/etaHEN.log
- Improved Cheats support, cheats with or without 0 sections are now supported
- Added Fix by TheFlow to Improve 2.xx PS4 PKG speeds
- Replaced the donation links in the etaHEN credits menu with ones to github sponsers
- Removed the non-whitelist app jailbreak option and moved it to an optional Legacy CMD Server option in the etaHEN Settings off by default
- Game Decryptor has been updated for the Itemzflow Dumper
- Updated the Plugin loader System
- The Payload SDK ELFLDR is now REQUIRED for etaHEN to load
- Replaced HTTP2 with Curl for better compatibility
- Added timeout for ShellUI to receive a response (will stop it from freezing if no response is given)

small fix
2025-12-01 20:31:16 -05:00

840 lines
18 KiB
C

/* Copyright (C) 2024 John Törnblom
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>. */
#include <elf.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/un.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <ps5/kernel.h>
#include "elfldr.h"
#include "log.h"
#include "pt.h"
#ifndef IPV6_2292PKTOPTIONS
#define IPV6_2292PKTOPTIONS 25
#endif
/**
* Convenient macros.
**/
#define ROUND_PG(x) (((x) + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1))
#define TRUNC_PG(x) ((x) & ~(PAGE_SIZE - 1))
#define PFLAGS(x) ((((x) & PF_R) ? PROT_READ : 0) | \
(((x) & PF_W) ? PROT_WRITE : 0) | \
(((x) & PF_X) ? PROT_EXEC : 0))
/**
* Context structure for the ELF loader.
**/
typedef struct elfldr_ctx {
uint8_t* elf;
pid_t pid;
intptr_t base_addr;
size_t base_size;
void* base_mirror;
} elfldr_ctx_t;
/**
* Absolute path to the SceSpZeroConf eboot.
**/
static const char* SceSpZeroConf = "/system/vsh/app/NPXS40112/eboot.bin";
/**
* Parse a R_X86_64_RELATIVE relocatable.
**/
static int
r_relative(elfldr_ctx_t *ctx, Elf64_Rela* rela) {
intptr_t* loc = ctx->base_mirror + rela->r_offset;
intptr_t val = ctx->base_addr + rela->r_addend;
*loc = val;
return 0;
}
/**
* Parse a PT_LOAD program header.
**/
static int
data_load(elfldr_ctx_t *ctx, Elf64_Phdr *phdr) {
void* data = ctx->base_mirror + phdr->p_vaddr;
if(!phdr->p_memsz) {
return 0;
}
if(!phdr->p_filesz) {
return 0;
}
memcpy(data, ctx->elf+phdr->p_offset, phdr->p_filesz);
return 0;
}
int
elfldr_sanity_check(uint8_t *elf, size_t elf_size) {
Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf;
Elf64_Phdr *phdr;
if(elf_size < sizeof(Elf64_Ehdr) ||
elf_size < sizeof(Elf64_Phdr) + ehdr->e_phoff ||
elf_size < sizeof(Elf64_Shdr) + ehdr->e_shoff) {
return -1;
}
if(ehdr->e_ident[0] != 0x7f || ehdr->e_ident[1] != 'E' ||
ehdr->e_ident[2] != 'L' || ehdr->e_ident[3] != 'F') {
return -1;
}
phdr = (Elf64_Phdr*)(elf + ehdr->e_phoff);
for(int i=0; i<ehdr->e_phnum; i++) {
if(phdr[i].p_offset + phdr[i].p_filesz > elf_size) {
return -1;
}
}
return 0;
}
/**
* Load an ELF into the address space of a process with the given pid.
**/
static intptr_t
elfldr_load(pid_t pid, uint8_t *elf) {
Elf64_Ehdr *ehdr = (Elf64_Ehdr*)elf;
Elf64_Phdr *phdr = (Elf64_Phdr*)(elf + ehdr->e_phoff);
Elf64_Shdr *shdr = (Elf64_Shdr*)(elf + ehdr->e_shoff);
elfldr_ctx_t ctx = {.elf = elf, .pid=pid};
size_t min_vaddr = -1;
size_t max_vaddr = 0;
int error = 0;
// Compute size of virtual memory region.
for(int i=0; i<ehdr->e_phnum; i++) {
if(phdr[i].p_vaddr < min_vaddr) {
min_vaddr = phdr[i].p_vaddr;
}
if(max_vaddr < phdr[i].p_vaddr + phdr[i].p_memsz) {
max_vaddr = phdr[i].p_vaddr + phdr[i].p_memsz;
}
}
min_vaddr = TRUNC_PG(min_vaddr);
max_vaddr = ROUND_PG(max_vaddr);
ctx.base_size = max_vaddr - min_vaddr;
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
int prot = PROT_READ | PROT_WRITE;
if(ehdr->e_type == ET_DYN) {
ctx.base_addr = 0;
} else if(ehdr->e_type == ET_EXEC) {
ctx.base_addr = min_vaddr;
flags |= MAP_FIXED;
} else {
LOG_PUTS("elfldr_load: ELF type not supported");
return 0;
}
if(!(ctx.base_mirror=malloc(ctx.base_size))) {
LOG_PERROR("malloc");
return 0;
}
// Reserve an address space of sufficient size.
if((ctx.base_addr=pt_mmap(pid, ctx.base_addr, ctx.base_size, prot,
flags, -1, 0)) == -1) {
LOG_PT_PERROR(pid, "pt_mmap");
free(ctx.base_mirror);
return 0;
}
// Parse program headers.
for(int i=0; i<ehdr->e_phnum && !error; i++) {
switch(phdr[i].p_type) {
case PT_LOAD:
error = data_load(&ctx, &phdr[i]);
break;
}
}
// Apply relocations.
for(int i=0; i<ehdr->e_shnum && !error; i++) {
if(shdr[i].sh_type != SHT_RELA) {
continue;
}
Elf64_Rela* rela = (Elf64_Rela*)(elf + shdr[i].sh_offset);
for(int j=0; j<shdr[i].sh_size/sizeof(Elf64_Rela); j++) {
switch(rela[j].r_info & 0xffffffffl) {
case R_X86_64_RELATIVE:
error = r_relative(&ctx, &rela[j]);
break;
}
}
}
if(pt_copyin(ctx.pid, ctx.base_mirror, ctx.base_addr, ctx.base_size)) {
LOG_PERROR("pt_copyin");
error = 1;
}
// Set protection bits on mapped segments.
for(int i=0; i<ehdr->e_phnum && !error; i++) {
if(phdr[i].p_type != PT_LOAD || phdr[i].p_memsz == 0) {
continue;
}
if(phdr[i].p_flags & PF_X) {
if(kernel_mprotect(pid, ctx.base_addr + phdr[i].p_vaddr,
ROUND_PG(phdr[i].p_memsz),
PFLAGS(phdr[i].p_flags))) {
LOG_PERROR("kernel_mprotect");
}
} else {
if(pt_mprotect(pid, ctx.base_addr + phdr[i].p_vaddr,
ROUND_PG(phdr[i].p_memsz),
PFLAGS(phdr[i].p_flags))) {
LOG_PT_PERROR(pid, "pt_mprotect");
error = 1;
}
}
}
if(pt_msync(pid, ctx.base_addr, ctx.base_size, MS_SYNC)) {
LOG_PT_PERROR(pid, "pt_msync");
error = 1;
}
free(ctx.base_mirror);
if(error) {
pt_munmap(pid, ctx.base_addr, ctx.base_size);
return 0;
}
return ctx.base_addr + ehdr->e_entry;
}
/**
* Create payload args in the address space of the process with the given pid.
**/
static intptr_t
elfldr_payload_args(pid_t pid) {
int victim_sock;
int master_sock;
intptr_t buf;
int pipe0;
int pipe1;
if((buf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) {
LOG_PT_PERROR(pid, "pt_mmap");
return 0;
}
if((master_sock=pt_socket(pid, AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
LOG_PT_PERROR(pid, "pt_socket");
return 0;
}
pt_setint(pid, buf+0x00, 20);
pt_setint(pid, buf+0x04, IPPROTO_IPV6);
pt_setint(pid, buf+0x08, IPV6_TCLASS);
pt_setint(pid, buf+0x0c, 0);
pt_setint(pid, buf+0x10, 0);
pt_setint(pid, buf+0x14, 0);
if(pt_setsockopt(pid, master_sock, IPPROTO_IPV6, IPV6_2292PKTOPTIONS, buf, 24)) {
LOG_PT_PERROR(pid, "pt_setsockopt");
return 0;
}
if((victim_sock=pt_socket(pid, AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
LOG_PT_PERROR(pid, "pt_socket");
return 0;
}
pt_setint(pid, buf+0x00, 0);
pt_setint(pid, buf+0x04, 0);
pt_setint(pid, buf+0x08, 0);
pt_setint(pid, buf+0x0c, 0);
pt_setint(pid, buf+0x10, 0);
if(pt_setsockopt(pid, victim_sock, IPPROTO_IPV6, IPV6_PKTINFO, buf, 20)) {
LOG_PT_PERROR(pid, "pt_setsockopt");
return 0;
}
if(kernel_overlap_sockets(pid, master_sock, victim_sock)) {
LOG_PUTS("kernel_overlap_sockets failed");
return 0;
}
if(pt_pipe(pid, buf)) {
LOG_PT_PERROR(pid, "pt_pipe");
return 0;
}
pipe0 = pt_getint(pid, buf);
pipe1 = pt_getint(pid, buf+4);
intptr_t args = buf;
intptr_t rwpipe = buf + 0x100;
intptr_t rwpair = buf + 0x200;
intptr_t kpipe_addr = kernel_get_proc_file(pid, pipe0);
intptr_t payloadout = buf + 0x300;
intptr_t getpid = pt_resolve(pid, "HoLVWNanBBc");
pt_setlong(pid, args + 0x00, getpid);
pt_setlong(pid, args + 0x08, rwpipe);
pt_setlong(pid, args + 0x10, rwpair);
pt_setlong(pid, args + 0x18, kpipe_addr);
pt_setlong(pid, args + 0x20, KERNEL_ADDRESS_DATA_BASE);
pt_setlong(pid, args + 0x28, payloadout);
pt_setint(pid, rwpipe + 0, pipe0);
pt_setint(pid, rwpipe + 4, pipe1);
pt_setint(pid, rwpair + 0, master_sock);
pt_setint(pid, rwpair + 4, victim_sock);
pt_setint(pid, payloadout, 0);
return args;
}
/**
* Prepare registers of a process for execution of an ELF.
**/
static int
elfldr_prepare_exec(pid_t pid, uint8_t *elf) {
intptr_t entry;
intptr_t args;
struct reg r;
if(pt_getregs(pid, &r)) {
LOG_PERROR("pt_getregs");
return -1;
}
if(!(entry=elfldr_load(pid, elf))) {
LOG_PUTS("elfldr_load failed");
return -1;
}
if(!(args=elfldr_payload_args(pid))) {
LOG_PUTS("elfldr_payload_args failed");
return -1;
}
r.r_rsp &= ~0xfl;
pt_setlong(pid, r.r_rsp-8, r.r_rip);
r.r_rsp -= 8;
r.r_rip = entry;
r.r_rdi = args;
if(pt_setregs(pid, &r)) {
LOG_PERROR("pt_setregs");
pt_detach(pid, SIGKILL);
return -1;
}
return 0;
}
/**
* Set the name of a process.
**/
static int
elfldr_set_procname(pid_t pid, const char* name) {
intptr_t buf;
if((buf=pt_mmap(pid, 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)) == -1) {
LOG_PT_PERROR(pid, "pt_mmap");
return -1;
}
pt_copyin(pid, name, buf, strlen(name)+1);
pt_syscall(pid, SYS_thr_set_name, -1, buf);
pt_msync(pid, buf, PAGE_SIZE, MS_SYNC);
pt_munmap(pid, buf, PAGE_SIZE);
return 0;
}
/**
* Escape jail and raise privileges.
**/
int
elfldr_raise_privileges(pid_t pid) {
static const uint8_t caps[16] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
intptr_t vnode;
if(!(vnode=kernel_get_root_vnode())) {
return -1;
}
if(kernel_set_proc_rootdir(pid, vnode)) {
return -1;
}
if(kernel_set_proc_jaildir(pid, 0)) {
return -1;
}
if(kernel_set_ucred_uid(pid, 0)) {
return -1;
}
if(kernel_set_ucred_caps(pid, caps)) {
return -1;
}
return 0;
}
/**
* Execute an ELF inside the process with the given pid.
**/
int
elfldr_exec(pid_t pid, int stdio, uint8_t* elf) {
uint8_t caps[16];
intptr_t jaildir;
intptr_t rootdir;
uint64_t authid;
int error = 0;
// backup privileges
jaildir = kernel_get_proc_jaildir(pid);
if(!(rootdir=kernel_get_proc_rootdir(pid))) {
LOG_PUTS("kernel_get_proc_rootdir failed");
pt_detach(pid, 0);
return -1;
}
if(kernel_get_ucred_caps(pid, caps)) {
LOG_PUTS("kernel_get_ucred_caps failed");
pt_detach(pid, 0);
return -1;
}
if(!(authid=kernel_get_ucred_authid(pid))) {
LOG_PUTS("kernel_get_ucred_authid failed");
pt_detach(pid, 0);
return -1;
}
if(elfldr_raise_privileges(pid)) {
LOG_PUTS("Unable to raise privileges");
pt_detach(pid, 0);
return -1;
}
if(stdio > 0) {
stdio = pt_rdup(pid, getpid(), stdio);
pt_close(pid, STDERR_FILENO);
pt_close(pid, STDOUT_FILENO);
pt_close(pid, STDIN_FILENO);
pt_dup2(pid, stdio, STDIN_FILENO);
pt_dup2(pid, stdio, STDOUT_FILENO);
pt_dup2(pid, stdio, STDERR_FILENO);
pt_close(pid, stdio);
}
if(elfldr_prepare_exec(pid, elf)) {
error = -1;
}
// restore privileges
if(kernel_set_proc_jaildir(pid, jaildir)) {
LOG_PUTS("kernel_set_proc_jaildir failed");
error = -1;
}
if(kernel_set_proc_rootdir(pid, rootdir)) {
LOG_PUTS("kernel_set_proc_rootdir failed");
error = -1;
}
if(kernel_set_ucred_caps(pid, caps)) {
LOG_PUTS("kernel_set_ucred_caps failed");
error = -1;
}
if(kernel_set_ucred_authid(pid, authid)) {
LOG_PUTS("kernel_set_ucred_authid failed");
error = -1;
}
if(pt_detach(pid, 0)) {
LOG_PERROR("pt_detach");
error = -1;
}
return error;
}
/**
* Set the heap size for libc.
**/
static int
elfldr_set_heap_size(pid_t pid, ssize_t size) {
intptr_t sceLibcHeapSize;
intptr_t sceLibcParam;
intptr_t sceProcParam;
intptr_t Need_sceLibc;
if(!(sceProcParam=pt_sceKernelGetProcParam(pid))) {
LOG_PT_PERROR(pid, "pt_sceKernelGetProcParam");
return -1;
}
if(pt_copyout(pid, sceProcParam+56, &sceLibcParam,
sizeof(sceLibcParam))) {
LOG_PERROR("pt_copyout");
return -1;
}
if(pt_copyout(pid, sceLibcParam+16, &sceLibcHeapSize,
sizeof(sceLibcHeapSize))) {
LOG_PERROR("pt_copyout");
return -1;
}
if(pt_setlong(pid, sceLibcHeapSize, size)) {
LOG_PERROR("pt_setlong");
return -1;
}
if(size != -1) {
return 0;
}
if(pt_copyout(pid, sceLibcParam+72, &Need_sceLibc,
sizeof(Need_sceLibc))) {
LOG_PERROR("pt_copyout");
return -1;
}
return pt_setlong(pid, sceLibcParam+32, Need_sceLibc);
}
static int
sys_budget_set(long budget) {
return __syscall(0x23b, budget);
}
static int
elfldr_rfork_entry(void* progname) {
char* const argv[] = {(char*)progname, 0};
if(sys_budget_set(0)) {
klog_perror("sys_budget_set");
return -1;
}
if(open("/dev/deci_stdin", O_RDONLY) < 0) {
klog_perror("open");
return -1;
}
if(open("/dev/deci_stdout", O_WRONLY) < 0) {
klog_perror("open");
return -1;
}
if(open("/dev/deci_stderr", O_WRONLY) < 0) {
klog_perror("open");
return -1;
}
if(ptrace(PT_TRACE_ME, 0, 0, 0)) {
klog_perror("ptrace");
return -1;
}
execve(SceSpZeroConf, argv, 0);
klog_perror("execve");
return -1;
}
/**
* Execute an ELF inside a new process.
**/
/**
* Fint the pid of a process with the given name.
**/
pid_t
elfldr_find_pid(const char* name) {
int mib[4] = {1, 14, 8, 0};
pid_t mypid = getpid();
pid_t pid = -1;
size_t buf_size;
uint8_t *buf;
if(sysctl(mib, 4, 0, &buf_size, 0, 0)) {
LOG_PERROR("sysctl");
return -1;
}
if(!(buf=malloc(buf_size))) {
LOG_PERROR("malloc");
return -1;
}
if(sysctl(mib, 4, buf, &buf_size, 0, 0)) {
LOG_PERROR("sysctl");
free(buf);
return -1;
}
for(uint8_t *ptr=buf; ptr<(buf+buf_size);) {
int ki_structsize = *(int*)ptr;
pid_t ki_pid = *(pid_t*)&ptr[72];
char *ki_tdname = (char*)&ptr[447];
ptr += ki_structsize;
if(!strcmp(name, ki_tdname) && ki_pid != mypid) {
pid = ki_pid;
}
}
free(buf);
return pid;
}
/**
* Read an ELF from a given socket.
**/
int
elfldr_read(int fd, uint8_t** elf, size_t* elf_size) {
Elf64_Shdr *shdr;
Elf64_Ehdr ehdr;
uint8_t* buf;
uint8_t* bak;
size_t size;
off_t shend;
size_t rem;
if(recv(fd, &ehdr, sizeof(ehdr), MSG_WAITALL) != sizeof(ehdr)) {
return -1;
}
if(ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E' ||
ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F') {
errno = ENOEXEC;
return -1;
}
size = ehdr.e_shoff + ehdr.e_shnum * sizeof(Elf64_Ehdr);
if(!(buf=malloc(size))) {
return -1;
}
memcpy(buf, &ehdr, sizeof(ehdr));
rem = size - sizeof(ehdr);
if(recv(fd, buf + sizeof(ehdr), rem, MSG_WAITALL) != rem) {
free(buf);
return -1;
}
shend = 0;
shdr = (Elf64_Shdr*)(buf + ehdr.e_shoff);
for(int i=0; i<ehdr.e_shnum; i++) {
if(shdr[i].sh_type == SHT_NOBITS) {
continue;
}
size_t end = shdr[i].sh_offset + shdr[i].sh_size;
if(end > shend) {
shend = end;
}
}
// sections appear before section headers
if(shend <= size) {
*elf = buf;
*elf_size = size;
return 0;
}
bak = buf;
if(!(buf=realloc(buf, shend))) {
free(bak);
return -1;
}
rem = shend - size;
if(recv(fd, buf + size, rem, MSG_WAITALL) != rem) {
free(buf);
return -1;
}
*elf = buf;
*elf_size = shend;
return 0;
}
/**
* Execute an ELF inside a new process.
**/
pid_t
elfldr_spawn(const char* cwd, int stdio, uint8_t* elf, const char* name) {
uint8_t int3instr = 0xcc;
struct kevent evt;
intptr_t brkpoint;
uint8_t orginstr;
void *stack;
pid_t pid;
int kq;
if((kq=kqueue()) < 0) {
LOG_PERROR("kqueue");
return -1;
}
if(!(stack=malloc(PAGE_SIZE))) {
LOG_PERROR("malloc");
close(kq);
return -1;
}
if((pid=rfork_thread(RFPROC | RFCFDG | RFMEM, stack+PAGE_SIZE-8,
elfldr_rfork_entry, (void*)name)) < 0) {
LOG_PERROR("rfork_thread");
free(stack);
close(kq);
return -1;
}
EV_SET(&evt, pid, EVFILT_PROC, EV_ADD, NOTE_EXEC, 0, 0);
if(kevent(kq, &evt, 1, &evt, 1, 0) < 0) {
LOG_PERROR("kevent");
free(stack);
close(kq);
return -1;
}
if(waitpid(pid, 0, 0) < 0) {
LOG_PERROR("waitpid");
free(stack);
close(kq);
return -1;
}
free(stack);
close(kq);
// The proc is now in the STOP state, with the instruction pointer pointing
// at the libkernel entry. Let the kernel assign process parameters accessed
// via sceKernelGetProcParam()
if(pt_syscall(pid, 599)) {
LOG_PT_PERROR(pid, "sys_dynlib_process_needed_and_relocate");
pt_detach(pid, SIGKILL);
return -1;
}
// Allow libc to allocate arbitrary amount of memory.
elfldr_set_heap_size(pid, -1);
//Insert a breakpoint at the eboot entry.
if(!(brkpoint=kernel_dynlib_entry_addr(pid, 0))) {
LOG_PUTS("kernel_dynlib_entry_addr failed");
pt_detach(pid, SIGKILL);
return -1;
}
brkpoint += 58;// offset to invocation of main()
if(kernel_mprotect(pid, brkpoint, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC)) {
LOG_PUTS("kernel_mprotect failed");
pt_detach(pid, SIGKILL);
return -1;
}
if(pt_copyout(pid, brkpoint, &orginstr, sizeof(orginstr))) {
LOG_PERROR("pt_copyout");
pt_detach(pid, SIGKILL);
return -1;
}
if(pt_copyin(pid, &int3instr, brkpoint, sizeof(int3instr))) {
LOG_PERROR("pt_copyin");
pt_detach(pid, SIGKILL);
return -1;
}
// Continue execution until we hit the breakpoint, then remove it.
if(pt_continue(pid, SIGCONT)) {
LOG_PERROR("pt_continue");
pt_detach(pid, SIGKILL);
return -1;
}
if(waitpid(pid, 0, 0) == -1) {
LOG_PERROR("waitpid");
pt_detach(pid, SIGKILL);
return -1;
}
if(pt_copyin(pid, &orginstr, brkpoint, sizeof(orginstr))) {
LOG_PERROR("pt_copyin");
pt_detach(pid, SIGKILL);
return -1;
}
// Execute the ELF
elfldr_set_procname(pid, name);
if(elfldr_exec(pid, stdio, elf)) {
kill(pid, SIGKILL);
return -1;
}
return pid;
}