当前位置: 首页 > news >正文

网页逆向实战:MD5、SHA、HMAC加密算法识别与破解指南

1. 项目概述:从加密算法到网页逆向的实战桥梁

在网页逆向分析这个领域里,你经常会遇到一堆看似杂乱无章的字符串,它们可能是登录时的密码参数,也可能是请求数据包里的一个神秘签名。很多时候,这些字符串就是由MD5、SHA、HMAC这类加密算法处理后的结果。不理解它们,逆向工作就像在黑暗中摸索,寸步难行。今天,我们不谈高深的理论,就从一名逆向工程师的实战视角,拆解这些最常见的加密算法,看看它们是如何在网页中“兴风作浪”,而我们又该如何“见招拆招”。

简单来说,MD5、SHA、HMAC都属于密码学中的哈希函数或消息认证码范畴。它们不是用来“加密”后还能“解密”的(那是AES、RSA的活儿),而是将任意长度的输入,通过一个不可逆的数学变换,映射成一个固定长度的、看起来像乱码的输出,我们称之为“摘要”或“哈希值”。在网页中,它们常被用于密码存储、数据完整性校验、生成API签名或请求令牌。逆向分析的核心任务之一,就是识别出前端JavaScript代码中使用了哪种算法、密钥是什么、对哪些数据进行了运算,从而在本地复现这个计算过程,模拟出合法的请求。

2. 核心加密算法原理与逆向特征拆解

要逆向,先得正向理解。我们得知道这些算法在“正常”情况下是怎么工作的,才能在被混淆、压缩的代码中找到它们的蛛丝马迹。

2.1 MD5算法:曾经的王者与如今的“指纹”

MD5(Message-Digest Algorithm 5)生成一个128位(16字节)的哈希值,通常表示为32个十六进制字符。它的计算过程包括填充、分块、循环压缩等。虽然因其抗碰撞性已被攻破(即能找到两个不同的输入产生相同的MD5值),不再推荐用于密码等安全场景,但在网页逆向中,它依然无处不在。

逆向识别特征:

  1. 常量特征:MD5算法内部使用4个固定的32位幻数(A=0x67452301, B=0xEFCDAB89, C=0x98BADCFE, D=0x10325476)。在JavaScript代码中,如果看到这四个常量的定义,极大概率是MD5。
  2. 函数名特征:常见的JavaScript MD5库会暴露函数如md5()hex_md5()b64_md5()等。
  3. 输出长度:32位十六进制字符串是最明显的标志。

实战注意事项:

MD5是单向哈希,理论上不能解密。网上所谓的“MD5解密”网站,实际上是庞大的“彩虹表”查询,即预先计算好海量明文和其MD5的对应关系,通过查询哈希值反推明文。对于加了“盐”(salt)的MD5,这种查询就失效了。在逆向时,我们的目标不是“解密”,而是找到生成这个MD5值的原始数据和算法代码。

2.2 SHA家族算法:更安全的哈希标准

SHA(Secure Hash Algorithm)系列比MD5更安全,常见的有SHA-1(160位输出)、SHA-256(256位输出)、SHA-512(512位输出)等。数字越长,安全性一般越高,计算也稍慢。

逆向识别特征:

  1. 常量特征:SHA-256使用8个初始化哈希值(如0x6a09e667),SHA-512使用8个64位初始化哈希值。这些固定的魔数是代码中的路标。
  2. 函数名:如sha1(),sha256(),sha512(),CryptoJS.SHA256()(如果使用CryptoJS库)。
  3. 输出长度:SHA-1是40位十六进制,SHA-256是64位,SHA-512是128位。这是快速区分的利器。

实操心得:在逆向中,看到长度40位的哈希,先怀疑SHA-1;看到64位的,优先考虑SHA-256。很多网站的API签名已经从MD5升级到了SHA-256,因为它更抗碰撞。如果代码中引用了crypto-jsforge这类库,搜索SHA256关键词往往能快速定位加密点。

2.3 HMAC算法:带密钥的哈希验证

HMAC(Hash-based Message Authentication Code)是关键所在。它不是独立的算法,而是利用MD5、SHA-1、SHA-256等哈希函数,结合一个密钥,来生成消息认证码。它可以确保数据在传输过程中未被篡改,并且发送方拥有正确的密钥。公式可以简化为:HMAC = Hash( (Key XOR opad) + Hash( (Key XOR ipad) + Message ) )。你不用记这个,但要知道核心是密钥(Key)

逆向识别特征与核心挑战:

  1. 函数调用:常见形式如CryptoJS.HmacSHA256(message, key)hmac-sha256库的调用。
  2. 寻找密钥:这是逆向HMAC最困难也最关键的一步。密钥可能被硬编码在JavaScript文件里(经过混淆),也可能由前端通过其他接口动态获取,甚至是由用户密码等派生而来。你需要仔细追踪生成HMAC的函数的第二个参数来源。
  3. 流程固定:HMAC一定是先有原始数据(消息)和密钥,然后调用特定哈希函数生成结果。在代码中寻找这种“二元输入”的哈希计算点。

一个关键技巧:在Chrome DevTools的Sources面板中,对疑似加密函数(如encryptsigngetToken)设置断点,然后触发网络请求。当断点命中时,观察调用栈(Call Stack)和该函数的参数(Scope),密钥和待加密的原始数据很可能就在眼前。这是动态调试优于静态分析的地方。

3. 网页逆向中的加密算法实战定位与分析

理论懂了,我们进入实战环节。假设我们要对一个登录请求进行逆向,发现其密码或一个sign参数被加密了。

3.1 第一步:网络抓包与初步判断

打开浏览器的开发者工具(F12),切换到Network(网络)选项卡,勾选Preserve log(保留日志)。进行登录操作,观察发出的POST请求。

  • 查看Form DataPayload,寻找可疑参数。例如,password可能是一串32位十六进制数(MD5),signature可能是一串64位十六进制数(SHA-256/HMAC-SHA256)。
  • 特别注意像_t(时间戳)、nonce(随机数)这类参数,它们经常是生成签名的一部分。

3.2 第二步:全局搜索与静态分析

在Sources面板中,对整个网页的JavaScript代码进行搜索(Ctrl+Shift+F)。

  • 搜索关键词:从网络热词和算法特征入手。例如:md5sha256hmacencryptsignCryptoJS(一个非常流行的前端加密库)、hexdigest。也可以直接搜索你抓包到的那个加密字符串,看它是否作为常量出现在代码中。
  • 分析代码结构:找到相关函数后,不要只看那几行。向上追溯,看这个函数的参数从哪里来,密钥是如何定义的。向下查看,看生成的哈希值被用在了哪里(通常是赋值给某个请求参数)。

3.3 第三步:动态调试与参数追踪

静态分析遇到混淆代码时,动态调试是唯一出路。

  1. XHR/Fetch断点:在Network面板,找到那个加密的请求,右键点击,选择“Break on” -> “XHR/fetch Breakpoints”。这样当JavaScript发起这个特定请求时,会自动暂停。
  2. 事件监听器断点:在Sources面板的右侧,展开“Event Listener Breakpoints”,勾选“Script”下的“Script First Statement”,或者“Mouse”下的“click”事件(如果加密由点击触发)。这有助于从用户交互点开始跟踪。
  3. 手动断点:在静态分析找到的疑似加密函数入口处打上断点(点击行号)。 当代码暂停后,利用Step Over(F10)、Step Into(F11)逐行执行,同时在Scope面板和Console面板观察变量值的变化。重点关注传递给加密函数的明文和密钥。

3.4 第四步:本地复现与验证

一旦找到了加密算法、密钥和明文组合方式,就需要在本地(比如用Python的hashlibhmac库,或Node.js环境)复现这个计算过程。

import hashlib import hmac # 示例:复现一个可能的HMAC-SHA256签名 def generate_sign(api_key, secret, timestamp, request_body): message = f"{api_key}{timestamp}{request_body}" sign = hmac.new(secret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).hexdigest() return sign # 使用抓包到的参数进行测试 my_sign = generate_sign('your_api_key', 'your_secret_key', '1648886400000', '{"page":1}') print(my_sign) # 对比抓包到的sign值

如果本地计算的结果与抓包到的值一致,恭喜你,逆向成功。你可以用这个函数生成任意请求所需的签名了。

4. 复杂场景与组合加密策略的应对

网页开发者为了增加逆向难度,不会只使用单一的MD5。他们会组合使用多种技术,这正是开头搜索片段中提到的“几种加密方式配合次序”的实战体现。

4.1 常见组合模式解析

  1. 哈希加盐(Salt)md5(password + salt)。盐是一个随机字符串,与密码拼接后再哈希。这彻底杜绝了彩虹表攻击。逆向时,你需要找到这个salt,它可能藏在另一个接口的响应里,或者是一个前端固定的值。
  2. 多次哈希与迭代sha256(sha256(password)),或者进行上千次的迭代哈希以对抗暴力破解。这在密码存储中常见。逆向登录时,你需要模拟同样的迭代次数。
  3. HMAC与动态参数sign = hmac-sha256(排序后的所有参数 + 密钥)。这是API签名的经典模式。难点在于参数排序规则(通常按字典序)和拼接格式(如key1=value1&key2=value2)。
  4. 非对称加密管理对称密钥:正如搜索片段所言,这是更高级的模式。例如,前端用RSA公钥加密一个随机生成的AES密钥,然后用这个AES密钥加密请求体。服务器用私钥解密出AES密钥,再解密请求。逆向这种模式,关键在于找到RSA公钥和AES密钥的生成逻辑。

4.2 逆向组合加密的思维导图

面对复杂加密,需要一个清晰的排查思路:

  1. 确定最终输出:抓包,确定需要破解的那个加密参数(如encryptedData,sign)。
  2. 识别算法家族:通过输出长度、特征初步判断是MD5、SHA还是HMAC。
  3. 定位加密函数:通过搜索关键词、断点追踪,找到生成该参数的JavaScript函数入口。
  4. 逆向输入流:从加密函数出发,反向追踪每一个参数的来源。
    • 明文数据从哪里来?(表单输入、页面元素、其他接口返回值)
    • 密钥从哪里来?(硬编码、接口获取、本地计算派生)
    • 盐(Salt)或初始向量(IV)从哪里来?
    • 是否有额外的处理步骤?(Base64编码、十六进制转换、字符串排序、截取部分结果)
  5. 绘制加密流程图:在纸上或脑图中画出数据流动和变换的完整路径。
  6. 分步复现验证:按照流程图,从第一步开始,在本地逐步实现,每一步都与调试时看到的中途结果对比,确保无误。

5. 常用工具链与调试技巧实录

工欲善其事,必先利其器。除了浏览器自带的DevTools,还有一些工具能极大提升逆向效率。

5.1 浏览器插件

  • ReRes:可以拦截浏览器请求,将线上JavaScript文件替换为本地的修改版,方便你插入调试代码或直接修改函数逻辑进行测试。
  • EditThisCookie:直接查看和编辑Cookie,有时签名或令牌会放在Cookie里。
  • JavaScript Source Tracker(或类似概念):有些插件能帮你可视化JavaScript文件的依赖关系和函数调用链,对理解大型项目结构有帮助。

5.2 本地模拟环境

  • Node.js:对于复杂的、依赖Node环境或npm包的前端代码,直接在Node里运行调试是最准确的。你可以把关键的加密函数片段提取出来,在Node中运行并打印中间变量。
  • Python + ExecJS/PyExecJS:如果你更熟悉Python,可以用这个库来执行JavaScript代码片段。这样你的爬虫或自动化脚本可以直接调用前端的加密逻辑,无需完全用Python重写。
    import execjs # 假设你提取出了关键的js加密函数,保存为 sign.js with open('sign.js', 'r', encoding='utf-8') as f: js_code = f.read() ctx = execjs.compile(js_code) result = ctx.call('generateSign', 'your_data', 'your_key') print(result)

5.3 高级调试技巧

  1. Hook函数:在控制台直接重写关键函数,让其输出调用参数和结果。这是“暴力”但有效的方法。
    // 假设原加密函数是 window.encrypt var old_encrypt = window.encrypt; window.encrypt = function(data, key) { console.log('encrypt被调用,数据:', data, '密钥:', key); var result = old_encrypt(data, key); console.log('加密结果:', result); return result; };
  2. 内存断点(Watchpoint):如果你知道密钥存储在某个变量或对象属性中,可以在DevTools的Memory面板或通过代码对其设置“访问/修改”断点,当代码读取或修改这个密钥时就会暂停。
  3. 格式化混淆代码:面对压缩成一行的代码,点击DevTools源代码面板左下角的{}(美化)按钮是第一步。对于更复杂的混淆(变量名替换、控制流平坦化),可能需要使用专门的去混淆工具或耐心分析。

6. 常见问题排查与避坑指南

在实际操作中,你肯定会遇到各种问题。这里记录一些典型的坑和解决方案。

6.1 问题:本地复现的签名和服务器的总是对不上

排查思路:

  1. 编码问题(最常见):确保你本地和前端JavaScript处理字符串的编码一致。前端通常使用UTF-8。在Python中,在哈希前明确使用.encode('utf-8')。特别注意中文等非ASCII字符。
  2. 参数顺序或格式:检查拼接参数的顺序、中间是否有连接符(如&|)、是否对键值对进行了URL编码。服务器端的拼接逻辑必须和你本地完全一致。
  3. 密钥或盐错误:再次确认你找到的密钥是否正确、完整。是否在传输前经过了Base64解码或其他变换?动态获取的密钥是否已过期?
  4. 算法或迭代次数错误:确认哈希算法是否准确(是SHA-256还是SHA-256-224?)。确认哈希迭代了 exactly 多少次。
  5. 时间戳或随机数的同步:如果签名包含时间戳,检查本地生成的时间戳和服务器时间是否在允许的误差范围内。随机数(nonce)是否每次请求都重新生成。

6.2 问题:断点打上了,但代码不暂停

可能原因与解决:

  1. 代码被动态加载或eval执行:代码可能通过eval()setTimeout或动态创建<script>标签加载,导致源映射丢失。尝试在“Script First Statement”事件上设置断点,或者搜索代码片段在Network中对应的JS文件,直接在该文件上打点。
  2. 断点被反调试技巧绕过:有些网站会检测开发者工具,并跳入无限debugger循环或使用异步函数扰乱调试。可以尝试使用“停用断点”功能先跳过无限循环,或者使用插件禁用反调试。更高级的方法是修改JavaScript文件,直接注释掉反调试代码。
  3. 断点位置不对:你可能在压缩后的代码行上打了断点,但实际执行的是另一份源文件。确保在正确的文件(通常是经过美化后的主文件)上操作。

6.3 问题:密钥被严重混淆,难以追踪

应对策略:

  1. 动态拦截:如果密钥是在运行时通过Ajax请求获取的,在Network面板找到那个请求,直接查看响应体。这比从混淆的JS代码里找容易得多。
  2. 内存搜索:如果密钥最终会被加载到内存中的一个变量里,可以在代码运行到某个阶段后,在Console中使用Object.keys(window)查看全局对象,或者对已知的容器对象进行递归搜索,寻找符合密钥特征(长度、字符集)的字符串。
  3. 日志大法:如果能在关键位置插入代码(通过ReRes替换文件),就在所有可能的密钥赋值语句前后加入console.log,进行“地毯式”输出。

逆向分析是一场与开发者斗智斗勇的过程。MD5、SHA、HMAC这些算法是工具,理解它们是基础。真正的功夫在于耐心、细致的代码追踪和逻辑推理。每一次成功的逆向,都是对网页应用安全机制的一次深刻理解。记住,我们的目的不是破坏,而是学习和实现合法的自动化交互。随着经验的积累,你会逐渐形成自己的直觉和工具箱,面对新的加密挑战时也能更加从容。

http://www.jsqmd.com/news/1133324/

相关文章:

  • PUBG罗技鼠标宏终极指南:5分钟实现完美压枪控制
  • EM3080-W条码扫描模块与STM32L496AG嵌入式系统设计
  • Si4732与TM4C129EKCPDT实现高保真音频系统设计
  • 时间序列预测基线模型:3个场景下朴素预测法(Naive)的适用性分析
  • STM32与74HC32实现高效按键管理的硬件与软件方案
  • 为什么NBTExplorer是Minecraft数据编辑的终极解决方案?
  • PIC32与WS2812智能LED控制方案详解
  • EM3080-W与PIC18F96J94构建高效条形码解码系统
  • LP5812与PIC18F4553实现智能RGB灯光控制方案
  • AD74413R与STM32F429NI硬件协同设计与同步采集实现
  • PIC18F85K22与M24C04-R EEPROM的嵌入式数据存储方案
  • Java单元测试异常处理:JUnit 5 assertThrows实战指南
  • STM32F334R8与Si4732构建高保真音频系统设计
  • KMX63与PIC18F46K20的硬件协同与低功耗设计
  • STM32F410RB与25CSM04实现1.8MB/s高速数据存储方案
  • 2026最新5款AI编程工具平替实测合集|进阶开发者低成本高效开发权威教程
  • STM32F745VG与LV3296的嵌入式信号处理系统设计
  • WS2812与PIC18F86K90的LED控制方案详解
  • 拜西洛克(BAISYLOK):精密仪表阀门与流体系统解决方案专家 | 一站式流体控制
  • 智习室落地避坑指南:3年实战经验与天学网技术选型全解析
  • 工业级定时系统设计:MIC1557与PIC18F25K40硬件方案
  • STM32F030RC与TPS65263电源管理设计实战
  • 基于Si4732与PIC18F87K22的高性能收音机设计
  • 03-模拟开关相关知识点
  • GTA5线上小助手:免费传送、载具管理与武器获取的终极解决方案
  • AD74413R与STM32F215RE高精度数据采集系统设计
  • STM32F091RC与MIC1557硬件看门狗定时器设计指南
  • 8、Vue项目自动构建与上传流程
  • AI工程实践:从高效微调到系统部署与持续迭代
  • PIC18F97J94驱动WS2812的硬件设计与优化实践