手机网站关键词快速排名/在线子域名二级域名查询工具
本文主要讨论 mmap 函数以及如何使用 mmap 函数来加载一个 ELF 的可加载段。
01纠错
Android 8 及以后是会读取 section header 的,但不是所有的 section 都会读取。
https://cs.android.com/android/platform/superproject/main/+/main:bionic/linker/linker_phdr.cpp;l=29?q=linker_phdr&sq=&ss=android
Android 8 应该是一个分水岭,可以看到会有很多版本检查逻辑:
mmap 函数
这个函数的参数在 man7 里面有非常详细的说明,建议看看:
https://man7.org/linux/man-pages/man2/mmap.2.html
看一个例子:
#include <stdio.h>
#include <sys/mman.h>
#include <dlfcn.h>int main()
{FILE *fp = fopen("/data/local/tmp/four.bin", "rb");void *addr = mmap((void *)0x80000000, 0x100, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_FIXED, fileno(fp), 0);fclose(fp);printf("%p\n", addr);printf("%08x\n", *(__uint8_t *)0x80000000);return 0;
}
需要注意的是,我们这里是脱离了Android Studio 来编写一个可执行程序,所以需要先搭建一下环境:
需要2个额外的文件来做交叉编译,试了下直接使用 aarch64-linux-gnu-gcc
编译出来的也无法执行,似乎必须得使用 ndk + cmake 来编译,不深入研究了,能跑就行。
2个额外文件的代码就不贴了,会上传到github上的 elf 文件夹里面。
https://github.com/aprz512/Android-Crack
将编译好的文件push到 /data/local/tmp/ 文件夹下,测试各个参数的作用。
第一个参数
第一个参数表示我们期望映射的地址,但是os并不一定会映射到这个地址,文档里面也说了,linux会选择一个页对齐的地址返回,如果该地址被占用了,会返回一个其他的地址。
第二个参数
第二个参数是映射的长度,这个很值得研究,需要分情况讨论。
我们以 four.bin 为例,该文件里面就只有 3 个字符串数字,大小为4个字节:
echo "123" > four.bin
当mmap传递的参数小于文件大小时,我们修改代码,将第二个参数的值改为2:
void *addr = mmap((void *)0x80000000, 0x2, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_FIXED, fileno(fp), 0);
尝试访问 0x80000002 处的地址,按照直觉来说,这个位置没有被分配,所以应该会出现 Segmentation fault 之类的错误。但是实际上并没有,输出结果为:
0x80000000
00000033
0x33对应的ascii就是字符“3”,这说明,它将整个文件都映射进去了,其实mmap是按照页来映射的,以 4KB 为单位。我们可以使用 IDA 验证一下,使用 getchar 卡住程序,然后调试程序:
可以看到 0x80000000 开始的位置确实是 four.bin 文件的数据。往下看直到 0x80000FFF的位置都是0值,从 0x80001000开始就不是进程空间地址了。
我们再做一个实验,将映射长度改为8KB,访问4KB+1的位置会如何呢?
0x80000000
00000033
Bus error
可以看到,访问 0x80000002 位置依然没有问题,但是访问 0x80001000 位置却出现了 Bus error。这个文档里面也说明了,出现这个错误是因为访问了超出文件映射结尾的页地址导致的。
我们看下 IDA 情况:
可以看到,后面的一页都是问号,访问这里面的虚拟地址就会出现 bus error。
第三个参数
权限标志位,没啥好说的,不如看文档。
需要注意的是,这里我们先全给 RWX,因为需要重定位,否则会报错。
第四个参数
只说一个MAP_FIXED,前面说到第一个参数的时候,我们传递了一个值给os,可是os不一定理我们。但是有些情况我们一定要os映射到指定的位置才行,比如段的加载。elf里面有 .text / .data 段,这两个段之间是有关系的,它们之间存在相互引用,如果不将这两个玩意挨着放,那么它们之间的一些相对偏移就会出问题。
所以,如何解决这个问题呢?就是传递 MAP_FIXED 标志位,它表示如果不能映射到我们指定的位置,干脆就直接失败。
加载段
好了,有了上面的基础,我们就可以自己实现 elf 的段加载了,其实就是调用 mmap 函数,将可加载段映射一下就完事。
不过需要考虑的事情有:当文件大小小于内存大小的时候,要怎么解决?
上面我们已经验证过了,如果直接映射会出 bus error。
所以,我们可以分两次映射,第二次映射一个匿名文件,是不是想到 maps 里面没名字的那一行了。
我们可以先看 linker 源码学习一下。
linker 源码
https://github.com/aosp-mirror/platform_bionic/blob/donut-release2/linker/linker.c
由于linker的核心代码变化不会太大,所以强烈建议研究老版本的源码,弄清楚了再去看新版本的。
这里有一个图:
示例代码
#include <stdio.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <string.h>
#include <elf.h>#define PAGE_SIZE (4096)
#define PAGE_MASK (PAGE_SIZE - 1)
#define BASE (0x80000000)int main()
{// FILE *fp = fopen("/data/local/tmp/four.bin", "rb");// void *addr = mmap((void *)0x80000000, 0x2000, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_FIXED, fileno(fp), 0);// fclose(fp);// printf("%p\n", addr);// printf("%08x\n", *(__uint8_t *)0x80000002);// // printf("%08x\n", *(__uint8_t *)0x80001000);// getchar();size_t elf64_header = sizeof(Elf64_Ehdr);Elf64_Ehdr *ehdr = (Elf64_Ehdr *)malloc(elf64_header);FILE *fp = fopen("/data/local/tmp/ls", "rb");// read Elf64_Ehdr bytesfread(ehdr, elf64_header, 1, fp);printf("e_phoff: %08x\n", ehdr->e_phoff);size_t elf64_phdr = sizeof(Elf64_Phdr);int phdr_num = ehdr->e_phnum;printf("phdr_num: %d\n", phdr_num);Elf64_Phdr *phdr = (Elf64_Phdr *)malloc(elf64_phdr * phdr_num);fseek(fp, ehdr->e_phoff, SEEK_SET);fread(phdr, elf64_phdr * phdr_num, 1, fp);uint64_t len;uint64_t tmp;uint64_t pbase;uint64_t extra_len;uint64_t extra_base;for (size_t i = 0; i < phdr_num; i++){// printf("p_type: %d\n", phdr->p_type);if (phdr->p_type == PT_LOAD){// 这里计算的是 pbase 的值tmp = BASE + phdr->p_vaddr & (~PAGE_MASK);// 看图可知,这里的文件大小加上 ( base + p_vaddr - pbase),也就是 mask off 的值len = phdr->p_filesz + (phdr->p_vaddr & PAGE_MASK);pbase = mmap(tmp,len,PROT_EXEC | PROT_WRITE | PROT_READ,MAP_PRIVATE | MAP_FIXED,fileno(fp),phdr->p_offset & (~PAGE_MASK));printf("mapped addr: %08x, %08x\n", pbase, len);tmp = (unsigned char *)(((unsigned)pbase + len + PAGE_SIZE - 1) & (~PAGE_MASK));if (tmp < (BASE + phdr->p_vaddr + phdr->p_memsz)){extra_len = BASE + phdr->p_vaddr + phdr->p_memsz - tmp;extra_base = mmap((void *)tmp, extra_len,PROT_EXEC | PROT_WRITE | PROT_READ,MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,-1, 0);printf("mapped addr: %08x, %08x\n", extra_base, extra_len);}}phdr++;}free(ehdr);free(phdr);fclose(fp);printf("mapped ok!!!");return 0;
}
运行结果如下:
sailfish:/data/local/tmp # ./elf
e_phoff: 00000040
phdr_num: 9
mapped addr: 80000000, 0005c45c
mapped addr: 8005d000, 000047a0
mapped addr: 80062000, 00003966
相关文章:

ELF解析03 - 加载段
本文主要讨论 mmap 函数以及如何使用 mmap 函数来加载一个 ELF 的可加载段。 01纠错 Android 8 及以后是会读取 section header 的,但不是所有的 section 都会读取。 https://cs.android.com/android/platform/superproject/main//main:bionic/linker/linker_phdr…...

Mysql——索引相关的数据结构
索引 引入 我们知道,数据库查询是数据库的最主要功能之一。我们都希望查询数据的速度能尽可能的快,因此数据库系统的设计者会从查询算法的角度进行优化。最基本的查询算法当然是顺序查找(linear search),这种复杂度为…...

无代码DIY图像检索
软件环境准备 可参见《HuggingFists-低代码玩转LLM RAG-准备篇》中的HuggingFists安装及Milvus安装。 流程环境准备 图片准备 进入HuggingFists内置的文件系统,数据源->文件系统->sengee_fs_settings_201创建Image文件夹将事先准备的多张相同或不同种类的图…...

Elasticsearch--Master选举
角色 主节点(active master):一般指的是活跃的主节点,避免负载任务,主节点主要用来管理集群,专用master节点仍将充当协调节点 候选节点(master-eligible nodes):默认具备…...

微服务实战系列之Filter
前言 Filter,又名过滤器,当然不是我们日常中见到的,诸如此类构件: 而应该是微服务中常使用的,诸如此类(图片来自官网,点击可查看原图): 一般用于字符编码转换…...

使用GPT大模型调用工具链
本文特指openai使用sdk的方式调用工具链。 安装openai pip install openai export OPENAI_API_KEY"YOUR OPENAI KEY" 定义工具函数 from openai import OpenAI import jsonclient OpenAI() #工具函数 def get_current_weather(location, unit"fahrenheit&q…...

C语言实现bmp图像底层数据写入与创建
要用C语言实现bmp图像底层数据写入进而创建一张bmp图像,需要对bmp图像文件格式非常了解,如果不太熟悉bmp图像文件格式请先移步bmp图像文件格式超详解 创建bmp图像文件的方式有很多,比如用halcon,用qt,这些都是把已经画…...

基于BP神经网络的定位算法,基于BP神经网络定位预测
目录 摘要 BP神经网络参数设置及各种函数选择 参数设置 训练函数 传递函数 学习函数 性能函数 显示函数 前向网络创建函数 BP神经网络训练窗口详解 训练窗口例样 训练窗口四部详解 基于BP神经网络的定位算法,基于BP神经网络定位预测 代码下载:基于BP神经网络的定位算法,基于…...

Java Http各个请求类型详细介绍
1. 前言 在Spring Boot框架中,HTTP请求类型是构建Web应用程序的重要组成部分。常见的请求类型包括GET、POST、PUT和DELETE,每种类型都有其特定的用途和特点。本文将详细比较这四种请求类型,帮助您在开发过程中做出明智的选择。 2. GET请求…...

python函数装饰器参数统计调用时间和次数
1 python函数装饰器参数统计调用时间和次数 python在函数装饰器外层定义一个函数生成封闭作用域来保存装饰器入参,供装饰器使用。 1.1 装饰器统计调用时间和次数 描述 通过类的可调用实例装饰器来统计函数每次调用时间和总调用时间,以及调用次数。 …...

机器学习之集成学习AdaBoost
概念 AdaBoost(Adaptive Boosting)是一种迭代的集成学习算法,其主要目标是通过组合多个弱学习器来创建一个强大的模型。以下是AdaBoost算法的主要步骤: 初始化样本权重: 为每个训练样本分配相等的权重,通常设为 w i = 1 N w_i = \frac{1}{N} w...

行云部署成长之路 -- 慢 SQL 优化之旅 | 京东云技术团队
当项目的SQL查询慢得像蜗牛爬行时,用户的耐心也在一点点被消耗,作为研发,我们可不想看到这样的事。这篇文章将结合行云部署项目的实践经验,带你走进SQL优化的奇妙世界,一起探索如何让那些龟速的查询飞起来!…...

Windows权限提升
0x01 简介 提权可分为纵向提权与横向提权: 纵向提权:低权限角色获得高权限角色的权限; 横向提权:获取同级别角色的权限。 Windows常用的提权方法有:系统内核溢出漏洞提权、数据库提权、错误的系统配置提权、组策略首…...

win系统搭建Minecraft世界服务器,MC开服教程,小白开服教程
Windows系统搭建我的世界世界服务器,Minecraft开服教程,小白开服教程,MC 1.19.4版本服务器搭建教程。 此教程使用 Mohist 1.19.4 服务端,此服务端支持Forge模组和Bukkit/Spigot/Paper插件,如果需要开其他服务端也可参…...

word2vec中的CBOW和Skip-gram
word2cev简单介绍 Word2Vec是一种用于学习词嵌入(word embeddings)的技术,旨在将单词映射到具有语义关联的连续向量空间。Word2Vec由Google的研究员Tomas Mikolov等人于2013年提出,它通过无监督学习从大规模文本语料库中学习词汇…...

在ios上z-index不起作用问题的总结
最近在维护一个H5老项目时,遇到一个问题,就是在ios上z-index不起作用,在安卓上样式都是好的。 项目的架构组成是vue2.x vux vuex vue-router等 用的UI组件库是vux 在页面中有一个功能点,就是点选择公司列表的时候,会…...

力扣labuladong一刷day59天动态规划
力扣labuladong一刷day59天动态规划 文章目录 力扣labuladong一刷day59天动态规划一、509. 斐波那契数二、322. 零钱兑换 一、509. 斐波那契数 题目链接:https://leetcode.cn/problems/fibonacci-number/description/ 思路:这是非常典型的一道题&#x…...

pyenv环境找不到sqlite:No module named _sqlite3
前言 一般遇到这个问题都在python版本管理或者虚拟环境切换中遇到,主要有两个办法解决,如下: 解决方法1 如果使用的pyenv管理python环境时遇到没有_sqlite3 库,可以将当前pyenv的python环境卸载 pyenv uninstall xxx然后在系统…...

Histone H3K4me2 Antibody, SNAP-Certified™ for CUTRUN
EpiCypher是一家为表观遗传学和染色质生物学研究提供高质量试剂和工具的专业制造商。EpiCypher推出的CUT&RUN级别的Histone H3K4me2 Antibody符合EpiCypher的批次特异性SNAP-CertifiedTM标准,在CUT&RUN中具有特异性和高效的靶点富集。通过SNAP-CUTANA™K-Me…...

我用 Laf 开发了一个非常好用的密码管理工具
【KeePass 密码管理】是一款简单、安全简洁的账号密码管理工具,服务端使用 Laf 云开发,支持指纹验证、FaceID,N 重安全保障,可以随时随地记录我的账号和密码。 写这个小程序之前,在国内市场找了很多密码存储类的 App …...

windows项目部署
文章目录 一、项目部署1.1 先准备好文件1.2安装jdk1.3 配置环境1.4 安装tomcat1.5 MySQL安装本机测试的话:远程连接测试 1.6 项目部署 一、项目部署 1.1 先准备好文件 1.2安装jdk 下一步 下一步 下一步 1.3 配置环境 变量名:JAVA_HOME 变量值:jdk的…...

http首部
1. htttp 报文首部 报文结构为:首部 空行(CRLF)主体 在请求中 http报文首部由请求方法,URI,http版本,首部字段等构成 在响应中:状态码,http版本,首部字段3部分构成 2…...

2024.1.8 Day04_SparkCore_homeWork
目录 1. 简述Spark持久化中缓存和checkpoint检查点的区别 2 . 如何使用缓存和检查点? 3 . 代码题 浏览器Nginx案例 先进行数据清洗,做后续需求用 1、需求一:点击最多的前10个网站域名 2、需求二:用户最喜欢点击的页面排序TOP10 3、需求三&#x…...

09.简单工厂模式与工厂方法模式
道生一,一生二,二生三,三生万物。——《道德经》 最近小米新车亮相的消息可以说引起了不小的轰动,我们在感慨SU7充满土豪气息的保时捷设计的同时,也深深的被本土品牌的野心和干劲所鼓舞。 今天我们就接着这个背景&…...

DHCP,怎么在Linux和Windows中获得ip
一、DHCP 1.1 什么是dhcp DHCP动态主机配置协议,通常被应用在大型的局域网络环境中,主要作用是集中地管理、分配IP地址,使网络环境中的主机动态的获得IP地址、DNS服务器地址等信息,并能够提升地址的使用率。 DHCP作为用应用层协…...

读写锁(arm)
参考文章读写锁 - ARM汇编同步机制实例(四)_汇编 prefetchw-CSDN博客 读写锁允许多个执行流并发访问临界区。但是写访问是独占的。适用于读多写少的场景 另外好像有些还区分了读优先和写优先 读写锁定义 typedef struct {arch_rwlock_t raw_lock; #if…...

【第33例】IPD体系进阶:市场细分
目录 内容简介 市场细分原因 市场细分主要活动 市场细分流程 作者简介 内容简介 这节内容主要来谈谈 IPD 市场管理篇的市场细分步骤。 其中,市场管理(Market Management)是一套系统的方法。 用于对广泛的机会进行选择性收缩,...

response 拦截器返回的二进制文档(同步下载excel)如何配置
response 拦截器返回的二进制文档(同步下载excel)如何配置 一、返回效果图二、response如何配置 一、返回效果图 二、response如何配置 service.interceptors.response.use(response > {// 导出excel接口if (response.config.isExport) {return resp…...

为什么要使用云原生数据库?云原生数据库具体有哪些功能?
相比于托管型关系型数据库,云原生数据库极大地提高了MySQL数据库的上限能力,是云数据库划代的产品;云原生数据库最早的产品是AWS的 Aurora。AWS Aurora提出来的 The log is the database的理念,实现存储计算分离,把大量…...

05- OpenCV:图像操作和图像混合
目录 一、图像操作 1、读写图像 2、读写像素 3、修改像素值 4、Vec3b与Vec3F 5、相关的代码演示 二、图像混合 1、理论-线性混合操作 2、相关API(addWeighted) 3、代码演示(完整的例子) 一、图像操作 1、读写图像 (1)…...