大家好,又见面了,我是你们的朋友全栈君。
一、hook简介
hook俗称钩子,主要作用是替换系统内存中的对象,在上层调用此对象的方法的时候可以修改传入参数或者返回值,达到欺骗上层的目的,就像小红帽故事里的大灰狼,通过扮演小红帽的外婆的角色来达到欺骗小红帽的目的。其实hook就是一种中间人劫持的思想,如图所示:
在安卓中实现hook主要通过两种方式:
1.反射技术和代理实现,当然代理不管是动态还是静态的都是可以实现的,但是只能hook自己应用内存中的对象;
2.在root的情况下,Xposed通过替换/system/bin/app_process程序控制zygote进程,使得app_process在启动过程中会加载XposedBridge.jar这个jar包,从而完成对Zygote进程及其创建的Dalvik虚拟机的劫持,可以达到hook整个系统中所有进程内存里面的对象的目的;
方式2虽然很强大、很逆天,但是也有限制就是必须的root,所以本文主要讲方式1的实现。
二、hookAms实践:
2376 private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
2377 protected IActivityManager More ...create() {
2378 IBinder b = ServiceManager.getService("activity");
2379 if (false) {
2380 Log.v("ActivityManager", "default service binder = " + b);
2381 }
2382 IActivityManager am = asInterface(b);
2383 if (false) {
2384 Log.v("ActivityManager", "default service = " + am);
2385 }
2386 return am;
2387 }
2388 };
26public abstract class More ...Singleton<T> {
27 private T mInstance;
28
29 protected abstract T More ...create();
30
31 public final T More ...get() {
32 synchronized (this) {
33 if (mInstance == null) {
34 mInstance = create();
35 }
36 return mInstance;
37 }
38 }
39}
android.app.ActivityManagerNative里面的一个静态内部类实现了Singleton的抽象方法create()并且返回mInstance即IActivityManeger
public static void hookAms(Context context){ try { //获取ActivityManagerNative里面的gDefault静态对象即是内存的唯一对象 Class<?> forName = Class.forName("android.app.ActivityManagerNative"); Field defauleField = forName.getDeclaredField("gDefault"); defauleField.setAccessible(true); Object defauleValue = defauleField.get(null);//静态对象传null即可 //获取gDefault里面的iActivityManagerObject对象 Class<?> forName2 = Class.forName("android.util.Singleton"); Field instanceField = forName2.getDeclaredField("mInstance"); instanceField.setAccessible(true); Object iActivityManagerObject = instanceField.get(defauleValue); //传入真实对象生成代理对象proxyy Object proxyy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{Class.forName("android.app.IActivityManager")}, new AmsInvocationHandler(context,iActivityManagerObject)); //真实对象替换为代理对象proxyy instanceField.set(defauleValue,proxyy); } catch (Exception e) { e.printStackTrace(); }}
public class AmsInvocationHandler implements InvocationHandler { private Context context; private Object iActivityManagerObject; public AmsInvocationHandler(Context context,Object iActivityManagerObject) { this.context = context; this.iActivityManagerObject = iActivityManagerObject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("startActivity".contains(method.getName())){ Intent intent = null; int index = 0; for(int i = 0;i<args.length;i++){ if(args[i] instanceof Intent){ intent = (Intent)args[i]; index = i; break; } } Intent proxyIntent = new Intent(context,ProxyActivity.class); proxyIntent.putExtra("oldIntent",intent); args[index] = proxyIntent; } return method.invoke(iActivityManagerObject,args); }}
如此便完成了意图的替换,接下来就是在通过检查后、启动Activity前把意图替换回来:
case LAUNCH_ACTIVITY: {
1273 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
1274 final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
1275
1276 r.packageInfo = getPackageInfoNoCheck(
1277 r.activityInfo.applicationInfo, r.compatInfo);
1278 handleLaunchActivity(r, null);
1279 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1280 } break;
可以看到msg携带的obj是一个叫做ActivityClientRecord的对象,而这个对象里面其实携带了Intent,基于此,我们便可以在mH的handlerMessage之前将msg截取修改里面的Intent参数就可以了,由于Looper从消息队列中取出msg,然后在获取他的target即是handler的时候是调用handler的dispatchMessage的,所以我们可以先看看此方法
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); }}
可以看到方法里会先检查有没有mCallback,如果有则直接调用它的handlerMesage,所以这里我们可以直接hook它的mCallback
public static void hookSystemHandler(){ try { // 获取全局的ActivityThread对象 Class<?> forName = Class.forName("android.app.ActivityThread"); Field currentActivityThreadField = forName.getDeclaredField("sCurrentActivityThread"); currentActivityThreadField.setAccessible(true); Object currentActivityThread = currentActivityThreadField.get(null); // 获取ActivityThread里面的mH对象 Field handlerField = forName.getDeclaredField("mH"); handlerField.setAccessible(true); Handler handlerObject = (Handler)handlerField.get(currentActivityThread); // 获取mH里面的mCallback对象,并且替换为我们自己的ActivityThreadHandlerCallBack Field callBackFieid = Handler.class.getDeclaredField("mCallback"); callBackFieid.setAccessible(true); callBackFieid.set(handlerObject,new ActivityThreadHandlerCallBack(handlerObject)); }catch (Exception e){ } }
public class ActivityThreadHandlerCallBack implements Handler.Callback{ Handler handler; public ActivityThreadHandlerCallBack(Handler handler) { this.handler = handler; } @Override public boolean handleMessage(Message msg) { if(msg.what == 100){ launchActiity(msg); } handler.handleMessage(msg); return true; } private void launchActiity(Message msg){ Object obj = msg.obj; try { Field intentField = obj.getClass().getDeclaredField("intent"); intentField .setAccessible(true); Intent proxyIntent = (Intent)intentField.get(obj); Intent realIntent = proxyIntent.getParcelableExtra("oldIntent"); if(realIntent != null){ proxyIntent.setComponent(realIntent.getComponent()); } }catch (Exception e){ } } }
至此,我们通过hook技术完成了启动不在清单注册也能启动Activity这个功能。
三、hookPms实践
public static void hookPms(Context context, String signed, int hashCode){ try{ // 获取全局的ActivityThread对象 Class<?> activityThreadClass = Class.forName("android.app.ActivityThread"); Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread"); Object currentActivityThread = currentActivityThreadMethod.invoke(null); // 获取ActivityThread里面原始的sPackageManager Field sPackageManagerField = activityThreadClass.getDeclaredField("sPackageManager"); sPackageManagerField.setAccessible(true); Object sPackageManager = sPackageManagerField.get(currentActivityThread); // 准备好代理对象, 用来替换原始的对象 Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] { Class.forName("android.content.pm.IPackageManager") }, new PmsHookBinderInvocationHandler(sPackageManager, signed, hashCode)); // 替换掉ActivityThread里面的 sPackageManager 字段 sPackageManagerField.set(currentActivityThread, proxy); // 替换 ApplicationPackageManager里面的 mPM对象 PackageManager pm = context.getPackageManager(); Field mPmField = pm.getClass().getDeclaredField("mPM"); mPmField.setAccessible(true); mPmField.set(pm, proxy); }catch (Exception e){ } }
public class PmsHookBinderInvocationHandler implements InvocationHandler{ private Object base; //应用正确的签名信息 private String SIGN; private int hashCode = 0; public PmsHookBinderInvocationHandler(Object base, String sign, int hashCode) { try { this.base = base; this.SIGN = sign; this.hashCode = hashCode; } catch (Exception e) { } } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if("getPackageInfo".equals(method.getName())){ Integer flag = (Integer)args[1]; if(flag == PackageManager.GET_SIGNATURES){ Signature sign = new Signature(SIGN); if(hashCode != 0){ try{ Class<?> clazz = sign.getClass(); Field mHaveHashCodeF = clazz.getDeclaredField("mHaveHashCode"); mHaveHashCodeF.setAccessible(true); mHaveHashCodeF.set(sign, true); Field mHashCodeF = clazz.getDeclaredField("mHashCode"); mHashCodeF.setAccessible(true); mHashCodeF.set(sign, hashCode); }catch(Exception e){ } } PackageInfo info = (PackageInfo) method.invoke(base, args); info.signatures[0] = sign; return info; } } return method.invoke(base, args); } }
最后再附上获取签名信息的方法:
private void getSignature() { try { PackageInfo packageInfo = getPackageManager().getPackageInfo( getPackageName(), PackageManager.GET_SIGNATURES); if (packageInfo.signatures != null) { Log.d("", "sig:"+packageInfo.signatures[0].toCharsString()+ "hashcode:"+packageInfo.signatures[0].hashCode()); } } catch (Exception e2) { } }
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/141290.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...