h5App的逆向

PC端的谷歌浏览器进入chrome://inspect/#devices

hook修改WebView为可调试

Java.perform(function(){
var WebView = Java.use('android.webkit.WebView');
WebView.$init.overload('android.content.Context').implementation = function(a){
console.log("WebView.$init is called!");
var retval = this.$init(a);
this.setWebContentsDebuggingEnabled(true);
return retval;
}
WebView.$init.overload('android.content.Context', 'android.util.AttributeSet').implementation = function(a, b){
console.log("WebView.$init is called!");
var retval = this.$init(a, b);
this.setWebContentsDebuggingEnabled(true);
return retval;
}
WebView.$init.overload('android.content.Context', 'android.util.AttributeSet', 'int').implementation = function(a, b, c){
console.log("WebView.$init is called!");
var retval = this.$init(a, b, c);
this.setWebContentsDebuggingEnabled(true);
return retval;
}
WebView.$init.overload('android.content.Context', 'android.util.AttributeSet', 'int', 'boolean').implementation = function(a, b, c, d){
console.log("WebView.$init is called!");
var retval = this.$init(a, b, c, d);
this.setWebContentsDebuggingEnabled(true);
return retval;
}
WebView.$init.overload('android.content.Context', 'android.util.AttributeSet', 'int', 'int').implementation = function(a, b, c, d){
console.log("WebView.$init is called!");
var retval = this.$init(a, b, c, d);
this.setWebContentsDebuggingEnabled(true);
return retval;
}
WebView.$init.overload('android.content.Context', 'android.util.AttributeSet', 'int', 'java.util.Map', 'boolean').implementation = function(a, b, c, d, e){
console.log("WebView.$init is called!");
var retval = this.$init(a, b, c, d, e);
this.setWebContentsDebuggingEnabled(true);
return retval;
}
WebView.$init.overload('android.content.Context', 'android.util.AttributeSet', 'int', 'int', 'java.util.Map', 'boolean').implementation = function(a, b, c, d, e, f){
console.log("WebView.$init is called!");
var retval = this.$init(a, b, c, d, e, f);
this.setWebContentsDebuggingEnabled(true);
return retval;
}

WebView.setWebContentsDebuggingEnabled.implementation = function(){
this.setWebContentsDebuggingEnabled(true);
console.log("setWebContentsDebuggingEnabled is called!");
}
});

编码

Hex编码

一个十六进制字符占4个bit位,半个字节,UTF-8编码的中文一个汉字占3个字节

Base64编码

一个65个字符,包括补位的”=”,进行get请求时,前端发送了’+’又没有使用URL编码,后端接收到的就是’ ‘(空格)

  • \n是Linux下的换行,\r\n是windows下的换行

消息摘要算法

  • 不停长度的输入产生固定长度的输出

MD5算法

MessageDigest md5 = MessageDigest.getInstance("MD5");//这行代码创建了一个 MessageDigest 对象,用于生成 MD5 哈希。getInstance("MD5") 指定了使用 MD5 算法。
md5.update("xiaojianbang".getBytes());//update 方法将要被哈希的字节数组(这里是字符串 "xiaojianbang" 的字节表示)传递给 MessageDigest 对象。getBytes() 方法将字符串转换为字节数组。
//update的重载函数
md5.update("xiaojianbang".getBytes(),1,3);
//从下标为1的开始取(第一个字节下标为0),长度为3
byte [] = md5.digest();//digest() 方法计算并返回当前更新内容的 MD5 哈希值。调用此方法后,MessageDigest 对象将被重置,无法再用于更新数据。
//编译成十六进制
System.out.println(HexBin.encode(result));
//Base64编码
System.out.println(Base64.getEncode().encodeToString(result));
//也可以直接一行代码
byte[] result = MessageDigest.getInstance("MD5").digest("xiaojianbang".getBytes());

SHA

MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.update("xiaojianbang".getBytes());
shaq.digest();

MD5、SHA算法通杀

工具函数的封装

Java.perform(function(){
function showStacks(){
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}
var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(tag,data){
console.log(tag+"Base64:"+ByteString.of(data).base64());
}
function toHex(tag,data){
console.log(tag+"Hex:"+ByteString.of(data).hex());
}
function toUtf8(tag,data){
console.log(tag+"Utf8:"+ByteString.of(data).utf8());
}
});

通杀MD5、SHAhook代码

Java.perform(function () {

function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(tag, data) {
console.log(tag + " Base64: " + ByteString.of(data).base64());
}
function toHex(tag, data) {
console.log(tag + " Hex: " + ByteString.of(data).hex());
}
function toUtf8(tag, data) {
console.log(tag + " Utf8: " + ByteString.of(data).utf8());
}

// toUtf8("xiaojianbang",[48, 49, 50, 51, 52]);
// toBase64("xiaojianbang",[48, 49, 50, 51, 52]);
// toHex("xiaojianbang",[48, 49, 50, 51, 52]);

var messageDigest = Java.use("java.security.MessageDigest");
messageDigest.update.overload('byte').implementation = function (data) {
console.log("MessageDigest.update('byte') is called!");
showStacks();
return this.update(data);
}
messageDigest.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("MessageDigest.update('java.nio.ByteBuffer') is called!");
showStacks();
return this.update(data);
}
messageDigest.update.overload('[B').implementation = function (data) {
console.log("MessageDigest.update('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
messageDigest.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.update('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}

messageDigest.digest.overload().implementation = function () {
console.log("MessageDigest.digest() is called!");
showStacks();
var result = this.digest();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest result";
toUtf8(tag, result);
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B').implementation = function (data) {
console.log("MessageDigest.digest('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data);
var tags = algorithm + " digest result";
toUtf8(tag, result);
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.digest('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data, start, length);
var tags = algorithm + " digest result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================", start, length);
return result;
}
});

MAC算法

MAC的Java实现

SecretKeySpec secreKeySpec = new SecretKeySpec("a12345678".getBytes(),"HmacSHA1");//创建一个 SecretKeySpec 对象,该对象是 HMAC 的密钥。这里使用的密钥是字符串 "a12345678",通过 getBytes() 方法将其转换为字节数组。
//指定算法为 "HmacSHA1",表示使用 SHA-1 哈希算法进行 HMAC 签名。
Mac mac = Mac.getInstance(secretKeySpec.getAlgorithm());//创建一个 Mac 对象,使用之前定义的算法(HmacSHA1)。
mac.init(secretKeySpec);//初始化 Mac 对象,使用之前创建的密钥 secreKeySpec
mac.update("xiaojianbang".getBytes());//将要签名的数据(字符串 "xiaojianbang")转换为字节数组并更新到 Mac 对象中。
mac.doFinal();//计算 HMAC 签名并返回结果。这个方法会返回一个字节数组,表示对输入数据的 HMAC 签名结果。


MAC算法通杀hook代码

Java.perform(function () {

function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}
var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(tag, data) {
console.log(tag + " Base64: " + ByteString.of(data).base64());
}
function toHex(tag, data) {
console.log(tag + " Hex: " + ByteString.of(data).hex());
}
function toUtf8(tag, data) {
console.log(tag + " Utf8: " + ByteString.of(data).utf8());
}

var mac = Java.use("javax.crypto.Mac");
mac.init.overload('java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (key, AlgorithmParameterSpec) {
console.log("Mac.init('java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
return this.init(key, AlgorithmParameterSpec);
}
mac.init.overload('java.security.Key').implementation = function (key) {
console.log("Mac.init('java.security.Key') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var keyBytes = key.getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
console.log("=======================================================");
return this.init(key);
}
mac.update.overload('byte').implementation = function (data) {
console.log("Mac.update('byte') is called!");
return this.update(data);
}
mac.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("Mac.update('java.nio.ByteBuffer') is called!");
return this.update(data);
}
mac.update.overload('[B').implementation = function (data) {
console.log("Mac.update('[B') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
mac.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("Mac.update('[B', 'int', 'int') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
mac.doFinal.overload().implementation = function () {
console.log("Mac.doFinal() is called!");
var result = this.doFinal();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal result";
toUtf8(tag, result);
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
mac.doFinal.overload('[B').implementation = function (data) {
console.log("Mac.doFinal.overload('[B') is called!");
return this.doFinal(data);
}
mac.doFinal.overload('[B', 'int').implementation = function (output, outOffset) {
console.log("Mac.doFinal.overload('[B', 'int') is called!");
return this.doFinal(output, outOffset);
}

});

对称加密算法

DES算法

DES的Java实现

SecretKeySpec desKey = new SecrectKeySpec("12345678".getBytes(),"DES");//创建一个 SecretKeySpec 对象,使用字符串 "12345678" 作为密钥,并指定使用 DES 加密算法。注意,DES 密钥长度必须为 8 字节。
Cipher des = Cipher.getInstance("DES/ECB/PKCS5Paddin");//获取一个 Cipher 实例,指定算法为 DES,工作模式为 ECB(电子密码本模式),填充方式为 PKCS5(填充方式用于处理非整数倍块大小的数据)。注意,原代码中的填充方式格式不正确,应该是 PKCS5Padding。
des.init(Chiper.ENCRYPT_MODE,deskey);//初始化 Cipher 对象,设置为加密模式,并传入刚创建的密钥 desKey。
byte[] result = des.doFinal("xiaojianbang" .getBytes());//使用 doFinal 方法对输入字符串 "xiaojianbang" 进行加密,返回加密结果的字节数组 result。
String hexStr = HexBin.encode(result);
System.out.println(hexStr);
System.out.println(Base64.getEncoder().encodeToString(result));
//解码
des.init(Cipher.DECRYPT_MODE,deskey);
byte[] result = des.doFinal(HexBin.decode(result));

DES的加密模式

SecretKeySpec desKey = new SecrectKeySpec("12345678".getBytes(),"DES");
IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());//长度按照对应算法的分组长度,生成一个随机的初始化向量(IV),它的长度与块大小相同(如 AES 的块大小为 16 字节,DES的块大小为8 字节)。
//将明文分成固定大小的块。
//第一个明文块与 IV 进行异或操作,然后对结果进行加密,得到第一个密文块。
//后续每个明文块与前一个密文块进行异或,然后加密,得到当前的密文块。

Cipher des = Cipher.getInstance("DES/C BC/PKCS5Paddin");
des.init(Chiper.ENCRYPT_MODE,deskey,ivParameterSpec);
byte[] result = des.doFinal("xiaojianbang" .getBytes());
String hexStr = HexBin.encode(result);
System.out.println(hexStr);
System.out.println(Base64.getEncoder().encodeToString(result));
des.init(Cipher.DECRYPT_MODE,deskey);
byte[] result = des.doFinal(HexBin.decode(result));

DES的填充方式

Cipher des = Cipher.getInstance("DES/CBC/NOPadding");//明文长度必须要和分组长度一致
Cipher des = Cipher.getInstance("DES/CBC/PKCS5Paddin");

  • 有使用到的密钥长度为56bit,每个字节的最后一个bit都没使用,例如12345678和03254769的加密结果一样

DESede算法(3DES算法)

  • DES加密
  • DES解密
  • DES加密

DESede的加解密Java实现

SecretKeySpec secretKeySpec = new SecretKeySpec("123456781234567812345678".getBytes(),"DESede");
IvParameterSpec ivParameterSpec = new IvParameterSpec("12345678".getBytes());
Cipher desede = Cipher.getInstance("DESede/CBC/PKCS5Padding");
desede.init(Cipher.ENCRYPT_MODE,secretKyeSpec,ivParameterSpec);
byte[] result = desede.doFinal("xiaojianbang".getBytes());
String hexStr = HexBin.encode(result);

AES

AES加解密的Java实现

SecretKeySpec key = new SecretKeySpec("1234567890abcdef".getBytes(),"AES");
AlgorithmParameterSpec iv = new IvParamterSpec("1234567890abcdef".getBytes());
Cipher aes = Cipher.getInstance("AES/CBC/PKCStPadding");
aes.init(Cipher.ENCRYPT_MODE,key,iv);
byte[] result = aes.doFinal("xiaojianbang1234xiaojianbang1234".getBytes());
String hexStr = HexBin.encode(result);
System.out.println(hexStr);
System.out.println(Base64.getEncoder().encodeToString(result));

DES、DESede、AES通杀hook

Java.perform(function () {

function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(tag, data) {
console.log(tag + " Base64: " + ByteString.of(data).base64());
}
function toHex(tag, data) {
console.log(tag + " Hex: " + ByteString.of(data).hex());
}
function toUtf8(tag, data) {
console.log(tag + " Utf8: " + ByteString.of(data).utf8());
}



var cipher = Java.use("javax.crypto.Cipher");
cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function () {
console.log("Cipher.init('int', 'java.security.cert.Certificate') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.SecureRandom') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.cert.Certificate', 'java.security.SecureRandom') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}

cipher.init.overload('int', 'java.security.Key').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var className = JSON.stringify(arguments[1]);
if(className.indexOf("OpenSSLRSAPrivateKey") === -1){
var keyBytes = arguments[1].getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
}
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var keyBytes = arguments[1].getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
var tags = algorithm + " init iv";
var iv = Java.cast(arguments[2], Java.use("javax.crypto.spec.IvParameterSpec"));
var ivBytes = iv.getIV();
toUtf8(tags, ivBytes);
toHex(tags, ivBytes);
toBase64(tags, ivBytes);
console.log("=======================================================");
return this.init.apply(this, arguments);
}

cipher.doFinal.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function () {
console.log("Cipher.doFinal('java.nio.ByteBuffer', 'java.nio.ByteBuffer') is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int') is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int', '[B') is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int', '[B', 'int') is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload().implementation = function () {
console.log("Cipher.doFinal() is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}

cipher.doFinal.overload('[B').implementation = function () {
console.log("Cipher.doFinal('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal data";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " doFinal result";
toUtf8(tags, result);
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================");
return result;
}
cipher.doFinal.overload('[B', 'int', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal data";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " doFinal result";
toUtf8(tags, result);
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================", arguments[1], arguments[2]);
return result;
}

});

非对称加密算法

RSA的密钥解析

byte[] keyBytes = Base64Decoder.decodeBuffer(key);//这一行使用 Base64Decoder 将一个 Base64 编码的字符串(key)解码为字节数组(keyBytes)。Base64 编码通常用于在文本格式中传输二进制数据,如公钥。
X509EncodeKeySpec keySpec = new X509EncodedKeySpec(keyBytes);//这里创建了一个 X509EncodedKeySpec 对象,该对象表示通过 X.509 标准编码的公钥。这个类的构造函数接受之前解码的字节数组。
KeyFactory keyFactory = KeyFactory.getInstance("RSA");//这行代码获取一个 KeyFactory 实例,指定使用 "RSA" 算法。KeyFactory 用于转换密钥规格(如公钥或私钥)为相应的密钥对象
PublicKey publicKey = keyFactory.generatePublic(keySpec);//最后,这行代码使用 KeyFactory 生成 PublicKey 对象,输入是之前创建的 X509EncodedKeySpec。这意味着 publicKey 现在是一个可以用来执行加密操作的 RSA 公钥。

byte[] keyBytess = publicKey.geteEncoded();//这一行调用 publicKey 对象的 getEncoded() 方法,这个方法返回公钥的字节数组表示。通常,这个字节数组是以 X.509 格式编码的。
System.out.println(Base64.getEncoder().encodeToString(keyBytess));// Base64 类的编码器将字节数组 keyBytess 转换为 Base64 编码的字符串,并将结果输出到控制台。encodeToString 方法会把字节数组转换为可读的字符串形式,方便传输或存储。

byte[] keyBytes = Base64Decoder.decodeBuffere(key);
PKCS8EncodedKeySpec keySpec = new PKCSBEncodedKeySpec(keyBytes);
keyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
byte[] privatekeyBytess = privateKeys.getEncoded();
System.out.println(Base64.getEncoder().encodeToString(privateKeyBytess));

RSA的加解密

Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE,publicKey);
byte[] bt_encrypted = cipher.doFinal(bt_plaintext);

Cipher cipher = Cipher.getInstance("RSA/None/NOPadding");
cipher.init(Cipher.DECRYPT_MODE,privateKey);
byte[] bt_original = cipher.doFinal(bt_encrypted);

RSA的加密模式和填充方式

RSA密钥的转换

RSA算法通杀

Java.perform(function () {

function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(tag, data) {
console.log(tag + " Base64: " + ByteString.of(data).base64());
}
function toHex(tag, data) {
console.log(tag + " Hex: " + ByteString.of(data).hex());
}
function toUtf8(tag, data) {
console.log(tag + " Utf8: " + ByteString.of(data).utf8());
}

// toUtf8("xiaojianbang",[48, 49, 50, 51, 52]);
// toBase64("xiaojianbang",[48, 49, 50, 51, 52]);
// toHex("xiaojianbang",[48, 49, 50, 51, 52]);

var messageDigest = Java.use("java.security.MessageDigest");
messageDigest.update.overload('byte').implementation = function (data) {
console.log("MessageDigest.update('byte') is called!");
console.log("=======================================================");
return this.update(data);
}
messageDigest.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("MessageDigest.update('java.nio.ByteBuffer') is called!");
console.log("=======================================================");
return this.update(data);
}
messageDigest.update.overload('[B').implementation = function (data) {
console.log("MessageDigest.update('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
messageDigest.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.update('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}

messageDigest.digest.overload().implementation = function () {
console.log("MessageDigest.digest() is called!");
showStacks();
var result = this.digest();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest result";
toUtf8(tag, result);
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B').implementation = function (data) {
console.log("MessageDigest.digest('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data);
var tags = algorithm + " digest result";
toUtf8(tag, result);
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.digest('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data, start, length);
var tags = algorithm + " digest result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================", start, length);
return result;
}

var mac = Java.use("javax.crypto.Mac");
mac.init.overload('java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (key, AlgorithmParameterSpec) {
console.log("Mac.init('java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
console.log("=======================================================");
return this.init(key, AlgorithmParameterSpec);
}
mac.init.overload('java.security.Key').implementation = function (key) {
console.log("Mac.init('java.security.Key') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var keyBytes = key.getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
console.log("=======================================================");
return this.init(key);
}
mac.update.overload('byte').implementation = function (data) {
console.log("Mac.update('byte') is called!");
return this.update(data);
}
mac.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("Mac.update('java.nio.ByteBuffer') is called!");
console.log("=======================================================");
return this.update(data);
}
mac.update.overload('[B').implementation = function (data) {
console.log("Mac.update('[B') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
mac.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("Mac.update('[B', 'int', 'int') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
mac.doFinal.overload().implementation = function () {
console.log("Mac.doFinal() is called!");
var result = this.doFinal();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal result";
toUtf8(tag, result);
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
mac.doFinal.overload('[B').implementation = function (data) {
console.log("Mac.doFinal.overload('[B') is called!");
return this.doFinal(data);
}
mac.doFinal.overload('[B', 'int').implementation = function (output, outOffset) {
console.log("Mac.doFinal.overload('[B', 'int') is called!");
console.log("=======================================================");
return this.doFinal(output, outOffset);
}

var cipher = Java.use("javax.crypto.Cipher");
cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function () {
console.log("Cipher.init('int', 'java.security.cert.Certificate') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.SecureRandom') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.cert.Certificate', 'java.security.SecureRandom') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.AlgorithmParameters') is called!");
console.log("=======================================================");
return this.init.apply(this, arguments);
}

cipher.init.overload('int', 'java.security.Key').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var className = JSON.stringify(arguments[1]);
if(className.indexOf("OpenSSLRSAPrivateKey") === -1){
var keyBytes = arguments[1].getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
}
console.log("=======================================================");
return this.init.apply(this, arguments);
}
cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function () {
console.log("Cipher.init('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var keyBytes = arguments[1].getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
var tags = algorithm + " init iv";
var iv = Java.cast(arguments[2], Java.use("javax.crypto.spec.IvParameterSpec"));
var ivBytes = iv.getIV();
toUtf8(tags, ivBytes);
toHex(tags, ivBytes);
toBase64(tags, ivBytes);
console.log("=======================================================");
return this.init.apply(this, arguments);
}

cipher.doFinal.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function () {
console.log("Cipher.doFinal('java.nio.ByteBuffer', 'java.nio.ByteBuffer') is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int') is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int', '[B') is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload('[B', 'int', 'int', '[B', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int', '[B', 'int') is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}
cipher.doFinal.overload().implementation = function () {
console.log("Cipher.doFinal() is called!");
console.log("=======================================================");
return this.doFinal.apply(this, arguments);
}

cipher.doFinal.overload('[B').implementation = function () {
console.log("Cipher.doFinal('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal data";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " doFinal result";
toUtf8(tags, result);
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================");
return result;
}
cipher.doFinal.overload('[B', 'int', 'int').implementation = function () {
console.log("Cipher.doFinal('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal data";
var data = arguments[0];
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.doFinal.apply(this, arguments);
var tags = algorithm + " doFinal result";
toUtf8(tags, result);
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================", arguments[1], arguments[2]);
return result;
}
});

数字签名算法

Java实现

//签名
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] privatekeyBytes = Base64.getDecoder().decode(privateKey);
PKCS8EncodedKeySpec privatekeySpec = new PKCS8EncodedKeySpec(privatekeyBytes);
PrivateKey privateKeys = keyFactory.generatePrivate(privatekeySpec);

Signature sig =Signatute.getInstance("SHA356withRSA");
sig.initSign(privateKeys);
sig.update("xiaojianbang".getBytes());
byte[] signResult = sig.sign();
System.out.println(Base64.getEncoder().encodeToString(signResult));
//验证
byte[] keyBytes = Base64.getDecoder().decode(pubkey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
publicKey publicKey - keyFactory.generatePublic(keySpec);
sig.ininVerify(publicKey);
sig.update("xiaojianbang".getBytes());
boolean isTrue = sig.verify(signResult);
System.out.println(isTrue);

数字签名算法的通杀hook


Java.perform(function () {

function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}

function logOutPut(msg) {
Java.use("android.util.Log").d("xiaojianbang", "frida inject: " + msg);
}

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(tag, data) {
//logOutPut(tag + " Base64: " + ByteString.of(data).base64());
console.log(tag + " Base64: " + ByteString.of(data).base64());
}
function toHex(tag, data) {
//logOutPut(tag + " Hex: " + ByteString.of(data).hex());
console.log(tag + " Hex: " + ByteString.of(data).hex());
}
function toUtf8(tag, data) {
//logOutPut(tag + " Utf8: " + ByteString.of(data).utf8());
console.log(tag + " Utf8: " + ByteString.of(data).utf8());
}

var signature = Java.use("java.security.Signature");
signature.update.overload('byte').implementation = function (data) {
console.log("Signature.update('byte') is called!");
return this.update(data);
}
signature.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("Signature.update('java.nio.ByteBuffer') is called!");
return this.update(data);
}
signature.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("Signature.update('[B', 'int', 'int') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
signature.sign.overload('[B', 'int', 'int').implementation = function () {
console.log("Signature.sign('[B', 'int', 'int') is called!");
return this.sign.apply(this, arguments);
}
signature.sign.overload().implementation = function () {
console.log("Signature.sign() is called!");
var result = this.sign();
var algorithm = this.getAlgorithm();
var tag = algorithm + " sign result";
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
});

CryptoJS