4、叉叉助手逆向分析续集--模拟实现游戏插件框架--再扩展到脱壳机

这里以HOOK程序启动后调用天天星联盟为例,下面是2014年4月30日抠出来的天天星联盟插件APK代码:
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 UniversalUIextends RelativeLayout { private static String mSoPath; private static UniversalUI me = nullprivate 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 native void setqudao();private void show() { if (!this.mShow) { this.mShow = true; Log.d("native", "叉叉辅助已成功装载"); Toast.makeText(this.mContext, "叉叉辅助已成功装载", 1).show(); System.load(mSoPath); xxdohook(); } }private native void xxdohook(); }
测试只要把so加载和调用的部分去掉即可,反编译后去掉UniversalUI.smali的以下代码:

     .  line  40
     sget  -  object  v0  ,  Lcom  /  xxAssistant  /  UI  /  UniversalUI;  ->  mSoPath:Ljava  / lang  /  String;

    invoke  -  static  {  v0  },  Ljava  /  lang  /  System;  ->  load  (  Ljava  /  lang  /  String; )  V

     .  line  41
     invoke  -  direct  {  p0  },  Lcom  /  xxAssistant  /  UI  /  UniversalUI;  ->  xxdohook  ()  V

以及:
.  method  private  native  xxdohook  ()  V
.  end method

回编译后再次确认下:
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 UniversalUIextends RelativeLayout { private static String mSoPath; private static UniversalUI me = nullprivate 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 native void setqudao();private void show() { if (!this.mShow) { this.mShow = true; Log.d("native", "叉叉辅助已成功装载"); Toast.makeText(this.mContext, "叉叉辅助已成功装载", 1).show(); } } }

最后记得签名APK,然后把修改后的APK复制到项目工程的assets目录下:
运行时动态将这两个资源文件复制到app_plugin目录下,叉叉助手是把不同的插件以id分别放到app_plugin下的子目录中,我们仅作测试不再创建子目录。

运行效果:

点击“浏览”按钮选择要HOOK的APP:

选择后程序会自动分析其包名和启动Acitivity,然后点击“HOOK”按钮开始注入:

注入成功后便可以点击“启动”按钮运行刚刚选择的APP了:

程序界面上显示了叉叉助手插件TOAST出的信息。

由于界面上设置了动态可配置的包名,随意选择另外一个APP并启动:

也就是说这种方法具有通用性。

LOG信息输出到界面中也是为了方便查看,不用每次都去用LOGCAT等工具查看,原理是底层通过反射调用java层函数:
void LOGMSG(const char *lpszText) { LOGD("%s", lpszText); if ( g_context!=NULL ) { jclass jclazz = g_env->GetObjectClass(g_context); jmethodID logMsg = g_env->GetMethodID(jclazz, "logMsg""(Ljava/lang/String;)V"); if ( logMsg ) {//LOGD("found: logMsg"); jstring jstr = str2jstring(g_env, lpszText, strlen(lpszText), NULL); //LOGD("CallObjectMethod 1"); g_env->CallVoidMethod(g_context, logMsg, jstr); //LOGD("CallObjectMethod 2"); } } }
但是这个仅限于在当前进程中,一旦注入到其他进程中,这种方式就不行,可以考虑其他通信方式。


执行流程:
injectso把middle注入到父进程,middle启动时调用该函数。
/*
由于libandroidloader.so使用动态方式加载libsubstratedvm.so并获取MSJavaHookMethod进行调用会崩溃,
一定需要隐式链接:
LOCAL_LDLIBS := -L$(LOCAL_PATH) -llog -ldl libsubstratedvm.so
所以libandroidloader.so在加载前进程模块中一定要存在libsubstratedvm.so和libsubstrate.so,
因此需要先注入一个跳板模块(这里就是middle)来完成对以上两个so的加载,然后再加载libandroidloader.so,
这样libandroidloader.so在启动时它所需要的两个so都已经被加载完成了,就不会出现崩溃问题了。
*/
HOOK android/app/ActivityThread::handleBindApplication,这样当APP启动时就能触发到回调函数。
OnCallback_handleBindApplicaton
//参数二的形式为:android.app.ActivityThread@41683ec8 //参数三的形式为:AppBindData{appInfo=ApplicationInfo{4178ead0 com.huawei.ChnUnicomAutoReg}} //因此可以通过参数三的包名进行过滤
static void OnCallback_handleBindApplicaton(JNIEnv *jni, jobject jthis, jobject appBindData) { LOGD("[%s] begin", __FUNCTION__); string strName; strName = getObjectClassName(jni, appBindData); if ( (int)strName.size() > 0 ) { LOGD("[%s] class: %s", __FUNCTION__, strName.c_str()); } //读取hook配置信息,这里每次都要读,考虑到配置文件会发生变动 bool bSuccess = LoadConfig(g_cfg); if ( bSuccess==false ) { LOGE("[%s] load config failed", __FUNCTION__); }else//根据包名过滤,hook指定的apk//string::size_type position = strName.npos; if ( strName.find(g_cfg.strHostPackage)!=strName.npos ) {//是目标app LOGD("[%s] target apk running: %s", __FUNCTION__, g_cfg.strHostPackage.c_str());// //hook目标的activity的类加载以及onCreate //MSJavaHookClassLoad(jni, g_cfg.strHostActivity.c_str(), &OnCallback_JavaClassLoad, NULL);// //上下两块独立互不干扰,可以同时使用也可分开使用 // //简易脱壳机:可脱我们自己的壳,梆梆加固,爱加密,360加固保等// void * handle=dlopen("libdvm.so", RTLD_NOW); LOGD("handle:%p", handle); JNINativeMethod *dvm_dalvik_system_DexFile = (JNINativeMethod*)dlsym(handle, "dvm_dalvik_system_DexFile"); dvmCreateCstrFromString = (dvmCreateCstrFromStringPtr)dlsym(handle,"_Z23dvmCreateCstrFromStringPK12StringObject"); LOGD("dvmCreateCstrFromString:%p", dvmCreateCstrFromString); dvmRawDexFileOpen = (dvmRawDexFileOpenPtr)dlsym(handle,"_Z17dvmRawDexFileOpenPKcS0_PP10RawDexFileb"); dvmJarFileOpen = (dvmRawDexFileOpenPtr)dlsym(handle,"_Z14dvmJarFileOpenPKcS0_PP7JarFileb"); LOGD("dvmRawDexFileOpen:%p", dvmRawDexFileOpen); LOGD("dvmJarFileOpen:%p", dvmJarFileOpen); if ( dvmRawDexFileOpen ) { MSHookFunction(dvmRawDexFileOpen, newdvmRawDexFileOpen, &olddvmRawDexFileOpen); } if ( dvmJarFileOpen ) { MSHookFunction(dvmJarFileOpen, newdvmJarFileOpen, &olddvmJarFileOpen); } //dvmDexFileOpenPartial = (dvmDexFileOpenPartialPtr)dlsym(handle, "_Z21dvmDexFileOpenPartialPKviPP6DvmDex");//LOGD("dvmDexFileOpenPartial: %p", dvmDexFileOpenPartial); //if ( dvmDexFileOpenPartial ) { //MSHookFunction(dvmDexFileOpenPartial, newdvmDexFileOpenPartial, &olddvmDexFileOpenPartial); //}//dvmDexFileOpenPartial会调用dexFileParse,因此只需要hookdexFileParse即可。 dexFileParse = (dexFileParsePtr)dlsym(handle, "_Z12dexFileParsePKhji"); LOGD("dexFileParse: %p", dexFileParse); if ( dexFileParse ) { MSHookFunction(dexFileParse, newdexFileParse, &olddexFileParse); }if(dvm_dalvik_system_DexFile){ lookup(dvm_dalvik_system_DexFile, "openDexFile""([B)I", &openDexFile); LOGD("openDexFile:%p",openDexFile); MSHookFunction(openDexFile, newDalvik_dalvik_system_DexFile_openDexFile_bytearray, &oldDalvik_dalvik_system_DexFile_openDexFile_bytearray); lookup(dvm_dalvik_system_DexFile,"openDexFile""(Ljava/lang/String;Ljava/lang/String;I)I", &openDexFile); LOGD("openDexFile:%p",openDexFile); MSHookFunction(openDexFile, newDalvik_dalvik_system_DexFile_openDexFile, &oldDalvik_dalvik_system_DexFile_openDexFile); }// } } //继续原函数处理(*old_handleBindApplication)(jni, jthis, appBindData); LOGD("[%s] end", __FUNCTION__); }

当目标的启动类被加载时触发回调  OnCallback_JavaClassLoad 
//当类被加载时触发的回调函数 static void OnCallback_JavaClassLoad(JNIEnv *jni, jclass _class, void *arg) { LOGD("[%s] begin", __FUNCTION__); if (!g_cfg.IsValid()) { LOGE("[%s] hook config is not valid", __FUNCTION__); return; } jmethodID onCreate = jni->GetMethodID(_class, "onCreate""(Landroid/os/Bundle;)V"); if (onCreate == NULL) { LOGE("[%s] \"onCreate\" not found in class: %s", __FUNCTION__, g_cfg.strHostActivity.c_str()); return; } old_onCreate = NULL; LOGD("[%s] hook \"onCreate\"", __FUNCTION__); MSJavaHookMethod(jni, _class, onCreate, (void *) (&OnCallback_ClassOnCreate), (void **) (&old_onCreate)); if ( old_onCreate==NULL ) { LOGE("[%s] old_onCreate returned NULL", __FUNCTION__); } LOGD("[%s] end", __FUNCTION__); }
主要目的是HOOK onCreate函数,这样当启动类的  onCreate被调用时首先是进入到我们的hook函数:
//当类的onCreate调用时触发回调,动态加载插件apk并调用插件函数 /* ClassLoader localClassLoader = ClassLoader.getSystemClassLoader(); DexClassLoader localDexClassLoader = new DexClassLoader(dexpath, dexoutputpath, null, localClassLoader); 动态加载时参数dexOutputDir为/data/data/目标APK包名/app_dex,获取方法: getDir("dex",0).getAbsolutePath() 其他路径会失败,错误:optimizedDirectory not readable/writable:+路径; 参见:http://www.cnblogs.com/LittleRedPoint/p/3429709.html 由于app_dex目录默认是不存在的,需要动态创建以及修改文件夹权限,比较繁琐,这里直接使用cache目录。 old_onCreate在最开始调用了,所以后面的函数都可以不限制地调用return */ static voidOnCallback_ClassOnCreate(JNIEnv *jni, jobject activity, jobject bundle) { stringstrName; strName = getObjectClassName(jni, activity); LOGD("[%s] begin: %s::OnCreate", __FUNCTION__, strName.c_str()); (*old_onCreate)(jni, activity, bundle); LOGD("[%s] dynamic load plug apk", __FUNCTION__); if (!g_cfg.IsValid()){ LOGD("[%s] config invalid", __FUNCTION__); return; } jclass ClassLoader = jni->FindClass("java/lang/ClassLoader"); if ( ClassLoader==NULL ) { LOGE("[%s] not found: java/lang/ClassLoader", __FUNCTION__); return; } jmethodID getSystemClassLoader = jni->GetStaticMethodID(ClassLoader, "getSystemClassLoader""()Ljava/lang/ClassLoader;"); if ( getSystemClassLoader==NULL ) { LOGE("[%s] not found: getSystemClassLoader", __FUNCTION__); return; } jobject systemLoader = jni->CallStaticObjectMethod(ClassLoader, getSystemClassLoader); if ( systemLoader==NULL ) { LOGE("[%s] getSystemClassLoader() return NULL", __FUNCTION__); return; } jclass dexLoaderClass = jni->FindClass("dalvik/system/DexClassLoader"); if ( dexLoaderClass==NULL ) { LOGE("[%s] not found: dalvik/system/DexClassLoader", __FUNCTION__); return; } jmethodID initDexLoaderMethod = jni->GetMethodID(dexLoaderClass, "<init>""(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");if ( initDexLoaderMethod==NULL ) { LOGE("[%s] not found: dalvik/system/DexClassLoader::<init>", __FUNCTION__); return; } //注意这里必须是当前进程的目录,不能跨进程目录读写 string app_dex = "/data/data/" + g_cfg.strHostPackage +"/cache"; //LOGD("app_dex is %s", app_dex.c_str()); jstring apkPath = jni->NewStringUTF(g_cfg.strPlugApkPath.c_str()); jstring dexOutputDir = jni->NewStringUTF(app_dex.c_str()); jobject dexClassLoader = jni->NewObject(dexLoaderClass, initDexLoaderMethod, apkPath, dexOutputDir, NULL, systemLoader); //jni->DeleteLocalRef(apkPath); //jni->DeleteLocalRef(dexOutputDir);if ( dexClassLoader==NULL ) { LOGE("[%s] new DexClassLoader(...) return NULL", __FUNCTION__); return; } jmethodID loadClass = jni->GetMethodID(dexLoaderClass,"loadClass""(Ljava/lang/String;)Ljava/lang/Class;"); if ( loadClass==NULL ) { LOGE("[%s] not found: dalvik/system/DexClassLoader::loadClass", __FUNCTION__);return; } jstring javaClassName = jni->NewStringUTF(g_cfg.strPlugActivity.c_str()); jclass plugClass = (jclass)jni->CallObjectMethod(dexClassLoader, loadClass, javaClassName); //jni->DeleteLocalRef(apkPath); if ( plugClass==NULL ) { LOGE("[%s] DexClassLoader::loadClass not found class: %s", __FUNCTION__, g_cfg.strPlugActivity.c_str()); return; } //调用插件的静态函数init,原型:public static void init(Activity activity, String soPath) jmethodID plugUIinit = jni->GetStaticMethodID(plugClass, "init""(Landroid/app/Activity;Ljava/lang/String;)V");if ( plugUIinit==NULL ) { LOGE("[%s] not found \"init\" in plug activity: public static void init(Activity activity, String soPath)", __FUNCTION__); }else{ LOGD("[%s] invoke %s::init", __FUNCTION__, g_cfg.strPlugActivity.c_str()); jstring soPath = jni->NewStringUTF(g_cfg.strPlugSoPath.c_str()); jni->CallStaticVoidMethod(plugClass, plugUIinit, activity, soPath); //jni->DeleteLocalRef(soPath); } LOGD("[%s] end", __FUNCTION__); }
其实主要目的就是(  jni  ->  CallStaticVoidMethod(plugClass, plugUIinit, activity, soPath); )调用插件某类的静态函数,传给两个参数。
但是实现上确实比较繁琐。

运行效果就是开头的几张图。



引申到脱壳机:在外壳加载原始apk的过程中,会调用某些系统api,只要hook拦截下来并dump出相应的数据即可。
再回到OnCallback_handleBindApplicaton函数分析下半部分。

涉及到的:
ODEX转DEX的操作(参考 http://blog.csdn.net/asmcvc/article/details/39078421):
1、ODEX反编译:
java -jar baksmali.jar -x a.odex 

2、反编译结果再打包成DEX: 
java -Xmx512M -jar smali.jar out -o classes.dex 

3、DEX转JAR看源码。 

如果出现诸如以下错误:
odex转dex遇到的异常 Cannot locate boot class path file /system/framework/core.odex
请按照上面链接中的解决办法解决。

爱加密:
static char chCount = 0x30//dvmDexFileOpenPartial会调用dexFileParse,因此只需要HOOK dexFileParse即可。int newdvmDexFileOpenPartial(const void* addr, int len, void* ppDvmDex) { LOGD("[%s] begin", __FUNCTION__); int nret = olddvmDexFileOpenPartial(addr, len, ppDvmDex); string dexFileName = "/data/data/" + g_cfg.strHostPackage + "/cache/o.odex"; dexFileName.append(1, ++chCount); if ( saveFile(addr, len, dexFileName.c_str()) ) { int nret = chmod(dexFileName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); LOGD("[%s] dumped file: %s chmod return: %d error: %s", __FUNCTION__, dexFileName.c_str(), nret, dlerror()); } LOGD("[%s] end", __FUNCTION__); return nret; }


梆梆加固:
[newDalvik_dalvik_system_DexFile_openDexFile] sourceName: /data/data/com.mxy/.cache/  classes.jar outputName: /data/data/com.mxy/.cache/  classes.dex 
[newdvmJarFileOpen] fileName: /data/data/com.mxy/.cache/classes.jar odexOutputName: /data/data/com.mxy/.cache/classes.dex
[newdvmRawDexFileOpen] fileName: /data/data/com.example.helloapplication/app_bangcleplugin/container.dex odexOutputName: /data/data/com.example.helloapplication/app_outdex.container.e8b06f9b6317e8fc0c1ddeafd7f71664/container.dex 
[newdvmRawDexFileOpen] fileName: /data/data/com.example.helloapplication/app_bangcleplugin/collector.dex odexOutputName: /data/data/com.example.helloapplication/app_outdex.collector.f961d3dbc359c93741d5c63d553c0f57/collector.dex
void newDalvik_dalvik_system_DexFile_openDexFile(const u4* args, JValue* pResult) { LOGD("[%s] begin", __FUNCTION__); oldDalvik_dalvik_system_DexFile_openDexFile(args, pResult); StringObject* sourceNameObj = (StringObject*) args[0]; StringObject* outputNameObj = (StringObject*) args[1]; char* sourceName = NULL; char* outputName = NULL; if ( dvmCreateCstrFromString!=NULL ) { sourceName = dvmCreateCstrFromString(sourceNameObj); outputName = dvmCreateCstrFromString(outputNameObj); LOGD("[%s] sourceName: %s outputName: %s", __FUNCTION__, sourceName, outputName); //复制备份 if ( strstr(sourceName, "classes.jar")!=NULL ) { string dexFileName = "/data/data/" + g_cfg.strHostPackage + "/cache/classes.jar"; dexFileName.append(1, ++chCount); LOGD("[%s] backup file to: %s", __FUNCTION__, dexFileName.c_str()); copyFile(sourceName, dexFileName.c_str()); chmod(dexFileName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); LOGD("[%s] dumped file: %s", __FUNCTION__, dexFileName.c_str()); }/*else if ( strstr(sourceName, "collector.dex")!=NULL || strstr(sourceName, "container.dex")!=NULL ) { string dexFileName = "/data/data/" + g_cfg.strHostPackage + "/cache/out.dex"; dexFileName.append(1, ++chCount); LOGD("[%s] backup file to: %s", __FUNCTION__, dexFileName.c_str()); copyFile(sourceName, dexFileName.c_str()); }*/ } LOGD("[%s] end", __FUNCTION__); }


梆梆加固的被Dalvik_dalvik_system_DexFile_openDexFile拦截到时判断输入参数,如果sourceName包含classes.jar,则复制备份出来,这个classes.jar其实是一个zip包,里面只有一个文件:classes.dex,classes.dex可以使用三方工具转换成jar文件,就是目标的DEX。collector.dex和collector.dex备份出来后发现是插件。

360加固保:
360的需要HOOK函数dexFileParse,可以DUMP出ODEX,但是直接使用baksmali.jar操作会出错:
Error occurred while loading boot class path files. Aborting. 
org.jf.util.ExceptionWithContext: Cannot locate boot class path file /system/fra 
mework/core.odex 
        at org.jf.dexlib2.analysis.ClassPath.loadClassPathEntry(ClassPath.java:2 
17) 
        at org.jf.dexlib2.analysis.ClassPath.fromClassPath(ClassPath.java:161) 
        at org.jf.baksmali.baksmali.disassembleDexFile(baksmali.java:67) 
        at org.jf.baksmali.main.main(main.java:280) 

这个应该需要再额外设置一些东西,此处不再研究。综合一下,由于函数dvmDexFileOpenPartial内部也要调用dexFileParse,因此爱加密和360加固的脱壳方法一致,统一HOOK函数dexFileParse:
//dvmDexFileOpenPartial会调用dexFileParse,因此只需要HOOK dexFileParse即可。void* newdexFileParse(const u1* data, size_t length, int flags) { LOGD("[%s] begin", __FUNCTION__); void* nret = olddexFileParse(data, length, flags); string dexFileName = "/data/data/" + g_cfg.strHostPackage + "/cache/o.odex"; dexFileName.append(1, ++chCount); if ( saveFile(data, length, dexFileName.c_str()) ) { intnret = chmod(dexFileName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); LOGD("[%s] dumped file: %s chmod return: %d error: %s", __FUNCTION__, dexFileName.c_str(), nret, dlerror()); } LOGD("[%s] end", __FUNCTION__); return nret; }


我们自己的加壳程序:
//hook内存加载odex的函数void newDalvik_dalvik_system_DexFile_openDexFile_bytearray(const u4* args, JValue* pResult) { LOGD("[%s] begin", __FUNCTION__); ArrayObject* fileContentsObj = (ArrayObject*) args[0];string dexFileName = "/data/data/" + g_cfg.strHostPackage + "/cache/out.odex"; dexFileName.append(1, ++chCount); if ( saveFile(fileContentsObj->contents, fileContentsObj->length, dexFileName.c_str()) ) { chmod(dexFileName.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); LOGD("[%s] dumped file: %s", __FUNCTION__, dexFileName.c_str()); } LOGD("[%s] end", __FUNCTION__); oldDalvik_dalvik_system_DexFile_openDexFile_bytearray(args, pResult); }


其他应用场景:
API Monitor
APKScan可以基于此原理
代码已递交SVN,大家可以根据需要完善或修改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/350327.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

软考A计划-电子商务设计师-复习要点

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

安装mt工具箱离线版本

安装mt工具箱 如果安装成功&#xff0c;那么恭喜你&#xff0c;如果安装失败&#xff0c;请看我后面的。 mt2.0 离线包不建议安装了&#xff0c;主要是插件中心挂了&#xff0c;喜欢折腾的可以参照我的文档&#xff0c;不喜欢折腾的&#xff0c;就不要折腾了 后记&#xff1a…

MT平台下载

2007-09-28 14:12:50 MetaTrader 4 模拟/真实平台下载请下载()mt4setup.exe, 3.0mb文件到你的电脑&#xff0c;并按照映屏上的指示安装好。在你第一次使用这个平台的时候&#xff0c;你会见到一个自动弹出的注册表窗口&#xff0c;请你填好这个表格&#xff0c;然后系统就会马上…

叉叉助手停运有什么替代的_亚马逊全球开店助手将停止服务!卖家:终究是错付了...

最近&#xff0c;亚马逊可谓是新规频出。上个礼拜&#xff0c;亚马逊发布“自2020年9月1日开始&#xff0c;商家名称和地址将显示在卖家资料页面”上的通知。随后&#xff0c;后台的“销售业绩”版块也悄悄换至下图的位置&#xff0c;让卖家很不适应。 一系列突如其来的操作让卖…

6、XPOSED二、叉叉助手框架--用XPOSED实现

继《 xposed框架初探》之后&#xff0c;编写一个小小的demo应用&#xff0c;刚好之前分析叉叉的游戏辅助框架(参考《 叉叉助手逆向分析续集--模拟实现游戏插件框架--再扩展到脱壳机 》&#xff0c; 我们是用了libsubstrate的hook框架来完成的 )&#xff0c;这次就用XPOSED实现一…

2、叉叉助手逆向分析(上)

描述&#xff1a;主要讲解如何有条例地逆向分析出软件的主要逻辑。 工具&#xff1a;APKIDE&#xff0c;JD-GUI 方法&#xff1a;顺藤摸瓜&#xff0c;smali代码主要看invoke关键函数调用&#xff0c;定位到相应的类中看代码。 使用APKIDE反编译xxzhushou_android.apk。 各个游…

3、叉叉助手逆向分析(下)

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提取出来&#xff1a;com.babeltime.fknsango_360-1.apk&#xf…

android 我叫mt 插件,叉叉我叫MT助手

叉叉mt助手是我叫mt的安卓版辅助插件&#xff0c;提供加速、自动点箭头、自动点异常、自动售卡、买体力、一键收/送体力、副本计数等功能&#xff0c;只需要一键精英就已经OK&#xff0c;叉叉mt助手旨在为玩家节省时间&#xff0c;提高游戏效率&#xff0c;给玩家最贴心的服务&…

使用GCN根据颗粒图像预测对应性能

之前做一个小实验写的代码&#xff0c;本想创建个git repo&#xff0c;想了想好像没必要&#xff0c;直接用篇博文记录一下吧。 对应资源 &#xff1a; https://download.csdn.net/download/rayso9898/87865298 0. 大纲 0.1 代码说明 dataGeneration.py -> RSA生成n张图像&…

电表网关BL102采集DL/T645电表的操作步骤

使用钡铼BL102网关&#xff1a;西门子S7-200PLC对接ThingsBoard流程 本文主要讲述了钡铼技术BL102物联网网关如何通过RS485采集DL/T645规约电表 BL102是一款采集西门子、三菱、欧姆龙、台达、AB、施耐德等各种PLC数据转换为Modbus TCP、OPC UA、MQTT、ThingsBoard等协议的工业…

JAVA开发(神乎其神的区块链技术之数据上链)

这是我第二遍写关于区块链的博文&#xff0c;前一篇文章《神乎其神的区块链概念和技术》主要介绍区块链的由来和基本概念。因为博主最近在做一个区块链项目&#xff0c;所以有时候也遇到一些概念性的知识需要去理解&#xff0c;比如数据的上链。谈到数据上链&#xff0c;我们先…

OpenCV(图像处理)-基于Python-图像的基本变换-平移-翻转-仿射变换-透视变换

1. 概述2. 接口介绍resize()flip()rotate()仿射变换warpAffine()getRotationMatrix2D()-变换矩阵1getAffineTransform()-变换矩阵2 透视变换warpPerspective()getPerspectiveTransform() 1. 概述 为了方便开发人员的操作&#xff0c;OpenCV还提供了一些图像变换的API&#xff…

计算机改名字后找不到网络,改了wifi名字后电脑搜不到网络怎么办? | 192路由网...

问&#xff1a;为什么我改了wifi名字后&#xff0c;我的电脑就搜不到wifi信号了&#xff1f; 答&#xff1a;修改wifi名称后如果搜索不到wifi信号了&#xff0c;可以按照下面的步骤进行操作&#xff0c;以解决此问题。 1. 如果将wifi名字改成了中文&#xff0c;建议你将其修改为…

柠檬班python自动化百度云_柠字取名2019-尚名网

柠字取名2019-尚名网 名字不是一个简单、随便的称号&#xff0c;它隐含着不容忽视的信息力量。寓意好的名字有积极的暗示作用&#xff0c;使人更有信心和勇气去实现理想&#xff0c;寓意欠佳的名字反之。可见&#xff0c;名字对人们而言是非常重要的&#xff0c;为人父母者一定…

为了取一个花名,我爬下了中草药网所有的名字!

很酷哦&#xff01;不过&#xff0c;对我这个选择恐惧症来说&#xff0c;也很纠结…我们先看一下有哪些要求吧&#xff1f; 中草药名&#xff1f;人参&#xff1f;西洋参&#xff1f;还有啥&#xff1f;&#xff1f;&#xff1f; 作为一个不怎么吃药的非医学生&#xff0c;这题…

使用MySQL查找姓名重名_查询名字有多少人重名,全国同名同姓查询全国姓名数据库...

查询名字有多少人重名&#xff0c;全国同名同姓查询全国姓名数据库 时间&#xff1a;2020-04-04 15:30:01 很多爸爸妈妈在帮孩子取姓名的时候&#xff0c;会想了解在全国范围内重名的人数&#xff0c;希望宝宝的名字不会跟太多人一样。或者有的小伙伴单纯想弄明白全中国同自己姓…

百度排名优化工具 V3.0 正式版

介绍 百度排名优化工具正式版是款可以迅速提升网址百度搜索排名的工具。软件拥有智能计算关键词点击数&#xff0c;点击规则自动添加等。软件还提供了维护模式&#xff0c;自动维护您的关键词排名&#xff0c;让您的关键词排名更加稳定可靠。百度排名优化工具可以将你的网站在…

给Android系统瘦身,安卓优化大师:给系统瘦身

安卓优化大师是一款基于Android平台的系统优化软件&#xff0c;最新版本界面设计简单&#xff0c;功能全面&#xff0c;可以帮助Android手机用户给系统瘦身&#xff0c;优化手机性能。 程序名称&#xff1a;安卓优化大师 平台&#xff1a;Android 类型&#xff1a;系统优化 软件…

Windows优化大师7.96版下载

Windows优化大师提供了全面且有效而简便安全的系统检测、系统优化、系统清理、系统维护四大功能模块以及数个附加的工具软件。它能够有效地帮助用户了解自己的计算机软硬件信息&#xff1b;简化操作系统设置步骤&#xff1b;提升计算机运行效率&#xff1b;清理系统运行时产生的…

SEO优化工具-免费SEO优化工具下载-SEO优化工具大全中心

什么是SEO优化工具&#xff1f;SEO优化工具&#xff08;Seo tools&#xff09;能在搜索引擎优化过程中起到辅助的作用&#xff0c;如数据查询工具、网站排名工具、网站流量分析功能&#xff0c;站群管理工具等&#xff0c;用来提高每个SEO人员工作中的效率。 seo优化工具&#…