10.苹果ios逆向-FridaHook-ios中的算法-CCMD5
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
内容参考于:图灵Python学院
工具下载:
链接:百度网盘 请输入提取码
提取码:zy89
复制这段内容后打开百度网盘手机App,操作更方便哦
上一个内容:9.苹果ios逆向-FridaHook-ios中的算法(CCCrypt)
上一个内容中通过CCCrypt算法拦截到了入参,如下图,搜索加密的数据

然后通过搜索加密的数据找它的被加密数据,7297aae7048485ac95238be125de0a1b,它的长度32位像是MD5加密,所以接下来开始拦截MD5加密

然后hookMd5算法使用,frida-trace -Up 进程id(使用frida-ps -Ua指令查询) -i CC_MD5 指令

它也是会给我创建一个文件

文件内容

还是全选复制给大模型,让大模型给我们介绍,给我们说明
onEnter说明,可以看出args[0]是要被md5加密的数据

onLeave说明

然后让大模型给我写代码,让它输出明文和密文,

/** Auto-generated by Frida. Please modify to match the signature of CC_MD5.* This stub is currently auto-generated from manpages when available.** For full API reference, see: https://frida.re/docs/javascript-api/*/{/*** Called synchronously when about to call CC_MD5.** @this {object} - Object allowing you to store state for use in onLeave.* @param {function} log - Call this function with a string to be presented to the user.* @param {array} args - Function arguments represented as an array of NativePointer objects.* For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8.* It is also possible to modify arguments by assigning a NativePointer object to an element of this array.* @param {object} state - Object allowing you to keep state across function calls.* Only one JavaScript function will execute at a time, so do not worry about race-conditions.* However, do not use this to store function arguments across onEnter/onLeave, but instead* use "this" which is an object for keeping state local to an invocation.*/onEnter(log, args, state) {var input = args[0].readUtf8String();log('明文: ' + input);this.input = input;log('CC_MD5()');},/*** Called synchronously when about to return from CC_MD5.** See onEnter for details.** @this {object} - Object allowing you to access state stored in onEnter.* @param {function} log - Call this function with a string to be presented to the user.* @param {NativePointer} retval - Return value represented as a NativePointer object.* @param {object} state - Object allowing you to keep state across function calls.*/onLeave(log, retval, state) {// 假设retval指向MD5结果的16字节缓冲区var hex = '';for (var i = 0; i < 16; i++) {var b = retval.add(i).readU8();hex += ('0' + b.toString(16)).slice(-2);}log('密文(十六进制): ' + hex);}
}
效果图:通过上方的MD5成功在MD5拦截里找到了

被MD5加密的数据

总结:
第一步使用 EC74E1D8-7511-4D03-8836-534842029CAE1754189311 做MD5加密
第二步获取MD5加密的值
第三步把MD5加密后的数据进行AES的CBC模式IV是0,然后加密就可以了
# 导入需要的工具包
# hashlib:用来做MD5加密的工具
# AES:用来做AES加密的工具
# binascii和base64:用来转换加密结果格式的工具
import hashlib
from Crypto.Cipher import AES
import binascii
import base64def aes_encrypt(key, data, mode, iv=None):"""这个函数是用来做AES加密的key:加密用的"钥匙"(必须是字节形式)data:要加密的数据(必须是字节形式)mode:加密模式(就像不同类型的锁)iv:初始化向量(某些锁需要这个辅助工具)"""# 根据选择的模式创建加密器(就像选不同的锁)if mode == AES.MODE_ECB:# ECB模式的锁比较简单,不需要ivcipher = AES.new(key, mode)else:# 其他模式(比如CBC)需要iv才能工作cipher = AES.new(key, mode, iv=iv)# 用创建好的加密器加密数据encrypted_data = cipher.encrypt(data)return encrypted_dataif __name__ == "__main__":# 我们要处理的原始字符串(可以想象成一封明文信)original_str = "EC74E1D8-7511-4D03-8836-534842029CAE1754193769"print(f"原始字符串: {original_str}")# 第一步:用MD5处理原始字符串# MD5就像把信揉成一个固定大小的纸团# 不管原来的信有多长,揉完都是32个字符md5_hash = hashlib.md5()# 把字符串变成计算机能处理的字节形式(加utf-8编码)md5_hash.update(original_str.encode('utf-8'))# 得到MD5处理后的结果(32个字符的字符串)md5_hex = md5_hash.hexdigest()print(f"MD5加密结果(十六进制): {md5_hex}")print(f"MD5十六进制长度: {len(md5_hex)}字符") # 这里会显示32# 第二步:把MD5结果变成字节形式# 因为计算机只认识字节(0和1组成的信号)md5_bytes = md5_hex.encode('utf-8')print(f"MD5十六进制转字节后长度: {len(md5_bytes)}字节") # 这里会显示32# 第三步:给数据"补零"# AES加密有个规矩:数据长度必须是16的倍数(就像快递必须用标准箱子)# 计算需要补多少个0才能凑够16的倍数pad_length = (16 - (len(md5_bytes) % 16)) % 16# 补充0字节(这里32正好是16的2倍,所以其实不用补,但代码还是做了准备)data = md5_bytes + b'\x00' * pad_lengthprint(f"补全后的数据长度: {len(data)}字节") # 这里会显示32print(f"补全后的数据(十六进制): {binascii.hexlify(data).decode('utf-8')}")# 第四步:准备AES加密的"钥匙"key_str = "neteasenewsboard" # 钥匙的字符串形式key = key_str.encode('utf-8') # 转成计算机能认的字节形式print(f"AES密钥: {key.hex()} ({key_str})")# 准备几个不同的"辅助钥匙"(IV)# IV是CBC模式需要的辅助工具,必须是16字节iv1 = b'\x00' * 16 # 全是0的辅助钥匙iv2 = key[:16] # 用主钥匙的前16个字节做辅助钥匙iv3 = data[:16] # 用数据的前16个字节做辅助钥匙# 准备尝试不同的加密模式(不同类型的锁)modes = [("ECB模式", AES.MODE_ECB, None), # ECB模式不需要辅助钥匙("CBC模式 (全0辅助钥匙)", AES.MODE_CBC, iv1),("CBC模式 (用主钥匙做辅助钥匙)", AES.MODE_CBC, iv2),("CBC模式 (用数据做辅助钥匙)", AES.MODE_CBC, iv3)]# 逐个尝试这些加密模式for mode_name, mode, iv in modes:try:# 执行AES加密encrypted = aes_encrypt(key, data, mode, iv)# 把加密结果转成十六进制字符串(方便查看)encrypted_hex = binascii.hexlify(encrypted).decode('utf-8')# 把加密结果转成Base64格式(另一种常用格式)encrypted_base64 = base64.b64encode(encrypted).decode('utf-8')# 显示加密结果print(f"\n{mode_name}:")print(f"使用的辅助钥匙: {binascii.hexlify(iv).decode('utf-8') if iv else '不需要'}")print(f"加密结果(十六进制): {encrypted_hex}")print(f"加密结果(Base64): {encrypted_base64}")except Exception as e:# 如果加密失败,显示错误信息print(f"❌ {mode_name} 加密失败: {str(e)}")
上方的代码是通过把下图红框的内容复制给ai大模型,它生成的,注意下方的代码是MD5后的,上方的代码是先用下图红框的内容生成AES加密,然后再告诉ai大模型md5的逻辑,然后在整合到aes加密里

效果图:


