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){
String md5 = "";
try {
MessageDigest messageDigest = MessageDigest.getInstance("md5");
byte[] buf = messageDigest.digest(input);
for (byte b : buf){
int val = b;
if(val < 0){
val += 256;
}
String str = "" + Integer.toHexString(val);
if(str.length() == 1){
str = "0" + str;
}
md5 += str;
}
} catch (
NoSuchAlgorithmException e) {
e.printStackTrace();
}
return md5;
}
}
以上代碼會輸出32位的MD5值和16位的MD5值,16位MD5值是從32位中截取的:
10ff0971d5ce668c3a9c20a8c96ba43e
d5ce668c3a9c20a8
分析和實現
眾所周知,MD5加密是不可逆的,也就是不能解密。如果,我們想要得到加密前的數據該怎么辦?想得到加密前的數據,我們可以Hook呀!Hook MessageDigest類的digest方法,這個方法輸入要加密的內容,返回加密的結果,只要Hook這個方法就能得到加密前的數據和加密后的數據了,完美!Hook工具這里用的frida。
對於frida,如果要Hook,要寫兩份代碼,一份JavaScript代碼,一份Python代碼。frida具體使用方法可以去看我以前寫的博文:frida的用法--Hook Java代碼篇
Python代碼
hookMD5.py:
import frida
import sys
def read_file_all(file):
fp=open(file)
text=fp.read()
fp.close()
return text
pass
def on_message(message, data):
if message['type'] == 'error':
print("[!] " + message['stack'])
elif message['type'] == 'send':
print(message['payload'])
if data != None:
print("[data] " + format_bytes(data))
else:
print(message)
pass
def format_bytes(bytes):
string='['
for b in bytes:
string=string+str(b)+','
return string[:len(string)-1]+"]"
pass
def main():
dev = frida.get_usb_device()
session = dev.attach("com.xxxx.xxxx")
text = read_file_all("hookMD5.js")
script = session.create_script(text)
script.on('message', on_message)
script.load()
sys.stdin.read()
pass
main()
注:
com.xxxx.xxxx改成自己想要Hook的App包名
JavaScript代碼
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;
}
寫好后把兩個腳本放在同一個目錄,運行Python腳本:
python hookMD5.py
Hook某App運行結果如下:

上面的frida腳本,不僅可以Hook MD5算法流程,還可以Hook SHA家族的散列算法流程,修改Javascript腳本開頭的algorithm變量即可達到目的,讀者可以自行嘗試。
