Android逆向分析之Cydia

来源:互联网 发布:数据架构管理流程图 编辑:程序博客网 时间:2024/04/30 06:49

最近开始使用Cydia Substrate框架进行逆向分析。

Cydia是什么东东我就不多说了,自行百度,听说它可以越狱什么的,修改手机配置什么的,但这里只是通过一个例子,介绍如何使用Cydia Substrate框架进行hook Android java代码。

相比Xposed框架,Cydia是有一定的优势的,根据我目前使用的情况,暂时有如下两点:

一是,Cydia能hook除了第一个smali文件夹外的第二第三个smali文件夹(如下图)。

这话怎说?APKTool反编译一个APK时,有时会分割成好几个smali文件,Xposed只能hook第一个smali文件夹下的smali文件,有点坑,但Cydia却都可以hook。


二是,Cydia能hook本地方法,而Xposed不可以



基于以上两个优点,个人认为Cydia比Xposed好用,Xposed局限性较大,起码目前是这么认为的~

但有个技巧的方法只能在Xposed上用,就是通过刻意抛异常,根据异常日志找方法调用路径,这个在逆向分析常用的技巧无法再Cydia上用,因为Cydia抛异常后貌似不会以日志的形式打印出来,反正我试了很多次都不行。。。


开始说说如何使用吧

-------------------------------------------------------

1.  首先,下载com.saurik.substrate.apk,然后安装,手机必须得root过。这个是Cydia Substrate框架,需要另写模块加载进去。


安装之后点击 “Link  Substrate  Files” 即可。


2.  确定需要hook的对象APK中的方法,编写模块代码。

这里,我将hook一个apk里被混淆过的方法,并说明注意点。


因为混淆过,所以类名和方法名都被改成a,b,c等

该方法所在类:com.dianping.h.f.a.o

方法名:b, 

参数:com.dianping.nvnetwork.u 类

返回值 :com.dianping.nvnetwork.u 类


好,开始写模块,先在Android Studio里创建一个工程,该工程不需要Activity,在工程创建一个java文件,该文件就是模块代码,然后下载Cydia Substrate SDK,解压后将其放到libs文件夹下,并将jar包“Add as library”。



接下来,打开AndroidManifest,配置好一个meta-data和一个permission即可:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.samuelzhan.substratehook">    <application>        <meta-data android:name="com.saurik.substrate.main"            android:value=".Module"/>    </application>    <uses-permission android:name="cydia.permission.SUBSTRATE"/></manifest>

然后,编写模块代码:

public class Module {    static void initialize(){        MS.hookClassLoad("com.dianping.h.f.a.o",                new MS.ClassLoadHook() {                    public void classLoaded(Class<?> resources) {                        Method method;                        try {//                       不能使用本进程的ClassLoader,必须使用hook对象进程的ClassLoader//                            Class<?> u=ClassLoader.getSystemClassLoader().loadClass("com.dianping.nvnetwork.u");//                            Class<?> u = Class.forName("com.dianping.nvnetwork.u").getClass();                            Class<?> u= resources.getClassLoader().loadClass("com.dianping.nvnetwork.u");//                       getMethod只能获取public方法,getDeclareMethod能获取所有方法//                            method = resources.getMethod("b", u);                            method = resources.getDeclaredMethod("b", u);                                                    } catch (Exception e) {                            Log.d("zz", "exception: "+e.toString());                            method = null;                        }                        if (method != null) {                            final MS.MethodPointer old = new MS.MethodPointer();                            MS.hookMethod(resources, method, new MS.MethodHook() {                                @Override                                public Object invoked(Object o, Object... objects) throws Throwable {                                    // before hook                                    Log.d("zz", "hook 成功");                                    Object result = old.invoke(o, objects);                                    // after hook                                    return result;                                }                            }, old);                        }                    }                });    }


经过一个下午的摸索,我这里提出三点注意的地方:

第一,模块和hook对象的进程是两个进程,所以使用ClassLoader加载 u 类时要从resources那里getClassLoader,这是获取hook对象的ClassLoader,不然你加载不了 u 类而抛异常ClassNotFound(当然,如果只是使用java原生的类,即不是自定义的类的话,那么直接  .class后缀就可以获取到 class<?>了)。

第二,获取该类下的方法时,使用getDeclaredMethod可以获取所有方法,包括public,private,protected,而getMethod只能获取public

因为我hook的那个函数是protected的,但由于笔者之前一直用getMethod而导致没法hook到这方法。。。

Method method = resources.getDeclaredMethod("b", u);
第三,在方法被hook时,回调invoked方法,在此方法内有一句

Object result = old.invoke(o, objects);
该行代码的上面和下面分别对应Xposed的beforeMethodHook和afterMethodHook两个回调方法,如下图:


3.  模块写好后,导出项目,然后安装到手机上,手机若安装了Cydia SubStrate,则会在通知栏提醒软重启。

重启手机后,我们运行我们的目标APK即可以被Cydia Substrate 模块识别到,并打印出相关日志。

------------------------------------------------

到此为止,Cydia Substrate的基本使用已到此为止。

附加内容(可以忽略):

我上面提到的参数和返回值都是 u类实例,我之所以要hook这个 u类,是因为该 u 类内有个变量 InputStream,混淆后以 g 字符命名。

为了看到这个InputStream的内容,我必须通过反射找到该类的字段g,所以模块的写法会有所变化,但变化不大,增加了Field变量的获取,直接代码:

public class Module {    static void initialize(){        MS.hookClassLoad("com.dianping.h.f.a.o",                new MS.ClassLoadHook() {                    public void classLoaded(final Class<?> resources) {                        try {                            Class<?> u= resources.getClassLoader().loadClass("com.dianping.nvnetwork.u");                            final Method method = resources.getDeclaredMethod("b", u);                            final Field field=u.getDeclaredField("g");                            final MS.MethodPointer old = new MS.MethodPointer();                            MS.hookMethod(resources, method, new MS.MethodHook() {                                @Override                                public Object invoked(Object o, Object... objects) throws Throwable{                                        // before hook                                        InputStream is1=(InputStream)field.get(objects[0]);                                        String before=byte2HexString(inputStream2Byte(is1));                                        Log.d("zz", "Before HexString:"+before);                                        is1.reset();                                        Object result = old.invoke(o, objects);                                        // after hook                                        InputStream is2=(InputStream)field.get(result);                                        String after=byte2HexString(inputStream2Byte(is2));                                        Log.d("zz", "After HexString:"+after);                                        is2.reset();                                        return result;                                }                            }, old);                        } catch (Exception e) {                            Log.d("zz", "exception: "+e.toString());                        }                    }                });    }    public static byte[] inputStream2Byte(InputStream is) throws IOException {        ByteArrayOutputStream baos = new ByteArrayOutputStream();        byte[] buffer = new byte[1024];        int n = 0;        while ((n = is.read(buffer)) != -1) {            baos.write(buffer, 0, n);        }        return baos.toByteArray();    }    public static byte[] hexString2Byte(String hex) {        int len = (hex.length() / 2);        hex=hex.toUpperCase();        byte[] result = new byte[len];        char[] achar = hex.toCharArray();        for (int i = 0; i < len; i++) {            int pos = i * 2;            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));        }        return result;    }
运行结果:


好了,Cydia的介绍到此为止,其实还有其它功能的,比如hook C/C++的方法,这个日后再继续研究。


1 0
原创粉丝点击