(Android) 如何使用HOOK实现动态注入以及自动化操作
为什么会有这边博文?
最近一直在搞一些apk破解以及自动化方面的东西.觉得有必要记录一下.也是为了修改下自己懒的毛病(很久很久很久没更新博客了)
一. 项目需求
项目功能:
本文将使用QQ为例,利用Hook实现自动登录,自动退出登录功能
项目流程:
流程比较简单
二. 资源准备
大致需要准备以下东西:
- 一台空闲的安卓手机,能root最好.
- 安装VirtualXposed(传送门),安装QQ(传送门,提取码: ty58)(注意QQ是8.0.0.4000版本,不同版本可能会影响hook点),对于不懂怎么使用hook的请参考
- 将QQ安装到VirtualXposed
- QQ脱壳获取源代码(不懂脱壳操作请点这里)
三. 功能实现
3.1 实现自动从QQ新用户页跳转到登陆页
第一次启动qq的时候,qq会停留在,显然要实现登陆的话我们需要让其自动进入登陆页面,如图:
3.1.1 获取新用户页的堆栈信息(手机需要连接电脑)
adb shell dumpsys activity >>输出路径
下面是导出的堆栈信息:
我们可以得到登陆界面的RegisterGuideView.以及登陆按钮的16进制值7f0b0da9
3.1.2 获取登陆按钮逻辑的Hook点
通过PowerGREP工具对脱壳后的QQdex源码(脱壳后可得到十几个dex文件)进行字符串搜索找到RegisterGuideView所在的dex,然后通过jeb工具反编译该dex, 以下是RegisterGuideView类的源码
package com.tencent.mobileqq.activity.registerGuideLogin;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View$OnClickListener;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import com.tencent.mobileqq.activity.RegisterPhoneNumActivity;
import com.tencent.mobileqq.app.QQAppInterface;
import com.tencent.mobileqq.statistics.ReportController;
import com.tencent.qphone.base.util.QLog;
public class RegisterGuideView extends GuideBaseFragment implements View$OnClickListener {
private View a;
private Button a;
private Button b;
public RegisterGuideView() {
super();
}
@SuppressLint(value={
"ValidFragment"}) public RegisterGuideView(QQAppInterface arg1) {
super(arg1);
}
public void onClick(View arg14) {
Intent v0;
switch(arg14.getId()) {
case 2131430824: {
ReportController.b(this.a, "CliOper", "", "", "0X8007576", "0X8007576", 0, 0, "", "", "", "");
v0 = new Intent(this.a, RegisterPhoneNumActivity.class);
v0.putExtra("key_register_from", 2);
v0.putExtra("leftViewText", this.a.getString(2131499116));
v0.addFlags(67108864);
this.a.startActivity(v0);
break;
}
case 2131430825: {
ReportController.b(this.a, "CliOper", "", "", "0X8007575", "0X8007575", 0, 0, "", "", "", "");
v0 = this.a.getIntent();
v0.putExtra("from_register_guide", true);
v0.putExtra("is_need_show_logo_animation", true);
GuideBaseFragment v0_1 = GuideHandler.a(this.a, this.a);
if(this.a == null) {
return;
}
this.a.a(v0_1);
break;
}
}
}
public View onCreateView(LayoutInflater arg7, ViewGroup arg8, Bundle arg9) {
View v1 = arg7.inflate(2130903607, arg8, false);
this.a = v1.findViewById(2131428759);
this.a.setVisibility(0);
this.a = v1.findViewById(2131430825);
this.b = v1.findViewById(2131430824);
this.a.setOnClickListener(((View$OnClickListener)this));
this.b.setOnClickListener(((View$OnClickListener)this));
View v0 = v1.findViewById(2131430823);
try {
((ImageView)v0).setImageDrawable(new BitmapDrawable(this.getResources(), this.getActivity().getAssets().open("splash.jpg")));
}
catch(Throwable v0_1) {
QLog.e("LoginActivity.RegisterGuideView", 1, "onCreateView error:" + v0_1.getMessage());
}
return v1;
}
}
通过我们得到的登陆按钮的16进制值7f0b0da9可以确定10进制值2131430825,从而确定变量a是登陆按钮.
3.1.3 通过Hook 实现登陆按钮点击
由于我们已经找到了登陆按钮相关的类和按钮变量对象,接下来我们只需要通过hook拿到该按钮对象,实现点击即可自动进入登陆页面
以下是核心代码:
/**
* hook新用户页,拿到登陆按钮,模拟点击登陆
*/
public static void hookRegisterGuideLogin()
{
XposedHelpers.findAndHookMethod("com.tencent.mobileqq.activity.registerGuideLogin.RegisterGuideView", context.getClassLoader(), "onCreateView", LayoutInflater.class, ViewGroup.class, Bundle.class, new XC_MethodHook()
{
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable
{
super.afterHookedMethod(param);
final Object obj = param.thisObject;
doMainLooper(context, 1000, new Runnable()
{
@Override
public void run()
{
//得到按钮对象
Object viewObj = ReflectUtils.getFieldValueForFiledClsNm(obj, "a", "android.widget.Button");
if (viewObj instanceof Button)
{
//点击按钮
((Button) viewObj).performClick();
}
}
});
}
});
}
目前为止,我们就已经完成了长征的第一步,从新用户页自动点击到登陆页. 下面是成果演示:
可以看到我们已经实现了从新用户页点击到登陆页了.