codesign_allocate 的 bug 依旧是个谜

昨天写的 codesign --remove-signature 的 bug 解决 一文中,在最末尾猜测了可能是 LLVM 的 LTO (link time optimaliztion)的问题,然后今天把 LLVM 的头文件下下来了,打开了 LTO 支持,发现也是可行的。这个就让人摸不着头脑了。不过上面提到的解决方法是没问题的。

如果想要打开 LLVM 的 LTO 支持的话,可以去 LLVM 的官网下载 Pre-built Binaries。比如现在的 LLVM Release 是 4.0.0,那么就下载Clang for Mac OS X。然后加上对应的编译选项 -I/PATH/TO/YOUR/clang+llvm-4.0.0-x86_64-apple-darwin/include(指定头文件搜索 clang+llvm-4.0.0-x86_64-apple-darwin/include 目录)

codesign_allocate compiled with LTO support
codesign_allocate compiled with LTO support

所以我们什么都不用改,只需要把 Apple 开源的 cctools 中的 codesign_allocate 重新编译一下,问题就神奇的解决了。

不过 codesign_allocate 中的确是存在一处无符号整数溢出的问题,只不过几乎没有影响。

在下面已经用高亮背景标记。

/*
* If this has a code signature load command reuse it and just change
* the size of that data.  But do not use the old data.
*/
if(object->code_sig_cmd != NULL){
    if(object->seg_linkedit != NULL){
        object->seg_linkedit->filesize += arch_signs[i].datasize - object->code_sig_cmd->datasize; 
        if(object->seg_linkedit->filesize > object->seg_linkedit->vmsize)
            object->seg_linkedit->vmsize = rnd(object->seg_linkedit->filesize, get_segalign_from_flag(&arch_signs[i].arch_flag));
    }
    else if(object->seg_linkedit64 != NULL){
        object->seg_linkedit64->filesize += arch_signs[i].datasize;
        object->seg_linkedit64->filesize -= object->code_sig_cmd->datasize;
        if(object->seg_linkedit64->filesize > object->seg_linkedit64->vmsize)
            object->seg_linkedit64->vmsize = rnd(object->seg_linkedit64->filesize,
        get_segalign_from_flag(&arch_signs[i].arch_flag));
    }

    object->code_sig_cmd->datasize = arch_signs[i].datasize;
    object->output_code_sig_data_size = arch_signs[i].datasize;
    object->output_code_sig_data = NULL;

    object->output_sym_info_size = rnd(object->output_sym_info_size, 16);
    object->output_sym_info_size += object->code_sig_cmd->datasize;
}

这里是在更新签名时,计算 i386 结构部分的 MachO 头部的 __LINKEDIT 段文件大小的代码,datasize 和 filesize 都是 uint32_t 类型,那么,如果是一个已经有代码签名的 i386 MachO 的话,在去除签名的时候,我们知道 datasize 是等于 0 的,而已有的 object->code_sig_cmd->datasize 必然是大于 0 的一个数,如此一来,算出来的结果就溢出了。

然而明明就在 else 语句处理 x86_64 部分,计算 __LINKEDIT 段的文件大小都是分成两句来写的……不过现在 macOS 上几乎难以找到 32 位的应用程序了,所以这一段也没什么影响。就算有这样的 32 位的文件,第一次 0 减去正数溢出之后,object->seg_linkedit->filesize 加上这个数又会溢出一次。不过一般情况下没问题,但是 object->code_sig_cmd->datasize > object->seg_linkedit->filesize 时,最终的object->seg_linkedit->filesize 就是一个非常大的数(因为是 uint32_t,如果你把它按照有符号数来解释的话,就是一个负数了)

Leave a Reply

Your email address will not be published. Required fields are marked *

16 + fourteen =