Android Studio 新版Logcat 从惊艳到放弃
AS总算更新了这个logcat了,原来的logcat真是使用起来贼难受,动不动过滤就失效,或者日志不打印,新版的logcat初步使用下来,那是贼舒服,先上一张界面图
- 一眼看去,可以看到主要改变有三点:
一个是多窗口支持,可以同时打开多个logcat窗口,这对于分析繁多复杂的日志十分有帮助,并且每个窗口又可以复制出多个子窗口,对于分析对比当前窗口不同位置的日志是非常有帮助的;
一个是过滤方式,改成了类似于Github里的搜索过滤语法,可以多个语法组合进行过滤,自定义更强更灵活了;
一个是打印格式,优化了多行日志的打印,日志排版也更清新,也支持了颜色高亮。并且打印信息也可以自定义是否显示
接下来就详细介绍一下这个过滤语法
过滤语法
package:mine 默认语法,官方原版解释:PIDs for the local app project,不太理解这个解释,不过根据使用,应该就是当前logcat窗口所在项目的log
package:my-package-ID 也就是根据包名过滤
tag:my-tag 根据tag进行过滤
level:ERROR 根据日志等级进行过滤
-tag:exclude-this-tag 在前面加了个‘-’,排除指定的TAG
tag~:regex-tag 在后面加了个’~',支持正则过滤
-tag~:exclude-this-regex-tag 这个自然就是支持正则过滤排除指定TAG
-package:exclude-this-package 同上
package~:regex-package 同上
-package~:exclude-this-regex-package 同上
总结
更新的内容挺好的,不过该有的问题依然存在,还是时不时的不显示logcat,需要重新插拔一下手机才行
后续
放弃了,日志更新不及时,删除也不及时,有些日志还没捕获到,比原来的logcat还垃圾,基本问题没解决,上层功能做的再花俏有什么卵用
退回旧版
Settings-> Experimental -> [x] Enable new Logcat tool window 取消选择 -> 重启 Android Studio
Android P以上隐藏API(非SDK接口)反射限制解决方案
相关限制说明参考:针对非 SDK 接口的限制
FreeReflection github
- Java层双重反射 (Android P)
- ClassLoader置空 (Android P+)(将被修复)
- native层通过偏移获取关键结构体然后修改其中的检查Flag (Android P+)
RestrictionBypass github
- Java层双重反射 (Android P)
- native层双重反射 (通过AttachCurrentThread隐藏未知调用者) (Android Q+) (将被修复)
AndroidHiddenApiBypass github
- 借用Unsafe重写反射代码(Android P+)
总结
目前本人仅使用了FreeReflection,不过由于时常报native层闪退异常已弃用(猜测是ClassLoader置空方案造成的,双重反射应该只在Android P生效,native层修改Flag未用到),其他暂未使用,不做评价,不过理论上比较看好AndroidHiddenApiBypass,纯Java,兼容性肯定是最好的,由于Unsafe涉及到native层访问,恐怕不太好封,限制访问部分内存区域?还是直接限制访问反射相关结构体?RestrictionBypass的native层双重反射应该也容易被检测修复
Android 10以上无法隐藏应用图标问题探究及解决方案
Android 10之前的隐藏方式:
con.getPackageManager().setComponentEnabledSetting(new ComponentName(con,activityAliasName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);
Android 10之后,该隐藏图标方式失效,隐藏成功后依然会在桌面上保留其图标,点击后会跳转到应用详情页。具体查看官方API更新说明:getActivityList 。
那这就很难受了,在我看来,目前设计的并不太合理,能不能隐藏应该由用户决定,而不是强制不允许隐藏,不过目前官方也设置了控制开关,可以修改系统设置来去掉该限制,只不过需要adb或能修改系统设置的APP或ROOT权限才能修改。接下来就是具体分析了。
具体分析
- getActivityList
//frameworks/base/core/java/android/content/pm/LauncherApps.javapublic List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {logErrorForInvalidProfileAccess(user);try {return convertToActivityList(mService.getLauncherActivities(mContext.getPackageName(),packageName, user), user);} catch (RemoteException re) {throw re.rethrowFromSystemServer();}}
- getLauncherActivities
//frameworks/base/services/core/java/com/android/server/pm/LauncherAppsService.java
@Override
public ParceledListSlice<LauncherActivityInfoInternal> getLauncherActivities(String callingPackage, String packageName, UserHandle user) throws RemoteException {//查询包含ACTION_MAIN和CATEGORY_LAUNCHER的activityParceledListSlice<LauncherActivityInfoInternal> launcherActivities =queryActivitiesForUser(callingPackage,new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER).setPackage(packageName),user);//检测系统设置(系统设置控制开关控制是否走新版限制逻辑)if (Settings.Global.getInt(mContext.getContentResolver(),Settings.Global.SHOW_HIDDEN_LAUNCHER_ICON_APPS_ENABLED, 1) == 0) {return launcherActivities;}//没有找到入口activityif (launcherActivities == null) {// Cannot access profile, so we don't even return any hidden apps.return null;}final int callingUid = injectBinderCallingUid();final long ident = injectClearCallingIdentity();try {//托管配置文件可以隐藏APPif (mUm.getUserInfo(user.getIdentifier()).isManagedProfile()) {// Managed profile should not show hidden appsreturn launcherActivities;}//设备管理员可以隐藏APPif (mDpm.getDeviceOwnerComponentOnAnyUser() != null) {// Device owner devices should not show hidden appsreturn launcherActivities;}final ArrayList<LauncherActivityInfoInternal> result = new ArrayList<>(launcherActivities.getList());if (packageName != null) {// If this hidden app should not be shown, return the original list.// Otherwise, inject hidden activity that forwards user to app details page.//可能是如果大于0,表示有有效的启动入口,则不用注入隐藏的APP详情页入口if (result.size() > 0) {return launcherActivities;}final ApplicationInfo appInfo = mPackageManagerInternal.getApplicationInfo(packageName, /* flags= */ 0, callingUid, user.getIdentifier());//根据APP信息进行判断是否注入隐藏APP详情页入口if (shouldShowSyntheticActivity(user, appInfo)) {LauncherActivityInfoInternal info = getHiddenAppActivityInfo(packageName,callingUid, user);if (info != null) {result.add(info);}}return new ParceledListSlice<>(result);}final HashSet<String> visiblePackages = new HashSet<>();for (LauncherActivityInfoInternal info : result) {visiblePackages.add(info.getActivityInfo().packageName);}final List<ApplicationInfo> installedPackages =mPackageManagerInternal.getInstalledApplications(/* flags= */ 0,user.getIdentifier(), callingUid);for (ApplicationInfo applicationInfo : installedPackages) {if (!visiblePackages.contains(applicationInfo.packageName)) {if (!shouldShowSyntheticActivity(user, applicationInfo)) {continue;}LauncherActivityInfoInternal info = getHiddenAppActivityInfo(applicationInfo.packageName, callingUid, user);if (info != null) {result.add(info);}}}return new ParceledListSlice<>(result);} finally {injectRestoreCallingIdentity(ident);}
}
- shouldShowSyntheticActivity
//frameworks/base/services/core/java/com/android/server/pm/LauncherAppsService.java
private boolean shouldShowSyntheticActivity(UserHandle user, ApplicationInfo appInfo) {//没有app信息,是系统APP或者更新的系统APP,则不添加隐藏详情页入口if (appInfo == null || appInfo.isSystemApp() || appInfo.isUpdatedSystemApp()) {return false;}//是管理员APP也不用添加该入口if (isManagedProfileAdmin(user, appInfo.packageName)) {return false;}final AndroidPackage pkg = mPackageManagerInternal.getPackage(appInfo.packageName);if (pkg == null) {// Should not happen, but we shouldn't be failing if it doesreturn false;}// If app does not have any default enabled launcher activity or any permissions,// the app can legitimately have no icon so we do not show the synthetic activity.return requestsPermissions(pkg) && hasDefaultEnableLauncherActivity(appInfo.packageName);
}
根据以上源码,可以发现该机制有个全局设置开关,并且有多种情况可以不受该机制限制。因此总结出如下解决方案:
- 若是你的APP有adb权限或ROOT权限,可以直接修改这个全局开关,修改命令如下:
adb shell settings put global show_hidden_icon_apps_enabled 0
- 或者你的APP有设备管理员权限
- 或者你的APP是系统APP
- 或者你的APP没有任何默认启动入口
- 或者你的APP没有请求任何权限
- 或者你的APP涉及到Managed profile(这个具体不太清楚怎么用)
- 或者你的APP是Xposed模块,可以直接注入系统服务拦截相关API,或者注入可以修改系统设置的APP(比如:设置)直接修改这个开关
- 或者你是系统源码开发者,可以直接修改该处代码即可
- 其它更多还未探索出的方式(比如利用某些逻辑漏洞)…
参考
- Android hide/unhide app icon programmatically
Android Studio gradle 没依赖成功 但不报错 只有调用时会报红
可以单独运行一下依赖任务,就会出现错误信息了
Empty SMPTE 2094-40 data 报错问题
搜索源码定位到打印日志位置:SharedMetadata#151
临时解决方案
借用AS 新版Logcat 过滤语法进行过滤即可,过滤语法如下
-tag:gralloc4
即排除掉tag为gralloc4的日志
【远程USB】VirtualHere 指定IP(Android 远程开发优雅连接调试设备)
一般我们Android远程调试一般直接是adb connect ip:port,但是呢,这个很不方便,你还需要配置wifi USB调试,但是远程USB就不一样了,连接远程设备就像连接本地设备一样操作,直接adb device就可以看见设备了,不用什么adb connect和wifi USB调试。
而远程USB工具,当然就推荐VirtualHere了,VirtualHere使用起来真香,局域网内,直接安装运行就行了,不需要任何操作(当然了,试用版同一时间仅限一台设备,不过对于个人使用,这足够了,需要时再切换即可,反正又不绑定设备),但互联网的话就不能这么操作了,毕竟互联网这么多IP,它怎么知道是哪个对不对,所以需要我们手动指定IP,正文开始…
服务端若是在服务器运行的,那就不用动了,若是在本地运行的话,就需要做内网穿透了,这里推荐FRP,简单方便开源,具体这里就不展开讲了;
然后在客户端中,在USB Hubs上右键菜单选择Specify Hubs…
然后点击add添加,在新窗口输入你的ip和port即可
之后等待USB hubs下出现新设备即可
若是出现问题,可以通过
telnet ip port
命令,看看是否可以正常连接,若不能正常连接,检查防火墙是否拦截了
Frida使用技巧
命令行
Frida命令
- 指定IP和Port:-H 127.0.0.1:27042
- 强制重启应用:-f
- 重启后直接运行应用:–no-pause
- 注入指定包名(必须):com.xxxxx.xxx
- 注入指定进程ID(与上面二选一):pid
- 调试js代码:–debug --runtime=v8
具体参考Here,其中代码方式开启调试测试不太管用,具体待分析
- 指定要加载的js文件路径(必须):-l path_to_js
接入Google Admob
官方Demo
Here
填坑
- 1.The ad request was successful, but no ad was returned due to lack of ad inventory
参考Here
1.未关联应用商店应用,在应用设置里添加应用ID,也就是包名,且在google play,或者其支持的应用商店上架
2.填充率低,采用中介模式,具体参考Here
2.1.查看国内支持的广告源,参考Here
- 2.需要上车才能显示Ad
参考
- 1.https://groups.google.com/g/google-admob-ads-sdk/c/Vy5itxLq704/m/F0OtHn4gBAAJ
App支付功能实现及踩坑
支付宝支付实现
1.正规支付实现
前提条件:
1. 企业或个体工商户可申请,且账号通过支付宝实名认证审核
2. 需提供真实有效的营业执照,且支付宝账户名称需与营业执照主体一致;
3. 提供APP名称或产品说明文档,开发者与支付宝账户名称不一致需提供开发合作协议。
(您可以提供产品介绍文档或者手机demo .apk .doc .docx .pdf格式,内容要求包含产品说明、接口使用场景、资费说明等(文件大小不超过5M)如果已经在appstore、googleplay、豌豆荚上架,可不提供文档demo,直接提供应用名称)
现在企业和个体工商户的办理,某宝应该都可以搜到,我咨询了卖家,说是需要对公账户,
对公账户具体意思呢,卖家就说是上面第二个条件.
还是不太明白,我又上网百度了下:
看来百度,也百度不到什么,试试用谷歌吧
终于让我找到了,看来还是谷歌大法好,百度真是越做越垃圾了!
看来要对公账号,就等于要申请一个公司啊,那还是算了,想起那一大堆文件和流程就害怕!只能等待以后有一定资金了直接某宝找人代办吧
2.非正规实现
1.还是使用个人支付账号,然后服务端后台(或个人电脑端)不断监听付款记录,当匹配到特定备注的支付记录时就进行相应处理!
2.使用第三方代理支付,就是把支付交给已经得到支付宝认证的第三方支付商,这样的话的确是最方便的,不做任何处理就可以得到支付宝的正规支付功能,缺点就是肯定会收手续费了,当然收手续费很正常,毕竟人家提供了服务嘛,另一个缺点就是这个服务商是否可信,毕竟人家后台怎么处理你根本不知道,同样的这种服务商都一个共同的最大的缺点—不稳定,就是一个开发者的App支付若是被投诉,肯定会影响到这个服务商,在支付宝那边就相当于这个服务商被投诉,若投诉多了,那这个服务商也就挂了!
微信支付实现
1.正规实现
同样需要企业认证,其开发者认证也不是很容易
仅认证个开发者就要300元,还仅是一年的!
还是需要企业,算了,放弃!
2.非正规实现
还在研究中…
参考
1.支付宝收款流程
DcseTBS获取设备ID原理
这款工具的就不说了,这不是文章的重点,今天我们要研究一下他的获取设备唯一ID的原理。
其实它获取设备唯一ID的方法跟别人的没啥区别,
实现代码:
TelephoneManager tm=TelephoneManager.getSystemService(Context.TELEPHONE_SERVICE);
tm.getDeviceId();
代码非常的简单,所以破解它也非常的简单,用xposed模块hook即可修改,或者直接反编译修改也可以。
但重点不在这里,而是破解之后的情况,它的每个设备ID不充值是仅能使用一天的,所以我破解它的方法是让他每次返回随机设备ID,这样不就可以破解了,可是事实不是这样的,并没有破解(其实后来才知道已经破解了),每次打开显示错误,真是让我纠结了半天,以为他是用了反射或者通过其他方式获取了设备ID,或者把设备ID存储在了内存卡,通过我的验证,最后发现都没有,这就让我懵逼了,难道使用了我不知到的方法,就在我准备放弃的时候,我想到了一个被我忽略的地方,那就是我的网络IP地址,并且发现有时候错误的信息并不一样,到最后我终于发现了问题的关键点
原来是当它获取到新的设备ID时,并不会第一时间就出现试用信息,而是出现错误信息,并让你重启,正常在没破解的情况下,在第二次进入时就会出现试用信息了,但是当我们把它破解之后,每次获取的都是随机的设备ID,也就是当第二次重启时,又获取的是新的设备ID,这是又需要再重启一次,可是再获取一次又是新的设备ID,这样造成的结果就是永远不会出现试用信息!
既然明白了问题,那破解也就简单了,只要在每次过了试用期后,再返回一个新的设备ID即可!
真是一个非常巧妙地防止被破解的方法!
破解后的截图
不要频繁重置ID,一天一次即可,设置了新的ID后直接点击“明天再提示”,就会等到明天这个时候会自动提示更换新ID,这时候再设置一个新ID即可。
破解后的APK
看有这多人要,我就直接发出来吧!
下载地址:https://download.csdn.net/download/qq_26914291/10383983
【注】该Apk仅供研究测试用,用作它用造成的一切损失一概与本人无关 !
总结
1.破解遇到问题,一定要仔细观察错误的信息,或许原因就藏在那些之中!
2.其实往往看似复杂的东西其实很简单!
代码混淆
初级混淆
使用proGuard进行代码混淆
1.参考教程:Android开发者指南(9) —— ProGuard
2.混淆模板:Android proguard-rules.pro 混淆模板
3.[Android 代码混淆 选项说明(https://blog.csdn.net/jjwwmlp456/article/details/44977721)
几个可以增加混淆强度的命令:
#将所有类放到跟目录下
-flattenpackagehierarchy#使用唯一的类成员名称
-useuniqueclassmembernames
几个可以增加混淆强度的字典
1.https://github.com/ihbing/AndroidObfuseDictionary
几个使用时需要注意的命令:
1.-assumenosideeffects使用时一定不要加-dontoptimize才起作用
# 移除Log类打印各个等级日志的代码,打正式包的时候可以做为禁log使用,这里可以作为禁止log打印的功能使用
# 记得proguard-android.txt中一定不要加-dontoptimize才起作用
-assumenosideeffects class android.util.Log {public static int v(...);public static int i(...);public static int w(...);public static int d(...);public static int e(...);
}
[注]
1.eclipse只有将项目导出时才会进行混淆
2.1 proguard.config=proguard-project.txt//采用相对路径配置,直接读取项目根目录下proguard-project.txt文件
2.2 proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt//采用绝对路径
使用proGuard-GUI进行手动混淆
使用AndResGuard进行资源混淆
参考教程:AndResGuard集成笔记
增加7z压缩
参考教程:Android项目集成AndResGuard资源混淆两种方式
参考教程:https://github.com/shwenzhang/AndResGuard/blob/master/doc/how_to_work.zh-cn.md
注意点
1.如何打开Gradle中的Task任务?
进阶混淆
使用StringFog对字符串Base64加密
参考教程:https://github.com/MegatronKing/StringFog
将字符串混淆成byte字节码
如下图
参考教程:https://github.com/ihbing/obfuseSmaliText
高阶混淆
修改proGuard工具的混淆字符
[注]AndroidStudio的自身proGuard混淆工具目录D:\Program Files\Android\Android Studio\gradle\m2repository\net\sf\proguard\proguard-base\
或D:\Program Files\Android\Android Studio\gradle\m2repository\net\proguard-base\
用无效代码对抗jadx&jd-gui
//添加无效代码,对抗jadx & jd-guiboolean qwerty21345hjdnjd = false;while (qwerty21345hjdnjd) {switch (1) {case 1:while (qwerty21345hjdnjd) {try {Throwable throwable=new Throwable();Throwable cause = throwable.getCause();} catch (NullPointerException e) {} finally {}}break;}}
参考
1.Android资源混淆工具
2.proGuard混淆笔记
3.Android代码混淆技术总结(一)
4.apk在线反混淆