0


移动安全面试题—hook技术

Frida

Frida 是一个动态代码插桩工具,可以用于在运行时修改应用程序的行为。它支持多种平台,包括 Windows、macOS、Linux、Android 和 iOS。Frida 的主要特点是跨平台性和动态性。它使用 JavaScript 作为脚本语言,允许用户在运行时快速编写和修改脚本。
实现原理:Frida 的底层是基于 Google 的 V8 JavaScript 引擎。它通过在目标进程中注入一个小型代理库(例如,Gadget)来与 V8 引擎进行通信。然后,Frida 通过 RPC 调用在目标进程中执行 JavaScript 脚本,从而实现对目标进程的 hook 和修改。

Frida是如何实现native函数hook

Frida 是一个动态二进制插桩(DBI)框架,它允许你在运行时改变应用程序的行为。Frida 支持多种平台(如 Windows、macOS、Linux、Android 和 iOS)和多种架构(如 x86、x64、ARM 和 ARM64)。Frida 可以实现对 Native 函数(如 C/C++ 编写的函数)的 Hook,从而修改或监控目标函数的行为。
Frida 实现 Native 函数 Hook 的主要步骤如下:

  1. 附加到目标进程:首先,Frida 需要附加到目标进程(或启动新的进程),这样它才能在进程内部执行插桩操作。Frida 提供了多种附加方式,如使用 frida.attach()(Python API)或 frida-trace(命令行工具)。
  2. 查找目标函数地址:为了 Hook Native 函数,需要首先找到目标函数在内存中的地址。Frida 提供了多种查找函数地址的方法,如使用 Module.findExportByName()(查找导出函数)或 Module.enumerateSymbols()(查找模块中的符号)。
  3. 编写 Hook 函数:编写一个 JavaScript 函数,用于替换或包装目标 Native 函数。这个 Hook 函数可以在目标函数执行前后插入自定义的逻辑,如修改参数、修改返回值或记录函数调用。
  4. 替换或包装目标函数:使用 Frida 的 Interceptor.attach() 函数将 Hook 函数绑定到目标函数的地址。这会导致目标函数被替换或包装,从而实现 Hook 功能。
  5. 卸载 Hook(可选):在完成 Hook 操作后,可以使用 Interceptor.detach() 函数卸载 Hook,恢复目标函数的原始行为。

下面是一个使用 Frida 的 Python API 实现 Native 函数 Hook 的简单示例:

import frida

# 目标进程的名称
target_process_name ="example"# 在目标进程中执行的 JavaScript 代码
js_code ="""
// 查找目标函数的地址
var target_function_address = Module.findExportByName("example_module", "example_function");

// 编写 Hook 函数
Interceptor.attach(target_function_address, {
    onEnter: function (args) {
        console.log("example_function called with arg0:", args[0].toInt32());
    },
    onLeave: function (retval) {
        console.log("example_function returned:", retval.toInt32());
    }
});
"""# 附加到目标进程
session = frida.attach(target_process_name)# 创建脚本并加载
script = session.create_script(js_code)
script.load()# 等待用户按下 Enterinput()# 卸载脚本并分离进程
script.unload()
session.detach()

在此示例中,我们首先附加到名为 “example” 的目标进程,然后查找名为 “example_function” 的 Native 函数的地址。接着,我们编写一个 Hook 函数,用于打印目标函数的参数和返回值。最后,我们将 Hook 函数绑定到目标函数的地址,实现 Hook 功能。

Frida 和 ptrace 的关系

Frida 和 ptrace 都是用于调试、分析和修改应用程序的工具,但它们的实现方式和使用场景有所不同。
Frida:
Frida 是一个跨平台的动态二进制插桩框架,主要用于动态地拦截、修改和监控应用程序的函数调用。Frida 使用 JavaScript 作为其脚本语言,允许用户编写自定义脚本来实现各种功能,例如:Hook Native 函数、修改内存、追踪函数调用等。Frida 可以跨平台工作,支持 Android、iOS、Windows、macOS 和 Linux 等操作系统。
ptrace:
ptrace 是 Linux 内核提供的一种进程跟踪和调试机制。通过 ptrace,一个进程可以监控和控制另一个进程的执行、修改其内存和寄存器等。ptrace 主要用于实现调试器(如 gdb)、系统调用追踪工具(如 strace)等。ptrace 主要局限于 Linux 平台。
Frida 与 ptrace 的关系:
尽管 Frida 和 ptrace 都可以用于进程调试、代码注入和内存修改,但它们之间的关系并不直接。Frida 在实现进程注入和代码修改时,可能会用到 ptrace(尤其是在早期版本中),但 Frida 的功能远远超出了 ptrace 所能提供的。Frida 提供了更高级别的抽象和跨平台支持,使得用户可以更方便地实现复杂的动态分析和代码修改任务。
总之,Frida 和 ptrace 都可以用于进程调试和代码修改,但 Frida 提供了更高级别的抽象和跨平台支持。在实现进程注入和代码修改时,Frida 可能会用到 ptrace,但它们之间的关系并不直接。

Xposed

Xposed 是一个运行在 Android 系统上的框架,允许用户在不修改 APK 的情况下修改应用程序的行为。Xposed 的主要特点是模块化和针对性。用户可以编写 Xposed 模块,针对特定应用程序或系统组件进行 hook 和修改。
实现原理:Xposed 通过修改 Android 系统的 Zygote 进程,使其在启动新的应用程序进程时加载 Xposed 框架。在加载过程中,Xposed 会读取已安装的模块,并在合适的时机调用模块中的 hook 函数。Xposed 的 hook 实现主要是基于 Android 的 Java 层,通过反射和代理技术来实现对目标方法的 hook。

Xposed为什么不能在Android8.0上使用?

Xposed 在 Android 8.0(Oreo)上不能直接使用的主要原因是 Android 系统在该版本中引入了一些重要的更改,特别是 Just-In-Time (JIT) 编译器和 Ahead-Of-Time (AOT) 编译器的优化,这些更改使得原始的 Xposed 框架与 Android 8.0 不兼容。
在 Android 8.0 中,Google 改进了 ART(Android Runtime)以提高性能和效率。这些改进包括对 JIT 编译器和 AOT 编译器的调整,以及对系统启动时的应用程序优化(App Optimization)的更改。由于 Xposed 框架主要依赖于修改 Android 系统的运行时行为,因此这些更改直接影响了 Xposed 框架的兼容性。
为了解决这个问题,Xposed 框架的开发者需要对框架进行重大更新,以适应 Android 8.0 中的更改。在一段时间的开发后,Xposed 框架的开发者发布了针对 Android 8.0 和更高版本的更新。自 Xposed v90-beta 版本开始,Xposed 框架已经支持 Android 8.0 及更高版本。
此外,您还可以考虑使用基于 Magisk 的 EdXposed 模块来在 Android 8.0 及更高版本上使用 Xposed 功能。EdXposed 是一个基于 Magisk 框架的 Xposed 模块,可以在 Android 8.0 及更高版本上实现 Xposed 功能。与传统的 Xposed 框架相比,EdXposed 具有更好的兼容性和更安全的系统修改方式。要使用 EdXposed,请确保您的设备已经安装了 Magisk,然后在 Magisk Manager 中搜索并安装 EdXposed 模块。安装完成后,您可以像使用传统的 Xposed 框架一样使用 EdXposed。

与 Frida 相比,Xposed 有以下不同之处:

  1. Hook 方法:Xposed 主要关注 Java 层的 Hook,而 Frida 同时支持 Java 层和 Native 层的 Hook。
  2. 跨平台支持:Frida 支持多个平台(如 Android、iOS、Windows、macOS 和 Linux),而 Xposed 仅支持 Android 平台。
  3. 安装和使用:Xposed 需要在 Android 设备上安装框架和 Xposed 安装器,安装过程相对复杂。而 Frida 可以通过简单地安装 frida-server 或将 frida-gadget 集成到目标应用中使用。
  4. 运行时性能:Xposed 直接修改 Android Runtime 的类加载机制,可能对系统性能产生较大影响。而 Frida 通过动态代码注入实现 Hook,对系统性能的影响相对较小。
  5. 动态和静态 Hook:Frida 是一种动态代码插桩框架,可以在运行时实时地对方法进行 Hook 和修改。而 Xposed 通常在系统启动时对目标方法进行 Hook,其 Hook 逻辑在编写模块时定义好,不太适合实时修改。

Inline Hook

Inline Hook 是一种二进制代码植入技术,通过修改目标函数的指令来实现 hook。这种技术在 Windows、Linux、macOS 等多种平台上都有应用。Inline Hook 的主要特点是对目标代码的直接修改,通常具有较高的隐蔽性和性能。
实现原理:Inline Hook 的实现通常包括以下几个步骤:

  1. 在目标函数的入口处保存原始指令。
  2. 将目标函数的入口处指令修改为跳转指令,跳转到自定义的 hook 函数。
  3. 在 hook 函数中执行自定义操作,然后执行保存的原始指令。
  4. 最后,通过跳转指令返回到目标函数的下一条指令。

这三种 hook 技术各有特点,适用于不同的场景。Frida 能够为跨平台的动态代码插桩提供支持,Xposed 专注于 Android 平台的应用程序和系统组件修改,而 Inline Hook 则适用于对二进制代码进行高效、隐蔽的植入。

Got表hook和inline hook区别

GOT(Global Offset Table)是一个在内存中的表,它存储了程序中使用到的外部库函数的地址。程序在运行时通过 GOT 来查找和调用外部库函数。GOT Hook 是一种通过修改 GOT 表中的函数地址来实现函数拦截的技术。
GOT Hook的原理如下:

  1. 查找目标程序的 GOT 表在内存中的位置。
  2. 定位需要 Hook 的函数在 GOT 表中的条目。
  3. 修改 GOT 表中的函数地址,使其指向自定义函数(Hook 函数)。
  4. 当目标程序调用被 Hook 的函数时,实际上会调用 Hook 函数。

GOT Hook与Inline Hook的区别

  1. 修改对象:GOT Hook 修改的是 GOT 表中的函数地址,而 Inline Hook 修改的是目标函数的指令。
  2. 适用范围:GOT Hook 主要用于 Hook 动态链接库中的函数,而 Inline Hook 可以用于 Hook 静态链接程序中的函数。
  3. 可检测性:Inline Hook 会直接修改目标函数的代码,因此更容易被安全检测工具发现。GOT Hook 修改的是 GOT 表,相对来说更难被检测。
  4. 兼容性:GOT Hook 主要适用于 ELF 格式的二进制文件(如 Linux 系统下的程序),而 Inline Hook 可以在多种平台和文件格式下使用。

两种 Hook 技术各有优缺点,实际应用中可以根据具体需求和目标程序的特点选择合适的方法。

riru和zygisk原理,他们有什么关系,有什么共同之处,有什么不同之处,优缺点是什么?回调的时机?

Riru

Riru 是一个使用 YAHFA 或 SandHook 作为基础的 Android Hook 框架,它主要通过在 native 层 hook zygote 进程实现对 Java 层的修改。在 zygote 进程启动过程中,Riru 会修改 OAT 文件的加载过程,将自定义的 dex 文件加载到虚拟机中,从而实现 Java 层的 hook。

Zygisk

Zygisk 是一个全新的框架,由原 Magisk 开发者设计。它将 Magisk 的一部分功能从 native 层移动到了 Zygote 层,实现对 Java 层的 hook。Zygisk 在 zygote 进程中注入一个模块,该模块在应用启动时运行,提供钩子和修改功能。Zygisk 的主要目标是解决 Magisk 遇到的一些问题,比如难以维护和兼容性问题。
关系与共同之处:
Riru 和 Zygisk 都是模块化框架,用于在不修改系统源代码的情况下实现对 Android 系统功能的扩展和修改。它们都主要通过对 Zygote 进程进行修改,在 Java 层实现 hook 功能。
不同之处:

  • Riru 更依赖于 native 层的 hook 技术,而 Zygisk 更注重对 Java 层的 hook。
  • Riru 使用 YAHFA 或 SandHook 作为基础,而 Zygisk 是 Magisk 开发者设计的全新框架。
  • Riru 的实现方式可能会导致一些兼容性问题,而 Zygisk 设计上更注重解决这些问题。

优缺点:

  • Riru 的优点是成熟、稳定,已经有很多基于它的模块。缺点是实现方式可能导致兼容性问题,维护成本较高。
  • Zygisk 的优点是更注重兼容性,设计上较为先进,更易于维护。缺点是相对较新,尚未完全普及。

从 Magisk v24 版本开始,Magisk 引入了名为 Zygisk(Zygote In-Memory Patcher)的新组件来实现系统级修改。Zygisk 旨在解决 ART(Android Runtime)及其他系统组件的强化安全措施带来的挑战,提供更安全、更可靠的修改方式。
Zygisk 的实现原理是在 Zygote 进程内执行代码注入。Zygote 进程是 Android 系统中的一个核心进程,负责启动和管理应用程序进程。当一个新的应用程序进程需要启动时,Zygote 进程会 fork 出一个新的子进程,并加载应用程序的代码和资源。
在 Magisk v24 及以后的版本中,Zygisk 会在 Zygote 进程启动时注入自己的代码。这使得 Zygisk 能够在应用程序进程创建时对其进行修改,例如实现 Root 功能。具体来说,Zygisk 可以在进程的内存中直接修改 libsu.so(提供 Root 功能的库)的加载方式,从而实现对进程的 Root。这种实现方式避免了对系统分区的修改,使得 Magisk 的 Root 功能更为安全和可靠。

回调时机
  1. onModuleLoaded: 当 Riru 模块被加载时调用。这个回调是在 Zygote 进程启动时触发的,用于模块进行初始化操作。可以在这个回调中设置钩子(hook)和注册相关的功能。
  2. onModuleUnloaded: 当 Riru 模块被卸载时调用。这个回调在模块被卸载、需要进行清理操作时触发,用于释放资源和取消之前设置的钩子。需要注意的是,这个回调可能在实际使用中比较少见,因为在大多数情况下,Riru 模块的卸载需要重启设备才能生效。
  3. onProcessCreating: 当新的进程被创建时调用。这个回调在每一个新进程创建时触发,包括应用进程和系统服务进程。这是一个很有用的回调,可以在这里针对特定进程进行特定的修改,比如对某个系统服务进行 hook。
  4. onProcessExiting: 当进程退出时调用。这个回调在进程退出时触发,用于在进程结束前进行清理操作。这个回调的实际应用场景可能较少,因为在大多数情况下,进程退出时系统会自动回收资源。
  5. riru_on_load: 这是 Riru 框架中的回调函数,当 Riru 模块被加载时调用。在该回调中,模块可以进行初始化操作,如设置钩子(hook)和注册相关功能。这个回调在 Zygote 进程启动时触发。
  6. riru_init: 这同样是 Riru 框架中的回调函数。当 Riru 框架自身初始化时,该回调会被触发。这与 riru_on_load 类似,但针对的是 Riru 框架本身的初始化工作,而不是特定模块的初始化。
  7. zygisk_on_fork: 这是 Zygisk 框架中的回调函数,在 Zygote 进程 fork 一个新进程时触发。在此回调中,您可以针对新进程进行特定的修改,如对特定进程的某个系统服务进行 hook。这个回调与 Riru 中的 onProcessCreating 类似。
  8. zygisk_on_load: 这是 Zygisk 框架中的回调函数,当 Zygisk 模块被加载时触发。这个回调用于模块的初始化操作,类似于 Riru 中的 riru_on_load。

Magisk 的实现原理?Magisk是怎么隐藏 Root 的?Magisk 和 EdXposed 什么关系?Magisk是怎么实现隐藏指纹信息的?

Magisk 的实现原理:

Magisk 是一个用于 Android 设备的系统级修改框架,允许用户在不修改系统分区的情况下实现设备的 Root 和其他系统级修改。Magisk 的核心原理是在设备启动时挂载一个覆盖在真实系统分区上的虚拟分区(称为 Magisk 分区),这个虚拟分区包含用户所需要的修改。这样,所有对系统分区的修改都会保存在这个虚拟分区中,而不会影响到实际的系统分区。这种实现方式避免了对系统分区的直接修改,从而降低了风险,并使得修改更易于管理。

Magisk 是怎么隐藏 Root 的:

Magisk 实现 Root 隐藏的主要方法是通过修改进程的命名空间和挂载点。当检测到一个应用程序试图访问设备的 Root 权限时,Magisk 会为这个进程创建一个新的命名空间,并在这个命名空间内隐藏所有与 Root 相关的文件和目录。这样,该进程在访问文件系统时就无法看到任何与 Root 相关的内容,从而实现了 Root 隐藏。
此外,Magisk 还可以通过拦截和修改一些系统 API 调用来进一步隐藏 Root 状态。例如,Magisk 可以修改 PackageManager 的行为,使其在检查应用权限时返回不包含 Root 权限的结果,从而使应用无法检测到 Root 状态。

Magisk 和 EdXposed 的关系:

Magisk 是一个系统级修改框架,提供了设备 Root 和其他系统级修改的能力。而 EdXposed 是一个基于 Magisk 框架的 Xposed 模块,用于在 Android 设备上实现 Xposed 功能。Xposed 是一个用于修改 Android 系统行为的框架,允许开发者通过编写模块来实现对系统功能和应用行为的定制。
Magisk 和 EdXposed 的关系可以理解为:Magisk 是基础设施,提供了对 Android 系统进行修改的能力,而 EdXposed 则是基于这个基础设施实现的一个具体功能模块。

Magisk 是怎么实现隐藏指纹信息的:

Magisk 可以通过修改系统属性(System Properties)和拦截系统 API 调用来实现隐藏设备指纹信息。设备指纹信息通常包括设备型号、制造商、品牌等,这些信息通常以系统属性的形式保存在设备上。当一个应用试图读取这些属性或通过系统 API 获取设备指纹信息时,Magisk 可以拦截这些请求,并返回修改过的属性值或 API 结果,从而实现隐藏指纹信息。
为了实现这个功能,Magisk 需要开发者编写相应的模块来定义如何修改设备指纹信息。用户可以根据需要安装不同的模块来实现对指纹信息的定制。

在Android逆向中,除了上面的三种hook技术,还有哪些主流hook技术,列举前五个,同样介绍一下实现原理

Substrate

Substrate 是一个跨平台的代码修改框架,支持 Android、iOS、macOS 和 Linux 等平台。它允许开发者在运行时修改目标程序的行为。
实现原理:Substrate 的 hook 实现方式包括 Inline Hook 和 trampoline 技术。在 Android 平台上,Substrate 主要针对 native 层函数。通过修改目标函数的入口指令,插入跳转到自定义 hook 函数的指令。在 hook 函数中完成自定义操作后,通过 trampoline 跳回目标函数的下一条指令。

AndHook

AndHook 是一个轻量级的 Android hook 框架。它可以在 Java 层和 native 层对目标函数进行 hook。
实现原理:AndHook 的 Java 层 hook 基于 Android 的动态代理技术,通过创建代理对象来替换原始对象。native 层的 hook 实现则采用类似于 Inline Hook 的方法,通过修改目标函数的入口指令,实现对目标函数的劫持。

Dobby

Dobby 是一个跨平台的 Inline Hook 框架,支持 Android、iOS、macOS 和 Linux 等平台。它可以对 native 层的函数进行 hook 和修改。
实现原理:Dobby 的 hook 实现依赖于 Inline Hook 技术。在目标函数的入口处插入跳转指令,将执行流程引导到自定义 hook 函数。在 hook 函数中完成自定义操作后,通过跳转指令恢复原始的执行流程。

YAHFA

YAHFA 是一个针对 Android 平台的 ART Hook 框架。它可以对 Java 层的方法进行 hook。
实现原理:YAHFA 主要基于 Android Runtime(ART)的特性实现 hook。通过修改目标方法的 ArtMethod 结构体,将目标方法的入口替换为自定义的 hook 方法。在 hook 方法中完成自定义操作后,通过调用原始方法的入口继续执行原始方法。

Whale

Whale 是一个针对 Android 和 iOS 的轻量级 hook 框架。它可以对 native 层的函数进行 hook。实现原理:Whale 的 hook 实现同样基于 Inline Hook 技术。通过在目标函数的入口处插入跳转指令,劫持目标函数的执行流程。在自定义的 hook 函数中执行自定义操作后,通过跳转指令返回到目标函数的下一条指令。
这五种 hook 技术在 Android 逆向中都有广泛的应用。根据具体需求和场景,开发者可以选择合适的技术进行代码的修改和分析。

如何Hook动态加载的dex

在 Android 脱壳过程中,我们的目标是找到加密或混淆的 Dex 文件,并在解密或还原后将其保存。为了实现这个目标,我们可以 Hook DexClassLoader、PathClassLoader 或 BaseDexClassLoader,拦截 Dex 文件的加载过程。

注入、hook框架的原理

Hook 是一种用于拦截和修改程序执行流程的技术。注入是将动态库注入到目标进程中,以便在目标进程的上下文中执行代码。常用的 Android Hook 框架有 Xposed 和 Frida。

Inline hook 和 GOT hook 原理,如何检测?Inline hook 跳板设计,多次跳转情况

Inline hook 的跳板设计通常包括保存原始指令、跳转到 Hook 函数、恢复原始指令并跳回目标函数。多次跳转情况下,需要考虑跳板间的连接及指令修复。

  • Inline hook:通过修改目标函数的指令,将其替换为跳转指令,指向我们的 Hook 函数。检测方法包括分析目标函数的指令,寻找异常跳转。
  • GOT hook:通过修改全局偏移量表(GOT)中的函数地址,将其替换为 Hook 函数的地址。检测方法是检查 GOT 表中的函数地址是否指向预期的函数。

中断 hook 的一些实现的函数方法

中断 hook 通常使用操作系统提供的中断机制,如 Linux 的信号处理(signal handler)或 Windows 的异常处理(Structured Exception Handling, SEH)。通过捕获中断事件,可以在中断处理函数中实现 hook 功能。

GOT 表 hook 和 PLT 表 hook 的区别

GOT 表(全局偏移量表)和 PLT 表(程序链接表)都用于动态链接。GOT 表 hook 是修改 GOT 表中的函数地址,而 PLT 表 hook 是修改 PLT 表中的跳转指令。两者都可以实现函数拦截,但 GOT 表 hook 更难检测。

GOT 表中有几种重定向的方式?

  • 修改 GOT 表中的函数地址,使其指向 Hook 函数。
  • 修改动态链接器的符号解析函数,使其返回 Hook 函数的地址。

GOT表 hook 和 inline hook 的优缺:

  • GOT 表 hook 优点:不修改目标函数指令,更难检测;可以在不同模块间进行 hook。缺点:仅适用于动态链接的函数。
  • Inline hook 优点:适用于任何函数,无论是静态还是动态链接。缺点:修改目标函数指令,可能被检测;需要处理多次跳转和指令修复问题。

如何去检测 inline hook?

  • 分析目标函数的指令,寻找异常跳转。
  • 比较目标函数与其在磁盘上的副本,检查是否有不一致之处。
  • 使用动态分析方法,观察程序执行过程中的行为,检测异常。
  • 使用反调试、反 hook 技术,检测并阻止 hook 行为。

本文转载自: https://blog.csdn.net/u010671061/article/details/131184515
版权归原作者 移动安全星球 所有, 如有侵权,请联系我们删除。

“移动安全面试题—hook技术”的评论:

还没有评论