对XX水印相机的分析

查看 79|回复 8
作者:Forgo7ten2020   
看了@闷骚小贱男 帖子https://www.52pojie.cn/thread-1353870-1-1.html,也想自己实战分析一下
今日水印相机自定义水印
apk没有加壳,还是比较好分析的
抓包
打开app开始抓包,有以下几个api


image-20210810004740692.png (391.59 KB, 下载次数: 0)
下载附件
2021-8-10 02:26 上传

逆向分析
分析天气参数的获取
jeb分析
jeb中搜索相应的URI


image-20210810004938096.png (19.83 KB, 下载次数: 0)
下载附件
2021-8-10 02:26 上传

选择第二个来到 一个所有request方法的类


image-20210810005040994.png (53.65 KB, 下载次数: 0)
下载附件
2021-8-10 02:26 上传

摁X进行交叉引用
参数1和参数2即为经纬度坐标


image-20210810005122554.png (22.83 KB, 下载次数: 0)
下载附件
2021-8-10 02:26 上传

来到这里


image-20210810005156768.png (40.1 KB, 下载次数: 0)
下载附件
2021-8-10 02:27 上传

发现内部类对其进行了解析,强转为WeatherInfo
public class WeatherInfo {
    public String apparentTemperature; // 体感温度:30
    public String aqi;   // 空气质量指数:37
    public String aqiLevel; // 空气质量等级:优
    public String humidity; // 湿度:75%
    public String pressure; // 压强:1001
    public String temperature; // 温度:27
    public String weather; // 天气:晴
    public String winddirection; // 风向:西南风
    public String windpower; // 风力:1级
}
接下来就是如何hook该内部类了
调试验证
运行fridaserver
使用frida的objection工具
先启动目标app
objection -N -h 192.168.0.104 -p 8888 -d -g com.xhey.xcamera explore
然后查找com.xhey.xcamera.e的类
com.xhey.xcamera on (google: 8.1.0) [net] # android hooking search classes com.xhey.xcamera.e                                                      
com.xhey.xcamera.e
com.xhey.xcamera.e$1
com.xhey.xcamera.e$5
com.xhey.xcamera.e$6
com.xhey.xcamera.e$8
com.xhey.xcamera.e$a
com.xhey.xcamera.e$b
Found 7 classes
挨个查看每个内部类的方法
com.xhey.xcamera on (google: 8.1.0) [net] # android hooking list class_methods com.xhey.xcamera.e$1                                                
private static void com.xhey.xcamera.e$1.b(xhey.com.network.model.BaseResponse)
public static void com.xhey.xcamera.e$1.lambda$Wc1CpEPvMWi1606k4HUcLAjQgiw(xhey.com.network.model.BaseResponse)
public void com.xhey.xcamera.e$1.a(xhey.com.network.model.BaseResponse)
public void com.xhey.xcamera.e$1.onError(java.lang.Throwable)
public void com.xhey.xcamera.e$1.onSuccess(java.lang.Object)
Found 5 method(s)
发现e$1,e$5,e$8具有相同的方法,且与上反编译源码中方法类似
function main(){
    Java.perform(function () {
        var clazz = Java.use('com.xhey.xcamera.e$5');
        clazz.a.implementation = function (response_argu) {
            var result = clazz.a.apply(this, arguments);
            var response = Java.cast(response_argu, Java.use("xhey.com.network.model.BaseResponse"));
            console.log("BaseResponse.code", response.code.value);
            console.log("BaseResponse.data", response.data.value);
            console.log("BaseResponse.msg", response.msg.value);
            console.log("BaseResponse.toast_msg", response.toast_msg.value);
            return result;
        }
    });
}
setImmediate(main)
frida来运行调试
frida -H 192.168.0.104:8888 -f com.xhey.xcamera -l syxj.js --no-pause
打印出如下信息
[Remote::com.xhey.xcamera]-> BaseResponse.code 200
BaseResponse.data com.xhey.xcamera.data.model.bean.WeatherInfo@1d5fef8
BaseResponse.msg success
BaseResponse.toast_msg
发现WeatherInfo,就是解密后的类
分析时间的获取
部分同天气获取,定位到


image-20210810012037704.png (34.96 KB, 下载次数: 0)
下载附件
2021-8-10 02:27 上传

其中v1.build()调用了aes,来对json字符串进行加密


image-20210810012124362.png (23.61 KB, 下载次数: 0)
下载附件
2021-8-10 02:27 上传

得到key和iv均为"xhey-cc4275fd-43",AES模式为"AES/CBC/PKCS5Padding"
package xhey.com.network.retrofit2;
public enum AESUtil {
    private static final String ENCRYPTION_IV = "xhey-cc4275fd-43";
    private static final String ENCRYPTION_KEY = "xhey-cc4275fd-43";
    public static String decrypt(String arg4) {
    }
    public static String encrypt(String arg5) {
        if(TextUtils.isEmpty(arg5)) {
            return arg5;
        }
        try {
            Cipher v0 = Cipher.getInstance("AES/CBC/PKCS5Padding");
            v0.init(1, AESUtil.makeKey(), AESUtil.makeIv());
            Log.e("time", "==" + Base64.encode(v0.doFinal(arg5.getBytes()), 0));
            return new String(Base64.encode(v0.doFinal(arg5.getBytes()), 2)).trim();
        }
        catch(Exception v5) {
            Log.e("AESUtil", "=encrypt=" + v5.getMessage());
            return "";
        }
    }
    static AlgorithmParameterSpec makeIv() {
        return new IvParameterSpec("xhey-cc4275fd-43".getBytes("utf-8"));
    }
    static SecretKeySpec makeKey() {
        return new SecretKeySpec("xhey-cc4275fd-43".getBytes("utf-8"), "AES");
    }
}
此时我们就可以对Fiddler抓到的包来进行加解密了。
requestTimeInChina继续查看上层引用,同样来到了com.xhey.xcamera.e类中


image-20210810012605219.png (65.44 KB, 下载次数: 0)
下载附件
2021-8-10 02:27 上传

同样frida分析后发现是e$8
分析定位
当程序获取天气参数的时候,使用了定位
交叉引用向上追溯
com.xhey.xcamera.network.service.NetWorkServiceKt.requestWeatherInfocom.xhey.xcamera.e.b(java.lang.String[])+2Ahcom.xhey.xcamera.e.a(boolean, com.baidu.location.BDLocation)+5D8h
找到赋值的地方


image-20210810013246491.png (19.75 KB, 下载次数: 0)
下载附件
2021-8-10 02:27 上传

hook这两个方法就可以修改经纬度也就是定位了
而BDLocation是百度地图的api
同理速度也可以hookBDLocation.getSpeed来修改
插件编写
Frida hook脚本
(换行全部都没了,重新格式化下是可以的)
function printStack(name) {    Java.perform(function () {        var Exception = Java.use("java.lang.Exception");        var ins = Exception.$new("Exception");        var straces = ins.getStackTrace();        if (straces != undefined && straces != null) {            var strace = straces.toString();            var replaceStr = strace.replace(/,/g, "\\n");            console.log("=============================" + name + " Stack strat=======================");            console.log(replaceStr);            console.log("=============================" + name + " Stack end=======================\r\n");            Exception.$dispose();        }    });}function main() {    Java.perform(function () {        /**         * 解析 /next/android/config         */        var clazz = Java.use('com.xhey.xcamera.e$1');        clazz.a.implementation = function (response_argu) {            var response = Java.cast(response_argu, Java.use("xhey.com.network.model.BaseResponse"));            // console.log("BaseResponse.code",response.code.value);            // console.log("BaseResponse.data",response.data.value);            // console.log("BaseResponse.msg",response.msg.value);            // console.log("BaseResponse.toast_msg",response.toast_msg.value);            var result = clazz.a.apply(this, arguments);            return result;        }    });    Java.perform(function () {        Java.openClassFile("/data/local/tmp/r0gson.dex").load();        const gson = Java.use('com.r0ysue.gson.Gson');        /**         * 解析天气 /next/GetCurrentWeather         * public class WeatherInfo {         *      public String apparentTemperature; // 体感温度:30         *      public String aqi;   // 空气质量指数:37         *      public String aqiLevel; // 空气质量等级:优         *      public String humidity; // 湿度:75%         *      public String pressure; // 压强:1001         *      public String temperature; // 温度:27         *      public String weather; // 天气:晴         *      public String winddirection; // 风向:西南风         *      public String windpower; // 风力:1级         * }         */        var clazz = Java.use('com.xhey.xcamera.e$5');        clazz.a.implementation = function (response_argu) {            var response = Java.cast(response_argu, Java.use("xhey.com.network.model.BaseResponse"));            var weather_info = Java.cast(response.data.value, Java.use("com.xhey.xcamera.data.model.bean.WeatherInfo"))            // 对值做修改            weather_info.temperature.value = Java.use("java.lang.String").$new("-99");            //            // console.log("BaseResponse.code", response.code.value);            // console.log("weather_info", gson.$new().toJson(weather_info));            // console.log("BaseResponse.msg", response.msg.value);            // console.log("BaseResponse.toast_msg", response.toast_msg.value);            var result = clazz.a.apply(this, arguments);            return result;        }    });    Java.perform(function () {        Java.openClassFile("/data/local/tmp/r0gson.dex").load();        const gson = Java.use('com.r0ysue.gson.Gson');        /**         * 解析时间 /next/inchina         *      public class TimeStatus {         *      private boolean in_china;   // 是否在中国:true         *      private boolean stopDevice; // false         *      private int timestamp;      // 时间戳         * }         */        var clazz = Java.use('com.xhey.xcamera.e$8');        clazz.a.implementation = function (response_argu) {            var response = Java.cast(response_argu, Java.use("xhey.com.network.model.BaseResponse"));            var time_info = Java.cast(response.data.value, Java.use("com.xhey.xcamera.data.model.bean.TimeStatus"));                        // console.log("=== TIME ===")            // console.log("BaseResponse.code", response.code.value);            // console.log("BaseResponse.data", response.data.value);            // console.log("BaseResponse.msg", response.msg.value);            // console.log("BaseResponse.toast_msg", response.toast_msg.value);            // console.log("Time", gson.$new().toJson(time_info));            // console.log("TimeStatus.timestamp", time_info.timestamp.value);            time_info.timestamp.value = Java.use("java.lang.Integer").$new("1912521600").intValue();            var result = clazz.a.apply(this, arguments);            return result;        }    });    Java.perform(function () {        var clazz = Java.use('com.baidu.location.BDLocation');        // 纬度        clazz.getLatitude.implementation = function () {            var result = clazz.getLatitude.apply(this, arguments);            // console.log("Latitude", result);            result = Java.use("java.lang.Double").$new("36.269893").doubleValue();            // console.log("Change Latitude", result);            return result;        }        // 经度        clazz.getLongitude.implementation = function () {            var result = clazz.getLongitude.apply(this, arguments);            // console.log("Longitude", result);            result = Java.use("java.lang.Double").$new("117.094738").doubleValue();            // console.log("Change Longitude", result);            return result;        }        // 速度        clazz.getSpeed.implementation = function () {            var result = clazz.getSpeed.apply(this, arguments);            // console.log("Speed", result);            result = Java.use("java.lang.Float").$new("99.99").floatValue();            // console.log("Change Speed", result);            return result;        }    });}function func() {    Java.perform(function () {        var clazz = Java.use('xhey.com.network.retrofit2.AESUtil');        clazz.decrypt.implementation = function (data) {            var result = clazz.decrypt.apply(this, arguments)            printStack("AES decrypt");            console.log("aes decrypt data:", data);            console.log("aes decrypt result: ", result);            return result;        }    });    Java.perform(function () {        var clazz = Java.use('xhey.com.network.retrofit2.AESUtil');        clazz.encrypt.implementation = function (data) {            var result = clazz.encrypt.apply(this, arguments)            printStack("AES encrypt");            console.log("aes encrypt data:", data);            console.log("aes encrypt result: ", result);            return result;        }    });}setImmediate(main)
Xposed插件开发
hook的类已经分析完了,懒得造轮子了
效果图


image-20210810022207796.png (212.94 KB, 下载次数: 0)
下载附件
2021-8-10 02:27 上传

总结
这算是自己分析的第一个app。花了差不多一天的时间,第一次接触这么大的代码量,刚开始有些懵逼。
但分析完发现这个app还是很简单的,没有壳也没有混淆,比较适合我这样的新手。
Frida啥的还是不熟练,疯狂找bug。
刚开始修改时间没有效果,最后发现是因为先执行了原方法result = clazz.a.apply(this, arguments);,导致时间在方法体内被直接应用了。
该文章也同步上传至我的GitHub博客 Example(0) 今日水印相机自定义水印 | Forgo7ten'blog
中间也多次向@闷骚小贱男 寻求指导,再次感谢

下载次数, 水印

mengma1120   

鉴于初入坑,写的还算完整,鼓励一下,
此外本文中有图片炸了应该是漏传了,
顺便说一下,你的博客里的图片全炸了。。。
xunxunmimi0936   

可以可以不错,加水印的这些app都不知道为啥要出
asdswd   

公司一直用水印相机打卡,这个非常不错。
丶不负年华   

下载不到,打开就404了
xyz星人   

楼主强啊~感谢楼主分享
hubohang   

大佬 学习了
Forgo7ten2020
OP
  


涛之雨 发表于 2021-8-10 10:06
鉴于初入坑,写的还算完整,鼓励一下,
此外本文中有图片炸了应该是漏传了,
顺便说一下,你的博客里的图 ...

感谢鼓励
图片漏传已补,发了帖子后发现hexo出问题了,但是当时太晚了就睡了
Forgo7ten2020
OP
  


丶不负年华 发表于 2021-8-10 11:54
下载不到,打开就404了

博客在修,修完了我再告诉你哈
您需要登录后才可以回帖 登录 | 立即注册

返回顶部