huolong blog

LLVM框架开发(二)

指令替换pass编写

上一节介绍了如何使用新旧PassManager进行Pass编写,本节则真正上手一个Pass的编写过程中去。 该Pass的主要目标是将加减乘除等简单运算替换为更复杂但效果等价的操作,提高逆向分析的难度。以下代码将运算a+b替换为:a-(-b)

void subAddInst(Function &f)
{
    Function *tmp = &f;
    BinaryOperator *work = nullptr;
    // 遍历函数中的基本块
    for (Function::iterator bb = tmp->begin(); bb != tmp->end(); ++bb)
    {
        // 遍历基本块中的命令
        for (BasicBlock::iterator ins = bb->begin(); ins != bb->end(); ++ins)
        {
            if (ins->isBinaryOp())
            {
                if (ins->getOpcode() == Instruction::Add)
                {
                    errs() << "find add op" << '\n';
                    BinaryOperator *op = dyn_cast<BinaryOperator>(ins);
                    IRBuilder<> builder(op);
                    Value *negInst = builder.CreateNeg(op->getOperand(1));
                    Value *newInst = builder.CreateSub(op->getOperand(0), negInst);
                    op->replaceAllUsesWith(newInst);
                    work = op;
                }
            }
        }
    }
    // 注意原命令脱离基本块操作不要在迭代中实现,否则会破坏迭代结构进而报错
    work->eraseFromParent();
}

函数空壳化pass编写

恶作剧形式的一个Pass,功能为将传入的函数除了return命令以外的所有命令移除,达到该函数没有功能的作用(目前只对main函数起作用)。

void hollow(Function &f)
{
    vector<Instruction *> vectorIns;
    vector<BasicBlock *> vectorBB;
    for (BasicBlock &bb : f)
    {
        vectorBB.push_back(&bb);
    }
    // 移除函数中除了最后一个块以外的所有块
    for (auto bb = vectorBB.begin(); bb < vectorBB.end() - 1; bb++)
    {
        (*bb)->eraseFromParent();
    }
    BasicBlock *end = vectorBB[vectorBB.size()-1];
    for(Instruction &ins: *end)
    {
        if(isa<ReturnInst>(&ins))
        {
            continue;
        }
        else
        {
            vectorIns.push_back(&ins);
        }
    }
    // 移除最后一个块中除了return以外的所有命令
    for(Instruction *ins: vectorIns)
    {
        ins->eraseFromParent();
    }
}