【微信小程序网站源码】【网易uu源码】【shadowrocket源码分析】libc源码解读

时间:2024-12-22 19:16:14 分类:网游源码 修复 来源:进口汽车溯源码

1.CALL 、源码libc++、解读libc
2.libc release和debug的区别
3.VirtualAPP源码解析-Native Hook技术
4.鸿蒙轻内核M核源码分析:LibC实现之Musl LibC
5.系统调用的源码实现细节(用户态)
6.exit()分析与利用

libc源码解读

CALL 、libc++、解读libc

       CALL 是源码 **(Compiler/Assembler/Linker/Loader)**的简称。如果你和 C/C++ 打过交道,解读微信小程序网站源码这几个词应该不会陌生。源码

       Levels of Representation/Interpretation

       抛开正确性,解读我们可以尝试填空(Python / C++、源码Go)并且知道:

       但是解读同时,Python 也能通过一些方式打包成 exe (虽然很巨大),源码同时 LLVM 这些层次的解读引入让我们的理解模糊了起来。所以我们要明确一下这个 Level。源码

       这个问题实际上是解读很含糊不清的,第三点里面 JIT 等的源码引入更让事情扑朔迷离了起来。具体其实可以参考这个链接里的说法: /question/。

       一般被称为“解释型语言”的是主流实现为解释器的语言,但并不是说它就无法编译。例如说经常被认为是“解释型语言”的 Scheme就有好几种编译器实现,其中率先支持 R6RS规范的大部分内容的是 Ikarus,支持在x上编译Scheme;它最终不是生成某种虚拟机的字节码,而是直接生成x机器码。

       实际上解释器的性能劣势也不一定是一种坏事,像我去年去 PyCon 听的“慢解释是一种优势”,虽然有点破罐子破摔的网易uu源码味道,但是如果你在 C/C++ 下开 asan/valgrind 或者带gcc -g, 和 Go 这种带 Runtime 的、V8这些可以提供的debug比较,难免会有羡慕的想法。

       Interpreter provides instruction set independence: run on any machine

       就是这样。

       CALL chain

       这是一张水图。可能还要处理一下预处理之类的过程,但是大概流程是这样没错。

       Compile

       Compile 的过程大概是

       不过看上面转的那篇文章,似乎形式有变,这方面我不是很了解。Lexer/Parser 的部分可以参考我之前的 Lex/Yacc 入门。总之,我们现在把源代码编译后可以转化为一种对应的 IR, 即nmsl.c -> nmsl.S.

       Assembler

       Assembler 接下来会nmsl.s -> nmsl.o.

       顺便给出这个 part 一个很有意思的 slide:

       ELF

       这个我觉得还是 csapp 写得好...总之生成的目标文件会满足这样的形式。

       Linker

       Combines several object (.o) files into a single executable (“linking”)

       这段我感觉 CSAPP 讲的稍微详细一些。

       在应用层面上,这里其实还涉及(不一定是这里引入的)name mangling,calling convention这种 C/C++ 相关的问题,所以可能extern "C" 在这种情况下就相对很好理解了。

       Loader

       When one is run, loader’s job is to load it into memory and start it running In reality, loader is the operating system (OS)

       这里可以参考 CSAPP 里面链接的时机相关的概念。

       libc/libc++

       qsort 是一个 下的函数,如果你去 libc++ 找的话,会发现事情好像不太对:

       github.com/llvm-mirror/...

       这里只有using 和函数声明,没有对应的实现。

       实际上 C++ 的shadowrocket源码分析标准库(以 libc++) 为例,可能会根据模版生成需要的函数/类。所以我们可以看到对应的一些源代码。

       C语言的库函数实际上通常以链接库的形式在 libc 中提供,链接的时候我们找到: stackoverflow.com/quest...

libc release和debug的区别

       Debug和Release区别

       VC下Debug和Release区别

       æœ€è¿‘写代码过程中,发现 Debug 下运行正常,Release 下就会出现问题,百思不得其解,而Release 下又无法进行调试,于是只能采用printf方式逐步定位到问题所在处,才发现原来是给定的一个数组未初始化,导致后面处理异常。网上查找了些资料,在这 罗列汇总下,做为备忘~

       ä¸€ã€Debug 和 Release 的区别

       Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。

       Debug 和 Release 的真正区别,在于一组编译选项。

       Debug 版本

       å‚æ•° 含义

       /MDd /MLd 或 /MTd 使用 Debug runtime library(调试版本的运行时刻函数库)

       /Od 关闭优化开关

       /D "_DEBUG" 相当于 #define _DEBUG,打开编译调试代码开关(主要针对assert函数)

       /ZI

       åˆ›å»º Edit and continue(编辑继续)数据库,这样在调试过程中如果修改了源代码不需重新编译

       GZ 可以帮助捕获内存错误

       Release 版本 参数含义

       /MD /ML 或 /MT 使用发布版本的运行时刻函数库

       /O1 或 /O2 优化开关,使程序最小或最快

       /D "NDEBUG" 关闭条件编译调试代码开关(即不编译assert函数)

       /GF 合并重复的字符串,并将字符串常量放到只读内存,防止被修改

       Debug 和 Release 并没有本质的界限,他们只是一组编译选项的集合,编译器只是按照预定的选项行动。

       1. 变量。

       å¤§å®¶éƒ½çŸ¥é“,debug跟release在初始化变量时所做的操作是不同的,debug是将每个字节位都赋成0xcc(注1),而release的赋值近 似于随机(我想是直接从内存中分配的,没有初始化过)。这样就明确了,如果你的程序中的某个变量没被初始化就被引用,就很有可能出现异常:用作控制变量将 导致流程导向不一致;用作数组下标将会使程序崩溃;更加可能是造成其他变量的不准确而引起其他的错误。所以在声明变量后马上对其初始化一个默认的值是最简 单有效的办法,否则项目大了你找都没地方找。代码存在错误在不用多说了。这也存在

VirtualAPP源码解析-Native Hook技术

       Native Hook技术在VirtualAPP中的应用背景在于虚拟APP的文件访问重定向。VirtualAPP作为子进程启动一个虚拟APP时,文件存储路径会默认指向VirtaulAPP的data目录。这可能导致文件访问冲突,且无法实现APP间的隔离。VirtualAPP通过Native Hook技术解决了这个问题,让每个APP有独立的文件存储路径。

       实现原理关键在于VClientImpl的startIOUniformer方法,通过进行存储路径映射,将子进程访问的目录路径转换为虚拟app路径。这个过程通过调用IOUniformer.cpp的startUniformer方法实现。我们知道Android系统基于Linux内核,文件读写操作通过库函数进行系统调用。因此,Native Hook技术实现方式是替换libc库函数的方法,将输入参数替换为虚拟app路径,从而实现文件访问路径的重定向。

       要确定需要hook的函数,开发者需要查看libc源码。Native Hook技术有PLT Hook与Inline Hook两种实现方式。PLT Hook主要通过替换程序链接表中的easynvr源码分析地址,而Inline Hook则直接修改汇编代码,实现更广泛的场景与更强的能力。虚拟app使用的第三方开源项目Cydia Substrate实现了Inline Hook方案,而爱奇艺开源的xHook则采用了PLT Hook方案。虚拟app通过宏定义灵活运用这两种Hook方案,实现对libc库函数的替换。

       Native Hook技术的实现过程涉及到so动态链接、ELF文件格式、汇编指令等知识,其具体步骤包括定义Hook调用和替换方法。例如,通过HOOK_SYMBOL宏定义函数指针,HOOK_DEF宏定义替换函数,最终通过hook_function方法实现Hook操作。MSHookFunction函数即为Cydia Substrate提供的Hook能力。

       学习Native Hook技术需要逐步积累,理解其原理和实现过程需要时间和实践。后续文章将深入探讨MSHookFunction的具体实现原理,进一步帮助读者掌握Native Hook技术。

鸿蒙轻内核M核源码分析:LibC实现之Musl LibC

       本文探讨了LiteOS-M内核中Musl LibC的实现,重点关注文件系统与内存管理功能。Musl LibC在内核中提供了两种LibC实现选项,使用者可根据需求选择musl libC或newlibc。本文以musl libC为例,烧写源码深度解析其文件系统与内存分配释放机制。

       在使用musl libC并启用POSIX FS API时,开发者可使用文件kal\libc\musl\fs.c中定义的文件系统操作接口。这些接口遵循标准的POSIX规范,具体用法可参阅相关文档,或通过网络资源查询。例如,mount()函数用于挂载文件系统,而umount()和umount2()用于卸载文件系统,后者还支持额外的卸载选项。open()、close()、unlink()等文件操作接口允许用户打开、关闭和删除文件,其中open()还支持多种文件创建和状态标签。read()与write()用于文件数据的读写操作,lseek()则用于文件读写位置的调整。

       在内存管理方面,LiteOS-M内核提供了标准的POSIX内存分配接口,包括malloc()、free()与memalign()等。其中,malloc()和free()用于内存的申请与释放,而memalign()则允许用户以指定的内存对齐大小进行内存申请。

       此外,calloc()函数在分配内存时预先设置内存区域的值为零,而realloc()则用于调整已分配内存的大小。这些函数构成了内核中内存管理的核心机制,确保资源的高效利用与安全释放。

       总结而言,musl libC在LiteOS-M内核中的实现,通过提供全面且高效的文件系统与内存管理功能,为开发者提供了强大的工具集,以满足不同应用场景的需求。本文虽已详述关键功能,但难免有所疏漏,欢迎读者在遇到问题或有改进建议时提出,共同推动技术进步。感谢阅读。

系统调用的实现细节(用户态)

       本文以Ubuntu ..4 LTS环境和x_架构的glibc为例,详细解析了系统调用的实现细节。以一个具体的事例说明,即在编写应用程序时如何链接系统调用。

       编译test.c后,链接libc.so动态库中的fork函数,其实现位于glibc源代码中。然而直接在glibc代码中找不到fork()的实现。通过实验,将应用程序静态链接libc.a生成可执行文件,反汇编后发现实际调用的是__libc_fork。

       __libc_fork在glibc工程sysdeps/nptl/fork.c路径下实现,调用系统功能的代码通过ARCH_FROK宏实现,此宏在glibc工程sysdeps/unix/sysv/linux/x_/arch-fork.h目录下。实现过程中,使用了__weak_alias实现在glibc工程include/libc-symbols.h路径下。

       进一步分析__libc_fork函数,它通过调用ARCH_FROK宏实现调用系统功能,具体通过INLINE_SYSCALL宏调用clone,此宏定义在glibc工程sysdeps/unix/sysv/linux/x_/sysdep.h头文件中,与体系结构相关。内部调用流程涉及INTERNAL_SYSCALL定义和SYS_ify宏定义。具体实现中,__NR_##syscall_name宏定义在ubuntu系统的/usr/include/x_-linux-gnu/asm/unistd_.h文件中,表示系统调用编号,如fork系统调用实际通过__NR_clone标号传参。

       通过内部_syscall##nr宏在glibc工程sysdeps/unix/sysv/linux/x_/sysdep.h定义,实现系统调用,从用户态到核心态。不同体系架构的系统调用流程基本相似,但汇编指令各不相同。

       本文旨在提供系统调用实现的详细解析,水平有限,欢迎指正批评,如有疑问欢迎私信交流。

exit()分析与利用

       main()函数结束时,需要执行一些清理工作,因此内核层面的终止通过`exit`系统调用完成,这实际上是调用一个syscall,由libc实现。然而,直接调用`_exit()`可能导致stdout缓冲区的数据被内核立即释放,无法刷新,信息丢失。因此,调用`_exit()`前,需要在用户层面完成一些清理工作。libc中定义了`exit()`函数,其主要作用是进行用户层面的资源清理,最后调用`_exit()`进行系统级别的清理。

       在pwn技术中,`_exit()`无法被利用,而`exit()`则提供了多种攻击点。因此,本文将深入分析libc中`exit()`函数的实现、相关机制以及利用方法。

       分析`exit()`源码,了解libc是如何组织清理函数,并通过`run_exit_handlers()`函数处理这些清理函数。分析`__exit_funcs`链表,探讨是否有可能通过劫持该链表来实现特定函数的调用。进一步研究`__exit_funcs`是如何添加清理函数的,以及其中包含哪些函数。理解程序启动过程,包括ELF的入口点`_start()`和动态链接器ld.so.2的作用,以及`libc_start_main()`函数如何在`exit_funcs`中添加函数,并调用构造函数。

       通过深入分析,了解`libc_start_main()`会在`exit_funcs`中放入`__libc_atexit`和构造函数。详细分析这三个关键要素,并讨论ELF的`fini()`和`init()`函数的作用。理解`ld.so.2`中的`rtdl_fini()`函数如何处理清理工作,并指出其带来的利用可能性。

       详细分析`rtdl_fini()`函数的实现和依赖的`rtld_global`数据结构,指出其攻击面。通过动态调试,明确如何劫持`rtld_global`中的函数指针,实现获取shell。进一步探讨如何利用`l_info`伪造`fini_array`节,将其迁移到可控制的位置,并在其中写入函数指针,实现多个函数的调用。

       在劫持`fini_array`后,我们具备了连续调用多个函数的能力,探讨如何将这种能力与ROP相结合,完成复杂操作。分析`fini_array`中函数的调用过程,利用寄存器环境的稳定性和栈环境的特性,设计利用策略,如利用`gets()`和`setcontext`实现SROP。

       利用`fini`段进行攻击相对简单,但只能执行一个函数,通常设置为`ogg`。通过修改`rtld_global`中的`l_info`指向`fini`段的函数指针,实现特定函数的调用。

       回顾`exit()`函数的清理流程,除了调用清理函数链表外,还有调用`__libc_atexit`中的默认清理函数。总结分析内容,强调对清理机制的理解和利用方法。