首页
社区
课程
招聘
[原创]用VirtualApp无root绕过ssl证书校验
发表于: 2017-9-2 20:08 9664

[原创]用VirtualApp无root绕过ssl证书校验

2017-9-2 20:08
9664

用VirtualApp无root绕过ssl证书校验

这目前还只是一个想法,正在试,感觉从理论上应该可以实现的。

 

后面我边自己尝试,边把结果跟新上去。

 

发现了andfix的一些坑,不知道怎么去解决了,这个贴要烂尾了

整体实现过程

  1. 修改AndFix,并且把它融合到VirtualApp中
  2. 使用AndFix来进行java层的hook,然后来完成ssl证书校验

为啥我要用AndFix,不用VirtualApp作者的lengend?

因为懒。AndFix native层核心代码挺少的,而且一看就懂,修改方便。

在VirtualApp中融入AndFix

AndFix可以完成java方法的替换我们的方法。然后我们就可以去做些操作完成SSL证书校验的绕过

创建工程来测试一下

https://github.com/smartdone/VirtualApp/tree/master/andfixtester

 

第一步:创建一个普通的android工程,创建的时候不勾选C++支持,因为android studio默认使用的cmake,AndFix用的Android.mk

 

第二步:把AndFix的jni目录拷贝到我们创建的工程的,然后设置下build.gradle,添加下面这些东西去build so。

android {
    ...
    sourceSets.main {
        jni.srcDirs 'src/main/jni'
    }
    externalNativeBuild {
        ndkBuild {
            path 'src/main/jni/Android.mk'
        }
    }
}

第三步:我们把AndFix这个类拷贝到我们的工程中来,保持它的包名不变。

 

第四步:创建一个类用来测试

需要解决的问题:

我最终会用第2种方案

1. 调用旧的方法

这里有两种解决的方法:

 

第一种:只在java层去操作。比如说你要hook Test.class里面的add方法,然后你可以创建两个add方法。一个用来保存旧的方法,一个用来替换目标类中的方法。

private void hook() {
    try {
        // 用需要hook的目标方法去替换我们这里定义的保存就方法的方法
        Method method = Test.class.getDeclaredMethod("add", int.class, int.class);
        replaceMethod(getClassLoader(), MainActivity.class.getName(), "orig_add", method);
        // 用新的方法去替换目标方法
        method = MainActivity.class.getDeclaredMethod("new_add", int.class, int.class);
        replaceMethod(getClassLoader(), Test.class.getName(), "add", method);
    }catch (Exception e) {
        Log.d(TAG, e.getMessage());
    }
}
// 用来替换目标类中的方法
private static int new_add(int a, int b) {
    return orig_add(a, b) * 2;
}

// 用来保存旧的方法
private static int orig_add(int a, int b) {
    return 0;
}

这种方式的效果

09-02 19:05:46.505 30813-30813/com.smartdone.andfixtester D/AndFix-Test: add(1, 2) = 3
09-02 19:05:46.505 30813-30813/com.smartdone.andfixtester D/AndFix-Test: add(1, 2) = 6

第二种:修改AndFix的代码,在底层把两个java方法交换了
以dalvik为例,在AndFix中,修改修改方法的代码如下:

extern void __attribute__ ((visibility ("hidden"))) dalvik_replaceMethod(
        JNIEnv* env, jobject src, jobject dest) {
    jobject clazz = env->CallObjectMethod(dest, jClassMethod);
    ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef_fnPtr(
            dvmThreadSelf_fnPtr(), clazz);
    clz->status = CLASS_INITIALIZED;

    Method* meth = (Method*) env->FromReflectedMethod(src);
    Method* target = (Method*) env->FromReflectedMethod(dest);
    LOGD("dalvikMethod: %s", meth->name);

//    meth->clazz = target->clazz;
    meth->accessFlags |= ACC_PUBLIC;
    meth->methodIndex = target->methodIndex;
    meth->jniArgInfo = target->jniArgInfo;
    meth->registersSize = target->registersSize;
    meth->outsSize = target->outsSize;
    meth->insSize = target->insSize;

    meth->prototype = target->prototype;
    meth->insns = target->insns;
    meth->nativeFunc = target->nativeFunc;
}

我们再去创建一个method,原方法和替换后的方法给交换了,修改后的代码如下

extern void __attribute__ ((visibility ("hidden"))) dalvik_replaceMethod(
        JNIEnv* env, jobject src, jobject dest) {
    jobject clazz = env->CallObjectMethod(dest, jClassMethod);
    ClassObject* clz = (ClassObject*) dvmDecodeIndirectRef_fnPtr(
            dvmThreadSelf_fnPtr(), clazz);
    clz->status = CLASS_INITIALIZED;

    Method* meth = (Method*) env->FromReflectedMethod(src);
    Method* target = (Method*) env->FromReflectedMethod(dest);
    LOGD("dalvikMethod: %s", meth->name);

    Method* tmp = (Method *) malloc(sizeof(Method));

//    tmp->clazz = meth->clazz;
    tmp->accessFlags = meth->accessFlags;
    tmp->methodIndex = meth->methodIndex;
    tmp->jniArgInfo = meth->jniArgInfo;
    tmp->registersSize = meth->registersSize;
    tmp->outsSize = meth->outsSize;
    tmp->insSize = meth->insSize;

    tmp->prototype = meth->prototype;
    tmp->insns = meth->insns;
    tmp->nativeFunc = meth->nativeFunc;

//    meth->clazz = target->clazz;
    meth->accessFlags |= ACC_PUBLIC;
    meth->methodIndex = target->methodIndex;
    meth->jniArgInfo = target->jniArgInfo;
    meth->registersSize = target->registersSize;
    meth->outsSize = target->outsSize;
    meth->insSize = target->insSize;

    meth->prototype = target->prototype;
    meth->insns = target->insns;
    meth->nativeFunc = target->nativeFunc;

//    target->clazz = tmp->clazz;
    target->accessFlags |= ACC_PUBLIC;
    target->methodIndex = tmp->methodIndex;
    target->jniArgInfo = tmp->jniArgInfo;
    target->registersSize = tmp->registersSize;
    target->outsSize = tmp->outsSize;
    target->insSize = tmp->insSize;

    target->prototype = tmp->prototype;
    target->insns = tmp->insns;
    target->nativeFunc = tmp->nativeFunc;


    free(tmp);
}

这个时候调用原方法就很神奇了,因为我们现在这个方法和要hook的方法交换了,所以调用原方法的时候就只需要写自己就行啦,看起来的写法就和递归一样。

 

调用原方法demo如下:

private void replaceMethod(ClassLoader classLoader, String clz,
                           String meth, Method method) {
    try {
        Class clazz = classLoader.loadClass(clz);
        if(clazz != null) {
            clazz = AndFix.initTargetClass(clazz);
            Method src = clazz.getDeclaredMethod(meth, method.getParameterTypes());
            AndFix.addReplaceMethod(src, method);
        }
    } catch (Exception e) {
        Log.e(TAG, "replaceMethod", e);
    }
}

private void hook() {
    try {
        Method method = MainActivity.class.getDeclaredMethod("add", int.class, int.class);
        replaceMethod(getClassLoader(), Test.class.getName(), "add", method);
    }catch (Exception e) {
        Log.d(TAG, e.getMessage());
    }
}

// 这里看起来就特别的神奇了,看起来是无限递归,实际上并不会。哈哈哈
private static int add(int a, int b) {
    // 调用原方法,并且在原方法基础上面+1
    return add(a, b) + 1;
}

最后效果如下

09-02 20:49:25.052 22164-22164/? D/AndFix-Test: add(1, 2) = 3
09-02 20:49:25.052 22164-22164/? D/AndFix-Test: add(1, 2) = 4

很久没有继续研究过,刚刚再恢复存档的时候发现了一个问题,如果要去hook系统类的话会出问题,系统类的类加载器是java.lang.BootClassLoader,然后app的类加载器是dalvik.system.PathClassLoader,如果只是单纯的用andfix替换,类会因为依赖不同,运行的时候会报错


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 878
活跃值: (496)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
更懒的方法是用VirtualHook
2017-9-2 20:43
0
雪    币: 3549
活跃值: (941)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
3
rrrfff 更懒的方法是用VirtualHook[em_1]
重复造轮子
2017-9-2 20:55
0
雪    币: 133
活跃值: (233)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
思路很清晰,尝试一下,Swizzle
2017-9-4 09:08
0
雪    币: 3549
活跃值: (941)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
5
不追浮云的人 思路很清晰,尝试一下,Swizzle
swizzle不是ios  runtime下的吗,android好像没这个
2017-9-4 09:53
0
雪    币: 40
活跃值: (690)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
virtualapp内部不是已经集成了一种hook方式么?
2017-9-4 10:11
0
雪    币: 709
活跃值: (2420)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
7
已解决。
2017-9-4 16:59
0
雪    币: 53
活跃值: (23)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Bet
8
可以不用AndFix,参考这个就行。
https://techblog.mediaservice.net/2017/07/universal-android-ssl-pinning-bypass-with-frida/
2017-9-5 13:10
0
游客
登录 | 注册 方可回帖
返回
//