本文为看雪论坛精华文章
看雪论坛作者ID:珍惜Any
一
前言
二
前奏知识
raw_syscall:
MOV R12, SP
STMFD SP!, {R4-R7}
MOV R7, R0
MOV R0, R1
MOV R1, R2
MOV R2, R3
LDMIA R12, {R3-R6}
SVC 0
LDMFD SP!, {R4-R7}
mov pc, lr
raw_syscall:
MOV X8, X0
MOV X0, X1
MOV X1, X2
MOV X2, X3
MOV X3, X4
MOV X4, X5
MOV X5, X6
SVC 0
RET
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <linux/seccomp.h>
#include <sys/prctl.h>
int main(int argc, char **argv)
{
int output = open(“output.txt”, O_WRONLY);
const char *val = “test”;
//通过prctl函数设置seccomp的模式为strict
printf(“Calling prctl() to set seccomp strict mode…\n”);
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
printf(“Writing to an already open file…\n”);
//尝试写入
write(output, val, strlen(val)+1);
printf(“Trying to open file for reading…\n”);
//设置完毕seccomp以后再次尝试open (因为设置了secomp的模式是strict,所以这行代码直接sign -9 信号)
int input = open(“output.txt”, O_RDONLY);
printf(“You will not see this message — the process will be killed first\n”);
}
BPF_LD, BPF_LDX加载指令
BPF_ST, BPF_STX存储指令
BPF_ALU, 计算指令
BPF_JMP, 跳转指令
BPF_RET, 返回指令 (结束指令)
BPF_MISC 其他指令
三
开发过程
/*
* 用fork出来的进程去attch主进程
*/
int trace_current_process(int sdkVersion) {
ALOGE("start trace_current_process ");
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
mainProcessPid = getpid();
pid_t child = fork();
if (child < 0) {
ALOGE("ptrace svc fork() error ");
return -errno;
}
//init first tracer
Tracer *first = get_tracer(nullptr, mainProcessPid, true);
if (child == 0) {
// attch main pid
int status = ptrace(PTRACE_ATTACH, mainProcessPid, NULL, NULL);
if (status != 0) {
//attch失败
ALOGE(">>>>>>>>> error: attach target process %d ", status);
return -errno;
}
first->wait_sigcont = true;
//开始执行死循环代码,因为处于一直监听状态,理论上该进程不会退出
exit(event_loop());
} else {
//init seccomp by main process
//the seccomp filtering rule is intended only for the current process
enable_syscall_filtering(first);
}
return 0;
}
while (true) {
int tracee_status;
Tracer *tracee;
int signal;
pid_t pid;
free_terminated_tracees();
//-1 all thread
pid = waitpid(-1, &tracee_status, 0);
if (pid < 0) {
ALOGE(">>>>>>>>>> !!!!! error: waitpid() %d %s", pid, strerror(errno))
if (errno != ECHILD) {
return EXIT_FAILURE;
}
break;
}
tracee = get_tracer(nullptr, pid, true);
assert(tracee != nullptr);
//handle action
signal = handle_tracee_event(tracee, tracee_status);
//restart
(void) restart_tracee(tracee, signal);
}
ALOGE("<<<<<<<<<<<< listening was error ,main listener stop !!")
return last_exit_status;
}
if (WIFEXITED(tracee_status)) {
//WEXITSTATUS取得子进程exit()返回的结束代码
last_exit_status = WEXITSTATUS(tracee_status);
//ALOGI("normal exit -> [%d] exit with status: %d ", tracee->pid, tracee_status);
//被跟踪者进程 正常执行结束,释放当前(被跟踪者)
terminate_tracee(tracee);
} else if (WIFSIGNALED(tracee_status)) {
int signNum = WTERMSIG(tracee_status);
//被跟踪进程因为信号退出
ALOGE("[%d] process exit with signal: 终止信号 = %d 异常原因 = %s ",
tracee->pid,
signNum,
strsignal(signNum)
)
terminate_tracee(tracee);
} else if (WIFSTOPPED(tracee_status)) {
signal = (tracee_status & 0xfff00) >> 8;
switch (signal) {
//svc
case SIGTRAP | 0x80:
//被调试线程调用svc,开始处理参数和返回值
...
#elif defined(ARCH_ARM_EABI)
static off_t reg_offset[] = {
[SYSARG_NUM] = USER_REGS_OFFSET(uregs[7]),
[SYSARG_1] = USER_REGS_OFFSET(uregs[0]),
[SYSARG_2] = USER_REGS_OFFSET(uregs[1]),
[SYSARG_3] = USER_REGS_OFFSET(uregs[2]),
[SYSARG_4] = USER_REGS_OFFSET(uregs[3]),
[SYSARG_5] = USER_REGS_OFFSET(uregs[4]),
[SYSARG_6] = USER_REGS_OFFSET(uregs[5]),
[SYSARG_RESULT] = USER_REGS_OFFSET(uregs[0]),
[FRAME_POINTER] = USER_REGS_OFFSET(uregs[12]),
[STACK_POINTER] = USER_REGS_OFFSET(uregs[13]),
[LINK_REGISTER] = USER_REGS_OFFSET(uregs[14]),
[INSTR_POINTER] = USER_REGS_OFFSET(uregs[15]),
[USERARG_1] = USER_REGS_OFFSET(uregs[0]),
};
#elif defined(ARCH_ARM64)
#undef USER_REGS_OFFSET
#define USER_REGS_OFFSET(reg_name) offsetof(struct user_regs_struct, reg_name)
static off_t reg_offset[] = {
[SYSARG_NUM] = USER_REGS_OFFSET(regs[8]),
[SYSARG_1] = USER_REGS_OFFSET(regs[0]),
[SYSARG_2] = USER_REGS_OFFSET(regs[1]),
[SYSARG_3] = USER_REGS_OFFSET(regs[2]),
[SYSARG_4] = USER_REGS_OFFSET(regs[3]),
[SYSARG_5] = USER_REGS_OFFSET(regs[4]),
[SYSARG_6] = USER_REGS_OFFSET(regs[5]),
[SYSARG_RESULT] = USER_REGS_OFFSET(regs[0]),
//https://zhuanlan.zhihu.com/p/42486116
//http://blog.chinaunix.net/uid-25564582-id-5852920.html
[FRAME_POINTER] = USER_REGS_OFFSET(regs[29]),
//64位30是LR寄存器
[LINK_REGISTER] = USER_REGS_OFFSET(regs[30]),
[STACK_POINTER] = USER_REGS_OFFSET(sp),
[INSTR_POINTER] = USER_REGS_OFFSET(pc),
[USERARG_1] = USER_REGS_OFFSET(regs[0]),
};
/**
* Return the *cached* value of the given @Tracers' @reg.
* 返回给定@Tracers@reg的缓存值
*/
word_t peek_reg(const Tracer *Tracer, RegVersion version, Reg reg) {
word_t result;
assert(version < NB_REG_VERSION);
result = REG(Tracer, version, reg);
/* Use only the 32 least significant bits (LSB) when running
* 32-bit processes on a 64-bit kernel. */
if (is_32on64_mode(Tracer))
result &= 0xFFFFFFFF;
return result;
}
/**
* Set the *cached* value of the given @Tracers' @reg.
*
* 修改寄存器的内容方法,value标识的是指针
*/
void poke_reg(Tracer *Tracer, Reg reg, word_t value) {
//设置之前先判断是否相等
if (peek_reg(Tracer, CURRENT, reg) == value)
//相等直接返回
return;
REG(Tracer, CURRENT, reg) = value;
//标识他已经被修改
Tracer->_regs_were_changed = true;
}
regs.iov_base = ¤t_sysnum;
regs.iov_len = sizeof(current_sysnum);
status = ptrace(PTRACE_SETREGSET, Tracer->pid, NT_ARM_SYSTEM_CALL, ®s);
if (status < 0) {
//note(Tracer, WARNING, SYSTEM, "can't set the syscall number");
return status;
}
一个打印Syscall调用方法的插件,可以很清楚的打印全部的系统调用,比如文件相关类型函数 网络相关类型的函数,等...他同样也可以用在安卓上面, 具体使用方式,国内资料比较多,可以去看一下。
const unsigned long default_ptrace_options = (
PTRACE_O_TRACESYSGOOD|
PTRACE_O_TRACEFORK |
PTRACE_O_TRACEVFORK |
PTRACE_O_TRACEVFORKDONE |
PTRACE_O_TRACEEXEC |
PTRACE_O_TRACECLONE |
PTRACE_O_TRACEEXIT);
//尝试开启ptrace+seccomp
status = ptrace(PTRACE_SETOPTIONS, tracee->pid, NULL,default_ptrace_options | PTRACE_O_TRACESECCOMP);
case SIGTRAP | PTRACE_EVENT_SECCOMP << 8:
void NetlinkMacHandler::netlinkHandler_recv(Tracer *tracee) {
ssize_t bytes_read = TEMP_FAILURE_RETRY(peek_reg(tracee, CURRENT, SYSARG_RESULT));
if (bytes_read > 0) {
word_t buff = peek_reg(tracee, CURRENT, SYSARG_2);
//buff长度
auto size = (size_t) peek_reg(tracee, CURRENT, SYSARG_3);
char tempBuff[size];
int readStr_ret = read_data(tracee, tempBuff, buff, size);
if (readStr_ret != 0) {
LOGE("svc netlink handler read_string error %s", strerror(errno))
return;
}
auto *hdr = reinterpret_cast<nlmsghdr *>(tempBuff);
//netlink数据包结构体
NetlinkMacHandler::handler_mac_callback_svc(tracee,hdr, bytes_read);
//将数据写入覆盖掉原来的数据
write_data(tracee, buff, tempBuff, size);
}
}
poke_reg(tracee, STACK_POINTER, peek_reg(tracee, ORIGINAL, STACK_POINTER));
四
注入方式
五
使用场景
2022-06-04 15:31:06.910 13927-13960/ I/Zhenxi: io sandbox /vendor/lib64/hw/ -> /vendor/lib64/hw/
2022-06-04 15:31:06.910 13951-13951/? I/Zhenxi: io sandbox /vendor/lib64/hw/ -> /vendor/lib64/hw/
2022-06-04 15:31:06.910 13927-13960/ I/Zhenxi: io sandbox /vendor/lib64/hw/[email protected]4.0-impl-qti-display.so -> /vendor/lib64/hw/[email protected]4.0-impl-qti-display.so
2022-06-04 15:31:06.910 13927-13960/ I/Zhenxi: io sandbox /vendor/lib64/hw/[email protected]4.0-impl-qti-display.so -> /vendor/lib64/hw/[email protected]4.0-impl-qti-display.so
2022-06-04 15:31:06.911 13951-13951/? I/Zhenxi: io sandbox /vendor/lib64/hw/[email protected]4.0-impl-qti-display.so -> /vendor/lib64/hw/[email protected]4.0-impl-qti-display.so
2022-06-04 15:31:06.911 13951-13951/? I/Zhenxi: io sandbox /proc/self/fd/109 -> /proc/self/fd/109
2022-06-04 15:31:06.911 13927-13960/ I/Zhenxi: io sandbox /proc/self/maps -> /proc/self/maps
2022-06-04 15:31:06.911 13951-13951/? I/Zhenxi: io sandbox /data/user/0/ /app_virtual_devices/START_UP_0/data/nativeCache/dev_maps_13951_13951 -> /data/user/0/ /app_virtual_devices/START_UP_0/data/nativeCache/dev_maps_13951_13951
2022-06-04 15:31:06.916 13927-13960/ I/Zhenxi: io sandbox libadreno_utils.so -> libadreno_utils.so
2022-06-04 15:31:06.916 13927-13960/ I/Zhenxi: io sandbox /proc/self/maps -> /proc/self/maps
2022-06-04 15:31:06.916 13951-13951/? I/Zhenxi: io sandbox /data/user/0/ /app_virtual_devices/START_UP_0/data/nativeCache/dev_maps_13951_13951 -> /data/user/0/ /app_virtual_devices/START_UP_0/data/nativeCache/dev_maps_13951_13951
2022-06-04 15:31:06.930 13927-13960/ I/Zhenxi: io sandbox /data/user_de/0/ /code_cache/com.android.opengl.shaders_cache -> /data/user/0/ /app_virtual_devices/START_UP_0/user_de/code_cache/com.android.opengl.shaders_cache
2022-06-04 15:31:06.930 13951-13951/? I/Zhenxi: io sandbox /data/user/0/ /app_virtual_devices/START_UP_0/user_de/code_cache/com.android.opengl.shaders_cache -> /data/user/0/ /app_virtual_devices/START_UP_0/user_de/code_cache/com.android.opengl.shaders_cache
2022-06-04 15:31:06.961 13927-13960/ I/Zhenxi: io sandbox libboost.so -> libboost.so
2022-06-04 15:31:06.962 13927-13960/ I/Zhenxi: io sandbox /system/lib64/libboost.so -> /system/lib64/libboost.so
2022-06-04 15:31:06.962 13951-13951/? I/Zhenxi: io sandbox /system/lib64/libboost.so -> /system/lib64/libboost.so
2022-06-04 15:31:06.962 13951-13951/? I/Zhenxi: io sandbox /proc/self/fd/110 -> /proc/self/fd/110
2022-06-04 15:31:06.962 13927-13960/ I/Zhenxi: io sandbox /proc/self/maps -> /proc/self/maps
2022-06-04 15:31:06.962 13951-13951/? I/Zhenxi: io sandbox /data/user/0/ /app_virtual_devices/START_UP_0/data/nativeCache/dev_maps_13951_13951 -> /data/user/0/ /app_virtual_devices/START_UP_0/data/nativeCache/dev_maps_13951_13951
2022-06-04 15:31:06.967 13927-13960/ I/Zhenxi: io sandbox /proc/13927/cmdline -> /proc/13927/cmdline
2022-06-04 15:31:06.967 13951-13951/? I/Zhenxi: io sandbox /proc/13927/cmdline -> /proc/13927/cmdline
2022-06-04 15:31:06.967 13927-13960/ I/Zhenxi: io sandbox /data/system/migt/migt -> /data/system/migt/migt
2022-06-04 15:31:06.967 13951-13951/? I/Zhenxi: io sandbox /data/system/migt/migt -> /data/system/migt/migt
... ...
else if (strstr(result, "magisk")) {
//直接包含magisk的都给干掉
result = NULL;
} else if (strstr(result, "edxposed")) {
result = NULL;
} else if (strstr(result, "edxp")) {
result = NULL;
}else if (strstr(result, "lsposed")) {
result = NULL;
} else if (strstr(result, "libriru") || strstr(result, "/riru")) {
result = NULL;
} else if (strstr(result, "sandhook")) {
result = NULL;
} else if (endsWith(result, "/su")) {
//su结尾的root文件都直接干掉
result = NULL;
}else if (strstr(result, "zygisk")) {
result = NULL;
}else if (strstr(result, "/data/adb/")) {
//这个文件里面包含很多magisk相关的,比如模块的list /data/adb/modules/
//https://github.com/LSPosed/NativeDetector/blob/master/app/src/main/jni/activity.cpp
result = NULL;
}
HOOK_JNI(env, CallObjectMethodV)
HOOK_JNI(env, CallBooleanMethodV)
HOOK_JNI(env, CallByteMethodV)
HOOK_JNI(env, CallCharMethodV)
HOOK_JNI(env, CallShortMethodV)
HOOK_JNI(env, CallIntMethodV)
HOOK_JNI(env, CallLongMethodV)
HOOK_JNI(env, CallFloatMethodV)
HOOK_JNI(env, CallDoubleMethodV)
HOOK_JNI(env, CallVoidMethodV)
HOOK_JNI(env, CallStaticObjectMethodV)
HOOK_JNI(env, CallStaticBooleanMethodV)
HOOK_JNI(env, CallStaticByteMethodV)
HOOK_JNI(env, CallStaticCharMethodV)
HOOK_JNI(env, CallStaticShortMethodV)
HOOK_JNI(env, CallStaticIntMethodV)
HOOK_JNI(env, CallStaticLongMethodV)
HOOK_JNI(env, CallStaticFloatMethodV)
HOOK_JNI(env, CallStaticDoubleMethodV)
HOOK_JNI(env, CallStaticVoidMethodV)
HOOK_JNI(env, GetObjectField)
HOOK_JNI(env, GetBooleanField)
HOOK_JNI(env, GetByteField)
HOOK_JNI(env, GetCharField)
HOOK_JNI(env, GetShortField)
HOOK_JNI(env, GetIntField)
HOOK_JNI(env, GetLongField)
HOOK_JNI(env, GetFloatField)
HOOK_JNI(env, GetDoubleField)
HOOK_JNI(env, GetStaticObjectField)
HOOK_JNI(env, GetStaticBooleanField)
HOOK_JNI(env, GetStaticByteField)
HOOK_JNI(env, GetStaticCharField)
HOOK_JNI(env, GetStaticShortField)
HOOK_JNI(env, GetStaticIntField)
HOOK_JNI(env, GetStaticLongField)
HOOK_JNI(env, GetStaticFloatField)
HOOK_JNI(env, GetStaticDoubleField)
//常用的字符串操作函数
HOOK_JNI(env, NewStringUTF)
HOOK_JNI(env, GetStringUTFChars)
//HOOK_JNI(env, FindClass)
HOOK_JNI(env, ToReflectedMethod)
HOOK_JNI(env, FromReflectedMethod)
HOOK_JNI(env, GetFieldID)
HOOK_JNI(env, GetStaticFieldID)
HOOK_JNI(env, NewObjectV)
HOOK_SYMBOL_DOBBY(handle, strstr);
HOOK_SYMBOL_DOBBY(handle, strcmp);
HOOK_SYMBOL_DOBBY(handle, strcpy);
HOOK_SYMBOL_DOBBY(handle, strdup);
HOOK_SYMBOL_DOBBY(handle, strxfrm);
// HOOK_SYMBOL_DOBBY(handle, memcpy);
// HOOK_SYMBOL_DOBBY(handle, sprintf);
// HOOK_SYMBOL_DOBBY(handle, printf);
// HOOK_SYMBOL_DOBBY(handle, snprintf);
// HOOK_SYMBOL_DOBBY(handle, vsnprintf);
看雪ID:珍惜Any
https://bbs.pediy.com/user-home-819934.htm
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!