调试一款APP的时候遇到这个错误。于是用machoview打开,如图
就只看到这几个cmdsize是40,没看到size是67的呢?是怎么回事呢?另外67size是怎么造成的呢,不是size在arm64都是8的倍数,在32位是4的倍数,不知道这个是怎么造成的。。另外大佬们谁有machoview包,我的一打开十几秒就会闪退。。。Load command 67意思是第67条lc
手动改成8的倍数
怎么修改?有工具还是写代码?
1, 010 手动改
2, 写代码改
对不起我比较新手,,。我可不可以认为我在手动注入几个动态库,就能凑到8的倍数?
不行的 他是注入的dylib的LC command size 不是8的倍数 你插入dylib 也影响不到之前插入的值
自己写一段代码去读取 Mach Header 和 Load Commands,遍历一下 load_commands 列表,找一下异常的 cmd,然后修改掉 cmdsize 再写回去。
给你一段代码参考,我把 cmdsize 向上圆整了,可能会有问题,向下圆整同样有可能会出问题,如果都不行就得魔改 Mach-O 文件了。
#import <Foundation/Foundation.h>
#import <mach-o/loader.h>
#import <sys/stat.h>
void readMachO() {
NSString *filePath = @"<path to mach-o file>";
int fd = open(filePath.UTF8String, O_RDWR);
if (fd < 0) {
printf("open file error");
exit(1);
}
struct stat fileStatus;
fstat(fd, &fileStatus);
uint8_t *mappedData = mmap(NULL, fileStatus.st_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);
struct mach_header_64 *header = (struct mach_header_64 *)mappedData;
uint32_t ncmds = header->ncmds;
uint64_t cur = sizeof(struct mach_header_64);
uint8_t *loadCommandsData = mappedData + cur;
for (uint32_t i = 0; i < ncmds; i++) {
struct load_command *loadCommand = (struct load_command *)loadCommandsData;
if (loadCommand->cmdsize % 8 != 0) {
printf("bad load_command with size %d\n", loadCommand->cmdsize);
// fix up
uint32_t fixup = 8 * (1 + loadCommand->cmdsize / 8);
printf("fix it to %d\n", fixup);
loadCommand->cmdsize = fixup;
}
loadCommandsData += loadCommand->cmdsize;
cur += loadCommand->cmdsize;
}
// sync to disk
msync(mappedData, cur, MS_SYNC);
}
太牛逼了,哥
哈哈,张总见笑了。
太牛逼了,哥
嗯,我也参考yololib写了代码,和你的有一些差别。要是是fat的,你这样能改得到吗?另外修改了lc的cmdsize,header里面总的size是不是也要修改啊?
肯定的 总数也要改,很简单,目标lc cmdsize 向上补齐到8的倍数,lc末尾补若干0, 总的cmdsize也加,最后在lc cmd后面和第一个段之间有一大片0的位置减去几个0 这样文件后面偏移都不会变 fat 也可以
你这个代码好像是没有修改总的size呢?另外lc不是有dylib_command、segment_command_64等等很多种,他们的内存结构这些都不一样,你都是按照load_command来处理的,虽说不同的lc都有load_command里面的东西,但是都按照load_command这个来处理不会出错吗?比如dylib_command里面还有path这些要影响size的,union lc_str name 里面的offset是不是也要被修改才对?比如我发的图rpath_command他的size也是不对的,也能按照load_command来处理吗? 我的意思是是不是要区分不同的lc来做处理?另外有没有可视化的mach-o编辑器啊,没有的话撸一个怎么样?
他们有公共的头部字段 cmd 和 cmdsize,读取的时候是先按照 lc 处理的,根据 cmd 类型再转换。MachOView 就可以编辑,你如果闪退用源码 debug 下看看原因。
总大小要在 header 里修改,上面漏掉了,另外这个是以 ARM64 为示例的,Fat 的话需要额外处理 Fat Header。
嗯,我用macho找到位置用hexfriend修改的,你刚才说的的每个lc后面有很多空白的零,意思是比如我修改lcsize加了几个size,我就把后面空白去掉几个size,这样后面的偏移不会变,而且总的lcsize也不用修改是吗?
哈哈,我们是俩人,这个是那个大佬跟你说的,他应该是指虽然你把 cmdsize 改大了,但是由于 lc 最后和第一个段之间有 padding,可以从修改的 lc 开始 padding 到 8 的整数倍,余下的整体向下移。
哈哈哈哈,解决了,还是直接修改二进制快,感觉好简单,谢谢你们指导!
顺带问下这是防注入的一个手段吗?
不是,是一个注入dylib 代码的bug
修改lc之后签名又不行了,报这个错:invalid or unsupported format for signature。难道是我修改lc没修改对?