首页 > 其他分享 >某物登录表单加密

某物登录表单加密

时间:2024-03-29 22:30:35浏览次数:32  
标签:console log java 表单 tag var 加密 某物 data

之前分析过某物h5的以及小程序的搜索接口,就是一个aes,秘钥不固定,表单里把秘钥以及密文一起发过去,服务器解密后再把数据加密返回,客户端解密展示到页面上.
这期是关于app的登录,密码登录

声明

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!
本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!
我创建了一个js 安卓 ios逆向的技术交流群,刚兴趣的可以加一下,在最后面.

抓包

在这里插入图片描述
可以看到表单里有newSign,password,userName加密了,都是32位的.并且响应也是加密的.
在这里插入图片描述
再来看看头部,框中的那几个都是可能需要分析的,其中有一个shumeiid,这个是数美sdk里的.这个难度估计有点大,这个我们下期分析,SK和edk和ltk自行研究,后面看了下so的结构,就算是so的难度应该也不会太大.这几个貌似都没变,但是ltk是一直变化的.这个也留着后面分析.

反编译

先查下壳,没加固,总算碰到一个没加固的,前几期都是加固的,看来是对自己的产品比较有信心.

尝试搜索下字符串username
在这里插入图片描述

有点多,这样一个个点过去太麻烦了,尝试hook hashmap

    var hashMap = Java.use("java.util.HashMap");
hashMap.put.implementation = function (a, b) {
    if(a!=null && a.equals("userName")){
        console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
        console.log("hashMap.put: ", a, b);
    }
    return this.put(a, b);
}

frida反调试

frida启动后以attach注入
在这里插入图片描述

直接断开,同时app会重启,这里用的已经是去过特征版的frida了,葫芦娃编译的,还是被检测到了.
以spawn方式启动试试
在这里插入图片描述
直接断开并没有重启,来看看它加载了哪些so.肯定是so的检测

var dlopen = Module.findExportByName(null, "dlopen");
var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");

Interceptor.attach(dlopen, {
    onEnter: function (args) {
        var path_ptr = args[0];
        var path = ptr(path_ptr).readCString();
        console.log("[dlopen:]", path);
    },
    onLeave: function (retval) {

    }
});
Interceptor.attach(android_dlopen_ext, {
    onEnter: function (args) {
        var path_ptr = args[0];
        var path = ptr(path_ptr).readCString();
        console.log("[dlopen_ext:]", path);
    },
    onLeave: function (retval) {
    }
});

在这里插入图片描述

libmsaoaidsec.so mobile security alliance open aid security,字面意思,看着就不是什么好东西,网上有分析libmsaoaidsec.so的文章,自行检索,我这里是直接把它删掉,有些app可以这样过,有些删了会闪退,闪退的话只能把它过掉.
删掉后frida可以正常使用,直接attach即可.
在这里插入图片描述

看到mobileLogin字眼,jadx中点过去看看
在这里插入图片描述
f.c方法点过去看看
在这里插入图片描述
看到了AES ECB字眼,应该是java层的,这样的话其他的几个也有可能是java层的,但是在上面图中的hashmap中没有看到newsign字眼,这个app用的okhttp3框架,极有可能是用的okhttp3.Interceptor添加的.因为有可能是java层的,有3个参数,当然优先考虑java通杀方案.

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) {
        //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 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";
        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";
        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!");
        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";
        toHex(tag, result);
        toBase64(tag, result);
        console.log("=======================================================");
        return result;
    }

    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!");
        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!");
        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!");
        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!");
        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!");
        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!");
        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!");
        showStacks();
        return this.doFinal.apply(this, arguments);
    }
    cipher.doFinal.overload('[B', 'int').implementation = function () {
        console.log("Cipher.doFinal('[B', 'int') is called!");
        showStacks();
        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!");
        showStacks();
        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!");
        showStacks();
        return this.doFinal.apply(this, arguments);
    }
    cipher.doFinal.overload().implementation = function () {
        console.log("Cipher.doFinal() is called!");
        showStacks();
        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";
        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";
        toHex(tags, result);
        toBase64(tags, result);
        console.log("=======================================================", arguments[1], arguments[2]);
        return result;
    }

    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;
    }
});

不过我比较喜欢用算法助手,原理是一样的.先在lsp里把目标app勾上,算法助手页面把这个app打开

在这里插入图片描述
全部勾上后重启app,登录一下,抓包同时开着,这个包里的

{
	"cipherParam": "userName",
	"countryCode": 86,
	"loginToken": "",
	"newSign": "614a0f4d2ef049ff1d0145b0a96d2ef0",
	"password": "ca8f119a27ec17f98b463807cd0b6b62",
	"platform": "android",
	"timestamp": "1711714586437",
	"type": "pwd",
	"userName": "83c7358c94e3a24e11f0fde1cbf5d559_1",
	"v": "5.38.5"
}

userName

日志里搜一下83c7358c94e3a24e11f0fde1cbf5d559,后面的_1自己添加上去的.
在这里插入图片描述

有结果
在这里插入图片描述

aes ecb nopadding,无填充是因为已经填充过了,看明文后面那一串,直接用pkcs7就可以了.userName解决

password

直接搜ca8f119a27ec17f98b463807cd0b6b62
在这里插入图片描述
在这里插入图片描述
密码加一个盐值,没什么好说的.

newSign

搜一下614a0f4d2ef049ff1d0145b0a96d2ef0
在这里插入图片描述

md5签的一串base64值.搜索这个值有没有结果,搜一部分dWWoXlbR3K87j2N27Dkv4uOPUnOsh0xrJ5t
在这里插入图片描述
没有搜到,这个值是base64过的,尝试hook一下base64的encodeToString方法

var base64 = Java.use("android.util.Base64");
base64.encodeToString.overload('[B', 'int').implementation = function (a, b) {
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()))
console.log("base64.encodeToString: ", JSON.stringify(a));
var result = this.encodeToString(a, b);
console.log("base64.encodeToString result: ", result)
return result;
    }

没有hook到,估计是so base64后返回的,所以没有hook到.
先看下先前的堆栈
在这里插入图片描述

let i0 = Java.use("gf.i0");
i0["c"].implementation = function (map, j, str) {
    console.log(`i0.c is called: map=${map}, j=${j}, str=${str}`);
    let result = this["c"](map, j, str);
    console.log(`i0.c result=${result}`);
    return result;
};

hook一下这个c方法,入参的str是空值
在这里插入图片描述
中间添加了些东西,这里直接跟这个aesencrypt.encode方法,一路跟到
在这里插入图片描述
encodebyte方法,写这个方法的主动调用

function call2(){
    Java.perform(function (){
    let AESEncrypt = Java.use("com.duapp.aesjni.AESEncrypt");
    var str='010110100010001010010010000011000111001011101010101000101110111010011010101101101010001000101100010110100010001010011010110011001111001011100010101000100100110010110010100010101011110010111100'
    var bArr = [99,105,112,104,101,114,80,97,114,97,109,117,115,101,114,78,97,109,101,99,111,117,110,116,114,121,67,111,100,101,56,54,108,111,103,105,110,84,111,107,101,110,112,97,115,115,119,111,114,100,99,97,56,102,49,49,57,97,50,55,101,99,49,55,102,57,56,98,52,54,51,56,48,55,99,100,48,98,54,98,54,50,112,108,97,116,102,111,114,109,97,110,100,114,111,105,100,116,105,109,101,115,116,97,109,112,49,55,49,49,55,48,52,48,56,49,52,55,54,116,121,112,101,112,119,100,117,115,101,114,78,97,109,101,56,51,99,55,51,53,56,99,57,52,101,51,97,50,52,101,49,49,102,48,102,100,101,49,99,98,102,53,100,53,53,57,95,49,117,117,105,100,49,48,49,51,48,48,102,98,51,57,48,51,48,56,52,101,118,53,46,51,56,46,53]
    var res = AESEncrypt["encodeByte"](bArr, str)
    console.log(res)
    })
}

des 3des aes关系

第一个字符串转16进制后是24字节,写文章之前不记得前面有个aes了,以为这个是3des,3des秘钥就是24字节,3des由des进化过来的,因为des不安全,那个时候aes还没出来,aes中的a是advanced,高级的,由des进化而来,aes的原始名称是Rijndael算法,是由创造这个算法的两位作者名字组成的.因为是在des基础上改进的,所以大家都称它aes.
des秘钥8字节太短了,aes有16字节,24字节,32字节的,密钥的长度在一定程度上决定着算法的安全性,而DES密钥长度过短,也就导致了它的安全性较低;而AES则更加安全,这也是AES能够取代DES的重要原因之一.
在aes还没出之前为了解决des安全性的问题,有专家推出了3des,cyberchef中名称是TripleDES,Triple有3的意思,秘钥24字节,由3把秘钥组成,每8个字节算一把秘钥,加密流程如图所示,如果前两把秘钥相同,就相当于只有一次des加密,3des目前已被证明安全性不足,目前用的都是aes,如果没记错的话某书的x-s就是用的3des,好吧扯得有点远了,回到正文.
在这里插入图片描述
用3des加密一遍结果不对,只能看so了.

第一个数组转utf-8

import base64
byte_list = [99,105,112,104,101,114,80,97,114,97,109,117,115,101,114,78,97,109,101,99,111,117,110,116,114,121,67,111,100,101,56,54,108,111,103,105,110,84,111,107,101,110,112,97,115,115,119,111,114,100,99,97,56,102,49,49,57,97,50,55,101,99,49,55,102,57,56,98,52,54,51,56,48,55,99,100,48,98,54,98,54,50,112,108,97,116,102,111,114,109,97,110,100,114,111,105,100,116,105,109,101,115,116,97,109,112,49,55,49,49,55,48,52,48,56,49,52,55,54,116,121,112,101,112,119,100,117,115,101,114,78,97,109,101,56,51,99,55,51,53,56,99,57,52,101,51,97,50,52,101,49,49,102,48,102,100,101,49,99,98,102,53,100,53,53,57,95,49,117,117,105,100,49,48,49,51,48,48,102,98,51,57,48,51,48,56,52,101,118,53,46,51,56,46,53]
num_list = bytearray()
for item in byte_list:
    if item < 0:
        item = item + 256
    num_list.append(item)
utf8_string = num_list.decode()
print('utf8_string:',utf8_string)

结果就是表单里除了newsign的东西cipherParamuserNamecountryCode86loginTokenpasswordca8f119a27ec17f98b463807cd0b6b62platformandroidtimestamp1711704081476typepwduserName83c7358c94e3a24e11f0fde1cbf5d559_1uuid101300fb3903084ev5.38.5,再拼了一个uuid和版本号.

so加固

上图中so的名字是libJNIEncrypt.so,只有64位的,用ida64打开
在这里插入图片描述

提示文件结果被破坏,点yes
在这里插入图片描述
警告这个so有无意义或者无效的节.点ok.
在这里插入图片描述
刚进来两处爆红,上面一条都是灰色的,没有代码段,不用想,加固了.

so dump

dump内存中的so,yang神的脚本

function dump_so(so_name) {
    Java.perform(function () {
        var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
        var dir = currentApplication.getApplicationContext().getFilesDir().getPath();
        var libso = Process.getModuleByName(so_name);
        console.log("[name]:", libso.name);
        console.log("[base]:", libso.base);
        console.log("[size]:", ptr(libso.size));
        console.log("[path]:", libso.path);
        var file_path = dir + "/" + libso.name + "_" + libso.base + "_" + ptr(libso.size) + ".so";
        var file_handle = new File(file_path, "wb");
        if (file_handle && file_handle != null) {
            Memory.protect(ptr(libso.base), libso.size, 'rwx');
            var libso_buffer = ptr(libso.base).readByteArray(libso.size);
            file_handle.write(libso_buffer);
            file_handle.flush();
            file_handle.close();
            console.log("[dump]:", file_path);

        }
    });
}
dump_so("libJNIEncrypt.so")

dump下来拉到电脑上用sofixer修复一下.
在这里插入图片描述

dump下来的没有前面的警告了,上面的"进度条"也变成了蓝色,同时看到了Jnionload,动态注册,以及base64和aes128,难怪之前hook不到base64,原来是so base64的
接下来找动态注册函数.hook libart

var addrRegisterNatives = null;
var symbols = Module.enumerateSymbolsSync("libart.so");
for (var i = 0; i < symbols.length; i++) {
    var symbol = symbols[i];
    if (symbol.name.indexOf("art") >= 0 &&
        symbol.name.indexOf("JNI") >= 0 &&
        symbol.name.indexOf("RegisterNatives") >= 0 &&
        symbol.name.indexOf("CheckJNI") < 0) {

        addrRegisterNatives = symbol.address;
        console.log("RegisterNatives is at ", symbol.address, symbol.name);
        break
    }
}
if (addrRegisterNatives) {
    // RegisterNatives(env, 类型, Java和C的对应关系,个数)
    Interceptor.attach(addrRegisterNatives, {
        onEnter: function (args) {
            var env = args[0];        // jni对象
            var java_class = args[1]; // 类
            var class_name = Java.vm.tryGetEnv().getClassName(java_class);
            var taget_class = "com.duapp.aesjni.AESEncrypt";   //111 某个类中动态注册的so
            if (class_name === taget_class) {
                //只找我们自己想要类中的动态注册关系
                console.log("\n[RegisterNatives] method_count:", args[3]);
                var methods_ptr = ptr(args[2]);
                var method_count = parseInt(args[3]);
                for (var i = 0; i < method_count; i++) {
                    // Java中函数名字的
                    var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
                    // 参数和返回值类型
                    var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
                    // C中的函数内存地址
                    var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));
                    var name = Memory.readCString(name_ptr);
                    var sig = Memory.readCString(sig_ptr);
                    var find_module = Process.findModuleByAddress(fnPtr_ptr);
                    // 地址、偏移量、基地址
                    var offset = ptr(fnPtr_ptr).sub(find_module.base);
                    console.log("name:", name, "sig:", sig,'module_name:',find_module.name ,"offset:", offset);
                }
            }
        }
    });
}

以spawn启动
在这里插入图片描述
0x174c,ida中跳过去看看,然后转换一下jnienv对象
在这里插入图片描述

看返回值,来自v18,v18来自j_AES_128_ECB_PKCS5Padding_Encrypt,很明显了,ecb无iv 16字节秘钥,pkcs5填充,直接frida hook这个函数打印两个入参.

var soAddr = Module.findBaseAddress("libJNIEncrypt.so");
var funcAddr = soAddr.add(0x182C)  //32位的话记得+1

Interceptor.attach(funcAddr,{
            onEnter: function(args){
                console.log('onEnter arg[0]: ',hexdump(args[0]))
                console.log('onEnter arg[1]: ',hexdump(args[1]))
                this.arg0 = args[0]
            },
            onLeave: function(retval){
                // console.log('onLeave arg[]: ')
                console.log('onLeave result: ',retval)
            }
        });

入参1是java层传来的明文,参数2是key d245a0ba8d678a61,验证一下,和主动调用结果一致,最后md5就是newsign了,至此,newsign分析完毕,没什么难度的.

技术交流+lyaoyao__i(两个_),群聊7天有效
在这里插入图片描述
微信公众号
在这里插入图片描述
知识星球
在这里插入图片描述

标签:console,log,java,表单,tag,var,加密,某物,data
From: https://blog.csdn.net/xmx_000/article/details/137154339

相关文章

  • https加密过程
    1.对称加密与非对称加密在介绍https加密过程前,需要先简单了解下其中用到的加密算法。对称加密算法:用该密钥加密的数据,可以再用该密钥解密。性能高,速度快。常见的对称加密算法有DES,AES。非对称加密算法:生成一对密钥对,分别称为公钥、私钥。用公钥加密的数据只能由私钥解密。用私......
  • WPF中实现动态表单-来自GPT4的回答
    实现C#和WPF项目中的动态表单功能,需要在后端设计灵活的数据结构来存储表单配置(例如字段名、字段类型等),同时前端需要能够解析这些配置并据此生成相应的控件。以下是一种可能的实现方法:1.数据库设计你的数据库需要至少包含两个表:一个用于存储表单字段的配置,另一个用于存储用户输......
  • 如何给PDF文件加密?
    PDF作为一种常用的文档格式,本身具有很好的稳定性以及兼容性,被广泛应用于学习以及生活当中。然而,这也意味着PDF文件的安全性成为了一个不可忽视的问题。因此,进行PDF加密操作变得至关重要。那么有那些好用的pdf加密的工具呢?1、nitropdf.com这是一款功能强大的PDF编辑软件,你可以使......
  • 五款常用在线JavaScript加密混淆工具详解:jscrambler、JShaman、jsfack、ipaguard和jje
    摘要本篇技术博客将介绍五款常用且好用的在线JavaScript加密混淆工具,包括jscrambler、JShaman、jsfack、freejsobfuscator和jjencode。通过对这些工具的功能及使用方法进行详细解析,帮助开发人员更好地保护和加密其JavaScript代码,提升网站的安全性和保密性。 引言在当今......
  • elementUI——el-form表单数据校验(包含数组循环)
    一、普通的值类型的数据校验①设置el-form-item的prop值与formdata中定义的key保持一致`②如果rules需要通过el-form统一设置,rules的key定义也与prop保持一致(如果不一致,需要在el-form-item中手动指定)③复杂的校验函数可通过validator单独定义<el-form......
  • ASP.NET Core 用密码加密 PDF
    需要使用itext-dotnet:https://github.com/itext/itext-dotnet使用Nuget:Install-PackageitextInstall-Packageitext.bouncy-castle-adapter使用密码加密PDF:publicstaticboolEncryptPdf(stringinputPath,stringoutputPath){boolresult=......
  • MD5 计算 (下一代加密辅助类, Win32, C++)
    CCNGHelper.h#pragmaonce#include<string>#include<tchar.h>#include<windows.h>#include<bcrypt.h>#ifdef_UNICODEusing_tstring=std::wstring;#elseusing_tstring=std::string;#endif//下一代加密辅助类//客户端:WindowsVista及......
  • Python逆向爬虫入门教程: 千千音乐加密参数 sign 逆向解析
    数据来源分析......
  • CIPHER命令 参数 显示或更改 NTFS 分区上目录[文件]的加密
    CIPHER是Windows操作系统中的一个命令行工具,用于执行文件和文件夹加密、解密以及管理加密密钥的操作。它主要用于对NTFS文件系统上的文件和文件夹进行加密,以保护数据的安全性。使用CIPHER命令,用户可以执行以下操作:加密文件和文件夹:通过指定路径和选项,可以对文件和文件......
  • 最好用的加密/数字货币打赏赞助平台
    最近在调研使用加密货币打赏的平台,发现idatariver平台https://idatariver.com推出的buymeabtc功能刚好符合使用场景,下图为平台的演示项目,演示项目入口https://buymeabtc.com/idatariver特点不少人都听说过buymeacoffee,可以在上面发布数字商品或者赞助收款,但是相对门槛会比......