前提:
该样本较为容易,无加固和frida检测,实践ida mcp 和cursor的逆向使用 。
版本:1.6.5
包名:com.xinhe.tataxingqiu
加固状态:未加固
IDA_Pro MCP接入与使用教程 - 吾爱破解 - 52pojie.cn
IDA_Pro MCP接入与使用教程 - 吾爱破解 - 52pojie.cn
一、初步分析
通过上图抓包我们可以看到,请求体和响应值都进行了加密,并且我们可以敏锐的发现带有 **@006** 这种类似标识,而且每次抓包都会返回不一样的标识,我们可以先猜测这个是对应的一种算法。
由于我们此次的样本的加固状态是未加固的,所以我们可以直接使用jadx打开我们的apk。然后通过搜索我们上述的关键词我们可以直接进行定位。
跳转到 com.beinasong.Beinasong中我们可以看到是一个native函数。这两个函数分别代表着加密和解密。
hook测试一下。直接就可以hook到的所以我们可以得知其实是libbeinasong.so的dr和ep函数进行我们的加密和解密。
二、ida Ai分析
这里我直接使用的 IDA_Pro MCP 配合cursor进行分析梭哈。首先连接idapro和cursor
点击mcp,接着输入命令ida-pro-mcp --config 获取配置到cursor配置具体详细步骤可以看开头给出的52破解相关帖子
{
"mcpServers": {
"github.com/mrexodia/ida-pro-mcp": {
"command": "C:\\Users\\25855\\AppData\\Local\\Programs\\Python\\Python312\\python.exe",
"args": [
"C:\\Users\\25855\\AppData\\Local\\Programs\\Python\\Python312\\Lib\\site-packages\\ida_pro_mcp\\server.py"
],
"timeout": 1800,
"disabled": false
}
}
}
这个是我的配置。
先简单分析一下这个so文件,映入眼帘的不就是native_encrypt和native_decrypt函数。这两个明显就是加密和解密。
有轻微的ollvm混淆不过没关系,我们此次有mcp+cursor。其实我们这里手动就能看出来是什么意思,我们让cursor分析一下。
这里我们看到了随机数,接下来我们重点看encode函数。
**User**
帮我分析下 encode 函数
---
**Cursor**
让我们来查看`encode`函数的具体实现。从之前的分析我们知道它在`native_encrypt`中被调用,让我们通过地址`0x400f78`附近查找这个函数:
让我尝试直接搜索`encode`函数:
很好,我们找到了`encode`函数,让我们看看它的反编译代码:
让我分析一下这个`encode`函数的主要逻辑:
1. 函数参数:
```cpp
__int64 __fastcall encode(char *a1, const char *a2, char *s, int a4)
```- `a1`: 加密模式(0-19)
- `a2`: 输入字符串
- `s`: 输出缓冲区
- `a4`: 输入字符串长度2. 主要加密逻辑:
- 首先检查加密模式是否超过20,如果超过则使用20
- 在输出缓冲区的前4个字节写入加密模式(通过sprintf写入)
- 使用一个查找表`aRmf5he08tgnpyb`进行字符映射,每种加密模式对应66字节的映射表
- 使用Base64类似的编码方式,但是:
- 每3个输入字节转换为4个输出字节
- 使用自定义的字符映射表而不是标准Base64字符集
- 对字节进行位运算和异或操作进行混淆
- 对不足3字节的情况有特殊处理(使用'='填充)3. 加密步骤:
- 将输入按3字节分组处理
- 对于每组3字节:
- 第一个输出字节:使用第一个输入字节的高6位
- 第二个输出字节:使用第一个输入字节的低2位和第二个输入字节的高4位
- 第三个输出字节:使用第二个输入字节的低4位和第三个输入字节的高2位
- 第四个输出字节:使用第三个输入字节的低6位
- 每个转换后的6位值用作索引查找自定义字符表
- 对最后不足3字节的组进行特殊处理,使用'='填充4. 特点:
- 使用20种不同的映射表
- 每次加密使用随机的映射表(0-19)
- 加密模式存储在输出的前4个字节
- 输出长度约为输入长度的2倍(由于Base64编码特性)
- 使用了复杂的位运算和异或操作增加混淆这是一个自定义的Base64变种加密算法,主要特点是:
1. 使用多个自定义字符映射表
2. 随机选择映射表增加随机性
3. 在标准Base64的基础上增加了额外的位运算混淆
4. 将使用的映射表索引存储在输出中,便于解密这种加密方式的安全性主要依赖于自定义字符映射表的保密性,但由于映射表是静态存储在程序中的,如果获得程序就可以提取出映射表,因此这种加密方式主要用于简单的数据混淆,而不是真正的安全加密。
我们通过ai分析直接可以得出此样本的是使用了20种不同的映射表将我们的明文根据随机rand数字选取映射表进行映射为加密字体。其实这里的解密也同理。
cursor实现算法:
class BeinasongEncoder:
### 20个不同的映射表
MAPPING_TABLES = [
"rMf5HE08tGnPYbydcZUiAgTlkepJqCNsO2xS7R6FLvQ9Va3WoDm4Ku1hwBzIjX+/=",
"2WjYJh60fmDru1nXMRSGQsU5OE7avAIL3PiyxolpC9gNdV8zwBcqek4TKHbFtZ+/=",
"xtH0aiTugLPBz9NyWb76crAXkwqs1v3C4FpJfoDeM2SUnm8QOdRjKYVhZ5GEIl+/=",
"McNirjO3X7pKIBwCFSu2HEZU15ae8xsPVvzJqQdgWA9h0DtlmGoT6yn4YLkbRf+/=",
"RO3rB2wpXmcixTd8qCnhQ9FHzofbG4YkyIZEWjDNtLPa5KuA1gsMl0eJV7vUS6+/=",
"FufxbzJCOp4kn3yUasH6itX0ejqMow5vE1dKSTZ9lgYWrBAIhN7mQDG8V2RcLP+/=",
"30Owz1lWvSRN2e94a5xiTI6Q8LbgytGFuVqjEfhsDkcAPKUHJp7rmYZCoMnBXd+/=",
"hgYcPI58nidvW14yVGtlSx9eTKZ3LU0bRB6JmOFqHjX7zfas2ECkoQprDAuNMw+/=",
"fCgxyqDnpBdAVuiPOsQ0TK9N8LhkFJe4vlIEwz5H62XGSmRUcW3Z7jYab1oMtr+/=",
"UoKWvCdiHtwS5B27PnLaATFy4DYfrIlukNX9bQ3EpZeRqJGx0cj81zhM6smVOg+/=",
"qjod0M1Sn9rsUAwtmLkBPx53JOHuGD2hEz6paFN8iIeZbTlg4YXQfKyv7VWRcC+/=",
"OdUbEeSBp7yHLoRW82wFDsAZzgXfnQIJCkGt9ach0V4N31rvKqYx6mjTi5luPM+/=",
"6tXKe5bwvORkfJmh1VEBFyP30HSlj4u2DqGcdMnxpoWzYIAgUr97QCiNaLTZs8+/=",
"MOtoudUjsv1KlEpfCTaRnZrwbceDH5q4JLyB6PXhW9FQxAk7NImSVgY832G0iz+/=",
"VRWucGgEofizMdq6PxlS0JX95bmT4pvUetZwjaOK1Ik3rYChDQ8ynNLHsA2B7F+/=",
"nOm1vuWUN5KMHRxpFVykI9zALCT8BX3brZj0fedlS6DPoGcws2aJq4EhYQgt7i+/=",
"x1sdAYPzyWipREB6GwlojVCXeM9rkUFOSa2NhHq0gfmLZT8KJtnIb4357QcvuD+/=",
"KGBAijw9PJHLcD1SNnaEqerCmbzUpl0RhFg7kyoVduT6vtYQ43fW28xOs5IXZM+/=",
"Cjli5W2FY8wBHg4OJkvATdhq1Xo0bIpxnuLPZsmafUN9y37tcEG6zMRQKDVeSr+/=",
"Y28iFvuXOCoE7fDq3MBkAJrwygbdGeVhHWZNmcln4aT9sxLIS5Q6t0pKPRjz1U+/="
]
@staticmethod
def encode(plaintext: str, mode: int) -> str:
"""
加密函数
:param plaintext: 明文字符串
:param mode: 加密模式 (0-19)
:return: 加密后的字符串
"""
# 确保mode在0-19之间
mode = mode % 20
# 获取对应的映射表
mapping_table = BeinasongEncoder.MAPPING_TABLES[mode]
# 将mode写入结果的前4个字节
result = f"{mode:02d}"
# 将输入文本转换为字节数组
data = plaintext.encode('utf-8')
length = len(data)
# 按3字节一组处理
idx = 0
while idx < length:
remaining = length - idx
if remaining >= 3:
# 处理完整的3字节组
b1, b2, b3 = data[idx], data[idx + 1], data[idx + 2]
# 4个6位值的转换
c1 = b1 >> 2
c2 = ((b1 & 0x3) << 4) | (b2 >> 4)
c3 = ((b2 & 0xF) << 2) | (b3 >> 6)
c4 = b3 & 0x3F
# 查表转换并添加到结果
result += mapping_table[c1]
result += mapping_table[c2]
result += mapping_table[c3]
result += mapping_table[c4]
elif remaining == 2:
# 处理剩余2字节
b1, b2 = data[idx], data[idx + 1]
c1 = b1 >> 2
c2 = ((b1 & 0x3) << 4) | (b2 >> 4)
c3 = (b2 & 0xF) << 2
result += mapping_table[c1]
result += mapping_table[c2]
result += mapping_table[c3]
result += '='
else:
# 处理剩余1字节
b1 = data[idx]
c1 = b1 >> 2
c2 = (b1 & 0x3) << 4
result += mapping_table[c1]
result += mapping_table[c2]
result += '=='
idx += 3
return result
经过测试得到的完全相同和我们的hook到的。
解密嘞直接梭哈吧:其实就是根据传回的前几个字符确定使用的第几套编码来再进行解密。
class BeinasongCrypto:
# 20个不同的映射表(与之前的encoder相同)
MAPPING_TABLES = [
"rMf5HE08tGnPYbydcZUiAgTlkepJqCNsO2xS7R6FLvQ9Va3WoDm4Ku1hwBzIjX+/=",
"2WjYJh60fmDru1nXMRSGQsU5OE7avAIL3PiyxolpC9gNdV8zwBcqek4TKHbFtZ+/=",
"xtH0aiTugLPBz9NyWb76crAXkwqs1v3C4FpJfoDeM2SUnm8QOdRjKYVhZ5GEIl+/=",
"McNirjO3X7pKIBwCFSu2HEZU15ae8xsPVvzJqQdgWA9h0DtlmGoT6yn4YLkbRf+/=",
"RO3rB2wpXmcixTd8qCnhQ9FHzofbG4YkyIZEWjDNtLPa5KuA1gsMl0eJV7vUS6+/=",
"FufxbzJCOp4kn3yUasH6itX0ejqMow5vE1dKSTZ9lgYWrBAIhN7mQDG8V2RcLP+/=",
"30Owz1lWvSRN2e94a5xiTI6Q8LbgytGFuVqjEfhsDkcAPKUHJp7rmYZCoMnBXd+/=",
"hgYcPI58nidvW14yVGtlSx9eTKZ3LU0bRB6JmOFqHjX7zfas2ECkoQprDAuNMw+/=",
"fCgxyqDnpBdAVuiPOsQ0TK9N8LhkFJe4vlIEwz5H62XGSmRUcW3Z7jYab1oMtr+/=",
"UoKWvCdiHtwS5B27PnLaATFy4DYfrIlukNX9bQ3EpZeRqJGx0cj81zhM6smVOg+/=",
"qjod0M1Sn9rsUAwtmLkBPx53JOHuGD2hEz6paFN8iIeZbTlg4YXQfKyv7VWRcC+/=",
"OdUbEeSBp7yHLoRW82wFDsAZzgXfnQIJCkGt9ach0V4N31rvKqYx6mjTi5luPM+/=",
"6tXKe5bwvORkfJmh1VEBFyP30HSlj4u2DqGcdMnxpoWzYIAgUr97QCiNaLTZs8+/=",
"MOtoudUjsv1KlEpfCTaRnZrwbceDH5q4JLyB6PXhW9FQxAk7NImSVgY832G0iz+/=",
"VRWucGgEofizMdq6PxlS0JX95bmT4pvUetZwjaOK1Ik3rYChDQ8ynNLHsA2B7F+/=",
"nOm1vuWUN5KMHRxpFVykI9zALCT8BX3brZj0fedlS6DPoGcws2aJq4EhYQgt7i+/=",
"x1sdAYPzyWipREB6GwlojVCXeM9rkUFOSa2NhHq0gfmLZT8KJtnIb4357QcvuD+/=",
"KGBAijw9PJHLcD1SNnaEqerCmbzUpl0RhFg7kyoVduT6vtYQ43fW28xOs5IXZM+/=",
"Cjli5W2FY8wBHg4OJkvATdhq1Xo0bIpxnuLPZsmafUN9y37tcEG6zMRQKDVeSr+/=",
"Y28iFvuXOCoE7fDq3MBkAJrwygbdGeVhHWZNmcln4aT9sxLIS5Q6t0pKPRjz1U+/="
]
@staticmethod
def decode(ciphertext: str) -> str:
"""
解密函数
:param ciphertext: 密文字符串(前两位为模式号)
:return: 解密后的明文
"""
# 获取加密模式
mode = int(ciphertext[1:4])
mode = mode % 20
# 获取实际的密文数据
data = ciphertext[4:]
# 获取对应的映射表
mapping_table = BeinasongCrypto.MAPPING_TABLES[mode]
# 创建反向映射表(用于快速查找字符位置)
reverse_map = {char: i for i, char in enumerate(mapping_table)}
# 解码结果
result = bytearray()
# 按4个字符一组处理
idx = 0
while idx < len(data):
# 获取4个字符
chunk = data[idx:idx + 4]
if len(chunk) < 4:
break
# 处理填充
padding = chunk.count('=')
if padding > 0:
chunk = chunk.rstrip('=') + 'A' * padding
# 获取4个6位值
b1 = reverse_map[chunk[0]]
b2 = reverse_map[chunk[1]]
b3 = reverse_map[chunk[2]]
b4 = reverse_map[chunk[3]]
# 组合成3个字节
result.append((b1 << 2) | (b2 >> 4))
if padding < 2:
result.append(((b2 & 0xF) << 4) | (b3 >> 2))
if padding < 1:
result.append(((b3 & 0x3) << 6) | b4)
idx += 4
# 转换为UTF-8字符串
return result.decode('utf-8')
@staticmethod
def encode(plaintext: str, mode: int) -> str:
"""
加密函数(与之前的实现相同)
"""
# ... 之前的encode实现 ...
# 创建加解密器实例
crypto = BeinasongCrypto()
# 测试加密和解密
plaintext = "@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