安全矩阵

 找回密码
 立即注册
搜索
查看: 2545|回复: 0

【移动安全】程序代码安全测试方法

[复制链接]

855

主题

862

帖子

2940

积分

金牌会员

Rank: 6Rank: 6

积分
2940
发表于 2021-3-31 10:36:23 | 显示全部楼层 |阅读模式
本帖最后由 Delina 于 2021-3-31 10:37 编辑

原文链接:【移动安全】程序代码安全测试方法
1.1运行环境
1、Android root环境检测
  • 检测目的
检测APP运行是否对Android ROOT环境运行检测。
  • 检测方法与步骤
(1)将被测APP安装在Android ROOT的运行环境中;
(2)运行APP,确认是否能够正常运行并提示用户。
测试方法1:反编译APP源代码,查看是否存在检测root运行环境的代码。通常要在root设备上找到su文件,文件检测是最常见的检测方法,包括检查busybox并尝试打开su文件,具体操作如下。
(1)查看系统是否是测试版
我们可以查看发布的系统版本,是test-keys(测试版),还是release-keys(正式版)。
可以先在adb shell中运行下命令查看:


这个返回结果“release-keys”,代表此系统是正式版。
在代码中的检测方法如下:
  1. public static boolean checkDeviceDebuggable() {
  2.     String buildTags = android.os.Build.TAGS;
  3.    if (buildTags != null && buildTags.contains("test-keys")) {
  4.         Log.i(LOG_TAG, "buildTags=" + buildTags);
  5.        return true;
  6.    }
  7.     return false;
  8. }
复制代码

若是非官方发布版,很可能是完全root的版本,存在使用风险。
(2)检查是否存在Superuser.apk
Superuser.apk是一个被广泛使用的用来root安卓设备的软件,所以可以检查这个app是否存在。检测方法如下:
  1. public static boolean checkSuperuserApk() {
  2.     try {
  3.         File file = new File("/system/app/Superuser.apk");
  4.         if (file.exists()) {
  5.           Log.i(LOG_TAG,"/system/app/Superuser.apk exist");
  6.             return true;
  7.         }
  8.     } catch (Exception e) {
  9.     }
  10.    return false;
  11. }
复制代码

(3)检查su命令
su是Linux下切换用户的命令,在使用时不带参数,就是切换到超级用户。如下如图所示:
​​
通常我们获取root权限,就是使用su命令来实现的,所以可以检查这个命令是否存在。这样,系统就会在PATH路径中搜索su,如果找到,就会执行,执行成功后,就是获取到真正的超级权限了。
  1. public static synchronized boolean checkGetRootAuth() {
  2.     Process process = null;
  3.     DataOutputStream os = null;
  4.     try {
  5.         Log.i(LOG_TAG, "to exec su");
  6.         process = Runtime.getRuntime().exec("su");
  7.         os = new DataOutputStream(process.getOutputStream());
  8.         os.writeBytes("exit\n");
  9.         os.flush();
  10.         int exitValue = process.waitFor();
  11.         Log.i(LOG_TAG, "exitValue=" + exitValue);
  12.         if (exitValue == 0) {
  13.             return true;
  14.         } else {
  15.             return false;
  16.         }
  17.     } catch (Exception e) {
  18.         Log.i(LOG_TAG, "Unexpected error - Here is what I know: "
  19.                 + e.getMessage());
  20.         return false;
  21.     } finally {
  22.         try {
  23.             if (os != null) {
  24.                 os.close();
  25.             }
  26.             process.destroy();
  27.         } catch (Exception e) {
  28.             e.printStackTrace();
  29.         }
  30.     }
  31. }
复制代码

这种检测su的方法应该是最靠谱的,不过,也有个问题,就是在已经root的设备上,会弹出提示框,请求给app开启root权限。

测试方法2:在真机中安装并运行APP,查看APP是否对root运行环境进行检测,是否提示用户APP在不安全的环境下运行,让运行选择,root环境检测结果如下:


  • 检测结论
在步骤(1)后,如果APP如法安装,或在步骤(2)后,如果APP在root系统环境中运行,在root环境提示,则本项检测结果为“通过”,否则为“不通过”。
  • 修复建议
通过多种方法检测root环境,如果发现APP在root环境中运行,弹窗提示用户APP在不安全环境下运行,或者禁止安装和运行。
2.Android模拟器环境检测
  • 检测目的
检测APP运行时,是否对Android模拟器环境运行检测。
  • 检测方法与步骤
(1)将被测APP安装在Android模拟器中;
(2)运行APP,确认是否能够正常运行并提示用户。
在模拟器中安装并运行APP,一旦发现运行环境是模拟器,将提示用户请勿在模拟器、虚拟机中运行APP。
  • 检测结论
在步骤(1)后,如果APP无法安装,或在步骤(2)后,APP在模拟器上无法运行,并存在模拟器检测提示,则本项测试结果为“通过”,否则为“不通过”。
  • 修复建议
APP运行时对模拟器环境进行检测,如果发现在模拟器环境中运行,弹窗提示用户APP在不安全环境下运行,或者禁止在模拟器中安装或者运行。
3.Android挂钩框架环境检测
  • 检测目的
检测APP是否存在逆向框架检测机制。
  • 检测方法与步骤
(1)将被测APP安装在装有逆向框架的环境中;
(2)运行APP,确认是否能够正常运行并提示用户。
测试方法1:反编译APP源代码,查看在APP代码中是否存在检测逆向框架的代码。用packageManager类检测包名来判断是否安装了逆向框架。
  1. if(item.packageName.equals("de.robv.android.xposed.installer")){
  2. Log.d("HookTest","检测到您的设备已安装exposed框架");
  3. }
  4. if(item.packageName.equals("com.saurik.substrate")){
  5. Log.d("HookTest","检测到您的设备已安装substrate框架");
  6. }
复制代码

测试方法2:在已安装逆向框架的手机上安装并运行APP,查看是否提示用户APP在不安全环境下运行。开启xpoesd如果打不开APP或者无法正常使用 ,就是做了xpoesd检测。

  • 检测结论
在步骤(1)后,如果APP无法安装,或在步骤(2)后,如果存在逆向框架的检测提示,则本项测试结果为“通过”,否则为“不通过”。
  • 修复建议
在APP代码中实现检测逆向框架的机制,一旦检测到手机安装了逆向框架,弹出提示告知用户运行环境不安全,让用户自己选择是否继续操作。
1.2防反编译1.反编译工具检测
  • 检测目的
检测APP是否可以防止反编译工具,是否具有防逆向保护措施。
  • 检测方法与步骤
(1)通过反编译工具对apk文件进行反编译,查看是否具有防逆向保护措施。
JADX是一款非常好用的反编译的工具jadx。jadx的功能非常强大,可以满足日常反编译需求。jadx优点:
  • 图形化的界面。
  • 拖拽式的操作。
  • 反编译输出java代码。
  • 导出Gradle工程。
将apk文件拖到jadx中,如果APP没有防逆向保护措施,就会出现反编译的源代码,如下图所示。

(2)通过IDAPro等反汇编工具对动态库so文件进行反汇编,查看APP是否具有防反汇编的能力。
为了提高APP的安全性,通常会将核心功能放在Native层实现,因此,防止动态库反汇编也是非常有必要的,常用的防范方法是将so文件导出函数加密。
加密前动态库so反汇编:

  • 检测结论
在步骤(2)后,如果APP的dex文件和so文件无法正常反编译或者APP经过加固处理,则本项测试结果为“通过”,否则为“不通过”。
  • 修复建议
对APP文件结构进行变形或加密,让反编译工具无法识别,或者对APP文件进行加固处理。
2.代码混淆检测
  • 检测目的
检测APP反编译后的源代码是否经过混淆处理。
  • 检测方法与步骤
通过反编译工具对APP进行反编译,查看代码中的类、字段和方法是否经过混淆处理。
  • 检测结论
如果反编译后的源代码的类、字段和方法使用a、b、c、d等无意义的字符重命名,如下图,则本项测试结果为“通过”,否则为“不通过”。

  • 修复建议
对APP源代码进行混淆。
3.混淆强度检测
  • 检测目的
检测APP反编译后源代码的混淆强度,查看是否能够有效地保护代码安全。
  • 检测方法与步骤
(1)检测dex文件代码中所有的类名、函数名、字段、方法,是否都经过混淆处理,例如反编译后无法正常识别java层函数功能。
(2)检测so文件中所有的类名、函数名、字段、方法,是否都进行了混淆处理,例如反汇编后无法正常识别native层函数功能。
  • 检测结论
在步骤(2)后,如果反编译后代码能够识别出APP函数的功能,如下图所示,则本项测试结果为“不通过”,否则为“通过”。


  • 修复建议
这对dex文件和so文件的类名、函数名、字段、方法进行高强度混淆。
4.关键代码(敏感段落和数据保护)检测
  • 检测目的
检测APP是否对关键代码和数据实施有效的保护措施,是否暴露业务逻辑。
  • 检测方法与步骤
通过反编译工具对APP进行反编译,结合mainfest.xml配置文件,份子APP注册,登录、支付过程、加密过程、数据通信等关键功能代码,查看相关代码逻辑是否有明显的暴露。
对APP进行反编译后,如果APP没有对关键代码和数据进行保护,相关业务字符串将会以明文显示,容易暴露业务逻辑,如下图所示:

  • 检测结论
如果关键代码未暴露,并且关键数据经过加密和隐藏保护处理,则本项测试结果为“不通过”,否则为“通过”。
  • 修复建议
将APP关键代码进行隐藏、混淆、加壳等处理,从而无法逆向出重要的代码信息。
1.3防篡改1.程序文件防篡改检测
  • 检测目的
检测APP启动时是否进行了完整性的校验,是否对客户端代码、资源文件进行修改,是否具有防篡改机制。
  • 检测方法与步骤
(1)使用反编译工具AndroidKiller对目标文件进行反编译。用AndroidKiller打开目标文件,可自动反编译apk。

(2)修改相关代码,篡改AndroidManifest.xml、assets文件、res文件配置文件等。例如,修改login.html文件,将登录按钮,改为登录test,如下图所示:

(3)点击android-编译按钮,重新打包签名后再运行APP,查看结果。

  • 检测结论
在步骤(3)后,如果APP签名能够正常进行,则本项测试结果为“不通过”,否则为“通过”。
  • 修复建议
采用完整性校验技术对安装包进行校验,校验的对象包括原包中代码、资源文件、配置文件等所有文件,一旦校验失败,立即退出。
2.内存数据防篡改检测
  • 检测目的
检测APP运行时,内存中的关键代码和敏感数据是否能被篡改。
  • 检测方法与步骤
(1)将被测APP安装到被测的移动智能终端上,并与服务器端进行连接;
(2)动态分析调试代码逻辑,修改APP运行期间内存中的数据,查看运行结果,比如修改登录逻辑、任意密码是否能够登录成功。
  • 检测结论
在步骤(2)后,如果在APP运行期间,能够动态篡改内存中的敏感数据,或者修改数据能够改变代码逻辑,则本项测试结果为“不通过”,否则为“通过”。
  • 修复建议
增加内存保护措施,防止攻击者修改内存数据达到不正当的目的。
1.4防调试1.调试工具防护检测
  • 检测目的
检测APP是否可以利用动态调试工具加载调试。
  • 检测方法与步骤
(1)安装并运行APP,通过动态调试工具加载调试,查看是否可以正常调试。
例如,通过IDAPro动态调试APP的dex文件,查看是否存在调试工具防护功能,调试方法如下图所示。

(2)解压测试APP,把classes.dex拖到IDA Pro中,点击“OK”。
(3)接着,选择“Debugger”->“Debugger Options”->“Set specific options”,根据Androidmainfest文件找到该apk的入口
Activity“com.ecar.driver.ui.SplashActivity”进行设置,如图所示,设置好后点击“OK”。

(4)选择com.ecar.driver.ui.SplashActivity中的某一函数出下断点。
(5)在IDA中点击F9快捷键执行程序,程序会自动断到刚才下断点的地方。
注意,根Android官方文档,想调试apk中的dex代码,必须满足下面两个条件之一。
  • 根据APP的manifest来进行,如果application项中包含了Android:debuggable="true",具有android:debuggable="true"属性,那么该apk就处于可调试状态。
  • 当VM从framework中启动,系统属性ro.debuggable为1时,即可对系统中所有APP进行调试,也就是default.prop中ro.debuggbable的值为1.
  • 检测结论
在步骤(1)后,如果APP能够被调试工具调试,则本项测试结果为“不通过”,否则为“通过”。
  • 修复建议
增加反调试工具功能,通过判定查看TracerPid是否有数值,一旦发现TracerPid为0,就退出进程。
2.内存防护检测
  • 检测目的
检测APP是否具有内存防护功能,例如防内存转储。
  • 检测方法与步骤
启动APP,使用ps命令查看进程PID,使用gdb -p 命令挂载APP进程,再使用gcore指令转储内存。
如果内存有防护,那么转储将会失败。如果在内存转储过程中出现大量的警告,可以忽略警告,警告只是内存权限问题,不是内存转储防护。
  • 检测结论
如果能够内存转储成功,生成corefile文件,则本项测试结果为“不通过”,否则为“通过”。
  • 检测目的
通过监控/proc/pid/mem与/proc/pid/pagemep来防止内存转储。
1.5防注入1.进程保护检测
  • 检测目的
检测APP进程空间是否可以被注入第三方动态库so文件。
  • 检测方法与步骤
(1)将被测APP安装到被测移动智能测试终端,并启动应用进程;
(2)通过注入工具或脚本,将第三方动态库文件注入APP的进程空间,查看第三方so文件是否在进程的内存空间中。
  • 检测结论
在步骤(2)后,如果第三方动态库能够注入目标进程空间,则本项测试结果为“不通过”,否则为“通过”。
  • 修复建议
增加ptrace函数的检测功能,使第三方无法使用该函数附件进程。修改linker汇总的dlopen函数,防止第三方金慈宁宫so加载。定时检测APP加载的第三方so库,如果发现是被注入的so文件,程序进程立即报异常。空间是否可以被注入第三方动态库so文件。
  • 检测方法与步骤
(1)将被测APP安装到被测移动智能测试终端,并启动应用进程;
(2)通过注入工具或脚本,将第三方动态库文件注入APP的进程空间,查看第三方so文件是否在进程的内存空间中。
  • 检测结论
在步骤(2)后,如果第三方动态库能够注入目标进程空间,则本项测试结果为“不通过”,否则为“通过”。
  • 修复建议
增加ptrace函数的检测功能,使第三方无法使用该函数附件进程。修改linker汇总的dlopen函数,防止第三方金慈宁宫so加载。定时检测APP加载的第三方so库,如果发现是被注入的so文件,程序进程立即报异常。



回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-9-21 01:37 , Processed in 0.014218 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

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