【工作】面试题整理 Android安全相关

Frida 和 Xposed 原理

Frida
Frida 是一个动态代码插桩工具,用于在运行时对应用程序进行分析和修改。其主要原理是通过注入一个代理(agent)到目标进程中,该代理可以执行用户定义的脚本,从而实现对目标进程的动态分析和修改。Frida 的注入过程包括以下步骤:

  1. 找到目标进程并使用 ptrace 跟踪目标进程。
  2. 获取 mmapdlopendlsym 等函数库的偏移。
  3. 在目标进程中申请一段内存空间,将 Frida agent 拷贝到该内存空间并执行。

Xposed
Xposed 是一个框架,用于在 Android 系统中动态修改应用程序的行为。其基本原理是通过修改 ART/Dalvik 虚拟机,将需要 hook 的函数注册为 Native 层函数。Xposed 在系统启动时加载 XposedBridge.jar,从而劫持 Zygote 进程及其创建的 Dalvik 虚拟机。Xposed 的工作流程包括:

  1. 替换 /system/bin/app_process 程序,控制 Zygote 进程。
  2. 在 Zygote 进程启动时加载 XposedBridge.jar
  3. 通过 JNI 方法 hookMethodNative 将 Java 函数变为 Native 函数,从而实现 hook。

Inline Hook、GOT Hook、Exception Hook 原理

Inline Hook
Inline Hook 是一种直接修改目标函数内部指令的 hook 方法。通过在目标函数的开头插入跳转指令,将执行流程转向自定义的函数。这种方法可以直接在函数内部进行修改,适用于对特定函数的精确控制。
GOT Hook
GOT(Global Offset Table)Hook 是通过修改动态链接库的全局偏移表来实现的 hook 方法。在动态链接过程中,函数的地址会通过 GOT 表进行查找。通过修改 GOT 表中的地址,可以将对目标函数的调用重定向到自定义的函数。
Exception Hook
Exception Hook 是通过捕获和处理异常来实现的 hook 方法。在目标进程中设置异常处理函数,当目标函数触发异常时,异常处理函数会拦截并处理该异常,从而实现对目标函数的 hook。

DEX 结构、ELF 结构、反编译过程

DEX 结构
DEX(Dalvik Executable)是 Android 应用程序的可执行文件格式。DEX 文件包含类、方法、字段等信息,以 Dalvik 字节码形式存储。DEX 文件的结构包括:

  • Header:包含文件标识、版本号等信息。
  • String Pool:字符串常量池。
  • Type Pool:类型池。
  • Method Pool:方法池。
  • Class Pool:类池。

ELF 结构
ELF(Executable and Linkable Format)是 Unix-like 系统中可执行文件的标准格式。ELF 文件的结构包括:

  • ELF Header:包含文件类型、架构等信息。
  • Program Header Table:描述如何加载程序到内存。
  • Section Header Table:描述文件的各个部分。

反编译过程
反编译是指将编译后的二进制文件转换回源代码的过程。对于 Android 应用程序,常见的反编译步骤包括:

  1. 使用 dex2jar 将 DEX 文件转换为 JAR 文件。
  2. 使用 jd-gui 或其他 Java 反编译工具查看 JAR 文件中的源代码。

Java 反射、静态代理和动态代理、类加载机制(双亲委派)

Java 反射
Java 反射允许程序在运行时访问、检测和修改类、接口、字段和方法的信息。通过反射,可以动态地创建对象、调用方法和访问字段。
静态代理和动态代理

  • 静态代理:通过在编译时创建代理类来实现代理功能。代理类实现了与目标类相同的接口,并在调用目标方法前后添加自定义逻辑。
  • 动态代理:通过在运行时动态生成代理类来实现代理功能。Java 提供了 java.lang.reflect.Proxy 类来生成动态代理。

类加载机制(双亲委派)
Java 的类加载机制采用双亲委派模型。当一个类加载器需要加载类时,它会先委托父类加载器尝试加载该类。如果父类加载器无法加载该类,子类加载器才会尝试加载。这种机制确保了 Java 核心类库的统一性。

安卓虚拟机(Dalvik 和 ART)、JIT 和 AOT

Dalvik 和 ART

  • Dalvik:Android 早期使用的虚拟机,基于寄存器的架构,使用 Dalvik 字节码。
  • ART:Android 5.0 及以上版本使用的虚拟机,基于 JIT(Just-In-Time)编译,直接将字节码编译为机器码,提高执行效率。

JIT 和 AOT

  • JIT(Just-In-Time Compilation):在运行时将字节码编译为机器码,提高执行效率。
  • AOT(Ahead-Of-Time Compilation):在编译时将字节码编译为机器码,生成可直接执行的文件。

HTTPS 证书校验(单向、双向校验)、中间人攻击

HTTPS 证书校验

  • 单向校验:客户端验证服务器的证书,确保服务器身份的真实性。
  • 双向校验:客户端和服务器互相验证对方的证书,确保双方身份的真实性。

中间人攻击
中间人攻击是指攻击者在通信双方之间进行拦截和篡改数据的攻击方式。HTTPS 通过证书校验和加密通信来防止中间人攻击。

安卓系统启动流程、Zygote 启动流程、APP 启动流程

安卓系统启动流程

  1. BootROM:初始化硬件,加载 Bootloader。
  2. Bootloader:加载内核。
  3. 内核:初始化系统,加载 init 进程。
  4. init 进程:解析配置文件,启动系统服务。

Zygote 启动流程

  1. 启动 Zygote 进程:由 init 进程启动,加载 Android 系统的核心库和资源。
  2. 预加载资源:加载常用的类和资源,提高应用启动速度。
  3. 创建子进程:通过 fork 创建子进程,启动应用程序。

APP 启动流程

  1. 启动 Activity:通过 Intent 启动 Activity。
  2. 加载资源:加载布局文件和资源。
  3. 初始化组件:初始化 View、Service 等组件。
  4. 启动服务:启动后台服务,如网络请求、数据处理等。

Activity 和 Service 的生命周期、Binder 通信机制

Activity 生命周期

  • **onCreate()**:创建 Activity。
  • **onStart()**:Activity 变为可见。
  • **onResume()**:Activity 开始与用户交互。
  • **onPause()**:Activity 即将失去焦点。
  • **onStop()**:Activity 不再可见。
  • **onDestroy()**:销毁 Activity。

Service 生命周期

  • **onCreate()**:创建 Service。
  • **onStartCommand()**:启动 Service。
  • **onBind()**:绑定 Service。
  • **onDestroy()**:销毁 Service。

Binder 通信机制
Binder 是 Android 系统中用于进程间通信(IPC)的机制。通过 Binder,一个进程可以调用另一个进程中的对象方法,实现跨进程的通信。Binder 机制包括:

  • Binder 驱动:内核模块,负责进程间的数据传递。
  • Binder Proxy:客户端的代理对象,用于与服务端进行通信。
  • Binder Stub:服务端的桩对象,用于接收客户端的请求并调用服务端的方法。

Java层和SO层是怎么hook的

在Android应用中,Java层和SO层的Hook技术是实现动态修改程序行为的常用手段。以下分别介绍这两种层的Hook方法及其原理:

Java层Hook

Java层的Hook主要通过修改字节码或利用Java的反射机制来实现。以下是一些常见的方法:

使用ASM框架

ASM是一个用于操作Java字节码的框架。通过ASM,可以在运行时动态修改类的字节码,从而实现Hook。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class HookExample implements Opcodes {
public static byte[] hookClass(byte[] classBytes) {
ClassReader cr = new ClassReader(classBytes);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS);
cr.accept(new HookClassVisitor(cw), 0);
return cw.toByteArray();
}

static class HookClassVisitor extends ClassVisitor {
public HookClassVisitor(ClassVisitor cv) {
super(ASM5, cv);
}

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (name.equals("methodToHook")) {
return new HookMethodVisitor(mv);
}
return mv;
}
}

static class HookMethodVisitor extends MethodVisitor {
public HookMethodVisitor(MethodVisitor mv) {
super(ASM5, mv);
}

@Override
public void visitInsn(int opcode) {
if (opcode >= IRETURN && opcode <= RETURN) {
// 在方法返回之前插入Hook代码
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("Hooked!");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
}
super.visitInsn(opcode);
}
}
}

SO层Hook

SO层的Hook通常使用动态库拦截技术,如LD_PRELOAD或使用Frida等工具。

使用Frida

Frida可以通过注入脚本到目标进程中,动态Hook函数。

示例代码

1
2
3
4
5
6
7
8
// Frida脚本示例
Interceptor.attach(Module.findExportByName("libexample.so", "functionToHook"), {
onEnter: function(args) {
console.log("Hooked functionToHook");
// 修改参数或返回值
args[0] = ptr(0x12345678);
}
});

Frida的原理

Frida是一种动态仪器框架,它允许你在运行时将脚本注入到本地和远程应用程序中。其工作原理如下:

  1. 注入脚本:Frida通过ptrace系统调用附加到目标进程,将脚本注入到进程中。
  2. 拦截函数:使用动态链接库和函数拦截技术,Frida可以在目标进程中Hook指定的函数。
  3. 通信机制:Frida提供了一个API,允许注入的脚本与外部工具进行通信,从而实现对目标进程的控制和数据收集。

加壳脱壳原理

加壳和脱壳是Android应用安全中的重要技术。加壳的目的是保护应用不被反编译和篡改,而脱壳则是为了分析和修改加壳后的应用。

加壳原理

加壳通常通过以下步骤实现:

  1. 加密DEX文件:将应用的DEX文件加密,防止直接反编译。
  2. 自定义加载器:编写一个自定义的类加载器,在应用启动时解密并加载DEX文件。
  3. 打包为SO文件:将加密的DEX文件和加载器打包为SO文件,增加反编译的难度。

脱壳原理

脱壳的过程通常包括:

  1. 提取加密的DEX文件:从加壳后的APK中提取加密的DEX文件。
  2. 获取解密密钥:通过逆向工程找到解密密钥或解密算法。
  3. 解密DEX文件:使用解密密钥或算法解密DEX文件,得到原始的DEX文件。

Inline Hook了解吗?简要说说, Got hook呢?说下原理

Inline Hook

Inline Hook是一种函数Hook技术,通过修改目标函数的开头部分指令,跳转到Hook函数,从而实现对目标函数的拦截和修改。

GOT Hook

GOT(Global Offset Table)Hook是利用动态链接过程中的GOT表进行Hook。GOT表存储了动态链接库中函数的地址,在程序运行时,通过修改GOT表中的地址,可以将对原函数的调用重定向到Hook函数。

第三代加壳dex2c和vmp能手动脱壳吗?说下脱壳细节

第三代加壳技术如DEX2C和VMP,通过将DEX字节码转换为C代码或使用虚拟机保护,增加了脱壳的难度。手动脱壳通常需要以下步骤:

  1. 分析加壳程序:使用反编译工具如IDA Pro或Ghidra分析加壳后的程序,了解其加密和加载逻辑。
  2. 提取加密数据:从加壳程序中提取加密的DEX数据或其他关键数据。
  3. 逆向加密算法:通过逆向工程还原加密算法,编写解密脚本。
  4. 模拟运行环境:在某些情况下,可能需要模拟加壳程序的运行环境,以正确解密和加载DEX文件。

说下elf文件和dex文件

ELF文件

ELF(Executable and Linkable Format)是Unix/Linux系统中可执行文件、目标文件和共享库的文件格式。ELF文件包含程序运行所需的所有信息,包括代码段、数据段、头部信息等。

DEX文件

DEX(Dalvik EXecutable)是Android平台上的可执行文件格式,用于存储Dalvik虚拟机的字节码。DEX文件包含类、方法、字段等信息,是Android应用的核心组成部分。

Frida是基于ptrace函数注入的,能说下ptrace这个函数吗?

ptrace是一个系统调用,用于进程跟踪和控制。它允许一个进程(如调试器)附加到另一个进程(如目标程序),并控制其执行、读取和修改其内存。Frida利用ptrace函数附加到目标进程,注入代码并进行Hook操作。

.ollvm混淆原理了解吗?说下如何对抗流程控制平坦化.

OLLVM(Obfuscator-LLVM)是一种基于LLVM的代码混淆工具,通过控制流平坦化、虚假控制流等技术保护代码不被逆向工程。

对抗流程控制平坦化

对抗流程控制平坦化的常用方法包括:

  • 静态分析:使用先进的静态分析工具,尝试还原原始的控制流图。
  • 动态分析:通过动态执行和调试,观察程序的实际行为,绕过混淆。
  • 模式匹配:识别常见的混淆模式,编写规则进行自动脱混。

了解反调试手段吗?说下如何反反调试(重点,问的很细)

反调试技术用于检测和阻止调试器附加到进程。常见的反调试手段包括:

  • 检测调试端口:检查特定的调试端口是否被占用。
  • 自带调试函数:使用自定义的调试检测函数。
  • TracerPid检测:检查/proc/self/status中的TracerPid值是否为0。
  • ptrace函数检测:尝试使用ptrace函数,检测是否被跟踪。

反反调试的方法包括:

  • 模拟正常行为:在检测过程中模拟正常的应用行为,绕过检测。
  • 修改检测逻辑:通过逆向工程修改反调试代码的逻辑。
  • 使用高级调试工具:如Frida等,能够在不触发反调试机制的情况下注入和调试。

说下Android的IPC机制

Android的IPC(Inter-Process Communication)机制主要包括以下几种:

Binder

Binder是Android系统中主要的IPC机制,具有以下优点:

  • 高效性:Binder机制在内核空间中实现,减少了用户空间和内核空间的数据拷贝。
  • 灵活性:支持多种通信方式,如单向通信、双向通信等。
  • 安全性:通过权限控制和身份验证,确保通信的安全性。

实现一次拷贝的过程

Binder在实现数据传输时,通过以下步骤实现一次拷贝:

  1. 用户空间到内核空间:发送方将数据从用户空间拷贝到内核空间的缓冲区。
  2. 内核空间到接收方用户空间:接收方从内核空间的缓冲区读取数据,完成数据传输。

说一下你对安卓里面的zygote的理解

Zygote是Android系统中的一个重要进程,负责fork出新的应用进程。Zygote在系统启动时被创建,预加载了系统资源和公共库,从而加快应用的启动速度。

Zygote的IPC通信机制为什么不采用Binder?

Zygote的IPC通信机制不采用Binder的原因主要包括:

  • 性能考虑:Zygote在fork子进程时,需要高效的进程创建机制。Binder机制在某些场景下可能引入额外的开销。
  • 设计目的:Zygote的主要目的是快速创建新的进程,而不是进行复杂的IPC通信。因此,它采用了更直接的fork机制。