背景
有个抓包结果被加密了
1、寻找入口,打断点
先正常请求一次,找到需要的请求接口。
寻找入口,需要重点关注几个关键字:new Promise 、new XMLHttpRequest、onreadystatechange、.interceptors.response.use、.interceptors.request.use
入口这一步很关键,入口找好了,大大降低了下面调式的工作量。
2、调试
这一步目的:请求参数是怎么加密组装的,响应参数是如何解密的。
这个 过程比较繁琐,慢慢来,F11进入关键函数后,再使用F10 一步一步往下执行。
这里响应参数被base64编码了两次
验证一下
3、代码验证测试
package com.study;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Map;
public class Test {
public static void main(String[] args) throws Exception {
String key = "8afccde05b2206ab681c65d6156b194a";
String url = "https://127.0.0.1:443/movie/app/list";
String param = "{\"pageParam\":{\"current\":1,\"size\":10},\"searchParam\":{\"movieType\":\"xxxxx\"}}";
byte[] bytes = sendPost(url, param);
ObjectMapper mapper = new ObjectMapper();
Map<String, String> result = mapper.readValue(new String(bytes), Map.class);
String data = result.get("data");
String s = decryptECB(data, key);
System.out.println(s);
}
/**
* AES ECB 解密
* @param message 密文
* @param key 密匙
* @return 解密后数据
*/
public static String decryptECB(String message, String key) {
final String cipherMode = "AES/ECB/PKCS5Padding";
try {
// 一般这里只会Base64解码一次,但是这次比较特殊,数据被编码了2次。所以需要解码2次。
byte[] messageByte = Base64.getDecoder().decode(Base64.getDecoder().decode(message));
byte[] keyByte = key.getBytes(StandardCharsets.UTF_8);
SecretKeySpec keySpec = new SecretKeySpec(keyByte, "AES");
Cipher cipher = Cipher.getInstance(cipherMode);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] content = cipher.doFinal(messageByte);
return new String(content, StandardCharsets.UTF_8);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 发送POST请求
*/
public static byte[] sendPost(String url, String params) {
HttpsURLConnection con = null;
InputStream is = null;
try {
con = (HttpsURLConnection) new URL(url).openConnection();
// 绕过证书验证
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new MyTrustManager()}, new java.security.SecureRandom());
con.setSSLSocketFactory(sc.getSocketFactory());
// 绕过验证主机名
con.setHostnameVerifier(new MyHostnameVerifier());
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
con.setUseCaches(false);
con.setConnectTimeout(5000);
con.setReadTimeout(15000);
con.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36");
if (params != null) {
OutputStream outputStream = con.getOutputStream();
outputStream.write(params.getBytes(StandardCharsets.UTF_8));
outputStream.close();
}
int len;
byte[] buf = new byte[4096];
is = con.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((len = is.read(buf)) != -1) {
baos.write(buf, 0, len);
baos.flush();
}
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (con != null) {
con.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
static class MyTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
static class MyHostnameVerifier implements HostnameVerifier {
@Override
public boolean verify(String urlHostName, SSLSession session) {
return true;
}
}
}