Xposed(LSposed)
Android启动流程详解
[原创]Lsposed 技术原理探讨 && 基本安装使用-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com
LSposed安装
《安卓逆向这档事》一、模拟器环境搭建 - 『移动安全区』 - 吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn
原理:
控制zygote进程:通过替换 /system/bin/app_process 程序控制zygote进程 使得它在系统启动的过程中会加载 xposed framework 的一个jar文件(XposedBridge.jar) 从而完成对zygote进程及其创建的 Dalvik/art 虚拟机的劫持
流程:
先执行Xposed中内容
后执行被hook内容
hook构造函数
1.调用 XposedHelpers.findAndHookConstructor
2.实现 beforeHookedMethod 和 afterHookedMethod
3.findAndHookConstructor 中写入重载类
hook普通函数/内部类函数/匿名函数
1.调用 XposedHelpers.findAndHookMethod(区别在于 className 参数)
2.param.setResult() 获得结果
修改对象属性
1.通过反射
其中构造函数 在beforeHookedMethod时 各函数值为系统赋值 而非人为赋值内容
所以需把内容写入afterHookedMethod中
1 2 3 4 5 6 7 8
| Class myclass = loadPackageParam.classLoader.loadClass("com.example.hooktest.tohook");
Field age = myclass.getDeclaredField("age");
age.setAccessible(true);
age.set(param.thisObject, 888);
|
2.通过Xposed的api
1 2 3 4 5 6 7
| Class myclass = loadPackageParam.classLoader.loadClass("com.example.hooktest.tohook");
XposedHelpers.setIntField(param.thisObject, "age", 777); XposedHelpers.setObjectField(param.thisObject, "name", "hookedname"); XposedHelpers.setBooleanField(param.thisObject, "hair", false);
|
xposed主动调用
1.通过反射完成
2.使用xposed api完成
获取实例方法
1.xposed api
2.hook构造函数
3.hook参数
4.反射
通过使用反射或者xposed api获得实例并完成主动调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| Class myclass = loadPackageParam.classLoader.loadClass("com.example.hooktest.tohook");
Method publicstatic = myclass.getDeclaredMethod("publicstatic"); String result = (String) publicstatic.invoke(null); Log.e("result==>", result);
String result = (String) XposedHelpers.callStaticMethod(myclass, "publicstatic"); Log.e("result==>", result);
Method publicmethod = myclass.getDeclaredMethod("publicmethod");
>-: Object publicobject = myclass.newInstance();
>-: Constructor publiccons = myclass.getConstructor(int.class); >-: Object publicobject = publiccons.newInstance();
>-: Object publicobject = XposedHelpers.newInstance(myclass, 1);
String result = (String) publicmethod.invoke(publicobject); Log.e("result==>", result);
Method privatemethod = myclass.getDeclaredMethod("privatemethod");
>-: Object privateobject = myclass.newInstance();
>-: Object privateobject = XposedHelpers.newInstance(myclass, 1);
privatemethod.setAccessible(true); String result = (String) privatemethod.invoke(privateobject); Log.e("result==>", result);
|
通过hook获得实例并完成主动调用(函数声明同上)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| XposedHelpers.findAndHookConstructor(myclass, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); }
@Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param);
Method publicmethod = myclass.getDeclaredMethod("publicmethod"); String publicstr = (String) publicmethod.invoke(param.thisObject); Method privatemethod = myclass.getDeclaredMethod("privatemethod"); privatemethod.setAccessible(true); String privatestr = (String) privatemethod.invoke(param.thisObject);
Log.e("publicstr==>", publicstr); Log.e("privatestr==>", privatestr); } });
XposedHelpers.findAndHookMethod(myclass,"hookstr", myclass, new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); >-: Method publicmethod = myclass.getDeclaredMethod("publicmethod"); >-: String publicstr = (String) publicmethod.invoke(param.args[0]); >-: String publicstr = (String) XposedHelpers.callMethod(param.args[0], "publicmethod"); Method privatemethod = myclass.getDeclaredMethod("privatemethod"); privatemethod.setAccessible(true); String privatestr = (String) privatemethod.invoke(param.args[0]);
Log.e("publicstr==>", publicstr); Log.e("privatestr==>", privatestr); }
@Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); } });
|
动态加载dex
将dexdemo写入
build为apk文件后解压
将class.dex push至/sdcard目录中 并赋予权限
1 2 3
| public class todex { public static void dexdemo() {Log.e("dexhookdemo==>", "from dexdemo.dex");} }
|
hookapp中写入动态加载 .dex (反射)文件内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class MainActivity extends AppCompatActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
DexClassLoader dexloader = new DexClassLoader("/sdcard/dexdemo.dex", this.getCacheDir().getAbsolutePath(), null, this.getClassLoader());
try { Class myclass = dexloader.loadClass("com.example.dexhook.todex"); Method dexdemomethod = myclass.getDeclaredMethod("dexdemo"); dexdemomethod.invoke(null);
} catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
|
在 AndroidManifest.xml 中加入 sdcard 读写权限
并打开 hookapp 的权限
1 2
| <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|

hook dex
通过 classLoader 获取 class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
|
public void classbyclassloader(ClassLoader loader) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { Class basedexclass = loader.loadClass("dalvik.system.BaseDexClassLoader"); Field dexpathlist = basedexclass.getDeclaredField("pathList"); dexpathlist.setAccessible(true); Object dexpathlistobj = dexpathlist.get(loader);
Class dexpathlistclass = loader.loadClass("dalvik.system.DexPathList"); Field dexelements = dexpathlistclass.getDeclaredField("dexElements"); dexelements.setAccessible(true); Object[] dexelementsobj = (Object[]) dexelements.get(dexpathlistobj);
for(Object a:dexelementsobj){ Class dexelementsclass = loader.loadClass("dalvik.system.DexPathList$Element"); Field dexfile = dexelementsclass.getDeclaredField("dexFile"); dexfile.setAccessible(true); DexFile dexfileobj = (DexFile) dexfile.get(a);
Enumeration<String> b = dexfileobj.entries();
while (b.hasMoreElements()) { String hookclass = b.nextElement(); Log.e("hookclass", hookclass); } } }
public void classbyclassloader(ClassLoader loader) { Object dexpathlistobj = XposedHelpers.getObjectField(loader, "pathList"); Object[] dexelementsobj = (Object[]) XposedHelpers.getObjectField(dexpathlistobj, "dexElements");
for(Object a:dexelementsobj){
DexFile dexfileobj = (DexFile) XposedHelpers.getObjectField(a, "dexFile"); Enumeration<String> b = dexfileobj.entries();
while (b.hasMoreElements()) { String hookclass = b.nextElement(); Log.e("hookclass", hookclass); } } }
|
hook dex替换的壳函数
一代壳获得classloader
[原创]FART:ART环境下基于主动调用的自动化脱壳方案-Android安全-看雪论坛-安全社区|安全招聘|bbs.pediy.com
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
public ClassLoader get_classloader(ClassLoader loader) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Class Act_Thr_class = loader.loadClass("android.app.ActivityThread"); Method cur_Act_Thr_met = Act_Thr_class.getDeclaredMethod("currentActivityThread"); cur_Act_Thr_met.setAccessible(true); Object Act_Thr_obj = cur_Act_Thr_met.invoke(null);
Field application = Act_Thr_class.getDeclaredField("mInitialApplication"); application.setAccessible(true); Object appli_obj = application.get(Act_Thr_obj);
Class App_class = loader.loadClass("android.app.Application"); Field mloadapk = App_class.getDeclaredField("mLoadApk"); mloadapk.setAccessible(true); Object mloadapk_obj = mloadapk.get(appli_obj);
Class mCl_Loa_class = loader.loadClass("android.app.LoadedApk"); Field mclassloader = mCl_Loa_class.getDeclaredField("mClassLoader"); mclassloader.setAccessible(true); ClassLoader mcla_loa_obj = (ClassLoader) mclassloader.get(mloadapk_obj);
return mcla_loa_obj; }
public ClassLoader get_classloader(ClassLoader loader) throws ClassNotFoundException { Class Act_Thr_class = loader.loadClass("android.app.ActivityThread"); Object Act_Thr_obj = XposedHelpers.callStaticMethod(Act_Thr_class, "currentActivityThread");
Object appli_obj = XposedHelpers.getObjectField(Act_Thr_obj, "mInitialApplication");
Object mloadapk_obj = XposedHelpers.getObjectField(appli_obj, "mLoadApk");
ClassLoader mcla_loa_obj = (ClassLoader) XposedHelpers.getObjectField(mloadapk_obj, "mClassLoader");
return mcla_loa_obj; }
|
native层处理
inlinehook(arm32)
需要在 build.gradle 中 android{ defaultConfig{ } } 里添加
1
| ndk {abiFilters 'armeabi-v7a'}
|
先将 inlinehook 解压包放置 main->cpp 中
之后在 main->cpp->native-lib.cpp 中写入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include <jni.h> #include <string> #include <stdlib.h> #include <dlfcn.h> #include "android/log.h"
extern "C" { #include "include/inlineHook.h" }
int (*old_strstr)(const char *, char *) = nullptr;
int new_strstr(const char* string1, char* string2) {
if (strcmp(string2, "yunyun") == 0) { return 1; } else { return old_strstr(string1, string2); } }
int hook() {
void *libc_addr = dlopen("libc.so", RTLD_NOW); void *strstr_addr = dlsym(libc_addr, "strstr"); __android_log_print(4, "cppyunaddr", "hook is ok==> %p", strstr_addr);
if (registerInlineHook((uint32_t) strstr_addr, (uint32_t) new_strstr, (uint32_t **) & old_strstr) != ELE7EN_OK) { return -1; } if (inlineHook((uint32_t) strstr_addr) != ELE7EN_OK) { return -1; } return 0; }
extern "C" JNIEXPORT jstring JNICALL Java_com_example_lsposedso_MainActivity_stringFromJNI( JNIEnv* env, jobject ) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); }
extern "C" void _init() { hook(); }
extern "C" jint JNICALL JNI_OnLoad(JavaVM *vm, void *res) { __android_log_print(4, "cppyun", "from JNI_Onload"); hook(); return JNI_VERSION_1_6; }
extern "C" JNIEXPORT void JNICALL Java_com_example_lsposedso_sohook_strstrhook(JNIEnv *env, jobject thiz) { hook(); }
|
打包成apk文件后解压将 lib.so 文件提取
push 至 Android 公有目录
使用 System.load() 写入绝对路径后进行加载
(系统不会自己加载个人编写的 so 文件 所以需要手动实现)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class sohook implements IXposedHookLoadPackage { @Override public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
Class myclass = loadPackageParam.classLoader.loadClass("java.lang.Runtime"); XposedBridge.hookAllMethods(myclass, "loadLibrary0", new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { super.beforeHookedMethod(param); }
@Override protected void afterHookedMethod(MethodHookParam param) throws Throwable { super.afterHookedMethod(param); System.load("/data/local/tmp/liblsposedso.so"); } }); } }
|
sandhook(arm64)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <jni.h> #include <string> #include "sandhook_native.h"
void * (*old_strstr)(char*, char*) = nullptr; void * new_strstr(char* a, char* b) { if(strcmp(b, "yunyun") == 0) { int a = 1; return &a;
} else { return old_strstr(a,b); } }
extern "C" JNICALL jint JNI_OnLoad(JavaVM *vm, void* res) { old_strstr = reinterpret_cast<void *(*)(char *, char *)> (SandInlineHookSym("/system/lib64/libc.so", "strstr", reinterpret_cast<void *>(new_strstr))); return JNI_VERSION_1_6; }
extern "C" JNIEXPORT jstring JNICALL Java_com_example_lsposedso_MainActivity_stringFromJNI( JNIEnv* env, jobject ) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); }
|