插件一开始用的资源布局写的,也就是通过R引用,代码如下:
package com.netease.ga.plug;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
/**
* Created by sing on 2014/12/10.
* desc:
*/
public class PlugMain {
private static final String TAG = "PlugMain";
public static String TITLE = "NISHook框架插件(1.0)";
public static String mSoPath;
private static PlugMain me = null;
private Activity mActivity;
private float mDp;
private RelativeLayout.LayoutParams mRlparams;
private ViewGroup mRootView;
private PopupWindow popupWindow;
static private EditText edt_log;
static {
mSoPath = null;
}
public PlugMain(Activity paramActivity) {
this.mActivity = paramActivity;
DisplayMetrics localDisplayMetrics = new DisplayMetrics();
this.mActivity.getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
this.mDp = localDisplayMetrics.density;
}
public static void init(Activity paramActivity, String paramString) {
mSoPath = paramString;
if (me == null) {
me = new PlugMain(paramActivity);
me.show();
logMsg("init run, target Activity: \n" + paramActivity);
logMsg("插件已加载");
Toast.makeText(paramActivity.getApplicationContext(), "插件已加载", Toast.LENGTH_LONG).show();
}
}
private void show() {
this.mRootView = new RelativeLayout(this.mActivity);
FrameLayout.LayoutParams localLayoutParams = new FrameLayout.LayoutParams(-1, -1);
this.mActivity.addContentView(this.mRootView, localLayoutParams);
initNativeFunC();
initView();
}
private void initNativeFunC() {
if (mSoPath != null) {
logMsg("load so: \n" + mSoPath);
System.load(mSoPath);
}
// if (mSoPath != null)
// xxUtility.init(this.mActivity, mSoPath);
}
private void initView() {
Context context = PlugMain.this.mRootView.getContext();
View contentView = View.inflate(context, R.layout.popup_main, null);//getApplicationContext()
LinearLayout localLinearLayout = new LinearLayout(this.mActivity);
localLinearLayout.setOrientation(LinearLayout.VERTICAL);
localLinearLayout.setBackgroundResource(R.drawable.rounded_corners_view);
localLinearLayout.setPadding((int) (4.0F * this.mDp), (int) (4.0F * this.mDp), (int) (4.0F * this.mDp), (int) (4.0F * this.mDp));
RelativeLayout.LayoutParams localLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
localLayoutParams.addRule(11);
localLayoutParams.addRule(15);
LinearLayout.LayoutParams localLayoutParams1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
TextView localTextView1 = new TextView(this.mActivity);
localTextView1.setText("查看");
localTextView1.setTextSize(26.0F);
localTextView1.setTextColor(Color.WHITE);
localLinearLayout.addView(localTextView1, localLayoutParams1);
this.mRootView.addView(localLinearLayout, localLayoutParams);
this.mRlparams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
this.mRlparams.addRule(11);
this.mRlparams.addRule(15);
/////////////////////////////////////////////////////////////////////////
//创建PopupWindow
//将布局文件转成view,该view用于显示PopupWindow中的内容
contentView.setBackgroundResource(R.drawable.rounded_corners_view);
edt_log = (EditText) contentView.findViewById(R.id.edt_log);
//创建PopupWindow窗体时必须要指定窗体的大小,否则不会显示在界面上。参数一:窗体中用于显示内容的viewContent,参数二、三:表示PopupWindow窗体的宽和高
popupWindow = new PopupWindow(contentView, DensityUtil.dip2px(context, 300), ViewGroup.LayoutParams.WRAP_CONTENT, true);
// 注意:一定要给popwindow设置背景图片或背景资源,如果不设置背景资源 , 动画、 焦点的处理 都会产生问题。
popupWindow.setBackgroundDrawable(PlugMain.this.mActivity.getResources().getDrawable(R.drawable.rounded_corners_pop));
/////////////////////////////////////////////////////////////////////////
localTextView1.setOnClickListener(new View.OnClickListener() {
public void onClick(View paramView) {
dismissPopupWindow();
//参数一:PopupWindow挂载在那个View上,参数二:设置PopupWindow显示的重心位置
//参数三:PopupWindow在View上X轴的偏移量,参数四:PopupWindow在View上Y轴的偏移量。X、Y轴的偏移量是相对于当前Activity所在的窗体,参照点为(0,0)
popupWindow.showAtLocation(mRootView, Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
}
});
}
/**
* 设置log信息
*
* @param s
*/
public static void logMsg(String s) {
if (edt_log != null) {
String strText = edt_log.getText().toString();
edt_log.setText(strText + s + "\n");
}
}
private void dismissPopupWindow() {
if (popupWindow != null && popupWindow.isShowing()) {
popupWindow.dismiss();
//popupWindow = null;
}
}
}
资源布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/ll_popup_container"
android:background="@android:color/darker_gray"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="NISHook插件"
android:textSize="20sp"
android:textColor="@android:color/white"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<EditText
android:id="@+id/edt_log"
android:textColor="@android:color/black"
android:background="@android:color/white"
android:layout_margin="2dp"
android:editable="false"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="信息输出栏..."
android:inputType="textMultiLine"
android:gravity="left|top"
android:minLines="10"
android:scrollbars="vertical"
android:layout_alignParentBottom="true"/>
</LinearLayout>
由于插件被加载后R实际上是找不到的,完美的解决方案可以参考:
Android apk动态加载机制的研究(二):资源加载和activity生命周期管理
对应的git代码:https://github.com/singwhatiwanna/dynamic-load-apk
但是感觉蛮复杂的,我们的插件界面又比较简单,所以沿用叉叉助手插件的方式动态创建布局。
写的时候动态创建的控件属性参考popup_main.xml进行设置。
后来写的时候由于一开始HOOK的是启动类的Activity,这个Activity有时候作为欢迎界面,所以生存周期比较短,当时考虑显示一个桌面悬浮窗口,
于是有了下面的代码:
package com.netease.ga.plug;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.GradientDrawable;
import android.text.InputType;
import android.text.method.ScrollingMovementMethod;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
/**
* Created by sing on 2014/12/10.
* desc:
*/
public class PlugMain {
private static final String TAG = "PlugMain";
public static String TITLE = "NISHook框架插件(1.0)";
public static String mSoPath;
private static PlugMain me = null;
//private Activity mActivity;
private Context mContext;
private WindowManager mWindowManager;
private float mDp;
private RelativeLayout.LayoutParams mRlparams;
private ViewGroup mRootView;
private PopupWindow popupWindow;
static private EditText edt_log;
static {
mSoPath = null;
}
public PlugMain(Activity paramActivity) {
mContext = paramActivity.getApplicationContext();
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics localDisplayMetrics = new DisplayMetrics();
mWindowManager.getDefaultDisplay().getMetrics(localDisplayMetrics);
this.mDp = localDisplayMetrics.density;
}
public static void init(Activity paramActivity, String strSoPath) {
mSoPath = strSoPath;
if (me == null) {
me = new PlugMain(paramActivity);
me.show();
logMsg("init run, target Activity: \n" + paramActivity);
me.initNativeFunC();
logMsg("插件已加载");
Toast.makeText(paramActivity.getApplicationContext(), "插件已加载", Toast.LENGTH_LONG).show();
}
}
private void show() {
this.mRootView = new RelativeLayout(mContext);
WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();
wmParams.type = WindowManager.LayoutParams.TYPE_PHONE; // 设置window type
wmParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明
wmParams.gravity = Gravity.CENTER;
// 以屏幕左上角为原点,设置x、y初始值
wmParams.x = 0;
wmParams.y = 0;
// 设置悬浮窗口长宽数据
wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;;
wmParams.height =WindowManager.LayoutParams.WRAP_CONTENT;;
mWindowManager.addView(this.mRootView, wmParams);
initView();
}
private void initNativeFunC() {
if (mSoPath != null) {
logMsg("load so: \n" + mSoPath);
System.load(mSoPath);
}else{
logMsg("未指定要加载的so文件\n");
}
// if (mSoPath != null)
// xxUtility.init(this.mActivity, mSoPath);
}
private void initView() {
Context context = PlugMain.this.mRootView.getContext();
GradientDrawable gradientDrawable;
gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(0xff606060);
gradientDrawable.setStroke(DensityUtil.dip2px(context, 3), 0xffff808);
gradientDrawable.setCornerRadius(DensityUtil.dip2px(context, 10));
LinearLayout localLinearLayout = new LinearLayout(mContext);
localLinearLayout.setOrientation(LinearLayout.VERTICAL);
localLinearLayout.setBackgroundDrawable(gradientDrawable);
localLinearLayout.setPadding((int) (4.0F * this.mDp), (int) (4.0F * this.mDp), (int) (4.0F * this.mDp), (int) (4.0F * this.mDp));
RelativeLayout.LayoutParams localLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
localLayoutParams.addRule(11);
localLayoutParams.addRule(15);
LinearLayout.LayoutParams localLayoutParams1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
TextView localTextView1 = new TextView(mContext);
localTextView1.setText("查看");
localTextView1.setTextSize(26.0F);
localTextView1.setTextColor(Color.WHITE);
localLinearLayout.addView(localTextView1, localLayoutParams1);
TextView localTextView2 = new TextView(mContext);
localTextView2.setText("退出");
localTextView2.setTextSize(26.0F);
localTextView2.setTextColor(Color.RED);
localLinearLayout.addView(localTextView2, localLayoutParams1);
this.mRootView.addView(localLinearLayout, localLayoutParams);
this.mRlparams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
this.mRlparams.addRule(11);
this.mRlparams.addRule(15);
/////////////////////////////////////////////////////////////////////////
//创建PopupWindow
LinearLayout.LayoutParams layoutParamsPopView = new LinearLayout.LayoutParams(DensityUtil.dip2px(context, 300), DensityUtil.dip2px(context, 250));
LinearLayout contentView = new LinearLayout(mContext);
contentView.setOrientation(LinearLayout.VERTICAL);
contentView.setLayoutParams(layoutParamsPopView);
gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(0xff606060);
gradientDrawable.setStroke(DensityUtil.dip2px(context, 3), 0xffff808);
gradientDrawable.setCornerRadius(DensityUtil.dip2px(context, 6));
contentView.setBackgroundDrawable(gradientDrawable);
contentView.setPadding(DensityUtil.dip2px(context, 4), DensityUtil.dip2px(context, 4), DensityUtil.dip2px(context, 4), DensityUtil.dip2px(context, 4));
//创建一个标题
LinearLayout.LayoutParams layoutParamsTitle = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParamsTitle.gravity = Gravity.CENTER;
TextView tv_Title = new TextView(mContext);
tv_Title.setText("NISHook插件");
tv_Title.setTextSize(22.0f);
tv_Title.setTextColor(Color.WHITE);
tv_Title.setPadding(1, 1, 1, 1);
contentView.addView(tv_Title, layoutParamsTitle);
//创建一个信息输出栏
LinearLayout.LayoutParams layoutParamsLog = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
edt_log = new EditText(mContext);
edt_log.setHint("信息输出栏...");
edt_log.setTextColor(Color.BLACK);
edt_log.setBackgroundColor(Color.WHITE);
edt_log.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE);
edt_log.setSingleLine(false); //改变默认的单行模式
edt_log.setMinLines(10);
edt_log.setMaxLines(15);
edt_log.setVerticalScrollBarEnabled(true);
edt_log.setMovementMethod(ScrollingMovementMethod.getInstance());
edt_log.setGravity(Gravity.LEFT | Gravity.TOP);
contentView.addView(edt_log, layoutParamsLog);
//创建PopupWindow窗体时必须要指定窗体的大小,否则不会显示在界面上。参数一:窗体中用于显示内容的viewContent,参数二、三:表示PopupWindow窗体的宽和高
popupWindow = new PopupWindow(contentView, DensityUtil.dip2px(context, 300), ViewGroup.LayoutParams.WRAP_CONTENT, true);
// 注意:一定要给popwindow设置背景图片或背景资源,如果不设置背景资源 , 动画、 焦点的处理 都会产生问题。
gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(0xffffffff);
gradientDrawable.setStroke(DensityUtil.dip2px(context, 3), 0xffff808);
gradientDrawable.setCornerRadius(DensityUtil.dip2px(context, 6));
popupWindow.setBackgroundDrawable(gradientDrawable);
popupWindow.getBackground().setAlpha(153);
/////////////////////////////////////////////////////////////////////////
localTextView1.setOnClickListener(new View.OnClickListener() {
public void onClick(View paramView) {
dismissPopupWindow();
//参数一:PopupWindow挂载在那个View上,参数二:设置PopupWindow显示的重心位置
//参数三:PopupWindow在View上X轴的偏移量,参数四:PopupWindow在View上Y轴的偏移量。X、Y轴的偏移量是相对于当前Activity所在的窗体,参照点为(0,0)
popupWindow.showAtLocation(mRootView, Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
}
});
localTextView2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismissPopupWindow();
mWindowManager.removeView(mRootView);
}
});
}
/**
* 设置log信息
*
* @param s
*/
public static void logMsg(String s) {
if (edt_log != null) {
String strText = edt_log.getText().toString();
edt_log.setText(strText + s + "\n");
}
}
private void dismissPopupWindow() {
if (popupWindow != null && popupWindow.isShowing()) {
popupWindow.dismiss();
//popupWindow = null;
}
}
}
但是显示悬浮窗口需要一个权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
当插件被加载到目标进程中时,是需要宿主拥有这个权限才行,只能通过先静态修改目标APK包添加上这个权限,然后安装重复以上步骤。
如果目标程序有防二次打包的话,这个方案就不是很好,而且来回操作也挺麻烦,最后无奈只好老老实实按照叉叉助手的插件模式来写,
就是动态创建的方式:
package com.netease.ga.plug;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.GradientDrawable;
import android.text.InputType;
import android.text.method.ScrollingMovementMethod;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
/**
* Created by sing on 2014/12/10.
* desc:
*/
public class PlugMain {
private static final String TAG = "PlugMain";
public static String TITLE = "NISHook框架插件(1.0)";
public static String mSoPath;
private static PlugMain me = null;
private Activity mActivity;
private float mDp;
private RelativeLayout.LayoutParams mRlparams;
private ViewGroup mRootView;
private PopupWindow popupWindow;
static private EditText edt_log;
static {
mSoPath = null;
}
public PlugMain(Activity paramActivity) {
this.mActivity = paramActivity;
DisplayMetrics localDisplayMetrics = new DisplayMetrics();
this.mActivity.getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
this.mDp = localDisplayMetrics.density;
}
public static void init(Activity paramActivity, String strSoPath) {
mSoPath = strSoPath;
if (me == null) {
me = new PlugMain(paramActivity);
me.show();
logMsg("init run, target Activity: \n" + paramActivity);
me.initNativeFunC();
logMsg("插件已加载");
Toast.makeText(paramActivity.getApplicationContext(), "插件已加载", Toast.LENGTH_LONG).show();
}
}
private void show() {
this.mRootView = new RelativeLayout(this.mActivity);
FrameLayout.LayoutParams localLayoutParams = new FrameLayout.LayoutParams(-1, -1);
this.mActivity.addContentView(this.mRootView, localLayoutParams);
initView();
}
private void initNativeFunC() {
if (mSoPath != null) {
logMsg("load so: \n" + mSoPath);
System.load(mSoPath);
} else {
logMsg("未指定要加载的so文件\n");
}
// if (mSoPath != null)
// xxUtility.init(this.mActivity, mSoPath);
}
private void initView() {
Context context = PlugMain.this.mRootView.getContext();
GradientDrawable gradientDrawable;
gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(0xff606060);
gradientDrawable.setStroke(DensityUtil.dip2px(context, 3), 0xffff808);
gradientDrawable.setCornerRadius(DensityUtil.dip2px(context, 10));
LinearLayout localLinearLayout = new LinearLayout(mActivity);
localLinearLayout.setOrientation(LinearLayout.VERTICAL);
localLinearLayout.setBackgroundDrawable(gradientDrawable);
localLinearLayout.setPadding((int) (4.0F * this.mDp), (int) (4.0F * this.mDp), (int) (4.0F * this.mDp), (int) (4.0F * this.mDp));
RelativeLayout.LayoutParams localLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
localLayoutParams.addRule(11);
localLayoutParams.addRule(15);
LinearLayout.LayoutParams localLayoutParams1 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
TextView localTextView1 = new TextView(mActivity);
localTextView1.setText("查看");
localTextView1.setTextSize(26.0F);
localTextView1.setTextColor(Color.WHITE);
localLinearLayout.addView(localTextView1, localLayoutParams1);
TextView localTextView2 = new TextView(mActivity);
localTextView2.setText("退出");
localTextView2.setTextSize(26.0F);
localTextView2.setTextColor(Color.RED);
localLinearLayout.addView(localTextView2, localLayoutParams1);
this.mRootView.addView(localLinearLayout, localLayoutParams);
this.mRlparams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
this.mRlparams.addRule(11);
this.mRlparams.addRule(15);
/////////////////////////////////////////////////////////////////////////
//创建PopupWindow
LinearLayout.LayoutParams layoutParamsPopView = new LinearLayout.LayoutParams(DensityUtil.dip2px(context, 300), DensityUtil.dip2px(context, 250));
LinearLayout contentView = new LinearLayout(mActivity);
contentView.setOrientation(LinearLayout.VERTICAL);
contentView.setLayoutParams(layoutParamsPopView);
gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(0xff606060);
gradientDrawable.setStroke(DensityUtil.dip2px(context, 3), 0xffff808);
gradientDrawable.setCornerRadius(DensityUtil.dip2px(context, 6));
contentView.setBackgroundDrawable(gradientDrawable);
contentView.setPadding(DensityUtil.dip2px(context, 4), DensityUtil.dip2px(context, 4), DensityUtil.dip2px(context, 4), DensityUtil.dip2px(context, 4));
//创建一个标题
LinearLayout.LayoutParams layoutParamsTitle = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
layoutParamsTitle.gravity = Gravity.CENTER;
TextView tv_Title = new TextView(mActivity);
tv_Title.setText("NISHook插件");
tv_Title.setTextSize(22.0f);
tv_Title.setTextColor(Color.WHITE);
tv_Title.setPadding(1, 1, 1, 1);
contentView.addView(tv_Title, layoutParamsTitle);
//创建一个信息输出栏
LinearLayout.LayoutParams layoutParamsLog = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
edt_log = new EditText(mActivity);
edt_log.setHint("信息输出栏...");
edt_log.setTextColor(Color.BLACK);
edt_log.setBackgroundColor(Color.WHITE);
edt_log.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE);
edt_log.setSingleLine(false); //改变默认的单行模式
edt_log.setMinLines(10);
edt_log.setMaxLines(15);
edt_log.setVerticalScrollBarEnabled(true);
edt_log.setMovementMethod(ScrollingMovementMethod.getInstance());
edt_log.setGravity(Gravity.LEFT | Gravity.TOP);
contentView.addView(edt_log, layoutParamsLog);
//创建PopupWindow窗体时必须要指定窗体的大小,否则不会显示在界面上。参数一:窗体中用于显示内容的viewContent,参数二、三:表示PopupWindow窗体的宽和高
popupWindow = new PopupWindow(contentView, DensityUtil.dip2px(context, 300), ViewGroup.LayoutParams.WRAP_CONTENT, true);
// 注意:一定要给popwindow设置背景图片或背景资源,如果不设置背景资源 , 动画、 焦点的处理 都会产生问题。
gradientDrawable = new GradientDrawable();
gradientDrawable.setColor(0xffffffff);
gradientDrawable.setStroke(DensityUtil.dip2px(context, 3), 0xffff808);
gradientDrawable.setCornerRadius(DensityUtil.dip2px(context, 6));
popupWindow.setBackgroundDrawable(gradientDrawable);
popupWindow.getBackground().setAlpha(153);
/////////////////////////////////////////////////////////////////////////
localTextView1.setOnClickListener(new View.OnClickListener() {
public void onClick(View paramView) {
dismissPopupWindow();
//参数一:PopupWindow挂载在那个View上,参数二:设置PopupWindow显示的重心位置
//参数三:PopupWindow在View上X轴的偏移量,参数四:PopupWindow在View上Y轴的偏移量。X、Y轴的偏移量是相对于当前Activity所在的窗体,参照点为(0,0)
popupWindow.showAtLocation(mRootView, Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
}
});
localTextView2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismissPopupWindow();
mRootView.setVisibility(View.INVISIBLE);
}
});
}
/**
* 设置log信息
*
* @param s
*/
public static void logMsg(String s) {
if (edt_log != null) {
String strText = edt_log.getText().toString();
edt_log.setText(strText + s + "\n");
}
}
private void dismissPopupWindow() {
if (popupWindow != null && popupWindow.isShowing()) {
popupWindow.dismiss();
//popupWindow = null;
}
}
}
运行预览:
HOOK框架界面部分:
package com.netease.ga.view;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.netease.ga.Injector;
import com.netease.ga.R;
import com.netease.ga.utils.util;
import java.util.List;
public class MainActivity extends Activity {
public static final String TAG = "MainActivity";
private native void hookApplication(Context context);
static {
}
private boolean bret;
private SharedPreferences sp;
private EditText edt_packageName;
private Button btn_browse;
private TextView tv_activity;
private EditText edt_activity;
private Button btn_startApp;
private Button btn_inject;
private static EditText edt_log;
private String strTargetActivity;
public MainActivity() {
super();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edt_packageName = (EditText) findViewById(R.id.edt_package);
btn_browse = (Button) findViewById(R.id.btn_browse);
tv_activity = (TextView) findViewById(R.id.tv_activity);
edt_activity = (EditText) findViewById(R.id.edt_activity);
btn_startApp = (Button) findViewById(R.id.btn_startApp);
btn_inject = (Button) findViewById(R.id.btn_inject);
edt_log = (EditText) findViewById(R.id.edt_log);
edt_log.setFocusableInTouchMode(false);
sp = getSharedPreferences("config", Context.MODE_PRIVATE);
//SharedPreferences.Editor editor = sp.edit();
String packageName = sp.getString("hookpackage", "com.netease.anep");
strTargetActivity = sp.getString("launcherActivity", "");
edt_packageName.setText(packageName);
edt_activity.setText(strTargetActivity);
tv_activity.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String topActivityClassName = null;
ActivityManager am = (ActivityManager) MainActivity.this.getSystemService(Activity.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> mRunningTasks = am.getRunningTasks(10);
for (ActivityManager.RunningTaskInfo runningTaskInfo : mRunningTasks) {
ComponentName cn = runningTaskInfo.topActivity;
String activityName = cn.getClassName();
if (activityName.indexOf("com.netease.ga.view") == -1 && activityName.indexOf("com.android.") == -1) {
activityName = activityName.replace('.', '/');
topActivityClassName = activityName;
}
}
if (topActivityClassName != null) {
strTargetActivity = topActivityClassName;
logMsg("launcher:" + strTargetActivity);
edt_activity.setText(strTargetActivity);
SharedPreferences.Editor editor = sp.edit();
editor.putString("launcherActivity", strTargetActivity);
editor.commit();
}
}
});
//显示到信息框中
logMsg("HOOK目标信息:");
logMsg("package: " + packageName);
logMsg("launcher: " + strTargetActivity + "\n");
if (strTargetActivity.isEmpty()) {
logMsg("[×]尚未选择目标,请先选择目标!");
}
//浏览app列表
btn_browse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setClass(MainActivity.this, MyGamesActivity.class);
MainActivity.this.startActivityForResult(intent, 0);
}
});
//注入
btn_inject.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//把hook的配置信息转换成易读取的文件,逐行写入到:/data/data/com.netease.ga/app_plugin/config.cfg
//保证在hook前把最新设置的hook信息配置到文件中去
MainActivity.this.setHookConfigFile();
Injector.injectSoToParent(MainActivity.this);
}
});
//运行指定的app
btn_startApp.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//启动的时候先配置好Hook信息
MainActivity.this.setHookConfigFile();
util.runApp(MainActivity.this, edt_packageName.getText().toString());
}
});
}
//把hook的配置信息转换成易读取的文件,逐行写入到:/data/data/com.netease.ga/app_plugin/config.cfg
private void setHookConfigFile() {
//把插件从资源目录下复制到app_plugin目录下
String plugPath = Injector.getPluginPath(edt_packageName.getText().toString(), this);
bret = Injector.copyAssetsFileToDir("plug.apk", plugPath, this);
bret = bret && Injector.setFileAttr755(plugPath + "/plug.apk");
logMsg(bret ? "[√]插件APK部署成功" : "[×]插件APK部署失败");
bret = Injector.copyAssetsFileToDir("libplug.so", plugPath, this);
bret = bret && Injector.setFileAttr755(plugPath + "/libplug.so");
logMsg(bret ? "[√]部署插件SO成功" : "[×]部署插件SO失败");
//plugPath = "/data/data/com.netease.anep/app_plugin";
bret = Injector.setHookConfigFile(this, edt_packageName.getText().toString(), strTargetActivity,
"com.netease.ga.plug.PlugMain", plugPath + "/plug.apk", plugPath + "/libplug.so");
bret = bret && Injector.setFileAttr755(plugPath + "/config.cfg");
logMsg(bret ? "[√]HOOK配置文件部署成功" : "[×]HOOK配置文件部署失败");
logMsg("");
}
/**
* 设置log信息
*
* @param s
*/
public static void logMsg(String s) {
String strText = edt_log.getText().toString();
edt_log.setText(strText + s + "\n");
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (resultCode) {
case RESULT_OK:
String packageName = data.getExtras().getString("package");
String mainActivityClassName = null;
String topActivityClassName = null;
edt_packageName.setText(packageName);
//获取包名对应的主activity
PackageManager localPackageManager = this.getPackageManager();
try {
PackageInfo localPackageInfo = localPackageManager.getPackageInfo(packageName, 0);
Intent localIntent1 = new Intent("android.intent.action.MAIN", null);
localIntent1.addCategory("android.intent.category.LAUNCHER");
localIntent1.setPackage(localPackageInfo.packageName);
List localList = localPackageManager.queryIntentActivities(localIntent1, 0);
if (localList.iterator().hasNext()) {
ResolveInfo localResolveInfo = (ResolveInfo) localList.iterator().next();
mainActivityClassName = localResolveInfo.activityInfo.name;
mainActivityClassName = mainActivityClassName.replace('.', '/');
//完美点可以动态检查一下该类是否有onCreate方法实现,此处默认它是有的
//...
}
} catch (PackageManager.NameNotFoundException localNameNotFoundException) {
localNameNotFoundException.printStackTrace();
}
ActivityManager am = (ActivityManager) MainActivity.this.getSystemService(Activity.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> mRunningTasks = am.getRunningTasks(10);
for (ActivityManager.RunningTaskInfo runningTaskInfo : mRunningTasks) {
ComponentName cn = runningTaskInfo.topActivity;
String activityName = cn.getClassName();
if (activityName.indexOf(packageName) != -1) {
activityName = activityName.replace('.', '/');
topActivityClassName = activityName;
}
}
if (topActivityClassName == null) {
//说明目标程序当前没有运行,则默认使用启动类
strTargetActivity = mainActivityClassName;
logMsg("[乄]所选择的目标程序当前没有运行,默认使用LAUNCHER属性的Activity作为HOOK目标! 如果该Activity的生存周期很短,意味着插件也会很快消失。");
logMsg("靠谱的做法是先启动一次目标程序,进入到生存周期较长的页面,然后再点击“浏览”按钮,本程序会自动识别有效的Activity。");
} else {
//说明是从正在运行的程序列表中找到的目标类,最有效!
strTargetActivity = topActivityClassName;
logMsg("[√]目标程序已经运行,将自动识别HOOK目标的Activity! 识别成功后请杀死目标进程,然后点击“启动”按钮。");
}
logMsg("launcher:" + strTargetActivity);
edt_activity.setText(strTargetActivity);
SharedPreferences.Editor editor = sp.edit();
editor.putString("hookpackage", packageName);
editor.putString("launcherActivity", strTargetActivity);
editor.commit();
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
运行预览:
注入后重新运行目标程序,效果:
文档信息
- 本文作者:zhupite
- 本文链接:https://zhupite.com/android/xxzhushou-9.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)