DWORD-aligned

本文解释了Windows系统中对ACL长度进行DWORD对齐的具体方法及其原因。通过详细步骤说明如何确保数据结构开始位置位于DWORD边界上,以符合系统对内存地址的要求。

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

系统:Windows8.1 64bit CS

这两天正好看到InitializeACL()  msdn.microsoft.com/en-us/library/windows/desktop/aa378853(v=vs.85).aspx

其中nAclLength [in]要求". In addition, this value must be DWORD-aligned. For more information about calculating the size of anACL, see Remarks.",而后面的例子是这么做align的

// Align cbAcl to a DWORD.
    cbAcl = (cbAcl + (sizeof(DWORD) - 1)) & 0xfffffffc;

那到底什么是aligned呢,为什么cbAcl要那么计算呢??


幸好有【ri_aje】的回答:

 cbAcl = (cbAcl + (sizeof(DWORD) - 1)) & 0xfffffffc;
cbAcl要被DWORD-aligned的意思就是能被4整除     在windows 32位、64位上DWORD都是4字节(64位上有个单独的DWORD64),即能被4整除。

http://stackoverflow.com/questions/39419/visual-c-how-large-is-a-dword-with-32-and-64-bit-code

任意数X要做到能被DWORD/4整除要做2步(类似可以扩展到WORD,DWORD64吧)

1.  X=X+(sizeof(DWORD)-1)    假设X∈【N*4 , (N+1)*4 ),N属于正整数。 X加上sizeof(DWORD)-1的目的是为了得到不小于X的并能被4整除的N*4或(N+1)*4

2. X=X & 0xfffffffc   与0xfffffffc的目的就是让X能被4整除。 若X==N*4,那最后我们得到N*4; 若X>N*4,那最后我们得到(N+1)*4


根据MSDN的DWORD-aligned定义  http://msdn.microsoft.com/en-us/library/aa369366%28v=vs.85%29.aspx

Each data structure in a value list must begin on a DWORD boundary. This means that the distance (in bytes) between the start of the value list buffer and the start of any data structure is always an even multiple of sizeof(DWORD).

这里要注意的是

1.   “begin on a DWORD boundary.”:DWORD是4字节,故DWORD bounday就是能被4整除的地方

2. "an even multiple of" :这里even不是偶数的意思,而是作为adv. "used to emphasize something unexpected or surprising",强调multiple of,即整数倍sizeof(DWORD)

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/mman.h> #include <sys/uio.h> #include <signal.h> #include <fcntl.h> #include <errno.h> #include <dirent.h> #include <ctype.h> #include <sys/types.h> #include <stdint.h> #include <sys/syscall.h> #include <sys/ptrace.h> #include <sys/wait.h> // ARM64缓存类型定义 #ifndef CACHE_TYPE_INSTRUCTION #define CACHE_TYPE_INSTRUCTION 0 #endif #ifndef CACHE_TYPE_DATA #define CACHE_TYPE_DATA 1 #endif // 系统调用号数组(适配Linux 5系列内核) #if defined(__aarch64__) const int cache_flush_syscalls[] = {118, 123, 124, 125, 126, 0}; #endif typedef uint64_t ADDRESS; // 全局变量(存储目标进程信息) struct ProcessInfo { int pid; uint64_t so_base; } processInfo = {-1, 0}; typedef struct { uint64_t start_addr; uint64_t end_addr; char permissions[5]; } ModuleRange; typedef struct { ModuleRange ranges[200]; int count; } ModuleInfo; // 获取目标进程PID int getPID(const char *packageName) { int id = -1; DIR *dir = opendir("/proc"); if (!dir) { perror("打开/proc目录失败"); return -1; } struct dirent *entry; while ((entry = readdir(dir)) != NULL) { if (entry->d_type == DT_DIR) { id = atoi(entry->d_name); if (id > 0) { char filename[64], cmdline[64]; snprintf(filename, sizeof(filename), "/proc/%d/cmdline", id); FILE *fp = fopen(filename, "r"); if (fp) { if (fgets(cmdline, sizeof(cmdline), fp)) { cmdline[strcspn(cmdline, "\n")] = '\0'; if (strcmp(packageName, cmdline) == 0) { fclose(fp); closedir(dir); return id; } } fclose(fp); } } } } closedir(dir); return -1; } // 获取模块内存信息(增强权限检查) ModuleInfo get_module_info(int pid, const char *module_name) { ModuleInfo info = {0}; FILE *fp; char line[8192]; char filename[32]; snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); if ((fp = fopen(filename, "r")) == NULL) { perror("打开maps文件失败"); return info; } while (fgets(line, sizeof(line), fp)) { if (strstr(line, module_name)) { uint64_t start, end; char perms[5], offset[17], dev[6], inode[11], pathname[256]; // 增强解析逻辑 if (sscanf(line, "%lx-%lx %4s %16s %5s %10s %255[^\n]", &start, &end, perms, offset, dev, inode, pathname) >= 6) { if (start < end) { if (info.count < 200) { info.ranges[info.count].start_addr = start; info.ranges[info.count].end_addr = end; strncpy(info.ranges[info.count].permissions, perms, 4); info.ranges[info.count].permissions[4] = '\0'; info.count++; } else { printf("警告:模块映射段过多(超过200段),部分段未记录\n"); break; } } } } } fclose(fp); return info; } // 使用ptrace安全写入DWORD int SafeWriteDword(int pid, uint64_t addr, uint32_t value) { // 附加到目标进程 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) { perror("ptrace附加失败"); return -1; } // 等待进程暂停 int status; waitpid(pid, &status, 0); if (!WIFSTOPPED(status)) { perror("进程未暂停"); ptrace(PTRACE_DETACH, pid, NULL, NULL); return -1; } // 逐字写入(避免对齐问题) for (int i = 0; i < sizeof(uint32_t); i++) { uint8_t byte = (value >> (i * 8)) & 0xFF; long data = ptrace(PTRACE_PEEKTEXT, pid, addr + i, NULL); if (data == -1 && errno) { perror("ptrace读取失败"); ptrace(PTRACE_DETACH, pid, NULL, NULL); return -1; } // 修改单个字节 long new_data = (data & ~0xFF) | byte; if (ptrace(PTRACE_POKETEXT, pid, addr + i, new_data) == -1) { perror("ptrace写入失败"); ptrace(PTRACE_DETACH, pid, NULL, NULL); return -1; } } // 分离目标进程 if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) { perror("ptrace分离失败"); return -1; } return 0; } // 使用ptrace安全读取DWORD int SafeReadDword(int pid, uint64_t addr, uint32_t *value) { *value = 0; // 附加到目标进程 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) { perror("ptrace附加失败"); return -1; } // 等待进程暂停 int status; waitpid(pid, &status, 0); if (!WIFSTOPPED(status)) { perror("进程未暂停"); ptrace(PTRACE_DETACH, pid, NULL, NULL); return -1; } // 逐字读取(避免对齐问题) for (int i = 0; i < sizeof(uint32_t); i++) { long data = ptrace(PTRACE_PEEKTEXT, pid, addr + i, NULL); if (data == -1 && errno) { perror("ptrace读取失败"); ptrace(PTRACE_DETACH, pid, NULL, NULL); return -1; } *value |= ((uint32_t)(data & 0xFF)) << (i * 8); } // 分离目标进程 if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) { perror("ptrace分离失败"); return -1; } return 0; } // 使用__builtin___clear_cache刷新缓存 int flush_with_builtin(uint64_t addr, size_t size) { char *start = (char *)(addr & ~(4095ULL)); char *end = start + size; __builtin___clear_cache(start, end); printf("成功: 使用__builtin___clear_cache刷新指令缓存\n"); return 0; } // 五级强刷新机制 int enhanced_flush_cache(uint64_t addr, size_t size) { uint64_t aligned_addr = addr & ~(4095ULL); size_t aligned_size = ((addr + size - aligned_addr + 4095) / 4096) * 4096; #ifdef __aarch64__ // 1. 优先使用__builtin___clear_cache if (flush_with_builtin(aligned_addr, aligned_size) == 0) { return 0; } // 2. 尝试系统调用刷新 const int *syscall_num = cache_flush_syscalls; while (*syscall_num != 0) { int ret_instr = syscall(*syscall_num, aligned_addr, aligned_size, CACHE_TYPE_INSTRUCTION); if (ret_instr == 0) { printf("成功: 使用syscall %d 刷新缓存\n", *syscall_num); return 0; } syscall_num++; } // 3. mprotect内存属性修改方案 void *page_start = (void *)aligned_addr; int pagesize = sysconf(_SC_PAGESIZE); unsigned long page_count = (aligned_size + pagesize - 1) / pagesize; int protection = PROT_READ | PROT_WRITE | PROT_EXEC; if (mprotect(page_start, page_count * pagesize, protection) == 0) { printf("成功: 通过mprotect修改内存保护属性刷新缓存\n"); return 0; } // 4. msync强制同步方案 if (msync((void *)aligned_addr, aligned_size, MS_SYNC | MS_INVALIDATE) == 0) { printf("成功: 使用msync同步刷新缓存\n"); return 0; } // 5. 终极方案:重建内存映射 void *tmp = mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (tmp) { memcpy(tmp, (void *)aligned_addr, aligned_size); munmap((void *)aligned_addr, aligned_size); mmap((void *)aligned_addr, aligned_size, PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0); memcpy((void *)aligned_addr, tmp, aligned_size); munmap(tmp, aligned_size); printf("成功: 通过重建内存映射刷新缓存\n"); return 0; } #endif perror("所有缓存刷新方法均失败"); return -1; } // 暂停目标进程 int pause_process(int pid) { if (kill(pid, SIGSTOP) == -1) { perror("发送SIGSTOP失败"); return -1; } // 等待进程真正停止 int status; waitpid(pid, &status, WUNTRACED); if (!WIFSTOPPED(status)) { perror("进程未正确停止"); return -1; } printf("进程已暂停(PID: %d)\n", pid); return 0; } // 恢复目标进程 int resume_process(int pid) { if (kill(pid, SIGCONT) == -1) { perror("发送SIGCONT失败"); return -1; } printf("进程已恢复运行(PID: %d)\n", pid); return 0; } // 主Hook函数 void hook_il2cpp() { const char *packageName = "com.tencent.tmgp.cf"; const uint64_t HOOK_OFFSET = 0x7EFD168; const uint32_t HOOK_VALUE = 505416143; const uint32_t ORIGINAL_VALUE = 505416142; processInfo.pid = getPID(packageName); if (processInfo.pid <= 0) { printf("获取PID失败\n"); return; } printf("获取到目标进程PID: %d\n", processInfo.pid); ModuleInfo module_info = get_module_info(processInfo.pid, "libil2cpp.so"); if (module_info.count == 0) { printf("获取SO模块地址失败(可能无权限或模块未加载)\n"); return; } // 使用第一个可执行段的起始地址作为模块基址 uint64_t module_base = 0; for (int i = 0; i < module_info.count; i++) { if (strstr(module_info.ranges[i].permissions, "x")) { module_base = module_info.ranges[i].start_addr; break; } } if (module_base == 0) { printf("未找到可执行段,使用第一个段作为基址\n"); module_base = module_info.ranges[0].start_addr; } uint64_t target_addr = module_base + HOOK_OFFSET; printf("\nlibil2cpp.so 模块基址: 0x%016lx\n", module_base); printf("目标Hook地址: 0x%016lx (基址 + 0x%lx)\n", target_addr, HOOK_OFFSET); // 验证目标地址是否在模块范围内且具有写权限 int in_range = 0; int has_write_permission = 0; for (int i = 0; i < module_info.count; i++) { if (target_addr >= module_info.ranges[i].start_addr && target_addr <= module_info.ranges[i].end_addr) { in_range = 1; if (strstr(module_info.ranges[i].permissions, "w")) { has_write_permission = 1; } break; } } if (!in_range) { printf("\n目标地址0x%016lx超出模块范围,退出操作\n", target_addr); return; } if (!has_write_permission) { printf("\n警告:目标地址无写权限,尝试修改内存保护属性\n"); } // 暂停进程进行内存操作 if (pause_process(processInfo.pid) != 0) { printf("暂停进程失败,退出Hook流程\n"); return; } // 读取原始值并验证 uint32_t original_val; if (SafeReadDword(processInfo.pid, target_addr, &original_val) != 0) { printf("读取原始值失败,恢复进程并退出\n"); resume_process(processInfo.pid); return; } printf("原始值: %u (预期: %u)\n", original_val, ORIGINAL_VALUE); if (original_val != ORIGINAL_VALUE) { printf("警告:原始值(%u)与预期值(%u)不匹配,继续操作但结果可能异常\n", original_val, ORIGINAL_VALUE); } // 写入新值 if (SafeWriteDword(processInfo.pid, target_addr, HOOK_VALUE) != 0) { printf("修改失败(可能因内存保护或权限问题),恢复进程并退出\n"); resume_process(processInfo.pid); return; } printf("成功写入新值: %u\n", HOOK_VALUE); // 刷新指令缓存 if (enhanced_flush_cache(target_addr & ~(4095), 4096) != 0) { printf("警告:缓存刷新失败,可能存在执行风险\n"); } // 验证新值 uint32_t new_val; if (SafeReadDword(processInfo.pid, target_addr, &new_val) == 0) { printf("验证修改: 新值 = %u (预期: %u)\n", new_val, HOOK_VALUE); if (new_val == HOOK_VALUE) { printf("\033[32m验证成功:值已修改为预期值\033[0m\n"); } else { printf("\033[31m验证失败:新值(%u)与预期值(%u)不匹配\033[0m\n", new_val, HOOK_VALUE); } } else { printf("验证修改失败(无法读取新值)\n"); } // 恢复进程运行 if (resume_process(processInfo.pid) != 0) { printf("恢复进程失败\n"); return; } printf("进程已恢复运行\n"); // 等待进程稳定 sleep(2); // 验证恢复后的值 uint32_t restored_val; if (SafeReadDword(processInfo.pid, target_addr, &restored_val) == 0) { printf("恢复后的值: %u (预期: %u)\n", restored_val, ORIGINAL_VALUE); if (restored_val == ORIGINAL_VALUE) { printf("\033[32m验证成功:值已恢复为原始值\033[0m\n"); } else { printf("\033[31m验证失败:恢复后的值(%u)与原始值(%u)不匹配\033[0m\n", restored_val, ORIGINAL_VALUE); } } else { printf("验证恢复值失败(可能无权限或地址不可读)\n"); } } int main() { if (getuid() != 0) { printf("需要root权限运行!\n"); return 1; } hook_il2cpp(); return 0; }获取到目标进程PID: 24442 libil2cpp.so 模块基址: 0x0000006f46366000 目标Hook地址: 0x0000006f4e263168 (基址 + 0x7efd168) 警告:目标地址无写权限,尝试修改内存保护属性 进程未正确停止: No child processes 暂停进程失败,退出Hook流程 [进程已结束 - 按回车关闭]修复好完整发给我 确认无任何报错后
07-16
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值