逆向工程入门:常见编码与加密算法识别与实战分析

发布时间:2026/8/2 9:29:19
逆向工程入门:常见编码与加密算法识别与实战分析 1. 项目概述从“菜鸡”到入门逆向路上的第一道门槛刚接触逆向分析那会儿我常常对着反编译出来的代码发懵。满屏的0xDEADBEEF、0xCAFEBABE还有一堆sub_401000、loc_4040A0看得人头大。但很快我就发现真正拦住我的往往不是复杂的控制流混淆或者花指令而是那些看起来平平无奇却无处不在的编码和加密算法。程序用它来保护字符串、校验数据、加密通信如果你看不懂这些“黑话”逆向分析就寸步难行。这就像侦探拿到了加密的日记本不先破解密码后面的推理全是空谈。“菜鸡学逆向——常见编码加密算法逆向总结”这个标题精准地戳中了所有逆向新手的痛点。它不是一个高深的密码学课题而是一份实战导向的“生存指南”。它的核心价值在于将逆向工程中最高频出现的那些“障眼法”进行归类、拆解并提供一套可复现的识别与分析方法。无论你是想分析一个安卓APK里的网络请求还是破解一个PC游戏的存档校验亦或是参加CTF比赛这些知识都是你工具箱里的螺丝刀和扳手是最基础也最不可或缺的部分。这篇文章我就结合自己踩过的坑和总结的经验带你系统梳理一遍逆向分析中常见的编码与加密算法。我们会从最基础的Base64、十六进制开始讲到古典的XOR、ROT再到现代对称加密的AES、DES以及国密算法SM4最后提一下非对称加密和哈希。重点不在于数学推导而在于在逆向的上下文中如何快速识别它们识别后又该如何验证、解密或绕过我们的目标是让你下次在IDA Pro、Ghidra或者Frida的动态日志里看到这些“老朋友”时能会心一笑然后迅速搞定它。2. 逆向分析中的编码算法数据的“化妆术”在逆向中编码Encoding和加密Encryption有本质区别。编码是为了方便数据传输或存储如避免特殊字符通常没有密钥过程可逆加密则是为了保密必须有密钥。但很多新手容易混淆因为它们在代码里看起来可能都是“把一串数据变成了另一串”。我们先从最简单的编码开始它们是逆向中最常见的“第一层皮”。2.1 Base64网络世界的“通用语”Base64是我在逆向中遇到频率最高的编码没有之一。它的目的很单纯将任意二进制数据比如一张图片、一段密文编码成由64个可打印ASCII字符A-Z, a-z, 0-9, , /用于填充组成的字符串。这样数据就能安全地在只支持文本的协议如HTTP、XML、JSON中传输。逆向识别特征字符串特征编码后的字符串长度通常是4的倍数字符集严格限定在A-Za-z0-9/之内。如果你在程序的字符串常量区或网络抓包中看到一长串这样的字符比如“dGVzdCBzdHJpbmc”那大概率是Base64。函数特征在反编译的代码中寻找包含base64、b64字样的函数名或变量名。更隐蔽的是寻找操作0x41(‘A’)到0x7A(‘z’)这个区间的字符映射表。标准的Base64编码表“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/”如果以常量形式出现就是铁证。调用模式常见于网络请求前对参数的包装或收到响应后的第一步处理。在Android逆向中android.util.Base64类是明显的线索。实战分析与解密识别后解密通常很简单。但这里有三个坑变种Base64有些开发者会自定义编码表比如把“/”换成“-_”URL安全的Base64或者完全打乱顺序。这时你需要找到程序中的编码表常量。在IDA中可以搜索字符串“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789”看其附近是否有被引用的、长度64的字符数组。多层嵌套尤其在CTF题中可能会遇到Base64套Base64甚至套了五六层。解决思路就是写个循环一直解码直到解码失败或结果不再变化。用Python的base64.b64decode捕获binascii.Error异常即可。自动识别工具在静态分析时可以用strings命令或IDA的字符串窗口配合过滤。动态分析时可以在Frida中Hook常见的Base64编码/解码函数直接打印输入输出。注意Base64编码会使数据体积膨胀约33%。如果一个字符串解码后是乱码但它符合Base64特征不妨考虑它是不是其他数据如压缩后的数据、另一个加密算法的输出的Base64形式需要进一步分析。2.2 十六进制Hex与URL编码明文的“伪装”十六进制编码就是把每个字节用两个十六进制数字0-9, A-F表示。URL编码百分号编码则是为了在URL中安全传输特殊字符。逆向识别特征Hex字符串仅由0-9和a-f或A-F组成长度为偶数。例如“68656c6c6f”对应“hello”。在代码中常看到sprintf(buf, “%02x”, data[i])这样的模式。URL编码字符串中包含大量%后跟两个十六进制数字的模式如“%E4%B8%AD%E6%96%87”“中文”的UTF-8 URL编码。在HTTP请求参数中极为常见。实战心得 这两种编码几乎没有保密性纯粹是为了格式兼容。逆向时看到Hex字符串先尝试用CyberChef或Python的bytes.fromhex()转换一下很可能就是关键的明文信息如密钥、初始向量IV或校验和。URL编码则通常在Web逆向和抓包中遇到浏览器的开发者工具或Burp Suite通常会自动解码。2.3 古典编码ROT13与XOR这些算法简单但常被用于CTF或一些轻量级混淆。ROT13字母移位13位自逆加密解密同一操作。识别特征是字符串由字母组成但看起来像乱码。“uryyb”解密后是“hello”。在代码中可能就是一个简单的循环加减13。XOR异或这是逆向中的“常客”既可用于简单加密也可用于复杂加密的组成部分。核心是data[i] ^ key[i % key_length]。XOR的逆向关键识别模式在反汇编代码中寻找对数据缓冲区进行循环并与某个密钥或固定值如0xFF进行XOR操作的指令。在IDA的图形视图里这常表现为一个循环块内有一个XOR指令。提取密钥如果已知部分明文比如文件头“PK\x03\x04”是ZIP“\x89PNG”是PNG可以通过密文 ^ 明文 密钥来推测密钥。这就是所谓的“已知明文攻击”。单字节XOR密钥为单个字节。可以通过分析密文字符的频率来爆破因为英文文本中空格0x20频率最高。用密文与0x20异或常常能直接得到密钥字节。实操技巧遇到一段数据看不出是什么编码可以先尝试用0xFF、0x00、0xAA等常见魔数进行单字节XOR看结果是否出现可读字符串。这招在分析固件或游戏资源文件时有时有奇效。3. 现代对称加密算法逆向寻找密钥的“狩猎”对称加密是逆向中的硬骨头算法本身是公开的如AES、DES、SM4安全完全依赖于密钥的保密。我们的目标往往不是破解算法那几乎不可能而是找到程序中隐藏或生成的密钥。3.1 AES逆向中的“霸主”AES高级加密标准是当今最流行的对称加密算法在软件中无处不在。它有多种模式如ECB、CBC、CTR等这直接影响我们的逆向策略。逆向识别特征静态常量表S盒AES算法内部使用一个256字节的替换表S-Box。在反编译的代码中查找一个大的、256字节的常量数组。标准的AES S盒开头是0x63, 0x7c, 0x77, 0x7b, 0xf2...。找到它几乎就坐实了AES。它的逆S盒也常同时存在。轮常数Rcon另一个小的常量数组通常10个或更多个32位整数。函数名/库使用OpenSSL、Crypto等库时函数名可能包含AES_encrypt、AES_set_encrypt_key等。在Android的Java层可能是javax.crypto.Cipher.getInstance(“AES/...”。逆向策略与动态分析静态识别算法只是第一步拿到密钥才是胜利。密钥硬编码最简单的情况。在IDA的字符串窗口或代码段中搜索可能的密钥字符串16/24/32字节的Hex或Base64形式。用Find Crypt等IDA插件可以自动识别算法常量。密钥动态生成密钥由设备信息IMEI、Android ID、用户输入、服务器下发等计算而来。这时需要动态调试如用Frida来捕获密钥生成过程。关键Hook点密钥生成函数HookAES_set_encrypt_key或Cipher.init函数打印其密钥参数。加密/解密函数HookAES_encrypt/AES_decrypt或Cipher.doFinal打印输入明文/密文、输出和内部状态对于CBC模式还需要IV。模式识别与影响ECB模式相同明文块产生相同密文块。不安全且无IV。逆向时只需找密钥。CBC模式最常用。需要密钥和IV初始化向量。IV可能随密文一起传输通常放在密文前也可能是固定的。在Hook时必须同时获取IV。CTR/GCM模式流加密模式。需要密钥和Nonce。思路类似。实战案例Frida Hook Android AES假设目标App使用Java的Cipher类进行AES-CBC加密。Java.perform(function() { var Cipher Java.use(‘javax.crypto.Cipher’); Cipher.getInstance.overload(‘java.lang.String’).implementation function(transformation) { console.log(‘[] Cipher.getInstance: ‘ transformation); return this.getInstance(transformation); }; Cipher.init.overload(‘int’, ‘java.security.Key’, ‘java.security.spec.AlgorithmParameterSpec’).implementation function(opmode, key, params) { console.log(‘[] Cipher.init: ‘); console.log(‘ opmode: ‘ opmode); // 1ENCRYPT_MODE, 2DECRYPT_MODE console.log(‘ key: ‘ bytesToHex(key.getEncoded())); if (params) { var ivSpec Java.cast(params, Java.use(‘javax.crypto.spec.IvParameterSpec’)); console.log(‘ IV: ‘ bytesToHex(ivSpec.getIV())); } return this.init(opmode, key, params); }; Cipher.doFinal.overload(‘[B’).implementation function(input) { console.log(‘[] Cipher.doFinal input: ‘ bytesToHex(input)); var result this.doFinal(input); console.log(‘[] Cipher.doFinal output: ‘ bytesToHex(result)); return result; }; });这段脚本能帮你捕获到算法模式、密钥、IV以及完整的输入输出数据。3.2 SM4国密算法国内应用的“标配”随着国密推广SM4在金融、政务、物联网等领域的App和软件中越来越常见。它是我国官方认定的商用密码算法分组长度和密钥长度均为128位。逆向识别特征常量S盒SM4也有自己的固定S盒与AES完全不同。其S盒是一个固定的256字节数组开头是0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7...。在IDA中搜索这些字节序列是识别SM4的最可靠方法。固定常数FK和CKSM4算法在密钥扩展中使用固定的系统参数FK4个32位字和CK32个32位字。这些常量也常出现在代码中。函数名/库可能使用GMSSL、国密算法库等函数名可能包含sm4。逆向要点逆向SM4的思路与AES完全一致。因为算法固定核心仍是找密钥和模式ECB、CBC等。由于SM4在国内环境使用更多其密钥可能来源于国密硬件盾、基于SM2的非对称协商或从服务器获取。动态Hook的方法与AES类似关键是定位到加密函数。重要提示无论是AES还是SM4在非攻击性安全测试如授权渗透测试中我们的目标是验证加密实现是否正确、密钥管理是否存在风险。在CTF竞赛中目标则是利用漏洞或侧信道获取密钥。绝对不要将其用于非法破解。3.3 DES与3DES逐渐退役的“老兵”DES数据加密标准因其56位密钥太短已不安全3DES是DES的加强版。现在已不推荐使用但在一些遗留系统或特定协议中还能遇到。逆向识别特征DES识别其8个固定的S盒每个S盒是4x16的查找表和初始置换IP/逆初始置换IP-1表。这些表在代码中非常显眼。3DES本质是执行三次DES密钥长度可以是112位或168位。在代码中可能看到三次DES加密/解密调用。逆向策略由于DES/3DES算法强度已不足除了寻找硬编码密钥在CTF中有时甚至可能尝试暴力破解如果密钥空间不大。但在实际App逆向中找到密钥生成和存储的逻辑仍是主要途径。4. 非对称加密与哈希算法逆向中的“验证者”非对称加密如RSA和哈希算法如MD5、SHA256在逆向中通常扮演“验证”或“签名”的角色而不是用来加密大量数据。4.1 RSA公钥的“公开秘密”在逆向中你很少需要去破解RSA在密钥长度足够时这不可行。更常见的是验证签名服务器用私钥签名客户端用内嵌的公钥验证。我们的目标是绕过验证而不是破解私钥。方法可能是Patch掉验证函数使其永远返回成功或者用Frida Hook验证函数直接修改返回值。分析密钥管理公钥可能硬编码在App内。用strings或搜索“BEGIN PUBLIC KEY”/“BEGIN RSA PUBLIC KEY”等PEM格式的标头可以找到。有时公钥被编码Base64或拆分成多个部分存储需要拼接还原。捕获加密数据如果App用RSA加密一个临时密钥即“数字信封”模式那么我们需要Hook加密函数捕获这个被加密的临时密钥。在内存中它可能以BigInteger或字节数组形式存在。逆向识别寻找大整数运算模幂运算a^b mod n、大素数生成、以及PEM格式的密钥字符串。OpenSSL的RSA_public_encrypt、RSA_verify等函数是明显的目标。4.2 哈希算法MD5, SHA系列完整性的“指纹”哈希是不可逆的。在逆向中遇到哈希通常是为了完整性校验校验文件、数据包是否被篡改。程序会计算接收数据的哈希值与一个预设值比较。密码存储比较用户输入密码的哈希值与存储的哈希值。生成密钥或标识用哈希将一些输入数据变成固定长度的密钥。逆向策略识别MD5、SHA1、SHA256等都有固定的初始常量魔数。例如MD5的初始A、B、C、D是0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476。在代码中搜索这些常量可以识别算法。目标我们的目的通常不是“反推”原文这极难而是绕过校验找到比较哈希值的地方往往是memcmp或strcmp通过调试修改比较结果或直接Patch跳转指令。构造碰撞仅限CTF或研究对于MD5、SHA1这类已发现碰撞漏洞的算法在CTF中可能需要构造两个哈希值相同的不同输入。这需要专门的工具和方法。理解逻辑明白程序用哈希来做什么是生成会话ID还是计算文件校验和这有助于理解整个程序的数据流。5. 综合逆向实战从识别到解密的完整链条理论说再多不如一个实战案例。假设我们拿到一个Android App其某个网络请求的data参数是一串加密的Base64。我们的目标是弄清其加密方式并解密。第一步静态探查用jadx-gui或APKTool反编译APK。搜索与data参数相关的字符串定位到网络请求库如OkHttp、Retrofit或相关代码。搜索“AES”、“DES”、“Cipher”、“encrypt”、“decode”等关键词。如果发现“SM4”或国密相关字符串重点关注。查看assets或res/raw目录下是否有包含密钥或配置的文件。第二步动态分析Frida 抓包启动App和抓包工具Charles/Fiddler捕获加密的请求。编写Frida脚本Hookjavax.crypto.Cipher类的所有重载方法如前文示例。触发网络请求观察Frida输出。理想情况下你能直接看到算法模式、密钥、IV和明文。如果密钥是动态计算的需要向上追溯。Hook密钥生成相关的函数或者HookSecretKeySpec的构造函数。第三步算法验证拿到疑似密钥和算法后需要用独立脚本验证。例如用Python的cryptography库使用捕获的密钥和IV对捕获的密文进行解密看是否能得到有意义的明文。第四步深度追踪如需如果加密在Native层so库进行就需要使用IDA Pro或Ghidra进行反汇编并结合Frida的Interceptor来Hook Native函数。这时识别算法常量的技能就派上用场了。在Native代码中搜索AES的S盒或SM4的S盒字节序列能快速定位加密函数。6. 常见问题与排查技巧实录逆向编码和加密的路上坑永远不会少。这里记录一些我踩过的坑和总结的技巧。问题1静态分析找到了加密函数但密钥是“一片空白”可能情况密钥来自服务器在运行时通过网络请求下发。或者密钥由多个部分拼接而成如part1 deviceId part2。排查技巧全局搜索拼接字符串的操作、StringBuilder.append。动态Hook所有网络响应解析函数查看是否有像密钥的数据。HookSharedPreferences或SQLite的读取操作看是否从本地存储中读取了密钥片段。问题2Frida Hook Cipher类什么都没打印可能情况App使用了自定义的加密实现自己写的算法或对标准库进行了封装、混淆没有走标准的CipherAPI。排查技巧查看调用栈找到真正执行加密的类。或者直接Hooklibc的malloc/memcpy等函数观察大块内存的分配和操作结合反编译代码分析。也可以尝试使用objection等工具的android hooking watch class命令来探查所有被调用的方法。问题3解密出来的数据是乱码可能情况密钥或IV错了。加密模式判断错误比如以为是ECB实际是CBC。密文在传输或处理时被修改了如去掉了Padding。解密后还需要进行其他处理如解压缩、二次解码。排查技巧首先确认算法、模式、Padding方式是否完全匹配。用捕获的密钥和IV对一段已知的明文进行加密看得到的密文是否与抓包的一致。如果不一致说明还有未知参数。检查密文长度是否符合算法分组的整数倍。问题4遇到代码混淆怎么办常见混淆类名、方法名、字段名被重命名为a, b, c字符串被加密控制流被扁平化或虚假分支。应对策略字符串解密寻找字符串解密函数。通常程序启动时会调用一个初始化函数解密所有字符串到内存。用Frida Hook内存分配函数在解密后去内存中dump字符串。关键点定位即使混淆加密操作最终还是要调用底层的API如MessageDigest、Cipher。直接Hook这些系统API是绕过混淆的好办法。动态追踪在未混淆的版本如果有或早期版本中定位关键函数记录其特征如参数数量、调用顺序再到混淆版本中通过特征匹配。问题5如何判断一个自定义算法是编码还是弱加密观察输入输出如果输出长度与输入有固定数学关系如Base64膨胀约33%Hex膨胀一倍且输出字符集有限很可能是编码。尝试频率分析对输出数据进行字节频率统计。如果分布均匀类似随机数可能是强加密。如果某些字节频率异常高可能是简单替换或XOR。搜索常量在代码中搜索大的常量数组S盒、置换表这是识别标准或自定义加密/编码算法的强信号。逆向工程是一个需要耐心、经验和大量实践的技术活。对编码和加密算法的熟悉能帮你快速拨开迷雾触及程序逻辑的核心。记住你的武器库不仅仅是IDA和Frida还包括对算法特征的深刻理解、严谨的假设验证流程以及一份永不言弃的好奇心。从识别一个简单的Base64开始慢慢积累你也能成为破译程序秘密的专家。