Android逆向实战(一)腾讯新闻去开屏广告

news/2024/12/12 5:52:07/

    上次反编译一个工具类app失败,原因是使用了360加固,回编译后无法启动。一般来讲,大厂的app考虑到性能、兼容性、包体积等,通常不用加固。因此,本次我们选一个大一些的app-腾讯新闻。写在前面:本篇博客仅用来研究和学习,如有侵权,请联系我删除,谢谢。

目录

一、前言

二、验证加固

1、反编译验证

2、ApkScan验证

三、反编译

1、使用apktool反编译

2、修改smali代码

3、回编译和签名

4、再次修改smali代码

5、再次花式修改源码


一、前言

    现在的app,不管是大厂的,还是一些名不见经传的小众app,都植入了非常多的广告。其中,最让人讨厌的应该就是开屏广告了,特别是那种一晃动就跳走的摇一摇广告。

    本篇,我们就通过腾讯新闻app手把手的教学,反编译去掉开屏广告。顺便一提:腾讯新闻的开屏广告真的是每次启动都必出:

2568775723c54364a2fab181158e603c.gif

二、验证加固

    首先,我们验证下腾讯新闻app是否加固,防止因为加固导致失败。验证加固有两种方式。

一种是反编译后不做任何修改直接回编译签名看是否可以安装和启动

一种是使用ApkScan验证

1、反编译验证

(1)反编译

apktool d /Users/xxx/Desktop/TencentNews_10565.apk  -o /Users/xxx/Desktop/TencentNews

(2)不做任何修改,直接回编译

apktool b /Users/xxx/Desktop/TencentNews

 (3)签名

java -jar apksigner.jar sign --ks /Users/xxx/Desktop/test.keystore  /Users/xxx/Desktop/TencentNews/dist/TencentNews_10565.apk

(4)安装

adb install -r /Users/xxx/Desktop/TencentNews/dist/TencentNews_10565.apk

安装后,启动腾讯新闻app,确认可以打开使用,验证结论:腾讯新闻app没有加固。 

2、ApkScan验证

执行以下命令:

java -jar /Users/xxx/Desktop/反编/ApkScan-PKID.jar

打开窗口后把apk拖进去:

b81570b5c6504a15a85f2489ccbc70b6.png

验证结论:腾讯新闻app没有加固。

三、反编译

1、使用apktool反编译

    如果验证加固使用的方法一,那么直接把反编译文件夹中的dist文件夹删掉,使用反编译的产物就可以了。如果验证加固使用的方法二,可以重新执行下反编译。

apktool d /Users/xxx/Desktop/TencentNews_10565.apk -o /Users/xxx/Desktop/TencentNews

    我们打开res/layout文件夹,这里面有很多的xml文件,这里面包含的就是应用用到的系统控件和自身页面的xml布局文件,可以看到很多包含ad的xml文件,腾讯新闻里面确实很多广告,我们还是挑选开屏广告来看吧。一般来讲,开屏广告是作为启动页,打开AndroidManifest.xml文件,搜索android.intent.category.LAUNCHER,找到了SplashActivity,毫无疑问这就是启动页,大概率承载了开屏广告:

4d7b044614504a1e85e2dafe042e71c1.png

 使用adb命令启动SplashActivity

adb shell am start -n com.tencent.news/.activity.SplashActivity

    确实是启动页,反复启动多次,均没有出现开屏广告,怀疑是判断了点击图标启动app才会出开屏广告。那么,可以顺着这个猜想去试试。直接查看smali代码难度有点大,我们去看下源码。

2、修改smali代码

    直接使用jadx反编译,反编后搜索SplashActivity,打开SplashActivity这个类,搜索onCreate:

79fe55548324452c9953b4182c89c1e9.png

    可以看到有多个if/else的判断逻辑,并且有finish(),猜测是不是结束掉SplashActivity就进入首页了。我们尝试修改smali代码,注意在Jadx不能直接修改,去我们使用aptool反编译后的文件夹中去搜索SplashActivity,然后在SplashActivity.smali修改。在另一个else分支(cond_1)插入finish()的代码:

invoke-virtual {p0}, Lcom/tencent/news/ui/BaseActivity;->finish()Vreturn-void

b010a9f43f574a68b482070a1525a07d.png

3、回编译和签名

修改smali代码并且保存后,回编:

apktool b /Users/xxx/Desktop/TencentNews

签名生成新的apk: 

java -jar apksigner.jar sign --ks /Users/xxx/Desktop/test.keystore  /Users/xxx/Desktop/TencentNews/dist/TencentNews_10565.apk

ef238032cfdc483694f688071a7eca70.png

    安装一下试试,这样是不行的,在首页直接退出app了,哈哈。之所以这样去尝试,其实是在我们的正常认知中,打开一个app首先是SplashActivity,然后是MainActivity,但其实在Manifest文件中也没搜到MainActivity,说不定SplashActivity也承担了主页的功能呢。 

4、再次修改smali代码

这次不fnish()了,直接插入return:

return-void

    再次执行回编译和签名后安装,果然也不行,卡在启动页不动了。这样尝试,是猜想app为了防止卡在启动页时间过长影响用户体验,可能会做一个定时的task,比如说3秒仍然未进入首页,则打开首页,但初步看上去TX新闻没有做这种兜底逻辑。

    这似乎更加验证了我们一开始的猜想:SplashActivity也承担了首页的功能,首页的几个tab应该是fragment,在首页的空白页面或开屏广告展现后,露出首页的新闻。其实可以在腾讯新闻的首页去dump一下activity:

adb shell dumpsys activity activities

可以看到,只有SplashActivity:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
Display #0 (activities from top to bottom):Stack #1050: type=standard mode=fullscreenisSleeping=falsemBounds=Rect(0, 0 - 0, 0)Task id #1051mBounds=Rect(0, 0 - 0, 0)mMinWidth=-1mMinHeight=-1mLastNonFullscreenBounds=null* TaskRecord{5a6a1a0 #1051 A=com.tencent.news U=0 StackId=1050 sz=1}userId=0 effectiveUid=u0a1943 mCallingUid=u0a74 mUserSetupComplete=true mCallingPackage=com.huawei.android.launcheraffinity=com.tencent.newsintent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.tencent.news/.activity.SplashActivity}mActivityComponent=com.tencent.news/.activity.SplashActivityautoRemoveRecents=false isPersistable=true numFullscreen=1 activityType=1rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLEActivities=[ActivityRecord{5d0d791 u0 com.tencent.news/.activity.SplashActivity t1051}]askedCompatMode=false inRecents=true isAvailable=truestackId=1050hasBeenVisible=true mResizeMode=RESIZE_MODE_RESIZEABLE mSupportsPictureInPicture=false isResizeable=true lastActiveTime=5012950897 (inactive for 0s)* Hist #0: ActivityRecord{5d0d791 u0 com.tencent.news/.activity.SplashActivity t1051}packageName=com.tencent.news processName=com.tencent.newslaunchedFromUid=11943 launchedFromPackage=com.tencent.news userId=0app=ProcessRecord{5e2ec99 21259:com.tencent.news/u0a1943}Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.tencent.news/.activity.SplashActivity (has extras) }frontOfTask=true task=TaskRecord{5a6a1a0 #1051 A=com.tencent.news U=0 StackId=1050 sz=1}taskAffinity=com.tencent.newsmActivityComponent=com.tencent.news/.activity.SplashActivitybaseDir=/data/app/com.tencent.news-wd3GPOer6dBCnZkO6QJNRg==/base.apkdataDir=/data/user/0/com.tencent.newsstateNotNeeded=false componentSpecified=true mActivityType=standardcompat={480dpi} labelRes=0x7f100073 icon=0x7f0e0000 theme=0x7f110127mLastReportedConfigurations:mGlobalConfig={1.0 ?mcc?mnc [zh_CN_#Hans] ldltr sw392dp w392dp h776dp 480dpi nrml long hdr port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1176, 2400) mAppBounds=Rect(0, 72 - 1176, 2400) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} suim:1 s.228}mOverrideConfig={1.0 ?mcc?mnc [zh_CN_#Hans] ldltr sw392dp w392dp h776dp 480dpi nrml long hdr port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1176, 2400) mAppBounds=Rect(0, 72 - 1176, 2400) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0} suim:1 s.1}CurrentConfiguration={1.0 ?mcc?mnc [zh_CN_#Hans] ldltr sw392dp w392dp h776dp 480dpi nrml long hdr port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1176, 2400) mAppBounds=Rect(0, 72 - 1176, 2400) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_0} suim:1 s.1}taskDescription: label="null" icon=null iconResource=0 iconFilename=null primaryColor=ffe6e6e6backgroundColor=fff3f3f3statusBarColor=ff000000navigationBarColor=fefcfcfblaunchFailed=false launchCount=0 lastLaunchTime=-20m25s855mshaveState=false icicle=nullstate=RESUMED stopped=false delayedResume=false finishing=falsekeysPaused=false inHistory=true visible=true sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_SHOWNfullscreen=true noDisplay=false immersive=false launchMode=1frozenBeforeDestroy=false forceNewConfig=falsemActivityType=standardnowVisible=true lastVisibleTime=-14s822msresizeMode=RESIZE_MODE_RESIZEABLEmLastReportedMultiWindowMode=false mLastReportedPictureInPictureMode=falseRunning activities (most recent first):TaskRecord{5a6a1a0 #1051 A=com.tencent.news U=0 StackId=1050 sz=1}Run #0: ActivityRecord{5d0d791 u0 com.tencent.news/.activity.SplashActivity t1051}mResumedActivity: ActivityRecord{5d0d791 u0 com.tencent.news/.activity.SplashActivity t1051}Stack #0: type=home mode=fullscreenisSleeping=falsemBounds=Rect(0, 0 - 0, 0)Task id #1mBounds=Rect(0, 0 - 0, 0)mMinWidth=-1mMinHeight=-1mLastNonFullscreenBounds=null* TaskRecord{5bdd731 #1 A=com.huawei.android.launcher U=0 StackId=0 sz=1}userId=0 effectiveUid=u0a74 mCallingUid=0 mUserSetupComplete=true mCallingPackage=nullaffinity=com.huawei.android.launcherintent={act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000300 cmp=com.huawei.android.launcher/.unihome.UniHomeLauncher}mActivityComponent=com.huawei.android.launcher/.unihome.UniHomeLauncherautoRemoveRecents=false isPersistable=true numFullscreen=1 activityType=2rootWasReset=false mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLEActivities=[ActivityRecord{5c57159 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t1}]askedCompatMode=false inRecents=true isAvailable=truemRootProcess=ProcessRecord{5706809 2869:com.huawei.android.launcher/u0a74}stackId=0hasBeenVisible=true mResizeMode=RESIZE_MODE_RESIZEABLE mSupportsPictureInPicture=false isResizeable=true lastActiveTime=5012936238 (inactive for 15s)* Hist #0: ActivityRecord{5c57159 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t1}packageName=com.huawei.android.launcher processName=com.huawei.android.launcherlaunchedFromUid=0 launchedFromPackage=null userId=0app=ProcessRecord{5706809 2869:com.huawei.android.launcher/u0a74}Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000300 cmp=com.huawei.android.launcher/.unihome.UniHomeLauncher }frontOfTask=true task=TaskRecord{5bdd731 #1 A=com.huawei.android.launcher U=0 StackId=0 sz=1}taskAffinity=com.huawei.android.launchermActivityComponent=com.huawei.android.launcher/.unihome.UniHomeLauncherbaseDir=/system/app/HwLauncher6/HwLauncher6.apkdataDir=/data/user_de/0/com.huawei.android.launcherstateNotNeeded=true componentSpecified=false mActivityType=homecompat={480dpi} labelRes=0x7f080084 icon=0x7f02012b theme=0x2060013mLastReportedConfigurations:mGlobalConfig={1.0 ?mcc?mnc [zh_CN_#Hans] ldltr sw392dp w392dp h776dp 480dpi nrml long hdr port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1176, 2400) mAppBounds=Rect(0, 72 - 1176, 2400) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0} suim:1 s.279}mOverrideConfig={1.0 ?mcc?mnc [zh_CN_#Hans] ldltr sw392dp w392dp h776dp 480dpi nrml long hdr port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1176, 2400) mAppBounds=Rect(0, 72 - 1176, 2400) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=home mAlwaysOnTop=undefined mRotation=ROTATION_0} suim:1 s.12}CurrentConfiguration={1.0 ?mcc?mnc [zh_CN_#Hans] ldltr sw392dp w392dp h776dp 480dpi nrml long hdr port finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1176, 2400) mAppBounds=Rect(0, 72 - 1176, 2400) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=home mAlwaysOnTop=undefined mRotation=ROTATION_0} suim:1 s.12}RequestedOverrideConfiguration={0.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?ldr ?wideColorGamut ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/? winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=null mWindowingMode=undefined mDisplayWindowingMode=undefined mActivityType=home mAlwaysOnTop=undefined mRotation=undefined}}launchFailed=false launchCount=0 lastLaunchTime=-32d11h41m24s609mshaveState=true icicle=Bundle[mParcelledData.dataSize=8832]state=STOPPED stopped=true delayedResume=false finishing=falsekeysPaused=false inHistory=true visible=false sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_NOT_SHOWNfullscreen=true noDisplay=false immersive=false launchMode=2frozenBeforeDestroy=false forceNewConfig=falsemActivityType=homenowVisible=false lastVisibleTime=-16s580msconnections=com.android.server.wm.ActivityServiceConnectionsHolder@5ce1c6dresizeMode=RESIZE_MODE_RESIZEABLEmLastReportedMultiWindowMode=false mLastReportedPictureInPictureMode=falseRunning activities (most recent first):TaskRecord{5bdd731 #1 A=com.huawei.android.launcher U=0 StackId=0 sz=1}Run #0: ActivityRecord{5c57159 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t1}mLastPausedActivity: ActivityRecord{5c57159 u0 com.huawei.android.launcher/.unihome.UniHomeLauncher t1}ResumedActivity:ActivityRecord{5d0d791 u0 com.tencent.news/.activity.SplashActivity t1051}ResumedActivity: ActivityRecord{5d0d791 u0 com.tencent.news/.activity.SplashActivity t1051}ActivityStackSupervisor state:topDisplayFocusedStack=ActivityStack{5e38a54 stackId=1050 type=standard mode=fullscreen visible=true translucent=false, 1 tasks}
mLastResumedActivity=ActivityRecord{5d0d791 u0 com.tencent.news/.activity.SplashActivity t1051}displayId=0 stacks=2mHomeStack=ActivityStack{5b6acd1 stackId=0 type=home mode=fullscreen visible=false translucent=true, 1 tasks}mPreferredTopFocusableStack=ActivityStack{5e38a54 stackId=1050 type=standard mode=fullscreen visible=true translucent=false, 1 tasks}mLastFocusedStack=ActivityStack{5e38a54 stackId=1050 type=standard mode=fullscreen visible=true translucent=false, 1 tasks}mCurTaskIdForUser={0=1051}mUserStackInFront={}isHomeRecentsComponent=true  KeyguardController:mKeyguardShowing=falsemAodShowing=falsemKeyguardGoingAway=falseOccluded=false DismissingKeyguardActivity=null at display=0mDismissalRequested=falsemVisibilityTransactionDepth=0LockTaskControllermLockTaskModeState=NONEmLockTaskModeTasks=mLockTaskPackages (userId:packages)=u0:[]

5、一种存在badcase的去广告方案

    接下来,只能再去看看SplashActivity的代码了。其实,腾讯新闻开屏广告的展示时间是有上限的,差不多五秒,经过了几次搜索,发现了以下两个类,存在疑似控制开屏广告跳过时间的代码。

(1)SplashView

看类名应该是开屏的承载组件

baef7bfb00f249ce8968b293497dfb0c.png

 (2)SplashAdLoader

看类名应该是开屏广告的加载器

21042b890ca24f129d10cb6112363fd6.png

    接下来,尝试转到smali源码,把5000修改为0。这里需要注意的是:smali源码中使用的是16进制,因此是看不到5000的,打开SplashView.smali,可以看到,是0x1388L,而定义完这个常量后,smali代码中不会使用这个常量的名字,而是直接使用0x1388,因此直接搜索0x1388,全部替换为0x0:

6799db90db13496b86c96ad444ad214a.png

SplashAdLoader.smali文件也一样,搜索1388后全部修改为0x0:

419cbf9d84854732ab420a46cba4dd5f.png

改完后保存并且回编译和签名,安装新的app,多次启动确实没展示开屏广告了,大功告成。

3623b00dad1d4ee2a9d11b07acf57ca6.gif

    这样修改并不是完美的,启动了几十次偶现露出开屏后瞬间自动消失,毕竟这么少量的代码修改app,多少会存在badcase。接下来,我们再看看有没有更好的方案?

6、完美的去开屏广告方案

    上面也提到过,SplashView看类名应该是开屏的承载组件。接下来,需要我们有耐心的详细看一下SplashView的源码。在入口方法init中发现了if/else的逻辑:

非常简单且清晰的代码,翻译一下:

if (展示开屏广告) {// 挑选出一个开屏pickOutSplash();
} else {// 不展示广告showNoAd();
}

 接下来怎么修改呢?很简单了吧?没错,就是这样:

if (展示开屏广告) {// 不展示广告showNoAd();
} else {// 不展示广告showNoAd();
}

尝试修改SplashView.smali代码,找到pickOutSplash()

尝试做如下修改:

接下来回编译,签名验证。哈哈,这次完美无漏出了,试了几十次,没问题,符合预期。当然受限于上传图片的大小为5M,只能演示几次:

再次总结一下反编app的几个步骤:

1、验证是否加固

2、反编译

3、分析和修改smali源码

4、回编译

5、签名

    最后,反编译app其实是不太好的行为。本文仅限于自娱自乐,研究和学习,坚决不会用于传播或商业行为。也希望看到本篇博客的朋友,不要用来做一些不好的事情,多多学些,传播正能量。


http://www.ppmy.cn/news/58359.html

相关文章

【LeetCode股票买卖系列:122. 买卖股票的最佳时机 II | 贪心 | 暴力递归=>记忆化搜索=>动态规划】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

PHP面试宝典之Mysql数据库基础篇

字符类型: tinyint(4):占1个字节,4代表字段值长度,用0填充,搭配zero fill使用 有符号:取值范围 负128 ~ 正127; 无符号:取值范围 0 ~ 255; 默认无…

APK文件结构

文件结构 assets文件用来存放需要打包到Android 应用程序的静态资源文件,例如图片资源文件,JSON配置文件,渠道配置文件,二进制数据文件,HTML5离线资源文件等 与res/raw目录不同的数,assets目录支持任意深度…

【数据分析之道-NumPy(四)】numpy广播机制

文章目录 专栏导读1、广播机制2、一维数组和二维数组的广播3、二维数组和三维数组的广播4、标量和数组的广播5、形状不兼容的数组不能进行广播 专栏导读 ✍ 作者简介:i阿极,CSDN Python领域新星创作者,专注于分享python领域知识。 ✍ 本文录入…

【LeetCode】221.最大正方形

221.最大正方形(中等) 题解 对于在矩阵内搜索正方形或长方形的题型,一种常见的做法是:定义一个二维 dp 数组,其中 dp[i][j] 表示满足题目条件的、以(i,j)为右下角的正方形或长方形属性。在本题中…

day11 TCP连接管理与UDP协议

目录 ​编辑 连接的建立——”三次握手” 连接的释放——“四次挥手” 保活计时器 用户数据报协议 UDP​编辑 连接的建立——”三次握手” TCP 建立连接的过程叫做握手。 采用三报文握手:在客户和服务器之间交换三个 TCP 报文段,以防止已失效的连接…

使用pg_basebackup备份

参考文档: http://postgres.cn/docs/14/app-pgbasebackup.html http://postgres.cn/docs/12/runtime-config-wal.html postgres版本 test# select version(); version …

ChatGPT技术原理 第八章:GPT与对话生成

目录 8.1 GPT在对话生成中的应用 8.2 基于GPT的对话生成模型 8.3 对话历史表示方法 8.4 策略学习