|
// HARDENING is removed for clarity (and it doesn't add much for protection, lol.) |
|
|
|
/* rtc.c */ |
|
|
|
#include <sys/stat.h> |
|
#include <sys/types.h> |
|
|
|
#include <errno.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <time.h> |
|
#include <unistd.h> |
|
|
|
/* 'Alleged RC4' */ |
|
|
|
static unsigned char stte[256], indx, jndx, kndx; |
|
|
|
/* |
|
* Reset arc4 stte. |
|
*/ |
|
void stte_0(void) |
|
{ |
|
indx = jndx = kndx = 0; |
|
do { |
|
stte[indx] = indx; |
|
} while (++indx); |
|
} |
|
|
|
/* |
|
* Set key. Can be used more than once. |
|
*/ |
|
void key(void * str, int len) |
|
{ |
|
unsigned char tmp, * ptr = (unsigned char *)str; |
|
while (len > 0) { |
|
do { |
|
tmp = stte[indx]; |
|
kndx += tmp; |
|
kndx += ptr[(int)indx % len]; |
|
stte[indx] = stte[kndx]; |
|
stte[kndx] = tmp; |
|
} while (++indx); |
|
ptr += 256; |
|
len -= 256; |
|
} |
|
} |
|
|
|
/* |
|
* Crypt data. |
|
*/ |
|
void arc4(void * str, int len) |
|
{ |
|
unsigned char tmp, * ptr = (unsigned char *)str; |
|
while (len > 0) { |
|
indx++; |
|
tmp = stte[indx]; |
|
jndx += tmp; |
|
stte[indx] = stte[jndx]; |
|
stte[jndx] = tmp; |
|
tmp += stte[indx]; |
|
*ptr ^= stte[tmp]; |
|
ptr++; |
|
len--; |
|
} |
|
} |
|
|
|
/* End of ARC4 */ |
|
|
|
/* |
|
* Key with file invariants. |
|
*/ |
|
int key_with_file(char * file) |
|
{ |
|
struct stat statf[1]; |
|
struct stat control[1]; |
|
|
|
if (stat(file, statf) < 0) |
|
return -1; |
|
|
|
/* Turn on stable fields */ |
|
memset(control, 0, sizeof(control)); |
|
control->st_ino = statf->st_ino; |
|
control->st_dev = statf->st_dev; |
|
control->st_rdev = statf->st_rdev; |
|
control->st_uid = statf->st_uid; |
|
control->st_gid = statf->st_gid; |
|
control->st_size = statf->st_size; |
|
control->st_mtime = statf->st_mtime; |
|
control->st_ctime = statf->st_ctime; |
|
key(control, sizeof(control)); |
|
return 0; |
|
} |
|
|
|
#if DEBUGEXEC |
|
void debugexec(char * sh11, int argc, char ** argv) |
|
{ |
|
int i; |
|
fprintf(stderr, "shll=%s\n", sh11 ? sh11 : "<null>"); |
|
fprintf(stderr, "argc=%d\n", argc); |
|
if (!argv) { |
|
fprintf(stderr, "argv=<null>\n"); |
|
} else { |
|
for (i = 0; i <= argc ; i++) |
|
fprintf(stderr, "argv[%d]=%.60s\n", i, argv[i] ? argv[i] : "<null>"); |
|
} |
|
} |
|
#endif /* DEBUGEXEC */ |
|
|
|
void rmarg(char ** argv, char * arg) |
|
{ |
|
for (; argv && *argv && *argv != arg; argv++); |
|
for (; argv && *argv; argv++) |
|
*argv = argv[1]; |
|
} |
|
|
|
void chkenv_end(void); |
|
|
|
int chkenv(int argc) |
|
{ |
|
char buff[512]; |
|
unsigned long mask, m; |
|
int l, a, c; |
|
char * string; |
|
extern char ** environ; |
|
|
|
mask = (unsigned long)getpid(); |
|
stte_0(); |
|
key(&chkenv, (void*)&chkenv_end - (void*)&chkenv); |
|
key(&data, sizeof(data)); |
|
key(&mask, sizeof(mask)); |
|
arc4(&mask, sizeof(mask)); |
|
sprintf(buff, "x%lx", mask); |
|
string = getenv(buff); |
|
#if DEBUGEXEC |
|
fprintf(stderr, "getenv(%s)=%s\n", buff, string ? string : "<null>"); |
|
#endif |
|
l = strlen(buff); |
|
if (!string) { |
|
/* 1st */ |
|
sprintf(&buff[l], "=%lu %d", mask, argc); |
|
putenv(strdup(buff)); |
|
return 0; |
|
} |
|
c = sscanf(string, "%lu %d%c", &m, &a, buff); |
|
if (c == 2 && m == mask) { |
|
/* 3rd */ |
|
rmarg(environ, &string[-l - 1]); |
|
return 1 + (argc - a); |
|
} |
|
return -1; |
|
} |
|
|
|
void chkenv_end(void){} |
|
|
|
#if !TRACEABLE |
|
|
|
#define _LINUX_SOURCE_COMPAT |
|
#include <sys/ptrace.h> |
|
#include <sys/types.h> |
|
#include <sys/wait.h> |
|
#include <fcntl.h> |
|
#include <signal.h> |
|
#include <stdio.h> |
|
#include <unistd.h> |
|
|
|
#if !defined(PT_ATTACHEXC) /* New replacement for PT_ATTACH */ |
|
#if !defined(PTRACE_ATTACH) && defined(PT_ATTACH) |
|
#define PT_ATTACHEXC PT_ATTACH |
|
#elif defined(PTRACE_ATTACH) |
|
#define PT_ATTACHEXC PTRACE_ATTACH |
|
#endif |
|
#endif |
|
|
|
void untraceable(char * argv0) |
|
{ |
|
char proc[80]; |
|
int pid, mine; |
|
|
|
switch(pid = fork()) { |
|
case 0: |
|
pid = getppid(); |
|
/* For problematic SunOS ptrace */ |
|
#if defined(__FreeBSD__) |
|
sprintf(proc, "/proc/%d/mem", (int)pid); |
|
#else |
|
sprintf(proc, "/proc/%d/as", (int)pid); |
|
#endif |
|
close(0); |
|
mine = !open(proc, O_RDWR|O_EXCL); |
|
if (!mine && errno != EBUSY) |
|
mine = !ptrace(PT_ATTACHEXC, pid, 0, 0); |
|
if (mine) { |
|
kill(pid, SIGCONT); |
|
} else { |
|
perror(argv0); |
|
kill(pid, SIGKILL); |
|
} |
|
_exit(mine); |
|
case -1: |
|
break; |
|
default: |
|
if (pid == waitpid(pid, 0, 0)) |
|
return; |
|
} |
|
perror(argv0); |
|
_exit(1); |
|
} |
|
#endif /* !TRACEABLE */ |
|
|
|
char * xsh(int argc, char ** argv) |
|
{ |
|
char * scrpt; |
|
int ret, i, j; |
|
char ** varg; |
|
char * me = argv[0]; |
|
if (me == NULL) { me = getenv("_"); } |
|
if (me == 0) { fprintf(stderr, "E: neither argv[0] nor $_ works."); exit(1); } |
|
|
|
ret = chkenv(argc); |
|
stte_0(); |
|
key(pswd, pswd_z); |
|
arc4(msg1, msg1_z); |
|
arc4(date, date_z); |
|
if (date[0] && (atoll(date)<time(NULL))) |
|
return msg1; |
|
arc4(shll, shll_z); |
|
arc4(inlo, inlo_z); |
|
arc4(xecc, xecc_z); |
|
arc4(lsto, lsto_z); |
|
arc4(tst1, tst1_z); |
|
key(tst1, tst1_z); |
|
arc4(chk1, chk1_z); |
|
if ((chk1_z != tst1_z) || memcmp(tst1, chk1, tst1_z)) |
|
return tst1; |
|
arc4(msg2, msg2_z); |
|
if (ret < 0) |
|
return msg2; |
|
varg = (char **)calloc(argc + 10, sizeof(char *)); |
|
if (!varg) |
|
return 0; |
|
if (ret) { |
|
arc4(rlax, rlax_z); |
|
if (!rlax[0] && key_with_file(shll)) |
|
return shll; |
|
arc4(opts, opts_z); |
|
arc4(text, text_z); |
|
arc4(tst2, tst2_z); |
|
key(tst2, tst2_z); |
|
arc4(chk2, chk2_z); |
|
if ((chk2_z != tst2_z) || memcmp(tst2, chk2, tst2_z)) |
|
return tst2; |
|
/* Prepend hide_z spaces to script text to hide it. */ |
|
scrpt = malloc(hide_z + text_z); |
|
if (!scrpt) |
|
return 0; |
|
memset(scrpt, (int) ' ', hide_z); |
|
memcpy(&scrpt[hide_z], text, text_z); |
|
} else { /* Reexecute */ |
|
if (*xecc) { |
|
scrpt = malloc(512); |
|
if (!scrpt) |
|
return 0; |
|
sprintf(scrpt, xecc, me); |
|
} else { |
|
scrpt = me; |
|
} |
|
} |
|
j = 0; |
|
#if BUSYBOXON |
|
varg[j++] = "busybox"; |
|
varg[j++] = "sh"; |
|
#else |
|
varg[j++] = argv[0]; /* My own name at execution */ |
|
#endif |
|
if (ret && *opts) |
|
varg[j++] = opts; /* Options on 1st line of code */ |
|
if (*inlo) |
|
varg[j++] = inlo; /* Option introducing inline code */ |
|
varg[j++] = scrpt; /* The script itself */ |
|
if (*lsto) |
|
varg[j++] = lsto; /* Option meaning last option */ |
|
i = (ret > 1) ? ret : 0; /* Args numbering correction */ |
|
while (i < argc) |
|
varg[j++] = argv[i++]; /* Main run-time arguments */ |
|
varg[j] = 0; /* NULL terminated array */ |
|
#if DEBUGEXEC |
|
debugexec(shll, j, varg); |
|
#endif |
|
execvp(shll, varg); |
|
return shll; |
|
} |
|
|
|
int main(int argc, char ** argv) |
|
{ |
|
#if SETUID |
|
setuid(0); |
|
#endif |
|
#if DEBUGEXEC |
|
debugexec("main", argc, argv); |
|
#endif |
|
#if !TRACEABLE |
|
untraceable(argv[0]); |
|
#endif |
|
argv[1] = xsh(argc, argv); |
|
fprintf(stderr, "%s%s%s: %s\n", argv[0], |
|
errno ? ": " : "", |
|
errno ? strerror(errno) : "", |
|
argv[1] ? argv[1] : "<null>" |
|
); |
|
return 1; |
|
} |
其實抄近路也行,開個 qemu 或者 qiling 最後攔一下 exec 就行,但是我就是要靜態分析,哈哈!