介绍
MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。[1]
有些人把MD5列为加密算法,这其实是不正确的,因为MD5计算本身就是不可逆的。
Java实现MD5散列计算
在Java中,我们用对数据进行MD5计算,代码大概是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| 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位中截取的:
1 2
| 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的文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| 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
变量即可达到目的,读者可以自行尝试。
参考