推荐文章:https://bbs.pediy.com/thread-255212.htm
包名检测
- 对策就是搜索包名
检测/proc/mypid/maps
char line[512];
FILE* fp;
fp = fopen("/proc/self/maps", "r");
if (fp) {
while (fgets(line, 512, fp)) {
if (strstr(line, "frida")) {
/* Evil library is loaded. Do something… */
}
}
fclose(fp);
} else {
/* Error opening /proc/self/maps. If this happens, something is off. */
}
}
每当一个进程创建的时候,/proc目录下就会有和该进程id对应的目录产生.
目录名称就是进程id.里面记录该进程的各种信息.其中maps记录了进程的内存信息
//检测xposed substrate
public static int checkMap() throws Throwable {
UnsupportedEncodingException unsupportedEncodingException;
BufferedReader bufferedReader;
Throwable th;
int i = 0;
BufferedReader bufferedReader2;
int i2;
int result = 0;
try {
HashSet hashSet = new HashSet();
bufferedReader2 = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/" + android.os.Process.myPid() + "/maps"), "utf-8"));
while (true) {
try {
String readLine = bufferedReader2.readLine();
if (readLine == null) {
break;
} else if (readLine.endsWith(".so") || readLine.endsWith(".jar")) {
hashSet.add(readLine.substring(readLine.lastIndexOf(" ") + 1));
}
} catch (UnsupportedEncodingException e) {
unsupportedEncodingException = e;
i2 = 0;
bufferedReader = bufferedReader2;
try {
unsupportedEncodingException.printStackTrace();
if (bufferedReader != null) {
}
} catch (Throwable th2) {
th = th2;
bufferedReader2 = bufferedReader;
if (bufferedReader2 != null) {
}
throw th;
}
}
}
Iterator it = hashSet.iterator();
while (it.hasNext()) {
int i3;
Object next = it.next();
if (((String) next).toLowerCase().contains("xposed")) {
result = result | 64;
}
if (((String) next).toLowerCase().contains("com.saurik.substrate")) {
result = result | 128;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
- 对策
int copy_file(char *src_path, char *dst_path) {
if (src_path && dst_path) {
int in, out;
ssize_t size; // TLS变量,减少堆栈占用
// static __thread char buffer[512]; // 内置函数(nested function),用于函数返回时关闭in,out文件句柄
in = old_open(src_path, O_RDONLY, 0, 0, 0);
if (-1 == in) {
return do_return(-1, in, out);
}
//S_IRUSR(S_IREAD) 文件拥有者具备读权限
//S_IWUSR(S_IWRITE) 文件拥有者具备写权限
//S_IRGRP 用户组具备读权限
//S_IWGRP 用户组具备写权限
//S_IXGRP
// 用户组具备可执行权限
//S_IROTH 其他用户具备读权限
// 创建目标文件,并指定合适的权限
const __mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
// out = old_open(dst_path, mode,0,0,0);
out = creat(dst_path, mode);
if (-1 == out) {
return do_return(-1, in, out);
}
while (1) {
std::string line;
char buf;
while ((size = read(in, &buf, 1) > 0)) {
if (buf == '\n') {
line.push_back(buf);
LogD("%s line.length=%d line=%s",__FUNCTION__,line.length(),line.c_str());
break;
}
line.push_back(buf);
}
if (size <= 0) {
break;
}
line = replace_all(line,"com.iplay.assistant","");
if (line.find("app_gameassist/builtin/") == -1) {
LogD("%s line.length=%d line=%s",__FUNCTION__,line.length(),line.c_str());
if (-1 == write(out, line.c_str(), line.length())) {
return do_return(-1, in, out);
}
}
line.clear();
}
{ // 如果目标文件权限与所要求的权限不同则修改文件权限
struct stat s_buf;
stat(dst_path, &s_buf);
if (mode != (s_buf.st_mode & mode)) {
if (-1 == chmod(dst_path, mode)) {
return do_return(-1, in, out);
}
}
}
return do_return(0, in, out);
}
return -1;
}
int (*old_open)(char *path, int mode, char *a3, char *a4, char *a5)=NULL;
int alt_open(char *path, int mode, char *a3, char *a4, char *a5) {
LogD("%s path%s", __FUNCTION__, path);
if(old_strstr(path,"com.iplay.assistant")){
return NULL;
}
if (strstr(path, "/maps") && strstr(path, "/proc/")) {
char myPath[512];
sprintf(myPath, "/%s/%d/%s", "proc", getpid(), "maps");
if (strstr(path, myPath) == NULL || strstr(path, "/proc/self/maps")) {
char *relPath = "sdcard/DCIM/maps";
copy_file(path, relPath);
int ret = old_open(relPath, mode, a3, a4, a5);
LogD("%s ret=%d %s -> %s", __FUNCTION__, ret, path, relPath);
return ret;
} else {
return -1;
}
}
return open(path, mode, a3, a4, a5);
}
char* (*old_strstr)(char* a1,char* a2) = NULL;
char* my_strstr(char* a1,char* a2) {
if(old_strstr(a2,"com.iplay.assistant")||old_strstr(a2,"center")){
LogD("%s a1=%s a2=%s", __FUNCTION__, a1,a2);
return NULL;
}
char* ret = old_strstr(a1,a2);
return ret;
}
int (*old_strncmp)(char* a1,char* a2,int length,int a4,int a5,int a6) = NULL;
int alt_strncmp(char* a1,char* a2,int length,int a4,int a5,int a6) {
if(strstr(a2,"racerPid")){
sleep(1000000);
}
if(strstr(a2,"iplay.assistant")||old_strstr(a2,"center")){
LogD("%s a1=%s a2=%s", __FUNCTION__, a1,a2);
char* dummy = "GameFuck: third party call";
return old_strncmp(a1,dummy,length,a4,a5,a6);
}
int ret = old_strncmp(a1,a2,length,a4,a5,a6);
return ret;
}
void setMemoryArt(int myfind){
if(myfind) {
size_t pagesize = sysconf(_SC_PAGESIZE);
// Calculate start and end addresses for the write.
uintptr_t start = (uintptr_t) myfind ;
uintptr_t end = start + 1024;
// Calculate start of page for mprotect.
uintptr_t pagestart = start & -pagesize;
int memorySize = end - pagestart;
mprotect((void *) pagestart, end - pagestart,PROT_WRITE | PROT_READ | PROT_EXEC);
}
}
void gotTableHook(void *got_addr,void *replace, void **result){
setMemoryArt((int)(got_addr));
*result = *(void **)got_addr;
*(void **)got_addr = replace;
}
inlineHookAddress((void *) open, (void *) alt_open, (void **) &old_open);
|| inlineHookAddress(dlsym(handle,"open"), (void *) alt_open, (void **) &old_open);
|| inlineHookAddress((void*)(info->base+0x1B0C + 1), (void *) alt_fopen, (void **) &old_fopen);
|| gotTableHook((void *)(info->base + 0x1F0CD4), (void*)alt_strncmp, (void**)&old_strncmp);
|| gotTableHook((void*)strstr,(void*)my_strstr,(void**)&old_strstr);
|| gotTableHook((void *)(info->base + 0x1F0D28), (void*)alt_open, (void**)&old_open);
检测堆栈信息
public static int checkStackTraceElement() {
int i = 0;
try {
throw new Exception("detect hook");
} catch (Exception e) {
int i2 = 0;
for (StackTraceElement stackTraceElement : e.getStackTrace()) {
if (stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge") && stackTraceElement.getMethodName().equals("main")) {
i2 |= 4;
}
if (stackTraceElement.getClassName().equals("de.robv.android.xposed.XposedBridge") && stackTraceElement.getMethodName().equals("handleHookedMethod")) {
i2 |= 8;
}
if (stackTraceElement.getClassName().equals("com.saurik.substrate.MS$2") && stackTraceElement.getMethodName().equals("invoked")) {
i2 |= 16;
}
if (stackTraceElement.getClassName().equals("com.android.internal.os.ZygoteInit")) {
i++;
if (i == 2) {
i2 |= 32;
}
}
}
return i2;
}
}
模拟器检测
public static String getVMDesc()
{
StringBuilder stringBuilder = new StringBuilder();
String VM = AdbShell.getprop("ro.genymotion.version");//判断genymotion模拟器
if (VM != null) {
stringBuilder.append("ro.genymotion.version");
stringBuilder.append("|");
stringBuilder.append(VM);
stringBuilder.append("\n");
}
VM = AdbShell.getprop("androVM.vbox_dpi");//判断使用了vbox的模拟器,目前很多市面上的安卓模拟器都是基于vbox的
if (VM != null) {
stringBuilder.append("androVM.vbox_dpi");
stringBuilder.append("|");
stringBuilder.append(VM);
stringBuilder.append("\n");
}
VM = AdbShell.getprop("qemu.sf.fake_camera");//检测安卓自身的模拟器
if (VM != null) {
stringBuilder.append("qemu.sf.fake_camera");
stringBuilder.append("|");
stringBuilder.append(VM);
}
return stringBuilder.toString();
}
模拟器都具有一些特殊的属性.查找这个特殊的属性就可以判断是否是模拟器.
其中AdbShell.getprop 等效于 Systemproperties.get(name).
Debug检测
//检测是否拥有调试属性
public static String HaveDebugProp()
{
//ro.debuggable表示调试权限,默认为0,1表示可以调试
StringBuilder builder = new StringBuilder();
builder.append("ro.debuggable");
builder.append(AdbShell.getprop("ro.debuggable"));
return builder.toString();
}
//如果进程被调试TracerPid不为0
public static String getTracerPid()
{
BufferedReader bufferedReader;
String readLine = "";
try {
bufferedReader = new BufferedReader(new FileReader("/proc/self/status"));
do{
readLine = bufferedReader.readLine();
if (readLine == null) {
break;
}
}while (!readLine.startsWith("TracerPid:"));
readLine = readLine.substring(10).trim();
} catch (Exception e) {
e.printStackTrace();
}
return readLine;
}
Root 检测
private static final String[] suFiles = new String[]{"/su", "/su/bin/su", "/sbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/data/local/su", "/system/xbin/su", "/system/bin/su", "/system/sd/xbin/su", "/system/bin/failsafe/su", "/system/bin/cufsdosck", "/system/xbin/cufsdosck", "/system/bin/cufsmgr", "/system/xbin/cufsmgr", "/system/bin/cufaevdd", "/system/xbin/cufaevdd", "/system/bin/conbb", "/system/xbin/conbb"};
public static boolean haveSu()
{
boolean z = false;
boolean z2 = false;
for (String file : suFiles) {
if (new File(file).exists()) {
z = true;
break;
}
}
if (Build.TAGS == null || !Build.TAGS.contains("test-keys")) {
z2 = false;
} else {
z2 = true;
}
return z2 || z;
}
public static String RootCheckProp()
{
//ro.secure表示root权限,如果为0则表示启用root权限,1则相反
//这个只能检测ROM被刷入时的默认属性.
StringBuilder builder = new StringBuilder();
builder.append("ro.secure:");
builder.append(AdbShell.getprop("ro.secure"));
builder.append("\n");
builder.append("ro.adb.secure:");
builder.append(AdbShell.getprop("ro.adb.secure"));
builder.append("\n");
return builder.toString();
}
DexFile文件检测
根据ClassLoad检测加载了那些Dex文件
//查询所有加载的dex,jar,apk文件,看一下是否有其他异己的模块加载
public static void allDex()
{
Object pathList = getDeclaredFieldValue(DexFileCheck.class.getClassLoader(),"pathList");
Object [] dexElements = (Object [])getDeclaredFieldValue(pathList,"dexElements");
for(Object dex:dexElements)
{
DexFile dexFile = (DexFile)getDeclaredFieldValue(dex,"dexFile");
if(dexFile == null)continue;
Log.d(TAG, "allDex: found dexfile "+ dexFile.getName());
}
}
网友评论