分你所享、信息共享、轻松分享
来自民间的思想 | 送人玫瑰,手有余香。

利用虚拟机绕过安卓原生加密方案

*本文原创作者:manwu91,本文属FreeBuf原创奖励计划,未经许可禁止转载
去年破解了某安卓app的加密算法,在抓了将近一年后发现该app有强制更新,旧版协议已经无法使用。通过分析发现返回的数据仍是用aes加密的,但密钥却是通过原生代码还原的,拿不到密钥也就无法解密。对于原生代码的还原很难,而且笔者的汇编知识早就随着岁月流走了,看着这一堆汇编代码心里已是万念俱灰;但发现该app竟然支持包括x86在内的多种架构,于是想到一种方案:让虚拟机运行原生代码,并通过http接口提供调用服务。

开发

移植jni代码

首先创建一个安卓工程,在src/main下创建目录jniLibs,然后将apk lib下的so文件复制进来(保留目录结构),项目结构下图所示 cns_proj_jnilib.png 然后在项目中创建jni类,类的全限定名称与内容要跟原apk中对应的类一样,建议在jadx中直接复制过来。如下是本例中的jni类 package com.xxx.xxx.util; public class StrToLongEnUtil { public static StrToLongEnUtil a; static { System.loadLibrary("enutil-lib"); } public static void main(String [] args){ System.out.println(StrToLongEnUtil.a(args[0], Integer.parseInt(args[1]))); } private StrToLongEnUtil() { } public static long a(String str, int i) { return a().StrToLong(str, i); } public static synchronized StrToLongEnUtil a() { StrToLongEnUtil strToLongEnUtil; synchronized (StrToLongEnUtil.class) { if (a == null) { a = new StrToLongEnUtil(); } strToLongEnUtil = a; } return strToLongEnUtil; } public static long b(String str, int i) { return a().StrToLong2(str, i); } public static long c(String str, int i) { return a().StrToLong3(str, i); } // 以下是与so绑定的原生方法 public native long StrToLong(String str, int i); public native long StrToLong2(String str, int i); public native long StrToLong3(String str, int i); } 这样就可以在这个安卓项目中调用StrToLongEnUtil中的原生方法了。

暴露http服务

我们已经可以在项目中运行原生代码了,但还需要将调用包装成服务供爬虫代码使用,于是google到了一个可以运行在安卓端的web服务器AndServer。它的使用非常简单,通过builder绑定网卡与端口,并注册访问路径与处理器就可以了,例如注册/jni路径提供解密服务: server = AndServer.serverBuilder() .inetAddress(addr) .port(Integer.parseInt(port)) .registerHandler("/", new HelloHandler()) .registerHandler("/jni", new AppJniHandler()) .build(); server.startup();