https://bitbucket.org/tewilove/injectso/src/41afcf79b9c4/injectso.c
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#if !defined(__ANDROID__) || (!defined(__arm__) && !defined(__thumb__))
#error "ARM Android only!"
#endif
static void die(int ln) {
char temp[256];
snprintf(temp, sizeof(temp), "failed at %d: %s\n", ln, strerror(errno));
fprintf(stderr, temp);
exit(-1);
}
static void usage(FILE *fp, const char *self) {
fprintf(fp, "Usage:\n");
fprintf(fp, "%s <pid> <so>\n", self);
}
static void* get_module_base_addr(pid_t pid, const char* name) {
FILE *fp;
char path[32];
long addr = -1;
char buffer[1024];
char *temp;
if (pid == -1)
snprintf(path, sizeof(path), "/proc/self/maps");
else
snprintf(path, sizeof(path), "/proc/%d/maps", pid);
fp = fopen(path, "r");
if (!fp)
return (void *)(-1);
while (fgets(buffer, sizeof(buffer), fp)) {
if (strstr(buffer, name)) {
temp = strtok(buffer, "-");
addr = strtoul(temp, NULL, 16);
if(addr == 0x8000) {
addr = 0;
}
break;
}
}
fclose(fp);
return (void*) addr;
}
static void *find_my_dlopen() {
void *handle = dlopen("libdl.so", RTLD_NOW);
if (!handle)
die(__LINE__);
void *symbol = dlsym(handle, "dlopen");
if (!symbol)
die(__LINE__);
return symbol;
}
static int find_symbol_offset(pid_t pid, const char *ref) {
void *mine = get_module_base_addr(-1, ref);
if (!mine)
return -1;
void *theirs = get_module_base_addr(pid, ref);
if (!theirs)
return -1;
return (int)(mine) - (int)(theirs);
}
static void *find_foreign_dlopen(pid_t pid, void *my_dlopen) {
int offset = find_symbol_offset(pid, "/system/bin/linker");
if (offset == -1)
offset = find_symbol_offset(pid, "/system/lib/libc.so");
if (offset == -1)
die(__LINE__);
int result = (int) my_dlopen + offset;
return (void *) result;
}
// memcpy like
static void ptrace_peek(pid_t pid, void* dest, const void* src, size_t n) {
int i;
long *d = (long *) dest, *s = (long *) src;
n /= sizeof(long);
for (i = 0; i < n; i++) {
d[i] = ptrace(PTRACE_PEEKTEXT, pid, s + i, NULL);
if (errno)
die(__LINE__);
}
}
static void ptrace_poke(pid_t pid, void* dest, const void* src, size_t n) {
int i;
long *d = (long *) dest, *s = (long *) src;
for (i = 0; i < n / sizeof(long); i++) {
if (ptrace(PTRACE_POKETEXT, pid, d + i, (void *) s[i]) == -1) {
die(__LINE__);
}
}
}
static int injectso(pid_t pid, const char *so) {
void *p_dlopen = NULL;
void *my_dlopen, *foreign_dlopen;
int err, status, len;
char old_stack[512], new_stack[512];
struct pt_regs old_regs, new_regs;
my_dlopen = find_my_dlopen();
printf("my dlopen = %p\n", my_dlopen);
foreign_dlopen = find_foreign_dlopen(pid, my_dlopen);
printf("foreign dlopen = %p\n", foreign_dlopen);
printf("attaching...\n");
err = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
if (err < 0)
die(__LINE__);
if (waitpid(pid, &status, 0) < 0)
die(__LINE__);
printf("getting regs...\n");
err = ptrace(PTRACE_GETREGS, pid, NULL, &old_regs);
if (err < 0)
die(__LINE__);
printf("pc=%08x, sp=%08x, lr=%08x, cpsr=%08x\n", old_regs.ARM_pc, old_regs.ARM_sp, old_regs.ARM_lr, old_regs.ARM_cpsr);
printf("reading foreign stack...\n");
ptrace_peek(pid, old_stack, (void *) old_regs.ARM_sp, sizeof(old_stack));
len = strlen(so);
memset(new_stack, 0, sizeof(new_stack));
memcpy(new_stack, so, len);
memcpy(&new_regs, &old_regs, sizeof(struct pt_regs));
printf("writing foreign stack...\n");
ptrace_poke(pid, (void *) old_regs.ARM_sp, new_stack, sizeof(new_stack));
// = psz_path
new_regs.ARM_r0 = old_regs.ARM_sp;
new_regs.ARM_r1 = RTLD_NOW;
new_regs.ARM_sp += sizeof(new_stack);
// trigger a SIGE*** after cont
new_regs.ARM_lr = 0;
new_regs.ARM_pc = (long) foreign_dlopen;
if (new_regs.ARM_pc & 1)
new_regs.ARM_cpsr |= PSR_T_BIT;
else
new_regs.ARM_cpsr &= ~PSR_T_BIT;
printf("setting regs...\n");
err = ptrace(PTRACE_SETREGS, pid, NULL, &new_regs);
if (err < 0)
die(__LINE__);
printf("resuming...\n");
err = ptrace(PTRACE_CONT, pid, NULL, NULL);
if (err < 0)
die(__LINE__);
if (waitpid(pid, &status, 0) < 0)
die(__LINE__);
printf("restoring foreign stack...\n");
ptrace_poke(pid, (void *) old_regs.ARM_sp, old_stack, sizeof(old_stack));
printf("restoring old regs...\n");
err = ptrace(PTRACE_SETREGS, pid, NULL, &old_regs);
if (err < 0)
die(__LINE__);
err = ptrace(PTRACE_DETACH, pid, NULL, NULL);
if (err < 0)
die(__LINE__);
return 0;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
usage(stderr, argv[0]);
exit(-1);
}
pid_t pid = strtoul(argv[1], NULL, 10);
return injectso(pid, argv[2]);
}
|