在逆向工程的实践中,我们经常会遇到各种各样的保护机制和技术难点。本文总结了一些常见的情况及其处理方式,希望对逆向分析工作有所帮助。
1. 隐藏字节 (Hidden Bytes) 1.1问题描述 程序在运行时动态生成或解密关键代码,静态分析时无法直接看到真实的执行逻辑。
1.2常见场景
加密的字符串在运行时解密
关键函数地址通过计算得出
重要代码段被加密存储
1.3隐藏字节实例 在实际逆向中,经常遇到这样的情况:
1 2 3 String salt = "xxssasdfasdfadsf" ;String v4 = new String (new byte []{-26 , -83 , -90 , -26 , -78 , -101 , -23 , -67 , -112 });
这些负数实际上是有符号字节,需要转换才能得到真实内容:
1 2 3 4 5 6 7 8 9 10 11 byte_list = [-26 , -83 , -90 , -26 , -78 , -101 , -23 , -67 , -112 ] bs = bytearray () for item in byte_list: if item < 0 : item = item + 256 bs.append(item) str_data = bs.decode('utf-8' ) print (str_data)
解释:
Java中的byte
是有符号的(-128到127)
当字节值大于127时,会显示为负数
通过加256转换为无符号字节(0-255)
最后按UTF-8解码得到真实字符串
这种技术常用于隐藏敏感字符串,避免被静态分析工具直接发现。
重要提醒: 在逆向分析中,特别注意寻找这些常见的隐藏字符串:
这些关键信息往往以字节数组形式隐藏,是破解加密算法的重要线索。
1.4反向操作:生成隐藏字节 如果你需要生成隐藏字节数组,可以用反向操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 data = "张三" data_bytes = data.encode('utf-8' ) data_list = bytearray ()for item in data_bytes: data_list.append(item)print (data_list) res = data_list.decode('utf-8' )print (res)
更简洁的写法:
1 2 3 4 5 6 7 8 9 data = "张三" data_bytes = data.encode('utf-8' ) data_list = []for item in data_bytes: data_list.append(item)print (data_list)
这样就能得到对应的字节数组,在Java中可以直接使用这些字节值来隐藏字符串。
1.5处理方式 1 2 3 4 5 6 7 bp 0x401000 x/100x $rsp dump memory decrypted.bin 0x401000 0x401100
工具推荐:
IDA Pro + 动态调试
x64dbg/OllyDbg
Frida 动态插桩
2. UUID UUID(Universally Unique Identifier)是理论上永远不会重复的值,常用于生成唯一标识符(网卡、mac、当前时间等)。
常见场景:
在逆向中的处理:
1 2 3 4 5 import java.util.UUID;String uuid = UUID.randomUUID().toString();
1 2 3 4 5 6 import uuid uid = str (uuid.uuid4())print (uid)
分析要点:
UUID通常用于生成设备指纹或会话标识
在逆向分析中,关注UUID的生成逻辑和使用场景
某些应用会基于设备信息生成固定的UUID作为设备ID
3. 随机值 随机值在逆向工程中经常遇到,特别是在加密、签名验证和防重放攻击中。
常见场景:
加密算法的随机种子
签名验证的随机数
防重放攻击的nonce值
设备指纹生成
Java中的随机值生成:
1 2 3 4 5 6 7 8 9 10 11 12 import java.math.BigInteger;import java.security.SecureRandom;public class Test { public static void main (String[] args) { BigInteger v4 = new BigInteger (80 , new SecureRandom ()); String res = v4.toString(16 ); System.out.println(res); } }
Python中的随机值处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import random open_udid = "" .join([hex (i)[2 :] for i in random.randbytes(10 )])print (open_udid) open_udid = "" .join(["%x" % i for i in random.randbytes(10 )])print (open_udid) data = random.randbytes(10 ) ele_list = []for item in data: ele = hex (item)[2 :] ele_list.append(ele) res = "" .join(ele_list)print (res) open_udid = "" .join(["%02x" % i for i in random.randbytes(10 )])print (open_udid)
分析要点:
关注随机数生成器的类型(伪随机vs真随机)
分析随机种子的来源和可预测性
在Android逆向中,注意SecureRandom
的使用
某些应用可能使用固定种子生成”随机”值
4. 时间戳 时间戳在逆向工程中经常作为唯一标识符、随机种子或防重放攻击的关键参数。
常见场景:
API请求的时间戳验证
加密算法的时间种子
日志记录和调试信息
防重放攻击机制
Java中的时间戳处理:
1 2 3 4 5 6 7 8 9 10 11 public class Test { public static void main (String[] args) { String t1 = String.valueOf(System.currentTimeMillis() / 1000 ); String t2 = String.valueOf(System.currentTimeMillis()); System.out.println(t1); System.out.println(t2); } }
Python中的时间戳处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import timefrom datetime import datetime timestamp_sec = int (time.time()) timestamp_ms = int (time.time() * 1000 ) print (f"秒级时间戳: {timestamp_sec} " )print (f"毫秒级时间戳: {timestamp_ms} " ) dt = datetime.now() timestamp_sec2 = int (dt.timestamp()) timestamp_ms2 = int (dt.timestamp() * 1000 )print (f"datetime秒级: {timestamp_sec2} " )print (f"datetime毫秒级: {timestamp_ms2} " ) readable_time = datetime.fromtimestamp(timestamp_sec)print (f"可读时间: {readable_time} " ) time_str = datetime.fromtimestamp(timestamp_sec).strftime("%Y-%m-%d %H:%M:%S" )print (f"格式化时间: {time_str} " )
分析要点:
时间戳常用于生成请求签名和验证
注意时间戳的精度(秒级vs毫秒级)
某些应用会对时间戳进行偏移或加密处理
在逆向分析中,时间戳可能是突破口之一
5. 16进制字符串 16进制字符串在逆向工程中广泛使用,特别是在处理二进制数据、加密密钥和哈希值时。
常见场景:
加密密钥的表示
哈希值的显示
二进制数据的可读化
网络协议中的数据传输
Java中的16进制处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 public static String H (byte [] arg5) { StringBuilder v0 = new StringBuilder (); int v1 = arg5.length; int v2; for (v2 = 0 ; v2 < v1; ++v2) { int v3 = arg5[v2] & 0xFF ; if (v3 < 16 ) { v0.append('0' ); } v0.append(Integer.toHexString(v3)); } return v0.toString(); }
Python中的16进制处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 name_bytes = [10 , -26 , -83 , -90 , -26 , -78 , -101 , -23 , -67 , -112 ] data_list = []for item in name_bytes: item = item & 0xff ele = "%02x" % item data_list.append(ele)print ("" .join(data_list))
更简洁的Python实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def bytes_to_hex (byte_array ): return "" .join(["%02x" % (item & 0xff ) for item in byte_array])def bytes_to_hex_builtin (data ): if isinstance (data, str ): data = data.encode('utf-8' ) return data.hex ()def signed_bytes_to_hex (signed_bytes ): return "" .join(["%02x" % (b & 0xff ) for b in signed_bytes]) name_bytes = [10 , -26 , -83 , -90 , -26 , -78 , -101 , -23 , -67 , -112 ] hex_string = signed_bytes_to_hex(name_bytes)print (hex_string)
分析要点:
注意Java中字节的有符号特性(-128到127)
使用& 0xFF
操作将有符号字节转换为无符号
%02x
格式化确保每个字节都是2位16进制
在逆向分析中,16进制字符串常用于表示密钥、哈希等关键数据
6. MD5加密 MD5在逆向工程中是最常见的哈希算法之一,广泛用于数据完整性验证、密码存储和签名生成。
常见场景:
API请求签名验证
密码哈希存储
文件完整性校验
防篡改机制
Python中的MD5实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 import hashlib obj = hashlib.md5() obj.update('xxxxx' .encode('utf-8' )) v1 = obj.hexdigest()print (v1) v2 = obj.digest()print (v2)
更完整的Python实现:
1 2 3 4 5 6 7 8 9 10 11 import hashlib m = hashlib.md5() m.update("张三" .encode("utf-8" )) v1 = m.digest()print (v1) v2 = m.hexdigest()print (v2)
Java中的MD5实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.security.MessageDigest;public static void main (String[] args) throws NoSuchAlgorithmException { String name = "张三" ; MessageDigest instance = MessageDigest.getInstance("MD5" ); byte [] nameBytes = instance.digest(name.getBytes()); StringBuilder sb = new StringBuilder (); for (int i=0 ; i<nameBytes.length; i++) { int val = nameBytes[i] & 255 ; if (val<16 ) { sb.append("0" ); } sb.append(Integer.toHexString(val)); } String hexData = sb.toString(); System.out.println(hexData); }
MD5加盐处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import hashlibdef md5_with_salt (data, salt ): """MD5加盐加密""" combined = data + salt return hashlib.md5(combined.encode('utf-8' )).hexdigest()def md5_double_salt (data, salt1, salt2 ): """双重加盐""" combined = salt1 + data + salt2 return hashlib.md5(combined.encode('utf-8' )).hexdigest() password = "123456" salt = "mysalt" hashed = md5_with_salt(password, salt)print (f"加盐MD5: {hashed} " )
实际应用场景 - 抖音X-SS-STUB:
在抖音等应用的逆向分析中,经常遇到这样的场景:
1 2 3 4 每次发送POST请求时,抖音都会携带一些请求头:X-SS-STUB = "fjaku9asdf" 读取请求体中的数据,对请求体中的数据进行md5加密。
这种机制用于防止请求被篡改,是典型的API签名验证方式。
分析要点:
MD5虽然已被认为不够安全,但在逆向分析中仍然常见
注意加盐的方式和位置(前缀、后缀、中间插入)
Java中需要手动转换字节为16进制字符串
Python的hexdigest()
方法直接返回16进制字符串
在API逆向中,MD5常用于生成请求签名
7. SHA-256加密 SHA-256是SHA-2系列中最常用的哈希算法,比MD5更安全,在现代应用中广泛使用。
常见场景:
区块链和加密货币
数字签名验证
密码安全存储
API签名生成
Java中的SHA-256实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;public class Hello { public static void main (String[] args) throws NoSuchAlgorithmException { String name = "张三" ; MessageDigest instance = MessageDigest.getInstance("SHA-256" ); byte [] nameBytes = instance.digest(name.getBytes()); StringBuilder sb = new StringBuilder (); for (int i=0 ; i<nameBytes.length; i++) { int val = nameBytes[i] & 255 ; if (val<16 ) { sb.append("0" ); } sb.append(Integer.toHexString(val)); } String hexData = sb.toString(); System.out.println(hexData); } }
Python中的SHA-256实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 import hashlib m = hashlib.sha256() m.update("张三" .encode("utf-8" )) v1 = m.digest()print (v1) v2 = m.hexdigest()print (v2)
分析要点:
SHA-256输出长度固定为64个16进制字符(256位)
比MD5更安全,抗碰撞能力更强
在区块链和现代加密应用中广泛使用
Java和Python的实现方式类似,但Java需要手动处理字节转换
8. AES加密 AES(Advanced Encryption Standard)是目前最广泛使用的对称加密算法,在逆向工程中经常遇到。
常见场景:
敏感数据加密存储
网络通信加密
配置文件保护
API数据传输加密
Python中的AES实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from Crypto.Cipher import AESfrom Crypto.Util.Padding import pad KEY = "fd6b639dbcff0c2a1b03b389ec763c4b" IV = "77b07a672d57d64c" def aes_encrypt (data_string ): aes = AES.new( key=KEY.encode('utf-8' ), mode=AES.MODE_CBC, iv=IV.encode('utf-8' ) ) raw = pad(data_string.encode('utf-8' ), 16 ) return aes.encrypt(raw) data = aes_encrypt("张三" )print (data)print ([i for i in data])
Java中的AES实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import javax.crypto.Cipher;import javax.crypto.spec.SecretKeySpec;import javax.crypto.spec.IvParameterSpec;public class Hello { public static void main (String[] args) throws Exception { String data = "张三" ; String key = "fd6b639dbcff0c2a1b03b389ec763c4b" ; String iv = "77b07a672d57d64c" ; byte [] raw = key.getBytes(); SecretKeySpec skeySpec = new SecretKeySpec (raw, "AES" ); IvParameterSpec ivSpec = new IvParameterSpec (iv.getBytes()); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding" ); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec); byte [] encrypted = cipher.doFinal(data.getBytes()); } }
AES解密实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from Crypto.Cipher import AESfrom Crypto.Util.Padding import unpaddef aes_decrypt (encrypted_data, key, iv ): """AES解密函数""" aes = AES.new( key=key.encode('utf-8' ), mode=AES.MODE_CBC, iv=iv.encode('utf-8' ) ) decrypted = aes.decrypt(encrypted_data) return unpad(decrypted, 16 ).decode('utf-8' ) KEY = "fd6b639dbcff0c2a1b03b389ec763c4b" IV = "77b07a672d57d64c" encrypted = aes_encrypt("张三" ) decrypted = aes_decrypt(encrypted, KEY, IV)print (f"解密结果: {decrypted} " )
常见AES模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from Crypto.Cipher import AESfrom Crypto.Util.Padding import pad, unpadimport osdef aes_ecb_encrypt (data, key ): """ECB模式加密""" aes = AES.new(key.encode('utf-8' ), AES.MODE_ECB) padded_data = pad(data.encode('utf-8' ), 16 ) return aes.encrypt(padded_data)def aes_cbc_encrypt (data, key, iv ): """CBC模式加密""" aes = AES.new(key.encode('utf-8' ), AES.MODE_CBC, iv.encode('utf-8' )) padded_data = pad(data.encode('utf-8' ), 16 ) return aes.encrypt(padded_data)def aes_ctr_encrypt (data, key ): """CTR模式加密""" nonce = os.urandom(8 ) aes = AES.new(key.encode('utf-8' ), AES.MODE_CTR, nonce=nonce) return aes.encrypt(data.encode('utf-8' ))
在逆向分析中的要点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def analyze_aes_usage (): """分析AES使用模式""" patterns = { "硬编码密钥" : "直接在代码中写死的密钥" , "动态生成" : "基于设备信息或时间戳生成" , "网络获取" : "从服务器动态获取密钥" , "密钥派生" : "通过PBKDF2等算法派生" } modes = { "ECB" : "最简单但不安全,相同明文产生相同密文" , "CBC" : "需要IV,最常用的模式" , "CTR" : "流加密模式,需要nonce" , "GCM" : "认证加密,提供完整性保护" } return patterns, modes
分析要点:
AES是对称加密,加密和解密使用相同密钥
密钥长度通常为128、192或256位
CBC模式需要IV(初始化向量),ECB模式不需要
注意填充方式:PKCS5Padding、PKCS7Padding等
在逆向中重点关注密钥和IV的来源
Java中需要指定完整的算法描述:”AES/CBC/PKCS5Padding”
9. GZIP压缩 GZIP是一种广泛使用的数据压缩算法,在逆向工程中经常遇到,特别是在网络传输和数据存储中。
常见场景:
HTTP响应数据压缩
日志文件压缩存储
配置文件压缩
网络传输数据减少
Java中的GZIP实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import java.io.*;import java.util.zip.*;public class Hello { public static void main (String[] args) throws IOException { String data = "张三" ; ByteArrayOutputStream v0_1 = new ByteArrayOutputStream (); GZIPOutputStream v1 = new GZIPOutputStream (v0_1); v1.write(data.getBytes()); v1.close(); byte [] arg6 = v0_1.toByteArray(); ByteArrayOutputStream out = new ByteArrayOutputStream (); ByteArrayInputStream in = new ByteArrayInputStream (arg6); GZIPInputStream ungzip = new GZIPInputStream (in); byte [] buffer = new byte [256 ]; int n; while ((n = ungzip.read(buffer)) >= 0 ) { out.write(buffer, 0 , n); } byte [] res = out.toByteArray(); System.out.println(out.toString("UTF-8" )); } }
Python中的GZIP实现:
1 2 3 4 5 6 7 8 9 10 11 import gzip s_in = "我是张三" .encode('utf-8' ) s_out = gzip.compress(s_in)print ([i for i in s_out]) res = gzip.decompress(s_out)print (res)print (res.decode('utf-8' ))
更完整的Python实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 import gzipimport iodef gzip_compress (data ): """GZIP压缩函数""" if isinstance (data, str ): data = data.encode('utf-8' ) return gzip.compress(data)def gzip_decompress (compressed_data ): """GZIP解压缩函数""" return gzip.decompress(compressed_data)def gzip_compress_to_file (data, filename ): """压缩数据到文件""" with gzip.open (filename, 'wb' ) as f: if isinstance (data, str ): data = data.encode('utf-8' ) f.write(data)def gzip_decompress_from_file (filename ): """从文件解压缩数据""" with gzip.open (filename, 'rb' ) as f: return f.read() original_data = "我是张三" compressed = gzip_compress(original_data) decompressed = gzip_decompress(compressed)print (f"原始数据: {original_data} " )print (f"压缩后字节: {[i for i in compressed]} " )print (f"解压缩结果: {decompressed.decode('utf-8' )} " )
在逆向分析中的应用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import gzipimport base64def analyze_compressed_data (data ): """分析可能的压缩数据""" if data.startswith(b'\x1f\x8b' ): print ("检测到GZIP压缩数据" ) try : decompressed = gzip.decompress(data) print (f"解压缩成功,原始大小: {len (decompressed)} " ) return decompressed except Exception as e: print (f"解压缩失败: {e} " ) try : decoded = base64.b64decode(data) if decoded.startswith(b'\x1f\x8b' ): print ("检测到Base64编码的GZIP数据" ) decompressed = gzip.decompress(decoded) return decompressed except : pass return None def handle_http_response (response_data, headers ): """处理HTTP响应中的GZIP数据""" if headers.get('Content-Encoding' ) == 'gzip' : try : decompressed = gzip.decompress(response_data) return decompressed.decode('utf-8' ) except Exception as e: print (f"GZIP解压缩失败: {e} " ) return response_data
压缩比分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import gzipdef compression_analysis (data ): """分析压缩效果""" if isinstance (data, str ): original_bytes = data.encode('utf-8' ) else : original_bytes = data compressed = gzip.compress(original_bytes) original_size = len (original_bytes) compressed_size = len (compressed) ratio = (1 - compressed_size / original_size) * 100 print (f"原始大小: {original_size} 字节" ) print (f"压缩后大小: {compressed_size} 字节" ) print (f"压缩比: {ratio:.2 f} %" ) return compressed test_data = "我是张三" * 100 compression_analysis(test_data)
重要提醒: Java、Python语言区别。(个人字节是不同,不影响整个的结果)
分析要点:
GZIP文件以魔数1F 8B
开头,这是识别GZIP数据的重要特征
压缩比取决于数据的重复性和模式
在网络抓包分析中,注意Content-Encoding: gzip
头部
Java实现相对复杂,需要使用流操作
Python的gzip
模块提供了简单的压缩/解压缩接口
在逆向分析中,GZIP常用于隐藏或减少数据传输量
10. Base64编码 Base64是一种基于64个可打印字符来表示二进制数据的编码方法,在逆向工程中极其常见。
常见场景:
数据传输编码
配置文件中的二进制数据
网络协议中的数据编码
图片和文件的文本表示
Python中的Base64实现:
1 2 3 4 5 6 7 8 9 10 11 12 import base64 name = "张三" res = base64.b64encode(name.encode('utf-8' ))print (res) data = base64.b64decode(res) origin = data.decode('utf-8' )print (origin)
Java中的Base64实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.util.Base64;public class Hello { public static void main (String[] args) { String name = "张三" ; Base64.Encoder encoder = Base64.getEncoder(); String res = encoder.encodeToString(name.getBytes()); System.out.println(res); Base64.Decoder decoder = Base64.getDecoder(); byte [] origin = decoder.decode(res); String data = new String (origin); System.out.println(data); } }
更完整的Python实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import base64def base64_encode (data ): """Base64编码函数""" if isinstance (data, str ): data = data.encode('utf-8' ) return base64.b64encode(data).decode('ascii' )def base64_decode (encoded_data ): """Base64解码函数""" if isinstance (encoded_data, str ): encoded_data = encoded_data.encode('ascii' ) return base64.b64decode(encoded_data)def base64_url_encode (data ): """URL安全的Base64编码""" if isinstance (data, str ): data = data.encode('utf-8' ) return base64.urlsafe_b64encode(data).decode('ascii' )def base64_url_decode (encoded_data ): """URL安全的Base64解码""" if isinstance (encoded_data, str ): encoded_data = encoded_data.encode('ascii' ) return base64.urlsafe_b64decode(encoded_data) text = "张三" encoded = base64_encode(text) decoded = base64_decode(encoded)print (f"原文: {text} " )print (f"编码: {encoded} " )print (f"解码: {decoded.decode('utf-8' )} " )
在逆向分析中的应用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 import base64import redef detect_base64 (data ): """检测可能的Base64编码数据""" base64_pattern = re.compile (r'^[A-Za-z0-9+/]*={0,2}$' ) if isinstance (data, bytes ): data = data.decode('ascii' , errors='ignore' ) if len (data) % 4 != 0 : return False if not base64_pattern.match (data): return False try : decoded = base64.b64decode(data) if all (32 <= b <= 126 or b in [9 , 10 , 13 ] for b in decoded): return True except : pass return False def analyze_base64_data (data ): """分析Base64数据""" if detect_base64(data): try : decoded = base64.b64decode(data) print (f"检测到Base64数据" ) print (f"原始长度: {len (data)} " ) print (f"解码后长度: {len (decoded)} " ) print (f"解码内容: {decoded} " ) try : text = decoded.decode('utf-8' ) print (f"UTF-8文本: {text} " ) except : print ("非UTF-8文本数据" ) return decoded except Exception as e: print (f"Base64解码失败: {e} " ) else : print ("不是有效的Base64数据" ) return None def detect_nested_encoding (data ): """检测多层Base64编码""" current = data layers = 0 while detect_base64(current) and layers < 10 : try : decoded = base64.b64decode(current) current = decoded.decode('ascii' , errors='ignore' ) layers += 1 print (f"第{layers} 层Base64解码: {current} " ) except : break return layers, current
Base64变种处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import base64import stringdef base64_custom_alphabet (data, alphabet ): """自定义字母表的Base64编码""" standard = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" trans_table = str .maketrans(alphabet, standard) standard_b64 = data.translate(trans_table) return base64.b64decode(standard_b64)def analyze_custom_base64 (data ): """分析可能的自定义Base64编码""" custom_alphabets = [ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" , "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/" , "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/" , ] for i, alphabet in enumerate (custom_alphabets): try : decoded = base64_custom_alphabet(data, alphabet) print (f"自定义字母表{i+1 } 解码成功: {decoded} " ) except : continue
分析要点:
Base64编码后的字符串长度总是4的倍数
只包含A-Z、a-z、0-9、+、/和=(填充)字符
URL安全版本使用-和_替代+和/
在逆向分析中,Base64常用于隐藏配置信息、密钥等
注意多层Base64编码的情况
某些应用会使用自定义的Base64字母表
11. 反调试技术 常见反调试手段
IsDebuggerPresent()
检测
PEB 结构检查
时间差检测
异常处理反调试
处理方式 11.1 API Hook 绕过 1 2 3 4 BOOL WINAPI FakeIsDebuggerPresent () { return FALSE; }
11.2 内存补丁 1 2 3 4 ; 将检测代码 nop 掉 mov eax, 0 ; 原: call IsDebuggerPresent nop ; 原: test eax, eax nop ; 原: jnz exit
11.3 PEB 修改 1 2 3 4 def modify_peb (): peb_addr = Process.getCurrentProcess().getPointer("PEB" ) peb_addr.add(0x02 ).writeU8(0 )
12. 代码混淆 常见混淆技术
处理策略 12.1 控制流分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import idaapiimport idcdef analyze_cfg (start_addr ): """分析控制流图""" visited = set () queue = [start_addr] while queue: addr = queue.pop(0 ) if addr in visited: continue visited.add(addr) insn = idaapi.insn_t() idaapi.decode_insn(insn, addr) for i in range (insn.Op1.type , insn.Op6.type ): if insn.ops[i].type == idaapi.o_near: queue.append(insn.ops[i].addr)
12.2 去混淆脚本 1 2 3 4 5 6 7 8 9 10 11 def remove_junk_code (start, end ): addr = start while addr < end: insn = idc.GetDisasm(addr) if "push eax" in insn and "pop eax" in idc.GetDisasm(addr + idc.ItemSize(addr)): idc.PatchByte(addr, 0x90 ) idc.PatchByte(addr + 1 , 0x90 ) addr = idc.NextHead(addr)
13. 字符串加密 识别方法
查找解密函数特征
分析字符串使用模式
动态跟踪字符串生成
解密策略 1 2 3 4 5 6 7 8 9 10 11 12 13 14 def decrypt_strings (): decrypt_func = 0x401234 for xref in idautils.XrefsTo(decrypt_func): encrypted_str = idc.GetOperandValue(xref.frm - 5 , 0 ) key = idc.GetOperandValue(xref.frm - 10 , 0 ) decrypted = simple_xor_decrypt(encrypted_str, key) idc.MakeComm(xref.frm, f"Decrypted: {decrypted} " )
14. 虚拟机保护 特征识别
分析方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def trace_vm_instructions (): vm_context = get_vm_context() instruction_log = [] while vm_context.running: opcode = vm_context.fetch_opcode() instruction_log.append({ 'pc' : vm_context.pc, 'opcode' : opcode, 'operands' : vm_context.get_operands() }) vm_context.execute() return instruction_log
15. 动态分析技巧 15.1 内存断点 1 2 3 4 # GDB 中设置内存访问断点 watch *0x401000 awatch *0x401000 # 访问断点 rwatch *0x401000 # 读取断点
15.2 API 监控 1 2 3 4 5 6 7 8 9 10 Java .perform (function ( ) { var targetClass = Java .use ("com.example.TargetClass" ); targetClass.sensitiveMethod .implementation = function (param ) { console .log ("[+] sensitiveMethod called with: " + param); var result = this .sensitiveMethod (param); console .log ("[+] Result: " + result); return result; }; });
16. 静态分析优化 16.1 函数识别 1 2 3 4 5 6 7 8 9 10 11 def find_crypto_functions (): crypto_patterns = [ b'\x31\xc0\x99\xf7\xf1' , b'\xd1\xe8\x73\x02' , ] for pattern in crypto_patterns: addr = idc.FindBinary(0 , idc.SEARCH_DOWN, pattern) if addr != idc.BADADDR: print (f"Potential crypto function at: {hex (addr)} " )
16.2 交叉引用分析 1 2 3 4 5 6 7 8 9 10 11 def analyze_key_usage (key_addr ): xrefs = [] for xref in idautils.XrefsTo(key_addr): func_name = idc.GetFunctionName(xref.frm) xrefs.append({ 'addr' : xref.frm, 'function' : func_name, 'type' : xref.type }) return xrefs
17. 实用工具与脚本 17.1 自动化分析脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import subprocessimport osdef auto_analysis (binary_path ): """自动化逆向分析流程""" print ("[+] 收集基础信息..." ) os.system(f"file {binary_path} " ) os.system(f"strings {binary_path} | head -20" ) print ("[+] 生成反汇编..." ) os.system(f"objdump -d {binary_path} > disasm.txt" ) print ("[+] 分析符号表..." ) os.system(f"nm {binary_path} > symbols.txt" ) print ("[+] 检查依赖..." ) os.system(f"ldd {binary_path} " )if __name__ == "__main__" : auto_analysis("target_binary" )
17.2 内存 Dump 工具 1 2 3 4 5 6 7 8 9 10 11 12 13 def dump_process_memory (pid, start_addr, size ): """导出进程内存""" try : with open (f"/proc/{pid} /mem" , "rb" ) as mem_file: mem_file.seek(start_addr) data = mem_file.read(size) with open (f"dump_{hex (start_addr)} .bin" , "wb" ) as dump_file: dump_file.write(data) print (f"[+] 内存已导出到 dump_{hex (start_addr)} .bin" ) except Exception as e: print (f"[-] 导出失败: {e} " )