android 12+从后台启动FGS限制
Posted AmyTan小小燕
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 12+从后台启动FGS限制相关的知识,希望对你有一定的参考价值。
后台启动FGS限制
限制简介
以 android 12(API 级别 31)或更高版本为目标平台的应用在后台运行时无法启动前台服务,少数特殊情况除外。 如果应用程序在后台运行时尝试启动前台服务,而前台服务不满足其中一种异常情况,系统将抛出 ForegroundServiceStartNotAllowedException。
注意:如果一个应用调用 Context.startForegroundService() 来启动另一个应用拥有的前台服务,则这些限制仅适用于两个应用都以 Android 12 或更高版本为目标的情况。
错误日志如下
12-17 01:14:55.156 1383 12145 W ActivityManager: Background started FGS: Disallowed [callingPackage: com.debug.loggerui; callingUid: 10102; uidState: SVC ; intent: Intent cmp=com.debug.loggerui/.framework.DebugLoggerUIService ; code:DENIED; tempAllowListReason:; targetSdkVersion:31; callerTargetSdkVersion:31; startForegroundCount:0; bindFromPackage:null]
java.lang.RuntimeException: Unable to create service com.debug.loggerui.framework.DebugLoggerUIService: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service com.debug.loggerui/.framework.DebugLoggerUIService
豁免日志如下:
12-21 01:01:17.121 2399 3193 I am_wtf : [0,2399,system_server,-1,ActivityManager,Background started FGS: Allowed [callingPackage: com.android.providers.contacts; callingUid: 10071; uidState: BFGS; intent: Intent act=android.intent.action.SIM_STATE_CHANGED cmp=com.android.providers.contacts/com.miui.providers.contacts.sim.SimStateChangedService (has extras) ; code:PROC_STATE_BFGS; tempAllowListReason:<,reasonCode:SYSTEM_ALLOW_LISTED,duration:9223372036854775807,callingUid:-1>; targetSdkVersion:33; callerTargetSdkVersion:33; startForegroundCount:0; bindFromPackage:null]]
限制原理
setFgsRestrictionLocked
FGS 有两个限制:
在 R 中,mAllowWhileInUsePermissionInFgs 是允许在前台服务中使用 while-in-use 权限。 从后台启动的 FGS 中的使用中权限可能会受到限制。 具体见 Bg start FGS的while in use权限
在S中,mAllowStartForeground是允许FGS是否startForeground。 从后台启动的服务可能不会成为 FGS。
启动或绑定或调用startForeground时会调用setFgsRestrictionLocked方法去校验上面的两个FGS限制。
private void setFgsRestrictionLocked(String callingPackage,
int callingPid, int callingUid, Intent intent, ServiceRecord r, int userId,
boolean allowBackgroundActivityStarts)
.......
if (!r.mAllowWhileInUsePermissionInFgs
|| (r.mAllowStartForeground == REASON_DENIED))
// while in use权限校验
......
// 是否允许后台启动FGS校验
if (r.mAllowStartForeground == REASON_DENIED)
r.mAllowStartForeground = shouldAllowFgsStartForegroundWithBindingCheckLocked(
allowWhileInUse, callingPackage, callingPid, callingUid, intent, r,userId);
shouldAllowFgsStartForegroundWithBindingCheckLocked
mAllowStartForeground由shouldAllowFgsStartForegroundWithBindingCheckLocked方法返回值赋值;并计算赋值mInfoAllowStartForeground,以便后面打印相关信息。
是否应该允许 FGS 启动(又名 startForeground())
具体豁免情况见下面的 后台启动限制的豁免
private @ReasonCode int shouldAllowFgsStartForegroundWithBindingCheckLocked(
@ReasonCode int allowWhileInUse, String callingPackage, int callingPid,
int callingUid, Intent intent, ServiceRecord r, int userId)
ActivityManagerService.FgsTempAllowListItem tempAllowListReason =
// mDeviceIdleExceptIdleAllowlist 或 mFgsStartTempAllowList列表中
r.mInfoTempFgsAllowListReason = mAm.isAllowlistedForFgsStartLOSP(callingUid);
// 见“后台启动限制的豁免”
int ret = shouldAllowFgsStartForegroundNoBindingCheckLocked(allowWhileInUse, callingPid,callingUid, callingPackage, r);
String bindFromPackage = null;
// 查看client是否允许start FGS
if (ret == REASON_DENIED)
bindFromPackage = canBindingClientStartFgsLocked(callingUid);
if (bindFromPackage != null)
ret = REASON_FGS_BINDING;
final int uidState = mAm.getUidStateLocked(callingUid);
int callerTargetSdkVersion = -1;
try
callerTargetSdkVersion = mAm.mContext.getPackageManager()
.getTargetSdkVersion(callingPackage);
catch (PackageManager.NameNotFoundException ignored)
final String debugInfo =
// calling 相关信息
"[callingPackage: " + callingPackage
+ "; callingUid: " + callingUid
+ "; uidState: " + ProcessList.makeProcStateString(uidState)
// service信息
+ "; intent: " + intent
// 豁免reson code打印
+ "; code:" + reasonCodeToString(ret)
// 打印临时白名单的相关信息
+ "; tempAllowListReason:<"
+ (tempAllowListReason == null ? null :
(tempAllowListReason.mReason
+ ",reasonCode:"
+ reasonCodeToString(tempAllowListReason.mReasonCode)
+ ",duration:" + tempAllowListReason.mDuration
+ ",callingUid:" + tempAllowListReason.mCallingUid))
+ ">"
+ "; targetSdkVersion:" + r.appInfo.targetSdkVersion
+ "; callerTargetSdkVersion:" + callerTargetSdkVersion
+ "; startForegroundCount:" + r.mStartForegroundCount
+ "; bindFromPackage:" + bindFromPackage
+ "]";
// 赋值mInfoAllowStartForeground以便在logFgsBackgroundStart 打印这些信息
if (!debugInfo.equals(r.mInfoAllowStartForeground))
r.mLoggedInfoAllowStartForeground = false;
r.mInfoAllowStartForeground = debugInfo;
return ret;
logFgsBackgroundStart
启动Service时,如果是FGS则会去校验是否允许本次启动,后台启动FGS是否豁免等;如果不满足条件会抛出如上异常。
if (fgRequired)
// 打印Background started FGS相关log,无论是否允许启动都会打印
logFgsBackgroundStart(r);
if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r))
String msg = "startForegroundService() not allowed due to "
+ "mAllowStartForeground false: service "
+ r.shortInstanceName;
// 打印出错信息
Slog.w(TAG, msg);
showFgsBgRestrictedNotificationLocked(r);
logFGSStateChangeLocked(r,
FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__DENIED,
0, FGS_STOP_REASON_UNKNOWN);
// 抛出异常
if (CompatChanges.isChangeEnabled(FGS_START_EXCEPTION_CHANGE_ID, callingUid))
throw new ForegroundServiceStartNotAllowedException(msg);
return null;
如果是后台启动FGS,则无论是否豁免均会打印Background started FGS相关log
private void logFgsBackgroundStart(ServiceRecord r)
// Only log if FGS is started from background.
if (!isFgsBgStart(r.mAllowStartForeground))
return;
if (!r.mLoggedInfoAllowStartForeground)
// 主要豁免信息等保存在mInfoAllowStartForeground中
final String msg = "Background started FGS: "
+ ((r.mAllowStartForeground != REASON_DENIED) ? "Allowed " : "Disallowed ")
+ r.mInfoAllowStartForeground;
if (r.mAllowStartForeground != REASON_DENIED)
if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
mAm.mConstants.mFgsStartAllowedLogSampleRate))
Slog.wtfQuiet(TAG, msg);
Slog.i(TAG, msg);
else
if (ActivityManagerUtils.shouldSamplePackageForAtom(r.packageName,
mAm.mConstants.mFgsStartDeniedLogSampleRate))
Slog.wtfQuiet(TAG, msg);
Slog.w(TAG, msg);
// 打印过后赋值为true
r.mLoggedInfoAllowStartForeground = true;
推荐解决方案
如果您发现您的应用在从后台运行时启动前台服务,请更新您的应用逻辑以使用 WorkManager。 要查看如何更新您的应用程序的示例,请查看 GitHub 上的 WorkManagerSample。
检查您的应用是否执行后台启动
为了更好地了解您的应用在后台运行时何时尝试启动前台服务,您可以启用每次出现此行为时显示的通知。 为此,请在连接到测试设备或模拟器的开发机器上执行以下 ADB 命令:
adb shell device_config put activity_manager default_fgs_starts_restriction_notification_enabled true
后台启动限制的豁免
/**
* The list of BG-FGS-Launch and temp-allow-list reason code.
* @hide
*/
@IntDef(flag = true, prefix = "REASON_" , value =
// BG-FGS-Launch reasons.
REASON_DENIED,
REASON_UNKNOWN,
REASON_OTHER,
// 前台procState
REASON_PROC_STATE_PERSISTENT,
REASON_PROC_STATE_PERSISTENT_UI,
REASON_PROC_STATE_TOP,
REASON_PROC_STATE_BTOP,
REASON_PROC_STATE_FGS,
REASON_PROC_STATE_BFGS,
// 有可见的window
REASON_UID_VISIBLE,
// 特殊uid
REASON_SYSTEM_UID,
REASON_ACTIVITY_STARTER,
// pendingIntent通知
REASON_START_ACTIVITY_FLAG,
// service的client能从后台启动FGS
REASON_FGS_BINDING,
REASON_DEVICE_OWNER,
// 资料所有者
REASON_PROFILE_OWNER,
// 应用使用配套设备管理器并声明
REASON_COMPANION_DEVICE_MANAGER,
// bg activity权限
REASON_BACKGROUND_ACTIVITY_PERMISSION,
// fgs权限
REASON_BACKGROUND_FGS_PERMISSION,
// bg activity权限的instr
REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION,
// fgs权限的instr
REASON_INSTR_BACKGROUND_FGS_PERMISSION,
// 悬浮窗权限
REASON_SYSTEM_ALERT_WINDOW_PERMISSION,
// 演示模式
REASON_DEVICE_DEMO_MODE,
// while-in-use
REASON_ALLOWLISTED_PACKAGE,
REASON_APPOP,
// 5s内可见
REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD,
// 应用获得允许ACTIVATE_VPN或ACTIVATE_PLATFORM_VPN权限
REASON_OP_ACTIVATE_VPN,
REASON_OP_ACTIVATE_PLATFORM_VPN,
// 应用是设备当前的输入法
REASON_CURRENT_INPUT_METHOD,
// while-in-use
REASON_TEMP_ALLOWED_WHILE_IN_USE,
)
@Retention(RetentionPolicy.SOURCE)
public @interface ReasonCode
在以下情况下,即使您的应用程序在后台运行,您的应用程序也可以启动前台服务:
@PowerExemptionManager.ReasonCode int mAllowStartForeground = REASON_DENIED;
应用程序在前台
- REASON_PROC_STATE_PERSISTENT
- REASON_PROC_STATE_PERSISTENT_UI
- REASON_PROC_STATE_TOP
private @ReasonCode int shouldAllowFgsStartForegroundNoBindingCheckLocked(
@ReasonCode int allowWhileInUse, int callingPid, int callingUid, String callingPackage,
@Nullable ServiceRecord targetService)
int ret = allowWhileInUse;
if (ret == REASON_DENIED)
final int uidState = mAm.getUidStateLocked(callingUid);
// Is the calling UID at PROCESS_STATE_TOP or above?
if (uidState <= PROCESS_STATE_TOP)
ret = getReasonCodeFromProcState(uidState);
- REASON_PROC_STATE_BTOP
- REASON_PROC_STATE_FGS
- REASON_PROC_STATE_BFGS
if (ret == REASON_DENIED)
final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app ->
if (app.uid == callingUid)
final ProcessStateRecord state = app.mState;
if (state.isAllowedStartFgs())
return getReasonCodeFromProcState(state.getCurProcState());
.......
@GuardedBy("mService")
boolean isAllowedStartFgs()
return mCurProcState <= PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
应用程序可见
- REASON_UID_VISIBLE
if (ret == REASON_DENIED)
// Does the calling UID have any visible activity?
final boolean isCallingUidVisible = mAm.mAtmInternal.isUidForeground(callingUid);
if (isCallingUidVisible)
ret = REASON_UID_VISIBLE;
该服务通过与通知交互来启动
该服务由不同的可见应用程序发送的 PendingIntent 启动
细节可参考 BackgroundLaunchProcessController 介绍
- REASON_START_ACTIVITY_FLAG
if (ret == REASON_DENIED)
// Is the allow activity background start flag on?
if (allowBackgroundActivityStarts)
ret = REASON_START_ACTIVITY_FLAG;
该服务由系统组件启动(root/system/nfc/shell)
- REASON_SYSTEM_UID
if (ret == REASON_DENIED)
boolean isCallerSystem = false;
final int callingAppId = UserHandle.getAppId(callingUid);
switch (callingAppId)
case ROOT_UID:
case SYSTEM_UID:
case NFC_UID:
case SHELL_UID:
isCallerSystem = true;
break;
default:
isCallerSystem = false;
break;
if (isCallerSystem)
ret = REASON_SYSTEM_UID;
该服务由具有 START_ACTIVITIES_FROM_BACKGROUND 特权权限的应用程序启动
- REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION
- REASON_BACKGROUND_ACTIVITY_PERMISSION
if (ret == REASON_DENIED)
if (mAm.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
== PERMISSION_GRANTED)
ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
if (ret == REASON_DENIED)
if (targetService != null && targetService.app != null)
ActiveInstrumentation instr = targetService.app.getActiveInstrumentation();
if (instr != null && instr.mHasBackgroundActivityStartsPermission)
ret = REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
该服务由具有 START_FOREGROUND_SERVICES_FROM_BACKGROUND 特权权限的应用程序启动。
- REASON_BACKGROUND_FGS_PERMISSION
- REASON_INSTR_BACKGROUND_FGS_PERMISSION
if (ret == REASON_DENIED)
final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app ->
if (app.uid == callingUid)
final ProcessStateRecord state = app.mState;
if (state.isAllowedStartFgs())
.......
else
final ActiveInstrumentation instr = app.getActiveInstrumentation();
if (instr != null
&& instr.mHasBackgroundForegroundServiceStartsPermission)
// 调用者是否拥有 START_FOREGROUND_SERVICES_FROM_BACKGROUND 权限
return REASON_INSTR_BACKGROUND_FGS_PERMISSION;
......
if (ret == REASON_DENIED)
if (mAm.checkPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, callingPid,callingUid) == PERMISSION_GRANTED)
ret = REASON_BACKGROUND_FGS_PERMISSION;
应用在5s内可见
- REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD
if (ret == REASON_DENIED)
final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app ->
if (app.uid == callingUid)
final ProcessStateRecord state = app.mState;
if (state.isAllowedStartFgs())
.......
else
.......
final long lastInvisibleTime = app.mState.getLastInvisibleTime();
if (lastInvisibleTime > 0 && lastInvisibleTime < Long.MAX_VALUE)
final long sinceLastInvisible = SystemClock.elapsedRealtime()
- lastInvisibleTime;
// 5s
if (sinceLastInvisible < mAm.mConstants.mFgToBgFgsGraceDuration)
return REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
......
应用申请了SYSTEM_ALERT_WINDOW权限并在权限管理页面获得用户同意
- REASON_SYSTEM_ALERT_WINDOW_PERMISSION
if (ret == REASON_DENIED)
if (mAm.mAtmInternal.hasSystemAlertWindowPermission(callingUid, callingPid,
callingPackage))
ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
应用使用配套设备管理器并声明REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND 权限或 REQUEST_COMPANION_RUN_IN_BACKGROUND 权限
尽可能使用 REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND。
- REASON_COMPANION_DEVICE_MANAGER
注意:当 CDM 应用程序具有 REQUEST_COMPANION_RUN_IN_BACKGROUND 时,该应用程序也会被放入用户白名单中。 但是,在这种情况下,我们要使用原因代码 REASON_COMPANION_DEVICE_MANAGER,因此此检查需要在 isAllowlistedForFgsStartLOSP 检查之前进行。
if (ret == REASON_DENIED)
final boolean isCompanionApp = mAm.mInternal.isAssociatedCompanionApp(
UserHandle.getUserId(callingUid), callingUid);
if (isCompanionApp)
if (isPermissionGranted(
REQUEST_COMPANION_START_FOREGROUND_SERVICES_FROM_BACKGROUND,
callingPid, callingUid)
|| isPeAndroid逆向-Android基础逆向(2-2)
[toc]
#0x00 前言
##不知所以然,请看
Android逆向-Android基础逆向(1)
Android逆向-Android基础逆向(2)
##以及java系列:
Android逆向-java代码基础(1)
Android逆向-java代码基础(2)
Android逆向-java代码基础(3)
Android逆向-java代码基础(4)
Android逆向-java代码基础(5)
Android逆向-java代码基础(6)
Android逆向-java代码基础(7)
Android逆向-java代码基础(8)
由于之前的Android逆向-Android基础逆向(2)的伪加密部分篇幅太长,导致其他内容没有完成,所以才有了这里的Android逆向-Android基础逆向(2-2)。希望可以完成计划中的内容。
##学习内容
(1)APK文件伪加密√
(2)资源文件防反编译
(3)apk打包流程
(4)apk反编译流程
(5)apk回编译流程、
#0x01 资源文件防反编译
之前说过可以通过更改第四个字段来进行防止一定程度的反编译。那么除了这种伪加密的方式,还有什么方式可以防止这种伪加密的出现呢。
来看看资源文件是如何防止反编译的。
自然我们需要研究一下xml文件的格式。四哥在2016年已经分析过了,不过那是人家分析的,只看别人分析的不能进行更深入的学习。纸上得来终觉浅,绝知此事要躬行。so,就有了这篇。
##1.第一个模块
![技术分享图片](http://t1.aixinxi.net/o_1c4qonh643er1mfetkl1rqc1mr5a.png-j.jpg)
这里对应使用一个实例分析,就用Android逆向-Android基础逆向(1)中的简单的apk来分析吧。
###1.1 Magic Number
![技术分享图片](http://t1.aixinxi.net/o_1c4qoqk4l1veta0e1a7s1f9p8uta.png-j.jpg)
这里魔数是00 08 00 03,这个是一个固定的值。
###1.2File Size
这个就是用来确认文件大小的。
![技术分享图片](http://t1.aixinxi.net/o_1c4qp0f6a4i5rnbuut18tk6opa.png-j.jpg)
这里是00 00 07 90 ,也就是1970个bytes。
###1.3用python实现分析
四哥用java写的,我就献丑写个python的,还在学习python的过程中,有什么错误或者做的不好的地方,还请见谅。
这个是实现这个模块的代码。但是感觉自己写的好繁琐,等一会儿适当修改一下。
2018年1月27日11:57:35,忙别的事情去了。
def fenxi(filename):
try:
f=open(filename,‘rb‘)
print ‘start--------‘
i=0
p1=""
p2=""
p3=""
p4=""
p=""
while True:
t=f.read(1)
t1=t.encode(‘hex‘)
if i==0:
p1=t1
if i==1:
p2=t1
if i==2:
p3=t1
if i==3:
p4=t1
i=i+1
if i<4:
p=p+" "
if i==4:
break
pass
p=p4+" "+p3+" "+p2+" "+p1
print "Magic Number:",p
i=0
p1=""
p2=""
p3=""
p4=""
p=""
while True:
t=f.read(1)
t1=t.encode(‘hex‘)
if i==0:
p1=t1
if i==1:
p2=t1
if i==2:
p3=t1
if i==3:
p4=t1
i=i+1
if i<4:
p=p+" "
if i==4:
break
pass
p=p4+" "+p3+" "+p2+" "+p1
print "FileSize:",p
except IOError:
print "This is bad for input ‘",name,"‘."
print "You can enter -h for help."
2.第二个模块
![技术分享图片](http://t1.aixinxi.net/o_1c4raf87m1qb53ub1bn03hes46a.png-j.jpg)
###1.Chunk Type
String Chunk 的标识符,默认是00 08 00 03
![技术分享图片](http://t1.aixinxi.net/o_1c4t961av1sqkc3bqb31ptoqrfa.png-j.jpg)
2.Chunk Size
String Chunk的大小。
![技术分享图片](http://t1.aixinxi.net/o_1c4t97kka6eu6is1ooa1cdq1b77a.png-j.jpg)
![技术分享图片](http://t1.aixinxi.net/o_1c4ta8i7g1atjkgo1krgjln1vjma.png-j.jpg)
3.String Count
字符串的个数。
![技术分享图片](http://t1.aixinxi.net/o_1c4tabv5oihr1agl12ag1u8a1dr1a.png-j.jpg)
4.Style Count
样式的个数
![技术分享图片](http://t1.aixinxi.net/o_1c4tbuj8p3hatub1job14ambm3a.png-j.jpg)
![技术分享图片](http://t1.aixinxi.net/o_1c4tc06m81shmvj81gd7dqd1r6ga.png-j.jpg)
5.Unknow
![技术分享图片](http://t1.aixinxi.net/o_1c4tc2oq8nmlnhl12g1fe8bena.png-j.jpg)
![技术分享图片](http://t1.aixinxi.net/o_1c4tc4cpf1dv216076an125q214a.png-j.jpg)
6.String Pool Offset
首部偏移量,也就是String Chunk的位置。
![技术分享图片](http://t1.aixinxi.net/o_1c4tcgkpu1m5d5rm14uc3db1g55a.png-j.jpg)
![技术分享图片](http://t1.aixinxi.net/o_1c4tcn54mdmd1834jjvkpb1fka.png-j.jpg)
7.Style Pool Offset
样式偏移,但是因为样式没有。所以这里全部为0
8.String Offsets
这个是字符串偏移,大小就是String count*4个bytes
![技术分享图片](http://t1.aixinxi.net/o_1c4te093usgq1s8513hes8cucva.png-j.jpg)
9.常量池
这个就是最主要的地方了。不过中间有一个0的空字符串。需要注意,然后使用一个循环就可以简单的分析出来了。
这里帖出代码部分。
while True:
t1=f.read(1)
t2=f.read(1)
tf1=t1.encode(‘hex‘)
tf2=t2.encode(‘hex‘)
p1=tf2+tf1
ph=int(p1, 16)
p3=""
i=0
while True:
t=f.read(1)
t1=t.encode(‘hex‘)
p=int(t1, 16)
p3=p3+chr(p)
t=f.read(1)
i=i+1
if i==ph:
break
pass
print "first string:",p3
t=f.read(2)
if l==12:
t=f.read(4)
l=l+1
if l==x-1:
break
运行结果展示:
![技术分享图片](http://t1.aixinxi.net/o_1c4ttibvi6s7tg6enjiup1292a.png-j.jpg)
![技术分享图片](http://t1.aixinxi.net/o_1c4ttk2stnrb1nma1alt19u2apa.png-j.jpg)
3.第三个模块 Resourceld Chunk
![技术分享图片](http://t1.aixinxi.net/o_1c4tuf7o5h2djuk173goukc5ba.png-j.jpg)
这个Chunk主要是存放的是AndroidManifest中用到的系统属性值对应的资源Id
3.1 Chunk Type
和其他Chunk一样,都有特征值,Resourceld Chunk的特征值是:0x00080108
![技术分享图片](http://t1.aixinxi.net/o_1c4tusbp913jb191la0otpm1b5ea.png-j.jpg)
3.2 Chunk Size
Size大小没有什么好解释的。
![技术分享图片](http://t1.aixinxi.net/o_1c4tv90jkhng1bcr1qurmjr10ana.png-j.jpg)
3.3Resourcelds
![技术分享图片](http://t1.aixinxi.net/o_1c4u0g6be1thrd4dq81pvt1ma4a.png-j.jpg)
![技术分享图片](http://t1.aixinxi.net/o_1c4u0l2uu36sq2h1dhi14t8106ra.png-j.jpg)
这里可以根据id在frameworks\base\core\res\res\values\public.xml中查找到相对应的string。
一下是简单的代码模块:
a=p/4-2
i1=0
while True:
i=0
p1=""
p2=""
p3=""
p4=""
p=""
while True:
t=f.read(1)
t1=t.encode(‘hex‘)
if i==0:
p1=t1
if i==1:
p2=t1
if i==2:
p3=t1
if i==3:
p4=t1
i=i+1
if i==4:
break
pass
p=p4+p3+p2+p1
p5=p4+" "+p3+" "+p2+" "+p1
p=int(p, 16)
print "123id:",p,"bytes","hex:",p5
i1=i1+1
if i1==a:
break
4.第四个模块
![技术分享图片](http://t1.aixinxi.net/o_1c4u176rcq9ng9c9u5uhdbnga.png-j.jpg)
这个Chunk主要包含一个AndroidManifest文件中的命令空间的内容
4.1 Chunk Type
特征码,这里不强调了。 特征码是00 10 01 00。
![技术分享图片](http://t1.aixinxi.net/o_1c4u1ftk71uq419to8po1bpo4qna.png-j.jpg)
4.2 Chunk Size
Chunk的大小。
![技术分享图片](http://t1.aixinxi.net/o_1c4u1ii0d1unhgsc6ss1i2b157aa.png-j.jpg)
4.3 Line Number
在AndroidManifest文件中的行号
![技术分享图片](http://t1.aixinxi.net/o_1c4u1t3ul191od9ti498j1c4na.png-j.jpg)
4.4Unknown
未知区域,一般是ffff
![技术分享图片](http://t1.aixinxi.net/o_1c4u1ubh2ga4991ts5cav9u5a.png-j.jpg)
4.5 Prefix
命名空间的前缀
![技术分享图片](http://t1.aixinxi.net/o_1c4u27fv4v3r96al5a1arkj8ea.png-j.jpg)
4.6Uri
命名空间的Urk
![技术分享图片](http://t1.aixinxi.net/o_1c4u2ems7nst319kdnir7ugra.png-j.jpg)
5.第五个模块
这个模块主要是为了存放标签信息
这里要啰嗦了。第五个模块要写完的时候,突然鼠标的返回键被按到了。我都在想是不是应该在本地写了,而不是在云端写,太感人了这个。伤心。准备偷懒了。
![技术分享图片](http://t1.aixinxi.net/o_1c4vqek6a10e5i9q5rt1v1ndl4a.png-j.jpg)
5.1 Chunk Type
标志字段,固定字符。
00 10 01 02
5.2 Chunk Size
Chunk 大小
5.3 Line Number
行数,和上一个段一样
5.4 Unknown
位置区域
5.5Namespace Uri
标签用的uri,但是也有可能是返回 ff ff ff ff。
代码实现:
i=0
p1=""
p2=""
p3=""
p4=""
p=""
while True:
t=f.read(1)
t1=t.encode(‘hex‘)
if i==0:
p1=t1
if i==1:
p2=t1
if i==2:
p3=t1
if i==3:
p4=t1
i=i+1
if i==4:
break
pass
p=p4+p3+p2+p1
p=int(p, 16)
try :
print "Namespace Uri:",list[p]
except IndexError:
print "Namespace Uri is nothing"
![技术分享图片](http://t1.aixinxi.net/o_1c4vrd0stg5t1jsjvcqjsf50ra.png-j.jpg)
5.6 name
标签名称字段
![技术分享图片](http://t1.aixinxi.net/o_1c4vrfl2d1hpj1hqq183m97g16sma.png-j.jpg)
5.7 flags字段
标识是开始flags还是结束flags
![技术分享图片](http://t1.aixinxi.net/o_1c4vrhl1t66fhj6qmc1vdsgv3a.png-j.jpg)
5.8 Attribute Count
包含属性的个数
![技术分享图片](http://t1.aixinxi.net/o_1c4vrnnsl1n2h19ku157v9bbaqta.png-j.jpg)
5.9 Class Attribute
标签包含的类属性
![技术分享图片](http://t1.aixinxi.net/o_1c4vs6e53h6r1ql10dp1hrk1ekta.png-j.jpg)
5.10Attributes Attribute
属性内容。包括NamespaceUri,Name,ValueString,type,Data,这五个字段。
![技术分享图片](http://t1.aixinxi.net/o_1c4vuq1sj139con61la41d29rra.png-j.jpg)
6.第六个模块
![技术分享图片](http://t1.aixinxi.net/o_1c4vunqga1jgq6r91j2414nv1c80a.png-j.jpg)
这个和第五个块一样。
![技术分享图片](http://t1.aixinxi.net/o_1c4vvs4jebbt1mmeo1h1gfk4vja.png-j.jpg)
7.第七个模块
因为是和之前的模块一样这里就不做解释了
![技术分享图片](http://t1.aixinxi.net/o_1c5005t11cjf1vh21ij3122b1tr8a.png-j.jpg)
收获
##python
1.python右移的方式
2.python格式转换
3.对二进制模块分析
4.这个是最大的收货,得到了一个xml文件分析工具。
5.github地址:xml.py文件分析
结束语
感觉这里需要的内容很多,就得要分成很多小块来说。为什么这里要写关于xml的分析呢,因为加固的目的就是为了防止反编译。那么我们可以针对反编译软件进行针对化加固,在下一个小块将会详细讲解。
以上是关于android 12+从后台启动FGS限制的主要内容,如果未能解决你的问题,请参考以下文章
为啥从 firebase 控制台发送的通知能够绕过 android 后台任务限制? - 反应原生火力基地 -