如下图所示,当别人在rom上改写了open.cpp函数,当发现打开/proc/cpuinfo文件时,会将其重定向到/system/ubin/cpuinfo 基我们自己定义的cpu ,同理内存/proc/memoryinfo,存储,也可以这样改写,比如某多多上的12G,512M的骁龙865,价格600多的平板,很可能就是这样改的。他会根据UID
if ((uid >= MINUID && uid <= MAXUID)) 来针对第三方的检测,当识别是第三方程序访问这些硬件变量时,就会重定向到一个指定的文件位置来实现模拟。
为了能检测出真实的设备,要在cpp文件中增加了svc的调用,相当于不通过libc的open函数打开/proc/cpuinfo,这样在libc中实现对openat的hook函数就无效了。见下面代码
这个函数更新时要运行一下ndk-build
app\src\main>ndk-build
如果增加了函数
要用\app\src\main>javah -d jni -classpath ./com.rom.cpptest
重新生成一下或者将鼠标放在新加的函数上,会有提示自动生成函数
#include <jni.h>
#include <string>
#include <fcntl.h>
#include "unistd.h"
#include <asm/unistd.h>
#include <android/log.h>
#define MAX_LINE 512
#define MAX_LENGTH 256
static const char *APPNAME = "MyReceiver";
#define LIBC "libc.so"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, APPNAME, __VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, APPNAME, __VA_ARGS__)
using namespace std;
#define __SYSCALL_LL_E(x) (x)
#define __SYSCALL_LL_O(x) (x)
#define __asm_syscall(...) do { \
__asm__ __volatile__ ( "svc 0" \
: "=r"(x0) : __VA_ARGS__ : "memory", "cc"); \
return x0; \
} while (0)
__attribute__((always_inline))
static inline long __syscall1(long n, long a)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0") = a;
__asm_syscall("r"(x8), "0"(x0));
}
__attribute__((always_inline))
static inline long __syscall3(long n, long a, long b, long c)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0") = a;
register long x1 __asm__("x1") = b;
register long x2 __asm__("x2") = c;
__asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2));
}
__attribute__((always_inline))
static inline long __syscall4(long n, long a, long b, long c, long d)
{
register long x8 __asm__("x8") = n;
register long x0 __asm__("x0") = a;
register long x1 __asm__("x1") = b;
register long x2 __asm__("x2") = c;
register long x3 __asm__("x3") = d;
__asm_syscall("r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3));
}
__attribute__((always_inline))
static inline int my_openat(int __dir_fd, const void* __path, int __flags, int __mode ){
return (int)__syscall4(__NR_openat, __dir_fd, (long)__path, __flags, __mode);
}
__attribute__((always_inline))
static inline ssize_t my_read(int __fd, void* __buf, size_t __count){
return __syscall3(__NR_read, __fd, (long)__buf, (long)__count);
}
__attribute__((always_inline))
static inline int my_close(int __fd){
return (int)__syscall1(__NR_close, __fd);
}
static inline int add_inline(int a,int b ){
return (int) a+b+1;
}
__attribute__((always_inline))
static inline bool isRooted_use_svc_open( ){
string a="/system";
string b="bin";
char infor[10];
sprintf(infor,"/%s",b.c_str());
string c="/su";
string e=a+infor+c ;
string d="/system/bin/su";
int fd = my_openat(AT_FDCWD,e.c_str() , O_RDONLY | O_CLOEXEC, 0);
if (fd > 0) {
LOGI("root detect ");
return true;
} else
{
LOGI("root not detect ");
return false;
}
}
__attribute__((always_inline))
static inline bool isRooted_use_libc_open( ){
string d="/system/bin/su";
int fd = open( d.c_str() , O_RDONLY | O_CLOEXEC );
if (fd > 0) {
LOGI("root detect in isRooted_use_libc_open");
return true;
} else
{
LOGI("root not detect ");
return false;
}
}
__attribute__((always_inline))
static inline string get_cpuinfor_svc( ){
string path="/proc/cpuinfo";
//libc 调用
// int fd = open( d.c_str() , O_RDONLY | O_CLOEXEC );
// svc 调用
long fd = my_openat(AT_FDCWD, path.c_str(), O_RDONLY | O_CLOEXEC, 0);
if (fd > 0) {
char buffer[8];
memset(buffer, 0, 8);
std::string str;
//int fd = open(path, O_RDONLY);
//失败 -1;成功:>0 读出的字节数 =0文件读完了
while (my_read(fd, buffer, 1) != 0) {
//LOGI("读取文件内容 %s" ,buffer);
str.append(buffer);
}
my_close(fd);
return str;
} else
{
LOGI("root not detect ");
return "null";
}
}
__attribute__((always_inline))
static string get_cpuinfor_libc( ){
string d="/proc/cpuinfo";
int fd = open( d.c_str() , O_RDONLY | O_CLOEXEC );
//int fd = my_openat(AT_FDCWD, d.c_str(), O_RDONLY | O_CLOEXEC, 0);
if (fd > 0) {
char buffer[1024];
memset(buffer, 0, 1024);
std::string str;
//int fd = open(path, O_RDONLY);
//失败 -1;成功:>0 读出的字节数 =0文件读完了
//while (my_read(fd, buffer, 1) != 0) {
while (read(fd, buffer, 1) != 0) {
LOGI("读取文件内容 %s" ,buffer);
str.append(buffer);
}
close(fd);
return str;
} else
{
LOGI("root not detect ");
return "null";
}
}
extern "C" JNIEXPORT jstring JNICALL
Java_com_rom_cpptest_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++ 你好中国";
int fd = my_openat(AT_FDCWD, "/system/bin/su", O_RDONLY | O_CLOEXEC, 0);
if (fd > 0) {
LOGI("root detect ");
} else
{
LOGI("root not detect ");
}
return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jint JNICALL
Java_com_rom_cpptest_MainActivity_add(JNIEnv *env, jobject thiz, jint a, jint b) {
if(isRooted_use_libc_open())
{
LOGI("add函数中检测到root,可以进行上报,进行追封");
}
return a+b;
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_rom_cpptest_MainActivity_detectRoot_1svc(JNIEnv *env, jobject thiz) {
return isRooted_use_svc_open();
}
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_rom_cpptest_MainActivity_detectRoot_1libC(JNIEnv *env, jobject thiz) {
// TODO: implement detectRoot_libC()
return isRooted_use_libc_open();
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_rom_cpptest_MainActivity_get_1cpuinfo_1svc(JNIEnv *env, jobject thiz) {
// TODO: implement get_cpuinfo()
return env->NewStringUTF(get_cpuinfor_svc().c_str());
}
extern "C"
JNIEXPORT jstring JNICALL
Java_com_rom_cpptest_MainActivity_get_1cpuinfo_1libc(JNIEnv *env, jobject thiz) {
// TODO: implement get_cpuinfo_libc()
return env->NewStringUTF(get_cpuinfor_libc().c_str());
}
编译后,用ida发现static inline string get_cpuinfor_svc( )的汇编代码如下
而 static string get_cpuinfor_libc( )的汇编代码如下
当我们只hooki libc 函数open2时,是无法拦截到get_cpuinfor_svc()的,所以要基于svc代码进行拦截处理。
代码如下
svc_call_demo: 演示使用svc 调用openat和 libc下的openat的区别用于检测硬件的篡改信息
参考了
Frida-syscall-interceptor_fenfei331的博客-CSDN博客一、目标现在很多App不讲武德了,为了防止 openat 、read、kill 等等底层函数被hook,干脆就直接通过syscall的方式来做系统调用,导致无法hook。应对这种情况有两种方案:刷机重写系统调用表来拦截内核调用inline Hook SWI/SVC指令我们今天采用第二种方法,用frida来实现内联汇编SWI/SVC做系统调用, syscallfrida inline hookhook syscallfrida ArmWriterfrida typescript prhttps://blog.csdn.net/fenfei331/article/details/117920733Android 系统调用实现函数功能--SVC指令的实现与检测_Rorschach:Blog-CSDN博客0x0 简述: arm android中通过一些反编译的工具分析ELF文件时,根据一些导入的系统函数可以很轻松的找到一些功能代码的实现:查看libc中分析这些函数的实现: arm中通过SVC指令实现的系统调用因此利用这一点应用中加入了类似的实现操作,隐蔽掉调用系统函数的符号,增加分析难度: 0x1 实现: 以getpid为例修改调用方式,获取pid原本通过系统API getpid获取,修https://blog.csdn.net/u011247544/article/details/76427571
时间关系没太深入研究
附上python调用代码和 js代码
import frida
import sys
import time
import io
#代码可以直接写入下面,但是可读性不好
jscode = """
Java.perform(function () {
});
"""
def printMessage(message,data):
if message['type'] == 'send':
print('[*] {0}'.format(message['payload']))
# file_object = open("e:\\log.txt", 'ab+')
# file_object.write(message['payload'].encode())
# file_object.write('\n'.encode())
# file_object.close()
else:
print(message)
device = frida.get_usb_device()
front_app = device.get_frontmost_application()
#下面要输入你应用的包名
pid = device.spawn(["com.rom.cpptest"])
device.resume(pid)
#这里必须要有个延迟不然获取不到front_app,时间跟据自己机型调整
time.sleep(18)
front_app = device.get_frontmost_application()
if front_app is None:
print("请运行要hook的应用")
exit(0)
print(front_app)
print(front_app.name)
process = device.attach(front_app.name)
#process = frida.get_usb_device().attach('cpptest')
#直接读入sotest.js,在pycharm中代码有颜色感知,易于编辑
with open('./_agent.js',encoding='utf-8') as f:
jscode = f.read()
script = process.create_script(jscode)
#script = process.create_script(jscode)
script.on('message',printMessage)
script.load()
sys.stdin.read()
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const logger_1 = require("./logger");
const frida_syscall_interceptor_1 = require("../../frida-syscall-interceptor");
const frida_syscall_interceptor_2 = require("../../frida-syscall-interceptor");
/*
const header = Memory.alloc(16);
header
.writeU32(0xdeadbeef).add(4)
.writeU32(0xd00ff00d).add(4)
.writeU64(uint64("0x1122334455667788"));
log(hexdump(header.readByteArray(16) as ArrayBuffer, { ansi: true }));
Process.getModuleByName("libSystem.B.dylib")
.enumerateExports()
.slice(0, 16)
.forEach((exp, index) => {
log(`export ${index}: ${exp.name}`);
});
Interceptor.attach(Module.getExportByName(null, "open"), {
onEnter(args) {
const path = args[0].readUtf8String();
log(`open() path="${path}"`);
}
});
*/
// Somewhere in your code.
//*
let baseAddr = Module.findBaseAddress('libnative-lib.so');
//指令的地址 这个地址会随着你自己编译的apk变化的,
// 如果hook一次后备份的地址会变化,要重新启动一下应用
// let address = baseAddr.add('0x81F8'); // 00 00 00 EF <= SVC 0
// hook openat /system/bin/su
let address1 = baseAddr.add('0xf1cc');
//hook openat /system/bin/su
logger_1.log("cpu "+Process.arch);
frida_syscall_interceptor_1.hookSyscall(address1, new NativeCallback(function (dirfd, pathname, mode, flags) {
let path = pathname.readCString();
logger_1.log(`Called openat hook` );
logger_1.log('- R0: ' + dirfd);
logger_1.log('- R1: ' + path);
logger_1.log('- R2: ' + mode);
logger_1.log('- R3: ' + flags);
return 0;
}, 'int', ['int', 'pointer', 'int', 'int']));
//如果出异常,重启动一下手机,一次只能hook一个函数
//__NR_read, __fd, (long)__buf, (long)__count
// let address2 = baseAddr.add('0x8520');
// let address2 = baseAddr.add('0xF588');
// frida_syscall_interceptor_2.hookSyscall(address2, new NativeCallback(function (dirfd, __buf, __count) {
// let infor = __buf.readCString();
// logger_1.log(`Called read hook` );
// logger_1.log('- R0: ' + dirfd);
// logger_1.log('- R1: ' + __buf +" string=> "+infor);
// logger_1.log('- R2: ' + __count);
// return 0;
// }, 'int', ['int', 'pointer', 'int']));
// frida -U -l _agent.js com.fenfei.syscalldemo
},{"../../frida-syscall-interceptor":4,"./logger":2}],2:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.log = void 0;
function log(message) {
console.log(message);
}
exports.log = log;
},{}],3:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class SyscallCallback {
constructor(frida, native) {
this.frida = frida;
this.native = native;
}
}
exports.SyscallCallback = SyscallCallback;
},{}],4:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const callback_1 = require("./callback");
let callbacks = [];
function hookSyscall(syscallAddress, callback) {
if (Process.arch == 'arm') {
const address = syscallAddress.sub(8);
const instructions = address.readByteArray(20);
if (instructions == null) {
throw new Error(`Unable to read instructions at address ${address}.`);
}
console.log(" ==== old instructions ==== " + address);
console.log(instructions);
Memory.patchCode(address, 20, function (code) {
let writer = null;
writer = new ArmWriter(code, { pc: address });
writer.putBranchAddress(createCallback(callback, instructions, address.add(20), syscallAddress));
writer.flush();
});
console.log(" ==== new instructions ==== " + address);
const instructionsNew = address.readByteArray(20);
console.log(instructionsNew);
}
else {
const address = syscallAddress.sub(12);
const instructions = address.readByteArray(12);
if (instructions == null) {
throw new Error(`Unable to read instructions at address ${address}.`);
}
console.log(" ==== old instructions ==== " + address);
console.log(instructions);
Memory.patchCode(address, 16, function (code) {
let writer = null;
writer = new Arm64Writer(code, { pc: address });
writer.putBranchAddress(createCallback(callback, instructions, address.add(16), syscallAddress));
writer.flush();
});
console.log(" ==== new instructions ==== " + address);
const instructionsNew = address.readByteArray(12);
console.log(instructionsNew);
}
}
exports.hookSyscall = hookSyscall;
function createCallback(callback, instructions, retAddress, syscallAddress) {
// Create custom instructions.
let frida = Memory.alloc(Process.pageSize);
Memory.patchCode(frida, Process.pageSize, function (code) {
let writer = null;
if (Process.arch == 'arm') {
writer = new ArmWriter(code, { pc: frida });
// Restore argument instructions.
writer.putBytes(instructions);
// FE 5F 2D E9 STMFD SP!, {R1-R12,LR} 寄存器入栈 不存 r0
// FF 5F 2D E9 STMFD SP!, {R0-R12,LR} 寄存器入栈
writer.putInstruction(0xE92D5FFF);
// 00 A0 0F E1 MRS R10, CPSR
// 00 04 2D E9 STMFD SP!, {R10} // 状态寄存器入栈
writer.putInstruction(0xE10FA000);
writer.putInstruction(0xE92D0400);
// instructions.size = 20 + 5条指令
writer.putLdrRegAddress("lr", frida.add(20 + 5 * 4));
writer.putBImm(callback);
// 00 04 BD E8 LDMFD SP!, {R10} // 状态寄存器出栈
// 0A F0 29 E1 MSR CPSR_cf, R10
writer.putInstruction(0xE8BD0400);
writer.putInstruction(0xE129F00A);
// FE 9F BD E8 LDMFD SP!, {R1-R12,PC} 寄存器出栈 不存 r0
// FF 5F BD E8 LDMFD SP!, {R0-R12,LR} 寄存器出栈
writer.putInstruction(0xE8BD5FFF);
}
else {
writer = new Arm64Writer(code, { pc: frida });
// Restore argument instructions.
writer.putBytes(instructions);
// Push all registers except x0.
writer.putPushRegReg('x15', 'x1');
writer.putPushRegReg('x2', 'x3');
writer.putPushRegReg('x4', 'x5');
writer.putPushRegReg('x6', 'x7');
writer.putPushRegReg('x8', 'x9');
writer.putPushRegReg('x10', 'x11');
writer.putPushRegReg('x12', 'x13');
writer.putPushRegReg('x14', 'x15');
writer.putPushRegReg('x16', 'x17');
writer.putPushRegReg('x18', 'x19');
writer.putPushRegReg('x20', 'x21');
writer.putPushRegReg('x22', 'x23');
writer.putPushRegReg('x24', 'x25');
writer.putPushRegReg('x26', 'x27');
writer.putPushRegReg('x28', 'x29');
writer.putInstruction(0xd53b420f); // 保存状态寄存器
writer.putPushRegReg('x30', 'x15');
// Call native.
writer.putLdrRegAddress('x16', callback);
writer.putBlrReg('x16');
// Pop all registers, except x0, so x0 from native call gets used.
writer.putPopRegReg('x30', 'x15');
writer.putInstruction(0xd51b420f); // 还原状态寄存器
writer.putPopRegReg('x28', 'x29');
writer.putPopRegReg('x26', 'x27');
writer.putPopRegReg('x24', 'x25');
writer.putPopRegReg('x22', 'x23');
writer.putPopRegReg('x20', 'x21');
writer.putPopRegReg('x18', 'x19');
writer.putPopRegReg('x16', 'x17');
writer.putPopRegReg('x14', 'x15');
writer.putPopRegReg('x12', 'x13');
writer.putPopRegReg('x10', 'x11');
writer.putPopRegReg('x8', 'x9');
writer.putPopRegReg('x6', 'x7');
writer.putPopRegReg('x4', 'x5');
writer.putPopRegReg('x2', 'x3');
writer.putPopRegReg('x15', 'x1');
}
// Call syscall.
// writer.putInstruction(0xd4000001);
writer.putBranchAddress(retAddress);
writer.flush();
});
console.log("==== frida ====");
console.log(frida);
console.log("==== retAddress ====");
console.log(retAddress);
// Store callback so it doesn't get garbage collected.
callbacks.push(new callback_1.SyscallCallback(frida, callback));
// Return pointer to the instructions.
return callbacks[callbacks.length - 1].frida;
}
},{"./callback":3}]},{},[1])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJhZ2VudC9pbmRleC50cyIsImFnZW50L2xvZ2dlci50cyIsIi4uL2ZyaWRhLXN5c2NhbGwtaW50ZXJjZXB0b3IvZGlzdC9jYWxsYmFjay5qcyIsIi4uL2ZyaWRhLXN5c2NhbGwtaW50ZXJjZXB0b3IvZGlzdC9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0FDQUEscUNBQStCO0FBQy9CLCtFQUE4RDtBQUc5RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBcUJFO0FBRUYsMEJBQTBCO0FBRTFCLEdBQUc7QUFDSCxJQUFJLFFBQVEsR0FBRyxNQUFNLENBQUMsZUFBZSxDQUFDLGtCQUFrQixDQUFFLENBQUM7QUFDM0QsSUFBSSxPQUFPLEdBQUcsUUFBUSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFHLDhCQUE4QjtBQUV0RSxZQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBRWxCLHVDQUFXLENBQUMsT0FBTyxFQUFFLElBQUksY0FBYyxDQUFDLFVBQVUsS0FBSyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsS0FBSztJQUMxRSxJQUFJLElBQUksR0FBRyxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUM7SUFFbEMsWUFBRyxDQUFDLG9CQUFvQixDQUFDLENBQUM7SUFDMUIsWUFBRyxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUMsQ0FBQztJQUN0QixZQUFHLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ3JCLFlBQUcsQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDckIsWUFBRyxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUMsQ0FBQztJQUV0QixPQUFPLENBQUMsQ0FBQztBQUNiLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7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QztZQUNuQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxNQUFNLENBQUMsY0FBYyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsVUFBVTtZQUM3QyxNQUFNLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuQyxlQUFlO1lBQ2YsTUFBTSxDQUFDLGdCQUFnQixDQUFDLEtBQUssRUFBRSxRQUFRLENBQUMsQ0FBQztZQUN6QyxNQUFNLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3hCLGtFQUFrRTtZQUNsRSxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsY0FBYyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsVUFBVTtZQUM3QyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNsQyxNQUFNLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNoQyxNQUFNLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNoQyxNQUFNLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNoQyxNQUFNLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNoQyxNQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQztTQUNwQztRQUNELGdCQUFnQjtRQUNoQixxQ0FBcUM7UUFDckMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3BDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNuQixDQUFDLENBQUMsQ0FBQztJQUNILE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUMvQixPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ25CLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUNwQyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3hCLHNEQUFzRDtJQUN0RCxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksVUFBVSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUNoRSxzQ0FBc0M7SUFDdEMsT0FBTyxTQUFTLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7QUFDakQsQ0FBQyIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIn0=
结果图
缺点是不能对每一个inline的svc进行拦截,一次只能拦截一个
另外SVC的一些补充,在arm v8架构下SVC调用一定是把调用函数方法存在了x8寄存器上了,如下,scv #0 对应上面的x8寄存器的mov 值就是svc的调用方法。如下图close()函数对应的就是
mov x8, __NR_close
如下所示如下图openat()函数对应的就是
mov x8, __NR_openat
所以我们找到svc 0,x8寄存器最后一次值就是SVC调用的函数名
如下图所示 #0x38对应的是56,
在unistd.h中找到56对应的值就是_NR_openat
下图中找到svc 0,x8寄存器最后一次值 为#0x3f
在unistd.h中找到0x3f=63对应的值就是_NR_read
这个要想自动解析出调用哪些值,实现起来还是要一定难度的。