常见加解密算法09 - HASH 算法

各位读者你们好啊,今天讨论一下 HASH 算法,也是这个系列的完结篇!!!

Hash算法,又称散列算法,是一种从任意长度的数据字符串中创建小的、固定长度的值的函数,该值通常被视为数据的“指纹”。不同的数据往往会通过散列算法产生不同的结果,若两个不同的数据通过同一散列函数产生了相同的结果(即散列冲突),这种情况是非常罕见的。

散列算法的关键特点包括:

  1. 确定性:相同的输入始终会产生相同的输出。

  2. 快速计算:计算任何给定数据的哈希值是快速的。

  3. 非逆性:理想中,从散列值中重建原始输入应该是不可行的,即散列函数是单向的。

  4. 冲突抵抗:两个不同输入很难产生相同的输出值。

固定的输出,这个是逆向研究的一个关键特征。

以下是几种常见散列算法:

  • MD5:产生一个128位(16字节)的哈希值,通常用一个32字符的十六进制数展示。MD5已经不再安全,容易受到冲突攻击。

  • SHA-1:安全散列算法(Secure Hash Algorithm)的第一个版本,产生一个160位(20字节)的哈希值。SHA-1比MD5更安全,但现在也认为它是不安全的。

  • SHA-256:属于SHA-2家族,产生一个256位(32字节)的哈希值,相比于SHA-1和MD5,它更安全。

  • SHA-512:是安全散列算法2(SHA-2)家族的一个成员,产生一个512位的哈希值。

  • SHA-3:最新的成员,提供与SHA-2不同的哈希算法和结构,针对各种不同的应用和环境提供多种输出大小。

CRC32

CRC32,全名为循环冗余校验码 32位 (Cyclic Redundancy Check 32-bit),是一种用于检测数字网络和存储设备上数据错误的校验算法。CRC32 通过将字节序列散列为 32 位的整数值来工作,其基于多项式除法的原理。在理论上,可以使用多种多项式来执行 CRC32,但在实际应用中通常只有两种被广泛使用。

CRC32 算法通过特定的多项式进行计算,生成一个数值,该数值随数据一同传输或存储。接收方在收到数据时,会使用同样的算法重新计算数据的 CRC32 值,若计算结果与传输来的 CRC32 值相匹配,则数据被认为是完好无误的。如果不匹配,则表明数据在传输或存储过程中可能遭受到了干扰或损坏。

CRC32 广泛应用于各种场合,例如以太网、FDDI、ZIP 文件和其他归档格式,以及 PNG 图像格式等。更深入的技术细节可以在各种技术文档或在线资源中找到。CRC算法的强大之处在于其检测随机错误的能力,尤其是在不需要错误修复(仅检测和报告)的场合中非常有用。

算法讲解:

https://www.bilibili.com/video/BV1V4411Z7VA/

Java版

    public static int getcrc32byapi(byte[] bytes) {
        CRC32 crc32 = new CRC32();
        crc32.update(bytes);
        return (int) crc32.getValue();
    }

Hook起来也非常的简单:

function hookCRC32() {
    if (Java.available) {
        Java.perform(function () {
                var CRC32Class = Java.use('java.util.zip.CRC32');

                CRC32Class.$init.implementation = function () {
                    console.log("CRC32 constructor function is called");
                    return this.$init();
                };

                CRC32Class.update.overload('[B').implementation = function (arg0) {
                    console.log("CRC32->update:", JSON.stringify(arg0));
                    var result = this.update(arg0);
                    return result;
                };
                CRC32Class.update.overload('java.nio.ByteBuffer').implementation = function (arg0) {
                    console.log("CRC32->update.overload('java.nio.ByteBuffer'):", JSON.stringify(arg0));
                    var result = this.update(arg0);
                    return result;
                };
                CRC32Class.update.overload('int').implementation = function (arg0) {
                    console.log("CRC32->update.overload('int'):", JSON.stringify(arg0));
                    var result = this.update(arg0);
                    return result;
                };
                CRC32Class.update.overload('int', 'int').implementation = function (arg0, arg1) {
                    console.log("CRC32->update.overload('int', 'int'):", arg0, '---', arg1);
                    var result = this.update(arg0, arg1);
                    return result;
                };
                CRC32Class.update.overload('[B', 'int', 'int').implementation = function (arg0, arg1, arg2) {
                    console.log("CRC32->update:", JSON.stringify(arg0), "---:", "---", arg1, "---", arg2);
                    var result = this.update(arg0, arg1, arg2);
                    return result;
                };
                CRC32Class.getValue.implementation = function () {
                    var result = this.getValue();
                    console.log("CRC32->getValue:", result);
                    return result;
                };

            }
        )
    }
}

C版

算法识别也可以使用 findcrypt 脚本,因为它也有一个常量表。CRC32常量表是用于计算CRC32校验值的预计算值表,它包含256个32位的条目。每个条目代表一个八位数的CRC值。这个表可以在运行时生成,但通常为了提高效率,会预先计算并存储使用。

rule CRC32_poly_Constant {
 meta:
  author = "_pusher_"
  description = "Look for CRC32 [poly]"
  date = "2015-05"
  version = "0.1"
 strings:
  $c0 = { 2083B8ED }
 condition:
  $c0
}

看一个实现:

static  uint32_t crc32_table[] FLASH_PROGMEM = {
        0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
        0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
        0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
        0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};

里面就有 0xedb88320 这个会命中规则。

MD5

给大家讲两个笑话:

  1. 某网站用字符串的哈希值来记录用户密码,后来网站升级,.NET 2.0升级为.NET 3.5,微软改了字符串取哈希值的算法,导致密码库失效,用户无法登陆,不得已网站又退回了.NET 2.0。

  2. 第二个笑话,某度网盘用哈希值检查文件实现秒传。结果有段时间有人发现秒传上传的根本不是自己的文件。

    public static String md5(String content) {
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            byte[] bytes = digest.digest(content.getBytes());
            String result = Base64.encodeToString(bytes, 0);
            return result;
        } catch (Exception ex) {
            ex.printStackTrace();
            return "";
        }
    }

SHA-1/SHA-256

    public static String sha1(String content) {
        MessageDigest md = null;
        String strDes = null;
        byte[] bt = content.getBytes();
        try {
            md = MessageDigest.getInstance("SHA-1");// 将此换成SHA-1、SHA-512、SHA-384等参数
            md.update(bt);
            byte[] result = md.digest();
            strDes = Base64.encodeToString(result, 0);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
        return strDes;
    }

MD5与SHA-1/SHA-2都是有常量表的,可以使用 findcrypt 来识别。

例子

使用脚本识别到了一个常量,但是没有直接引用,说明识别到了常量表的中间部分,往上找到该数据段的头部,按 X 找到引用位置。

一层一层往上找,就能找到对应的入口了,然后使用 frida hook,重放, 确定函数即可。

二手的程序员

欢迎关注二手的程序员,这里主要分享逆向相关的知识。专注于完整系列,让知识不再碎片化。不定时更新,也欢迎关注我的博客:lyldalek.top

公众号

CFB-HASH算法和CBC-Hash算法是两种不同的哈希算法,它们在实现上有一些相似之处,但也有明显的区别。 相似之处: 1. 都是基于块密码的哈希算法:CFB-HASH和CBC-Hash都是使用块密码来实现哈希功能。块密码是一种将固定长度的明文块转换为相同长度的密文块的密码算法。 2. 都具有可逆性:CFB-HASH和CBC-Hash都可以通过相应的解密算法将哈希值还原回原始的明文块。 3. 都具有数据完整性校验功能:CFB-HASH和CBC-Hash都能够校验数据的完整性,即通过对明文块进行哈希计算,然后将哈希值与接收方计算得到的哈希值进行比较,来判断数据是否被篡改。 区别: 1. 工作模式不同:CFB-HASH使用的是加密反馈(CFB)模式,而CBC-Hash使用的是密码块链(CBC)模式。CFB模式是一种自同步的模式,它将前一个密文块的输出作为加密函数的输入,而CBC模式则是将前一个密文块与当前明文块进行异或操作后再进行加密。 2. 密钥使用方式不同:CFB-HASH和CBC-Hash在密钥的使用上也有区别。CFB-HASH使用的是相同的密钥用于加密和解密过程,而CBC-Hash使用的是两个不同的密钥,一个用于加密,一个用于解密。 3. 安全性不同:由于使用不同的工作模式和密钥使用方式,CFB-HASH和CBC-Hash在安全性上也有所差异。一般来说,CBC-Hash相对于CFB-HASH更安全,因为它具有更好的抗差分攻击和抗重放攻击的能力。 总结:CFB-HASH和CBC-Hash是两种不同的哈希算法,它们在工作模式、密钥使用方式和安全性等方面存在明显的区别,但都具有基于块密码的哈希功能和数据完整性校验功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二手的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值