记安卓入门

一、常用工具

ApktoolKit
Apkide
JEB
logcat

二、安卓五层架构

参考文献:Android系统五层架构_android分为几个层-CSDN博客

安卓系统五层架构:从上到下依次为应用层、应用架构层、系统运行库层、硬件抽象层、Linux内核层

image.png

1. 应用层(System Apps)

系统内置应用程序以及非系统级的应用程序都属于应用层,负责与用户进行直接交互,通常使用Java开发

2. 应用框架层 (Java API Framework)

API(Application Programming Interface)
应用框架层提供开发所需API,平时开发都是调用这一层提供的API(包括系统应用)。这一层由Java开发,可以称为Java Framework。

主要组件如下:
image.png

3. 系统运行库层

系统运行库层分为 C/C++程序库和Android运行时库

  1. C/C++程序库
    image.png

  2. Android运行时库

运行时库分为核心库和ART(安卓运行时库:Android RunTime)(5.0之后,Dalvik虚拟机被ART取代)。核心库提供Java语言核心库的大多数功能

4. 硬件抽象层(HAL/HIDL)

硬件抽象层是位于操作系统内核与硬件电路之间的接口层,其目的在于将硬件抽象化,为了保护硬件厂商的知识产权,它隐藏了特定平台的硬件接口细节,为操作系统提供虚拟硬件平台,使其具有硬件无关性,可在多种平台上进行移植。 从软硬件测试的角度来看,软硬件的测试工作都可分别基于硬件抽象层来完成,使得软硬件测试工作的并行进行成为可能。通俗来讲,就是将控制硬件的动作放在硬件抽象层中。

5. Linux内核层

Android 的核心系统服务基于Linux 内核,在此基础上添加了部分Android专用的驱动。系统的安全性、内存管理、进程管理、网络协议栈和驱动模型等都依赖于该内核。

三、APK包体基本结构

最小基本五个结构:

META-INF:apk签名文件,是apk正盗版的唯一标识
AndroidManifest.xml:配置清单文件,标识者一个软件有多少组件/服务、界面
classese.dex:apk的代码所在,执行代码/业务逻辑/算法所在,由Java代码编译之后转化生成(逆向的核心所在)
resources.arsc:资源文件/字符文件
/res:图片/画面文件

/assets:一些额外的文件
/lib:armeabi-v7a基本通用所有Android设备,arm64-v8a只适用于64位Android设备,x86常见用Android模拟机,其中的.so文件是c或c++编译的动态链接库文件

反编译后:

/res:由resources.arsc反编译
/smali:由classes.dex反编译

四、AndroidMainfest.xml结构

AndroidMainfest.xml文件是整个应用程序的信息描述文件,定义了应用程序中包含的Activity,Service,Content provider和BroadcastReceiver组件信息,描述了package中暴露的组件,各自的实现类,各种能1被处理的数据和启动位置

属性 定义
versionCode 版本号,主要用于更新,例如:12
versionName 版本名:展示给用户看,例如:1.2
package 包名,例如:com.example.demo
uses-permission android:name="" 应用权限,例如:android.permission.INTERNET 代表网络权限
android:label="@string/app_name" 应用名称
android:icon="@mipmap/ic_launcher" 应用图标路径
android:debuggable="true" 应用是否开启debug权限

如何寻找启动类?

在AndroidManifest.xml中寻找:

标签:<intent-filter>

关键点:<action android:name="android.intent.action.MAIN" />

五、

Activity的生命周期

函数名称 描述
onCreate() 一个Activity启动后第一个被调用的函数,常用来在此方法中进行Activity的一些初始化操作。例如创建View,绑定数据,注册监听,加载参数等。
onStart() 当Activity显示在屏幕上时,此方法被调用但此时还无法进行与用户的交互操作。
onResume() 这个方法在onStart()之后调用,也就是在Activity准备好与用户进行交互的时候调用,此时的Activity一定位于Activity栈顶,处于运行状态。
onPause() 这个方法是在系统准备去启动或者恢复另外一个Activity的时候调用,通常在这个方法中执行一些释放资源的方法,以及保存一些关键数据。
onStop() 这个方法是在Activity完全不可见的时候调用的。
onDestroy() 这个方法在Activity销毁之前调用,之后Activity的状态为销毁状态。
onRestart() 当Activity从停止stop状态恢进入start状态时调用状态。

image.png

六、 动态调试及Log插桩

jeb调试

调试快捷键

ctrl + b 下断点
F6        步过
ctrl + F6 步进
F7从方法中跳出来
F8
ctrl + R运行到光标处

注意调试过程中类似于:equalsIgnoreCase(sn); 和equals()相似,前者是忽略大小写的版本

debug模式启动

adb shell am start -D -n com.zj.wuaipojie/.ui.MainActivity

adb shell am start -D -n
adb shell am start -D -n 包名/类名
am start -n 表示启动一个activity
am start -D 表示将应用设置为可调试模式

log插桩

定义:log插桩1是指在反编译apk的时候,在对应的smali文件里,添加相应的smali代码,将程序中的关键信息,以log日志的形式输出


invoke-static {对应寄存器}, Lcom/mtools/LogUtils;->v(Ljava/lang/Object;)V

七、签名校验机制对抗

1.什么是校验

开发者在数据传送时采用的一种校正数据的一种方式

常见的校验:签名校验(最常见)、dexcrc校验、apk完整性校验、路径文件校验等

2.什么是apk签名

apk签名可以证明对apk的所有权和控制权,可用于安装和更新应用。
在android设备上,没有被签名的app不能安装。在安装apk的时候,软件包管理器也会验证apk是否已经被正常签名,并通过签名证书和数据摘要验证是否合法没有被篡改

主要作用:

  1. 证明APK所有者
  2. 允许Android市场和设备校验apk正确性

3.什么是签名校验

如何判断是否有签名校验

不做任何修改,直接签名安装,如果应用闪退则说明大概率有签名校验
一般普通的签名校验会导致闪退、黑屏、卡启动页等,狠人作者会直接rm -rf /

4.签名校验对抗方法

芽衣的帖子 - 吾爱破解 - 52pojie.cn

方法一:核心破解插件,不签名安装应用 (某些软件检测META-INF里面文件的值)
方法二:一键过签名工具,例如MT、NP、ARMPro、CNFIX、Modex的去除签名校验功能
方法三:具体分析签名校验逻辑(手撕签名校验)
方法四:io重定向--VA&SVC:ptrace+seccomp
SVC的TraceHook沙箱的实现&无痕Hook实现思路
方法五:去作者家严刑拷打拿到.jks文件和密码(jks:签名时的密钥文件)

5.手动实现PM代理

6.IO重定向

当读取A文件的时候指向B文件

io重定向:
virjarRatel/ratel-core: 平头哥的核心代码
asLody/VirtualApp: Virtual Engine for Android(Support 14.0 in business version)

作用:

  1. 让文件只能读不能写
  2. 禁止访问文件
  3. 路径替换

具体实现

  1. 过签名检测(让它去读取原包)
  2. 风控对抗(例如:一个文件记录App启动的次数)
  3. 过Root检测,Xposed检测(文件不可取)

7.root检测

反制手段
1.算法助手、对话框取消等插件一键hook
2.分析具体的检测代码
3.利用IO重定向使文件不可读
4.修改Andoird源码,去除常见指纹

常用的检测是否root:

fun isDeviceRooted(): Boolean {
    return checkRootMethod1() || checkRootMethod2() || checkRootMethod3()
}

fun checkRootMethod1(): Boolean {
    val buildTags = android.os.Build.TAGS
    return buildTags != null && buildTags.contains("test-keys")
}

fun checkRootMethod2(): Boolean {
    val paths = arrayOf("/system/app/Superuser.apk", "/sbin/su", "/system/bin/su", "/system/xbin/su", "/data/local/xbin/su", "/data/local/bin/su", "/system/sd/xbin/su",
            "/system/bin/failsafe/su", "/data/local/su", "/su/bin/su")
    for (path in paths) {
        if (File(path).exists()) return true
    }
    return false
}

fun checkRootMethod3(): Boolean {
    var process: Process? = null
    return try {
        process = Runtime.getRuntime().exec(arrayOf("/system/xbin/which", "su"))
        val bufferedReader = BufferedReader(InputStreamReader(process.inputStream))
        bufferedReader.readLine() != null
    } catch (t: Throwable) {
        false
    } finally {
        process?.destroy()
    }
}

8.模拟器检测:

fun isEmulator(): Boolean { 
        return Build.FINGERPRINT.startsWith("generic") || Build.FINGERPRINT.startsWith("unknown") || Build.MODEL.contains("google_sdk") Build.MODEL.contains("Emulator") || Build.MODEL.contains("Android SDK built for x86") || Build.MANUFACTURER.contains("Genymotion") || Build.HOST.startsWith("Build") || Build.PRODUCT == "google_sdk" 
        }

模拟器检测对抗:模拟器检测对抗

9.反调试检测

[原创]对安卓反调试和校验检测的一些实践与结论-Android安全-看雪-安全社区|安全招聘|kanxue.com

安卓系统自带调试检测函数

fun checkForDebugger() {  
    if (Debug.isDebuggerConnected()) {  
        // 如果调试器已连接,则终止应用程序  
        System.exit(0)  
    }  
}

debuggable属性

public boolean getAppCanDebug(Context context)//上下文对象为xxActivity.this
{
    boolean isDebug = context.getApplicationInfo() != null &&
            (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
    return isDebug;
}

ptrace检测

int ptrace_protect()//ptrace附加自身线程 会导致此进程TracerPid 变为父进程的TracerPid 即zygote
{
    return ptrace(PTRACE_TRACEME,0,0,0);;//返回-1即为已经被调试
}

每个进程同时刻只能被1个调试进程ptrace  ,主动ptrace本进程可以使得其他调试器无法调试

调试进程名检测

int SearchObjProcess()
{
    FILE* pfile=NULL;
    char buf[0x1000]={0};

    pfile=popen("ps","r");
    if(NULL==pfile)
    {
        //LOGA("SearchObjProcess popen打开命令失败!\n");
        return -1;
    }
    // 获取结果
    //LOGA("popen方案:\n");
    while(fgets(buf,sizeof(buf),pfile))
    {

        char* strA=NULL;
        char* strB=NULL;
        char* strC=NULL;
        char* strD=NULL;
        strA=strstr(buf,"android_server");//通过查找匹配子串判断
        strB=strstr(buf,"gdbserver");
        strC=strstr(buf,"gdb");
        strD=strstr(buf,"fuwu");
        if(strA || strB ||strC || strD)
        {
            return 1;
            // 执行到这里,判定为调试状态

        }
    }
    pclose(pfile);
    return 0;
}

frida检测

xxr0ss/AntiFrida: 一些Frida检测手段

posted @ 2025-06-26 14:51  vstral  阅读(57)  评论(0)    收藏  举报