-
Notifications
You must be signed in to change notification settings - Fork 12
/
freethedsp.c
124 lines (102 loc) · 3.74 KB
/
freethedsp.c
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
// 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 -Iinclude -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)
// under 100 lines of code begins now
#include <stdio.h>
#include <dlfcn.h>
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
int close(int fd);
// 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 file; /* pointer to elf file */
int32_t filelen; /* elf file length */
int32_t filefd; /* ION fd for the file */
uintptr_t 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);
if (handle == NULL) {
handle = dlopen("/lib/aarch64-linux-gnu/libc.so.6", 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, 4) == 0);
memcpy((void*)(init->mem+PATCH_ADDR), PATCH_NEW, 4);
// 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 = PATCH_ADDR;
flush_data.length = PATCH_LEN;
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;
}