欧美网站模板 psd,电子商务网站建设含义,网站建设虚线的代码,qq免费搭建网站目录 工具类IDASegment registers(shiftF8) 反调试利用IO重定向来绕过反调试 EBPF使用eBPF完成安卓App hook xHookUNIDBG补环境 文件结构ELFsection和segment的关系.dynamic段.init和.init_array段 花指令花指令5要素 Smali基础打包 工具类
IDA
Segment registers(shiftF8)
… 目录 工具类IDASegment registers(shiftF8) 反调试利用IO重定向来绕过反调试 EBPF使用eBPF完成安卓App hook xHookUNIDBG补环境 文件结构ELFsection和segment的关系.dynamic段.init和.init_array段 花指令花指令5要素 Smali基础打包 工具类
IDA
Segment registers(shiftF8)
当IDA遇到改变段寄存器的指令时它会创建一个段寄存器变化点。所以大多数变化点都由IDA自己维护。IDA假设段寄存器在变化点之间不会改变其值。如果您发现IDA无法找到段寄存器的变化或者想要更改寄存器的值则可以使用Change Segment Register命令创建一个变化点。您也可以使用Set default segment register value命令更改段寄存器的值。 IDA对变化点进行分类。在变化点列表中您可以看到在寄存器值后面的以下后缀 a自动-由IDA创建。之后可能会由IDA更改。 u由用户-由用户创建。IDA不会更改它。 如果未被相应命令禁用则IDA会为变化点生成相应的“assume”指令。
反调试
利用IO重定向来绕过反调试
IO重定向是一种在操作系统级别上修改输入输出流向的技术。在某些情况下它可以用来绕过反调试措施。反调试技术通常用于检测和阻止调试器或其他分析工具的接入以保护软件不被篡改或逆向工程。以下是一些基本的步骤和技巧用于利用IO重定向来绕过反调试 启用IO重定向在一些系统中你可以通过修改系统的IO端口或使用特定的指令来启用IO重定向。这通常涉及到向 IO_BASE 寄存器写入一个特定的值以启用重定向。 修改内存映射修改内存映射是一种常见的技术用于将内存中的某些区域映射到其他区域。这可以通过修改 GOT全局偏移表或 PLT程序链接表来实现。 使用原始指令在一些情况下原始指令如 NOP 指令可以用来绕过反调试检查因为它们不修改任何寄存器或内存状态。 利用代码覆盖通过覆盖特定的代码区域可以使得反调试器认为程序正在执行正常的代码路径从而绕过防护。 修改调试信息修改程序的调试信息如函数名、变量名等可以使得反调试器难以识别程序的结构从而降低逆向工程的效果。 使用第三方工具有些第三方工具如 Frida、DBI 等可以用来动态修改程序的行为从而绕过反调试防护。
EBPF
使用eBPF完成安卓App hook
使用 eBPF (Extended Berkeley Packet Filter) 完成安卓 App 的 hook 是一个高级的逆向工程任务它通常需要对 Linux 内核、eBPF 编程以及安卓系统的内部工作原理有深入的了解。以下是一个简化的步骤指南用于在安卓应用中实现 eBPF hook 设置 eBPF 环境 确保你的开发环境支持 eBPF例如使用最新的 Linux 内核。 安装必要的工具如 clang、llvm、bpftool 等。 编写 eBPF 程序 使用 eBPF 语言编写你的 hook 程序它将运行在安卓设备的内核空间。 编写程序以过滤和处理你感兴趣的事件例如系统调用、网络流量等。 编译 eBPF 程序 使用 clang 编译你的 eBPF 程序为二进制格式。 安装 eBPF 程序到安卓设备 使用 adb 或其他工具将编译后的 eBPF 二进制文件安装到安卓设备上。 确保你有权限在设备上安装内核模块。 加载 eBPF 程序 使用 bpftool 或系统调用将 eBPF 程序加载到内核中。 配置 eBPF 程序的参数如挂钩点、过滤条件等。 测试和验证 运行你的安卓应用并验证 eBPF 程序是否按预期工作。 调试和调整 eBPF 程序直到它能够稳定地提供你想要的数据。 持久化 eBPF 程序 如果需要将 eBPF 程序打包到安卓系统的启动脚本中使其在设备启动时自动加载。 请注意这个过程涉及到对系统内核的修改可能会对设备的保修状态产生影响并且在某些情况下可能违反软件的服务条款。在进行这些操作之前请确保你有足够的权限并且对你的行为负责。此外由于安卓系统的复杂性和安全性eBPF hook 的实现可能需要特定的知识和技能因此在实际应用中可能需要专业的逆向工程师来完成。
以下是一个简单的示例展示了如何使用eBPF在安卓应用中插入代码 首先创建一个名为hook_example.c的C文件内容如下
#include uapi/linux/ptrace.h
#include linux/sched.h
#include bcc/proto.hint count 0;int trace_syscalls(struct pt_regs *ctx, struct kernel_syscall_args *) {count;return 0;
}char __license[] __section(license) GPL;编译这个C文件为eBPF程序 bash
$ clang -target bpf -O2 -Wall -Werror -c hook_example.c -o hook_example.o
$ llc -marchbpf -filetypeobj -o hook_example.o.bc hook_example.o将生成的.o.bc文件转换为eBPF字节码
$ sudo bpftool c-to-bpf hook_example.o.bc加载并运行eBPF程序
$ sudo bpftool prog load hook_example.o
$ sudo bpftool map create count_map pinned /sys/fs/bpf/count_map type long
$ sudo bpftool map dump count_map在你的安卓应用中使用JNI调用上述命令来加载和运行eBPF程序。例如你可以在你的Java代码中添加以下方法
public native void runEbpf();static {System.loadLibrary(your_native_library);
}然后在你的C或C代码中实现这个方法
#include jni.h
#include your_header_file.hJNIEXPORT void JNICALL Java_your_package_name_YourClassName_runEbpf(JNIEnv *env, jobject obj) {// 在这里调用上述命令来加载和运行eBPF程序
}这样每当你的安卓应用调用runEbpf()方法时eBPF程序就会被加载并运行从而实现对安卓应用的hook。
xHook
xHook 是一个用于Android原生ELF可执行文件和共享库的PLT过程链接表钩子库。它具有以下特点 支持Android 4.0至10API级别14至29。 支持armeabi、armeabi-v7a、arm64-v8a、x86和x86_64。 支持ELF HASH和GNU HASH索引的符号。 支持SLEB128编码的相对定位信息。 支持通过正则表达式设置钩子信息。 不需要root权限或任何系统权限。 不依赖任何第三方共享库。 xHook的功能包括 注册钩子信息通过xhookregister函数可以注册需要钩子的ELF文件和符号。 忽略钩子信息通过xhookignore函数可以忽略某些钩子信息。 执行钩子操作通过xhookrefresh函数可以实际执行钩子操作。 清除缓存通过xhookclear函数可以清除xHook持有的所有缓存将所有全局标志重置为默认值。 启用/禁用调试信息通过xhookenabledebug函数可以启用或禁用调试信息。 启用/禁用SFP段错误保护通过xhookenablesigsegvprotection函数可以启用或禁用SFP。 xHook的使用案例主要包括 修改ELF文件中的函数实现可以通过钩子机制在加载的ELF文件中替换原始函数实现。 忽略特定ELF文件的钩子可以根据正则表达式忽略特定ELF文件的钩子。 总之xHook是一个在Android原生ELF文件上实现钩子操作的库可以用于修改、忽略或执行特定ELF文件的钩子。它具有较高的兼容性和稳定性适用于不同版本的Android系统和多种架构。
UNIDBG
补环境
Unidbg 是一个强大的逆向调试工具它支持多种调试技术和插件可以模拟执行 Android 和 iOS 平台上的应用程序。为了能够正确地调试和分析应用程序Unidbg 需要一个完整的补环境bootstrap environment这个环境包括了 JNI 补环境、文件访问补环境以及补系统调用和库函数。以下是对这些补环境的详细介绍 JNI 补环境 JNIJava Native Interface是 Java 用于与本地代码如 C/C交互的接口。在逆向 Android 应用程序时如果应用程序使用了 JNI 调用本地库Unidbg 需要一个 JNI 补环境来模拟这些调用。这个补环境包括了 JNI 函数的声明和实现它们可以被 Unidbg 用来拦截和模拟 JNI 调用。 文件访问补环境 应用程序可能需要访问文件系统来读取或写入文件。Unidbg 的文件访问补环境允许模拟这些文件操作包括文件路径、权限和文件内容。这样即使在模拟环境中应用程序也能够像在真实设备上一样进行文件访问从而保证调试的连贯性。 补系统调用和库函数 系统调用和库函数是操作系统和应用程序交互的接口。Unidbg 提供了补系统调用和库函数的功能这允许它模拟系统调用和库函数的行为。这对于调试那些依赖于特定操作系统功能的应用程序至关重要如权限检查、进程管理和硬件访问等。 为了创建这些补环境通常需要编写相应的脚本和插件。Unidbg 社区提供了许多现成的补环境脚本和插件这些可以被下载和使用。用户也可以根据自己的需要定制和扩展这些补环境以支持特定的应用程序或平台。 使用 Unidbg 的补环境时用户可以加载和执行应用程序的 SO 文件设置断点观察程序的执行以及跟踪和修改程序的状态。这些功能使得 Unidbg 成为一个强大的工具用于 Android 和 iOS 应用程序的逆向工程和调试。
文件结构
ELF
section和segment的关系
在ELFExecutable and Linkable Format文件中section和segment是描述文件中数据组织的两个概念。它们之间的关系可以这样理解 Section节 Section是编译器创建的用于将程序的不同部分逻辑地组织在一起。例如.text节包含程序的代码.data节包含初始化的数据.bss节包含未初始化的数据等。 Section的边界在编译时是固定的它们是目标文件object file中的一个连续的数据块。 Section头表Section Header Table包含了有关每个section的信息如大小、位置和属性等这些信息对于链接器linker来说是重要的因为链接器需要它们来将不同的目标文件合并成一个可执行文件。 Segment段 Segment是加载器loader创建的它们代表了程序在内存中的物理布局。每个段都有特定的访问权限如读Read、写Write和执行Execute。 Segment的边界在加载时是动态的它们可以跨越多个section。例如代码段可能包含.text和.plt节。 Segment头表Program Header Table包含了有关每个segment的信息如大小、文件偏移量、虚拟地址和物理地址等这些信息对于加载器来说是重要的因为加载器需要它们来将程序的各个部分映射到内存中的正确位置。 总结来说section是编译器层面的概念用于源代码的编译和链接而segment是加载器层面的概念用于程序的加载和执行。在编译过程中编译器会生成section然后在链接过程中链接器会根据section信息来创建segment。加载器在程序运行时会使用segment信息来将程序的各个部分映射到内存中。
.dynamic段
.dynamic段包含了一些用于动态链接的信息。.dynamic段不是标准ELF段名但它通常出现在可执行文件和共享库文件中用于存储与动态链接相关的数据。.dynamic段包含了三个主要的部分.dynsym、.dynstr和.hash。 .dynsym动态符号表 .dynsym段包含了动态链接时需要的符号信息。这些符号是动态符号表的一部分用于在运行时将程序中的符号解析为相应的函数和变量。 动态符号表中的条目通常包括符号的名字、类型、属性如是否为外部符号、大小和位置等信息。 .dynstr动态字符串表 .dynstr段包含了动态链接时需要的字符串字面量。这些字符串通常用于动态符号表中的符号名称和版本控制。 动态字符串表中的条目包含了字符串的内容和它们在文件中的偏移量。 .hash动态哈希表 .hash段包含了用于加速动态链接过程的哈希表。这个哈希表是根据符号的名称和属性来组织的它使得查找符号的速度更快。 动态哈希表通常包括符号的哈希值、名称和偏移量等信息。 这些段落通常在程序被动态链接器处理时会用到。当程序被加载时动态链接器会使用.dynamic段中的信息来解析符号和字符串并创建相应的符号表和哈希表。这使得程序能够在运行时动态地引用其他共享库中的函数和变量。 需要注意的是这些段落的布局和内容可能会根据不同的编译器和目标系统有所不同。因此当处理.dynamic段时需要参考特定编译器和目标系统的文档。
.init和.init_array段
.init和.init_array段是用于初始化代码和初始化调用序列的特殊段。 .init 段 .init段包含了程序的初始化代码。这部分代码在程序启动时被调用用于执行任何必要的初始化任务。这通常包括设置全局变量、初始化静态数据结构、注册信号处理程序等。 .init段中的代码是程序启动时执行的第一批代码之一。在Linux系统上.init段通常会由系统初始化程序如init或者脚本如startup.script调用。 .init_array 段 .init_array段是一个特殊的节它包含了初始化函数的数组。这些函数在程序启动时按顺序被调用。.init_array中的函数通常用于初始化共享库或者程序的特定部分。 在Linux系统上当一个共享库被加载时动态链接器会查找.init_array段并按照其中的函数列表调用它们。这些函数可以用来进行全局初始化比如设置全局变量、初始化数据结构等。 .init_array段中的函数通常以弱符号weak symbols的形式声明这意味着如果同一个符号在其他的.init段或者.init_array段中被更强地定义那么这个弱符号的初始化函数就不会被调用。 需要注意的是.init和.init_array段是可选的并不是所有的ELF程序都会使用它们。如果一个程序或者共享库不需要在启动时执行初始化代码那么这些段就可以省略。 在 objdump 工具的输出中你可以看到.init和.init_array段的内容包括它们包含的函数和数据。这些信息对于理解程序的初始化流程和调试初始化问题时非常有用。 .init和.init_array两个section用于在so文件被加载时做初始化工作系统在加载so文件时会先执行.init中的代码然后再顺序执行.init_array中的各个代码块且.init和.init_array的执行时机均早于JNI_OnLoad方法所以这两个section的执行时间是比较早的所以有时解密函数会放在.init或者.init_array中.
花指令
花指令5要素
花指令Junk Code是一种用于混淆和干扰逆向工程分析的技巧。它通过在程序中插入无用的、看似随机或者无害的代码来迷惑逆向工程师使得他们难以理解程序的真实逻辑。花指令的有效性通常取决于以下五个要素 复杂性花指令应该足够复杂以至于不会被轻易识别出其真实的意图。这通常意味着它们包含了一些不常见的指令或者特殊的编码模式。 随机性花指令通常看起来像是随机生成的没有明显的模式或者逻辑。这种随机性可以防止逆向工程师通过统计分析来识别代码的模式。 误导性花指令可能会模仿有效的指令但是执行时并不会产生预期的效果或者它们可能会在某些条件下执行从而误导逆向工程师认为它们是有用的代码。 变化性花指令可能会根据不同的条件或者执行阶段发生变化使得同一代码在不同情况下有不同的表现这增加了逆向分析的难度。 叠加性花指令可能会与程序中的其他代码片段叠加形成一个新的代码序列这个新的序列可能会对逆向工程师造成额外的混淆。 为了提高花指令的效果通常会结合使用多种技巧比如在代码中插入特殊的字符串或者模式使用复杂的跳转逻辑或者在不同的执行上下文中插入不同的代码片段。逆向工程师在分析花指令时需要具备深厚的汇编语言和程序设计知识以便能够识别和理解这些复杂的干扰模式。
Smali
基础
指令Smali 包含了一系列指令用于表示程序的控制流、操作数和返回值。例如nop 用于无操作move-result 用于将操作结果移动到指定变量。 局部变量Smali 允许定义局部变量并使用 . 操作符来访问它们。局部变量通常以数字索引的方式进行引用。 常量池Smali 中的常量池用于存储字符串、数字和其他常量。常量池索引通常以 # 开头。 方法调用Smali 中的方法调用使用 invoke 指令。调用可以是有返回值的也可以是虚拟调用还可以是静态调用。 控制流Smali 支持条件分支和循环控制流。条件分支使用 if-eq、if-ne 等指令循环使用 goto 和 if 指令。 异常处理Smali 提供了异常处理的机制使用 try、catch 和 finally 指令来捕获和处理异常。
打包
重打包技巧通常涉及到对 Smali 代码的修改以实现特定的目的比如修改应用程序的行为、移除权限要求或者绕过某些安全检查。以下是一些重打包技巧 修改方法签名通过改变方法的签名可以创建一个新的方法该方法与原始方法具有相同的名称但参数列表不同。 修改常量池通过修改常量池中的内容可以改变代码中的字符串和数字值。 添加或删除指令通过添加或删除 Smali 指令可以改变程序的控制流和行为。 修改局部变量和参数通过修改局部变量和参数的索引可以改变变量和参数的名称和作用。 使用 Smali 混淆通过使用 Smali 混淆技术可以使得代码更难以阅读和理解。 在进行重打包时需要谨慎操作因为不当的修改可能导致应用程序崩溃或行为异常。此外重打包可能会违反软件许可协议因此在进行此类操作之前请确保您有权修改和使用该软件。