原理很简单 就是hook c++一个函数,将hook到的lua代码保存到手机内存卡中。咱们这个思路主要是参考gh助手的思路。
进入主题 写一个插件类Plugin.java
package com.gh.assist; import android.app.Activity; public class Plugin { public static boolean isload = false; public static void init(Activity paramActivity) { SoManager.setOnAfterLoadListener(new SoManager.afterLoadListener() { public void onAfterLoad(String paramAnonymousString) { Plugin.isload = true; System.out.println("加载完成==="+paramAnonymousString); } }); if (!isload) { SoManager.load(paramActivity); return; } } }
so管理类SoManager
package com.gh.assist; import java.io.File; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; @SuppressLint({ "DefaultLocale" }) public class SoManager { public static Activity S_ACTIVITY; public static String game; public static afterLoadListener mafterLoadListener; public static String pluinName; public static String[] soFiles = { "libsubstrate.so", "libygrdjh_cocos_v2_0224.so" }; public static String soPath1; public static String soPath2; public static native void apply(Context paramContext, int paramInt); public static String getApplicationName(Activity paramActivity) { try { String applicationName = paramActivity.getApplicationContext().getPackageManager().getApplicationInfo(paramActivity.getPackageName(), 0).packageName; return applicationName; } catch (PackageManager.NameNotFoundException e) { } return null; } public static String getfilePath(Activity paramActivity, String paramString) { String filePath = paramActivity.getFilesDir().getAbsolutePath() + "/gh"; File localFile = new File(filePath); if (!localFile.exists()) { localFile.mkdirs(); } return paramActivity + "/" + paramString; } public static String getfileLibPath(Activity paramActivity, String paramString) { String filePath = paramActivity.getApplicationInfo().dataDir + "/lib"; File localFile = new File(filePath); if (!localFile.exists()) { localFile.mkdirs(); } return filePath + "/" + paramString; } public static void init() { // copyFiles(S_ACTIVITY); System.out.println("初始化....."); soPath1 = getfileLibPath(S_ACTIVITY, soFiles[0]); soPath2 = getfileLibPath(S_ACTIVITY, soFiles[1]); System.out.println(soPath1); System.out.println(soPath2); System.out.println("初始化完成....."); loadLib(); } public static native boolean isNormalVersion(); public static native boolean isShowSubPanel(); public static void load(Activity paramActivity) { S_ACTIVITY = paramActivity; init(); } public static native String stringFromJNI(); public static void loadLib() { System.loadLibrary("substrate"); System.loadLibrary("ygrdjh_cocos_v2_0224"); //System.load(soPath1); //System.load(soPath2); // apply(S_ACTIVITY, 1); mafterLoadListener.onAfterLoad(pluinName); String str = stringFromJNI(); System.out.println("*****str:" + str); } public static void setOnAfterLoadListener(afterLoadListener paramafterLoadListener) { mafterLoadListener = paramafterLoadListener; } public static abstract interface afterLoadListener { public abstract void onAfterLoad(String paramString); } }
这不是最终的需要用的,我们需要用到的是将此类编译后获取到smali
工具 apktool b xxxx.apk
以上为加载我们自己的注入so做准备
下面书写so相关逻辑
#include"ygrdjh_cocos.h" #include <string.h> #include <jni.h> #include "substrate.h" #include <android/log.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #define TAG "HOOKTEST" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) /* #define MAXLEN 100 int ReplaceStr(char *sSrc, char *sMatchStr, char *sReplaceStr) { int StringLen; char caNewString[MAXLEN]; char *FindPos = strstr(sSrc, sMatchStr);//找到第一个匹配字符串,返回其首地址 if( (!FindPos) || (!sMatchStr) ) return -1; while( FindPos ) { memset(caNewString, 0, sizeof(caNewString)); StringLen = FindPos - sSrc; strncpy(caNewString, sSrc, StringLen); strcat(caNewString, sReplaceStr); strcat(caNewString, FindPos + strlen(sMatchStr));//将第一个匹配字符串的其首地址FindPos + strlen(sMatchStr)长度的 指针作为剩余字符 //串的首地址 strncpy(sSrc, caNewString,strlen(caNewString)); FindPos = strstr(sSrc, sMatchStr); } return 0; } */ //./str_replace_all "(uid=%u/%u)" "%u" chantra char *str_replace(const char *string, const char *substr, const char *replacement ) { char *tok = NULL; char *newstr = NULL; char *oldstr = NULL; /* if either substr or replacement is NULL, duplicate string a let caller handle it */ if ( substr == NULL || replacement == NULL ) return strdup(string); newstr = strdup (string); while ( (tok = strstr(newstr,substr))) { oldstr = newstr; newstr = (char*)malloc(strlen(oldstr) + 1); /*failed to alloc mem, free old string and return NULL */ if (newstr == NULL) { free (oldstr); return NULL; } memcpy( newstr, oldstr, tok - oldstr ); memcpy( newstr + (tok - oldstr), replacement, strlen ( replacement ) ); memcpy( newstr + (tok - oldstr) + strlen( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) ); memset( newstr + strlen ( oldstr ), 0, 1 ); free(oldstr); } return newstr; } int StringFind(const char *pSrc, const char *pDst) { int i, j; for (i=0; pSrc[i]!='\0'; i++) { if(pSrc[i]!=pDst[0]) continue; j = 0; while(pDst[j]!='\0' && pSrc[i+j]!='\0') { j++; if(pDst[j]!=pSrc[i+j]) break; } if(pDst[j]=='\0') return i; } return -1; } MSConfig(MSFilterLibrary, "libgame.so") int (*old_luaL_loadbuffer)(lua_State *L, const char *buff, size_t sz,const char *name); //保留原来的地址 int my_luaL_loadbuffer(lua_State *L, const char *buff, size_t sz,const char *filename) { //新的函数 //if (strlen(filename)<200 && !strchr(filename,'\"') && !strchr(filename,'\'') && !strchr(filename,'=') && !strchr(filename,'(') && !strchr(filename,')') )//要用\引导写成'\''而不能写成''' LOGI("call===:%s",filename); if (!strchr(filename,'\"') && !strchr(filename,'\'') && !strchr(filename,'=') && !strchr(filename,'(') && !strchr(filename,')') && StringFind(filename,".lua")!=-1) { LOGI("call!!:%s",filename); { //write to file //char buf[sz+1]; //sprintf(buf,"%s", filename); //ReplaceStr(buf,"/","="); char *buf = str_replace(filename,"/","="); //if (strcmp(buf,"src=data=StaticData=Skill.lua")!=0) //{ LOGI("call!!:%s",buf); char dd[sz+20]; sprintf(dd,"/sdcard/lua_qipai/%s", buf);///sdcard/lhsg/%s //导出dex文件 FILE *f = fopen(dd, "wb"); if (!f) { LOGI("error open sdcard file to write"); } else { // LOGI("write file %s",buf); fwrite(buff, 1, sz, f); fclose(f); //LOGI("close file %s",buf); } //} LOGI("call!end:%s",buf); } } return old_luaL_loadbuffer(L, buff, sz,filename); //进行原来的调用, 不影响程序运行 } //Substrate entry point MSInitialize { LOGI("Substrate initialized."); MSImageRef image; image = MSGetImageByName("data/data/com.yuanqi.n1/lib/libgame.so"); //载入lib if (image != NULL) { LOGI("FIND libcocos2dlua"); //注意这个是个c++函数,可以通过objdump来获取 void * dexload = MSFindSymbol(image, "luaL_loadbuffer"); if (dexload == NULL) { LOGI("error find luaL_loadbuffer "); } else { LOGI("find luaL_loadbuffer "); MSHookFunction(dexload, (void*) &my_luaL_loadbuffer, (void **) &old_luaL_loadbuffer); } } else { LOGI("ERROR FIND libcocos2dlua"); } } jstring Java_com_gh_assist_SoManager_stringFromJNI(JNIEnv* env, jobject obj) { return env->NewStringUTF("Hello World JNI!"); }
以上为hook 的luaL_loadbuffer 获取lua代码
最后为全部代码的压缩包欢迎支持。
请赞赏
朋友,创作不易;为犒赏小编的辛勤劳动,请她喝杯咖啡吧!
给她赞赏,您将财运亨通