吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 21959|回复: 349
收起左侧

[Android 原创] 某视频app的逆向初体验

    [复制链接]
zglbinary 发表于 2022-7-26 11:09

一、前言

最近发现一款视频神器,界面精良,海量资源,高清免费,播放速度快,某二级页面如下:

1.png

唯一不足的是播放前需要先观看广告,毕竟开发不易,但是我们可以尝试着破解一下,方便自己的同时熟悉下逆向方面的知识。

二、破解条件

将apk在jadx中打开发现没有进行加固,可以用本文的方式进行破解:

2.png

对比360加固过的apk内容如下:

3.png

三、工欲善其事必先利其器(工具介绍)

1.Apktool 目前使用版本2.6.1,用于apk的解包与重新打包;

2.jadx 使用版本为 jadx-gui-1.1.0-with-jre-windows,只做代码查看有类似工具也可以替代。

3.IDA Pro 7.6.210427 网上搜索的汉化破解版,支持64位so处理,最初使用的版本不支持64位so的F5按键操作,造成了很大的困扰。 用于so文件的分析与修改。

周树人:没有困难,制造困难也要上

4.python 3.7 + PyCharm 此用作对解包后因资源混淆产生的资源名称问题处理,个人感觉python简单一些。也可以用java做类似处理。

5.你看上的APK 这边用的是:
https://pan.baidu.com/s/163Sa_-ZFOtFhDw5WXJIbRw?pwd=m9ue
提取码:m9ue

四、天才第一步,解包与重新打包

下面一步步来进行我们的破解之旅,其中遇到的问题,以及解决尝试也一并介绍。

  1. 将apk放在apktool的存放目录:

4.png

  1. 命令行切换到对应目录,进行解包:

apktool d hlg.apk -o hlg_floader

hlg.apk为源文件,hlg_floader为解包后文件,如下为解包成功:

5.png

3.回编
apktool b -o hlg_new.apk D:\hlg\hlg_floader --use-aapt2

此处可能有两个问题,一个是直接用hlg_floader提示找不到文件,使用全路径名可以解决;另一个是在一些命令行工具下提示apktool找不到,可使用java -jar apktool.jar XXXX 解决

6.png

很不幸报错了,hlg_floader\res\animator\a.xml:4: error: attribute state_liftable (aka com.hlgys.hlg:state_liftable) not found.提示com.hlgys.hlg下的state_liftable属性找不到。将apk拖入jadx,Ctrl + Shift + F 全局搜索state_liftable

7.png

发现没有在com.hlgys.hlg包名下的属性,ok那确实没找到。

全局搜索state_liftable的属性值2130969527:

8.png

发现com.hlgys.hlg.R下的z1state_liftable的值是一样的,说明hlg_floader\res\animator\a.xml下用z1替代state_liftable就可以了,z1是混淆过的,而state_liftable是非混淆的,state_liftable没有就用z1,那我思路就清晰了:

  1. com.hlgys.hlg.R 下的属性和值以键值对形式存储,以属性值作为key;如<2130969527, z1>,得到一个集合
  2. com.junyue.resource(只要是非混淆的目录就行不一定非要用这个)目录下的resource文件中属性进行遍历,获取到键值对<state_liftable, 2130969527>,跟上一步做映射,得到最终键值对<state_liftable, z1>,得到最终集合
  3. 对hlg_floader下的res目录进行替换,如app:state_liftable="true"转换为app:z1="true"

这个过程我这边用python实现的,ApktoolHelper.py代码如下:

import re
import os
import shutil

def getFileReplacedMap(finalMap, filePath, replaceMap):
    file = open(filePath, "r")
    for line in file:
        nameBase = re.findall(r'int (.*?) =', line)
        idBase = re.findall(r'= (.*?);', line)
        if len(nameBase) != 0:
            name = nameBase[0].strip()
            id = idBase[0].strip()
            finalId = replaceMap.get(id)
            if not finalId is None:
                print("map change ==========",name," ",id," ",finalId)
                finalMap[name] = finalId

def replaceAttr(filePath, finalMap):
    if path.endswith("xml"):
        print(path)
        file = open(filePath, "r", encoding="utf-8")
        newFile = open("%s.bak" % filePath, "w", encoding="utf-8")
        for line in file:
            nameBase = re.findall(r'app:(.*?)="', line)
            mvBase = re.findall(r'mv:(.*?)="', line)
            if len(nameBase) != 0:
                for str in nameBase:
                    print(str,"-----------------")
                    if str in finalMap:
                        print("-----------------", str, "-----------------")
                        line = line.replace(str+"=", finalMap.get(str)+"=")
            if len(mvBase) != 0:
                for str in mvBase:
                    print(str,"-----------------")
                    if str in finalMap:
                        print("-----------------", str, "-----------------")
                        line = line.replace(str+"=", finalMap.get(str)+"=")

            newFile.write(line)
        file.close()
        newFile.close()
        os.remove(filePath)
        os.rename("%s.bak" % filePath, filePath)

def copydirs(from_file, to_file):
    if not os.path.exists(to_file):  # 如不存在目标目录则创建
        os.makedirs(to_file)
    files = os.listdir(from_file)  # 获取文件夹中文件和目录列表
    for f in files:
        if os.path.isdir(from_file + '/' + f):  # 判断是否是文件夹
            copydirs(from_file + '/' + f, to_file + '/' + f)  # 递归调用本函数
        else:
            shutil.copy(from_file + '/' + f, to_file + '/' + f)  # 拷贝文件

file = open("R.java", "r")
replaceMap = {}
for line in file:
    nameBase = re.findall(r'int (.*?) =', line)
    idBase = re.findall(r'= (.*?);', line)
    if len(nameBase) != 0:
        name = nameBase[0].strip()
        id = idBase[0].strip()
        print("map ==========",id," ",name)
        replaceMap[id] = name

finalMap = {}
resource = "resource"
for dirpath, dirnames, filenames in os.walk(resource):
    for filepath in filenames:
        path = os.path.join(dirpath, filepath)
        print(path)
        getFileReplacedMap(finalMap, path, replaceMap)

oldFile = "oldFile"
newFile = "newFile"
copydirs(oldFile, newFile)

for dirpath, dirnames, filenames in os.walk(newFile):
    for filepath in filenames:
        path = os.path.join(dirpath, filepath)
        replaceAttr(path, finalMap)

目录结构如下:

9.png

其中R.java为com.hlgys.hlg.R.java,可以从jadx中复制出来;

resource为com.junyue.resource下的文件,如下

10.png

如果此目录下属性的不能完全覆盖R.java下的属性,就全局搜索下所缺失的,一并将目录放在resource目录下,如图中video文件夹中放的就是com.junyue.video路径下的res文件。

然后将hlg_floader\res放在oldFile下,执行ApktoolHelper.py进行替换,得到新的res文件夹。随便打开一个回编报错的文件查看,如hlg_floader\res\animator\a.xml:4: error: attribute state_liftable,可以看到属性已经被替换了。

11.png

将res替换为新的之后,重新回编:

12.png

成功!

4.签名

创建自己的签名文件 keytool -genkey -v -keystore mykey.keystore -alias mykeyaliasname -keyalg RSA -keysize 2048 -validity 10000
根据提示操作完成后,可能会提示转换,
keytool -importkeystore -srckeystore mykey.keystore -destkeystore mykey.keystore -deststoretype pkcs12根据提示信息里的命令进一步转换,如下:

13.png

对apk进行签名,此处禁用了v2 v3签名:
apksigner sign --ks mykey.keystore --ks-key-alias mykeyaliasname --v2-signing-enabled false --v3-signing-enabled false hlg_new.apk

非必要:验证签名apksigner verify -v --print-certs hlg_new.apk

字节对齐优化zipalign -v 4 hlg_new.apk final.apk

非必要:检查对齐zipalign -c -v 4 final.apk

最终得到了final.apk, 安装到手机上打开,发现应用闪退了...

五、第二步,处理so崩溃

应用崩溃信息如下:

14.png

  1. native崩溃分析:

查看so列表:

15.png
对比报错信息

#05 pc 000000000003ebe8  /data/app/com.hlgys.hlg-vsaiqBt38w592bqtvc4Azg==/lib/arm64/libfcore.so (BuildId: 724cd6be15957976c57ae0c1f613b73b400cfefb)

发现libfcore.so中的000000000003ebe8发生了崩溃。

2.IDA问题定位:

安装完IDA后,将arm64-v8a下的libfcore.so用ida64打开,注意位数一定要对应。

此时进入主页面如图:

16.png

在IDA View页面下按 空格键,然后进行文字搜索"Alt+T", 搜索到一条内容:

17.png
双击跳转到对应的IDA View视图中的代码位置:

18.png

按F5转换为c代码:

19.png

strcmp 函数用于比较两个字符串是否相等,如果相等则返回0。否则就进入sub_402BC函数。

这个地方是strcmp函数内部崩了,说明跟传入的参数有关,此处的两个参数v41和v27只做了判断,后续并未使用,所以这个位置只要不崩就行,随便传两个字符串进去即可。考虑找一个现有的字符串,两个参数都传同一个字符串,这就保证不会为空并且值相等,具体传哪个字符串呢,我们在代码里搜寻一下。

先看下java层调用so的代码:
搜索下"fcore", 找到:

20.png
其中用init方法,我们到so中去看下,在左侧列表中"Ctrl + F"搜索init

21.png

未找到,说明是在onLoad中动态注册的方法,在IDA View页面下按 "ctrl + s",双击.data.rel.ro,可以看到init方法:
22.png

23.png
箭头所指的sub_3DC44为真正方法,点击后按F5查看代码:

24.png

看到有字符串ca14b343b9b43dd1382d4ec17b39a28d,全局搜索下此子串看到:

25.png

我们就使用 aCa14b343b9b43d吧。

  1. 进行修改:
    在IDA View视图中对strcmp点一下空格,会进入Graph view,如下:

26.png

查看上一步ADRL            X0, aCa14b343b9b43d ;的64位视图,将光标移动到这一行上,然后 视图-打开子视图-十六进制转储 ,打开了十六进制视图,

27.png

这一条指令为 20 00 00 B0 00 E8 38 91

在查看ADD             X0, X19, #0xC4 ; s1 STRB            WZR, [X19,#0xE4]两条指令的十六进制,两条指令刚好与ADRL            X0, aCa14b343b9b43d ;长度一致,进行替换。

28.png

在60 12 03 91上右键-编辑 修改完后,右键应用更改:

29.png
查看IDA中视图:

30.png
两条指令已经被替换为一条,但是后面值为unk_43E3A有误,右键-手动输入,将unk_43E3A更改为aCa14b343b9b43d。strcmp中第一个参数修改完成。

修改MOV 指令,将X20赋值到x1,修改为MOV             X1, X0,x0对应的十六进制为00,打开十六进制视图后,将E1 03 14 AA 修改为E1 03 00 AA。结果如下:
31.png

这样两个值就都为字符串ca14b343b9b43dd1382d4ec17b39a28d了,F5查看代码:

32.png

4.保存so

33.png
点击确认,这样就得到了新的so。

将so替换调原来so,重新进行打包、签名、对齐、安装。

应用能打开了,这时候我们尝试播放视频,在吃了一个广告之后,发现:

34.png

六、第三步,跳过签名校验

上一步中ca14b343b9b43dd1382d4ec17b39a28d这个字符串就是签名相关的内容,找到init所对应的方法sub_3DC44:

35.png

发现有两个校验,一个是长度校验,一个是值的校验,查看Graph视图:

36.png

cbz指令 比较,为零则跳转;

cbnz: 指令 比较,为非零则跳转。

所以此处只需要将cbz更换为cbnz就做了取反操作。
打开在线工具https://armconverter.com/
CBZ             X0, loc_3DC9C对应的16进制E0 00 00 B4 转换为ARM指令

37.png

切换一下arm转hex,并将 cbz x0, #0x1c 修改为 cbnz x0, #0x1c, 再转换为hex,得到E0 00 00 B5, 修改IDA中对应的hex数值,得到:

38.png

以同样的方式修改另一条CBZ指令, 保存so。重新编译apk,运行。发现视频可以正常播放。但是一进应用就吃了一个广告有点难受。

七、第四步,广告去除

  1. 安装完应用,第二次进入应用,开屏页结束后发现必吃一个广告,我们查看下开屏页Activity

    adb shell dumpsys activity activities | findstr "mResumedActivity"
    为SplashActivity,
    查看onCreate方法,发现如果同意过协议就走T2()方法,

39.png

f中进行了广告请求:

40.png

直接把方法改为

public final void T2() {
    R2();
}

在hlg_floader\smali_classes3\com\junyue\video下找到SplashActivity.smali文件:

对T2方法进行修改,删除多余逻辑

# virtual methods
.method public final T2()V
    .locals 5

    :cond_1
    invoke-direct {p0}, Lcom/junyue/video/SplashActivity;->R2()V

    :goto_1
    return-void
.end method

将修改后的smail拖入jadx检查下:

public final void T2() {
        R2();
    }

无误。

2.处理播放视频前的广告:
全局搜索下免广告,找到

public final void a3() {
    String str;
    long decodeLong = MMKV.defaultMMKV().decodeLong("free_ad_second_timestamp");
    if (decodeLong == -1) {
        S2().setVisibility(0);
        str = "免广告至:永久";
    } else if (decodeLong < x0.b()) {
        S2().setVisibility(8);
        str = null;
    } else {
        S2().setVisibility(0);
        str = j.l("免广告至:", s.b(decodeLong * ((long) 1000), "yyyy-MM-dd HH:mm:ss"));
    }
    S2().setText(str);
}

free_ad_second_timestamp sp中存储的就是免广告相关的值,全局搜索下free_ad_second_timestamp,找到取值的地方:

public static boolean N() {
    long decodeLong = MMKV.defaultMMKV().decodeLong("free_ad_second_timestamp");
    if (decodeLong != -1 && decodeLong - x0.b() <= 0) {
        return false;
    }
    return true;
}

猜测此方法为免广告的判断条件,如果值是-1就是永久免广告,所以此方法只要恒返回true就可以了,同样修改smail文件:

.method public static N()Z
.registers 1

    .prologue
    .line 14
    const/4 v0, 0x1

    return v0

.end method

java代码变为

public static boolean N() {
        return true;
    }

保存后重新打包运行,发现广告都已经去除。至此你就得到了一个可以让女朋友沉浸其中追剧的神器,再也没有人来打扰你看直播打游戏了。

file.rar

1.43 MB, 下载次数: 962, 下载积分: 吾爱币 -1 CB

res(删除了部分体积较大图片资源),R文件,64位so

免费评分

参与人数 94吾爱币 +83 热心值 +75 收起 理由
junjia215 + 1 + 1 用心讨论,共获提升!
Wxyyy + 1 + 1 我很赞同!
MODENGXIAN1A + 1 + 1 用心讨论,共获提升!
cherrylong + 1 + 1 热心回复!
joyzz + 1 + 1 我很赞同!
Xncker + 1 + 1 我很赞同!
beyond85 + 1 + 1 我很赞同!
weiye588 + 1 + 1 我很赞同!
shannima + 1 + 1 谢谢@Thanks!
步杪 + 1 我很赞同!
Janision + 1 + 1 谢谢@Thanks!
haooyuan + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
nswzad + 1 + 1 要学的东西太多了
Re52 + 1 谢谢@Thanks!
haopeiyou + 1 用心讨论,共获提升!
ddddhm + 1 + 1 我很赞同!
c259179 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
SUN521Chen + 1 + 1 热心回复!
being1 + 1 + 1 谢谢@Thanks!
Ucool + 1 用心讨论,共获提升!
acntbbs + 1 精华是有道理的
chenjiew + 1 + 1 我很赞同!
学习使我快乐1 + 1 + 1 我很赞同!
孟大叔 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
9911911 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
ManaCola + 1 + 1 用心讨论,共获提升!
LeisurelyCloud + 1 谢谢@Thanks!
ziseshidai + 1 + 1 鼓励转贴优秀软件安全工具和文档!
墨荷碧露 + 1 + 1 谢谢@Thanks!
hjthack + 1 + 1 热心回复!
luckytiger996 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
回归本心 + 1 + 1 我很赞同!
yelig + 1 + 1 谢谢@Thanks!
qc123 + 1 + 1 我很赞同!
jxbb077026 + 1 我很赞同!
IGW + 1 用心讨论,共获提升!
紫轩冰凌 + 2 + 1 谢谢@Thanks!
Null666yyds + 1 + 1 谢谢@Thanks!
GuiXiaoQi + 1 我很赞同!
bsdn321321 + 1 谢谢@Thanks!
半边天 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
gomg007 + 1 + 1 很详细,看得津津有味!欢迎分析讨论交流,吾爱破解论坛有你更精彩!
ABC0123 + 1 + 1 厉害
wasd3152 + 1 + 1 谢谢@Thanks!
江月年年望相似 + 1 谢谢@Thanks!
HaibaraAi818 + 1 + 1 用心讨论,共获提升!
987654321012345 + 1 + 1 我很赞同!
superman88 + 1 + 1 我看不懂,但我极为震撼!
lyslxx + 1 + 1 我很赞同!
zouya1990 + 1 + 1 我估计干到中间就放弃了
Filiation + 1 + 1 用心讨论,共获提升!
nirunyu + 1 + 1 谢谢@Thanks!
jolin7714 + 1 + 1 用心讨论,共获提升!
43cs + 1 我很赞同!
红海豚 + 1 用心讨论,共获提升!
vicky526356 + 1 膜拜大佬,收下我的膝盖
zjk2070 + 1 + 1 我很赞同!
linfengtai2008 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
jyz0506 + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!
djsz + 1 用心讨论,共获提升!
dummersoul + 1 + 1 谢谢@Thanks!
Zbq + 1 我很赞同!
Zzsleep + 1 + 1 牛逼牛逼,好细致,膜拜大佬
linwuhu + 1 + 1 谢谢@Thanks!
yeeb + 1 + 1 用心讨论,共获提升!
oostudy + 1 热心回复!
Caicai123456 + 1 谢谢@Thanks!
g167349852l + 1 + 1 用心讨论,共获提升!
yuxuechao + 1 我很赞同!
xu167 + 1 + 1 我很赞同!
#sky# + 1 + 1 热心回复!
libailin + 1 我很赞同!
RayC02 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
gaosld + 1 + 1 谢谢@Thanks!
JanusGreenB + 1 + 1 谢谢@Thanks!
zwding + 1 + 1 谢谢@Thanks!
XXFFKK + 1 热心回复!
ljj35266 + 1 谢谢@Thanks!
Bob5230 + 1 我很赞同!
htwl1023 + 1 + 1 我很赞同!
Bbcoq + 1 + 1 谢谢@Thanks!
李佑辰 + 1 用心讨论,共获提升!
zhengkai0319 + 1 + 1 我很赞同!
see1 + 1 谢谢@Thanks!
miadaydream + 1 用心讨论,共获提升!
lAQUQ + 1 用心讨论,共获提升!
lysuro + 1 + 1 我很赞同!
WuJ1n9 + 1 我很赞同!
jellybz + 1 + 1 用心讨论,共获提升!
starryskyyy + 1 + 1 谢谢@Thanks!
没事路过 + 1 + 1 谢谢@Thanks!
Dumas + 1 我很赞同!
Bizhi-1024 + 1 用心讨论,共获提升!
恶搞大王 + 2 + 1 我很赞同!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| zglbinary 发表于 2022-7-26 22:46
xihuxiaren666 发表于 2022-7-26 21:29
你是真牛,IDA很熟练哈

IDA跟着首页的《教我兄弟学Android逆向系列课程》大佬教程学的,真的是赞
xzg919 发表于 2022-7-27 14:49
sunnyAlvis 发表于 2022-7-26 13:09
mayi2077 发表于 2022-7-26 12:58
欢迎分析讨论交流,吾爱破解论坛有你更精彩!
jellybz 发表于 2022-7-26 13:03
大佬,有的图片没弄上来
芽衣 发表于 2022-7-26 12:20
图片怎么看不见
quanjujsq 发表于 2022-7-26 12:18
对阿  有些app 图片不能保存呢
ZhuanZhuYuIT 发表于 2022-7-26 13:13
膜拜大佬
ts219 发表于 2022-7-26 13:19
大佬666,存一哈,留着有时间搞
 楼主| zglbinary 发表于 2022-7-26 13:48
本帖最后由 zglbinary 于 2022-7-26 14:01 编辑
jellybz 发表于 2022-7-26 13:03
大佬,有的图片没弄上来

更新了一下

点评

建议图片上传论坛本地,防止图床丢失。  详情 回复 发表于 2022-7-26 14:57
mytf 发表于 2022-7-26 13:55
大佬太强了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-4 02:59

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表