bluesadi / Pluto

Obfuscator based on LLVM 14.0.6
831 stars 185 forks source link

GlobalsEncryption 在编译 protobuf 时由于 llvm.ctros 没有正确处理而 crash #55

Open mrh929 opened 11 months ago

mrh929 commented 11 months ago

用 pluto-obfuscator -gle 选项编译 protobuf (https://github.com/protocolbuffers/protobuf/tree/79009d92375c4ba955ef37c810b84a6d047bb7ee) 的时候模块出现 crash

我的调试代码如下:

bool GlobalsEncryption::runOnModule(Module &M) {
    if (!enable) {
        return false;
    }
    INIT_CONTEXT(M);

    int gv_count;
    vector<GlobalVariable *> GVs;

    gv_count = M.getGlobalList().size();
    for (GlobalVariable &GV : M.getGlobalList()) {
        GVs.push_back(&GV);
    }
    for (int i = 0; i < ObfuTimes; i++) {
        for (GlobalVariable *GV : GVs) {

        // for (GlobalVariable &T : M.getGlobalList()) {
        // GlobalVariable *GV = &T;

        outs() << "original gv_count: " << gv_count << "  now: " << M.getGlobalList().size() << "\n";

        outs() << "debug: ===============\n";

        outs() << "isa<GlobalVariable>:" << isa<GlobalVariable>(GV) << "\n";

        outs() << "GV->classof(GV):" << GV->classof(GV) << "\n";

        GV->dump();

        // Only encrypt globals of integer and array
        if (!GV->getValueType()->isIntegerTy() &&
            !GV->getValueType()->isArrayTy()) {
            continue;
        }

        outs() << "-----------------------\n";

        if (GV->hasInitializer() && GV->getInitializer() &&
            (GV->getName().contains(".str") || !OnlyStr)
            // Do not encrypt globals having a section named "llvm.metadata"
            && !GV->getSection().equals("llvm.metadata")) {
            Constant *initializer = GV->getInitializer();
            ConstantInt *intData = dyn_cast<ConstantInt>(initializer);
            ConstantDataArray *arrData = dyn_cast<ConstantDataArray>(initializer);
            if (arrData) {
            uint32_t eleSize = arrData->getElementByteSize();
            uint32_t eleNum = arrData->getNumElements();
            uint32_t arrLen = eleNum * eleSize;
            char *data = const_cast<char *>(arrData->getRawDataValues().data());
            char *dataCopy = new char[arrLen];
            memcpy(dataCopy, data, arrLen);
            uint64_t key = cryptoutils->get_uint64_t();
            // A simple xor encryption
            for (uint32_t i = 0; i < arrLen; i++) {
                dataCopy[i] ^= ((char *)&key)[i % eleSize];
            }
            GV->setInitializer(ConstantDataArray::getRaw(
                StringRef(dataCopy, arrLen), eleNum, arrData->getElementType()));
            GV->setConstant(false);
            insertArrayDecryption(M, {GV, key, eleNum});
            } else if (intData) {
            uint64_t key = cryptoutils->get_uint64_t();
            ConstantInt *enc =
                CONST(intData->getType(), key ^ intData->getZExtValue());
            GV->setInitializer(enc);
            GV->setConstant(false);
            insertIntDecryption(M, {GV, key, 1LL});
            }
        }
        }
    }
    return true;
}

部分编译错误信息: 新建 文本文档.txt 复现代码: gmock-all-5d551a.zip

目前初步结论是 M.getGlobalList() 函数返回的列表中的某些元素在处理的过程中有发生改变。而这里我们的代码直接在一开始就把列表中的元素全部放入了 vector 内,等到 vector 取出该元素时,它已经不是一个合法的 GlobalVariable 了,导致 pass crash 掉。

还发现了几个其他的 bug,晚点我会申请 pr