目录

记一次某app的逆向
记一次某app的逆向

access_time
brush 15100个字
local_library 241
local_offer 安卓

配置好代理,打开app抓包,点击登录,发现数据被加密

图片.png

从Charles可以看到,发送的数据是加密的,发送回来的数据也是加密的

发送的数据包

POST /api/user/login HTTP/1.1
If-Modified-Since: Thu, 09 Feb 2023 05:17:17 GMT
Content-Type: application/json; Charset=utf-8
User-Agent: Dalvik/2.1.0 (Linux; U; Android 10; Pixel 4 XL Build/QD1A.190821.011.C4)
Host: api.dodovip.com
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 249

{"Encrypt":"NIszaqFPos1vd0pFqKlB42Np5itPxaNH\/\/FDsRnlBfgL4lcVxjXii\/UNcdXYMk0EaHz9LRZCfkpz\nazbo8zb2jdzkGqEAe9VKNk8FmwSoaur1PhpwV+iCeHcftk6ZlsGui5zmyjMBX\/Ng7c701M7sY6iW\noWntyfWevnsJrN+wPARNX35V+O1JquZqhvoK8em4\/UxIVR3NO6WGr6ITQMXjfn1INGMnUAtT\n"}

返回的数据包

HTTP/1.1 200 OK
Date: Thu, 09 Feb 2023 05:17:17 GMT
Content-Type: application/json;Charset=utf-8
Transfer-Encoding: chunked
Server: Nginx
Content-Encoding: gzip
Connection: keep-alive

2v+DC2gq7RuAC8PE5GZz5wH3/y9ZVcWhFwhDY9L19g9iEd075+Q7xwewvfIN0g0ec/NaaF43/S0=

为了伪造登录请求,我们就要对app进行逆向

首先先查一下壳

图片.png

没有加壳

将app导入jadx进行反编译

图片.png

在进行逆向之前,我们先分析一下界面,确定app是原生的还是h5app

图片.png

可以确定是原生的app

先尝试通过搜索字符串定位关键加密代码,可以搜索链接,可以搜索加密的参数名,也可以搜索同一个数据包中,没有加密的参数名

直接搜索数据包中的Encypt,有105个结果

图片.png

再加上双引号,变成了24个

图片.png

其中,与包名相关的,我们可以优先关注

图片.png

我们先进入到第一个函数

图片.png

关键字encodeDesMap和sign关键字可以知道,相关性较大

图片.png

进入paraMap函数,这里对参数进行了处理

图片.png

图片.png

我们进入encodeDesMap函数,可以看出进行了des加密处理

进入第二个函数,我们看到des加密和sign,相关性也比较大

图片.png



通过搜索POST数据包里的链接,我们同样搜索出了两个函数,我们可以基本定位登录函数

图片.png

登陆函数

图片.png

函数的分析

 private void login(String userName, String pwd) {
        this.DEFAULT_TYPE = new TypeToken() { // from class: com.dodonew.online.ui.LoginActivity.1
        }.getType();
        this.para.clear();
        this.para.put("username", userName);//放入用户名
        this.para.put("userPwd", pwd);//放入密码
        if (TextUtils.isEmpty(DodonewOnlineApplication.devId)) {
            DodonewOnlineApplication.devId = Utils.getDevId(DodonewOnlineApplication.getAppContext());
        }
        this.para.put("equtype", Config.equtype);
        this.para.put("loginImei", "Android" + DodonewOnlineApplication.devId);
        requestNetwork("user/login", this.para, this.DEFAULT_TYPE);//通过requestNetwork函数进行提交
    }

提交函数

图片.png

private void requestNetwork(final String cmd, Map para, Type type) {
        showProgress();
        this.request = new JsonRequest(this, "http://api.dodovip.com/api/" + cmd, "", new Response.Listener() { // from class: com.dodonew.online.ui.LoginActivity.2//发送请求,回调函数
            public void onResponse(RequestResult requestResult) {
                if (!requestResult.code.equals(a.e)) {
                    LoginActivity.this.showToast(requestResult.message);
                } else if (cmd.equals("user/login")) {
                    DodonewOnlineApplication.loginUser = (User) requestResult.data;
                    DodonewOnlineApplication.loginLabel = "mobile";
                    Utils.saveJson(LoginActivity.this, DodonewOnlineApplication.loginLabel, Config.LOGINLABEL_JSON);
                    LoginActivity.this.intentMainActivity();
                }
                LoginActivity.this.dissProgress();
            }
        }, this, type);//回调函数结束 
        this.request.addRequestMap(para, 0);//将带有用户名,密码等信息的para传入addRequestMap中
        DodonewOnlineApplication.addRequest(this.request, this);
    }

进入addRequestMap

图片.png

 public void addRequestMap(Map addMap, int a) {
        String time = System.currentTimeMillis() + "";//取时间戳
        if (addMap == null) {
            addMap = new HashMap<>();
        }
        addMap.put("timeStamp", time);//将时间戳加入到addMap中
        String encrypt = RequestUtil.encodeDesMap(RequestUtil.paraMap(addMap, Config.BASE_APPEND, "sign"), this.desKey, this.desIV);//addMap先传到paraMap中进行第一步处理,然后将deskey和desiv传入到encodeDesMap中进行des加密。这两个函数是分析的重点
        JSONObject obj = new JSONObject();
        try {
            obj.put("Encrypt", encrypt);//输出最终结果进行提交
            this.mRequestBody = obj + "";
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

跟进paraMap函数

图片.png

  public static String paraMap(Map addMap, String append, String sign) {
        try {
            Set keyset = addMap.keySet();
            StringBuilder builder = new StringBuilder();
            List list = new ArrayList<>();
            for (String keyName : keyset) {//加强for循环,将addMap全部放入list中
                list.add(keyName + "=" + addMap.get(keyName));
            }
            Collections.sort(list);//对参数进行排序
            for (int i = 0; i < list.size(); i++) {//转成字符串,以便进行MD5加密
                builder.append(list.get(i));
                builder.append("&");
            }
            builder.append("key=" + append);
            addMap.put("sign", Utils.md5(builder.toString()).toUpperCase());//使用MD5进行加密,得到签名的值
            String result = new Gson().toJson(sortMapByKey(addMap));//将addMap转成Json字符串
            Log.w(AppConfig.DEBUG_TAG, result + "   result");
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

跟进encodeDesMap

图片.png

继续跟进DesSecurity

图片.png

public class DesSecurity {
    Cipher deCipher;
    Cipher enCipher;

    public DesSecurity(String key, String iv) throws Exception {
        if (key == null) {
            throw new NullPointerException("Parameter is null!");
        }
        InitCipher(key.getBytes(), iv.getBytes());//将key和iv转字节后传入InitCipher中
    }

    private void InitCipher(Byte[] secKey, Byte[] secIv) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");//将key进行了MD5加密
        md.update(secKey);
        SecretKey key = SecretKeyFactory.getInstance("DES").generateSecret(new DESKeySpec(md.digest()));//将key加密后MD5的值直接传入DESKeySpec中作为des加密的密钥,注意,digest()是字节,取加密结果16个字节中的前8个字节
        IvParameterSpec iv = new IvParameterSpec(secIv);//iv直接传入
        this.enCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");//DES加密模式
        this.deCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        this.enCipher.init(1, key, iv);
        this.deCipher.init(2, key, iv);
    }

    public String encrypt64(Byte[] data) throws Exception {
        return Base64.encodeToString(this.enCipher.doFinal(data), 0);//对加密后的结果进行doFinal,并进行Base64编码
    }

    public Byte[] decrypt64(String data) throws Exception {
        return this.deCipher.doFinal(Base64.decode(data, 0));
    }
}

静态分析后,我们要使用Firda进行Hook了

我们首先Hook paraMap函数

图片.png

编写hook代码

Java.perform(function () {
    console.log("xxx")
    var jsonRequest= Java.use("com.dodonew.online.http.JsonRequest");
    jsonRequest.paraMap.implementation=function (a) {
        console.log("jsonRequest.paraMap is called");
        return this.paraMap(a);
    }
})

app点击登陆,发现函数并未被调用

图片.png

我们再hook addRequestMap函数

图片.png

Java.perform(function () {
    console.log("xxx")
    var jsonRequest= Java.use("com.dodonew.online.http.JsonRequest");
    jsonRequest.paraMap.implementation=function (a) {
        console.log("jsonRequest.paraMap is called");
        return this.paraMap(a);
    }
    jsonRequest.addRequestMap.implementation=function (addMap,a) {
        console.log("jsonRequest.addRequestMap is called");
        return this.addRequestMap(addMap,a);
    }
})

再次hook发现报错,函数有三个重载,很明显是第二个

图片.png

修改hook代码,再次hook

Java.perform(function () {
    console.log("xxx")
    var jsonRequest= Java.use("com.dodonew.online.http.JsonRequest");
    jsonRequest.paraMap.implementation=function (a) {
        console.log("jsonRequest.paraMap is called");
        return this.paraMap(a);
    }
    jsonRequest.addRequestMap.overload('java.util.Map', 'int').implementation=function (addMap,a) {
        console.log("jsonRequest.addRequestMap is called");
        return this.addRequestMap(addMap,a);
    }
})

再次点击登陆,addRequestMap函数触发

图片.png

再hook encodeDesMap函数

图片.png

编写hook代码

Java.perform(function () {
    console.log("xxx")
    var jsonRequest= Java.use("com.dodonew.online.http.JsonRequest");
    var requestUtil= Java.use("com.dodonew.online.http.RequestUtil");
    jsonRequest.paraMap.implementation=function (a) {
        console.log("jsonRequest.paraMap is called");
        return this.paraMap(a);
    }
    jsonRequest.addRequestMap.overload('java.util.Map', 'int').implementation=function (addMap,a) {
        console.log("jsonRequest.addRequestMap is called");
        return this.addRequestMap(addMap,a);
    }
    requestUtil.encodeDesMap.overload('java.lang.String', 'java.lang.String', 'java.lang.String').implementation=function (data,deskey,desIv) {
        console.log("requestUtil.encodeDesMap is called");
        console.log("data:",data,"deskey:",deskey,"desIv:",desIv);
        var encodeDesMap=this.encodeDesMap(data,deskey,desIv);
        console.log("encodeDesMap:",encodeDesMap)
        return encodeDesMap;
    }
})

点击登陆按钮,成功hook

图片.png

将hook到的数据与抓包数据对比一致

jsonRequest.addRequestMap is called
requestUtil.encodeDesMap is called
data: {"equtype":"AndROID","loginImei":"Androidnull","sign":"5CDC2DA6AB93DAAE28BB8B8F9B9A5396","timeStamp":"1675951114924","userPwd":"123456","username":"13258556988"} 
deskey: 65102933 
desIv: 32028092
encodeDesMap: NIszaqFPos1vd0pFqKlB42Np5itPxaNH//FDsRnlBfgL4lcVxjXii/UNcdXYMk0Er+dH33DGoDbR
vwi+0/JK4jFMtDufcIdMyMoUuHGtsYRGE5pi5gHNJVE51UAaJ4ZS2gFFoiuzvQALhou4Uyl/Cjgc
bufrQMwC0DVacym7aemdRNuNgr4QPTi4WpUDvu3zUgSP05lfYaFJiO4RlyuiDxpjia7V7/S2

抓包数据

POST /api/user/login HTTP/1.1
If-Modified-Since: Thu, 09 Feb 2023 13:55:01 GMT
Content-Type: application/json; Charset=utf-8
User-Agent: Dalvik/2.1.0 (Linux; U; Android 10; Pixel 4 XL Build/QD1A.190821.011.C4)
Host: api.dodovip.com
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 250

{"Encrypt":"NIszaqFPos1vd0pFqKlB42Np5itPxaNH\/\/FDsRnlBfgL4lcVxjXii\/UNcdXYMk0Er+dH33DGoDbR\nvwi+0\/JK4jFMtDufcIdMyMoUuHGtsYRGE5pi5gHNJVE51UAaJ4ZS2gFFoiuzvQALhou4Uyl\/Cjgc\nbufrQMwC0DVacym7aemdRNuNgr4QPTi4WpUDvu3zUgSP05lfYaFJiO4RlyuiDxpjia7V7\/S2\n"}

目前,我们还有一个sign的参数是未知的

图片.png

跟进paraMap函数,我们发现传入了三个参数,该函数之前静态分析已经分析过

图片.png

我们从上面的函数中跟进找到了append的值

图片.png

继续跟进MD5函数

图片.png

我们接下来hook MD5函数

Java.perform(function () {
    console.log("xxx")
    var jsonRequest= Java.use("com.dodonew.online.http.JsonRequest");
    var requestUtil= Java.use("com.dodonew.online.http.RequestUtil");
    var utils=Java.use("com.dodonew.online.util.Utils")
    jsonRequest.paraMap.implementation=function (a) {
        console.log("jsonRequest.paraMap is called");
        return this.paraMap(a);
    }
    jsonRequest.addRequestMap.overload('java.util.Map', 'int').implementation=function (addMap,a) {
        console.log("jsonRequest.addRequestMap is called");
        return this.addRequestMap(addMap,a);
    }
    requestUtil.encodeDesMap.overload('java.lang.String', 'java.lang.String', 'java.lang.String').implementation=function (data,deskey,desIv) {
        console.log("requestUtil.encodeDesMap is called");
        console.log("data:",data,"deskey:",deskey,"desIv:",desIv);
        var encodeDesMap=this.encodeDesMap(data,deskey,desIv);
        console.log("encodeDesMap:",encodeDesMap)
        return encodeDesMap;
    }
    utils.md5.implementation=function (a) {
        console.log("sign data:",a);
        var md5 =this.md5(a);
        console.log("sign:",md5);
        return md5;
    }
})

成功hook

图片.png

jsonRequest.addRequestMap is called
sign data: equtype=AndROID&loginImei=Androidnull&timeStamp=1675953260605&userPwd=123456&username=13258556988&key=sdlkjsdljf0j2fsjk
sign: cb925fbd6ba322eda4afa035b1feca97
requestUtil.encodeDesMap is called
data: {"equtype":"AndROID","loginImei":"Androidnull","sign":"CB925FBD6BA322EDA4AFA035B1FECA97","timeStamp":"1675953260605","userPwd":"123456","username":"13258556988"} 
deskey: 65102933 
desIv: 32028092
encodeDesMap: NIszaqFPos1vd0pFqKlB42Np5itPxaNH//FDsRnlBfgL4lcVxjXii/UNcdXYMk0EbKdY0NLSwwFz
rDi3e6GNtkV6lxF18rOwC0ljfaCvUVSspPnzB2mfNvJPDutqTnTsPwcaqzXNKmmhnHNPJd7s5bIH
OeqgVNfdlJ/rTZK7koJWj3zqiVHksUkI1PYRm9HccAeksGWW9XF1K9TxWgTyZ3sYUUl7d0wX

抓包数据

POST /api/user/login HTTP/1.1
If-Modified-Since: Thu, 09 Feb 2023 13:56:49 GMT
Content-Type: application/json; Charset=utf-8
User-Agent: Dalvik/2.1.0 (Linux; U; Android 10; Pixel 4 XL Build/QD1A.190821.011.C4)
Host: api.dodovip.com
Connection: Keep-Alive
Accept-Encoding: gzip
Content-Length: 248

{"Encrypt":"NIszaqFPos1vd0pFqKlB42Np5itPxaNH\/\/FDsRnlBfgL4lcVxjXii\/UNcdXYMk0EbKdY0NLSwwFz\nrDi3e6GNtkV6lxF18rOwC0ljfaCvUVSspPnzB2mfNvJPDutqTnTsPwcaqzXNKmmhnHNPJd7s5bIH\nOeqgVNfdlJ\/rTZK7koJWj3zqiVHksUkI1PYRm9HccAeksGWW9XF1K9TxWgTyZ3sYUUl7d0wX\n"}


#如无特别声明,该文章均为 原创,转载请遵循 署名-非商业性使用 4.0 国际(CC BY-NC 4.0) 协议,即转载请注明文章来源。
#最后编辑时间为: 2023-02-09 22:35:32



create 添加新评论

请先登陆后再发表评论