本帖最后由 Evan422 于 2024-4-21 08:43 编辑
我们先抓一下包,然后准备apk逆向
一开始没有想到有壳的问题,拖入jadx分析后看目录类很少,凭少有的经验应该是加壳了,然后我们查一下壳
果然,百度的壳,但是后来用mt分析时发现是是伪百度,所以直接用黑盒进行脱壳,顺利脱掉,然后我们搜索UserLogin,
(其实最开始我搜的是sign,没有找到结果)
这里我们右键点击查找用例,只有一个结果,直接跟进去,来到login函数的定义处
这里其实我们就已经可以清晰的看到sign加密所需要的参数了,分别是{Action ,LoginID ,Pass ,OS,verifystr , HD, PhoneType,以及addFixedParams(params)所额外添加的参数),
根据抓包分析Action 的话是路由地址这里的话是UserLogin,
LoginID的话后来分析是请求UserTipForChangePass服务器返回的LoginID的值,
Pass的话是调用encryptionPs得到的加密值,这里是将用户密码以及请求UserTipForChangePass服务器返回的LoginID进行处理
我们自己实现一下这个加密逻辑
加密后与我们抓包得到的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值那么我们其实也可以固定
最后一个就是这个addFixedParams,我们看看它往我们的参数中添加了哪些额外参数,我们右键跟进去
其实也很清晰,这里面除了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
}
}
}
对了,还有一个密钥,这个的话很简单,一直点跳转到声明就跟进去了
最后的话我们实现以下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;
}
}
登录成功,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";
}
}
}
逆向小白,大佬勿喷感谢 |