某海外市场运营商app登录协议逆向

查看 65|回复 6
作者:hHunter   


1.png (14.53 KB, 下载次数: 0)
下载附件
2025-7-22 20:31 上传

首先拿到应用的格式为xapk,这个格式其实就是把包的其他资源分开打包了。
后缀改为zip解压后得到几个文件如下图:


2.png (58.15 KB, 下载次数: 0)
下载附件
2025-7-22 20:31 上传



3.png (82.34 KB, 下载次数: 0)
下载附件
2025-7-22 20:31 上传

大致看出来有com的这个就是核心代码apk文件了,咱们主要分析这个包体,看看怎么个事
首先通过一个root过的真机进行调试,首先把xapk丢入手机中进行安装,点击运行后出现的界面顺序如下两张图
先是出现了登录界面,然后便跳出另外一个界面了。
我先打开Manifest.xml文件分析一下主Activity的调用为


4.png (8.78 KB, 下载次数: 0)
下载附件
2025-7-22 20:36 上传

然后adb进入手机的启动frda的服务短程序
使用objection调用其内存中存在的Activity,这里我直接调用SplashScreenActivity,成功跳到手机号输入界面。
启动Reqable,进行抓包,输入手机号码,点击GET OTP按钮后出现登录请求的包体数据,全部进行加密了。
NP8AqqGZMadYeIN5AcedoWFyiYW9Rln4dHDFFaNLy8umH6qSwAOppb7O/SmycgtWOL+A3ndWEYtOGbnlYpnx+9/Kr8sWtrS+wk/PFgBXmfRb6Es6LpCYdycxhoX2+tRvloAhJ8FXCo+FDC6ZO+QJwM1Hcbcc6eLzfbZ6Pp+0dID7p90nJLFClcfCUk5T8q8jCtBR3l4BxCfUAZcgvrAlp487ITaGyxhMp6aogUrm4AcwFzdPhgG2XpMrn60xWKx/vBuq7wYmJH7h6VKcrjjS4zNQaBUbaODFBJMyXeWfSw3Ctf8D9IfXOtzPr+NJmGGfD+grlwFVfm2Cbd3OqkYD9xu0udjf3gjw9Nw/S85aEcj0lN5VaepJ2hRoSCPK5589yxB+K8CEwoiNDWZJMg4xwca7We9mffeeHWC39IXyvtTqEX7WHOY+aN9zQU6cu2SjUuk8fLuYWCyrY0IdIxc/2pKFyh2pxr5gQSW2teobrgmLUNBBLgRXwN2a6Oz+SYAF+a4n/+5Rr/A=
然后输入验证码后出现真实的请求包体数据,同样也进行加密了。
SbCgfyIaaDwVpdFfDj0noFoSauFfqOkBfA6X1nb+zwj5EPwWmfvVApVZkXTjurcMHShSo+gKTwOuAq34AFzHn2SR2IZU3kJ2qbX8NVWNFeykBNDwD0lu0R/uiv4n8rR7DLg0gGIfMgtMxhZbnk9tTrc1VJqAL83kzJHRK63OadSNKM8IWE2QrOyhmyUt2F0onKwJpcY1/C5CLatJnggBZADmTRUmsKSZo/4WHlwUQaxMNF4XVb4lfKYtCjn3XWQEEFO3WCQeANg=
我收到了验证码登录后的响应并没有进行加密:
arg[1]: [response={"errorCode":-304,"success":null,"errorMsg":"OTP is incorrect or expired; try again.","httpStatusCode":200}]
OTP is incorrect or expired; try again. 这个提示就是验证码错误的响应。
继续打开开源脚本r0trace.py进行hook此应用 输入完整的验证码后,然后查看堆栈信息,发现如下重点信息:


5.png (16.02 KB, 下载次数: 0)
下载附件
2025-7-22 20:49 上传

这个方法应该就是登录后发送的请求加密函数了
打开jadx找到此函数
[Java] 纯文本查看 复制代码    public static String encryptToString(String str) {
        try {
            return getCompletePayload(str, readPublicKeyFromFile(KEY_FILE));
        } catch (IOException unused) {
            return null;
        }
    }
[Java] 纯文本查看 复制代码private static String getCompletePayload(String str, PublicKey publicKey) {
        try {
            String substring = UUID.randomUUID().toString().substring(0, 24);
            String encrypt = encrypt(substring, str);
            String encrypt2 = encrypt(substring, String.valueOf(System.currentTimeMillis()));
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(1, publicKey);
            byte[] doFinal = cipher.doFinal(substring.getBytes());
            String encodeToString = android.util.Base64.encodeToString(doFinal, 0, doFinal.length, 2);
            return "data=" + URLEncoder.encode(encrypt, CHARSET) + "&key=" + URLEncoder.encode(encodeToString, CHARSET) + "×tamp=" + URLEncoder.encode(encrypt2, CHARSET) + "&dataContentType=" + URLEncoder.encode(ContentType.JSON_PROXY_MONEY, CHARSET);
        } catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException unused) {
            return null;
        }
    }
[Java] 纯文本查看 复制代码String substring = UUID.randomUUID().toString().substring(0, 24);
这个是得到一个UUID的密钥
[Java] 纯文本查看 复制代码String encrypt = encrypt(substring, str);
这个就是加密数据的方法
[Java] 纯文本查看 复制代码Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(1, publicKey);
            byte[] doFinal = cipher.doFinal(substring.getBytes());
这里是拿到公钥给加密的密码进行再次加密,用的是RSA非对称加密。
继续分析encrypt函数代码
[Java] 纯文本查看 复制代码    private static String encrypt(String str, String str2) {
        byte[] bArr = new byte[24];
        if (str == null) {
            new SecureRandom().nextBytes(bArr);
        } else {
            System.arraycopy(str.getBytes(), 0, bArr, 0, 24);
        }
        try {
            SecretKey generateSecret = SecretKeyFactory.getInstance("DESede").generateSecret(new DESedeKeySpec(bArr));
            Cipher cipher = Cipher.getInstance(generateSecret.getAlgorithm());
            cipher.init(1, generateSecret);
            byte[] doFinal = cipher.doFinal(str2.getBytes(CHARSET));
            return android.util.Base64.encodeToString(doFinal, 0, doFinal.length, 2);
        } catch (UnsupportedEncodingException | InvalidKeyException | NoSuchAlgorithmException | InvalidKeySpecException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException unused) {
            return "";
        }
    }
str密钥 str2是密码
可以看输出数据加密使用的是3DES进行加密,也就是128位168位的二进制数据进行加密,这里使用的是24位3个字节数据来存储密码。
写一个脚本进行解密代码如下:
[Python] 纯文本查看 复制代码from Crypto.Cipher import DES3
from Crypto.Util.Padding import unpad
import base64
def decrypt_3des_ecb(encrypted_base64: str, key_str: str) -> str:
    """
    解密使用Java函数加密的3DES-ECB数据
   
    参数:
        encrypted_base64: Base64编码的加密字符串
        key_str: 密钥字符串(长度不足24字节时用0填充)
   
    返回:
        解密后的原始字符串
    """
    # 处理密钥(与Java逻辑一致)
    key_bytes = key_str.encode('utf-8')
    if len(key_bytes)
最终得到解密的原始协议数据

代码, 下载次数

Pinus   

app没加壳吗
lumeijian   

最终得到解密的原始协议数据
neversettle07   

学习一下
hHunter
OP
  


Pinus 发表于 2025-7-23 14:37
app没加壳吗

没有加壳
seagull000   

有没有ios的 急需
4everlove   

居然还是纯Java层,海外App对应用安全这方面很少
您需要登录后才可以回帖 登录 | 立即注册

返回顶部