【Android逆向】某python环境app回编译后的This copy of software is corrupted and is not safe to use问题分析

本文主要是介绍【Android逆向】某python环境app回编译后的This copy of software is corrupted and is not safe to use问题分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言

一、分析思路

1、谁在做校验

2、用来校验的是什么

3、发送错误信息的方式

4、修改思路

二、修改后的效果

1.pip已经能正常使用

2.个别库安装还是有些问题,个别sample脚本运行还有问题

总结



前言

前一篇博文【五一创作】【Android逆向】某python环境app的PREMIUM内容展示分析_疑燃的博客-CSDN博客讲到,界面按钮虽然修改成功了,但实际上是运行不起来的,apk做了包校验,库不能安装成功,提示This copy of software is corrupted and is not safe to use.
To fix this error, uninstall your copy and do a clean install of this app from an official source (e.g. Google Play)

最近花了一些时间分析和验证这件事,主要是寻找这个是被谁校验了,校验的什么,怎样发出的这种错误信息,以及怎样解决。


一、分析思路

1、谁在做校验

在logcat日志里搜一下这个报错信息,发现日志除了打印这个信息,前面还有pip:out:的关键字:

 在反编译的代码里面找一下这个关键字,找到对应代码位置:

 继续分析代码,发现python脚本是通过java的Runtime.getRuntime().exec来调用的:

 所以构造日志,把拼接的命令打印出来,方法是去修改smali,这个在上一篇博文提到过,这里就不再多说了:

public void m51b(String str) {ProgressBar progressBar = new ProgressBar(m14462f(), null, 16842874);progressBar.setTag("progress_bar_tag");this.f14851Z.addView(progressBar);this.f14856e0 = new StringBuilder();PowerManager.WakeLock newWakeLock = ((PowerManager) m14462f().getSystemService("power")).newWakeLock(536870918, "pip:wakelock");newWakeLock.acquire();this.f14862k0 = true;this.f14851Z.setOnTouchListener(new View.OnTouchListener() { // from class: .pipactivity.f@Override // android.view.View.OnTouchListenerpublic final boolean onTouch(View view, MotionEvent motionEvent) {return C4866r.this.m59a(view, motionEvent);}});this.f14852a0.post(new RunnableC4868b());try {Process exec = Runtime.getRuntime().exec(C4821a.m165f((Activity) m14462f()) + " sh ", (String[]) null, new File(C4821a.m149o(m14462f())));try {BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(exec.getOutputStream()));String str2 = C4821a.m152l(m14462f()) + " ; /data/user/0/XXXX/files/busybox sh /storage/emulated/0/pd_before_act/pd_before_act.sh && /data/user/0/XXXX/files/aarch64-linux-android/bin/python " + str + " ; exit\n";Log.d("===", str2);bufferedWriter.write(str2);bufferedWriter.flush();Log.d("execBench", "writed");} catch (Exception e) {this.f14857f0 = false;e.printStackTrace();}Handler handler = new Handler();new Thread(new RunnableC4869c(exec)).start();new Thread(new RunnableC4870d(exec, handler, newWakeLock)).start();new Thread(new RunnableC4872e(exec)).start();} catch (Exception e2) {e2.printStackTrace();}}

这里需要说明的是:

a.日志以===开头,是便于查找,大家也可以根据自己的喜好,使用其他的关键字;

b.修改命令拼接串,加入的 /data/user/0/XXXX/files/busybox sh /storage/emulated/0/pd_before_act/pd_before_act.sh 是为了方便调试,添加的一个外接脚本,好处是可以不重新回编译,就可以通过在脚本里面加shell命令,来达到调试的目的,只要功能一运行到这里,就会执行脚本里面的语句。

c.busybox和python路径是怎么找到的:也是通过日志插桩确定的,但如果使用的是模拟器,而且root了,就方便多了,可以看得到文件路径。

 加日志是一个好方法,工作量小,比动态调试的动静小多了,这个的效果如下,拼接的命令打印出来就很清楚了:

 

在调试中发现,其他的shell命令都能正常执行,但只要一碰到运行python,就会报错,那问题应该就出在这里,apk的作者应该是对python做了一些修改。但是改的哪里,是python主文件还是so文件,需要确定。apk自带的python3.8,依赖libpython3.8.so.1.0这个库文件,为了确定是哪个被修改了,我另外找了一个python3.8,把LD_LIBRARY_PATH改成apk的python的lib路径,运行就会报错,这就确定了是libpython3.8.so.1.0被改了。

 走到这一步,就基本已经确定了方向,为此耗费了大量的时间。

2、用来校验的是什么

这个需要从分析libpython3.8.so.1.0这个so文件入手,但这个使用IDA反编译出来,搜索不到报错信息,需要用动态调试来做了,但是这个是python的so,并不是apk的so,apk的动态调试方法可能并不适用,而且汇编,哎。。。太过枯燥,就放弃了。大家如果有兴趣,可以自行研究一下。

回到问题本身,如果没办法从代码找到证据确定校验内容,也可以猜测一下。一般这种校验会校验些什么。我能想到的最明显的一个就是签名和原来的包不一致,可能会用来做校验;另外,反编译出来之后,会和原来包里的同一文件出现不一致的情况,暂时还想不到。

3、发送错误信息的方式

确定了修改点之后,发送方式基本也就确定了,那就是so文件回复的内容。

4、修改思路

如果对so文件反编译,而且有兴趣去研究汇编和动态调试,那可以尝试修改so文件,这样的副作用是最小的,至少包的依赖不会出现问题;

另一种方法,把libpython3.8.so.1.0替换掉,可以另外找一个,甚至可以自己编译一个,但是因为不能确定apk中的so的编译参数,所以用别的so文件来替换,可能会出现一些未知的问题。我暂时先用这种方法,替换了libpython3.8.so.1.0和_posixsubprocess.cpython-38.so。对这件事,做到这一步,就可以告一段落了,再去编译一个python,再去调apk本身的功能,这明显已经超纲了,之后有时间再尝试吧。

二、修改后的效果

1.pip已经能正常使用

2.个别库安装还是有些问题,个别sample脚本运行还有问题

这些问题就没有一个一个的去试了,按照具体错误提示,分析修改就行了。


总结

花了很多时间,终于把报错的原因分析出来了,作者的校验思路和校验点真是出乎意料。虽然距离真正解决这个错误,还有一小段路要走,但对于apk的逆向来说,该做的都已经做了。在这个过程中,通过填坑,也积累了不少经验教训,这个apk在包校验上也算得上一个逆向分析教科书式的存在了。

修改后的apk暂时还没有打包上传,这个事情近期应该会完成,如果有需要,可以联系我获取。

这篇关于【Android逆向】某python环境app回编译后的This copy of software is corrupted and is not safe to use问题分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/221099

相关文章

SpringSecurity整合redission序列化问题小结(最新整理)

《SpringSecurity整合redission序列化问题小结(最新整理)》文章详解SpringSecurity整合Redisson时的序列化问题,指出需排除官方Jackson依赖,通过自定义反序... 目录1. 前言2. Redission配置2.1 RedissonProperties2.2 Red

nginx 负载均衡配置及如何解决重复登录问题

《nginx负载均衡配置及如何解决重复登录问题》文章详解Nginx源码安装与Docker部署,介绍四层/七层代理区别及负载均衡策略,通过ip_hash解决重复登录问题,对nginx负载均衡配置及如何... 目录一:源码安装:1.配置编译参数2.编译3.编译安装 二,四层代理和七层代理区别1.二者混合使用举例

Java JDK1.8 安装和环境配置教程详解

《JavaJDK1.8安装和环境配置教程详解》文章简要介绍了JDK1.8的安装流程,包括官网下载对应系统版本、安装时选择非系统盘路径、配置JAVA_HOME、CLASSPATH和Path环境变量,... 目录1.下载JDK2.安装JDK3.配置环境变量4.检验JDK官网下载地址:Java Downloads

使用Python删除Excel中的行列和单元格示例详解

《使用Python删除Excel中的行列和单元格示例详解》在处理Excel数据时,删除不需要的行、列或单元格是一项常见且必要的操作,本文将使用Python脚本实现对Excel表格的高效自动化处理,感兴... 目录开发环境准备使用 python 删除 Excphpel 表格中的行删除特定行删除空白行删除含指定

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

Python办公自动化实战之打造智能邮件发送工具

《Python办公自动化实战之打造智能邮件发送工具》在数字化办公场景中,邮件自动化是提升工作效率的关键技能,本文将演示如何使用Python的smtplib和email库构建一个支持图文混排,多附件,多... 目录前言一、基础配置:搭建邮件发送框架1.1 邮箱服务准备1.2 核心库导入1.3 基础发送函数二、

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class