1.Unity3D 导出的源码apk进行混淆加固、保护与优化原理(防止反编译)
2.通过do_execve源码分析程序的详解执行(上)(基于linux0.11)
3.linux内核情景分析之execve的实现
4.linux 进程加载 - execve 系统调用
Unity3D 导出的apk进行混淆加固、保护与优化原理(防止反编译)
某讯手游保护系统采用了一套方法,源码其中包括对Unity3D引擎手游的详解保护方案。该方案对Dll文件的源码保护措施包括对变量名、函数名、详解源码时代科技类名进行加密混淆处理,源码以提升静态分析的详解难度。
尽管可以通过动态分析改源码刷机或hook libc.so中的源码execve函数来绕过该保护方案,但本文主要讲解如何从内存中获取Assembly-CSharp.dll和Assembly-CSharp-firstpass.dll文件。详解绕过保护后,源码启动GameGuardian,详解在游戏Logo出现时附加到游戏上,源码并在登录页面通过内存搜索值的详解方式搜索PE文件Dos头的特征码。记录下第一个值和最后一个的源码值,然后进行dump操作。
保存完毕后,可以从手机上拉取文件到本地。使用get_dll_from_bin.exe工具从bin文件中dump出所有的dll文件,并用dnSpy打开查看是否存在目标dll文件。如果不存在,可能需要使用editor打开文件,修复被清零的ema源码检测PE头前字节,然后通过get_dll_from_bin.exe操作修复的bin文件。
经过操作后,可以获取到与Assembly-CSharp.dll和Assembly-CSharp-firstpass.dll大小相同的文件。将这两个文件拖入dnspy中,可以看到3.dll是目标文件Assembly-CSharp.dll,而.dll是Assembly-CSharp-fristpass.dll。至此,所有目标文件已获取完毕。
最后,分享一款好用的工具——ipaguard,用于对程序进行加固。Ipa Guard是一款功能强大的ipa混淆工具,可以直接对ipa文件进行混淆加密,保护代码、代码库、资源文件等。通过设置,可以对函数名、变量名、类名等关键代码进行重命名和混淆处理,降低代码的可读性,增加破解反编译难度。java试卷源码此外,还可以修改、资源、配置等文件的名称和md5值。
在使用混淆器后,还需要进行加固以防止反编译。导入自己的包,选择好混淆后的包,等待上传、加固、下载完成后,即可导出经过混淆和加固的安全包。
通过do_execve源码分析程序的执行(上)(基于linux0.)
execve函数是操作系统的关键功能,它允许程序转变为进程。本文通过剖析do_execve源码,揭示程序转变成进程的机制。do_execve被视为系统调用,其运行过程在前文已有详细解析,此处不再赘述。分析将从sys_execve函数开启。
在执行_do_execve前,先审视内核栈。rootkit源码分析接下来,我们将深入理解do_execve的实现。
在加载可执行文件时,存在两种情况:编译后的二进制文件与脚本文件。脚本文件需加载对应解释器,本文仅探讨编译后的二进制文件。解析流程如下:首先验证文件可执行性和当前进程权限,通过后,仅加载头部数据,具体代码在真正运行时通过缺页中断加载。然后,申请物理内存并存储环境变量和参数,该步骤在copy_string函数中实现。
完成上述步骤后,内核栈结构发生变化。接着,执行代码释放原进程页目录和页表项信息,解除物理地址映射,这些信息通过fork继承。随后,调用change_ldt函数设置代码段、数据段基地址和限长,stickline指标源码其中数据段限长为MB,代码段限长根据执行文件头部信息确定。完成物理地址映射后,内存布局随之调整。
紧接着,通过create_tables函数分配执行环境变量和参数的数组。执行完毕后,内存布局进一步调整。最后,设置栈、堆位置,以及eip为执行文件头部指定值,esp为当前栈位置,至此,可执行文件加载阶段完成。下文将探讨执行第一条指令后的后续步骤。
linux内核情景分析之execve的实现
Linux内核中的execve函数实现涉及到用户态CPU寄存器在内核栈中的保存和系统调用的细节。首先,理解sys_execve源码中的do_execve函数至关重要。它涉及到一个名为linux_bin_fmt的结构,该结构存储了内核对各种可执行程序格式的支持信息,包括加载和执行函数,以及保存文件路径、参数和环境变量的linux_bin_prm结构。
do_execve的实现从读取可执行文件的头部字节开始,通过prepare_binprm函数,将文件头部数据放入bprm->buf缓存。内核通过search_binary_handler遍历formats队列,识别文件的正确格式并调用相应的处理函数,如load_aout_binary处理a.out格式。
在load_aout_binary中,如遇到/bin/echo,会调用flush_old_exec,涉及信号处理函数指针复制、内存空间处理(包括信号处理模式、用户空间的清理)和文件关闭等。其中,make_private_signal和exec_mmap函数分别处理信号处理和内存映射,根据close_on_exec位图关闭相关文件。
在载入新程序时,内核会复制可执行文件路径到内核空间,然后查找并打开文件,读取前字节初始化数据结构。接下来,通过formats队列的遍历,找到合适的代理加载器(如a.out的load_aout_binary)来执行后续的加载和初始化操作,如设置信号处理、用户空间和文件资源等。
最终,新进程会通过各个代理加载器的定制化空间申请和参数映射,调用start_thread启动进程。尽管描述了大致流程,但实际执行中涉及许多细节问题,如线程隔离、用户空间计数处理等,需要深入内核代码才能详细了解。
linux 进程加载 - execve 系统调用
在 Linux 平台下,程序运行的最后一步是加载过程。此过程由加载器负责,将生成的可执行代码放到指定内存位置并从预设地址执行。加载基于 ELF 格式可执行文件,不同于直接拷贝到内存的二进制文件,因为 ELF 文件格式包含额外的结构,如代码、数据段以及页表等。加载器需要解析 ELF 文件,将代码和数据部分放置到链接指定的内存位置,执行代码开始运行。
加载过程涉及 ELF 文件格式和链接知识,深入了解可参考相关文档。对于 Linux 平台的 ELF 文件加载,不深入讨论共享库的源码实现,而是关注 execve 系统调用。execve 用于启动新程序执行,根据指定的文件名或目录名找到可执行文件,并用它取代当前进程的数据、代码和堆栈段。此过程涉及多个 exec 函数变体,其本质上调用 glibc 中的 __execve 函数,向内核发起执行。
execve 系统调用被定义在内核文件 fs/exec.c 中,通过 getname() 函数将用户空间文件名指针拷贝到内核,返回一个结构包含内核和用户空间文件名地址。接下来,调用 do_execve 函数进行参数处理,紧接着调用 do_execveat_common 函数,真正开始文件处理。核心数据结构 linux_binprm 包括了 execve 系统调用所需的所有资源。
整个 do_execveat_common 实现分为三部分,执行流程清晰。在 exec_binprm 中,调用 search_binary_handler 函数遍历系统已注册的加载器,尝试解析当前可执行文件并加载。formats 是全局链表,包含所有加载程序,每个加载器由 struct linux_binfmt 描述。list_for_each_entry() 依次调用 load_binary 回调函数,确定是否能找到处理当前文件的加载器。对于 ELF 格式的文件,调用 load_elf_binary 函数进行实际加载。
load_elf_binary 函数解析 ELF 文件,主要操作文件段加载。分析此函数前,需了解 ELF 文件格式,目标文件段类型分为指令、数据和未初始化数据。链接过程产生可执行文件,内存访问权限划分内存区域,形成多个 segment。加载过程分为读取 ELF 头获取信息和读取 segment 头表,根据信息将 segment 放置到不同内存区域。
核心操作包括读取 ELF 文件头部、解析段表以及将段合并到内存区域。load_elf_binary 函数直接操作 ELF 文件,读取头部和段表信息,根据段属性分配内存区域。整个加载过程涉及系统调用、内核栈保存和恢复,最终完成程序替换并执行新程序。
整个加载过程总结为几个关键阶段,包括文件解析、段合并和内存映射。由于篇幅限制,代码逻辑分析未详述,有兴趣深入了解者可查阅内核源码和相关文档。