欢迎光临
我们一直在努力

HUApp逆向 RSA加密 脱壳 登录 Android调试

HUApp逆向分析技术文章大纲

技术背景与目标

基于Android Studio对HUAPP进行断点调试,解码分析登录接口。对apk进行修改调试

抓包分析

打开目标app点击会员登录,随便输入账号密码触发请求。里面路径是/v2/login.参数由公共参数和data的加密参数组成。公共参数里面处理riskToken是接口返回。blackbox是设备采集。别的字段可以模拟。blackbox可以看往期文章获取这次对data里面的进行解码分析。里面number是账号。pin是密码。tosave是默认true

脱壳技术实践
1.利用adb拉取手机上的apk

查看apk路径

adb shell pm path com.rytong.hnair

拉取apk

adb pull /data/app/com.rytong.hnair-1/base.apk C:\\Users\\Administrator\\Desktop\\

2.修改apk

利用Apktool Box对拉取的apk进行查壳

反编译apk后修改AndroidManifest.xml。对application节点加上android:debuggable="true"

然后点击回编apk,回编之后点击zipalign进行apk对齐。最后进行签名

3.安装修改后的apk

卸载旧版并安装修改后的apk

adb uninstall com.rytong.hnair
adb install "C:\\Users\\Administrator\\Desktop\\hnair_current.apk"

登录流程调试
1.静态分析

全局搜索/v2/login,找到接口声明位置。往上稍微翻一下。找到方法的声明

找到声明方法是loginV2

搜一下里面的参数UserLoginRequest。里面是数据类型,对应data里面的参数

2.动态调试

全局搜索loginV2并打上断点进行触发

进入loginV2跟栈,找到serialize

进入serialize方法,可以看到加密声明

继续进入方法,可以看到密码现在明文被传入HttpRequestRsaFieldEncrypt方法进行处理

继续跟栈找到base64处理那里,已经生成值了。

往上一步,这里进行了加密。看断点内容。里面是rsa加密。往上翻一番可以找到公钥

invoke-virtual {v2, p1}, Ljavax/crypto/Cipher;->doFinal([B)[B

RSA公钥

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCziHP+DnK5og1PAxmgKbrN/dChW6Pq1/8TxKKnc2e2qifoMZbsYy+/I2o6HnzGm3QNxA6ernkU9DptfQ9j+mIv6nmEmMXu0qusTs8hKVzOaX9z7BgwlpvgoN6ZN++lWc2DQVhJs8fafcG0hJuQmsbaKH3mvEQBqJnE0vQHAuBe8wIDAQAB

AES加密

继续跟栈。密码加密后会重新组装。进入外层加密。

继续跟栈。跟到这个方法进去

Lcom/hnair/airlines/base/utils/AES256Encryption

进去方法会发现确实是AES

在return打上断点,此时已经加密结束

往上翻占堆,会发现aes的key

iv生成:继续跟栈。iv是在这个方法生成。将comm的公共数据里面的akey进行截取前16位

invoke-static {p1, v0}, Lkotlin/text/StringsKt;->a1(Ljava/lang/String;I)Ljava/lang/String;

在这个方法拼接上时间戳

sget-object v0, Lkotlin/text/Charsets;->b:Ljava/nio/charset/Charset;

跳出外层AES加密。这里对数据进行“hna”处理。对number和sens进行处理

apk内部防护

正常修改apk后可以自主调试。HUAPP有反调试。回编后的apk调试的时候会触发自我检测。跳出检测到测试连接字段然后退出。是因为apk运行的时候会启动这个函数检测。有反调试

invoke-static {}, Landroid/os/Debug;->isDebuggerConnected()Z

解决办法:hook注入js来跳过检测

// anti.js – 绕过常见的 Java 层反调试检测
Java.perform(function() {
console.log("[+] 反调试脚本已注入…");

// 1. 绕过 isDebuggerConnected() 检测
try {
var Debug = Java.use("android.os.Debug");
Debug.isDebuggerConnected.implementation = function() {
return false;
};
console.log("[+] Hook isDebuggerConnected 成功");
} catch(e) {}

// 2. 绕过 /proc/self/status 中的 TracerPid 检测
try {
var FileInputStream = Java.use("java.io.FileInputStream");
FileInputStream.$init.overload('java.io.File').implementation = function(file) {
var path = file.getAbsolutePath();
if (path.indexOf("/proc/") !== -1 && path.indexOf("/status") !== -1) {
console.log("[+] 检测到读取 status 文件: " + path);
// 注意:真正的完整绕过需要重写 read 方法,此处为简化版,主要针对常见检测
}
return this.$init(file);
};
} catch(e) {}

console.log("[+] 脚本加载完成,等待操作…");
});

python实现
RSA加密源码

PUBLIC_KEY_BASE64 = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCziHP+DnK5og1PAxmgKbrN/dChW6Pq1/8TxKKnc2e2qifoMZbsYy+/I2o6HnzGm3QNxA6ernkU9DptfQ9j+mIv6nmEmMXu0qusTs8hKVzOaX9z7BgwlpvgoN6ZN++lWc2DQVhJs8fafcG0hJuQmsbaKH3mvEQBqJnE0vQHAuBe8wIDAQAB"

def rsa_encrypt(password: str) -> str:
der_data = base64.b64decode(PUBLIC_KEY_BASE64)
public_key = serialization.load_der_public_key(der_data, backend=default_backend())
ciphertext = public_key.encrypt(
password.encode('utf-8'),
padding.PKCS1v15()
)
return base64.b64encode(ciphertext).decode('utf-8')

AES加密源码

def aes_encrypt(plaintext: str, stime: str, akey: str, add_prefix: bool = True) -> str:
"""
plaintext: 待加密明文
stime/akey: 请求 common 中的字段
add_prefix: 是否添加 APK 使用的 %hna% 前缀
"""
iv_text = (stime + akey)[:16]
iv = iv_text.encode("utf-8")

if len(iv) != 16:
raise ValueError("stime + akey 截取后必须正好生成 16 字节 IV")

cipher = AES.new(KEY, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(pad(plaintext.encode("utf-8"), AES.block_size))
result = base64.b64encode(encrypted).decode("ascii")

return "%hna%" + result if add_prefix else result

安全防护绕过

分析HUApp的反调试机制(如ptrace检测、签名校验等)
使用Frida脚本绕过常见防护措施
修改Smali代码或重打包App,绕过关键校验逻辑

成功验证

法律与伦理边界

  • 逆向技术的合法使用范围
  • 企业防护与用户隐私的平衡
  • 个人观点,禁止商业行为,侵权请联系下架

 

赞(0)
未经允许不得转载:171主机测评 » HUApp逆向 RSA加密 脱壳 登录 Android调试
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址