抱歉,最近在忙各种备案的工作,一直抽不出时间进行更新。
不知攻,焉知防,要防御移动端攻击,首先要了解攻击者的技术手段,然后才能采取有效的安全措施。本章节主要介绍一下针对客户端的常见攻击手段,通过这些手段找出客户端的薄弱点,从而更好提高客户端的安全防护水平。
Android App在编译时系统会遍历应用中的文件计算其对应的 Hash 摘要,并将所的文件摘要进行 BASE64 编码后写入签名文件即MANIFEST.MF 文件。App运行时系统会校验文件的Hash是否正确,攻击者可能会为达到绕过收费,实现App多开等目的会对App进行解包篡改。
通过Apktool工具可将Android Ap进行解包反编译,攻击者可以修改后重新使用其进行打包。具体命令如下所示:
将App解包后的文件篡改后重新进行打包,因为文件的Hash值已经变动与原签名信息不匹配,无法通过App的签名校验的,这将导致篡改后的文件无法正常安装到设备,具体如下图所示。
为了保证篡改后的APK文件可以正常使用,攻击者会使用自己的签名文件重新对重打包后的应用进行签名,从而达到绕过APK安装时系统的签名校验目的。可利用apksigner工具对二次打包后的App进行重新签名。具体命令如下所示:
目前大多数的开发者会在APP运行时获取当前的的签名信息,并将获取到的与正版签名信息进行比对,以确保自己的App是受到二次打包重签名攻击。通常开发者检测到App被重打包篡改后,会对用户进行安全提醒。例如如下图所示:
攻击者会尝试各种方法绕过客户端的的签名校验。原理基本大致相同即篡改客户端签名校验的结果,从而达到欺骗客户端的目的。获取签名信息的方法如下:
获取签名信息最核心的代码是Signature[] signatures = packageInfo.signatures,常见篡改方式有两种:
1.反编译客户端找定位到签名校验处的代码,将判断逻辑更改为相反的形式。或者通过Hook的方式将检测返回值修改。签名校验示例代码如下图所示:
只要将返回结果全部更改为True即可通过客户端签名校验。如果应用的签名校验逻辑是放在动态库so中,同样的原理只要修改返回结果或者修改签名校验是的跳转逻辑就可达到绕过签名校验的目的。参考示例代码:
2.动态代理,即通过反射机制为其它对象提供一种控制某个对象的访问的方式,以实现Hook对系统API,当客户端调用系统API获取签名信息时将篡改后的签名信息替换为官方签名信息。
实现原理,即通过PackageManagerService服务简称PMS获取的的应用签名信息,可通过反射结合动态代理的的方式控制PMS返回值,从而达到替换签名的目的。
具体操作流程:创建一个和目标应用相同包名的新应用,里面用通过动态代理的方式实现PackageManager服务的替换,在触发getPackageInfo接口时将获取到签名信息使用目标应用的官方签名替换。具体流程如下图所示:
HookServiceWraper.smali中的代码主要功能为替换PackageManagerService服务。核心代码片段如下图所示:
ProxyHookPMS.smali中的主要功能为使用官方签名信息替换伪造的签名信息,核心片段代码如下图所示:
重打包后通过getPackageInfo获取函数签名时已被替换为合法的官方签名信息,即可绕过验签名的合法性校验。
该章节用使用到的示例代码和相关工具地址:https://github.com/aylhex/book-code
iOS App在打包过程中会对代码进行签名,苹果设备认可的证书签名的代码才能够被执行,否则在安装或者运行时会因为无法通过系统的签名校验而失败。重签名攻击即使用自己的证书重新对别人的应用进行签名,从而达到非法利用的目的。现方式就是将目标应用砸壳以后进行信息篡改然后攻击者重新使用自己的证书对篡改后的应用重新签名。
通过App store下载安装的应用都是经过苹果签名加密的,无法直接对其重新签名。需要在越狱的设备上使用砸壳工具对其进行砸壳后才可进行重新签名。砸壳后的应用解压目录如下图所示:
进行重新签名操作前,需要保证当前系统中有可用的签名证书,查看系统中已有证书命令如下所示:
执行命令后会列出当前系统中可以使用的证书清单,具体如下图所示:
攻击者为了实现应用多开通常会更改bundleId,以便和官方正版应用进行区分,达到在同一设备共存多个应用的目的。进入到repackage.app中编辑Info.plist文件中的Bundle identifier属性即可变更bundleId。具体如图所示:
为保证重签名以后能顺利通过苹果的校验,需要替换砸壳后repackage.app中的embedded.mobileprovision文件。使用Xcode创建新的项目选择重签名时要使用的证书将其打包编译成ipa包,然后解包拷贝其中的embedded.mobileprovision文件,用以替换掉砸壳应用repackage.app中的embedded.mobileprovision文件。有的应用砸壳后可能没有embedded.mobileprovisio文件,这种情况直接将新生成的embedded.mobileprovision放入其中即可。具体文件格式如下图所示:
生成授权文件entitlements.plist,并将生成的授权文件移动到repackage.app目录中,具体命令如下所示:
对砸壳后的应用repackage.app中的可执行文件进行重新签名操作,具体签名代码如下所示:
砸壳后应用中如包含动态库,还需要对动态库重新签名,具体代码如下所示:
如果遇到无法进行重签名的插件或者其它文件可以尝试将其直接删除。完成以上所有操作后对砸壳后的应用repackage.app整体进行重签名,签名之前需要将生成的授权文件entitlements.plist文件拷贝一份到Payload目录,然后使用以下代码进行重签名:
将重新签名后的repackage.app文件重新打包成ipa安装包,具体命令如下图所示
重新签名后的ipa包可通过xcode或者爱思助手等工具安装到设备,如果应用运行时闪退大概率是进行了重打包校验。常用的检测方有两种:方法一检测应用的bundleId是否发生了改变,方法二、检测证书的teamId是否发生了改变。针对bundleId变更校验,将bundleId更改为官方的值即可,如果是校验的teamId的值就要分析代码定位到具体位置将其返回结果patch即可。
apktool d demo.apk
-
o output
apktool b ouput
-
o new_demo.apk
apktool d demo.apk
-
o output
apktool b ouput
-
o new_demo.apk
apksigner sign
-
-
ks key.keystore
-
-
ks
-
key
-
alias key new_demo.apk
apksigner sign
-
-
ks key.keystore
-
-
ks
-
key
-
alias key new_demo.apk
public static byte[] getSignature(Context context) {
try
{
PackageInfo packageInfo
=
context.getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
Signature[] signatures
=
packageInfo.signatures;
if
(signatures !
=
null) {
return
signatures[
0
].toCharsString();
}
} catch (Exception e) {
}
return
null;
}
public static byte[] getSignature(Context context) {
try
{
PackageInfo packageInfo
=
context.getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
Signature[] signatures
=
packageInfo.signatures;
if
(signatures !
=
null) {
return
signatures[
0
].toCharsString();
}
} catch (Exception e) {
}
return
null;
}
public static boolean checkSignature(Context context){
if
(sign.equals(getAppSignature(context))){
return
true;
}
else
{
return
false;
}
}
public static boolean checkSignature(Context context){
if
(sign.equals(getAppSignature(context))){
return
true;
}
else
{
return
false;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2024-6-20 09:50
被FIGHTING安编辑
,原因: 错误更正