You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
120 lines
3.6 KiB
120 lines
3.6 KiB
7 years ago
|
// freethedsp by geohot
|
||
|
// (because the DSP should be free)
|
||
|
// released under MIT License
|
||
|
|
||
|
// usage instructions:
|
||
|
// 1. Compile an example from the Qualcomm Hexagon SDK
|
||
|
// 2. Try to run it on your phone
|
||
|
// 3. Be very sad when "adsprpc ... dlopen error: ... signature verify start failed for ..." appears in logcat
|
||
|
// ...here is where people would give up before freethedsp
|
||
|
// 4. Compile freethedsp with 'clang -shared freethedsp.c -o freethedsp.so' (or statically link it to your program)
|
||
|
// 5. Run your program with 'LD_PRELOAD=./freethedsp.so ./<your_prog>'
|
||
|
// 6. OMG THE DSP WORKS
|
||
|
// 7. Be happy.
|
||
|
|
||
|
// *** patch may have to change for your phone ***
|
||
|
|
||
|
// this is patching /dsp/fastrpc_shell_0
|
||
|
// correct if sha hash of fastrpc_shell_0 is "fbadc96848aefad99a95aa4edb560929dcdf78f8"
|
||
|
// patch to return 0xFFFFFFFF from is_test_enabled instead of 0
|
||
|
// your fastrpc_shell_0 may vary
|
||
|
#define PATCH_ADDR 0x5200c
|
||
|
#define PATCH_OLD "\x40\x3f\x20\x50"
|
||
|
#define PATCH_NEW "\x40\x3f\x00\x5a"
|
||
|
#define PATCH_LEN (sizeof(PATCH_OLD)-1)
|
||
|
#define _BITS_IOCTL_H_
|
||
|
|
||
|
// under 100 lines of code begins now
|
||
|
#include <stdio.h>
|
||
|
#include <dlfcn.h>
|
||
|
#include <assert.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
// ioctl stuff
|
||
|
#define IOC_OUT 0x40000000 /* copy out parameters */
|
||
|
#define IOC_IN 0x80000000 /* copy in parameters */
|
||
|
#define IOC_INOUT (IOC_IN|IOC_OUT)
|
||
|
#define IOCPARM_MASK 0x1fff /* parameter length, at most 13 bits */
|
||
|
|
||
|
#define _IOC(inout,group,num,len) \
|
||
|
(inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
|
||
|
#define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t))
|
||
|
|
||
|
// ion ioctls
|
||
|
#include <linux/ion.h>
|
||
|
#define ION_IOC_MSM_MAGIC 'M'
|
||
|
#define ION_IOC_CLEAN_INV_CACHES _IOWR(ION_IOC_MSM_MAGIC, 2, \
|
||
|
struct ion_flush_data)
|
||
|
|
||
|
struct ion_flush_data {
|
||
|
ion_user_handle_t handle;
|
||
|
int fd;
|
||
|
void *vaddr;
|
||
|
unsigned int offset;
|
||
|
unsigned int length;
|
||
|
};
|
||
|
|
||
|
// fastrpc ioctls
|
||
|
#define FASTRPC_IOCTL_INIT _IOWR('R', 6, struct fastrpc_ioctl_init)
|
||
|
|
||
|
struct fastrpc_ioctl_init {
|
||
|
uint32_t flags; /* one of FASTRPC_INIT_* macros */
|
||
|
uintptr_t __user file; /* pointer to elf file */
|
||
|
int32_t filelen; /* elf file length */
|
||
|
int32_t filefd; /* ION fd for the file */
|
||
|
uintptr_t __user mem; /* mem for the PD */
|
||
|
int32_t memlen; /* mem length */
|
||
|
int32_t memfd; /* ION fd for the mem */
|
||
|
};
|
||
|
|
||
|
int ioctl(int fd, unsigned long request, void *arg) {
|
||
|
static void *handle = NULL;
|
||
|
static int (*orig_ioctl)(int, int, void*);
|
||
|
|
||
|
if (handle == NULL) {
|
||
|
handle = dlopen("/system/lib64/libc.so", RTLD_LAZY);
|
||
|
assert(handle != NULL);
|
||
|
orig_ioctl = dlsym(handle, "ioctl");
|
||
|
}
|
||
|
|
||
|
int ret = orig_ioctl(fd, request, arg);
|
||
|
|
||
|
// carefully modify this one
|
||
|
if (request == FASTRPC_IOCTL_INIT) {
|
||
|
struct fastrpc_ioctl_init *init = (struct fastrpc_ioctl_init *)arg;
|
||
|
|
||
|
// confirm patch is correct and do the patch
|
||
|
assert(memcmp((void*)(init->mem+PATCH_ADDR), PATCH_OLD, PATCH_LEN) == 0);
|
||
|
memcpy((void*)(init->mem+PATCH_ADDR), PATCH_NEW, PATCH_LEN);
|
||
|
|
||
|
// flush cache
|
||
|
int ionfd = open("/dev/ion", O_RDONLY);
|
||
|
assert(ionfd > 0);
|
||
|
|
||
|
struct ion_fd_data fd_data;
|
||
|
fd_data.fd = init->memfd;
|
||
|
int ret = ioctl(ionfd, ION_IOC_IMPORT, &fd_data);
|
||
|
assert(ret == 0);
|
||
|
|
||
|
struct ion_flush_data flush_data;
|
||
|
flush_data.handle = fd_data.handle;
|
||
|
flush_data.vaddr = (void*)init->mem;
|
||
|
flush_data.offset = 0;
|
||
|
flush_data.length = init->memlen;
|
||
|
ret = ioctl(ionfd, ION_IOC_CLEAN_INV_CACHES, &flush_data);
|
||
|
assert(ret == 0);
|
||
|
|
||
|
struct ion_handle_data handle_data;
|
||
|
handle_data.handle = fd_data.handle;
|
||
|
ret = ioctl(ionfd, ION_IOC_FREE, &handle_data);
|
||
|
assert(ret == 0);
|
||
|
|
||
|
// cleanup
|
||
|
close(ionfd);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|