Hook Java API以获得MD5计算前数据
介绍
MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。[1]
有些人把MD5列为加密算法,这其实是不正确的,因为MD5计算本身就是不可逆的。
Java实现MD5散列计算
在Java中,我们用对数据进行MD5计算,代码大概是这样的:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Utils {
public static void main(String[] args) {
String md5 = md5("luoyesiqiu".getBytes());
System.out.println(md5);
System.out.println(md5.substring(8,24));
}
public static String md5(byte[] input){
StringBuilder md5 = new StringBuilder();
try {
MessageDigest messageDigest = MessageDigest.getInstance("md5");
byte[] buf = messageDigest.digest(input);
for (byte b : buf){
int val = b;
if(val < 0){
val += 256;
}
String hex = String.format("%02x",val);
md5.append(hex);
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return md5.toString();
}
}
以上代码会输出32位的MD5值和16位的MD5值,16位MD5值是从32位中截取的:
10ff0971d5ce668c3a9c20a8c96ba43e
d5ce668c3a9c20a8
分析和实现
众所周知,MD5计算是不可逆的。如果,我们想要得到MD5计算前的数据该怎么办?想得到MD5计算前的数据,我们可以Hook呀!Hook MessageDigest
类的digest
方法,这个方法输入要计算的数据,返回一个计算的结果,只要Hook这个方法就能得到MD5计算前的数据和计算后的数据了,完美!Hook工具这里用的frida。
在frida中,想要Hook,要用JavaScript写代码逻辑,写法可以参考我以前的博文:frida的用法--Hook Java代码篇
Hook代码
MessageDigest
类的digest
方法有两个重载方式,我们把它们都给Hook了。
这里创建一个名为hookMD5.js的文件:
var algorithm = 'MD5';
if(Java.available)
{
Java.perform(function(){
var MessageDigest= Java.use('java.security.MessageDigest');
var digest1 = MessageDigest.digest.overload("[B","int","int");
digest1.implementation=function(buf,offset,len){
var ret = digest2.call(this,buf);
parseIn(this,buf);
parseOut(this,ret);
return ret;
}
var digest2 = MessageDigest.digest.overload("[B");
digest2.implementation=function(buf){
var ret = digest2.call(this,buf);
parseIn(this,buf);
parseOut(this,ret);
return ret;
}
});
}
function parseIn(digest,input){
var Integer= Java.use('java.lang.Integer');
var String= Java.use('java.lang.String');
if(digest.getAlgorithm() != algorithm){
return;
}
try{
console.log("original:"+String.$new(input));
}
catch(e){
console.log(parseHex(input));
}
}
function parseOut(digest,ret){
var Integer= Java.use('java.lang.Integer');
var String= Java.use('java.lang.String');
var result = "";
for(var i = 0;i<ret.length;i++){
var val = ret[i];
if(val < 0){
val += 256;
}
var str = Integer.toHexString(val);
if(String.$new(str).length()==1){
str = "0" + str;
}
result += str;
}
if(digest.getAlgorithm()==algorithm){
console.log(digest.getAlgorithm() + "(32):" + result);
console.log(digest.getAlgorithm() + "(16):" + result.substring(8,24));
console.log("");
}
}
function parseHex(input){
var Integer= Java.use('java.lang.Integer');
var byte_array = "";
for(var j = 0;j<input.length;j++){
var hex = Integer.toHexString(input[j]);
if(hex.length == 1){
hex = "0" + hex;
}
byte_array += hex;
}
console.log("original(hex):");
var pair = "";
var hex_table = "";
for(var k = 0;k<byte_array.length;k++){
pair += byte_array.charAt(k);
if((k+1)%2 == 0){
pair += " "
hex_table += pair;
pair = ""
}
if((k+1)%32 == 0){
hex_table += "\n"
}
}
return hex_table;
}
写好后注入到目标进程:
frida -U -l hookMD5.js com.xxx.xxx
注:-U代表对USB设备注入;
com.xxxx.xxxx
是要Hook的App包名
Hook某App运行结果如下:
上面的frida脚本,不仅可以Hook MD5算法流程,还可以Hook SHA家族的散列算法流程,修改Javascript脚本开头的algorithm
变量即可达到目的,读者可以自行尝试。