①继续分析插件,上面分析到插件的存放目录在“/data/data/com.xxAssistant/app_plugin/”下,ls查看目录列表:
ls
103
111
117
120
每个插件有一个插件id,进入每个插件id的目录下查看文件组织形式。
/data/data/com.xxAssistant/app_plugin/120 # ls
com.yodo1tier1.ido360.SkiSafari.xxplist
libxxHuaxue.so
xxHuaXue.apk
滑雪大冒险的插件id是120,里面有三个文件,分别pull出来,其中com.yodo1tier1.ido360.SkiSafari.xxplist:
--game-name:com.yodo1tier1.ido360.SkiSafari
--apk-path:/data/data/com.xxAssistant/app_plugin/120/xxHuaXue.apk
--ui-name:com.xxAssistant.UI.xxMain
--activity-name:com/example/werk_lock/MainActivity
--so-path:/data/data/com.xxAssistant/app_plugin/120/libxxHuaxue.so
放开那三国分析:
adb pull /data/data/com.xxAssistant/app_plugin/117/com.babeltime.fknsango_360.xxplist e:\com.babeltime.fknsango_360.xxplist
adb pull /data/data/com.xxAssistant/app_plugin/117/com.babeltime.fknsango_91.xxplist e:\com.babeltime.fknsango_91.xxplist
adb pull /data/data/com.xxAssistant/app_plugin/117/com.babeltime.fknsango_uc.xxplist e:\com.babeltime.fknsango_uc.xxplist
adb pull /data/data/com.xxAssistant/app_plugin/117/com.babletimes.fknsango.wdj.xxplist e:\com.babletimes.fknsango.wdj.xxplist
adb pull /data/data/com.xxAssistant/app_plugin/117/libxxfknsg.so e:\libxxfknsg.so
adb pull /data/data/com.xxAssistant/app_plugin/117/xxFknsg.apk e:\xxFknsg.apk
其中com.babeltime.fknsango_360.xxplist:
--game-name:com.babeltime.fknsango_360
--apk-path:/data/data/com.xxAssistant/app_plugin/117/xxFknsg.apk
--ui-name:com/xxAssistant/FknsgUI/xxMain
--activity-name:com/babeltimes/main/MainActivity
--so-path:/data/data/com.xxAssistant/app_plugin/117/libxxfknsg.so
我们将手机里的apk提取出来:com.babeltime.fknsango_360-1.apk,分析xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="3"
android:versionName="1.1.8"
android:installLocation="0"
package="com.babeltime.fknsango_360"
>
<supports-screens
android:anyDensity="true"
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:resizeable="true"
>
</supports-screens>
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17"
>
</uses-sdk>
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE"
>
</uses-permission>
……
<uses-permission
android:name="android.permission.VIBRATE"
>
</uses-permission>
<application
android:theme="@7F060001"
android:label="@7F050000"
android:icon="@7F020000"
android:allowBackup="true"
>
<activity
android:theme="@android:01030007"
android:label="@7F050000"
android:name="com.babeltimes.main.MainActivity"
android:screenOrientation="1"
android:configChanges="0x00000080"
>
<intent-filter
>
<action
android:name="android.intent.action.MAIN"
>
</action>
<category
android:name="android.intent.category.LAUNCHER"
>
</category>
</intent-filter>
</activity>
<activity
android:theme="@android:01030007"
android:label="@7F050000"
android:name="com.babeltimes.main.CrashHandler"
android:screenOrientation="1"
android:configChanges="0x00000080"
>
<intent-filter
>
<category
android:name="android.intent.category.LAUNCHER"
>
</category>
</intent-filter>
</activity>
<activity
android:theme="@android:01030010"
android:name="com.qihoopay.insdk.activity.ContainerActivity"
android:configChanges="0x400006E4"
>
</activity>
<activity
android:theme="@android:01030010"
android:name="com.qihoopp.qcoinpay.QcoinActivity"
android:configChanges="0x400006E4"
android:windowSoftInputMode="0x00000013"
>
</activity>
<meta-data
android:name="QHOPENSDK_APPID"
android:value="200983446"
>
</meta-data>
……
<meta-data
android:name="QHOPENSDK_CHANNEL"
android:value="default"
>
</meta-data>
<activity
android:theme="@7F060015"
android:name="cn.paypalm.pppayment.InitialAct"
android:screenOrientation="3"
android:configChanges="0x000004A0"
android:windowSoftInputMode="0x00000003"
>
</activity>
……
<activity
android:theme="@7F060015"
android:name="cn.paypalm.pppayment.BankcardAgreement"
android:screenOrientation="3"
android:configChanges="0x000004A0"
android:windowSoftInputMode="0x00000003"
>
</activity>
</application>
</manifest>
可以看出:
game-name为游戏包名,
apk-path为插件全路径
ui-name为插件界面
activity-name为游戏启动activity
so-path为插件so库全路径
再分析插件xxFknsg.apk:
<?xml version="1.0" encoding="utf-8"?><manifest android:versionCode="1" android:versionName="1.0" package="com.xxAssistant.FknsgUI"
xmlns:android="http://schemas.android.com/apk/res/android">
<application android:theme="@style/AppTheme" android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:debuggable="true" android:allowBackup="true">
<activity android:label="@string/app_name" android:name="com.xxAssistant.FknsgUI.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Application是没有name标签的,activity:com.xxAssistant.FknsgUI.MainActivity:
package com.xxAssistant.FknsgUI;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
public class MainActivity extends Activity
{
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130903040);
xxMain.init(this, null);
}
public boolean onCreateOptionsMenu(Menu paramMenu)
{
getMenuInflater().inflate(2131165184, paramMenu);
return true;
}
}
插件的MainActivity只是调用了一个xxMain.init,查看xxMain.class:
package com.xxAssistant.FknsgUI;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout.LayoutParams;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
import com.xxAssistant.FknsgUI.bg.ShapeBg;
public class xxMain
{
public static String TITLE = "叉叉放开那三国助手 1.0.0";
public static String mSoPath = null;
private static xxMain me = null;
private xxAbout mAboutView;
private Activity mActivity;
private float mDp;
private RelativeLayout.LayoutParams mRlparams;
private ViewGroup mRootView;
private xxSettingView mSettingView;
public xxMain(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);
for (xxMain localxxMain = new xxMain(paramActivity); ; localxxMain = me)
{
me = localxxMain;
me.show();
return;
}
}
private void initNativeFunC()
{
if (mSoPath != null)
xxUtility.init(this.mActivity, mSoPath);
}
private void initView()
{
this.mSettingView = new xxSettingView(this.mActivity, this.mRootView);
this.mAboutView = new xxAbout(this.mActivity, this.mRootView);
this.mAboutView.setXXVersionString(TITLE);
LinearLayout localLinearLayout = new LinearLayout(this.mActivity);
localLinearLayout.setOrientation(1);
ShapeBg localShapeBg = new ShapeBg(this.mActivity);
localShapeBg.setColor(-16777216);
localShapeBg.setCornerRadii(new float[] { 4.0F, 0.0F, 0.0F, 4.0F });
localLinearLayout.setBackgroundDrawable(localShapeBg);
localLinearLayout.getBackground().setAlpha(153);
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(-2, -2);
localLayoutParams.addRule(11);
localLayoutParams.addRule(15);
LinearLayout.LayoutParams localLayoutParams1 = new LinearLayout.LayoutParams(-2, -2);
TextView localTextView1 = new TextView(this.mActivity);
localTextView1.setText("设置");
localTextView1.setTextSize(16.0F);
localTextView1.setTextColor(-1);
LinearLayout.LayoutParams localLayoutParams2 = new LinearLayout.LayoutParams(-2, -2);
TextView localTextView2 = new TextView(this.mActivity);
localTextView2.setText("叉叉");
localTextView2.setTextSize(16.0F);
localTextView2.setTextColor(-16711936);
localLayoutParams2.topMargin = ((int)(5.0F * this.mDp));
localLinearLayout.addView(localTextView1, localLayoutParams1);
localLinearLayout.addView(localTextView2, localLayoutParams2);
this.mRootView.addView(localLinearLayout, localLayoutParams);
this.mRlparams = new RelativeLayout.LayoutParams(-1, -1);
this.mRlparams.addRule(11);
this.mRlparams.addRule(15);
localTextView1.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
xxMain.this.mRootView.removeView(xxMain.this.mAboutView);
xxMain.this.mRootView.removeView(xxMain.this.mSettingView);
xxMain.this.mRootView.addView(xxMain.this.mSettingView, xxMain.this.mRlparams);
}
});
localTextView2.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramAnonymousView)
{
xxMain.this.mRootView.removeView(xxMain.this.mAboutView);
xxMain.this.mRootView.removeView(xxMain.this.mSettingView);
xxMain.this.mRootView.addView(xxMain.this.mAboutView, xxMain.this.mRlparams);
}
});
}
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();
}
}
package com.xxAssistant.FknsgUI;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.ScrollView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import com.xxAssistant.FknsgUI.bg.ShapeBg;
public class xxSettingView extends RelativeLayout
{
private static int MAX;
private static int mSpeed = 0;
private Activity mActivity;
private float mDp;
private ViewGroup mParent;
private LinearLayout mRealSettingView;
private RelativeLayout mSettingView;
static
{
MAX = 100;
}
public xxSettingView(Activity paramActivity, ViewGroup paramViewGroup)
{
super(paramActivity);
this.mActivity = paramActivity;
this.mParent = paramViewGroup;
this.mSettingView = this;
DisplayMetrics localDisplayMetrics = new DisplayMetrics();
this.mActivity.getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
this.mDp = localDisplayMetrics.density;
initView();
}
private void initView()
{
this.mSettingView.setGravity(17);
this.mSettingView.setBackgroundColor(-16777216);
this.mSettingView.getBackground().setAlpha(80);
this.mRealSettingView = new LinearLayout(this.mActivity);
this.mRealSettingView.setOrientation(1);
this.mRealSettingView.setGravity(1);
int i = (int)(16.0F * this.mDp);
this.mRealSettingView.setPadding(i, i, i, i);
ShapeBg localShapeBg1 = new ShapeBg(this.mActivity);
localShapeBg1.setCornerRadius(8.0F);
localShapeBg1.setColor(-16777216);
localShapeBg1.setStroke(1, -1);
this.mRealSettingView.setBackgroundDrawable(localShapeBg1);
this.mRealSettingView.getBackground().setAlpha(153);
RelativeLayout.LayoutParams localLayoutParams = new RelativeLayout.LayoutParams((int)(300.0F * this.mDp), -2);
this.mSettingView.addView(this.mRealSettingView, localLayoutParams);
TextView localTextView1 = new TextView(this.mActivity);
localTextView1.setText("设置");
localTextView1.setTextSize(22.0F);
localTextView1.setTextColor(-1);
localTextView1.setGravity(1);
this.mRealSettingView.addView(localTextView1);
ScrollView localScrollView = new ScrollView(this.mActivity);
localScrollView.setScrollBarStyle(0);
LinearLayout localLinearLayout1 = new LinearLayout(this.mActivity);
localLinearLayout1.setOrientation(1);
LinearLayout localLinearLayout2 = new LinearLayout(this.mActivity);
LinearLayout localLinearLayout3 = new LinearLayout(this.mActivity);
ShapeBg localShapeBg2 = new ShapeBg(this.mActivity);
localShapeBg2.setCornerRadius(10.0F);
localShapeBg2.setColor(-1);
localLinearLayout2.setBackgroundDrawable(localShapeBg2);
localLinearLayout3.setBackgroundDrawable(localShapeBg2);
(int)(6.0F * this.mDp);
LinearLayout.LayoutParams localLayoutParams1 = new LinearLayout.LayoutParams(-1, -2);
localLayoutParams1.topMargin = (int)(8.0F * this.mDp);
this.mRealSettingView.addView(localScrollView, localLayoutParams1);
localScrollView.addView(localLinearLayout1);
TextView localTextView2 = new TextView(this.mActivity);
localTextView2.setText("游戏加速:0 倍");
localTextView2.setTextColor(-1);
localTextView2.setTextSize(17.0F);
localTextView2.setGravity(14);
SeekBar localSeekBar = new SeekBar(this.mActivity);
localSeekBar.setMinimumHeight(2 * (int)this.mDp);
localLinearLayout1.addView(localTextView2, localLayoutParams1);
localLinearLayout1.addView(localSeekBar, localLayoutParams1);
localSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(localTextView2)
{
public void onProgressChanged(SeekBar paramSeekBar, int paramInt, boolean paramBoolean)
{
xxSettingView.mSpeed = paramInt * (xxSettingView.MAX / 100);
this.val$tittle.setText("游戏加速:" + xxSettingView.mSpeed + " 倍");
if (xxSettingView.mSpeed == 0);
for (int i = 1000; ; i = 1000 * xxSettingView.mSpeed)
{
xxUtility.setTimeScale(i);
return;
}
}
public void onStartTrackingTouch(SeekBar paramSeekBar)
{
}
public void onStopTrackingTouch(SeekBar paramSeekBar)
{
}
});
this.mSettingView.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View paramView, MotionEvent paramMotionEvent)
{
float f1 = paramMotionEvent.getX();
float f2 = paramMotionEvent.getY();
float f3 = xxSettingView.this.mRealSettingView.getLeft();
float f4 = xxSettingView.this.mRealSettingView.getTop();
float f5 = xxSettingView.this.mRealSettingView.getBottom();
float f6 = xxSettingView.this.mRealSettingView.getRight();
switch (paramMotionEvent.getAction())
{
default:
return false;
case 0:
}
if ((f1 < f3) || (f1 > f6));
while (true)
{
xxSettingView.this.mParent.removeView(xxSettingView.this.mSettingView);
return false;
if (f2 < f4)
continue;
if (f2 <= f5)
break;
}
}
});
}
}
package com.xxAssistant.FknsgUI;
import android.app.Activity;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
import com.xxAssistant.FknsgUI.bg.ShapeBg;
public class xxAbout extends RelativeLayout
{
private RelativeLayout mAbout;
private Activity mActivity;
private float mDp;
private ViewGroup mParent;
private LinearLayout mRealAbout;
private TextView mTvContent;
private TextView mTvTitle;
public xxAbout(Activity paramActivity, ViewGroup paramViewGroup)
{
super(paramActivity);
this.mActivity = paramActivity;
this.mParent = paramViewGroup;
this.mAbout = this;
DisplayMetrics localDisplayMetrics = new DisplayMetrics();
this.mActivity.getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
this.mDp = localDisplayMetrics.density;
initView();
}
private void initView()
{
this.mAbout.setGravity(17);
this.mAbout.setBackgroundColor(-16777216);
this.mAbout.getBackground().setAlpha(0);
this.mRealAbout = new LinearLayout(this.mActivity);
this.mRealAbout.setOrientation(1);
this.mRealAbout.setGravity(1);
ShapeBg localShapeBg1 = new ShapeBg(this.mActivity);
localShapeBg1.setCornerRadius(8.0F);
localShapeBg1.setColor(-16777216);
localShapeBg1.setStroke(1, -1);
this.mRealAbout.setBackgroundDrawable(localShapeBg1);
this.mRealAbout.getBackground().setAlpha(153);
int i = (int)(16.0F * this.mDp);
this.mRealAbout.setPadding(i, i, i, i);
RelativeLayout.LayoutParams localLayoutParams = new RelativeLayout.LayoutParams((int)(300.0F * this.mDp), (int)(150.0F * this.mDp));
this.mAbout.addView(this.mRealAbout, localLayoutParams);
this.mTvTitle = new TextView(this.mActivity);
this.mTvTitle.setTextSize(22.0F);
this.mTvTitle.setText("关于");
this.mTvTitle.setTextColor(-1);
this.mTvTitle.setGravity(17);
this.mRealAbout.addView(this.mTvTitle);
this.mTvContent = new TextView(this.mActivity);
ShapeBg localShapeBg2 = new ShapeBg(this.mActivity);
localShapeBg2.setCornerRadius(6.0F);
localShapeBg2.setColor(-1);
this.mTvContent.setBackgroundDrawable(localShapeBg2);
this.mTvContent.setTextColor(-16777216);
this.mTvContent.setTextSize(18.0F);
int j = (int)(4.0F * this.mDp);
this.mTvContent.setPadding(j, j, j, j);
this.mTvContent.setGravity(3);
LinearLayout.LayoutParams localLayoutParams1 = new LinearLayout.LayoutParams(-1, -2);
localLayoutParams1.topMargin = (int)(20.0F * this.mDp);
this.mRealAbout.addView(this.mTvContent, localLayoutParams1);
TextView localTextView = new TextView(this.mActivity);
localTextView.setText("隐藏界面");
localTextView.setTextColor(-16711936);
LinearLayout.LayoutParams localLayoutParams2 = new LinearLayout.LayoutParams(-2, -2);
localLayoutParams2.topMargin = (int)(20.0F * this.mDp);
localLayoutParams2.gravity = 5;
this.mRealAbout.addView(localTextView, localLayoutParams2);
localTextView.setOnClickListener(new View.OnClickListener()
{
public void onClick(View paramView)
{
AlertDialog.Builder localBuilder = new AlertDialog.Builder(xxAbout.this.mActivity);
localBuilder.setMessage("警告:界面隐藏后,只能在下次游戏启动时再次出现,请确认是否执行该操作。");
localBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface paramDialogInterface, int paramInt)
{
xxAbout.this.mParent.removeAllViews();
}
});
localBuilder.setNegativeButton("取消", null);
localBuilder.show();
}
});
this.mAbout.setOnTouchListener(new View.OnTouchListener()
{
public boolean onTouch(View paramView, MotionEvent paramMotionEvent)
{
float f1 = paramMotionEvent.getX();
float f2 = paramMotionEvent.getY();
float f3 = xxAbout.this.mRealAbout.getLeft();
float f4 = xxAbout.this.mRealAbout.getTop();
float f5 = xxAbout.this.mRealAbout.getBottom();
float f6 = xxAbout.this.mRealAbout.getRight();
switch (paramMotionEvent.getAction())
{
default:
return false;
case 0:
}
if ((f1 < f3) || (f1 > f6));
while (true)
{
xxAbout.this.mParent.removeView(xxAbout.this.mAbout);
return false;
if (f2 < f4)
continue;
if (f2 <= f5)
break;
}
}
});
}
public void setXXVersionString(String paramString)
{
this.mTvContent.setText(paramString);
}
}
其中xxUtility.setTimeScale在xxUtility中:
package com.xxAssistant.FknsgUI;
import android.app.Activity;
public class xxUtility
{
public static Activity mActivity;
private static boolean mIsInitOk = false;
private static native void doSetTimeScale(int paramInt);
public static void init(Activity paramActivity, String paramString)
{
mActivity = paramActivity;
if (paramString != null)
{
System.load(paramString);
mIsInitOk = xxdohook();
}
}
public static void setTimeScale(int paramInt)
{
if (mIsInitOk)
doSetTimeScale(paramInt);
}
private static native boolean xxdohook();
}
加载对应的插件目录下的libxxfknsg.so:
对gettimeofday和clock_gettime做一些hook,然后通过xxUtility::setTimeScale加速设置加速倍数。
再分析“天天星连萌”的插件:
package com.xxAssistant.UI;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.widget.RelativeLayout;
import android.widget.Toast;
public class UniversalUI extends RelativeLayout
{
private static String mSoPath;
private static UniversalUI me = null;
private Activity mActivity;
private Context mContext;
private boolean mShow;
private UniversalUI(Activity paramActivity)
{
super(paramActivity);
this.mContext = paramActivity;
this.mActivity = paramActivity;
this.mShow = false;
}
public static void init(Activity paramActivity, String paramString)
{
if (me == null);
for (UniversalUI localUniversalUI = new UniversalUI(paramActivity); ; localUniversalUI = me)
{
me = localUniversalUI;
mSoPath = paramString;
me.show();
return;
}
}
private void show()
{
if (!this.mShow)
{
this.mShow = true;
Log.d("native", "叉叉辅助已成功装载");
Toast.makeText(this.mContext.getApplicationContext(), "叉叉辅助已成功装载1111111111111111111111111111111111", 1).show();
System.load(mSoPath);
xxdohook();
}
}
private native void xxdohook();
}
可以看出都有一个静态的init函数,插桩修改打印参数:
.class public Lcom/xxAssistant/UI/UniversalUI;
.super Landroid/widget/RelativeLayout;
.source "UniversalUI.java"
# static fields
.field private static mSoPath:Ljava/lang/String;
.field private static me:Lcom/xxAssistant/UI/UniversalUI;
# instance fields
.field private mActivity:Landroid/app/Activity;
.field private mContext:Landroid/content/Context;
.field private mShow:Z
# direct methods
.method static constructor <clinit>()V
.locals 1
.prologue
.line 12
const/4 v0, 0x0
sput-object v0, Lcom/xxAssistant/UI/UniversalUI;->me:Lcom/xxAssistant/UI/UniversalUI;
.line 17
return-void
.end method
.method private constructor <init>(Landroid/app/Activity;)V
.locals 1
.parameter "activity"
.prologue
.line 20
invoke-direct {p0, p1}, Landroid/widget/RelativeLayout;-><init>(Landroid/content/Context;)V
.line 22
iput-object p1, p0, Lcom/xxAssistant/UI/UniversalUI;->mContext:Landroid/content/Context;
.line 23
iput-object p1, p0, Lcom/xxAssistant/UI/UniversalUI;->mActivity:Landroid/app/Activity;
.line 24
const/4 v0, 0x0
iput-boolean v0, p0, Lcom/xxAssistant/UI/UniversalUI;->mShow:Z
#debug by sing
const-string v0, "MODBYSING"
invoke-virtual {p1}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v0, v1}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
#debug by sing
.line 25
return-void
.end method
.method public static init(Landroid/app/Activity;Ljava/lang/String;)V
.locals 1
.parameter "activity"
.parameter "soPath"
.prologue
.line 29
sget-object v0, Lcom/xxAssistant/UI/UniversalUI;->me:Lcom/xxAssistant/UI/UniversalUI;
if-nez v0, :cond_0
new-instance v0, Lcom/xxAssistant/UI/UniversalUI;
invoke-direct {v0, p0}, Lcom/xxAssistant/UI/UniversalUI;-><init>(Landroid/app/Activity;)V
:goto_0
sput-object v0, Lcom/xxAssistant/UI/UniversalUI;->me:Lcom/xxAssistant/UI/UniversalUI;
.line 30
sput-object p1, Lcom/xxAssistant/UI/UniversalUI;->mSoPath:Ljava/lang/String;
.line 31
sget-object v0, Lcom/xxAssistant/UI/UniversalUI;->me:Lcom/xxAssistant/UI/UniversalUI;
invoke-direct {v0}, Lcom/xxAssistant/UI/UniversalUI;->show()V
.line 32
return-void
.line 29
:cond_0
sget-object v0, Lcom/xxAssistant/UI/UniversalUI;->me:Lcom/xxAssistant/UI/UniversalUI;
goto :goto_0
.end method
.method private show()V
.locals 3
.prologue
const/4 v2, 0x1
.line 35
iget-boolean v0, p0, Lcom/xxAssistant/UI/UniversalUI;->mShow:Z
if-nez v0, :cond_0
.line 36
iput-boolean v2, p0, Lcom/xxAssistant/UI/UniversalUI;->mShow:Z
.line 38
const-string v0, "native"
const-string v1, "\u53c9\u53c9\u8f85\u52a9\u5df2\u6210\u529f\u88c5\u8f7d"
invoke-static {v0, v1}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
.line 39
iget-object v0, p0, Lcom/xxAssistant/UI/UniversalUI;->mContext:Landroid/content/Context;
invoke-virtual {v0}, Landroid/content/Context;->getApplicationContext()Landroid/content/Context;
move-result-object v0
const-string v1, "\u53c9\u53c9\u8f85\u52a9\u5df2\u6210\u529f\u88c5\u8f7d1111111111111111MODBYSING"
invoke-static {v0, v1, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
move-result-object v0
invoke-virtual {v0}, Landroid/widget/Toast;->show()V
.line 40
sget-object v0, Lcom/xxAssistant/UI/UniversalUI;->mSoPath:Ljava/lang/String;
#debug by sing
const-string v1, "MODBYSING"
invoke-static {v1,v0} ,Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
#debug by sing
invoke-static {v0}, Ljava/lang/System;->load(Ljava/lang/String;)V
.line 41
invoke-direct {p0}, Lcom/xxAssistant/UI/UniversalUI;->xxdohook()V
.line 43
:cond_0
return-void
.end method
.method private native xxdohook()V
.end method
此插件实现的效果是任意消除,捕获的log信息:
04-09 15:46:23.770: V/MODBYSING(13478): com.tencent.lian.MiniGame@41c711a8
04-09 15:46:23.800: V/MODBYSING(13478): /data/data/com.xxAssistant/app_plugin/105/libxxlianmeng_mm.so
实际运行中MainActivity::onCreate并没有执行(单独直接运行APK会执行,仅仅方便开发使用,具体启动游戏时插件的运行逻辑中不会执行到MainActivity::onCreate),证实Activity确实是游戏的主Activity。
再看插件so文件导出的xxdohook函数,Java_com_xxAssistant_UI_UniversalUI_xxdohook:
函数内部调用了do_hook:
调用了MSHookFunction(libSubstrate.so提供的函数)来hook原游戏libGameApp.so中的函数。
下面把插件APK直接安装运行,这个是滑雪大冒险的插件运行效果图:
可以看出和启动游戏后的插件显示效果类似,只不过单独运行时只是一个hello world的界面。
综合以上分析猜测:
所有插件按照一定格式编写,需要有一个.xxplist配置文件,一个可以安装运行的APK(可以直接安装运行是为了方便插件的开发),如果有做底层hook操作的还会有一个so文件。
.xxplist配置文件的内容格式如下:
game-name为游戏包名,
apk-path为插件全路径
ui-name为插件界面
activity-name为游戏启动activity
so-path为插件so库全路径
叉叉助手游戏列表中保存有插件id,点击“启动游戏”时按照item对应的插件id加载创建目录对应的插件apk,启动规则是按照插件目录下的.xxplist配置文件来的。
叉叉助手在运行时会做一次注入操作,在叉叉助手里启动游戏时,将相应的插件配置文件重定向到一个plist.xx的公共配置文件,由于做了注入,处于底层的监控层监控到游戏启动时判断当前的activity的包名是否和配置文件中的包名吻合,如果吻合说明当前游戏和当前插件匹配,则通过配置文件读取插件apk并动态加载,并调用一个静态的init函数,传递参数为:参数1是游戏的activity启动实例,参数2为配置文件中的插件so库文件路径。init函数完成插件的界面配置,显示为游戏界面上的悬浮窗口,加载so库并调用so的导出函数进行hook操作。
待研究内容:
1、libsubstrate的hook框架。
2、验证:注入后如何监控游戏的启动并加载插件。
文档信息
- 本文作者:zhupite
- 本文链接:https://zhupite.com/android/xxzhushou-3.html
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)