最近想在沙箱中使用frida的hook能力,有三个方案:
1 集成frida-server到系统
2 内置frida-gadget.so,然后将其加载到应用中
3 集成gumjs引擎
考虑到使用的体验性,最终打算用第三种方案
一、编译gumjs
1.1 先去frida官网下载gumjs的头文件和静态库
1.2 创建工程,导入gumjs.a和头文件
编译成动态库
二、创建Hook管理类
/frameworks/base/core/java/android/app/HookUtils.java
package android.app;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
import android.util.Log;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import dalvik.system.DexClassLoader;
import org.json.JSONObject;
import org.json.JSONArray;
public class HookUtils {
public static final String TAG = "HookUtils";
public static HookJs hookjs;
public static class HookJs{
public boolean open = false;
public String[] packageName;
public String arm32SoPath;
public String arm64SoPath;
public HookJs(JSONObject js){
try{
open = js.getBoolean("open");
JSONArray names = js.getJSONArray("packageName");
if (names != null){
packageName = new String[names.length()];
for (int i = 0; i < names.length(); i++){
packageName[i] = names.getString(i);
}
}
arm32SoPath = js.getString("ArmSoPath");
arm64SoPath = js.getString("Arm64SoPath");
} catch(Exception e){
Log.e(TAG, "HookJs:" + e.toString());
}
}
}
public static void getConfig() {
try{
String conf = readConfig();
//Log.i(TAG, "getConfig -> " + conf);
JSONObject arr = new JSONObject(conf);
hookjs = new HookJs(arr.getJSONObject("hookJs"));
Log.i(TAG, String.valueOf(hookjs.open));
if (hookjs.packageName != null){
for (int i = 0; i < hookjs.packageName.length; i++){
Log.i(TAG, hookjs.packageName[i]);
}
}
Log.i(TAG, hookjs.arm32SoPath.toString());
Log.i(TAG, hookjs.arm64SoPath.toString());
} catch (Exception e){
Log.e(TAG, "getConfig error:" + e.toString());
}
}
public static String readConfig(){
try {
return readFileAll("/data/local/tmp/config.js");
}catch (Exception e) {
Log.e(TAG, e.toString());
}
return null;
}
public static String readFileAll(String path) {
File file = new File(path);
StringBuilder sb=new StringBuilder();
if (file != null && file.exists()) {
InputStream inputStream = null;
BufferedReader bufferedReader = null;
try {
inputStream = new FileInputStream(file);
bufferedReader = new BufferedReader(new InputStreamReader(
inputStream));
String outData;
while((outData=bufferedReader.readLine())!=null){
sb.append(outData+"\n");
}
} catch (Throwable t) {
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (Exception e) {
Log.e(TAG, "readFileAll" + e.toString());
}
try {
if (inputStream != null) {
inputStream.close();
}
} catch (Exception e) {
Log.e(TAG, "readFileAll" + e.toString());
}
}
}
return sb.toString();
}
public static boolean checkHookJs(String processName){
try{
if (processName != null){
if (hookjs != null){
if (hookjs.open){
if (hookjs.packageName != null){
for (String s:hookjs.packageName){
if (processName.contains(s)){
//Log.i(TAG, "hook -> " + String.valueOf(processName));
return true;
}
}
}else{
return true;
}
}
}
}
}catch (Exception e){
Log.e(TAG, "checkHookJs:" + e.toString());
}
return false;
}
public static void moveSoToData(String dstFileName){
String srcFileName;
if(System.getProperty("os.arch").indexOf("64") >= 0) {
srcFileName = hookjs.arm64SoPath;
}else{
srcFileName = hookjs.arm32SoPath;
}
deleteDataFile(dstFileName);
InputStream in = null;
OutputStream out = null;
try {
in = new FileInputStream(srcFileName);
out = new FileOutputStream(dstFileName);
byte[] bytes = new byte[1024];
int i;
while ((i = in.read(bytes)) != -1)
out.write(bytes, 0, i);
} catch (IOException e) {
Log.e(TAG, e.toString());
} finally {
try {
if (in != null)
in.close();
if (out != null){
out.flush();
out.close();
}
} catch (IOException e) {
Log.e(TAG, e.toString());
}
setPermission(dstFileName);
}
}
public static void deleteDataFile(String fileName){
try {
File file = new File(fileName);
if (file.exists()){
file.delete();
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
public static void setPermission(String path){
try{
File file = new File(path);
if (file.exists()){
int perm = FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO;
FileUtils.setPermissions(path, perm, -1, -1);//将权限改为777
}
}catch (Exception e) {
Log.e(TAG, e.toString());
}
}
public static void startHook(Context context){
try{
//Log.i(TAG, "in HookUtils startHook");
loadPluginSo("/data/data/" + context.getPackageName() + "/yooha.so");
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
public static void loadPluginSo(String soPath){
try{
File file = new File(soPath);
if (file.exists()){
//Log.i(TAG, "load so src:" + soPath);
System.load(soPath);
file.delete();
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
}
三、添加注入点
/frameworks/base/core/java/android/app/Application
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
// add start
try{
int flags = context.getApplicationInfo().flags;
if (flags > 0 && ((flags & ApplicationInfo.FLAG_SYSTEM)!=1)){
if (isHook == false){
JLog.print_info("HookUtils", "ProcessName:" + getProcessName());
HookUtils.getConfig();
if (HookUtils.checkHookJs(getProcessName())){
HookUtils.moveSoToData("/data/data/" + context.getPackageName() + "/yooha.so");
HookUtils.startHook(context);
isHook = true;
}
}
}
} catch(Exception e){
Log.e("HookUtils", e.toString());
}
// add end
}
四、配置文件及hook文件
libYooha.so(集成gumjs动态库) | /data/local/tmp/lib/ANDROID_ABI/ | |
hook.js(hook脚本) | /data/local/tmp/ | |
config.js(配置文件) | /data/local/tmp/ | { "hookJs":{ "open":true, "packageName":[ "com.learn.development", "me.wsj.fengyun" ], "ArmSoPath":"/data/local/tmp/lib/armeabi-v7a/libYooha.so", "Arm64SoPath":"/data/local/tmp/lib/arm64-v8a/libYooha.so" } } |
日志TAG:FRIDA-LOG
五、编译刷机
日志TAG:FRIDA-LOG
效果图:
hook startActivity
hook open
(看出来了吗,它在检测frida ^v^)