吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2202|回复: 15
收起左侧

[Android 原创] 某练通登录sign算法逆向

[复制链接]
Evan422 发表于 2024-4-21 03:15
本帖最后由 Evan422 于 2024-4-21 08:43 编辑

我们先抓一下包,然后准备apk逆向
91fee738c95dcec9f53047d4ad45944.png
一开始没有想到有壳的问题,拖入jadx分析后看目录类很少,凭少有的经验应该是加壳了,然后我们查一下壳
7fc146687c870e80182486af505e05c.jpg
果然,百度的壳,但是后来用mt分析时发现是是伪百度,所以直接用黑盒进行脱壳,顺利脱掉,然后我们搜索UserLogin,
(其实最开始我搜的是sign,没有找到结果)
b3f173aa9f86bac765954e37c2eab60.png
这里我们右键点击查找用例,只有一个结果,直接跟进去,来到login函数的定义处
b311c06816fcf90fdab374b7761fbca.png
这里其实我们就已经可以清晰的看到sign加密所需要的参数了,分别是{Action ,LoginID ,Pass ,OS,verifystr , HD,  PhoneType,以及addFixedParams(params)所额外添加的参数),
根据抓包分析Action 的话是路由地址这里的话是UserLogin,
LoginID的话后来分析是请求UserTipForChangePass服务器返回的LoginID的值,
Pass的话是调用encryptionPs得到的加密值,这里是将用户密码以及请求UserTipForChangePass服务器返回的LoginID进行处理
b3f173aa9f86bac765954e37c2eab60.png
我们自己实现一下这个加密逻辑
7eecd3c01a7e84fd9b592e297b6f015.png
加密后与我们抓包得到的Pass一致,算法正确,这里贴一下代码

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class EncryptionHelper {

public static String encryptionPs(String ps, String id) {
    String md5Ps = getMD5(ps);
    try {
        String en_psg = URLEncoder.encode(md5Ps + id, "GB2312");
        String unescape4 = java.net.URLDecoder.decode(en_psg, "GB2312");
        return getMD5(unescape4);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        return getMD5(md5Ps + id);
    }
}

public static String getMD5(String input) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] messageDigest = md.digest(input.getBytes());
        return convertByteToHex(messageDigest);
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
}

private static String convertByteToHex(byte[] data) {
    StringBuilder sb = new StringBuilder();
    for (byte b : data) {
        sb.append(String.format("%02x", b));
    }
    return sb.toString();
}

public static void main(String[] args) {
    String ps = ""; //用户密码
    String id = ""; // 请求UserTipForChangePass服务器返回的LoginID值
    String encryptedPs = encryptionPs(ps, id);
    System.out.println("加密后的密码为: " + encryptedPs);
}

}


OS,verifystr这两个参数可以固定,HD是随机生成的uuid值那么我们其实也可以固定
79c2f9e7bc2bc06a55235b67f45a7af.png
最后一个就是这个addFixedParams,我们看看它往我们的参数中添加了哪些额外参数,我们右键跟进去
f028e0e2f373ea60a9a4fe26dd635cc.png
其实也很清晰,这里面除了timestamp,剩下参数值都可以固定(UserID固定为零),这里的timestamp其实从长短能看出,是对当前时间戳经过处理后得到的,这里的话直接给出我实现后的时间戳处理代码

import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

public class TimeUtil {
// 设定时间格式和时区
private static final String FORMAT_DATE_TIME_STR = "yyyy-MM-dd HH:mm:ss";
private static final TimeZone TIME_ZONE = TimeZone.getTimeZone("GMT+8");  // GMT+8 时区

// 获取当前时间的时间戳
public static long getCurrentTimestamp() {
    Date currentTime = new Date();
    SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_DATE_TIME_STR);
    formatter.setTimeZone(TIME_ZONE); // 设置时区
    String formattedDate = formatter.format(currentTime);

    try {
        Date parsedDate = formatter.parse(formattedDate);
        return parsedDate.getTime() / 1000; // 转换为秒
    } catch (Exception e) {
        e.printStackTrace();
        return 0L; // 出现错误时返回0
    }
}

}



对了,还有一个密钥,这个的话很简单,一直点跳转到声明就跟进去了
55c729a4491075c16965abd85d2c4cd.png

最后的话我们实现以下sign的代码进行测试

private static String getSign(String data) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hashInBytes = md.digest(data.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : hashInBytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
System.err.println("MD5 Algorithm not found: " + e.getMessage());
return null;
}
}


12758148a648c5ea22f2309c9f0cac0.png
登录成功,sign算法正确,最后附上完整测试代码

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.stream.Stream;

public class Demo {
private static final String SIGN_KEY = "9c7b9399680658d308691f2acad58c0a";
private static final String BASE_URL = "https://server.dailiantong.com.cn/API/APPService.ashx";

public static void main(String[] args) {
    String timestamp = getCurrentTimestamp();
    String paramsValueStr = Stream.of(
                    "UserLogin", "UserTipForChangePass返回的LoginID值", "pass的加密值", "Android", "", "bdcba826-8ff0-4b5d-9428-7424a13c51fb",
                    "HUAWEI CAZ-AL10", "0", timestamp, "1.0", "Android", "DLTAndroid", "4.8.7", "huawei")
            .reduce("", String::concat);

    String fullStr = SIGN_KEY + paramsValueStr;
    String calculatedSign = getSign(fullStr);
    System.out.println("Sign: " + calculatedSign);

    try {
        String query = "?Action=UserLogin&LoginID=LoginID值&Pass=pss加密值&OS=Android&verifystr=&HD=bdcba826-8ff0-4b5d-9428-7424a13c51fb&PhoneType=HUAWEI%20CAZ-AL10&UserID=0&TimeStamp=" + timestamp + "&Ver=1.0&AppOS=Android&AppID=DLTAndroid&AppVer=4.8.7&ODM=huawei&Sign=" + calculatedSign;
        URL url = new URL(BASE_URL + query);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");

        int responseCode = conn.getResponseCode();
        System.out.println("Response Code : " + responseCode);
        BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String inputLine;
        StringBuilder response = new StringBuilder();
        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
        in.close();
        System.out.println("Response Body : " + response.toString());
    } catch (Exception e) {
        System.err.println("Error during HTTP request: " + e.getMessage());
    }
}

private static String getSign(String data) {
    try {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] hashInBytes = md.digest(data.getBytes(StandardCharsets.UTF_8));
        StringBuilder sb = new StringBuilder();
        for (byte b : hashInBytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    } catch (NoSuchAlgorithmException e) {
        System.err.println("MD5 Algorithm not found: " + e.getMessage());
        return null;
    }
}

public static String getCurrentTimestamp() {
    Date currentTime = new Date();
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    formatter.setTimeZone(TimeZone.getTimeZone("GMT+8"));
    String formattedDate = formatter.format(currentTime);

    try {
        Date parsedDate = formatter.parse(formattedDate);
        String date = String.valueOf(parsedDate.getTime() / 1000);
        return date; // 转换为秒
    } catch (Exception e) {
        e.printStackTrace();
        return "0";
    }
}

}



逆向小白,大佬勿喷感谢

免费评分

参与人数 8威望 +1 吾爱币 +27 热心值 +6 收起 理由
Sydyanlei0 + 1 用心讨论,共获提升!
PRfectDD + 1 + 1 谢谢@Thanks!
西枫游戏 + 1 + 1 某些重要的字段记得用XXX代替
merky + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
lingyun011 + 1 + 1 热心回复!
zyastc521 + 1 + 1 谢谢@Thanks!
正己 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
为之奈何? + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| Evan422 发表于 2024-4-21 08:55
图掉了,重新贴一下
正己 发表于 2024-4-21 10:06
 楼主| Evan422 发表于 2024-4-21 10:11
hualy 发表于 2024-4-21 11:16

来学习一下
clovert 发表于 2024-4-21 11:34
看看再说
zyastc521 发表于 2024-4-21 12:45
已收藏,感谢分享!
wyp123 发表于 2024-4-21 13:56
黑盒进行脱壳的黑盒是啥
qwq23496 发表于 2024-4-21 14:19
来学习学习
 楼主| Evan422 发表于 2024-4-21 14:47
wyp123 发表于 2024-4-21 13:56
黑盒进行脱壳的黑盒是啥

BlackBox32位
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-15 06:35

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表