5
5
#include <string.h>
6
6
#include <time.h>
7
7
8
+ #include "patcher-payload.h"
9
+
8
10
#define LOGFILE "/data/local/tmp/patcher-payload.log"
9
11
#define LOGFILE_MODE "w" // fopen() mode; 'a'ppend or 'w'rite (with truncation).
10
12
13
+ #define OWN_LIBNAME "patcher-payload" // Our own name, for skipping the GOT patching.
14
+
15
+ #define MAIN_PROCESS_NAME "dtv_svc" // Name of the main binary (dl* just return "").
16
+
17
+ #define UNUSED __attribute__((unused))
18
+
19
+ // Log file, opened in init().
11
20
static FILE * logf = NULL ;
12
21
22
+ // A machine word.
23
+ typedef uint32_t word ;
24
+
25
+ // Log handler; to be used with the log() macro that passes file and line.
13
26
__attribute__((format (printf , 3 , 4 )))
14
27
static void do_log (const char * filename , int lineno , const char * format , ...) {
15
28
if (!logf )
@@ -32,89 +45,56 @@ static void do_log(const char *filename, int lineno, const char *format, ...) {
32
45
fflush (logf );
33
46
}
34
47
48
+ // Log with current filename and line.
35
49
#define log (...) do_log(__FILE__, __LINE__, __VA_ARGS__)
36
50
37
- #define PROT_NONE 0x00
38
- #define PROT_READ 0x04
39
- #define PROT_WRITE 0x02
40
- #define PROT_EXEC 0x01
41
- extern int mprotect (void * addr , size_t len , int prot );
42
-
43
- #define PF_X (1 << 0) /* Segment is executable */
44
- #define PF_W (1 << 1) /* Segment is writable */
45
- #define PF_R (1 << 2) /* Segment is readable */
46
-
47
- #define PF_RW (PF_R|PF_W)
48
-
49
- #define PT_NULL 0 /* Program header table entry unused */
50
- #define PT_LOAD 1 /* Loadable program segment */
51
- #define PT_DYNAMIC 2 /* Dynamic linking information */
52
- /* […] rest omitted for brevity */
53
-
54
- struct elf32_phdr {
55
- uint32_t type ; /* Segment type */
56
- uint32_t offset ; /* Segment file offset */
57
- uint32_t vaddr ; /* Segment virtual address */
58
- uint32_t paddr ; /* Segment physical address */
59
- uint32_t filesz ; /* Segment size in file */
60
- uint32_t memsz ; /* Segment size in memory */
61
- uint32_t flags ; /* Segment flags */
62
- uint32_t align ; /* Segment alignment */
51
+ // A request to patch each loaded library’s GOT with pointers to oldval pointing to newval.
52
+ struct patch_got_req {
53
+ word oldval ;
54
+ word newval ;
63
55
};
64
56
65
- struct dl_phdr_info {
66
- void * addr ; /* Base address of object */
67
- const char * name ; /* Name of object */
68
- const struct elf32_phdr * phdr ; /* Pointer to array of ELF program headers */
69
- uint16_t phnum ; /* # of items in phdr */
57
+ // An item in the undo_list, for unpatching GOTs in fini().
58
+ struct undo_item {
59
+ word * addr ;
60
+ word oldval ;
70
61
};
71
62
72
- extern int dl_iterate_phdr (void * callback , void * data );
73
-
74
- #define RTLD_LAZY 0x00001 /* Lazy function call binding. */
75
- #define RTLD_NOW 0x00002 /* Immediate function call binding. */
76
- #define RTLD_BINDING_MASK 0x3 /* Mask of binding time value. */
77
- #define RTLD_NOLOAD 0x00004 /* Do not load the object. */
78
- #define RTLD_DEEPBIND 0x00008 /* Use deep binding. */
63
+ // Patched words with their old value.
64
+ #define UNDO_LIST_SIZE 256
65
+ static struct undo_item undo_list [UNDO_LIST_SIZE ];
79
66
80
- extern void * dlsym (void * hdl , const char * name );
81
- extern void * dlopen (const char * , int );
82
- extern int dlclose (void * );
83
-
84
- #define UNUSED __attribute__((unused))
67
+ // Number of undo_list elements populated. Top of stack is undo_list[undo_size-1].
68
+ static unsigned int undo_size = 0 ;
85
69
86
70
static char * (* orig_getval )(int16_t grp , char * cfg , int32_t * value ) = NULL ;
87
71
88
- struct patch_got_req {
89
- void * oldval ;
90
- void * newval ;
91
- };
92
-
93
- struct undo_item {
94
- uint32_t * addr ;
95
- uint32_t oldval ;
96
- };
97
-
98
- static struct undo_item undo [256 ];
99
- static unsigned int nundo = 0 ;
100
-
101
72
static char * my_getval (int16_t grp , char * cfg , int32_t * value ) {
102
73
char * ret = orig_getval (grp , cfg , value );
103
74
log ("orig_getval(grp=%d, cfg=%s, *value=%ld) = %s" , grp , cfg , (value ?* value :0xDEAD ), ret );
104
75
return ret ;
105
76
}
106
77
107
- static int patch_got (void * start , void * end , const char * filename , struct patch_got_req * req ) {
78
+ // Patch a GOT as described in req. The GOT is expected to be within start-end and contain the
79
+ // value to patch at most once. (We can’t really easily tell where the GOT in the ELF segment
80
+ // is, so we search all of it and if we found the value twice, the chances of either of them
81
+ // being some other random data is nonzero.)
82
+ static int patch_got (word * start , word * end , const char * filename , struct patch_got_req * req ) {
83
+ if (strstr (filename , OWN_LIBNAME ))
84
+ return 0 ;
85
+
108
86
if (!* filename )
109
- filename = "dtv_svc" ;
87
+ filename = MAIN_PROCESS_NAME ;
110
88
111
- uint32_t * off = NULL ;
89
+ word * off = NULL ;
112
90
113
- for (uint32_t * p = start ; p < ( uint32_t * ) end ; p ++ ) {
114
- if (* p != ( uint32_t ) req -> oldval )
91
+ for (word * p = start ; p < end ; p ++ ) {
92
+ if (* p != req -> oldval )
115
93
continue ;
94
+
116
95
if (off ) {
117
- log ("patch_got(%p, %p): found old value twice (%p and %p), not patching." , start , end , off , p );
96
+ log ("patch_got(%p, %p, \"%s\"): found old value twice (at %p and at %p), not patching." ,
97
+ start , end , filename , off , p );
118
98
return -1 ;
119
99
}
120
100
off = p ;
@@ -123,27 +103,27 @@ static int patch_got(void *start, void *end, const char *filename, struct patch_
123
103
if (!off )
124
104
return 0 ;
125
105
126
- if (++ nundo > sizeof (undo )) {
127
- log ("can 't store more than %d undo items" , sizeof (undo ));
106
+ if (++ undo_size > sizeof (undo_list )) {
107
+ log ("Can 't store more than %d undo items, increase UNDO_LIST_SIZE. " , sizeof (undo_list ));
128
108
return -1 ;
129
109
}
130
110
131
- undo [nundo - 1 ].addr = off ;
132
- undo [nundo - 1 ].oldval = * off ;
133
- * off = (uint32_t )req -> newval ;
134
- log ("Patched %p 0x%08lx -> 0x%08lx" , off , undo [nundo - 1 ].oldval , * off );
111
+ undo_list [undo_size - 1 ].addr = off ;
112
+ undo_list [undo_size - 1 ].oldval = * off ;
113
+ * off = req -> newval ;
114
+ log ("Patched GOT of %s at %p (from 0x%08lx to 0x%08lx)" , filename , off ,
115
+ undo_list [undo_size - 1 ].oldval , * off );
135
116
136
117
return 0 ;
137
118
}
138
119
120
+ // Callback for dl_iterate_phdr. Walks over all ELF segments and calls patch_got for each that
121
+ // is likely to contain a GOT (i.e. is of type LOAD and read- and writable).
139
122
static int find_got_phdr (struct dl_phdr_info * info , size_t size UNUSED , struct patch_got_req * req ) {
140
123
for (int i = 0 ; i < info -> phnum ; i ++ ) {
141
124
if (info -> phdr [i ].type != PT_LOAD || (info -> phdr [i ].flags & PF_RW ) != PF_RW )
142
125
continue ;
143
126
144
- if (strstr (info -> name , "patcher-payload" )) // XXX
145
- continue ;
146
-
147
127
void * start = info -> addr + info -> phdr [i ].vaddr ;
148
128
void * end = start + info -> phdr [i ].memsz ;
149
129
@@ -155,6 +135,7 @@ static int find_got_phdr(struct dl_phdr_info *info, size_t size UNUSED, struct p
155
135
}
156
136
157
137
138
+ // Sets up logging and installs all hooks.
158
139
__attribute__((constructor )) static void init () {
159
140
if (logf )
160
141
fclose (logf );
@@ -170,7 +151,7 @@ __attribute__((constructor)) static void init() {
170
151
return ;
171
152
}
172
153
173
- void * hdl = dlopen ("libmtkapp.so" , 6 );
154
+ void * hdl = dlopen ("libmtkapp.so" , RTLD_NOW | RTLD_NOLOAD );
174
155
const char * symname = "a_mtktvapi_config_get_value" ;
175
156
orig_getval = dlsym (hdl , symname );
176
157
@@ -184,22 +165,23 @@ __attribute__((constructor)) static void init() {
184
165
185
166
log ("Patching GOTs referencing %s = %p" , symname , orig_getval );
186
167
struct patch_got_req req = {
187
- .oldval = orig_getval ,
188
- .newval = my_getval ,
168
+ .oldval = ( word ) orig_getval ,
169
+ .newval = ( word ) my_getval ,
189
170
};
190
171
dl_iterate_phdr (find_got_phdr , & req );
191
172
192
173
193
174
log ("Initialized" );
194
175
}
195
176
177
+ // Uninstalls all hooks and closes the logfile.
196
178
__attribute__((destructor )) static void fini () {
197
179
log ("Tearing down." );
198
180
199
- while (nundo > 0 ) {
200
- * (undo [ nundo - 1 ].addr ) = undo [ nundo - 1 ].oldval ;
201
- log ("Undid GOT patch at %p" , undo [ nundo - 1 ].addr );
202
- nundo -- ;
181
+ while (undo_size > 0 ) {
182
+ * (undo_list [ undo_size - 1 ].addr ) = undo_list [ undo_size - 1 ].oldval ;
183
+ log ("Undid GOT patch at %p" , undo_list [ undo_size - 1 ].addr );
184
+ undo_size -- ;
203
185
}
204
186
205
187
if (fclose (logf ) == 0 )
0 commit comments