拓冰建站拓冰建站
首页 / 资讯中心 / 正文

aes-finder实战:从进程内存中快速提取AES轮密钥

简介面向安全研究与逆向工程场景的AES密钥查找工具基于C实现支持在运行进程内存中定位128位、192位与256位AES密钥。工具本身为开源项目适合安全分析师、二进制审计人员或有逆向基础的CTF选手学习研究。资源包共包含10个文件其中4个头文件、1个cpp源码、Visual Studio工程配置sln与vcxproj、README及跨平台头文件等整体约20KB结构精简可用Visual Studio 2013或gcc/clang直接编译。目前已有1632人学习下载参考价值获得一定认可。通过阅读源码可以理解AES密钥在进程内存中的特征与扫描匹配思路在逆向分析中此类工具也常被用来从内存中快速定位加密参数为后续解密通信数据、提取关键线索提供支持。借助Linux、Windows、macOS相关的头文件还可灵活适配不同系统环境便于继续改造或集成到自研工具中。 做恶意样本分析或者CTF逆向的时候我经常遇到一个非常微妙的场景程序跑起来了流量也能抓到对方用的明明是AES加密密钥就是不知道在哪。静态分析里翻遍了常量区、资源段、字符串引用都没有跟了一遍算法流程发现密钥是运行时从系统信息、机器码、甚至内存别的进程里拼出来的。这时候最直接的办法是在程序运行过程中把正在使用的AES密钥直接从内存里“捞”出来。aes-finder这个实用程序就是干这个的。aes-finder的核心定位很明确它是一个运行期工具不是静态分析工具。你给它一个目标进程的PID它会扫描该进程的内存空间找出其中已经被Key Expansion展开过的AES轮密钥。它不关心你的目标程序是什么语言写的、用没用加密壳、密钥是从哪来的只要程序在某个时刻用AES加解密并且轮密钥表已经在内存里展开就有机会被直接命中。这篇文章我会把它的核心识别原理、工具选型思路、实际使用流程以及我在实战中踩过的坑完整梳理一遍。适合正在做恶意软件取证、CTF逆向、或者需要在授权环境下分析加密行为的读者参考。1. AES密钥查找的核心思路1.1 为什么运行时查找比静态分析高效静态分析里找AES密钥是个体力活。很多程序不会把密钥原样放在二进制里常见做法是先存储编码后的密文密钥运行时再解码或者通过字符串拼接、XOR、hash派生得到真正的密钥。这种情况下你从静态角度看到的只是一个不完整的中间值必须把整个推导逻辑还原出来才能得到最终密钥。这个过程耗时而且很容易在某个分支条件上卡住。但运行时的情况完全不同。密钥在真正用于加密和解密之前必须经过AES的Key Expansion密钥扩展算法生成完整的轮密钥表round keys。这个表会被真实地写入内存并且在整个加解密会话期间持续驻留。无论密钥本身怎么伪装、怎么派生最终落地的轮密钥表无法伪装。aes-finder正是抓住了这个“最后一公里”的必然性直接在内存里找展开后的轮密钥绕开了静态分析中繁琐的密钥推导过程。1.2 AES密钥在内存里的存在形态理解aes-finder的识别机制关键是要明白AES轮密钥在内存里长什么样。以AES-128为例原始16字节密钥经过Key Expansion后会扩展成176字节的轮密钥数据分成11组round 0到round 10每组16字节。加解密每一轮都会使用其中一组。这个过程中最后一轮轮密钥round 10并不是一个随机的数据块它和前面的轮密钥之间存在着严格的数学校验关系由S盒替换和轮常量异或两个操作维系。aes-finder的扫描原理就是对进程内存中的每个可能偏移位置应用AES密钥扩展的逆运算进行校验。如果某一处数据能够通过轮密钥结构的完整校验就极有可能是一份真实的AES轮密钥表。这个过程类似在一堆草稿纸里找一张写了特殊递推公式的纸——纸上内容看起来像随机的十六进制流水账但前后几行之间必须严格满足数学关系能做这种校验的只有真正的轮密钥数据。2. 工具选型与方案拆解2.1 为什么不做离线内存转储再分析一提到内存分析很多人第一反应是先把目标进程的内存dump下来再用Volatility之类的工具离线分析。这个思路在硬盘取证和事后分析场景当然可行但放在“程序正在运行、我需要实时拿到密钥”的场景下就不太顺手。第一个问题是你不知道密钥什么时候会被释放等dump完再慢慢分析可能密钥已经被覆盖了。第二个问题是进程内存可能极大尤其是一些业务系统动辄几个GB离线扫描一遍的成本不低。aes-finder用的是注入式实时扫描的思路它直接附加到目标进程在进程自己的工作集和虚拟内存范围内执行扫描。这种方式能精确地在目标进程还活着、轮密钥表还在内存的时候完成识别不需要整块内存的原始副本扫描速度和命中率都更可控。另外从执行模型上看它走的是Windows调试API和内存读取接口而不是把自己的DLL强行塞进目标进程这样触发目标进程反调试逻辑的概率会低一些。2.2 核心算法轮密钥特征识别细节aes-finder在识别轮密钥时不是简单地找16字节看起来“随机”的数据而是把整个轮密钥组的生成顺序作为筛子。AES密钥扩展的逻辑是每一轮密钥的0-3字节是从上一轮密钥的对应位置通过S盒替换、轮常量异或、循环移位等操作逐字生成的。所以只要内存中的一段数据满足这种连续递推关系就能确认它是轮密钥表而不是恰好长得很像随机数据。这样设计有一个明显的好处即使程序不是直接保存原始密钥只要它使用正常的AES实现包括绝大多数的软件实现和硬件加速库在调用加解密函数时必然会在内存中展开轮密钥表。aes-finder需要校验的特征来自展开后的结果与原始密钥的存放方式无关。这意味着不管你是从配置文件中读取密钥、从API接口动态获取密钥、还是通过PBKDF2或哈希算法派生密钥最终只要进入了加解密流程轮密钥表就会暴露在内存里存在被aes-finder命中的可能。3. 实操过程与核心环节实现3.1 环境的准备与权限要求aes-finder的编译和使用主要面向Windows平台。我在实践中用的是Visual Studio的开发者命令行来编译源码整个过程不复杂按仓库里的构建说明走一遍就能得到可执行文件。如果你更习惯Linux环境也可以走交叉编译路线但运行时对目标进程的调试权限模型、内存布局扫描方式都是按Windows设计的Windows下使用体验最稳定。运行aes-finder必须要管理员权限这是它能否真正工作的关键。原因在于它需要调用系统调试接口来打开目标进程并读取内存而这个操作在默认权限下是被拒绝的。我第一次运行时就踩了这个坑在普通权限的命令行窗口里执行程序报“无法打开进程”错误换成管理员身份的命令行后问题立刻消失。在实战环境中如果目标是以管理员权限或者系统服务方式运行你还需要确保自己的分析环境具备足够权限。3.2 基本用法与一次实战复现假设你已经拿到了目标进程的PID命令非常简单直接把它作为参数传给aes-finder即可。命令行形式大致如下aes-finder.exe 1234这里的1234是目标进程PID。执行后程序会扫描该进程的内存空间如果发现符合AES轮密钥结构的候选数据就会在控制台输出命中的内存地址和对应的密钥值。我常用的一个实战演练对象是自己写的一个测试程序程序内用OpenSSL的AES-256-CBC加密一段数据密钥随机生成后不落盘只保存在内存变量里。然后用aes-finder扫描它的PID几秒内就找到了完整的256位密钥输出结果和源码里的原始密钥完全一致。如果目标进程包含多个线程、多个加密上下文你可能会一次性收到多处命中。建议先用校验模式过滤候选把那些严格满足轮密钥结构的地址筛选出来再结合目标的业务逻辑判断哪一个才是真正活跃的密钥。这里还有一个实用的细节把命中地址附近的内存再dump出来看一看通常能发现密钥之外的有用信息比如IV值或者加密数据块的起始位置。3.3 常见参数与关键时刻的判断大多数版本的aes-finder会提供少量参数用来应对不同的密钥长度和字节序情况。AES支持128、192、256三种密钥长度对应的轮密钥表长度也不同。默认设置通常能覆盖128位但如果目标程序用的是256位AES建议确认工具的扫描范围包含了256位轮密钥表的校验逻辑部分实现需要显式指定密钥长度比如通过--key-size参数。实战里我建议直接开启“校验模式”或者“严格模式”防止把内存中的随机碎片误判为轮密钥虽然扫描速度会慢一些但准确性高很多。字节序是另一个必须留意的点。AES轮密钥表中的数据在内存中的排列方式取决于具体实现是按32位字DWORD还是按字节数组保存。x86架构默认小端序很多软件实现会以字节顺序存储这正好能和aes-finder默认的识别逻辑对上。但有些用硬件指令优化的库内部会把轮密钥以32位字为单位存储这时字段顺序会反过来如果扫描结果为空可以试试交换字节序的扫描模式通常能立刻看到大量命中。4. 常见问题与排查技巧实录4.1 为什么扫了半天什么都没有这是我收到过最多的反馈对着PID执行了aes-finder结果啥也没发现。我排查过很多次绝大多数情况是下面几个原因之一。首先是目标进程确实没用AES可能用的是ChaCha20、SM4或者干脆是异或加密那aes-finder当然没有用武之地。其次目标程序虽然调用了AES但密钥是在某个临时缓冲区里展开的加解密完毕立刻清零你没有赶上那个时间窗口。权限问题也容易造成“空手而归”。如果目标进程是以更高权限运行的而你的扫描进程权限不够OpenProcess虽然会失败但部分版本的aes-finder不会把错误处理得很细可能只是静默跳过读取导致结果为空。遇到这种情况建议先确认当前命令行是否有管理员权限再确认能否用其他工具正常读取目标进程内存做个基础连通性验证。最后位数不一致也是坑32位的aes-finder扫描64位进程或者反过来都可能出现读取异常。4.2 命中了一堆候选怎么确认哪个是真的aes-finder的识别机制是特征校验理论上严格模式下的命中已经很可靠但实际运行中目标进程可能非常复杂同时存在多个AES上下文命中候选不止一个。这种情况下不要急着随便挑一个用。我的经验是把命中地址附近的几百字节内存都dump下来观察是否有哈希常量表如SHA系列算法的初始常量或其他加密算法特征。如果一个地址附近密集分布着各种密码学算法的常量表那通常是加密库的静态数据区域不是实际使用中的密钥。更可靠的方法是对候选密钥做实弹验证拿它解密一段已知的密文或者加密一段测试数据比对结果。如果你已经通过流量抓包或文件数据拿到了密文并且知道是AES的哪种模式CBC、CTR、GCM等可以直接用候选密钥去解能解出有意义内容的那个就是真实密钥。这个方法听起来笨但在实战里是最能一锤定音的判断方式。4.3 不同平台和编译版本的差异Linux和macOS环境下AES轮密钥一样会在内存中展开理论上同样的扫描思路可行。但aes-finder的官方支持重点在Windows跨平台使用需要自己处理进程内存读取接口的差异。在Linux上你可能会用到/proc/pid/mem文件或者process_vm_readv系统调用来读取目标进程内存这和Windows的ReadProcessMemory机制完全不同。如果只是临时在Linux上分析一个ELF样本我建议先用gdb挂上去手动dump内存再用独立脚本校验轮密钥效率反而更高。另外要注意不同编译器优化级别可能影响轮密钥表在内存中的存活时间。开启O2优化后某些高性能AES实现会把部分轮密钥放进寄存器而非内存这时aes-finder只能扫到栈上保存的那部分。如果目标程序使用了类似mbedtls_aes_setkey_enc这类短生命周期API密钥展开和加解密在同一个函数内完成轮密钥表存在栈上且很快被覆盖扫描时机就非常讲究最好在加解密循环触发的最频繁阶段去扫描命中率会高很多。4.4 容易被忽视的反调试与自保护机制不少恶意软件或者商业保护程序会对进程内存做完整性校验一旦发现被调试或被外部读取轻则清空密钥重则直接崩溃退出。我在分析一个带反调试的样本时aes-finder一直没有命中的原因就是目标程序每隔几秒就对关键内存区域做CRC校验发现被读取后立刻把密钥缓冲区重新加密存放。这种情况下调低扫描频率、拉长监控时间窗口比反复快速扫描更有效。还有一个很容易被忽略的点某些样本使用了“无效化轮密钥表”的技巧也就是密钥扩展完成后参与实际运算的是经过再次变换的伪轮密钥表标准AES的校验关系被刻意打破所以aes-finder无法识别。遇到这种对抗单纯的密钥查找工具已经不够用了需要结合CPU指令级动态插桩比如用Intel Pin或者Frida hook的AES加密函数在函数执行时截获传入的轮密钥参数。这种手段看的是实参而不是扫描内存特征能绕过大部分轮密钥表混淆。最后分享一点个人实操体会aes-finder这类工具用好了是取证和逆向的加速器但别把它当作万能钥匙。它在分析目标加密通信、定位恶意样本的C2密钥、验证自己写的代码是否把密钥安全存放这些场景下非常顺手反过来如果目标程序根本不在当前机器上运行或者你只有一份加密后的二进制文件此时需要的是带符号执行能力的静态分析框架而不是运行期工具。我自己现在的习惯是拿到一个样本先跑起来观察行为同时用aes-finder扫一遍内存如果没有命中再切换到静态分析去追密钥逻辑——两个方向配合着来分析效率比单靠任何一边都要高得多。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门