cheat-engine/Cheat Engine/ceserver/extensionloader.c
2022-09-04 23:35:56 +02:00

1219 lines
29 KiB
C
Executable File

/*
* extentionloader.c
*
* Created on: Aug 19, 2013
* Author: eric
*
* Used for loading an module that will extend the ceserver
* client<-->ceserver<-->extention
*
* It doesn't HAVE to be used if the forced module load method works (Do not assume so)
*
* How it works:
* Ptrace the target (this means it must be loaded BEFORE the debugger is attached)
* Cause a stop and make sure it's runnable (Not sure if it executes if it's suspended for some reason. e.g: wait for event/critical section that may never happen)
* Change the current instruction pointer to the beginning of dlopen and the register/stack state setup to execute
* Set the return addres to an invalid return address (e.g 0x0ce0)
* Execute it and wait till a sigtrap/sigseg happens on that specific invalid address
* Then restore the state back
*
* On arm32: Bit J and T in CPSR define the current execution state
* J T
* 0 0 = ARM
* 0 1 = Thumb
* 1 0 = Jazelle (java...)
* 1 1 = ThumbEE*
*
* If ARM so set to 0 0 and restore that as well
* Note that The least significant bit in an address specifier also determines if it's THUMB or ARM (edit: nope. But lets go with this in CE)
* It doesn't seem to matter if you set the least significant bit in the PC register. It will ignore that but on execute. (probably a good idea to clear that bit anyhow)
*
*
* Problem: It doesn't return properly when the registers are changed when it's waiting in a syscall, so only change it when outside of a syscall
* Better solution: It seems it failed because the stop was at a syscall, so the program counter was decremented tithe the size of the syscall
* To prevent this RESTART change EAX to 0 so it won't do the restart. Also works on ARM
*
* Problem2: In android dlopen is in /system/bin/linker but not using a symbol (so ce's symbollist can't be used to find the address)
*
* dlopen("libdl.so", RTLD_NOW) actually works in android and dlsym as well. (point to the linker version)
* This is useful since this makes it cross compatible with normal linux.
* for some reason getting the address of dlopen in x86 returns a local stub and I don't know yet how to prevent those stubs
*
* so, to find dlopen find address range dlopen is in in this process (/proc/selfpid/maps), get the base address of that specific module
* and then add that offset to the same named module in the target process
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#ifdef HAS_LINUX_USER_H
#include <linux/user.h>
#else
#include <sys/user.h>
#endif
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <libgen.h>
#ifdef __aarch64__
#include <elf.h>
#ifdef __ANDROID__
#include <arm-linux-androideabi/asm/ptrace.h>
#endif
#endif
#include "symbols.h"
#include "porthelp.h"
#include "api.h"
#include "ceserver.h"
#ifndef SUN_LEN //missing in android (copy from linux sys/un.h)
/* Evaluate to actual length of the `sockaddr_un' structure. */
# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
+ strlen ((ptr)->sun_path))
#endif
int WaitForPid(int *status)
{
int pid=-1;
while (pid==-1)
{
pid=waitpid(-1, status, __WALL);
if ((pid==-1) && (errno!=EINTR))
{
debug_log("LoadExtension wait fail. :%d\n", errno);
return -1; //something bad happened
}
}
return pid;
}
int showRegisters(int pid)
{
/*
#ifdef __aarch64__
struct user_pt_regs regs;
#else
#ifdef __arm__
struct pt_regs r;
#else
struct user_regs_struct r;
#endif
#endif
int result=ptrace(PTRACE_GETREGS, pid, 0, &r);
if (result!=0)
{
debug_log("PTRACE_GETREGS FAILED (%d)\n", result);
return result;
}
#ifdef __arm__
debug_log("r0=%lx\n", r.ARM_r0);
debug_log("orig_r0=%lx\n", r.ARM_ORIG_r0);
debug_log("pc=%lx\n", r.ARM_pc);
#else
#if defined(__x86_64__)
debug_log("RAX=%lx\n", r.rax);
debug_log("orig_rax=%lx\n", r.orig_rax);
debug_log("rip=%lx\n", r.rip);
#endif
#if defined(__i386__)
debug_log("EAX=%lx\n", r.eax);
debug_log("orig_eax=%lx\n", r.orig_eax);
debug_log("eip=%lx\n", r.eip);
#endif
#endif
*/
return 0;
}
uintptr_t finddlopen(int pid, uintptr_t *_dlerror) //todo: use the elf parsing routines (they work better now)
{
void *libdl;
void *realdlopen;
void *realdlerror;
libdl=dlopen("libdl.so", RTLD_NOW);
debug_log("libdl=%p\n", libdl);
realdlopen=dlsym(libdl,"dlopen");
realdlerror=dlsym(libdl,"dlerror");
debug_log("dlopen=%p\n", dlopen);
debug_log("realdlopen=%p\n", realdlopen);
debug_log("dlerror=%p\n", dlerror);
debug_log("realdlerror=%p\n", realdlerror);
#ifndef __arm__
if (dlopen==realdlopen)
debug_log("Please tell db what you did to get this to function (excluding manually editing this if statement)\n");
#endif
//open /proc/self/maps and look up the region that holds realdlopen
FILE *maps=fopen("/proc/self/maps", "r");
char x[200];
char currentmodule[256];
char modulepath[256];
unsigned long long currentmodulestart;
currentmodule[0]=0;
while (fgets(x, 200, maps))
{
unsigned long long start;
unsigned long long stop;
debug_log("%s", x);
sscanf(x, "%llx-%llx %*s %*s %*s %*s %s\n", &start, &stop, modulepath);
if (strcmp(modulepath, currentmodule)!=0)
{
strcpy(currentmodule, modulepath);
currentmodulestart=start;
}
if (
(((uintptr_t)realdlopen)>=start) &&
(((uintptr_t)realdlopen)<stop)
)
{
unsigned int offset=(uintptr_t)realdlopen-currentmodulestart;
unsigned int offset2=(uintptr_t)realdlerror-currentmodulestart;
char mapsfilename[255];
debug_log("found it. Module: %s Offset=%x\n", currentmodule, offset);
//find this module in the target process and apply this offset to get the address of dlopen
sprintf(mapsfilename, "/proc/%d/maps", pid);
FILE *maps2=fopen(mapsfilename, "r");
if (maps2)
{
char y[200];
while (fgets(y, 200, maps2))
{
if (y[strlen(y)-1]!='\n')
{
//need to go to the end of line first
char discard[100];
do
{
discard[99]=0;
fgets(discard, 99, maps);
} while (discard[99]!=0);
}
debug_log("%s", y);
modulepath[0]='\0';
sscanf(y, "%llx-%llx %*s %*s %*s %*s %s\n", &start, &stop, modulepath);
debug_log("Check if '%s' == '%s'\n", modulepath, currentmodule);
if (strcmp(modulepath, currentmodule)==0)
{
debug_log("found the module in the target process\n");
fclose(maps);
fclose(maps2);
*_dlerror=start+offset2;
return start+offset;
}
}
fclose(maps2);
}
else
{
debug_log("Failure to open %s\n", mapsfilename);
}
fclose(maps);
return 0;
}
else debug_log("Nope\n");
}
fclose(maps);
return 1;
}
void writeString(int pid, uintptr_t address, char *string)
{
int l=strlen(string)+1;
long *p;
long v;
int i;
int bs;
i=0;
debug_log("l=%d\n", l);
while (i<l)
{
p=(long *)&string[i];
if ((l-i)<sizeof(long))
{
bs=sizeof(long);
v=*p;
}
else
{
v=string[i];
bs=1;
}
safe_ptrace(PTRACE_POKEDATA, pid, (void*)(address+i), (void*)v);
i+=bs;
}
}
int openExtension(int pid, int *openedSocket)
{
int i;
int s;
int al;
char name[256];
s=socket(AF_UNIX, SOCK_STREAM, 0);
debug_log("s=%d\n", s);
sprintf(name, " ceserver_extension%d", pid);
struct sockaddr_un address;
address.sun_family=AF_UNIX;
strcpy(address.sun_path, name);
al=SUN_LEN(&address);
address.sun_path[0]=0;
i=connect(s, (struct sockaddr *)&address, al);
if (i==0)
{
debug_log("Successful connection\n");
*openedSocket=s;
return 1;
}
else
{
close(s);
return 0;
}
}
int isExtensionLoaded(int pid)
{
int s;
int result=openExtension(pid, &s);
if (result)
close(s);
return result;
}
int loadExtension(PProcessData p, char *path)
{
int pid;
uintptr_t dlerror;
uintptr_t str;
int status;
int pathlen=strlen(path)+1; //0-terminater
debug_log("loadExtension()\n");
debug_log("Phase 0: Check if it's already open\n");
if (isExtensionLoaded(p->pid))
{
debug_log("Already loaded\n");
return TRUE;
}
else
debug_log("Not yet loaded\n");
if (p->dlopen==0) //fallback to the old method
{
debug_log("Phase 1: Find dlopen in target\n");
p->dlopen=finddlopen(p->pid, &dlerror);
}
if (p->dlopen==0)
{
debug_log("dlopen==NULL Abort!\n");
return 0;
}
debug_log("dlopen=%p\n", (void *)p->dlopen);
//debug_log("dlerror=%p\n", (void *)dlerror);
if (!p->isDebugged)
{
pid=ptrace_attach_andwait(p->pid);
debug_log("After wait. PID=%d\n", pid);
//safe_ptrace(PTRACE_CONT,pid,0,0);
}
else
{
debug_log("Killing pid %d\n", p->pid);
int e=kill(p->pid, SIGSTOP);
debug_log("kill returned %d\n", e);
debug_log("Waiting for thread to stop\n");
pid=WaitForPid(&status);
if (WIFSTOPPED(status))
debug_log("Stopped with signal %d\n", WSTOPSIG(status));
else
debug_log("Unexpected status: %x\n", status);
}
showRegisters(pid);
printf("After wait 2. PID=%d\n", pid);
//save the current state and set the state to what I need it to be
#ifdef __i386__
struct user_regs_struct origregs;
struct user_regs_struct newregs;
#endif
#ifdef __x86_64__
struct user_regs_struct origregs;
struct user_regs_struct newregs;
#endif
#ifdef __arm__
struct pt_regs origregs;
struct pt_regs newregs;
#endif
#ifdef __aarch64__
struct user_pt_regs origregs;
struct user_pt_regs newregs;
typedef struct _pt_regs32 {
uint32_t uregs[18];
} pt_regs32, *ppt_regs32;
pt_regs32 origregs32;
pt_regs32 newregs32;
struct iovec iov;
#endif
#ifdef __aarch64__
if (p->is64bit)
{
iov.iov_base=&newregs;
iov.iov_len=sizeof(newregs);
}
else
{
iov.iov_base=&newregs32;
iov.iov_len=sizeof(newregs32);
}
if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &iov))
#else
if (ptrace(PTRACE_GETREGS, pid, 0, &newregs)!=0)
#endif
{
debug_log("PTRACE_GETREGS FAILED\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
#ifdef __aarch64__
if (p->is64bit)
{
iov.iov_base=&origregs;
iov.iov_len=sizeof(origregs);
}
else
{
iov.iov_base=&origregs32;
iov.iov_len=sizeof(origregs32);
}
if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &iov))
#else
if (ptrace(PTRACE_GETREGS, pid, 0, &origregs)!=0)
#endif
{
debug_log("PTRACE_GETREGS FAILED 2\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
uintptr_t returnaddress=0x0ce0;
#ifdef __arm__
//allocate space in the stack
newregs.ARM_sp-=8+4*((pathlen+3)/ 4);
//not sur eif [sp] is written to with a push or if it's [sp-4] and then sp decreased, so start at sp+4 instead
str=newregs.ARM_sp+4;
writeString(pid, str, path);
newregs.ARM_lr=returnaddress;
newregs.ARM_pc=p->dlopen;
newregs.ARM_r0=str;
newregs.ARM_r1=RTLD_NOW;
if (newregs.ARM_pc & 1)
{
//THUMB Address link
debug_log("THUMB destination\n");
newregs.ARM_cpsr=newregs.ARM_cpsr | (1 << 5);
//not sure how to set the J bit (thumbee uses it...)
//for now disable it until a bug happens
newregs.ARM_cpsr=newregs.ARM_cpsr & (~(1<<25)); //unset J
}
else
{
debug_log("ARM destination\n");
debug_log("newregs.ARM_cpsr was %x\n", newregs.ARM_cpsr);
newregs.ARM_cpsr=newregs.ARM_cpsr & (~(1<<5)); //unset T
newregs.ARM_cpsr=newregs.ARM_cpsr & (~(1<<25)); //unset J
debug_log("newregs.ARM_cpsr is %x\n", newregs.ARM_cpsr);
}
debug_log("r0=%lx\n", origregs.ARM_r0);
debug_log("orig_r0=%lx\n", origregs.ARM_ORIG_r0);
debug_log("pc=%lx\n", origregs.ARM_pc);
debug_log("cpsr=%lx\n", origregs.ARM_cpsr);
#endif
#ifdef __aarch64__
//todo: if target is 32-bit .....
if (p->is64bit==0)
{
debug_log("orig pc=%lx\n", origregs32.ARM_pc);
debug_log("orig sp=%lx\n", origregs32.ARM_sp);
debug_log("orig cpsr=%lx\n", origregs32.ARM_cpsr);
newregs32.ARM_sp-=8+4*((pathlen+3)/ 4);
//not sur eif [sp] is written to with a push or if it's [sp-4] and then sp decreased, so start at sp+4 instead
str=newregs32.ARM_sp+4;
writeString(pid, str, path);
newregs32.ARM_lr=returnaddress;
newregs32.ARM_pc=p->dlopen;
newregs32.ARM_r0=str;
newregs32.ARM_r1=RTLD_NOW;
if (newregs32.ARM_pc & 1)
{
//THUMB Address link
debug_log("THUMB destination\n");
newregs32.ARM_cpsr=newregs32.ARM_cpsr | (1 << 5);
//not sure how to set the J bit (thumbee uses it...)
//for now disable it until a bug happens
newregs32.ARM_cpsr=newregs32.ARM_cpsr & (~(1<<25)); //unset J
}
else
{
debug_log("ARM destination\n");
debug_log("newregs32.ARM_cpsr was %x\n", newregs32.ARM_cpsr);
newregs32.ARM_cpsr=newregs32.ARM_cpsr & (~(1<<5)); //unset T
newregs32.ARM_cpsr=newregs32.ARM_cpsr & (~(1<<25)); //unset J
debug_log("newregs32.ARM_cpsr is %x\n", newregs32.ARM_cpsr);
}
debug_log("new pc=%lx\n", newregs32.ARM_pc);
debug_log("new sp=%lx\n", newregs32.ARM_sp);
debug_log("new cpsr=%lx\n", newregs32.ARM_cpsr);
}
else
{
debug_log("64-bit target\n");
debug_log("orig pc=%llx\n", origregs.pc);
debug_log("orig sp=%llx\n", origregs.sp);
debug_log("orig lr=%llx\n", origregs.regs[30]);
debug_log("orig x0=%llx\n", origregs.regs[0]);
debug_log("orig x1=%llx\n", origregs.regs[1]);
debug_log("extensionloader is not implemented yet for aarch64\n");
//allocate space in the stack
newregs.sp-=16+16*((pathlen+3)/16);
str=newregs.sp;
writeString(pid, str, path);
newregs.regs[30]=returnaddress; //30=LR
newregs.pc=p->dlopen;
newregs.regs[0]=str;
newregs.regs[1]=RTLD_NOW;
debug_log("new pc=%llx\n", origregs.pc);
debug_log("new sp=%llx\n", origregs.sp);
debug_log("new lr=%llx\n", origregs.regs[30]);
debug_log("new x0=%llx\n", origregs.regs[0]);
debug_log("new x1=%llx\n", origregs.regs[1]);
}
#endif
#ifdef __x86_64__
debug_log("rax=%lx\n", origregs.rax);
debug_log("rbp=%lx\n", origregs.rbp);
debug_log("rsp=%lx\n", origregs.rsp);
debug_log("orig_rax=%lx\n", origregs.orig_rax);
debug_log("rip=%lx\n", origregs.rip);
//allocate stackspace
newregs.rsp=newregs.rsp-0x28-(8*((pathlen+7) / 8));
//check that the first 4 bits of rsp are 1000 (8) (aligned with the function return push)
if ((newregs.rsp & 0xf)!=8)
{
debug_log("Aligning stack. Was %llx", newregs.rsp);
newregs.rsp-=8;
newregs.rsp&=~(0xf); //clear the first 4 bits
newregs.rsp=newregs.rsp | 8; //set to 8
debug_log(" is now %llx\n", newregs.rsp);
}
//set the return address
debug_log("Writing 0x0ce0 to %lx\n", newregs.rsp);
if (ptrace(PTRACE_POKEDATA, pid, newregs.rsp, returnaddress)!=0)
{
debug_log("Failed to write return address\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
if (ptrace(PTRACE_POKEDATA, pid, newregs.rsp-8, returnaddress)!=0)
{
debug_log("Fuck\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
if (ptrace(PTRACE_POKEDATA, pid, newregs.rsp+8, returnaddress)!=0)
{
debug_log("Fuck\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
//write the path at rsp+10
str=newregs.rsp+0x18;
writeString(pid, str, path);
debug_log("str=%p\n", (void *)str);
returnaddress=ptrace(PTRACE_PEEKDATA, pid, newregs.rsp, 0);
debug_log("[%lx]=%lx", newregs.rsp, returnaddress);
newregs.rip=p->dlopen;
newregs.rax=0;
newregs.rdi=str;
newregs.rsi=RTLD_NOW;
newregs.orig_rax=0;
#endif
#ifdef __i386__
debug_log("eax=%lx\n", origregs.eax);
debug_log("ebp=%lx\n", origregs.ebp);
debug_log("esp=%lx\n", origregs.esp);
debug_log("orig_eax=%lx\n", origregs.orig_eax);
debug_log("eip=%lx\n", origregs.eip);
//allocate stackspace
newregs.esp=newregs.esp-0x28-(8*((pathlen+7) / 8));
if ((newregs.esp & 0xf)!=8)
{
debug_log("Aligning stack. Was %llx", newregs.esp);
newregs.esp-=8;
newregs.esp&=~(0xf); //clear the first 4 bits
newregs.esp=newregs.esp | 8; //set to 8
debug_log(" is now %llx\n", newregs.esp);
}
//in 32-bit the stack will have to look like:
//0-3: Return address (0x0ce0)
//4-7: Address to path
//8-11:RTLD_NOW
//12-...: Path
//
if (ptrace(PTRACE_POKEDATA, pid, newregs.esp+0, returnaddress)!=0)
{
debug_log("Fuck\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
if (ptrace(PTRACE_POKEDATA, pid, newregs.esp+4, newregs.esp+12)!=0)
{
debug_log("Fuck2\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
if (ptrace(PTRACE_POKEDATA, pid, newregs.esp+8, RTLD_NOW)!=0)
{
debug_log("Fuck3\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
writeString(pid, newregs.esp+12, path);
newregs.eip=p->dlopen;
newregs.orig_eax=0;
#endif
#ifdef __aarch64__
if (p->is64bit)
{
iov.iov_base=&newregs;
iov.iov_len=sizeof(newregs);
}
else
{
iov.iov_base=&newregs32;
iov.iov_len=sizeof(newregs32);
}
if (ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, &iov))
#else
if (ptrace(PTRACE_SETREGS, pid, 0, &newregs)!=0)
#endif
{
debug_log("PTRACE_SETREGS FAILED\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
#ifdef __aarch64__
if (p->is64bit)
{
iov.iov_base=&newregs;
iov.iov_len=sizeof(newregs);
}
else
{
iov.iov_base=&newregs32;
iov.iov_len=sizeof(newregs32);
}
if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &iov))
#else
if (ptrace(PTRACE_GETREGS, pid, 0, &newregs)!=0)
#endif
{
debug_log("PTRACE_GETREGS FAILED 4\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
debug_log("after setregs:\n");
#ifdef __arm__
debug_log("r0=%lx\n", newregs.ARM_r0);
debug_log("orig_r0=%lx\n", newregs.ARM_ORIG_r0);
debug_log("pc=%lx\n", newregs.ARM_pc);
debug_log("cpsr=%lx\n", newregs.ARM_cpsr);
#endif
#ifdef __aarch64__
debug_log("pc=%llx\n", newregs.pc);
debug_log("sp=%llx\n", newregs.sp);
debug_log("lr=%llx\n", newregs.regs[30]);
debug_log("x0=%llx\n", newregs.regs[0]);
debug_log("x1=%llx\n", newregs.regs[1]);
#endif
#ifdef __x86_64__
debug_log("rax=%lx\n", newregs.rax);
debug_log("rdi=%lx\n", newregs.rdi);
debug_log("rsi=%lx\n", newregs.rsi);
debug_log("rbp=%lx\n", newregs.rbp);
debug_log("rsp=%lx\n", newregs.rsp);
debug_log("orig_rax=%lx\n", newregs.orig_rax);
debug_log("rip=%lx\n", newregs.rip);
#endif
#ifdef __i386__
debug_log("eax=%lx\n", newregs.eax);
debug_log("edi=%lx\n", newregs.edi);
debug_log("esi=%lx\n", newregs.esi);
debug_log("ebp=%lx\n", newregs.ebp);
debug_log("esp=%lx\n", newregs.esp);
debug_log("orig_eax=%lx\n", newregs.orig_eax);
debug_log("eip=%lx\n", newregs.eip);
#endif //__x86_64__
debug_log("\n\nContinuing thread\n");
int ptr;
ptr=ptrace(PTRACE_CONT,pid,(void *)0,(void *)SIGCONT);
debug_log("PRACE_CONT=%d\n", ptr);
if (ptr!=0)
{
debug_log("PTRACE_CONT FAILED\n");
return 1;
}
//wait for this thread to crash
int pid2;
pid2=-1;
while (pid2==-1)
{
pid2=waitpid(-1, &status, WUNTRACED| __WALL);
if (WIFSTOPPED(status))
{
debug_log("Stopped with signal %d\n", WSTOPSIG(status));
if (pid2!=pid)
{
debug_log("It's a different thread\n");
if (!p->isDebugged)
{
debug_log("No debugger present. Continuing it unhandled\n");
if (WSTOPSIG(status)!=SIGSTOP)
ptrace(PTRACE_CONT,pid2,(void *)0,(void *)(uintptr_t)WSTOPSIG(status));
else
ptrace(PTRACE_CONT,pid2,(void *)0,0);
}
else
{
//add it to the debug events
DebugEvent de;
de.threadid=pid2;
de.debugevent=WSTOPSIG(status);
AddDebugEventToQueue(p, &de);
debug_log("Debugger present. Added to the queue\n");
}
pid2=-1;
continue;
}
}
else
debug_log("Unexpected status: %x\n", status);
if ((pid2==-1) && (errno!=EINTR))
{
debug_log("LoadExtension wait fail. :%d\n", errno);
return FALSE;
}
if (pid2==0)
pid2=-1;
debug_log(".");
}
debug_log("after wait: pid=%d (status=%x)\n", pid, status);
siginfo_t si;
if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)!=0)
{
debug_log("GETSIGINFO FAILED\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
debug_log("si.si_signo=%d\n", si.si_signo);
// if (si.si_signo==SIGSEGV)
//debug_log("si._sifields._sigfault._addr=%x\n", si._sifields._sigfault._addr);
#ifdef __aarch64__
if (p->is64bit)
{
iov.iov_base=&newregs;
iov.iov_len=sizeof(newregs);
}
else
{
iov.iov_base=&newregs32;
iov.iov_len=sizeof(newregs32);
}
if (ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &iov))
#else
if (ptrace(PTRACE_GETREGS, pid, 0, &newregs)!=0)
#endif
{
debug_log("PTRACE_GETREGS FAILED (2)\n");
safe_ptrace(PTRACE_DETACH, pid,0,0);
return FALSE;
}
#ifdef __arm__
debug_log("r0=%lx\n", newregs.ARM_r0);
debug_log("orig_r0=%lx\n", newregs.ARM_ORIG_r0);
debug_log("pc=%lx\n", newregs.ARM_pc);
debug_log("sp=%lx\n", newregs.ARM_sp);
debug_log("cpsr=%lx\n", newregs.ARM_cpsr);
#endif
#ifdef __aarch64__
if (p->is64bit)
{
debug_log("pc=%llx\n", newregs.pc);
debug_log("sp=%llx\n", newregs.sp);
debug_log("lr=%llx\n", newregs.regs[30]);
debug_log("x0=%llx\n", newregs.regs[0]);
debug_log("x1=%llx\n", newregs.regs[1]);
}
else
{
debug_log("r0=%lx\n", newregs32.ARM_r0);
debug_log("orig_r0=%lx\n", newregs32.ARM_ORIG_r0);
debug_log("pc=%lx\n", newregs32.ARM_pc);
debug_log("sp=%lx\n", newregs32.ARM_sp);
debug_log("cpsr=%lx\n", newregs32.ARM_cpsr);
}
#endif
#ifdef __x86_64__
debug_log("rax=%lx\n", newregs.rax);
debug_log("rdi=%lx\n", newregs.rdi);
debug_log("rsi=%lx\n", newregs.rsi);
debug_log("rbp=%lx\n", newregs.rbp);
debug_log("rsp=%lx\n", newregs.rsp);
debug_log("orig_rax=%lx\n", newregs.rax);
debug_log("rip=%lx\n", newregs.rip);
#endif
#ifdef __i386__
debug_log("eax=%lx\n", newregs.eax);
debug_log("edi=%lx\n", newregs.edi);
debug_log("esi=%lx\n", newregs.esi);
debug_log("ebp=%lx\n", newregs.ebp);
debug_log("esp=%lx\n", newregs.esp);
debug_log("orig_eax=%lx\n", newregs.eax);
debug_log("eip=%lx\n", newregs.eip);
#endif
#ifdef __aarch64__
if (p->is64bit)
{
iov.iov_base=&origregs;
iov.iov_len=sizeof(origregs);
}
else
{
iov.iov_base=&origregs32;
iov.iov_len=sizeof(origregs32);
}
if (ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, &iov))
#else
if (ptrace(PTRACE_SETREGS, pid, 0, &origregs)!=0)
#endif
{
debug_log("PTRACE_SETREGS FAILED (20\n");
}
if (!p->isDebugged)
{
debug_log("Detaching\n");
if (ptrace(PTRACE_DETACH, pid,0,0)!=0)
debug_log("PTRACE_DETACH FAILED\n");
}
else
{
if (ptrace(PTRACE_CONT,pid,(void *)0,(void *)SIGCONT)!=0)
debug_log("PTRACE_CONT failed\n");
}
debug_log("End...\n");
return 1;
}
void finddlopencallback(uintptr_t address, char *symbolname, PProcessData context)
{
debug_log("found dlopen at %llx\n", address);
context->dlopen=address;
}
int loadCEServerExtension(HANDLE hProcess)
{
debug_log("loadCEServerExtension\n");
if (GetHandleType(hProcess) == htProcesHandle )
{
PProcessData p=(PProcessData)GetPointerFromHandle(hProcess);
if (p->isDebugged)
{
debug_log("this process is being debugged\n");
//make sure this is executed by the debugger thread
if (p->debuggerThreadID!=pthread_self())
{
debug_log("Not the debugger thread. Switching...\n");
//tell the debugger thread to do this
int result=0;
#pragma pack(1)
struct
{
uint8_t command;
uint32_t pHandle;
} lx;
#pragma pack()
lx.command=CMD_LOADEXTENSION;
lx.pHandle=hProcess;
if (pthread_mutex_lock(&debugsocketmutex) == 0)
{
sendall(p->debuggerClient, &lx, sizeof(lx), 0);
WakeDebuggerThread();
recvall(p->debuggerClient, &result, sizeof(result), MSG_WAITALL);
debug_log("Returned from debugger thread. Result:%d\n", result);
pthread_mutex_unlock(&debugsocketmutex);
}
return result;
}
else
debug_log("This is the debugger thread\n");
}
if (p->hasLoadedExtension==0)
{
char modulepath[256], modulepath2[256];
int l;
memset(modulepath, 0, 256);
memset(modulepath2, 0, 256);
char *mp;
l=readlink("/proc/self/exe", modulepath2, 256);
if (l!=-1)
{
modulepath2[l]=0;
debug_log("modulepath2=%s\n", modulepath2);
sscanf(modulepath2,"%s", modulepath); //sometimes it has a (deleted) text after it
debug_log("modulepath=%s\n", modulepath);
mp=dirname(modulepath);
debug_log("after dirname: %s\n", mp);
strcpy(modulepath, mp);
strcat(modulepath, "/libceserver-extension");
#ifdef __i386__
strcat(modulepath, "_x86");
#endif
#ifdef __x86_64__
if (p->is64bit)
strcat(modulepath, "_x86_64");
else
strcat(modulepath, "_x86");
#endif
#ifdef __aarch64__
if (p->is64bit)
strcat(modulepath, "_arm64");
else
strcat(modulepath, "_arm");
#endif
#ifdef __arm__
strcat(modulepath, "_arm");
#endif
strcat(modulepath,".so");
}
else
{
strcpy(modulepath, "libceserver-extension");
#ifdef __i386__
strcat(modulepath, "_x86");
#endif
#ifdef __x86_64__
if (p->is64bit)
strcat(modulepath, "_x86_64");
else
strcat(modulepath, "_x86");
#endif
#ifdef __aarch64__
if (p->is64bit)
strcat(modulepath, "_arm64");
else
strcat(modulepath, "_arm");
#endif
#ifdef __arm__
strcat(modulepath, "_arm");
#endif
strcat(modulepath,".so");
}
debug_log("modulepath = %s\n", modulepath);
if (p->isDebugged)
{
debug_log("This process is being debugged. Checking if it's already loaded\n");
pthread_mutex_lock(&p->extensionMutex);
p->hasLoadedExtension=openExtension(p->pid, &p->extensionFD);
pthread_mutex_unlock(&p->extensionMutex);
}
// else
if (p->hasLoadedExtension)
debug_log("The extension is already loaded\n");
debug_log("Scanning for dlopen\n");
if (p->dlopen==0)
FindSymbol(hProcess,"dlopen", (symcallback)finddlopencallback, p);
if (p->dlopen==0)
debug_log("failure finding dlopen\n");
{
pthread_mutex_lock(&p->extensionMutex);
if (p->hasLoadedExtension==0) //still 0
{
if (p->neverForceLoadExtension==0)
{
debug_log("Calling loadExtension\n");
p->hasLoadedExtension=loadExtension(p, modulepath);
}
if (p->hasLoadedExtension)
p->hasLoadedExtension=openExtension(p->pid, &p->extensionFD);
debug_log("p->hasLoadedExtension=%d\n", p->hasLoadedExtension);
}
pthread_mutex_unlock(&p->extensionMutex);
}
}
else
debug_log("Already loaded\n");
return p->hasLoadedExtension;
}
else
{
debug_log("Invalid handle type");
return 0;
}
}