pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1)计算页偏移

本文介绍了一种在mmap中实现页对齐的方法,并通过示例代码详细解释了如何计算内存中的页偏移量。具体包括使用sysconf获取页大小、通过位运算计算偏移量等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1)计算页偏移

mmap的手册中有一段示例代码,其中有一行:

offset = atoi(argv[2]);
pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
/* offset for mmap() must be page aligned */

这一行代码表示的含义是:计算出内存中的页偏移量。具体的计算过程可以例举几个值计算一下,得到的刚好是指定偏移量offset对应的页偏移量。

下面进行验证:

首先使用getconf命令查看系统页大小,这里可以看到该系统的页大小为4096

ubuntu@ubuntu:~/Desktop/linux$ getconf -a | grep PAGE
PAGESIZE                           4096
PAGE_SIZE                          4096
_AVPHYS_PAGES                      23885
_PHYS_PAGES                        501586

然后将mmap手册中的代买复制出来,其中添加三行输出,编译并执行。

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define handle_error(msg) \
    do { perror(msg); exit(EXIT_FAILURE); } while (0)

int
main(int argc, char *argv[])
{
    char *addr;
    int fd;
    struct stat sb;
    off_t offset, pa_offset;
    size_t length;
    ssize_t s;

    if (argc < 3 || argc > 4) {
        fprintf(stderr, "%s file offset [length]\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    fd = open(argv[1], O_RDONLY);
    if (fd == -1)
        handle_error("open");

    if (fstat(fd, &sb) == -1)           /* To obtain file size */
        handle_error("fstat");

    offset = atoi(argv[2]);
    pa_offset = offset & ~(sysconf(_SC_PAGE_SIZE) - 1);
        /* offset for mmap() must be page aligned */

    if (offset >= sb.st_size) {
        fprintf(stderr, "offset is past end of file\n");
        exit(EXIT_FAILURE);
    }

    if (argc == 4) {
        length = atoi(argv[3]);
        if (offset + length > sb.st_size)
            length = sb.st_size - offset;
                /* Can't display bytes past end of file */

    } else {    /* No length arg ==> display to end of file */
        length = sb.st_size - offset;
    }

    addr = mmap(NULL, length + offset - pa_offset, PROT_READ,
                MAP_PRIVATE, fd, pa_offset);
    if (addr == MAP_FAILED)
        handle_error("mmap");
	printf("length = %ld\n", length);
	printf("offset = %ld\n", offset);
	printf("pa_offset = %ld\n", pa_offset);
	printf("length + offset - pa_offset = %ld\n", length + offset - pa_offset);
    s = write(STDOUT_FILENO, addr + offset - pa_offset, length);
    if (s != length) {
        if (s == -1)
            handle_error("write");

        fprintf(stderr, "partial write");
        exit(EXIT_FAILURE);
    }

    munmap(addr, length + offset - pa_offset);
    close(fd);

    exit(EXIT_SUCCESS);
}

运行结果为:

ubuntu@ubuntu:~/Desktop/linux$ ./a.out 0.test.c 6000 6000
length = 6000
offset = 6000
pa_offset = 4096
length + offset - pa_offset = 7904
# 下面省略输出的文件内容
#include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;unistd.h&gt; #include &lt;sys/ptrace.h&gt; #include &lt;sys/wait.h&gt; #include &lt;errno.h&gt; #include &lt;stdint.h&gt; #include &lt;string.h&gt; #include &lt;pthread.h&gt; #include &lt;signal.h&gt; #define TARGET_PKG &quot;com.proximabeta.mf.uamo&quot; // 目标应用包名 #define TARGET_LIB &quot;libanogs.so&quot; // 目标动态库名 #define CHECK_INTERVAL 3 // 检查间隔(秒) #define MAX_RETRY 5 // 最大重试次数 #define PAGE_SIZE sysconf(_SC_PAGESIZE) #define ARM64_INSTRUCTION_SIZE 8 // ARM64指令长度(8字节) #define PTRACE_DATA_TYPE uint64_t // 64位数据类型 // Hook点配置结构(ARM64专用,64位指令) typedef struct { long offset; // 模块内偏移(64位,需与基址相加得到绝对地址) PTRACE_DATA_TYPE shellcode; // 64位机器码(如NOP指令:0xD503201F) PTRACE_DATA_TYPE original; // 原始64位指令(运行时读取) } HookPoint; // 线程控制结构体(共享状态) struct ThreadControl { pthread_mutex_t lock; // 互斥锁 int active; // 监控状态(1=运行,0=停止) int hook_success; // Hook结果(1=成功,0=失败) }; // 示例Hook点(需根据实际反汇编填写,注意8字节对齐) HookPoint hooks[] = { {0x1A8D08, 0xD503201F, 0}, // 偏移+64位NOP指令+原始指令(初始0) // 添加更多Hook点:{offset, 0x十六进制机器码, 0}, }; int num_hooks = sizeof(hooks) / sizeof(HookPoint); // 全局控制变量 struct ThreadControl ctrl = { .active = 1, .hook_success = 0 }; // 信号处理函数(处理中断信号) void handle_signal(int sig) { printf(&quot;\n接收到信号 %d,正在清理...\n&quot;, sig); pthread_mutex_lock(&amp;ctrl.lock); ctrl.active = 0; // 停止监控 pthread_mutex_unlock(&amp;ctrl.lock); } // 获取目标进程PID(带缓存) static int get_pid_cached(int *cached_pid) { static int last_pid = -1; if (*cached_pid &gt; 0) return *cached_pid; // 使用缓存PID char cmd[128]; snprintf(cmd, sizeof(cmd), &quot;pidof -s %s&quot;, TARGET_PKG); FILE *fp = popen(cmd, &quot;r&quot;); if (!fp) return -1; int pid = -1; if (fscanf(fp, &quot;%d&quot;, &amp;pid) == 1) { last_pid = pid; } pclose(fp); return (*cached_pid = pid); // 更新缓存并返回 } // 获取模块基址(带缓存,64位处理) static long get_module_base_cached(int pid, long *cached_base) { static long last_base = -1L; if (*cached_base != -1L) return *cached_base; // 使用缓存基址 char path[64]; snprintf(path, sizeof(path), &quot;/proc/%d/maps&quot;, pid); FILE *fp = fopen(path, &quot;r&quot;); if (!fp) return -1L; char line[256]; while (fgets(line, sizeof(line), fp)) { if (strstr(line, TARGET_LIB)) { char *start_addr = strtok(line, &quot;-&quot;); *cached_base = strtoul(start_addr, NULL, 16); // 解析64位十六进制地址 fclose(fp); return *cached_base; } } fclose(fp); return (*cached_base = -1L); // 模块未加载 } // ARM64专用Hook安装函数(64位指令操作) static int install_hooks(int pid, long base) { if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) { perror(&quot;ptrace 附加失败&quot;); return -1; } int status; waitpid(pid, &amp;status, 0); // 等待进程暂停 int success_count = 0; for (int i = 0; i &lt; num_hooks; i++) { HookPoint *hook = &amp;hooks[i]; uintptr_t addr = (uintptr_t)base + hook-&gt;offset; // 计算绝对地址 // ARM64地址对齐检查(必须8字节对齐) if ((addr &amp; (ARM64_INSTRUCTION_SIZE - 1)) != 0) { fprintf(stderr, &quot;错误:Hook地址0x%lx未8字节对齐(ARM64要求)\n&quot;, addr); continue; } // 读取原始64位指令 hook-&gt;original = ptrace(PTRACE_PEEKDATA, pid, (void*)addr, NULL); if (errno != 0) { fprintf(stderr, &quot;读取0x%lx原始指令失败: %s\n&quot;, addr, strerror(errno)); continue; } // 写入新64位指令 if (ptrace(PTRACE_POKEDATA, pid, (void*)addr, hook-&gt;shellcode) == -1) { fprintf(stderr, &quot;写入0x%lx新指令失败: %s\n&quot;, addr, strerror(errno)); continue; } // 验证写入结果 PTRACE_DATA_TYPE verify = ptrace(PTRACE_PEEKDATA, pid, (void*)addr, NULL); if (verify == hook-&gt;shellcode) { success_count++; printf(&quot;Hook[%d] 成功:0x%016&quot; PRIxPTR &quot; 原始=0x%016&quot; PRIx64 &quot; 新=0x%016&quot; PRIx64 &quot;\n&quot;, i, addr, hook-&gt;original, hook-&gt;shellcode); } else { fprintf(stderr, &quot;Hook[%d] 验证失败:预期0x%016&quot; PRIx64 &quot; 实际0x%016&quot; PRIx64 &quot;\n&quot;, i, hook-&gt;shellcode, verify); } } ptrace(PTRACE_DETACH, pid, NULL, NULL); // 分离进程 return success_count == num_hooks ? 0 : -1; // 所有Hook成功才返回0 } // 监控线程函数(循环尝试Hook) void* monitor_thread(void *arg) { int cached_pid = -1; long cached_base = -1L; int attempt = 0; while (1) { pthread_mutex_lock(&amp;ctrl.lock); if (!ctrl.active) { // 检查是否停止监控 pthread_mutex_unlock(&amp;ctrl.lock); break; } pthread_mutex_unlock(&amp;ctrl.lock); int pid = get_pid_cached(&amp;cached_pid); if (pid &lt;= 0) { printf(&quot;目标进程未运行,等待%d秒...\n&quot;, CHECK_INTERVAL); sleep(CHECK_INTERVAL); continue; } long base = get_module_base_cached(pid, &amp;cached_base); if (base == -1L) { printf(&quot;目标模块未加载,等待%d秒...\n&quot;, CHECK_INTERVAL); sleep(CHECK_INTERVAL); continue; } printf(&quot;尝试 %d/%d:PID=%d,模块基址=0x%lx\n&quot;, ++attempt, MAX_RETRY, pid, base); if (install_hooks(pid, base) == 0) { pthread_mutex_lock(&amp;ctrl.lock); ctrl.hook_success = 1; // 标记Hook成功 pthread_mutex_unlock(&amp;ctrl.lock); printf(&quot;所有Hook安装成功!\n&quot;); break; } if (attempt &gt;= MAX_RETRY) { printf(&quot;超过最大尝试次数%d,Hook失败\n&quot;, MAX_RETRY); break; } sleep(CHECK_INTERVAL); // 间隔后重试 } return NULL; } int main() { // 初始化互斥锁 if (pthread_mutex_init(&amp;ctrl.lock, NULL) != 0) { perror(&quot;互斥锁初始化失败&quot;); return EXIT_FAILURE; } // 注册信号处理(Ctrl+C退出) signal(SIGINT, handle_signal); signal(SIGTERM, handle_signal); pthread_t monitor; if (pthread_create(&amp;monitor, NULL, monitor_thread, NULL) != 0) { perror(&quot;监控线程创建失败&quot;); pthread_mutex_destroy(&amp;ctrl.lock); return EXIT_FAILURE; } // 等待监控线程结束 pthread_join(monitor, NULL); // 清理资源 pthread_mutex_destroy(&amp;ctrl.lock); if (ctrl.hook_success) { printf(&quot;Hook安装成功,程序正常退出\n&quot;); return EXIT_SUCCESS; } else { printf(&quot;Hook安装失败,程序退出\n&quot;); return EXIT_FAILURE; } }完整修复这个代码。
05-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值