1091 lines
22 KiB
C
1091 lines
22 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <jni.h>
|
|
#include <fcntl.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <dlfcn.h>
|
|
#include <sys/system_properties.h>
|
|
#include <inttypes.h>
|
|
#include <android/log.h>
|
|
#include <errno.h>
|
|
|
|
#include "plt.h"
|
|
#include "inline.h"
|
|
#include "apk-sign-v2.h"
|
|
#include "am-proxy.h"
|
|
#include "common.h"
|
|
#include "openat.h"
|
|
#include "path.h"
|
|
|
|
#ifdef CHECK_MOUNT
|
|
#include "mount.h"
|
|
#endif
|
|
|
|
static int genuine = CHECK_TRUE;
|
|
|
|
static int sdk;
|
|
|
|
static int uid;
|
|
|
|
static inline void fill_maps(char v[]) {
|
|
static unsigned int m = 0;
|
|
if (m == 0) {
|
|
m = 13;
|
|
} else if (m == 17) {
|
|
m = 19;
|
|
}
|
|
v[0x0] = '-';
|
|
v[0x1] = 's';
|
|
v[0x2] = 'v';
|
|
v[0x3] = 'j';
|
|
v[0x4] = 'e';
|
|
v[0x5] = '(';
|
|
v[0x6] = '{';
|
|
v[0x7] = 'l';
|
|
v[0x8] = 'f';
|
|
v[0x9] = 'm';
|
|
v[0xa] = '#';
|
|
v[0xb] = 'm';
|
|
v[0xc] = '`';
|
|
v[0xd] = 'r';
|
|
v[0xe] = 'p';
|
|
for (unsigned int i = 0; i < 0xf; ++i) {
|
|
v[i] ^= ((i + 0xf) % m);
|
|
}
|
|
v[0xf] = '\0';
|
|
}
|
|
|
|
#ifndef NO_CHECK_MAPS
|
|
static inline void fill_cannot_open_proc_self_maps(char v[]) {
|
|
// cannot open /proc/self/maps
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 23;
|
|
} else if (m == 29) {
|
|
m = 31;
|
|
}
|
|
|
|
v[0x0] = 'g';
|
|
v[0x1] = 'd';
|
|
v[0x2] = 'h';
|
|
v[0x3] = 'i';
|
|
v[0x4] = 'g';
|
|
v[0x5] = '}';
|
|
v[0x6] = '*';
|
|
v[0x7] = 'd';
|
|
v[0x8] = '|';
|
|
v[0x9] = 'h';
|
|
v[0xa] = '`';
|
|
v[0xb] = '/';
|
|
v[0xc] = '?';
|
|
v[0xd] = 'a';
|
|
v[0xe] = '`';
|
|
v[0xf] = '|';
|
|
v[0x10] = 'w';
|
|
v[0x11] = ':';
|
|
v[0x12] = 'e';
|
|
v[0x13] = 'e';
|
|
v[0x14] = 'm';
|
|
v[0x15] = 'd';
|
|
v[0x16] = ',';
|
|
v[0x17] = 'i';
|
|
v[0x18] = 'd';
|
|
v[0x19] = 'v';
|
|
v[0x1a] = 't';
|
|
for (unsigned int i = 0; i < 0x1b; ++i) {
|
|
v[i] ^= ((i + 0x1b) % m);
|
|
}
|
|
v[0x1b] = '\0';
|
|
}
|
|
|
|
static inline void fill_r(char v[]) {
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 2;
|
|
} else if (m == 3) {
|
|
m = 5;
|
|
}
|
|
|
|
v[0x0] = 's';
|
|
for (unsigned int i = 0; i < 0x1; ++i) {
|
|
v[i] ^= ((i + 0x1) % m);
|
|
}
|
|
v[0x1] = '\0';
|
|
}
|
|
|
|
static inline void rstrip(char *line) {
|
|
char *path = line;
|
|
if (line != NULL) {
|
|
while (*path && *path != '\r' && *path != '\n') {
|
|
++path;
|
|
}
|
|
if (*path) {
|
|
*path = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline bool isapk(const char *str) {
|
|
const char *dot = strrchr(str, '.');
|
|
return dot != NULL
|
|
&& *++dot == 'a'
|
|
&& *++dot == 'p'
|
|
&& *++dot == 'k'
|
|
&& (*++dot == '\0' || *dot == '\r' || *dot == '\n');
|
|
}
|
|
|
|
static inline bool isdex(const char *str) {
|
|
const char *dot = strrchr(str, '.');
|
|
return dot != NULL
|
|
&& *++dot == 'd'
|
|
&& *++dot == 'e'
|
|
&& *++dot == 'x'
|
|
&& (*++dot == '\0' || *dot == '\r' || *dot == '\n');
|
|
}
|
|
|
|
static inline bool isodex(const char *str) {
|
|
const char *dot = strrchr(str, '.');
|
|
return dot != NULL
|
|
&& *++dot == 'o'
|
|
&& *++dot == 'd'
|
|
&& *++dot == 'e'
|
|
&& *++dot == 'x'
|
|
&& (*++dot == '\0' || *dot == '\r' || *dot == '\n');
|
|
}
|
|
|
|
static inline bool isso(const char *str) {
|
|
const char *dot = strrchr(str, '.');
|
|
return dot != NULL
|
|
&& *++dot == 's'
|
|
&& *++dot == 'o'
|
|
&& (*++dot == '\0' || *dot == '\r' || *dot == '\n');
|
|
}
|
|
|
|
#ifdef ANTI_ODEX
|
|
static inline size_t fill_dex2oat_cmdline(char v[]) {
|
|
// dex2oat-cmdline
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 13;
|
|
} else if (m == 17) {
|
|
m = 19;
|
|
}
|
|
|
|
v[0x0] = 'f';
|
|
v[0x1] = 'f';
|
|
v[0x2] = '|';
|
|
v[0x3] = '7';
|
|
v[0x4] = 'i';
|
|
v[0x5] = 'f';
|
|
v[0x6] = '|';
|
|
v[0x7] = '$';
|
|
v[0x8] = 'i';
|
|
v[0x9] = 'f';
|
|
v[0xa] = 'h';
|
|
v[0xb] = 'l';
|
|
v[0xc] = 'h';
|
|
v[0xd] = 'l';
|
|
v[0xe] = 'f';
|
|
for (unsigned int i = 0; i < 0xf; ++i) {
|
|
v[i] ^= ((i + 0xf) % m);
|
|
}
|
|
v[0xf] = '\0';
|
|
return 0xf;
|
|
}
|
|
|
|
static inline size_t fill_dex_file(char v[]) {
|
|
// --dex-file
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 7;
|
|
} else if (m == 11) {
|
|
m = 13;
|
|
}
|
|
|
|
v[0x0] = '.';
|
|
v[0x1] = ')';
|
|
v[0x2] = 'a';
|
|
v[0x3] = 'c';
|
|
v[0x4] = 'x';
|
|
v[0x5] = ',';
|
|
v[0x6] = 'd';
|
|
v[0x7] = 'j';
|
|
v[0x8] = 'h';
|
|
v[0x9] = '`';
|
|
for (unsigned int i = 0; i < 0xa; ++i) {
|
|
v[i] ^= ((i + 0xa) % m);
|
|
}
|
|
v[0xa] = '\0';
|
|
return 0xa;
|
|
}
|
|
|
|
static inline int checkOdex(const char *path) {
|
|
size_t len;
|
|
char *cmdline;
|
|
char buffer[0x400], find[64];
|
|
|
|
int ret = 0;
|
|
int fd = open(path, (unsigned) O_RDONLY | (unsigned) O_CLOEXEC);
|
|
if (fd == -1) {
|
|
return 1;
|
|
}
|
|
|
|
lseek(fd, 0x1000, SEEK_SET);
|
|
read(fd, buffer, 0x400);
|
|
|
|
cmdline = buffer;
|
|
len = fill_dex2oat_cmdline(find) + 1;
|
|
for (int i = 0; i < 0x200; ++i, ++cmdline) {
|
|
if (memcmp(cmdline, find, len) == 0) {
|
|
cmdline += len;
|
|
fill_dex_file(find);
|
|
if ((ret = (strstr(cmdline, find) != NULL))) {
|
|
fill_dex2oat_cmdline(find);
|
|
LOGE(find);
|
|
LOGE(cmdline);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static inline bool isSameFile(const char *path1, const char *path2) {
|
|
struct stat stat1, stat2;
|
|
if (path1 == NULL || path2 == NULL) {
|
|
return false;
|
|
}
|
|
if (lstat(path1, &stat1)) {
|
|
return false;
|
|
}
|
|
if (lstat(path2, &stat2)) {
|
|
return false;
|
|
}
|
|
return stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino;
|
|
}
|
|
|
|
static inline void fill_ba88(char v[]) {
|
|
// ba887869b4a4a6d1e915d383fad97c49
|
|
static unsigned int m = 0;
|
|
if (m == 0) {
|
|
m = 13;
|
|
} else if (m == 17) {
|
|
m = 19;
|
|
}
|
|
v[0x0] = 'f';
|
|
v[0x1] = 'o';
|
|
v[0x2] = '[';
|
|
v[0x3] = 'l';
|
|
v[0x4] = 'r';
|
|
v[0x5] = 'b';
|
|
v[0x6] = 'z';
|
|
v[0x7] = 'h';
|
|
v[0x8] = '~';
|
|
v[0x9] = 'n';
|
|
v[0xa] = 'S';
|
|
v[0xb] = 'p';
|
|
v[0xc] = 'i';
|
|
v[0xd] = 'f';
|
|
v[0xe] = 'q';
|
|
for (unsigned int i = 0; i < 0xf; ++i) {
|
|
v[i] ^= ((i + 0xf) % m);
|
|
}
|
|
v[0xf] = '\0';
|
|
}
|
|
|
|
static inline bool isSame(const char *path1, const char *path2) {
|
|
if (path1[0] == '/') {
|
|
return strcmp(path1, path2) == 0;
|
|
} else {
|
|
return strcmp(path1, strrchr(path2, '/') + 1) == 0;
|
|
}
|
|
}
|
|
|
|
static inline void fill_cannot_find_s(char v[]) {
|
|
// cannot find %s
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 13;
|
|
} else if (m == 17) {
|
|
m = 19;
|
|
}
|
|
|
|
v[0x0] = 'b';
|
|
v[0x1] = 'c';
|
|
v[0x2] = 'm';
|
|
v[0x3] = 'j';
|
|
v[0x4] = 'j';
|
|
v[0x5] = 'r';
|
|
v[0x6] = '\'';
|
|
v[0x7] = 'n';
|
|
v[0x8] = '`';
|
|
v[0x9] = 'd';
|
|
v[0xa] = 'o';
|
|
v[0xb] = ',';
|
|
v[0xc] = '%';
|
|
v[0xd] = 'r';
|
|
for (unsigned int i = 0; i < 0xe; ++i) {
|
|
v[i] ^= ((i + 0xe) % m);
|
|
}
|
|
v[0xe] = '\0';
|
|
}
|
|
|
|
static inline void fill_invalid_signature_path_s(char v[]) {
|
|
// invalid signature, path: %s
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 23;
|
|
} else if (m == 29) {
|
|
m = 31;
|
|
}
|
|
|
|
v[0x0] = 'm';
|
|
v[0x1] = 'k';
|
|
v[0x2] = 'p';
|
|
v[0x3] = 'f';
|
|
v[0x4] = 'd';
|
|
v[0x5] = '`';
|
|
v[0x6] = 'n';
|
|
v[0x7] = '+';
|
|
v[0x8] = '\x7f';
|
|
v[0x9] = 'd';
|
|
v[0xa] = 'i';
|
|
v[0xb] = 'a';
|
|
v[0xc] = 'q';
|
|
v[0xd] = 'e';
|
|
v[0xe] = 'g';
|
|
v[0xf] = 'a';
|
|
v[0x10] = 'q';
|
|
v[0x11] = '9';
|
|
v[0x12] = '6';
|
|
v[0x13] = 'p';
|
|
v[0x14] = '`';
|
|
v[0x15] = 'v';
|
|
v[0x16] = 'k';
|
|
v[0x17] = '>';
|
|
v[0x18] = '%';
|
|
v[0x19] = '#';
|
|
v[0x1a] = 't';
|
|
for (unsigned int i = 0; i < 0x1b; ++i) {
|
|
v[i] ^= ((i + 0x1b) % m);
|
|
}
|
|
v[0x1b] = '\0';
|
|
}
|
|
|
|
enum {
|
|
TYPE_NON,
|
|
TYPE_APK,
|
|
TYPE_DEX,
|
|
TYPE_SO,
|
|
};
|
|
|
|
static inline int checkMaps(const char *packageName) {
|
|
FILE *fp = NULL;
|
|
char line[PATH_MAX];
|
|
char maps[0x10];
|
|
int check = genuine;
|
|
bool loaded = false;
|
|
|
|
fill_maps(maps);
|
|
int fd = (int) openAt(AT_FDCWD, maps, O_RDONLY);
|
|
#ifdef DEBUG_OPENAT
|
|
LOGI("openat %s returns %d", maps, fd);
|
|
#endif
|
|
if (fd < 0) {
|
|
fill_cannot_open_proc_self_maps(line);
|
|
LOGE(line);
|
|
return CHECK_ERROR;
|
|
}
|
|
|
|
Symbol symbol;
|
|
fill_ba88(line);
|
|
memset(&symbol, 0, sizeof(Symbol));
|
|
symbol.check = (PLT_CHECK_PLT_APP | PLT_CHECK_NAME);
|
|
symbol.symbol_name = (char *) line;
|
|
if (dl_iterate_phdr_symbol(&symbol)) {
|
|
LOGE(line);
|
|
check = CHECK_ERROR;
|
|
goto clean2;
|
|
}
|
|
|
|
#if __ANDROID_API__ >= 21 || !defined(__arm__)
|
|
if (symbol.size == 0) {
|
|
LOGE(line);
|
|
check = CHECK_ERROR;
|
|
goto clean2;
|
|
}
|
|
#endif
|
|
|
|
char mode[0x2];
|
|
fill_r(mode);
|
|
|
|
fp = fdopen(fd, mode);
|
|
if (fp == NULL) {
|
|
fill_cannot_open_proc_self_maps(line);
|
|
LOGE(line);
|
|
check = CHECK_ERROR;
|
|
goto clean3;
|
|
}
|
|
|
|
while (fgets(line, PATH_MAX - 1, fp) != NULL) {
|
|
int type;
|
|
char *path = line;
|
|
if (strchr(line, '/') == NULL) {
|
|
continue;
|
|
}
|
|
while (*path != '/') {
|
|
++path;
|
|
}
|
|
rstrip(path);
|
|
if (isapk(path)) {
|
|
type = TYPE_APK;
|
|
} else if (isodex(path) || isdex(path)) {
|
|
type = TYPE_DEX;
|
|
} else if (isso(path)) {
|
|
type = TYPE_SO;
|
|
if (symbol.size > 0) {
|
|
bool found = false;
|
|
for (int i = 0; i < symbol.size; ++i) {
|
|
if (symbol.names[i] != NULL) {
|
|
if (isSame(symbol.names[i], path)) {
|
|
free(symbol.names[i]);
|
|
symbol.names[i] = NULL;
|
|
} else {
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
if (!found) {
|
|
symbol.size = 0;
|
|
}
|
|
}
|
|
} else {
|
|
type = TYPE_NON;
|
|
}
|
|
#ifdef DEBUG_MAPS
|
|
LOGI("type: %d, line: %s", type, line);
|
|
#endif
|
|
if (strstr(path, packageName) != NULL) {
|
|
if (type == TYPE_APK) {
|
|
#ifdef DEBUG
|
|
LOGI("check %s", path);
|
|
#endif
|
|
if (isDataApp(path) || isExternalSdApp(path)) {
|
|
loaded = true;
|
|
int sign = checkSignature(path);
|
|
if (sign) {
|
|
fill_invalid_signature_path_s(line);
|
|
LOGE(line, path);
|
|
#ifndef DEBUG_FAKE
|
|
check = sign < 0 ? CHECK_NOAPK : CHECK_FAKE;
|
|
#endif
|
|
}
|
|
}
|
|
} else if (type == TYPE_DEX) {
|
|
#ifdef ANTI_ODEX
|
|
#ifdef DEBUG
|
|
LOGI("check %s", path);
|
|
#endif
|
|
if (checkOdex(path)) {
|
|
LOGE(path);
|
|
check = CHECK_ODEX;
|
|
}
|
|
#endif
|
|
}
|
|
} else if (isDataApp(path)) {
|
|
if (type == TYPE_DEX) {
|
|
//LOGE(path);
|
|
//check = CHECK_DEX;
|
|
} else if (type == TYPE_APK) {
|
|
#ifdef ANTI_OVERLAY
|
|
LOGE(path);
|
|
check = CHECK_OVERLAY;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
clean3:
|
|
close(fd);
|
|
|
|
clean2:
|
|
fill_cannot_find_s(line);
|
|
if (!loaded) {
|
|
LOGE(line, "");
|
|
check = CHECK_ERROR;
|
|
}
|
|
for (int i = 0; i < symbol.size; ++i) {
|
|
if (symbol.names[i] != NULL) {
|
|
if (strchr(symbol.names[i], '!') == NULL) {
|
|
LOGE(line, symbol.names[i]);
|
|
check = CHECK_ERROR;
|
|
}
|
|
free(symbol.names[i]);
|
|
symbol.names[i] = NULL;
|
|
}
|
|
}
|
|
if (symbol.names != NULL) {
|
|
free(symbol.names);
|
|
symbol.names = NULL;
|
|
}
|
|
|
|
return check;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CHECK_HOOK
|
|
static inline void fill_jniRegisterNativeMethods(char v[]) {
|
|
// jniRegisterNativeMethods
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 23;
|
|
} else if (m == 29) {
|
|
m = 31;
|
|
}
|
|
|
|
v[0x0] = 'k';
|
|
v[0x1] = 'l';
|
|
v[0x2] = 'j';
|
|
v[0x3] = 'V';
|
|
v[0x4] = '`';
|
|
v[0x5] = 'a';
|
|
v[0x6] = 'n';
|
|
v[0x7] = '{';
|
|
v[0x8] = '}';
|
|
v[0x9] = 'o';
|
|
v[0xa] = 'y';
|
|
v[0xb] = 'B';
|
|
v[0xc] = 'l';
|
|
v[0xd] = 'z';
|
|
v[0xe] = 'f';
|
|
v[0xf] = 'f';
|
|
v[0x10] = 't';
|
|
v[0x11] = '_';
|
|
v[0x12] = 'v';
|
|
v[0x13] = '`';
|
|
v[0x14] = '}';
|
|
v[0x15] = 'y';
|
|
v[0x16] = 'd';
|
|
v[0x17] = 'r';
|
|
for (unsigned int i = 0; i < 0x18; ++i) {
|
|
v[i] ^= ((i + 0x18) % m);
|
|
}
|
|
v[0x18] = '\0';
|
|
}
|
|
|
|
static inline void fill___openat(char v[]) {
|
|
// __openat
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 7;
|
|
} else if (m == 11) {
|
|
m = 13;
|
|
}
|
|
|
|
v[0x0] = '^';
|
|
v[0x1] = ']';
|
|
v[0x2] = 'l';
|
|
v[0x3] = 't';
|
|
v[0x4] = '`';
|
|
v[0x5] = 'h';
|
|
v[0x6] = 'a';
|
|
v[0x7] = 'u';
|
|
for (unsigned int i = 0; i < 0x8; ++i) {
|
|
v[i] ^= ((i + 0x8) % m);
|
|
}
|
|
v[0x8] = '\0';
|
|
}
|
|
|
|
static inline void fill_openat(char v[]) {
|
|
// openat
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 5;
|
|
} else if (m == 7) {
|
|
m = 11;
|
|
}
|
|
|
|
v[0x0] = 'n';
|
|
v[0x1] = 'r';
|
|
v[0x2] = 'f';
|
|
v[0x3] = 'j';
|
|
v[0x4] = 'a';
|
|
v[0x5] = 'u';
|
|
for (unsigned int i = 0; i < 0x6; ++i) {
|
|
v[i] ^= ((i + 0x6) % m);
|
|
}
|
|
v[0x6] = '\0';
|
|
}
|
|
|
|
static inline void fill_open(char v[]) {
|
|
// open
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 3;
|
|
} else if (m == 5) {
|
|
m = 7;
|
|
}
|
|
|
|
v[0x0] = 'n';
|
|
v[0x1] = 'r';
|
|
v[0x2] = 'e';
|
|
v[0x3] = 'o';
|
|
for (unsigned int i = 0; i < 0x4; ++i) {
|
|
v[i] ^= ((i + 0x4) % m);
|
|
}
|
|
v[0x4] = '\0';
|
|
}
|
|
|
|
#endif
|
|
|
|
static inline void fill_sdk_d_genuine_d(char v[]) {
|
|
// sdk: %d, genuine: %d
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 19;
|
|
} else if (m == 23) {
|
|
m = 29;
|
|
}
|
|
|
|
v[0x0] = 'r';
|
|
v[0x1] = 'f';
|
|
v[0x2] = 'h';
|
|
v[0x3] = '>';
|
|
v[0x4] = '%';
|
|
v[0x5] = '#';
|
|
v[0x6] = 'c';
|
|
v[0x7] = '$';
|
|
v[0x8] = ')';
|
|
v[0x9] = 'm';
|
|
v[0xa] = 'n';
|
|
v[0xb] = 'b';
|
|
v[0xc] = 'x';
|
|
v[0xd] = 'g';
|
|
v[0xe] = 'a';
|
|
v[0xf] = 'u';
|
|
v[0x10] = '+';
|
|
v[0x11] = '2';
|
|
v[0x12] = '%';
|
|
v[0x13] = 'e';
|
|
for (unsigned int i = 0; i < 0x14; ++i) {
|
|
v[i] ^= ((i + 0x14) % m);
|
|
}
|
|
v[0x14] = '\0';
|
|
}
|
|
|
|
static inline void fill_add_sigcont(char v[]) {
|
|
// add sigcont handler
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 17;
|
|
} else if (m == 19) {
|
|
m = 23;
|
|
}
|
|
|
|
v[0x0] = 'c';
|
|
v[0x1] = 'g';
|
|
v[0x2] = '`';
|
|
v[0x3] = '%';
|
|
v[0x4] = 'u';
|
|
v[0x5] = 'n';
|
|
v[0x6] = 'o';
|
|
v[0x7] = 'j';
|
|
v[0x8] = 'e';
|
|
v[0x9] = 'e';
|
|
v[0xa] = 'x';
|
|
v[0xb] = '-';
|
|
v[0xc] = 'f';
|
|
v[0xd] = 'n';
|
|
v[0xe] = '~';
|
|
v[0xf] = 'd';
|
|
v[0x10] = 'm';
|
|
v[0x11] = 'g';
|
|
v[0x12] = 'q';
|
|
for (unsigned int i = 0; i < 0x13; ++i) {
|
|
v[i] ^= ((i + 0x13) % m);
|
|
}
|
|
v[0x13] = '\0';
|
|
}
|
|
|
|
static inline void fill_received_sigcont(char v[]) {
|
|
// received sigcont
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 13;
|
|
} else if (m == 17) {
|
|
m = 19;
|
|
}
|
|
|
|
v[0x0] = 'q';
|
|
v[0x1] = 'a';
|
|
v[0x2] = 'f';
|
|
v[0x3] = 'c';
|
|
v[0x4] = 'n';
|
|
v[0x5] = '~';
|
|
v[0x6] = 'l';
|
|
v[0x7] = 'n';
|
|
v[0x8] = '+';
|
|
v[0x9] = '\x7f';
|
|
v[0xa] = 'i';
|
|
v[0xb] = 'f';
|
|
v[0xc] = 'a';
|
|
v[0xd] = 'l';
|
|
v[0xe] = 'j';
|
|
v[0xf] = 'q';
|
|
for (unsigned int i = 0; i < 0x10; ++i) {
|
|
v[i] ^= ((i + 0x10) % m);
|
|
}
|
|
v[0x10] = '\0';
|
|
}
|
|
|
|
#if defined(CHECK_ARM64) && defined(__arm__)
|
|
static inline void fill_ro_product_cpu_abi(char v[]) {
|
|
// ro.product.cpu.abi
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 17;
|
|
} else if (m == 19) {
|
|
m = 23;
|
|
}
|
|
|
|
v[0x0] = 's';
|
|
v[0x1] = 'm';
|
|
v[0x2] = '-';
|
|
v[0x3] = 't';
|
|
v[0x4] = 'w';
|
|
v[0x5] = 'i';
|
|
v[0x6] = 'c';
|
|
v[0x7] = '}';
|
|
v[0x8] = 'j';
|
|
v[0x9] = '~';
|
|
v[0xa] = '%';
|
|
v[0xb] = 'o';
|
|
v[0xc] = '}';
|
|
v[0xd] = '{';
|
|
v[0xe] = '!';
|
|
v[0xf] = 'q';
|
|
v[0x10] = 'b';
|
|
v[0x11] = 'h';
|
|
for (unsigned int i = 0; i < 0x12; ++i) {
|
|
v[i] ^= ((i + 0x12) % m);
|
|
}
|
|
v[0x12] = '\0';
|
|
}
|
|
|
|
static inline bool isArm64V8a(const char *str) {
|
|
return str != NULL
|
|
&& *str == 'a'
|
|
&& *++str == 'r'
|
|
&& *++str == 'm'
|
|
&& *++str == '6'
|
|
&& *++str == '4'
|
|
&& *++str == '-'
|
|
&& *++str == 'v'
|
|
&& *++str == '8'
|
|
&& *++str == 'a';
|
|
}
|
|
|
|
static inline void fill_32_64(char v[]) {
|
|
// run in 32 on 64 machine
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 19;
|
|
} else if (m == 23) {
|
|
m = 29;
|
|
}
|
|
|
|
v[0x0] = 'v';
|
|
v[0x1] = 'p';
|
|
v[0x2] = 'h';
|
|
v[0x3] = '\'';
|
|
v[0x4] = 'a';
|
|
v[0x5] = 'g';
|
|
v[0x6] = '*';
|
|
v[0x7] = '8';
|
|
v[0x8] = '>';
|
|
v[0x9] = '-';
|
|
v[0xa] = 'a';
|
|
v[0xb] = 'a';
|
|
v[0xc] = '0';
|
|
v[0xd] = '\'';
|
|
v[0xe] = '&';
|
|
v[0xf] = ' ';
|
|
v[0x10] = 'l';
|
|
v[0x11] = 'c';
|
|
v[0x12] = '`';
|
|
v[0x13] = 'l';
|
|
v[0x14] = 'l';
|
|
v[0x15] = 'h';
|
|
v[0x16] = 'b';
|
|
for (unsigned int i = 0; i < 0x17; ++i) {
|
|
v[i] ^= ((i + 0x17) % m);
|
|
}
|
|
v[0x17] = '\0';
|
|
}
|
|
#endif
|
|
|
|
static void handler(int sig __unused) {
|
|
char v[0x11];
|
|
fill_received_sigcont(v);
|
|
LOGI(v);
|
|
}
|
|
|
|
#ifdef DEBUG_HOOK_IO
|
|
|
|
static void check_hook_function(void *handle, const char *name) {
|
|
void *symbol = dlsym(handle, name);
|
|
#ifdef DEBUG
|
|
void *symbol2 = plt_dlsym(name, NULL);
|
|
LOGI("symbol: %s, dlsym: %p, dl_iterate_phdr: %p", name, symbol, symbol2);
|
|
#endif
|
|
if (symbol != NULL && setRead(symbol) && isInlineHooked(symbol)) {
|
|
LOGI("%s is hooked", name);
|
|
}
|
|
}
|
|
|
|
#define HOOK_SYMBOL(x, y) check_hook_function(x, #y)
|
|
|
|
static void check_inline_hook_io() {
|
|
void *handle = dlopen("libc.so", RTLD_NOW);
|
|
if (handle) {
|
|
HOOK_SYMBOL(handle, faccessat);
|
|
HOOK_SYMBOL(handle, __openat);
|
|
HOOK_SYMBOL(handle, fchmodat);
|
|
HOOK_SYMBOL(handle, fchownat);
|
|
HOOK_SYMBOL(handle, renameat);
|
|
HOOK_SYMBOL(handle, fstatat64);
|
|
HOOK_SYMBOL(handle, __statfs);
|
|
HOOK_SYMBOL(handle, __statfs64);
|
|
HOOK_SYMBOL(handle, mkdirat);
|
|
HOOK_SYMBOL(handle, mknodat);
|
|
HOOK_SYMBOL(handle, truncate);
|
|
HOOK_SYMBOL(handle, linkat);
|
|
HOOK_SYMBOL(handle, readlinkat);
|
|
HOOK_SYMBOL(handle, unlinkat);
|
|
HOOK_SYMBOL(handle, symlinkat);
|
|
HOOK_SYMBOL(handle, utimensat);
|
|
HOOK_SYMBOL(handle, __getcwd);
|
|
HOOK_SYMBOL(handle, chdir);
|
|
HOOK_SYMBOL(handle, execve);
|
|
}
|
|
dlclose(handle);
|
|
}
|
|
|
|
#endif
|
|
|
|
static inline void fill_openat_is_hooked(char v[]) {
|
|
// openAt is hooked
|
|
static unsigned int m = 0;
|
|
|
|
if (m == 0) {
|
|
m = 13;
|
|
} else if (m == 17) {
|
|
m = 19;
|
|
}
|
|
|
|
v[0x0] = 'l';
|
|
v[0x1] = 't';
|
|
v[0x2] = '`';
|
|
v[0x3] = 'h';
|
|
v[0x4] = 'F';
|
|
v[0x5] = '|';
|
|
v[0x6] = ')';
|
|
v[0x7] = 'c';
|
|
v[0x8] = 'x';
|
|
v[0x9] = ',';
|
|
v[0xa] = 'h';
|
|
v[0xb] = 'n';
|
|
v[0xc] = 'm';
|
|
v[0xd] = 'h';
|
|
v[0xe] = 'a';
|
|
v[0xf] = 'a';
|
|
for (unsigned int i = 0; i < 0x10; ++i) {
|
|
v[i] ^= ((i + 0x10) % m);
|
|
}
|
|
v[0x10] = '\0';
|
|
}
|
|
|
|
bool has_native_libs() {
|
|
#if __ANDROID_API__ >= 24
|
|
return true;
|
|
#else
|
|
Symbol symbol;
|
|
char v[0x10];
|
|
fill_ba88(v);
|
|
memset(&symbol, 0, sizeof(Symbol));
|
|
symbol.check = (PLT_CHECK_PLT_APP | PLT_CHECK_NAME);
|
|
symbol.symbol_name = (char *) v;
|
|
if (dl_iterate_phdr_symbol(&symbol)) {
|
|
#ifdef DEBUG_NATIVE
|
|
LOGW("cannot dl_iterate_phdr_symbol");
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool extractNativeLibs = true;
|
|
for (int i = 0; i < symbol.size; ++i) {
|
|
if (symbol.names[i] != NULL) {
|
|
#ifdef DEBUG_NATIVE
|
|
LOGW("%s: %s", v, symbol.names[i]);
|
|
#endif
|
|
if (extractNativeLibs && strstr(symbol.names[i], "apk!") != NULL) {
|
|
extractNativeLibs = false;
|
|
}
|
|
free(symbol.names[i]);
|
|
symbol.names[i] = NULL;
|
|
}
|
|
}
|
|
if (symbol.names != NULL) {
|
|
free(symbol.names);
|
|
symbol.names = NULL;
|
|
}
|
|
|
|
#ifdef DEBUG_NATIVE
|
|
LOGW("has_native_libs: %s", extractNativeLibs ? "true" : "false");
|
|
#endif
|
|
return extractNativeLibs;
|
|
#endif
|
|
}
|
|
|
|
bool checkGenuine(JNIEnv *env) {
|
|
char v1[0x20];
|
|
|
|
signal(SIGCONT, handler);
|
|
fill_add_sigcont(v1);
|
|
LOGI(v1); // 0x14
|
|
|
|
sdk = getSdk();
|
|
|
|
if (sdk < 21) {
|
|
genuine = CHECK_FATAL;
|
|
goto done;
|
|
}
|
|
|
|
uid = getuid();
|
|
|
|
#ifdef DEBUG_HOOK_SELF
|
|
LOGI("+++ whale +++");
|
|
check_inline_hook_whale();
|
|
LOGI("--- whale ----");
|
|
#if defined(__arm__) || defined(__aarch64__)
|
|
LOGI("+++ hookzz-b +++");
|
|
check_inline_hook_hookzz_b();
|
|
LOGI("--- hookzz-b ---");
|
|
LOGI("+++ hookzz +++");
|
|
check_inline_hook_hookzz();
|
|
LOGI("--- hookzz ---");
|
|
#endif
|
|
#if defined(__arm__)
|
|
LOGI("+++ hookzz-b +++");
|
|
check_inline_hook_hookzz_b();
|
|
LOGI("--- hookzz-b ---");
|
|
LOGI("+++ substrate +++");
|
|
check_inline_hook_substrate();
|
|
LOGI("--- substrate ---");
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
LOGI("JNI_OnLoad start, sdk: %d, uid: %d", sdk, uid);
|
|
#endif
|
|
|
|
#ifdef DEBUG_HOOK_IO
|
|
check_inline_hook_io();
|
|
#endif
|
|
|
|
#ifdef DEBUG_MAPS
|
|
LOGI("openAt: %p", &openAt);
|
|
#endif
|
|
if (isInlineHooked(&openAt)) {
|
|
fill_openat_is_hooked(v1);
|
|
LOGE(v1);
|
|
genuine = CHECK_FATAL;
|
|
goto done;
|
|
}
|
|
|
|
char *packageName = getGenuinePackageName();
|
|
|
|
if (uid < 10000) {
|
|
goto clean;
|
|
}
|
|
|
|
#ifdef CHECK_MOUNT
|
|
checkMount(maps);
|
|
#endif
|
|
|
|
#ifndef NO_CHECK_MAPS
|
|
#ifdef DEBUG
|
|
LOGI("checkMaps start");
|
|
#endif
|
|
genuine = checkMaps(packageName);
|
|
#endif
|
|
|
|
#ifdef CHECK_HOOK
|
|
#define CHECK_HOOK_SYMBOL(x) do {\
|
|
if (genuine == CHECK_TRUE) {\
|
|
fill_##x(v1);\
|
|
if (isPltHooked(v1, true)) {\
|
|
genuine = CHECK_FALSE;\
|
|
}\
|
|
}\
|
|
} while(0);
|
|
CHECK_HOOK_SYMBOL(open);
|
|
CHECK_HOOK_SYMBOL(openat);
|
|
CHECK_HOOK_SYMBOL(__openat);
|
|
CHECK_HOOK_SYMBOL(jniRegisterNativeMethods);
|
|
#endif
|
|
|
|
#if defined(CHECK_ARM64) && defined(__arm__)
|
|
if (genuine == CHECK_TRUE) {
|
|
fill_ro_product_cpu_abi(v1);
|
|
__system_property_get(v1, prop);
|
|
if (isArm64V8a(prop)) {
|
|
fill_32_64(v1);
|
|
LOGW(v1);
|
|
genuine = CHECK_FALSE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
clean:
|
|
#ifdef GENUINE_NAME
|
|
free(packageName);
|
|
#endif
|
|
#ifdef DEBUG
|
|
LOGI("JNI_OnLoad end, genuine: %d", genuine);
|
|
#endif
|
|
|
|
if (genuine != CHECK_PROXY && isAmProxy(env, sdk)) {
|
|
genuine = CHECK_PROXY;
|
|
}
|
|
|
|
done:
|
|
fill_sdk_d_genuine_d(v1); // 0x15
|
|
LOGI(v1, sdk, genuine);
|
|
|
|
return setGenuine(env, genuine);
|
|
}
|