Files
Mergen/lifter/Semantics.cpp
T
2024-07-09 14:26:09 +03:00

4600 lines
159 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "FunctionSignatures.h"
#include "GEPTracker.h"
#include "OperandUtils.h"
#include "PathSolver.h"
#include "includes.h"
#include "utils.h"
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Type.h>
#include <llvm/Support/Casting.h>
FunctionType* parseArgsType(funcsignatures::functioninfo* funcInfo,
LLVMContext& context) {
if (!funcInfo) {
FunctionType* externFuncType = FunctionType::get(
Type::getInt64Ty(context),
{llvm::Type::getInt64Ty(context), llvm::Type::getInt64Ty(context),
llvm::Type::getInt64Ty(context), llvm::Type::getInt64Ty(context),
llvm::Type::getInt64Ty(context), llvm::Type::getInt64Ty(context),
llvm::Type::getInt64Ty(context), llvm::Type::getInt64Ty(context),
llvm::Type::getInt64Ty(context), llvm::Type::getInt64Ty(context),
llvm::Type::getInt64Ty(context), llvm::Type::getInt64Ty(context),
llvm::Type::getInt64Ty(context), llvm::Type::getInt64Ty(context),
llvm::Type::getInt64Ty(context), llvm::Type::getInt64Ty(context)},
false);
return externFuncType;
}
std::vector<llvm::Type*> argTypes;
for (const auto& arg : funcInfo->args) {
llvm::Type* type = nullptr;
type = llvm::Type::getIntNTy(context, 8 << (arg.argtype.size - 1));
if (arg.argtype.isPtr) {
type = type->getPointerTo();
}
argTypes.push_back(type);
}
return llvm::FunctionType::get(llvm::Type::getInt64Ty(context), argTypes,
false);
}
vector<Value*> parseArgs(funcsignatures::functioninfo* funcInfo,
IRBuilder<>& builder) {
auto& context = builder.getContext();
auto RspRegister = GetRegisterValue(builder, ZYDIS_REGISTER_RSP);
if (!funcInfo)
return {
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_RAX),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_RCX),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_RDX),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_RBX),
Type::getInt64Ty(context)),
RspRegister,
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_RBP),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_RSI),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_RDI),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_RDI),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_R8),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_R9),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_R10),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_R11),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_R12),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_R13),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_R14),
Type::getInt64Ty(context)),
createZExtFolder(builder, GetRegisterValue(builder, ZYDIS_REGISTER_R15),
Type::getInt64Ty(context)),
getMemory()};
std::vector<Value*> args;
for (const auto& arg : funcInfo->args) {
Value* argValue = GetRegisterValue(builder, arg.reg);
argValue = createZExtOrTruncFolder(
builder, argValue,
Type::getIntNTy(context, 8 << (arg.argtype.size - 1)));
if (arg.argtype.isPtr)
argValue = ConvertIntToPTR(builder, argValue);
// now convert to pointer if its a pointer
args.push_back(argValue);
}
return args;
}
// probably move this stuff somewhere else
void callFunctionIR(string functionName, IRBuilder<>& builder,
funcsignatures::functioninfo* funcInfo) {
auto& context = builder.getContext();
/*
if (functionName == "GetTickCount64") {
SetRegisterValue(
builder, ZYDIS_REGISTER_RAX,
ConstantInt::get(builder.getInt64Ty(), 1)); // rax = externalfunc()
return;
}
*/
// TODO: lololololololol wtf
if (!funcInfo) {
// try to get funcinfo from name
funcInfo = funcsignatures::getFunctionInfo(functionName);
}
FunctionType* externFuncType = parseArgsType(funcInfo, context);
auto M = builder.GetInsertBlock()->getParent()->getParent();
// what about ordinals???????
Function* externFunc = cast<Function>(
M->getOrInsertFunction(functionName, externFuncType).getCallee());
// fix calling
vector<Value*> args = parseArgs(funcInfo, builder);
auto callresult = builder.CreateCall(externFunc, args);
SetRegisterValue(builder, ZYDIS_REGISTER_RAX,
callresult); // rax = externalfunc()
// check if the function is exit or something similar to that
}
Value* computeOverflowFlagAdc(IRBuilder<>& builder, Value* Lvalue,
Value* Rvalue, Value* cf, Value* add) {
auto cfc = createZExtOrTruncFolder(builder, cf, add->getType(), "ofadc1");
auto ofAdd = createAddFolder(builder, add, cfc, "ofadc2");
auto xor0 = createXorFolder(builder, Lvalue, ofAdd, "ofadc3");
auto xor1 = createXorFolder(builder, Rvalue, ofAdd, "ofadc4");
auto ofAnd = createAndFolder(builder, xor0, xor1, "ofadc5");
return createICMPFolder(builder, CmpInst::ICMP_SLT, ofAnd,
ConstantInt::get(ofAnd->getType(), 0), "ofadc6");
}
Value* computeOverflowFlagAdd(IRBuilder<>& builder, Value* Lvalue,
Value* Rvalue, Value* add) {
auto xor0 = createXorFolder(builder, Lvalue, add, "ofadd");
auto xor1 = createXorFolder(builder, Rvalue, add, "ofadd1");
auto ofAnd = createAndFolder(builder, xor0, xor1, "ofadd2");
return createICMPFolder(builder, CmpInst::ICMP_SLT, ofAnd,
ConstantInt::get(ofAnd->getType(), 0), "ofadd3");
}
Value* computeOverflowFlagSub(IRBuilder<>& builder, Value* Lvalue,
Value* Rvalue, Value* sub) {
auto xor0 = createXorFolder(builder, Lvalue, Rvalue, "ofsub");
auto xor1 = createXorFolder(builder, Lvalue, sub, "ofsub1");
auto ofAnd = createAndFolder(builder, xor0, xor1, "ofsub2");
return createICMPFolder(builder, CmpInst::ICMP_SLT, ofAnd,
ConstantInt::get(ofAnd->getType(), 0), "ofsub3");
}
Value* computeOverflowFlagSbb(IRBuilder<>& builder, Value* Lvalue,
Value* Rvalue, Value* cf, Value* sub) {
auto cfc = createZExtOrTruncFolder(builder, cf, sub->getType(), "ofsbb");
auto ofSub = createSubFolder(builder, sub, cfc, "ofsbb1");
auto xor0 = createXorFolder(builder, Lvalue, Rvalue, "ofsbb2");
auto xor1 = createXorFolder(builder, Lvalue, ofSub, "ofsbb3");
auto ofAnd = createAndFolder(builder, xor0, xor1, "ofsbb4");
return createICMPFolder(builder, CmpInst::ICMP_SLT, ofAnd,
ConstantInt::get(ofAnd->getType(), 0), "ofsbb5");
}
Value* computeAuxFlagSbb(IRBuilder<>& builder, Value* Lvalue, Value* Rvalue,
Value* cf) {
auto ci15 = ConstantInt::get(Lvalue->getType(), 15);
auto and0 = createAndFolder(builder, Lvalue, ci15, "auxsbb1");
auto and1 = createAndFolder(builder, Rvalue, ci15, "auxsbb2");
auto sub = createSubFolder(builder, and0, and1, "auxsbb3");
auto cfc = createZExtOrTruncFolder(builder, cf, sub->getType(), "auxsbb4");
auto add = createAddFolder(builder, sub, cfc, "auxsbb5");
return createICMPFolder(builder, CmpInst::ICMP_UGT, add, ci15, "auxsbb6");
}
/*
https://graphics.stanford.edu/~seander/bithacks.html#ParityWith64Bits
Compute parity of a byte using 64-bit multiply and modulus division
unsigned char b; // byte value to compute the parity of
bool parity =
(((b * 0x0101010101010101ULL) & 0x8040201008040201ULL) % 0x1FF) & 1;
The method above takes around 4 operations, but only works on bytes.
*/
Value* computeParityFlag(IRBuilder<>& builder, Value* value) {
LLVMContext& context = value->getContext();
Value* lsb = builder.CreateZExt(
createAndFolder(builder, value, ConstantInt::get(value->getType(), 0xFF),
"lsb"),
Type::getInt64Ty(context));
// s or u rem?
Value* parity = createAndFolder(
builder,
builder.CreateURem(
createAndFolder(
builder,
builder.CreateMul(
lsb, ConstantInt::get(lsb->getType(), 0x0101010101010101),
"pf1"),
ConstantInt::get(lsb->getType(), 0x8040201008040201ULL), "pf2"),
ConstantInt::get(lsb->getType(), 0x1FF), "pf3"),
ConstantInt::get(lsb->getType(), 1), "pf4");
// parity
parity =
builder.CreateICmpEQ(ConstantInt::get(lsb->getType(), 0), parity, "pf5");
return parity; // Returns 1 if even parity, 0 if odd
}
Value* computeZeroFlag(IRBuilder<>& builder, Value* value) { // x == 0 = zf
return createICMPFolder(builder, CmpInst::ICMP_EQ, value,
ConstantInt::get(value->getType(), 0), "zeroflag");
}
Value* computeSignFlag(IRBuilder<>& builder, Value* value) { // x < 0 = sf
return createICMPFolder(builder, CmpInst::ICMP_SLT, value,
ConstantInt::get(value->getType(), 0), "signflag");
}
// this function is used for jumps that are related to user, ex: vms using
// different handlers, jmptables, etc.
void branchHelper(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses, Value* condition,
string instname, int numbered) {
LLVMContext& context = builder.getContext();
// TODO:
// save the current state of memory, registers etc.,
// after execution is finished, return to latest state and continue
// execution from the other branch
auto block = builder.GetInsertBlock();
block->setName(instname + to_string(numbered));
auto function = block->getParent();
auto dest = instruction.operands[0];
Value* true_jump = ConstantInt::get(
function->getReturnType(),
dest.imm.value.s + instruction.runtime_address + instruction.info.length);
Value* false_jump =
ConstantInt::get(function->getReturnType(),
instruction.runtime_address + instruction.info.length);
Value* next_jump =
createSelectFolder(builder, condition, true_jump, false_jump);
auto lastinst = builder.CreateRet(next_jump);
uint64_t destination = 0;
PATH_info pathInfo = solvePath(function, destination, next_jump);
ValueToValueMapTy VMap_test;
block->setName("previousjmp_block-" + to_string(destination) + "-");
// cout << "pathInfo:" << pathInfo << " dest: " << destination <<
// "\n";
if (pathInfo == PATH_solved) {
lastinst->eraseFromParent();
string block_name = "jmp-" + to_string(destination) + "-";
auto bb = BasicBlock::Create(context, block_name.c_str(),
builder.GetInsertBlock()->getParent());
builder.CreateBr(bb);
blockAddresses->push_back(make_tuple(destination, bb, getRegisters()));
}
}
namespace mov {
void lift_movsb(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
// DEST := SRC;
// [esi] = [edi]
// sign = DF (-1/+1)
// incdecv = size*sign (sb means size is 1)
// esi += incdecv
// edi += incdecv
//
// Value* SRCptrvalue =
// GetOperandValue(builder,instruction.operands[0],instruction.operands[0].size);
Value* DSTptrvalue = GetOperandValue(builder, instruction.operands[1],
instruction.operands[1].size);
SetOperandValue(builder, instruction.operands[0], DSTptrvalue);
bool isREP = (instruction.info.attributes & ZYDIS_ATTRIB_HAS_REP) != 0;
Value* DF = getFlag(builder, FLAG_DF);
auto one = ConstantInt::get(DF->getType(), 1);
// sign = (x*(x+1)) - 1
// v = sign * bytesize ; bytesize is 1
Value* Direction = builder.CreateSub(
builder.CreateMul(DF, builder.CreateAdd(DF, one)), one);
auto SRCop = instruction.operands[2 + isREP];
auto DSTop = instruction.operands[3 + isREP];
Value* SRCvalue = GetOperandValue(builder, SRCop, SRCop.size);
Value* DSTvalue = GetOperandValue(builder, DSTop, DSTop.size);
if (isREP) {
// if REP, instruction.operands[1] will be e/rax
// in that case, repeat and decrement e/rax until its 0
// we can create a loop but I dont know how that would effect our
// optimizations
Value* count = GetOperandValue(builder, instruction.operands[2],
instruction.operands[2].size);
if (auto countci = dyn_cast<ConstantInt>(count)) {
Value* UpdateSRCvalue = SRCvalue;
Value* UpdateDSTvalue = DSTvalue;
uint64_t looptime = countci->getZExtValue();
printvalue2(looptime);
for (int i = looptime; i > 0; i--) {
// TODO: fix this loop
// Value* SRCptrvalue = GetOperandValue(builder,
// instruction.operands[0],
// instruction.operands[0].size);
Value* DSTptrvalue = GetOperandValue(builder, instruction.operands[1],
instruction.operands[1].size);
SetOperandValue(builder, instruction.operands[0], DSTptrvalue);
UpdateSRCvalue = builder.CreateAdd(UpdateSRCvalue, Direction);
UpdateDSTvalue = builder.CreateAdd(UpdateDSTvalue, Direction);
printvalue(UpdateDSTvalue) printvalue(UpdateSRCvalue);
SetOperandValue(builder, SRCop, UpdateSRCvalue);
SetOperandValue(builder, DSTop, UpdateDSTvalue);
// bad cheat
if (i > 1)
debugging::increaseInstCounter();
}
SetOperandValue(builder, instruction.operands[2],
ConstantInt::get(count->getType(), 0));
return;
} else {
throw "fix rep";
}
}
Value* UpdateSRCvalue = builder.CreateAdd(SRCvalue, Direction);
Value* UpdateDSTvalue = builder.CreateAdd(DSTvalue, Direction);
SetOperandValue(builder, SRCop, UpdateSRCvalue);
SetOperandValue(builder, DSTop, UpdateDSTvalue);
}
void lift_movaps(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Rvalue = GetOperandValue(builder, src, src.size,
to_string(instruction.runtime_address));
SetOperandValue(builder, dest, Rvalue,
to_string(instruction.runtime_address));
}
void lift_mov(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Rvalue = GetOperandValue(builder, src, src.size,
to_string(instruction.runtime_address));
switch (instruction.info.mnemonic) {
case ZYDIS_MNEMONIC_MOVSX: {
Rvalue = createSExtFolder(
builder, Rvalue, Type::getIntNTy(context, dest.size),
"movsx-" + to_string(instruction.runtime_address) + "-");
break;
}
case ZYDIS_MNEMONIC_MOVZX: {
Rvalue = createZExtFolder(
builder, Rvalue, Type::getIntNTy(context, dest.size),
"movzx-" + to_string(instruction.runtime_address) + "-");
break;
}
case ZYDIS_MNEMONIC_MOVSXD: {
Rvalue = createSExtFolder(
builder, Rvalue, Type::getIntNTy(context, dest.size),
"movsxd-" + to_string(instruction.runtime_address) + "-");
break;
}
default: {
break;
}
}
printvalue(Rvalue);
if (src.type == ZYDIS_OPERAND_TYPE_IMMEDIATE) {
Rvalue = GetOperandValue(builder, src, dest.size);
}
printvalue(Rvalue);
SetOperandValue(builder, dest, Rvalue,
to_string(instruction.runtime_address));
}
}; // namespace mov
namespace cmov {
void lift_cmovbz(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* zf = getFlag(builder, FLAG_ZF);
Value* cf = getFlag(builder, FLAG_CF);
Value* condition = createOrFolder(builder, zf, cf, "cmovbz-or");
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, condition, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
void lift_cmovnbz(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* Rvalue = GetOperandValue(builder, src, src.size);
Value* cf = getFlag(builder, FLAG_CF);
Value* zf = getFlag(builder, FLAG_ZF);
Value* nbeCondition = createAndFolder(
builder, builder.CreateNot(cf), builder.CreateNot(zf), "nbeCondition");
Value* resultValue =
createSelectFolder(builder, nbeCondition, Rvalue, Lvalue, "cmovnbe");
SetOperandValue(builder, dest, resultValue,
to_string(instruction.runtime_address));
}
void lift_cmovz(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* Rvalue = GetOperandValue(builder, src, src.size);
Value* zf = getFlag(builder, FLAG_ZF);
Value* resultValue =
createSelectFolder(builder, zf, Rvalue, Lvalue, "cmovz");
SetOperandValue(builder, dest, resultValue,
to_string(instruction.runtime_address));
}
void lift_cmovnz(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* zf = getFlag(builder, FLAG_ZF);
zf = createICMPFolder(builder, CmpInst::ICMP_EQ, zf,
ConstantInt::get(Type::getInt1Ty(context), 0));
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, zf, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
void lift_cmovl(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* sf = getFlag(builder, FLAG_SF);
Value* of = getFlag(builder, FLAG_OF);
Value* condition = createICMPFolder(builder, CmpInst::ICMP_NE, sf, of);
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, condition, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
void lift_cmovb(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* cf = getFlag(builder, FLAG_CF);
Value* condition =
createICMPFolder(builder, CmpInst::ICMP_EQ, cf,
ConstantInt::get(Type::getInt1Ty(context), 1));
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, condition, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
void lift_cmovnb(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* Rvalue = GetOperandValue(builder, src, src.size);
Value* cf = getFlag(builder, FLAG_CF);
Value* resultValue = createSelectFolder(builder, builder.CreateNot(cf),
Rvalue, Lvalue, "cmovnb");
SetOperandValue(builder, dest, resultValue,
to_string(instruction.runtime_address));
}
void lift_cmovns(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* sf = getFlag(builder, FLAG_SF);
Value* condition =
createICMPFolder(builder, CmpInst::ICMP_EQ, sf,
ConstantInt::get(Type::getInt1Ty(context), 0));
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, condition, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
// cmovnl = cmovge
void lift_cmovnl(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* sf = getFlag(builder, FLAG_SF);
Value* of = getFlag(builder, FLAG_OF);
Value* condition = createICMPFolder(builder, CmpInst::ICMP_EQ, sf, of);
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
printvalue(sf);
printvalue(of);
printvalue(condition);
printvalue(Lvalue);
printvalue(Rvalue);
Value* result = createSelectFolder(builder, condition, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
void lift_cmovs(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* sf = getFlag(builder, FLAG_SF);
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, sf, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
void lift_cmovnle(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* zf = getFlag(builder, FLAG_ZF);
Value* sf = getFlag(builder, FLAG_SF);
Value* of = getFlag(builder, FLAG_OF);
Value* condition = createAndFolder(
builder, builder.CreateNot(zf, "notZF"),
createICMPFolder(builder, CmpInst::ICMP_EQ, sf, of, "sf_eq_of"),
"cmovnle_cond");
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, condition, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
void lift_cmovle(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* zf = getFlag(builder, FLAG_ZF);
Value* sf = getFlag(builder, FLAG_SF);
Value* of = getFlag(builder, FLAG_OF);
Value* sf_neq_of = createICMPFolder(builder, CmpInst::ICMP_NE, sf, of);
Value* condition = createOrFolder(builder, zf, sf_neq_of, "cmovle-or");
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, condition, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
void lift_cmovo(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* of = getFlag(builder, FLAG_OF);
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, of, Rvalue, Lvalue);
printvalue(Lvalue);
printvalue(Rvalue);
printvalue(of);
printvalue(result);
SetOperandValue(builder, dest, result);
}
void lift_cmovno(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* of = getFlag(builder, FLAG_OF);
printvalue(of) of = builder.CreateNot(of, "negateOF");
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, of, Rvalue, Lvalue);
printvalue(Lvalue) printvalue(Rvalue) printvalue(result)
SetOperandValue(builder, dest, result);
}
void lift_cmovp(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* pf = getFlag(builder, FLAG_PF);
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
printvalue(pf) printvalue(Lvalue) printvalue(Rvalue)
Value* result = createSelectFolder(builder, pf, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
void lift_cmovnp(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* pf = getFlag(builder, FLAG_PF);
pf = builder.CreateNot(pf, "negatePF");
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = createSelectFolder(builder, pf, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
}
} // namespace cmov
namespace branches {
// for now assume every call is fake
void lift_call(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
LLVMContext& context = builder.getContext();
// 0 = function
// 1 = rip
// 2 = register rsp
// 3 = [rsp]
auto src = instruction.operands[0]; // value that we are pushing
auto rsp = instruction.operands[2]; // value that we are pushing
auto rsp_memory = instruction.operands[3]; // value that we are pushing
auto RspValue = GetOperandValue(builder, rsp, rsp.size);
auto val = ConstantInt::getSigned(Type::getInt64Ty(context),
8); // assuming its x64
auto result = createSubFolder(builder, RspValue, val, "pushing_newrsp");
SetOperandValue(builder, rsp, result,
to_string(instruction.runtime_address));
; // sub rsp 8 first,
auto push_into_rsp = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
SetOperandValue(builder, rsp_memory, push_into_rsp,
to_string(instruction.runtime_address));
; // sub rsp 8 first,
string block_name = "jmp-call";
uint64_t jump_address =
instruction.runtime_address + instruction.info.length;
switch (src.type) {
case ZYDIS_OPERAND_TYPE_IMMEDIATE: {
jump_address += src.imm.value.s;
break;
}
case ZYDIS_OPERAND_TYPE_MEMORY:
case ZYDIS_OPERAND_TYPE_REGISTER: {
auto registerValue = GetOperandValue(builder, src, 64);
if (!isa<ConstantInt>(registerValue)) {
callFunctionIR(registerValue->getName().str() + "fnc_ptr", builder,
nullptr);
SetOperandValue(builder, rsp, RspValue,
to_string(instruction.runtime_address));
break;
// registerValue =
// ConstantInt::get(Type::getInt32Ty(context), 0x1337);
// throw("trying to call an unknown value");
}
auto registerCValue = cast<ConstantInt>(registerValue);
jump_address = registerCValue->getZExtValue();
break;
}
default:
break;
}
auto bb = BasicBlock::Create(context, block_name.c_str(),
builder.GetInsertBlock()->getParent());
// if its trying to jump somewhere else than our binary, call it and
// continue from [rsp]
APInt temp;
builder.CreateBr(bb);
printvalue2(jump_address);
blockAddresses->push_back(make_tuple(jump_address, bb, getRegisters()));
}
int ret_count = 0;
void lift_ret(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses, bool& run) {
LLVMContext& context = builder.getContext();
// [0] = rip
// [1] = rsp
// [2] = [rsp]
// if its ret 0x10
// then its
// [0] = 0x10
// [1] = rip
// [2] = rsp
// [3] = [rsp]
auto rspaddr = instruction.operands[2];
auto rsp = ZYDIS_REGISTER_RSP;
auto rspvalue = GetRegisterValue(builder, rsp);
if (instruction.operands[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) {
rspaddr = instruction.operands[3];
}
auto realval = GetOperandValue(builder, rspaddr, rspaddr.size);
auto block = builder.GetInsertBlock();
block->setName("ret_check" + to_string(ret_count));
auto function = block->getParent();
auto lastinst = builder.CreateRet(realval);
printvalue(rspvalue) debugging::doIfDebug([&]() {
std::string Filename = "output_rets.ll";
std::error_code EC;
raw_fd_ostream OS(Filename, EC);
function->getParent()->print(OS, nullptr);
});
uint64_t destination = 0;
ROP_info result = ROP_return;
if (llvm::ConstantInt* constInt =
llvm::dyn_cast<llvm::ConstantInt>(rspvalue)) {
int64_t rspval = constInt->getSExtValue();
printvalue2(rspval);
result = rspval == STACKP_VALUE ? REAL_return : ROP_return;
}
printvalue2(result);
if (result == REAL_return) {
lastinst->eraseFromParent();
block->setName("real_ret");
auto rax = GetRegisterValue(builder, ZYDIS_REGISTER_RAX);
builder.CreateRet(
createZExtFolder(builder, rax, Type::getInt64Ty(rax->getContext())));
Function* originalFunc_finalnopt = builder.GetInsertBlock()->getParent();
std::string Filename_finalnopt = "output_finalnoopt.ll";
std::error_code EC_finalnopt;
raw_fd_ostream OS_finalnopt(Filename_finalnopt, EC_finalnopt);
originalFunc_finalnopt->print(OS_finalnopt);
// function->print(outs());
final_optpass(originalFunc_finalnopt);
debugging::doIfDebug([&]() {
std::string Filename = "output_finalopt.ll";
std::error_code EC;
raw_fd_ostream OS(Filename, EC);
originalFunc_finalnopt->print(OS);
});
run = 0;
return;
}
PATH_info pathInfo = solvePath(function, destination, realval);
block->setName("previousret_block");
if (pathInfo == PATH_solved) {
lastinst->eraseFromParent();
block->setName("fake_ret");
string block_name = "jmp_ret-" + to_string(destination) + "-";
auto bb = BasicBlock::Create(context, block_name.c_str(),
builder.GetInsertBlock()->getParent());
auto val = ConstantInt::getSigned(Type::getInt64Ty(context),
8); // assuming its x64
auto result = createAddFolder(
builder, rspvalue, val,
"ret-new-rsp-" + to_string(instruction.runtime_address) + "-");
if (instruction.operands[0].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) {
rspaddr = instruction.operands[3];
result = createAddFolder(
builder, result,
ConstantInt::get(result->getType(),
instruction.operands[0].imm.value.u));
}
SetRegisterValue(builder, rsp, result); // then add rsp 8
builder.CreateBr(bb);
blockAddresses->push_back(make_tuple(destination, bb, getRegisters()));
run = 0;
}
}
int jmpcount = 0;
void lift_jmp(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses, bool& run) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto Value = GetOperandValue(builder, dest, 64);
auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
auto newRip = createAddFolder(
builder, Value, ripval,
"jump-xd-" + to_string(instruction.runtime_address) + "-");
jmpcount++;
if (dest.type == ZYDIS_OPERAND_TYPE_REGISTER ||
dest.type == ZYDIS_OPERAND_TYPE_MEMORY) {
auto rspvalue = GetOperandValue(builder, dest, 64);
auto trunc = createZExtOrTruncFolder(
builder, rspvalue, Type::getInt64Ty(context), "jmp-register");
auto block = builder.GetInsertBlock();
block->setName("jmp_check" + to_string(ret_count));
auto function = block->getParent();
auto lastinst = builder.CreateRet(trunc);
debugging::doIfDebug([&]() {
std::string Filename = "output_beforeJMP.ll";
std::error_code EC;
raw_fd_ostream OS(Filename, EC);
function->print(OS);
});
uint64_t destination = 0;
PATH_info pathInfo = solvePath(function, destination, trunc);
ValueToValueMapTy VMap_test;
block->setName("previousjmp_block-" + to_string(destination) + "-");
// cout << "pathInfo:" << pathInfo << " dest: " << destination <<
// "\n";
if (pathInfo == PATH_solved) {
lastinst->eraseFromParent();
string block_name = "jmp-" + to_string(destination) + "-";
auto bb = BasicBlock::Create(context, block_name.c_str(),
builder.GetInsertBlock()->getParent());
builder.CreateBr(bb);
blockAddresses->push_back(make_tuple(destination, bb, getRegisters()));
run = 0;
}
run = 0;
// if ROP is not JOP_jmp, then its bugged
return;
}
SetRegisterValue(builder, ZYDIS_REGISTER_RIP, newRip);
uint64_t test = dest.imm.value.s + instruction.runtime_address +
instruction.info.length;
string block_name = "jmp-" + to_string(test) + "-";
auto bb = BasicBlock::Create(context, block_name.c_str(),
builder.GetInsertBlock()->getParent());
builder.CreateBr(bb);
blockAddresses->push_back(make_tuple(test, bb, getRegisters()));
run = 0;
}
int branchnumber = 0;
// jnz and jne
void lift_jnz(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
LLVMContext& context = builder.getContext();
auto zf = getFlag(builder, FLAG_ZF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jnz");
printvalue(zf);
zf = createICMPFolder(builder, CmpInst::ICMP_EQ, zf,
ConstantInt::get(Type::getInt1Ty(context), 0));
branchHelper(builder, instruction, blockAddresses, zf, "jnz", branchnumber);
branchnumber++;
}
void lift_js(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto sf = getFlag(builder, FLAG_SF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "js");
branchHelper(builder, instruction, blockAddresses, sf, "js", branchnumber);
branchnumber++;
}
void lift_jns(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto sf = getFlag(builder, FLAG_SF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jns");
sf = builder.CreateNot(sf);
branchHelper(builder, instruction, blockAddresses, sf, "jns", branchnumber);
branchnumber++;
}
void lift_jz(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
// if 0, then jmp, if not then not jump
auto zf = getFlag(builder, FLAG_ZF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jnz");
branchHelper(builder, instruction, blockAddresses, zf, "jz", branchnumber);
branchnumber++;
}
void lift_jle(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
// If SF != OF or ZF = 1, then jump. Otherwise, do not jump.
auto sf = getFlag(builder, FLAG_SF);
auto of = getFlag(builder, FLAG_OF);
auto zf = getFlag(builder, FLAG_ZF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jle");
// Check if SF != OF or ZF is set
auto sf_neq_of = createXorFolder(builder, sf, of, "jle_SF_NEQ_OF");
auto condition = createOrFolder(builder, sf_neq_of, zf, "jle_Condition");
branchHelper(builder, instruction, blockAddresses, condition, "jle",
branchnumber);
branchnumber++;
}
void lift_jl(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto sf = getFlag(builder, FLAG_SF);
auto of = getFlag(builder, FLAG_OF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jl");
printvalue(sf);
printvalue(of);
auto condition = createXorFolder(builder, sf, of, "jl_Condition");
branchHelper(builder, instruction, blockAddresses, condition, "jl",
branchnumber);
branchnumber++;
}
void lift_jnl(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto sf = getFlag(builder, FLAG_SF);
auto of = getFlag(builder, FLAG_OF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jnl");
printvalue(sf);
printvalue(of);
auto condition =
builder.CreateNot(createXorFolder(builder, sf, of), "jnl_Condition");
branchHelper(builder, instruction, blockAddresses, condition, "jnl",
branchnumber);
branchnumber++;
}
void lift_jnle(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto sf = getFlag(builder, FLAG_SF);
auto of = getFlag(builder, FLAG_OF);
auto zf = getFlag(builder, FLAG_ZF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jnle");
// Jump short if greater (ZF=0 and SF=OF).
printvalue(sf) printvalue(zf) printvalue(of)
auto sf_eq_of = createXorFolder(builder, sf, of); // 0-0 or 1-1 => 0
auto sf_eq_of_not =
builder.CreateNot(sf_eq_of, "jnle_SF_EQ_OF_NOT"); // 0 => 1
auto zf_not = builder.CreateNot(zf, "jnle_ZF_NOT"); // zf == 0
auto condition =
createAndFolder(builder, sf_eq_of_not, zf_not, "jnle_Condition");
branchHelper(builder, instruction, blockAddresses, condition, "jnle",
branchnumber);
branchnumber++;
}
void lift_jbe(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto cf = getFlag(builder, FLAG_CF);
auto zf = getFlag(builder, FLAG_ZF);
printvalue(cf) printvalue(zf) // auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jbe");
auto condition = createOrFolder(builder, cf, zf, "jbe_Condition");
branchHelper(builder, instruction, blockAddresses, condition, "jbe",
branchnumber);
branchnumber++;
}
void lift_jb(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto cf = getFlag(builder, FLAG_CF);
printvalue(cf);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jb");
auto condition = cf;
branchHelper(builder, instruction, blockAddresses, condition, "jb",
branchnumber);
branchnumber++;
}
void lift_jnb(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto cf = getFlag(builder, FLAG_CF);
printvalue(cf);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jnb");
auto condition = builder.CreateNot(cf, "notCF");
branchHelper(builder, instruction, blockAddresses, condition, "jnb",
branchnumber);
branchnumber++;
}
void lift_jnbe(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto cf = getFlag(builder, FLAG_CF);
auto zf = getFlag(builder, FLAG_ZF);
printvalue(cf);
printvalue(zf);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jnbe");
auto condition =
createAndFolder(builder, builder.CreateNot(cf, "notCF"),
builder.CreateNot(zf, "notZF"), "jnbe_ja_Condition");
branchHelper(builder, instruction, blockAddresses, condition, "jnbe_ja",
branchnumber);
branchnumber++;
}
void lift_jo(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto of = getFlag(builder, FLAG_OF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jo");
printvalue(of);
branchHelper(builder, instruction, blockAddresses, of, "jo", branchnumber);
branchnumber++;
}
void lift_jno(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto of = getFlag(builder, FLAG_OF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jno");
of = builder.CreateNot(of);
branchHelper(builder, instruction, blockAddresses, of, "jno", branchnumber);
branchnumber++;
}
void lift_jp(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto pf = getFlag(builder, FLAG_PF);
printvalue(pf);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jp");
branchHelper(builder, instruction, blockAddresses, pf, "jp", branchnumber);
branchnumber++;
}
void lift_jnp(IRBuilder<>& builder, ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses) {
auto pf = getFlag(builder, FLAG_PF);
// auto dest = instruction.operands[0];
// auto Value = GetOperandValue(builder, dest, 64);
// auto ripval = GetRegisterValue(builder, ZYDIS_REGISTER_RIP);
// auto newRip = createAddFolder(builder, Value, ripval, "jnp");
pf = builder.CreateNot(pf);
printvalue(pf);
branchHelper(builder, instruction, blockAddresses, pf, "jnp", branchnumber);
branchnumber++;
}
} // namespace branches
namespace arithmeticsAndLogical {
void lift_sbb(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
//
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* cf = createZExtOrTruncFolder(builder, getFlag(builder, FLAG_CF),
Rvalue->getType());
Value* srcPlusCF = createAddFolder(builder, Rvalue, cf, "srcPlusCF");
Value* tmpResult =
createSubFolder(builder, Lvalue, srcPlusCF, "sbbTempResult");
SetOperandValue(builder, dest, tmpResult);
Value* newCF = createICMPFolder(builder, CmpInst::ICMP_ULT, Lvalue,
srcPlusCF, "newCF");
Value* sf = computeSignFlag(builder, tmpResult);
Value* zf = computeZeroFlag(builder, tmpResult);
Value* pf = computeParityFlag(builder, tmpResult);
Value* af = computeAuxFlagSbb(builder, Lvalue, Rvalue, cf);
auto of = computeOverflowFlagSbb(builder, Lvalue, Rvalue, cf, tmpResult);
setFlag(builder, FLAG_CF, newCF);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
setFlag(builder, FLAG_AF, af);
setFlag(builder, FLAG_OF, of);
printvalue(Lvalue);
printvalue(Rvalue);
printvalue(tmpResult);
printvalue(sf);
printvalue(of);
}
/*
(* RCL and RCR Instructions *)
SIZE := OperandSize;
CASE (determine count) OF
SIZE := 8: tempCOUNT := (COUNT AND 1FH) MOD 9;
SIZE := 16: tempCOUNT := (COUNT AND 1FH) MOD 17;
SIZE := 32: tempCOUNT := COUNT AND 1FH;
SIZE := 64: tempCOUNT := COUNT AND 3FH;
ESAC;
IF OperandSize = 64
THEN COUNTMASK = 3FH;
ELSE COUNTMASK = 1FH;
FI;
(* RCL Instruction Operation *)
WHILE (tempCOUNT ≠ 0)
DO
tempCF := MSB(DEST);
DEST := (DEST 2) + CF;
CF := tempCF;
tempCOUNT := tempCOUNT 1;
OD;
ELIHW;
IF (COUNT & COUNTMASK) = 1
THEN OF := MSB(DEST) XOR CF;
ELSE OF is undefined;
FI;
*/
void lift_rcl(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto count = instruction.operands[1];
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto countValue = GetOperandValue(builder, count, dest.size);
auto carryFlag = getFlag(builder, FLAG_CF);
unsigned long bitWidth = Lvalue->getType()->getIntegerBitWidth();
unsigned maskC = bitWidth == 64 ? 0x3f : 0x1f;
auto actualCount = createAndFolder(
builder, countValue, ConstantInt::get(countValue->getType(), maskC),
"actualCount");
auto wideType = Type::getIntNTy(context, dest.size * 2);
auto wideLvalue = createZExtFolder(builder, Lvalue, wideType);
auto cf_extended = createZExtFolder(builder, carryFlag, wideType);
auto shiftedInCF =
createShlFolder(builder, cf_extended, dest.size, "shiftedincf");
wideLvalue = createOrFolder(builder, wideLvalue,
createZExtFolder(builder, shiftedInCF, wideType,
"shiftedInCFExtended"));
auto leftShifted = createShlFolder(
builder, wideLvalue,
createZExtFolder(builder, actualCount, wideType, "actualCountExtended"),
"leftshifted");
auto rightShiftAmount = createSubFolder(
builder, ConstantInt::get(actualCount->getType(), dest.size),
actualCount, "rightshiftamount");
auto rightShifted = createLShrFolder(
builder, wideLvalue,
createZExtFolder(builder, rightShiftAmount, wideType), "rightshifted");
auto rotated =
createOrFolder(builder, leftShifted,
createZExtFolder(builder, rightShifted, wideType,
"rightShiftedExtended"));
auto result = createZExtOrTruncFolder(builder, rotated, Lvalue->getType());
auto newCFBitPosition = ConstantInt::get(rotated->getType(), dest.size - 1);
auto newCF = createZExtOrTruncFolder(
builder, createLShrFolder(builder, rotated, newCFBitPosition),
Type::getInt1Ty(context), "rclnewcf");
auto msbAfterRotate = createZExtOrTruncFolder(
builder, createLShrFolder(builder, result, dest.size - 1),
Type::getInt1Ty(context), "rclmsbafterrotate");
auto isCountOne =
createICMPFolder(builder, CmpInst::ICMP_EQ, actualCount,
ConstantInt::get(actualCount->getType(), 1));
auto newOF = createZExtOrTruncFolder(
builder, createXorFolder(builder, newCF, msbAfterRotate),
Type::getInt1Ty(context));
newOF = createSelectFolder(builder, isCountOne, newOF,
getFlag(builder, FLAG_OF));
printvalue(Lvalue) printvalue(countValue) printvalue(carryFlag)
printvalue(cf_extended) printvalue(shiftedInCF) printvalue(actualCount)
printvalue(wideLvalue) printvalue(leftShifted)
printvalue(rightShifted) printvalue(rotated) printvalue(result)
SetOperandValue(builder, dest, result);
setFlag(builder, FLAG_CF, newCF);
setFlag(builder, FLAG_OF, newOF);
}
/*
(* RCL and RCR Instructions *)
SIZE := OperandSize;
CASE (determine count) OF
SIZE := 8: tempCOUNT := (COUNT AND 1FH) MOD 9;
SIZE := 16: tempCOUNT := (COUNT AND 1FH) MOD 17;
SIZE := 32: tempCOUNT := COUNT AND 1FH;
SIZE := 64: tempCOUNT := COUNT AND 3FH;
ESAC;
IF OperandSize = 64
THEN COUNTMASK = 3FH;
ELSE COUNTMASK = 1FH;
FI;
(* RCR Instruction Operation *)
IF (COUNT & COUNTMASK) = 1
THEN OF := MSB(DEST) XOR CF;
ELSE OF is undefined;
FI;
WHILE (tempCOUNT ≠ 0)
DO
tempCF := LSB(SRC);
DEST := (DEST / 2) + (CF * 2SIZE);
CF := tempCF;
tempCOUNT := tempCOUNT 1;
OD;
ELIHW;
*/
void lift_rcr(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto count = instruction.operands[1];
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto countValue = GetOperandValue(builder, count, dest.size);
auto carryFlag = getFlag(builder, FLAG_CF);
unsigned long bitWidth = Lvalue->getType()->getIntegerBitWidth();
unsigned maskC = bitWidth == 64 ? 0x3f : 0x1f;
auto actualCount = createAndFolder(
builder, countValue, ConstantInt::get(countValue->getType(), maskC),
"actualCount");
auto wideType = Type::getIntNTy(context, dest.size * 2);
auto wideLvalue = createZExtFolder(builder, Lvalue, wideType);
auto shiftedInCF = createShlFolder(
builder, createZExtFolder(builder, carryFlag, wideType), dest.size);
wideLvalue = createOrFolder(builder, wideLvalue,
createZExtFolder(builder, shiftedInCF, wideType,
"shiftedInCFExtended"));
auto rightShifted = createLShrFolder(
builder, wideLvalue,
createZExtFolder(builder, actualCount, wideType, "actualCountExtended"),
"rightshifted");
auto leftShiftAmount = createSubFolder(
builder, ConstantInt::get(actualCount->getType(), dest.size),
actualCount);
auto leftShifted =
createShlFolder(builder, wideLvalue,
createZExtFolder(builder, leftShiftAmount, wideType,
"leftShiftAmountExtended"));
auto rotated = createOrFolder(builder, rightShifted, leftShifted);
auto result = createZExtOrTruncFolder(builder, rotated, Lvalue->getType());
auto newCFBitPosition = ConstantInt::get(rotated->getType(), dest.size - 1);
auto newCF = createZExtOrTruncFolder(
builder, createLShrFolder(builder, rotated, newCFBitPosition),
Type::getInt1Ty(context), "rcrcf");
auto msbAfterRotate = createZExtOrTruncFolder(
builder, createLShrFolder(builder, result, dest.size - 1),
Type::getInt1Ty(context), "rcrmsb");
auto newOF = createSelectFolder(
builder,
createICMPFolder(builder, CmpInst::ICMP_EQ, actualCount,
ConstantInt::get(actualCount->getType(), 1)),
createXorFolder(builder, newCF, msbAfterRotate),
getFlag(builder, FLAG_OF));
Value* isCountOne =
createICMPFolder(builder, CmpInst::ICMP_EQ, actualCount,
ConstantInt::get(actualCount->getType(), 1));
newCF = createSelectFolder(builder, isCountOne, newOF,
getFlag(builder, FLAG_OF));
result = createSelectFolder(builder, isCountOne, result, Lvalue);
SetOperandValue(builder, dest, result);
setFlag(builder, FLAG_CF, newCF);
setFlag(builder, FLAG_OF, newOF);
}
void lift_not(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto Rvalue = GetOperandValue(builder, dest, dest.size);
Rvalue = builder.CreateNot(
Rvalue, "realnot-" + to_string(instruction.runtime_address) + "-");
SetOperandValue(builder, dest, Rvalue,
to_string(instruction.runtime_address));
printvalue(Rvalue);
// Flags Affected
// None
}
void lift_neg(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto Rvalue = GetOperandValue(builder, dest, dest.size);
auto cf = createICMPFolder(builder, CmpInst::ICMP_NE, Rvalue,
ConstantInt::get(Rvalue->getType(), 0), "cf");
auto result = builder.CreateNeg(Rvalue, "neg");
SetOperandValue(builder, dest, result);
auto sf = computeSignFlag(builder, result);
auto zf = computeZeroFlag(builder, result);
auto pf = computeParityFlag(builder, result);
Value* fifteen = ConstantInt::get(Rvalue->getType(), 0xf);
auto af = createICMPFolder(builder, CmpInst::ICMP_NE,
createAndFolder(builder, Rvalue, fifteen),
ConstantInt::get(Rvalue->getType(), 0), "af");
auto isZero =
createICMPFolder(builder, CmpInst::ICMP_NE, Rvalue,
ConstantInt::get(Rvalue->getType(), 0), "zero");
printvalue(Rvalue) printvalue(result) printvalue(sf);
// OF is not cleared?
Value* of;
if (dest.size > 32)
of = ConstantInt::getSigned(Rvalue->getType(), 0);
else {
of = createICMPFolder(builder, CmpInst::ICMP_EQ, result, Rvalue);
of = createSelectFolder(builder, isZero, of,
ConstantInt::get(of->getType(), 0));
}
printvalue(of);
// The CF flag set to 0 if the source operand is 0; otherwise it is set
// to 1. The OF, SF, ZF, AF, and PF flags are set according to the
// result.
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_AF, af);
}
/*
IF 64-Bit Mode and using REX.W
THEN
countMASK := 3FH;
ELSE
countMASK := 1FH;
FI
tempCOUNT := (COUNT AND countMASK);
tempDEST := DEST;
WHILE (tempCOUNT ≠ 0)
DO
IF instruction is SAL or SHL
THEN
CF := MSB(DEST);
ELSE (* Instruction is SAR or SHR *)
CF := LSB(DEST);
FI;
IF instruction is SAL or SHL
THEN
DEST := DEST 2;
ELSE
IF instruction is SAR
THEN
DEST := DEST / 2; (* Signed divide, rounding
toward negative infinity *) ELSE (* Instruction is SHR *) DEST := DEST / 2 ;
(* Unsigned divide *) FI; FI; tempCOUNT := tempCOUNT 1; OD;
(* Determine overflow for the various instructions *)
IF (COUNT and countMASK) = 1
THEN
IF instruction is SAL or SHL
THEN
OF := MSB(DEST) XOR CF;
ELSE
IF instruction is SAR
THEN
OF := 0;
ELSE (* Instruction is SHR *)
OF := MSB(tempDEST);
FI;
FI;
ELSE IF (COUNT AND countMASK) = 0
THEN
All flags unchanged;
ELSE (* COUNT not 1 or 0 *)
OF := undefined;
FI;
FI;
*/
// maybe
void lift_sar(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto count = instruction.operands[1];
Value* Lvalue = GetOperandValue(builder, dest, dest.size,
to_string(instruction.runtime_address));
Value* countValue = GetOperandValue(builder, count, dest.size);
Value* zero = ConstantInt::get(countValue->getType(), 0);
uint8_t bitWidth = Lvalue->getType()->getIntegerBitWidth();
uint8_t maskC = bitWidth == 64 ? 0x3f : 0x1f;
Value* clampedCount = createAndFolder(
builder, countValue, ConstantInt::get(countValue->getType(), maskC),
"sarclamp");
Value* result = builder.CreateAShr(
Lvalue, clampedCount,
"sar-lshr-" + to_string(instruction.runtime_address) + "-");
Value* isZeroed = createICMPFolder(
builder, CmpInst::ICMP_UGT, clampedCount,
ConstantInt::get(clampedCount->getType(), bitWidth - 1));
result = createSelectFolder(builder, isZeroed, zero, result);
auto cfRvalue = createSubFolder(
builder, clampedCount, ConstantInt::get(clampedCount->getType(), 1));
auto cfShl = createShlFolder(
builder, ConstantInt::get(cfRvalue->getType(), 1), cfRvalue);
auto cfAnd = createAndFolder(builder, cfShl, Lvalue);
auto cfValue = createICMPFolder(builder, CmpInst::ICMP_NE, cfAnd,
ConstantInt::get(cfAnd->getType(), 0));
Value* isCountOne =
createICMPFolder(builder, CmpInst::ICMP_EQ, clampedCount,
ConstantInt::get(clampedCount->getType(), 1));
Value* of = createSelectFolder(builder, isCountOne, builder.getInt1(0),
getFlag(builder, FLAG_OF));
Value* isNotZero =
createICMPFolder(builder, CmpInst::ICMP_NE, clampedCount, zero);
Value* oldcf = getFlag(builder, FLAG_CF);
cfValue = createSelectFolder(builder, isNotZero, cfValue, oldcf);
cfValue = createSelectFolder(
builder, isZeroed, builder.CreateTrunc(zero, Type::getInt1Ty(context)),
cfValue);
Value* sf = computeSignFlag(builder, result);
Value* zf = computeZeroFlag(builder, result);
Value* pf = computeParityFlag(builder, result);
printvalue(Lvalue) printvalue2(bitWidth) printvalue(countValue);
printvalue(clampedCount) printvalue(result) printvalue(isNotZero);
printvalue(cfValue) printvalue(oldcf);
setFlag(builder, FLAG_CF, cfValue);
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
SetOperandValue(builder, dest, result,
to_string(instruction.runtime_address));
;
}
// TODO fix
void lift_shr(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto count = instruction.operands[1];
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* countValue = GetOperandValue(builder, count, dest.size);
unsigned bitWidth = Lvalue->getType()->getIntegerBitWidth();
unsigned maskC = bitWidth == 64 ? 0x3f : 0x1f;
Value* clampedCount = createAndFolder(
builder, countValue, ConstantInt::get(countValue->getType(), maskC),
"shrclamp");
Value* result = createLShrFolder(
builder, Lvalue, clampedCount,
"shr-lshr-" + to_string(instruction.runtime_address) + "-");
Value* zero = ConstantInt::get(countValue->getType(), 0);
Value* isZeroed = createICMPFolder(
builder, CmpInst::ICMP_UGT, clampedCount,
ConstantInt::get(clampedCount->getType(), bitWidth - 1));
result = createSelectFolder(builder, isZeroed, zero, result, "shiftValue");
Value* cfValue = builder.CreateTrunc(
createLShrFolder(
builder, Lvalue,
createSubFolder(builder, clampedCount,
ConstantInt::get(clampedCount->getType(), 1)),
"shrcf"),
builder.getInt1Ty());
Value* isCountOne =
createICMPFolder(builder, CmpInst::ICMP_EQ, clampedCount,
ConstantInt::get(clampedCount->getType(), 1));
Value* of = createICMPFolder(builder, CmpInst::ICMP_SLT, Lvalue,
ConstantInt::get(Lvalue->getType(), 0));
of = createSelectFolder(builder, isCountOne, of, getFlag(builder, FLAG_OF),
"of");
Value* isNotZero =
createICMPFolder(builder, CmpInst::ICMP_NE, clampedCount, zero);
Value* oldcf = getFlag(builder, FLAG_CF);
cfValue =
createSelectFolder(builder, isNotZero, cfValue, oldcf, "cfValue1");
cfValue = createSelectFolder(
builder, isZeroed, builder.CreateTrunc(zero, Type::getInt1Ty(context)),
cfValue, "cfValue2");
Value* sf = computeSignFlag(builder, result);
Value* zf = computeZeroFlag(builder, result);
Value* pf = computeParityFlag(builder, result);
printvalue(sf);
printvalue(result);
setFlag(builder, FLAG_CF, cfValue);
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
printvalue(Lvalue) printvalue(clampedCount) printvalue(result)
printvalue(isNotZero) printvalue(oldcf) printvalue(cfValue)
SetOperandValue(builder, dest, result,
to_string(instruction.runtime_address));
}
void lift_shl(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto count = instruction.operands[1];
Value* Lvalue = GetOperandValue(builder, dest, dest.size,
to_string(instruction.runtime_address));
Value* countValue = GetOperandValue(builder, count, dest.size);
unsigned bitWidth = Lvalue->getType()->getIntegerBitWidth();
unsigned maskC = bitWidth == 64 ? 0x3f : 0x1f;
auto bitWidthValue = ConstantInt::get(countValue->getType(), bitWidth);
Value* clampedCountValue = createAndFolder(
builder, countValue, ConstantInt::get(countValue->getType(), maskC),
"shlclamp");
Value* result =
createShlFolder(builder, Lvalue, clampedCountValue, "shl-shift");
Value* zero = ConstantInt::get(countValue->getType(), 0);
Value* isZeroed = createICMPFolder(
builder, CmpInst::ICMP_UGT, clampedCountValue,
ConstantInt::get(clampedCountValue->getType(), bitWidth - 1));
result = createSelectFolder(builder, isZeroed, zero, result);
Value* cfValue = createLShrFolder(
builder, Lvalue,
createSubFolder(builder, bitWidthValue, clampedCountValue), "shlcf");
Value* one = ConstantInt::get(cfValue->getType(), 1);
cfValue = createAndFolder(builder, cfValue, one, "shlcf");
cfValue =
createZExtOrTruncFolder(builder, cfValue, Type::getInt1Ty(context));
auto countIsNotZero =
createICMPFolder(builder, CmpInst::ICMP_NE, clampedCountValue,
ConstantInt::get(clampedCountValue->getType(), 0));
auto cfRvalue =
createSubFolder(builder, clampedCountValue,
ConstantInt::get(clampedCountValue->getType(), 1));
auto cfShl = createShlFolder(builder, Lvalue, cfRvalue);
auto cfIntT = cast<IntegerType>(cfShl->getType());
auto cfRightCount = ConstantInt::get(cfIntT, cfIntT->getBitWidth() - 1);
auto cfLow = createLShrFolder(builder, cfShl, cfRightCount, "lowcfshr");
cfValue = createSelectFolder(
builder, countIsNotZero,
createZExtOrTruncFolder(builder, cfLow, Type::getInt1Ty(context)),
getFlag(builder, FLAG_CF));
cfValue = createSelectFolder(
builder, isZeroed,
createZExtOrTruncFolder(builder, zero, Type::getInt1Ty(context)),
cfValue);
Value* isCountOne =
createICMPFolder(builder, CmpInst::ICMP_EQ, clampedCountValue,
ConstantInt::get(clampedCountValue->getType(), 1));
Value* originalMSB = createLShrFolder(
builder, Lvalue, ConstantInt::get(Lvalue->getType(), bitWidth - 1),
"shlmsb");
originalMSB = createAndFolder(
builder, originalMSB, ConstantInt::get(Lvalue->getType(), 1), "shlmsb");
originalMSB =
createZExtOrTruncFolder(builder, originalMSB, Type::getInt1Ty(context));
Value* cfAsMSB = createZExtOrTruncFolder(
builder,
createLShrFolder(builder, Lvalue,
ConstantInt::get(Lvalue->getType(), bitWidth - 1),
"shlcfasmsb"),
Type::getInt1Ty(context));
Value* resultMSB = createZExtOrTruncFolder(
builder,
createLShrFolder(builder, result,
ConstantInt::get(result->getType(), bitWidth - 1),
"shlresultmsb"),
Type::getInt1Ty(context));
Value* ofValue = createSelectFolder(
builder, isCountOne, createXorFolder(builder, resultMSB, cfAsMSB),
getFlag(builder, FLAG_OF));
setFlag(builder, FLAG_CF, cfValue);
setFlag(builder, FLAG_OF, ofValue);
Value* sf = computeSignFlag(builder, result);
Value* zf = computeZeroFlag(builder, result);
Value* pf = computeParityFlag(builder, result);
printvalue(Lvalue);
printvalue(countValue);
printvalue(clampedCountValue);
printvalue(isCountOne);
printvalue(result);
printvalue(ofValue);
printvalue(cfValue);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
SetOperandValue(builder, dest, result,
to_string(instruction.runtime_address));
}
void lift_bswap(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto Lvalue = GetOperandValue(builder, dest, dest.size);
// if 16bit, 0 it
if (dest.size == 16) {
Value* zero = ConstantInt::get(Lvalue->getType(), 0);
SetOperandValue(builder, dest, zero);
return;
}
Value* newswappedvalue = ConstantInt::get(Lvalue->getType(), 0);
Value* mask = ConstantInt::get(Lvalue->getType(), 0xff);
for (unsigned i = 0; i < Lvalue->getType()->getIntegerBitWidth() / 8; i++) {
// 0xff
// b = a & 0xff >> 0
// b = 0x78
// nb |= b << 24
// nb |= 0x78000000
// 0xff00
// b = a & 0xff00 >> 8
// b = 0x56
// nb |= b << 16
// nb = 0x78560000
auto byte =
createLShrFolder(builder, createAndFolder(builder, Lvalue, mask),
i * 8, "shlresultmsb");
auto shiftby = Lvalue->getType()->getIntegerBitWidth() - (i + 1) * 8;
auto newposbyte = createShlFolder(builder, byte, shiftby);
newswappedvalue = createOrFolder(builder, newswappedvalue, newposbyte);
mask = createShlFolder(builder, mask, 8);
}
SetOperandValue(builder, dest, newswappedvalue);
}
void lift_cmpxchg(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto accop = instruction.operands[2];
auto Rvalue = GetOperandValue(builder, src, src.size);
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto accum = GetOperandValue(builder, accop, dest.size);
auto sub = builder.CreateSub(accum, Lvalue);
auto of = computeOverflowFlagSub(builder, Lvalue, Rvalue, sub);
auto lowerNibbleMask = ConstantInt::get(Lvalue->getType(), 0xF);
auto RvalueLowerNibble =
createAndFolder(builder, Lvalue, lowerNibbleMask, "lvalLowerNibble");
auto op2LowerNibble =
createAndFolder(builder, Rvalue, lowerNibbleMask, "rvalLowerNibble");
auto cf =
createICMPFolder(builder, CmpInst::ICMP_UGT, Rvalue, Lvalue, "add_cf");
auto af = createICMPFolder(builder, CmpInst::ICMP_ULT, RvalueLowerNibble,
op2LowerNibble, "add_af");
auto sf = computeSignFlag(builder, sub);
/*
TEMP := DEST
IF accumulator = TEMP
THEN
ZF := 1;
DEST := SRC;
ELSE
ZF := 0;
accumulator := TEMP;
DEST := TEMP;
FI;
*/
auto zf = createICMPFolder(builder, CmpInst::ICMP_EQ, accum, Lvalue);
// if zf dest = src
auto result = createSelectFolder(builder, zf, Rvalue, Lvalue);
SetOperandValue(builder, dest, result);
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_AF, af);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
}
void lift_xchg(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Rvalue = GetOperandValue(builder, src, src.size);
auto Lvalue = GetOperandValue(builder, dest, dest.size);
printvalue(Lvalue) printvalue(Rvalue)
SetOperandValue(builder, dest, Rvalue,
to_string(instruction.runtime_address));
;
SetOperandValue(builder, src, Lvalue);
}
void lift_shld(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto source = instruction.operands[1];
auto count = instruction.operands[2];
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto sourceValue = GetOperandValue(builder, source, dest.size);
auto countValue = GetOperandValue(builder, count, dest.size);
unsigned bitWidth = Lvalue->getType()->getIntegerBitWidth();
auto effectiveCountValue = builder.CreateURem(
countValue, ConstantInt::get(countValue->getType(), bitWidth),
"effectiveShiftCount");
auto shiftedDest =
createShlFolder(builder, Lvalue, effectiveCountValue, "shiftedDest");
auto complementCount = createSubFolder(
builder, ConstantInt::get(countValue->getType(), bitWidth),
effectiveCountValue, "complementCount");
auto shiftedSource = createLShrFolder(builder, sourceValue, complementCount,
"shiftedSource");
auto resultValue =
createOrFolder(builder, shiftedDest, shiftedSource, "shldResult");
auto countIsNotZero =
createICMPFolder(builder, CmpInst::ICMP_NE, effectiveCountValue,
ConstantInt::get(effectiveCountValue->getType(), 0));
auto lastShiftedBitPosition =
createSubFolder(builder, effectiveCountValue,
ConstantInt::get(effectiveCountValue->getType(), 1));
auto lastShiftedBit = createAndFolder(
builder, createLShrFolder(builder, Lvalue, lastShiftedBitPosition),
ConstantInt::get(Lvalue->getType(), 1), "shldresultmsb");
auto cf =
createSelectFolder(builder, countIsNotZero,
createZExtOrTruncFolder(builder, lastShiftedBit,
Type::getInt1Ty(context)),
getFlag(builder, FLAG_CF));
resultValue =
createSelectFolder(builder, countIsNotZero, resultValue, Lvalue);
auto isOne =
createICMPFolder(builder, CmpInst::ICMP_EQ, effectiveCountValue,
ConstantInt::get(effectiveCountValue->getType(), 1));
auto newOF = createXorFolder(
builder,
createLShrFolder(builder, Lvalue,
ConstantInt::get(Lvalue->getType(), bitWidth - 1),
"subof"),
createLShrFolder(builder, resultValue,
ConstantInt::get(resultValue->getType(), bitWidth - 1),
"subof2"),
"subxorof");
auto of = createSelectFolder(
builder, isOne,
createZExtOrTruncFolder(builder, newOF, Type::getInt1Ty(context)),
getFlag(builder, FLAG_OF));
// CF := BIT[DEST, SIZE COUNT]; if shifted,
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_OF, of);
SetOperandValue(builder, dest, resultValue,
to_string(instruction.runtime_address));
}
void lift_shrd(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto source = instruction.operands[1];
auto count = instruction.operands[2];
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto sourceValue = GetOperandValue(builder, source, dest.size);
auto countValue = GetOperandValue(builder, count, dest.size);
unsigned bitWidth = Lvalue->getType()->getIntegerBitWidth();
auto effectiveCountValue = builder.CreateURem(
countValue, ConstantInt::get(countValue->getType(), bitWidth),
"effectiveShiftCount");
auto shiftedDest =
createLShrFolder(builder, Lvalue, effectiveCountValue, "shiftedDest");
auto complementCount = createSubFolder(
builder, ConstantInt::get(countValue->getType(), bitWidth),
effectiveCountValue, "complementCount");
auto shiftedSource =
createShlFolder(builder, sourceValue, complementCount, "shiftedSource");
auto resultValue =
createOrFolder(builder, shiftedDest, shiftedSource, "shrdResult");
// Calculate CF
auto cfBitPosition =
createSubFolder(builder, effectiveCountValue,
ConstantInt::get(effectiveCountValue->getType(), 1));
Value* cf = createLShrFolder(builder, Lvalue, cfBitPosition);
cf = createAndFolder(builder, cf, ConstantInt::get(cf->getType(), 1),
"shrdcf");
cf = createZExtOrTruncFolder(builder, cf, Type::getInt1Ty(context));
// Calculate OF, only when count is 1
Value* isCountOne =
createICMPFolder(builder, CmpInst::ICMP_EQ, effectiveCountValue,
ConstantInt::get(effectiveCountValue->getType(), 1));
Value* mostSignificantBitOfDest = createLShrFolder(
builder, Lvalue, ConstantInt::get(Lvalue->getType(), bitWidth - 1),
"shlmsbdest");
mostSignificantBitOfDest = createAndFolder(
builder, mostSignificantBitOfDest,
ConstantInt::get(mostSignificantBitOfDest->getType(), 1), "shrdmsb");
Value* mostSignificantBitOfResult = createLShrFolder(
builder, resultValue,
ConstantInt::get(resultValue->getType(), bitWidth - 1), "shlmsbresult");
mostSignificantBitOfResult = createAndFolder(
builder, mostSignificantBitOfResult,
ConstantInt::get(mostSignificantBitOfResult->getType(), 1), "shrdmsb2");
Value* of = createXorFolder(builder, mostSignificantBitOfDest,
mostSignificantBitOfResult);
of = createZExtOrTruncFolder(builder, of, Type::getInt1Ty(context));
of = createSelectFolder(builder, isCountOne, of,
ConstantInt::getFalse(context));
of = createZExtFolder(builder, of, Type::getInt1Ty(context));
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_OF, of);
SetOperandValue(builder, dest, resultValue,
to_string(instruction.runtime_address));
}
void lift_lea(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Rvalue = GetEffectiveAddress(builder, src, dest.size);
printvalue(Rvalue)
SetOperandValue(builder, dest, Rvalue,
to_string(instruction.runtime_address));
;
}
// extract sub from this function, this is convoluted for no reason
void lift_add_sub(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Rvalue = GetOperandValue(builder, src, dest.size);
auto Lvalue = GetOperandValue(builder, dest, dest.size);
Value* result = nullptr;
Value* cf = nullptr;
Value* af = nullptr;
Value* of = nullptr;
auto lowerNibbleMask = ConstantInt::get(Lvalue->getType(), 0xF);
auto RvalueLowerNibble =
createAndFolder(builder, Lvalue, lowerNibbleMask, "lvalLowerNibble");
auto op2LowerNibble =
createAndFolder(builder, Rvalue, lowerNibbleMask, "rvalLowerNibble");
switch (instruction.info.mnemonic) {
case ZYDIS_MNEMONIC_ADD: {
result = createAddFolder(
builder, Lvalue, Rvalue,
"realadd-" + to_string(instruction.runtime_address) + "-");
cf = createOrFolder(builder,
createICMPFolder(builder, CmpInst::ICMP_ULT, result,
Lvalue, "add_cf1"),
createICMPFolder(builder, CmpInst::ICMP_ULT, result,
Rvalue, "add_cf2"),
"add_cf");
auto sumLowerNibble = createAddFolder(
builder, RvalueLowerNibble, op2LowerNibble, "add_sumLowerNibble");
af = createICMPFolder(builder, CmpInst::ICMP_UGT, sumLowerNibble,
lowerNibbleMask, "add_af");
of = computeOverflowFlagAdd(builder, Lvalue, Rvalue, result);
break;
}
case ZYDIS_MNEMONIC_SUB: {
result = createSubFolder(
builder, Lvalue, Rvalue,
"realsub-" + to_string(instruction.runtime_address) + "-");
of = computeOverflowFlagSub(builder, Lvalue, Rvalue, result);
cf = createICMPFolder(builder, CmpInst::ICMP_UGT, Rvalue, Lvalue,
"add_cf");
af = createICMPFolder(builder, CmpInst::ICMP_ULT, RvalueLowerNibble,
op2LowerNibble, "add_af");
break;
}
default:
break;
}
/*
Flags Affected
The OF, SF, ZF, AF, CF, and PF flags are set according to the result.
*/
auto sf = computeSignFlag(builder, result);
auto zf = computeZeroFlag(builder, result);
auto pf = computeParityFlag(builder, result);
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_AF, af);
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_PF, pf);
printvalue(Lvalue);
printvalue(Rvalue);
printvalue(result);
printvalue(cf);
printvalue(sf);
printvalue(of);
SetOperandValue(builder, dest, result);
}
void lift_imul2(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction, bool isSigned) {
LLVMContext& context = builder.getContext();
auto src = instruction.operands[0];
auto Rvalue = GetRegisterValue(builder, ZYDIS_REGISTER_AL);
Value* Lvalue = GetOperandValue(builder, src, src.size);
if (isSigned) { // do this in a prettier way
Lvalue =
builder.CreateSExt(Lvalue, Type::getIntNTy(context, src.size * 2));
Rvalue = builder.CreateSExtOrTrunc(
Rvalue, Type::getIntNTy(context,
src.size)); // make sure the size is correct,
// 1 byte, GetRegisterValue doesnt
// ensure we have the correct size
Rvalue = builder.CreateSExtOrTrunc(Rvalue, Lvalue->getType());
} else {
Lvalue = createZExtFolder(builder, Lvalue,
Type::getIntNTy(context, src.size * 2));
Rvalue = createZExtOrTruncFolder(
builder, Rvalue,
Type::getIntNTy(context,
src.size)); // make sure the size is correct, 1
// byte, GetRegisterValue doesnt
// ensure we have the correct size
Rvalue = createZExtOrTruncFolder(builder, Rvalue, Lvalue->getType());
}
Value* result = builder.CreateMul(Rvalue, Lvalue);
Value* lowerresult = builder.CreateTrunc(
result, Type::getIntNTy(context, src.size), "lowerResult");
Value* of;
Value* cf;
if (isSigned) {
of = builder.CreateICmpNE(
result, builder.CreateSExt(lowerresult, result->getType()));
cf = of;
} else {
Value* highPart = builder.CreateLShr(result, src.size, "highPart");
Value* highPartTruncated = builder.CreateTrunc(
highPart, Type::getIntNTy(context, src.size), "truncatedHighPart");
cf = builder.CreateICmpNE(highPartTruncated,
ConstantInt::get(result->getType(), 0), "cf");
of = cf;
}
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_OF, of);
printvalue(cf);
printvalue(of);
SetRegisterValue(builder, ZYDIS_REGISTER_AX, result);
printvalue(Lvalue);
printvalue(Rvalue);
printvalue(result);
// if imul modify cf and of flags
// if not, dont do anything else
}
// TODO rewrite this
void lift_imul(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0]; // dest ?
if (dest.size == 8 && instruction.info.operand_count_visible == 1) {
lift_imul2(builder, instruction, 1);
return;
}
auto src = instruction.operands[1];
auto src2 = (instruction.info.operand_count_visible == 3)
? instruction.operands[2]
: dest; // if exists third operand
Value* Rvalue = GetOperandValue(builder, src, src.size);
Value* Lvalue = GetOperandValue(builder, src2, src2.size);
uint8_t initialSize = src.size;
printvalue2(initialSize);
printvalue(Rvalue);
printvalue(Lvalue);
Rvalue =
builder.CreateSExt(Rvalue, Type::getIntNTy(context, initialSize * 2));
Lvalue =
builder.CreateSExt(Lvalue, Type::getIntNTy(context, initialSize * 2));
Value* result = builder.CreateMul(Lvalue, Rvalue, "intmul");
// Flags
Value* highPart = builder.CreateLShr(result, initialSize, "highPart");
Value* highPartTruncated = builder.CreateTrunc(
highPart, Type::getIntNTy(context, initialSize), "truncatedHighPart");
/*
For the one operand form of the instruction, the CF and OF flags are set
when significant bits are carried into the upper half of the result and
cleared when the result fits exactly in the lower half of the result.
For the two- and three-operand forms of the instruction, the CF and OF
flags are set when the result must be truncated to fit in the
destination operand size and cleared when the result fits exactly in the
destination operand size. The SF, ZF, AF, and PF flags are undefined.
*/
/*
DEST := TruncateToOperandSize(TMP_XP);
IF SignExtend(DEST) ≠ TMP_XP
THEN CF := 1; OF := 1;
ELSE CF := 0; OF := 0; FI;
*/
Value* truncresult = builder.CreateTrunc(
result, Type::getIntNTy(context, initialSize), "truncRes");
Value* cf = builder.CreateICmpNE(
result, builder.CreateSExt(truncresult, result->getType()), "cf");
Value* of = cf;
if (instruction.info.operand_count_visible == 3) {
SetOperandValue(builder, dest, truncresult);
} else if (instruction.info.operand_count_visible == 2) {
SetOperandValue(builder, instruction.operands[0], truncresult);
} else { // For one operand, result goes into ?dx:?ax if not a byte
// operation
auto splitResult = builder.CreateTruncOrBitCast(
result, Type::getIntNTy(context, initialSize), "splitResult");
Value* SEsplitResult = builder.CreateSExt(splitResult, result->getType());
printvalue(splitResult);
printvalue(result);
cf = builder.CreateICmpNE(SEsplitResult, result);
of = cf;
printvalue(of);
printvalue(result);
printvalue(SEsplitResult);
if (initialSize == 8) {
SetOperandValue(builder, instruction.operands[1], result);
} else {
SetOperandValue(builder, instruction.operands[1], splitResult);
SetOperandValue(builder, instruction.operands[2], highPartTruncated);
}
}
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_OF, of);
printvalue(Lvalue) printvalue(Rvalue) printvalue(result)
printvalue(highPartTruncated) printvalue(of) printvalue(cf)
}
// rewrite this too
void lift_mul(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
/*
mul rdx
[0] rdx
[1] rax
[2] rdx
[3] flags
*/
/*
IF (Byte operation)
THEN
AX := AL SRC;
ELSE (* Word or doubleword operation *)
IF OperandSize = 16
THEN
DX:AX := AX SRC;
ELSE IF OperandSize = 32
THEN EDX:EAX := EAX SRC; FI;
ELSE (* OperandSize = 64 *)
RDX:RAX := RAX SRC;
FI;
FI;
*/
LLVMContext& context = builder.getContext();
auto src = instruction.operands[0];
if (src.size == 8 && instruction.info.operand_count_visible == 1) {
lift_imul2(builder, instruction, 0);
return;
}
auto dest1 = instruction.operands[1]; // ax
auto dest2 = instruction.operands[2];
Value* Rvalue = GetOperandValue(builder, src, dest1.size);
Value* Lvalue = GetOperandValue(builder, dest1, dest1.size);
uint8_t initialSize = Rvalue->getType()->getIntegerBitWidth();
printvalue2(initialSize);
Rvalue = createZExtFolder(builder, Rvalue,
Type::getIntNTy(context, initialSize * 2));
Lvalue = createZExtFolder(builder, Lvalue,
Type::getIntNTy(context, initialSize * 2));
Value* result = builder.CreateMul(Lvalue, Rvalue, "intmul");
// Flags
auto resultType = Type::getIntNTy(context, initialSize);
Value* highPart = builder.CreateLShr(result, initialSize, "highPart");
Value* highPartTruncated = builder.CreateTrunc(
highPart, Type::getIntNTy(context, initialSize), "truncatedHighPart");
/* The OF and CF flags are set to 0 if the upper half of the result is
* 0; otherwise, they are set to 1. The SF, ZF, AF, and PF flags are
* undefined.
*/
Value* cf = builder.CreateICmpNE(highPartTruncated,
ConstantInt::get(resultType, 0), "cf");
Value* of = cf;
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_OF, of);
auto splitResult = builder.CreateTruncOrBitCast(
result, Type::getIntNTy(context, initialSize), "splitResult");
// if not byte operation, result goes into ?dx:?ax
SetOperandValue(builder, dest1, splitResult);
SetOperandValue(builder, dest2, highPartTruncated);
printvalue(Lvalue) printvalue(Rvalue) printvalue(result)
printvalue(highPart) printvalue(highPartTruncated)
printvalue(splitResult) printvalue(of) printvalue(cf)
}
void lift_div2(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto src = instruction.operands[0];
auto dividend = GetRegisterValue(builder, ZYDIS_REGISTER_AX);
Value* divisor = GetOperandValue(builder, src, src.size);
divisor = createZExtFolder(builder, divisor,
Type::getIntNTy(context, src.size * 2));
dividend = createZExtOrTruncFolder(builder, dividend, divisor->getType());
Value* remainder = builder.CreateURem(dividend, divisor);
Value* quotient = builder.CreateUDiv(dividend, divisor);
SetRegisterValue(
builder, ZYDIS_REGISTER_AL,
createZExtOrTruncFolder(builder, quotient,
Type::getIntNTy(context, src.size)));
SetRegisterValue(
builder, ZYDIS_REGISTER_AH,
createZExtOrTruncFolder(builder, remainder,
Type::getIntNTy(context, src.size)));
printvalue(remainder);
printvalue(quotient);
printvalue(divisor);
printvalue(dividend);
}
void lift_idiv2(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto src = instruction.operands[0];
auto dividend = GetRegisterValue(builder, ZYDIS_REGISTER_AX);
Value* divisor = GetOperandValue(builder, src, src.size);
divisor =
builder.CreateSExt(divisor, Type::getIntNTy(context, src.size * 2));
dividend = builder.CreateSExtOrTrunc(dividend, divisor->getType());
Value* remainder = builder.CreateSRem(dividend, divisor);
Value* quotient = builder.CreateSDiv(dividend, divisor);
SetRegisterValue(
builder, ZYDIS_REGISTER_AL,
createZExtOrTruncFolder(builder, quotient,
Type::getIntNTy(context, src.size)));
SetRegisterValue(
builder, ZYDIS_REGISTER_AH,
createZExtOrTruncFolder(builder, remainder,
Type::getIntNTy(context, src.size)));
printvalue(remainder);
printvalue(quotient);
printvalue(divisor);
printvalue(dividend);
}
void lift_div(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto src = instruction.operands[0];
if (src.size == 8) {
lift_div2(builder, instruction);
return;
}
auto dividendLowop = instruction.operands[1]; // eax
auto dividendHighop = instruction.operands[2]; // edx
auto Rvalue = GetOperandValue(builder, src, src.size);
Value *dividendLow, *dividendHigh, *dividend;
dividendLow = GetOperandValue(builder, dividendLowop, src.size);
dividendHigh = GetOperandValue(builder, dividendHighop, src.size);
dividendLow = createZExtFolder(builder, dividendLow,
Type::getIntNTy(context, src.size * 2));
dividendHigh =
createZExtFolder(builder, dividendHigh, dividendLow->getType());
uint8_t bitWidth = src.size;
dividendHigh = builder.CreateShl(dividendHigh, bitWidth);
printvalue2(bitWidth);
printvalue(dividendLow);
printvalue(dividendHigh);
dividend = builder.CreateOr(dividendHigh, dividendLow);
printvalue(dividend);
Value* divide = createZExtFolder(builder, Rvalue, dividend->getType());
Value *quotient, *remainder;
if (isa<ConstantInt>(divide) && isa<ConstantInt>(dividend)) {
APInt divideCI = cast<ConstantInt>(divide)->getValue();
APInt dividendCI = cast<ConstantInt>(dividend)->getValue();
APInt quotientCI = dividendCI.udiv(divideCI);
APInt remainderCI = dividendCI.urem(divideCI);
printvalue2(divideCI);
printvalue2(dividendCI);
printvalue2(quotientCI);
printvalue2(remainderCI);
quotient = ConstantInt::get(Rvalue->getType(), quotientCI);
remainder = ConstantInt::get(Rvalue->getType(), remainderCI);
} else {
quotient = builder.CreateUDiv(dividend, divide);
remainder = builder.CreateURem(dividend, divide);
}
SetOperandValue(
builder, dividendLowop,
createZExtOrTruncFolder(builder, quotient, Rvalue->getType()));
SetOperandValue(
builder, dividendHighop,
createZExtOrTruncFolder(builder, remainder, Rvalue->getType()));
printvalue(Rvalue) printvalue(dividend) printvalue(remainder)
printvalue(quotient)
}
void lift_idiv(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto src = instruction.operands[0];
if (src.size == 8) {
lift_idiv2(builder, instruction);
return;
}
auto dividendLowop = instruction.operands[1]; // eax
auto dividendHighop = instruction.operands[2]; // edx
auto Rvalue = GetOperandValue(builder, src, src.size);
Value *dividendLow, *dividendHigh, *dividend;
dividendLow = GetOperandValue(builder, dividendLowop, src.size);
dividendHigh = GetOperandValue(builder, dividendHighop, src.size);
dividendLow = createZExtFolder(builder, dividendLow,
Type::getIntNTy(context, src.size * 2));
dividendHigh =
createZExtFolder(builder, dividendHigh, dividendLow->getType());
uint8_t bitWidth = src.size;
dividendHigh = builder.CreateShl(dividendHigh, bitWidth);
printvalue2(bitWidth);
printvalue(dividendLow);
printvalue(dividendHigh);
dividend = builder.CreateOr(dividendHigh, dividendLow);
printvalue(dividend);
Value* divide = builder.CreateSExt(Rvalue, dividend->getType());
Value *quotient, *remainder;
if (isa<ConstantInt>(divide) && isa<ConstantInt>(dividend)) {
APInt divideCI = cast<ConstantInt>(divide)->getValue();
APInt dividendCI = cast<ConstantInt>(dividend)->getValue();
APInt quotientCI = dividendCI.sdiv(divideCI);
APInt remainderCI = dividendCI.srem(divideCI);
printvalue2(divideCI);
printvalue2(dividendCI);
printvalue2(quotientCI);
printvalue2(remainderCI);
quotient = ConstantInt::get(Rvalue->getType(), quotientCI);
remainder = ConstantInt::get(Rvalue->getType(), remainderCI);
} else {
quotient = builder.CreateSDiv(dividend, divide);
remainder = builder.CreateSRem(dividend, divide);
}
SetOperandValue(
builder, dividendLowop,
createZExtOrTruncFolder(builder, quotient, Rvalue->getType()));
SetOperandValue(
builder, dividendHighop,
createZExtOrTruncFolder(builder, remainder, Rvalue->getType()));
printvalue(Rvalue) printvalue(dividend) printvalue(remainder)
printvalue(quotient)
}
void lift_xor(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Rvalue = GetOperandValue(builder, src, dest.size);
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto result = createXorFolder(
builder, Lvalue, Rvalue,
"realxor-" + to_string(instruction.runtime_address) + "-");
printvalue(Lvalue) printvalue(Rvalue) printvalue(result)
auto sf = computeSignFlag(builder, result);
auto zf = computeZeroFlag(builder, result);
auto pf = computeParityFlag(builder, result);
// The OF and CF flags are cleared; the SF, ZF, and PF flags are set
// according to the result. The state of the AF flag is undefined.
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
setFlag(builder, FLAG_OF,
ConstantInt::getSigned(Type::getInt1Ty(context), 0));
setFlag(builder, FLAG_CF,
ConstantInt::getSigned(Type::getInt1Ty(context), 0));
SetOperandValue(builder, dest, result);
}
void lift_or(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Rvalue = GetOperandValue(builder, src, dest.size);
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto result = createOrFolder(
builder, Lvalue, Rvalue,
"realor-" + to_string(instruction.runtime_address) + "-");
printvalue(Lvalue);
printvalue(Rvalue);
printvalue(result);
auto sf = computeSignFlag(builder, result);
auto zf = computeZeroFlag(builder, result);
auto pf = computeParityFlag(builder, result);
printvalue(sf);
// The OF and CF flags are cleared; the SF, ZF, and PF flags are set
// according to the result. The state of the AF flag is undefined.
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
setFlag(builder, FLAG_OF,
ConstantInt::getSigned(Type::getInt1Ty(context), 0));
setFlag(builder, FLAG_CF,
ConstantInt::getSigned(Type::getInt1Ty(context), 0));
SetOperandValue(builder, dest, result);
}
void lift_and(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Rvalue = GetOperandValue(builder, src, dest.size);
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto result = createAndFolder(
builder, Lvalue, Rvalue,
"realand-" + to_string(instruction.runtime_address) + "-");
auto sf = computeSignFlag(builder, result);
auto zf = computeZeroFlag(builder, result);
auto pf = computeParityFlag(builder, result);
// The OF and CF flags are cleared; the SF, ZF, and PF flags are set
// according to the result. The state of the AF flag is undefined.
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
setFlag(builder, FLAG_OF,
ConstantInt::getSigned(Type::getInt1Ty(context), 0));
setFlag(builder, FLAG_CF,
ConstantInt::getSigned(Type::getInt1Ty(context), 0));
printvalue(Lvalue) printvalue(Rvalue) printvalue(result);
SetOperandValue(builder, dest, result,
"and" + to_string(instruction.runtime_address));
}
/*
tempCOUNT := (COUNT & COUNTMASK) MOD SIZE
WHILE (tempCOUNT ≠ 0)
DO
tempCF := MSB(DEST);
DEST := (DEST 2) + tempCF;
tempCOUNT := tempCOUNT 1;
OD;
ELIHW;
IF (COUNT & COUNTMASK) ≠ 0
THEN CF := LSB(DEST);
FI;
IF (COUNT & COUNTMASK) = 1
THEN OF := MSB(DEST) XOR CF;
ELSE OF is undefined;
FI
*/
void lift_rol(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto Rvalue = GetOperandValue(builder, src, dest.size);
unsigned bitWidth = Lvalue->getType()->getIntegerBitWidth();
Rvalue = createAndFolder(builder, Rvalue,
ConstantInt::get(Rvalue->getType(), bitWidth - 1),
"maskRvalue");
Value* shiftedLeft = createShlFolder(builder, Lvalue, Rvalue);
Value* shiftedRight = createLShrFolder(
builder, Lvalue,
createSubFolder(builder, ConstantInt::get(Rvalue->getType(), bitWidth),
Rvalue),
"rol");
Value* result = createOrFolder(builder, shiftedLeft, shiftedRight);
Value* lastBit =
createAndFolder(builder, shiftedRight,
ConstantInt::get(Lvalue->getType(), 1), "rollastbit");
Value* cf =
createZExtOrTruncFolder(builder, lastBit, Type::getInt1Ty(context));
Value* zero = ConstantInt::get(Rvalue->getType(), 0);
Value* isNotZero =
createICMPFolder(builder, CmpInst::ICMP_NE, Rvalue, zero);
Value* oldcf = getFlag(builder, FLAG_CF);
cf = createSelectFolder(builder, isNotZero, cf, oldcf);
result = createSelectFolder(builder, isNotZero, result, Lvalue);
// of = cf ^ MSB
Value* newMSB = createLShrFolder(builder, result, bitWidth - 1, "rolmsb");
Value* of = createXorFolder(
builder, cf,
createZExtOrTruncFolder(builder, newMSB, Type::getInt1Ty(context)));
// Use Select to conditionally update OF based on whether the shift
// amount is 1
Value* isOneBitRotation =
createICMPFolder(builder, CmpInst::ICMP_EQ, Rvalue,
ConstantInt::get(Rvalue->getType(), 1));
Value* ofCurrent = getFlag(builder, FLAG_OF);
of = createSelectFolder(builder, isOneBitRotation, of, ofCurrent);
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_OF, of);
printvalue(Lvalue) printvalue(Rvalue) printvalue(result)
SetOperandValue(builder, dest, result);
}
/*
tempCOUNT := (COUNT & COUNTMASK) MOD SIZE
WHILE (tempCOUNT ≠ 0)
DO
tempCF := LSB(SRC);
DEST := (DEST / 2) + (tempCF 2SIZE);
tempCOUNT := tempCOUNT 1;
OD;
ELIHW;
IF (COUNT & COUNTMASK) ≠ 0
THEN CF := MSB(DEST);
FI;
IF (COUNT & COUNTMASK) = 1
THEN OF := MSB(DEST) XOR MSB 1(DEST);
ELSE OF is undefined;
FI
*/
void lift_ror(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto Rvalue = GetOperandValue(builder, src, dest.size);
auto size = ConstantInt::getSigned(Lvalue->getType(),
Lvalue->getType()->getIntegerBitWidth());
Rvalue = builder.CreateURem(Rvalue, size);
Value* result = createOrFolder(
builder, createLShrFolder(builder, Lvalue, Rvalue),
createShlFolder(builder, Lvalue,
createSubFolder(builder, size, Rvalue)),
"ror-" + std::to_string(instruction.runtime_address) + "-");
Value* msb = createLShrFolder(
builder, result,
createSubFolder(
builder, size,
ConstantInt::get(
context, APInt(Rvalue->getType()->getIntegerBitWidth(), 1))));
Value* cf = createZExtOrTruncFolder(builder, msb, Type::getInt1Ty(context),
"ror-cf");
Value* secondMsb = createLShrFolder(
builder, result,
createSubFolder(
builder, size,
ConstantInt::get(
context, APInt(Rvalue->getType()->getIntegerBitWidth(), 2))),
"ror2ndmsb");
auto ofDefined = createZExtOrTruncFolder(
builder, createXorFolder(builder, msb, secondMsb), cf->getType());
auto isOneBitRotation = createICMPFolder(
builder, CmpInst::ICMP_EQ, Rvalue,
ConstantInt::get(context,
APInt(Rvalue->getType()->getIntegerBitWidth(), 1)));
Value* ofCurrent = getFlag(builder, FLAG_OF);
Value* of = createSelectFolder(builder, isOneBitRotation, ofDefined,
ofCurrent, "ror-of");
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_OF, of);
auto isZeroBitRotation = createICMPFolder(
builder, CmpInst::ICMP_EQ, Rvalue,
ConstantInt::get(context,
APInt(Rvalue->getType()->getIntegerBitWidth(), 0)),
"iszerobit");
result = createSelectFolder(builder, isZeroBitRotation, Lvalue, result,
"ror-result");
printvalue(Lvalue) printvalue(Rvalue) printvalue(result)
SetOperandValue(builder, dest, result);
}
void lift_inc_dec(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto operand = instruction.operands[0];
Value* Lvalue = GetOperandValue(builder, operand, operand.size);
Value* one = ConstantInt::get(Lvalue->getType(), 1, true);
Value* result;
Value* of;
// The CF flag is not affected. The OF, SF, ZF, AF, and PF flags are set
// according to the result.
if (instruction.info.mnemonic == ZYDIS_MNEMONIC_INC) {
// treat it as add r, 1 for flags
result = createAddFolder(builder, Lvalue, one,
"inc-" + to_string(instruction.runtime_address) +
"-");
of = computeOverflowFlagAdd(builder, Lvalue, one, result);
} else {
// treat it as sub r, 1 for flags
result = createSubFolder(builder, Lvalue, one,
"dec-" + to_string(instruction.runtime_address) +
"-");
of = computeOverflowFlagSub(builder, Lvalue, one, result);
}
printvalue(Lvalue) printvalue(result)
Value* sf = computeSignFlag(builder, result);
Value* zf = computeZeroFlag(builder, result);
Value* pf = computeParityFlag(builder, result);
printvalue(sf)
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
SetOperandValue(builder, operand, result);
}
void lift_push(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto src = instruction.operands[0]; // value that we are pushing
auto dest = instruction.operands[2];
auto rsp = instruction.operands[1];
auto Rvalue = GetOperandValue(builder, src, dest.size);
auto RspValue = GetOperandValue(builder, rsp, rsp.size); // ?
auto val = ConstantInt::getSigned(
Type::getInt64Ty(context),
dest.size / 8); // jokes on me apparently this is not a fixed value
auto result = createSubFolder(
builder, RspValue, val,
"pushing_newrsp-" + to_string(instruction.runtime_address) + "-");
printvalue(RspValue) printvalue(result) SetOperandValue(
builder, rsp, result, to_string(instruction.runtime_address));
; // sub rsp 8 first,
SetOperandValue(builder, dest, Rvalue,
to_string(instruction.runtime_address));
; // then mov rsp, val
}
void lift_pushfq(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto src = instruction.operands[2]; // value that we are pushing rflags
auto dest = instruction.operands[1]; // [rsp]
auto rsp = instruction.operands[0]; // rsp
auto Rvalue = GetOperandValue(builder, src, dest.size);
// auto Rvalue = GetRFLAGS(builder);
auto RspValue = GetOperandValue(builder, rsp, rsp.size);
auto val = ConstantInt::get(Type::getInt64Ty(context), 8);
auto result = createSubFolder(builder, RspValue, val);
SetOperandValue(builder, rsp, result,
to_string(instruction.runtime_address));
; // sub rsp 8 first,
// pushFlags(builder, dest, Rvalue,
// to_string(instruction.runtime_address));;
SetOperandValue(builder, dest, Rvalue,
to_string(instruction.runtime_address));
; // then mov rsp, val
}
void lift_pop(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0]; // value that we are pushing
auto src = instruction.operands[2];
auto rsp = instruction.operands[1];
auto Rvalue = GetOperandValue(builder, src, dest.size,
to_string(instruction.runtime_address));
;
auto RspValue = GetOperandValue(builder, rsp, rsp.size,
to_string(instruction.runtime_address));
;
auto val = ConstantInt::getSigned(Type::getInt64Ty(context),
dest.size / 8); // assuming its x64
auto result = createAddFolder(
builder, RspValue, val,
"popping_new_rsp-" + to_string(instruction.runtime_address) + "-");
printvalue(Rvalue) printvalue(RspValue) printvalue(result)
SetOperandValue(builder, rsp, result); // then add rsp 8
SetOperandValue(builder, dest, Rvalue,
to_string(instruction.runtime_address));
; // mov val, rsp first
}
void lift_popfq(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[2]; // value that we are pushing
auto src = instruction.operands[1]; // [rsp]
auto rsp = instruction.operands[0]; // rsp
auto Rvalue = GetOperandValue(builder, src, dest.size,
to_string(instruction.runtime_address));
;
auto RspValue = GetOperandValue(builder, rsp, rsp.size,
to_string(instruction.runtime_address));
;
auto val = ConstantInt::getSigned(Type::getInt64Ty(context),
8); // assuming its x64
auto result = createAddFolder(
builder, RspValue, val,
"popfq-" + to_string(instruction.runtime_address) + "-");
SetOperandValue(builder, dest, Rvalue,
to_string(instruction.runtime_address));
; // mov val, rsp first
SetOperandValue(builder, rsp, result,
to_string(instruction.runtime_address));
; // then add rsp 8
}
void lift_adc(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* Lvalue = GetOperandValue(builder, dest, dest.size);
Value* Rvalue = GetOperandValue(builder, src, dest.size);
Value* cf = getFlag(builder, FLAG_CF);
cf = createZExtFolder(builder, cf, Lvalue->getType());
Value* tempResult = createAddFolder(
builder, Lvalue, Rvalue,
"adc-temp-" + to_string(instruction.runtime_address) + "-");
Value* result = createAddFolder(
builder, tempResult, cf,
"adc-result-" + to_string(instruction.runtime_address) + "-");
// The OF, SF, ZF, AF, CF, and PF flags are set according to the result.
printvalue(Lvalue) printvalue(Rvalue) printvalue(tempResult) printvalue(
result)
auto cfAfterFirstAdd = createOrFolder(
builder,
createICMPFolder(builder, CmpInst::ICMP_ULT, tempResult, Lvalue),
createICMPFolder(builder, CmpInst::ICMP_ULT, tempResult, Rvalue));
auto cfFinal = createOrFolder(
builder, cfAfterFirstAdd,
createICMPFolder(builder, CmpInst::ICMP_ULT, result, cf));
auto lowerNibbleMask = ConstantInt::get(Lvalue->getType(), 0xF);
auto destLowerNibble =
createAndFolder(builder, Lvalue, lowerNibbleMask, "adcdst");
auto srcLowerNibble =
createAndFolder(builder, Rvalue, lowerNibbleMask, "adcsrc");
auto sumLowerNibble =
createAddFolder(builder, destLowerNibble, srcLowerNibble);
auto af = createICMPFolder(builder, CmpInst::ICMP_UGT, sumLowerNibble,
lowerNibbleMask);
auto of = computeOverflowFlagAdc(builder, Lvalue, Rvalue, cf, result);
Value* sf = computeSignFlag(builder, result);
Value* zf = computeZeroFlag(builder, result);
Value* pf = computeParityFlag(builder, result);
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_AF, af);
setFlag(builder, FLAG_CF, cfFinal);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
SetOperandValue(builder, dest, result);
}
void lift_xadd(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto Rvalue = GetOperandValue(builder, src, src.size);
Value* sumValue = createAddFolder(
builder, Lvalue, Rvalue,
"xadd_sum-" + to_string(instruction.runtime_address) + "-");
SetOperandValue(builder, dest, sumValue,
to_string(instruction.runtime_address));
;
SetOperandValue(builder, src, Lvalue,
to_string(instruction.runtime_address));
;
/*
TEMP := SRC + DEST;
SRC := DEST;
DEST := TEMP;
*/
printvalue(Lvalue) printvalue(Rvalue) printvalue(sumValue)
auto cf = createOrFolder(
builder,
createICMPFolder(builder, CmpInst::ICMP_ULT, sumValue, Lvalue),
createICMPFolder(builder, CmpInst::ICMP_ULT, sumValue, Rvalue));
auto lowerNibbleMask = ConstantInt::get(Lvalue->getType(), 0xF);
auto destLowerNibble =
createAndFolder(builder, Lvalue, lowerNibbleMask, "xadddst");
auto srcLowerNibble =
createAndFolder(builder, Rvalue, lowerNibbleMask, "xaddsrc");
auto sumLowerNibble =
createAddFolder(builder, destLowerNibble, srcLowerNibble);
auto af = createICMPFolder(builder, CmpInst::ICMP_UGT, sumLowerNibble,
lowerNibbleMask);
auto resultSign = createICMPFolder(builder, CmpInst::ICMP_SLT, sumValue,
ConstantInt::get(Lvalue->getType(), 0));
auto destSign = createICMPFolder(builder, CmpInst::ICMP_SLT, Lvalue,
ConstantInt::get(Lvalue->getType(), 0));
auto srcSign = createICMPFolder(builder, CmpInst::ICMP_SLT, Rvalue,
ConstantInt::get(Rvalue->getType(), 0));
auto inputSameSign =
createICMPFolder(builder, CmpInst::ICMP_EQ, destSign, srcSign);
auto of = createAndFolder(
builder, inputSameSign,
createICMPFolder(builder, CmpInst::ICMP_NE, destSign, resultSign),
"xaddof");
Value* sf = computeSignFlag(builder, sumValue);
Value* zf = computeZeroFlag(builder, sumValue);
Value* pf = computeParityFlag(builder, sumValue);
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_AF, af);
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
// The CF, PF, AF, SF, ZF, and OF flags are set according to the result
// of the addition, which is stored in the destination operand.
}
void lift_test(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* Lvalue = GetOperandValue(builder, instruction.operands[0],
instruction.operands[0].size);
Value* Rvalue = GetOperandValue(builder, instruction.operands[1],
instruction.operands[0].size);
Value* testResult = createAndFolder(builder, Lvalue, Rvalue, "testAnd");
Value* of = ConstantInt::get(Type::getInt64Ty(context), 0, "of");
Value* cf = ConstantInt::get(Type::getInt64Ty(context), 0, "cf");
Value* sf =
createICMPFolder(builder, CmpInst::ICMP_SLT, testResult,
ConstantInt::get(testResult->getType(), 0), "sf");
Value* zf =
createICMPFolder(builder, CmpInst::ICMP_EQ, testResult,
ConstantInt::get(testResult->getType(), 0), "zf");
Value* pf = computeParityFlag(builder, testResult);
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
}
void lift_cmp(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
Value* Lvalue = GetOperandValue(builder, instruction.operands[0],
instruction.operands[0].size);
Value* Rvalue = GetOperandValue(builder, instruction.operands[1],
instruction.operands[0].size);
Value* cmpResult = createSubFolder(builder, Lvalue, Rvalue);
Value* signL = createICMPFolder(builder, CmpInst::ICMP_SLT, Lvalue,
ConstantInt::get(Lvalue->getType(), 0));
Value* signR = createICMPFolder(builder, CmpInst::ICMP_SLT, Rvalue,
ConstantInt::get(Rvalue->getType(), 0));
Value* signResult =
createICMPFolder(builder, CmpInst::ICMP_SLT, cmpResult,
ConstantInt::get(cmpResult->getType(), 0));
Value* of = createOrFolder(
builder,
createAndFolder(builder, signL,
createAndFolder(builder, builder.CreateNot(signR),
builder.CreateNot(signResult),
"cmp-and1-")),
createAndFolder(builder, builder.CreateNot(signL),
createAndFolder(builder, signR, signResult),
"cmp-and2-"),
"cmp-OF-or");
Value* cf = createICMPFolder(builder, CmpInst::ICMP_ULT, Lvalue, Rvalue);
Value* zf = createICMPFolder(builder, CmpInst::ICMP_EQ, cmpResult,
ConstantInt::get(cmpResult->getType(), 0));
Value* sf = createICMPFolder(builder, CmpInst::ICMP_SLT, cmpResult,
ConstantInt::get(cmpResult->getType(), 0));
Value* pf = computeParityFlag(builder, cmpResult);
setFlag(builder, FLAG_OF, of);
setFlag(builder, FLAG_CF, cf);
setFlag(builder, FLAG_SF, sf);
setFlag(builder, FLAG_ZF, zf);
setFlag(builder, FLAG_PF, pf);
}
void lift_rdtsc(IRBuilder<>& builder) {
// cout << instruction.runtime_address << "\n";
LLVMContext& context = builder.getContext();
auto rdtscCall =
builder.CreateIntrinsic(Intrinsic::readcyclecounter, {}, {});
auto edxPart = createLShrFolder(builder, rdtscCall, 32, "to_edx");
auto eaxPart = createZExtOrTruncFolder(builder, rdtscCall,
Type::getInt32Ty(context), "to_eax");
SetRegisterValue(builder, ZYDIS_REGISTER_EDX, edxPart);
SetRegisterValue(builder, ZYDIS_REGISTER_EAX, eaxPart);
}
void lift_cpuid(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
// instruction.operands[0] = eax
// instruction.operands[1] = ebx
// instruction.operands[2] = ecx
// instruction.operands[3] = edx
/*
c++
#include <intrin.h>
int getcpuid() {
int cpuInfo[4];
__cpuid(cpuInfo, 1);
return cpuInfo[0] + cpuInfo[1];
}
ir
define dso_local noundef i32 @getcpuid() #0 {
%1 = alloca [4 x i32], align 16
%2 = getelementptr inbounds [4 x i32], ptr %1, i64 0, i64 0
%3 = call { i32, i32, i32, i32 } asm "xchgq %rbx,
${1:q}\0Acpuid\0Axchgq %rbx, ${1:q}", "={ax},=r,={cx},={dx},0,2"(i32 1,
i32 0) %4 = getelementptr inbounds [4 x i32], ptr %1, i64 0, i64 0 %5 =
extractvalue { i32, i32, i32, i32 } %3, 0 %6 = getelementptr inbounds
i32, ptr %4, i32 0 store i32 %5, ptr %6, align 4 %7 = extractvalue {
i32, i32, i32, i32 } %3, 1 %8 = getelementptr inbounds i32, ptr %4, i32
1 store i32 %7, ptr %8, align 4 %9 = extractvalue { i32, i32, i32, i32 }
%3, 2 %10 = getelementptr inbounds i32, ptr %4, i32 2 store i32 %9, ptr
%10, align 4 %11 = extractvalue { i32, i32, i32, i32 } %3, 3 %12 =
getelementptr inbounds i32, ptr %4, i32 3 store i32 %11, ptr %12, align
4
%13 = getelementptr inbounds [4 x i32], ptr %1, i64 0, i64 0
%14 = load i32, ptr %13, align 16
%15 = getelementptr inbounds [4 x i32], ptr %1, i64 0, i64 1
%16 = load i32, ptr %15, align 4
%17 = add nsw i32 %14, %16
ret i32 %17
}
opt
define dso_local noundef i32 @getcpuid() local_unnamed_addr {
%1 = tail call { i32, i32, i32, i32 } asm "xchgq %rbx,
${1:q}\0Acpuid\0Axchgq %rbx, ${1:q}", "={ax},=r,={cx},={dx},0,2"(i32 1,
i32 0) #0 %2 = extractvalue { i32, i32, i32, i32 } %1, 1 ret i32 %2
}
*/
// int cpuInfo[4];
// ArrayType* CpuInfoTy = ArrayType::get(Type::getInt32Ty(context), 4);
Value* eax = GetOperandValue(builder, instruction.operands[0],
instruction.operands[0].size);
// one is eax, other is always 0?
std::vector<Type*> AsmOutputs = {
Type::getInt32Ty(context), Type::getInt32Ty(context),
Type::getInt32Ty(context), Type::getInt32Ty(context)};
StructType* AsmStructType = StructType::get(context, AsmOutputs);
std::vector<Type*> ArgTypes = {Type::getInt32Ty(context),
Type::getInt32Ty(context)};
// this is probably incorrect
InlineAsm* IA =
InlineAsm::get(FunctionType::get(AsmStructType, ArgTypes, false),
"xchgq %rbx, ${1:q}\ncpuid\nxchgq %rbx, ${1:q}",
"={ax},=r,={cx},={dx},0,2", true);
std::vector<Value*> Args{eax, ConstantInt::get(eax->getType(), 0)};
Value* cpuidCall = builder.CreateCall(IA, Args);
Value* eaxv = builder.CreateExtractValue(cpuidCall, 0, "eax");
Value* ebx = builder.CreateExtractValue(cpuidCall, 1, "ebx");
Value* ecx = builder.CreateExtractValue(cpuidCall, 2, "ecx");
Value* edx = builder.CreateExtractValue(cpuidCall, 3, "edx");
SetOperandValue(builder, instruction.operands[0], eaxv);
SetOperandValue(builder, instruction.operands[1], ebx);
SetOperandValue(builder, instruction.operands[2], ecx);
SetOperandValue(builder, instruction.operands[3], edx);
}
} // namespace arithmeticsAndLogical
namespace flagOperation {
void lift_setnz(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
Value* zf = getFlag(builder, FLAG_ZF);
Value* result = createZExtFolder(builder, builder.CreateNot(zf),
Type::getInt8Ty(context));
SetOperandValue(builder, dest, result);
}
void lift_seto(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
Value* of = getFlag(builder, FLAG_OF);
Value* result = createZExtFolder(builder, of, Type::getInt8Ty(context));
SetOperandValue(builder, dest, result);
}
void lift_setno(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
Value* of = getFlag(builder, FLAG_OF);
Value* notOf = builder.CreateNot(of, "notOF");
Value* result = createZExtFolder(builder, notOf, Type::getInt8Ty(context));
SetOperandValue(builder, dest, result);
}
void lift_setnb(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
Value* cf = getFlag(builder, FLAG_CF);
Value* result =
createICMPFolder(builder, CmpInst::ICMP_EQ, cf,
ConstantInt::get(Type::getInt1Ty(context), 0));
Value* byteResult =
createZExtFolder(builder, result, Type::getInt8Ty(context));
SetOperandValue(builder, dest, byteResult);
}
void lift_setbe(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* cf = getFlag(builder, FLAG_CF);
Value* zf = getFlag(builder, FLAG_ZF);
Value* condition = createOrFolder(builder, cf, zf, "setbe-or");
Value* result =
createZExtFolder(builder, condition, Type::getInt8Ty(context));
auto dest = instruction.operands[0];
SetOperandValue(builder, dest, result);
}
void lift_setnbe(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* cf = getFlag(builder, FLAG_CF);
Value* zf = getFlag(builder, FLAG_ZF);
Value* condition = createAndFolder(builder, builder.CreateNot(cf),
builder.CreateNot(zf), "setnbe-and");
Value* result =
createZExtFolder(builder, condition, Type::getInt8Ty(context));
auto dest = instruction.operands[0];
SetOperandValue(builder, dest, result);
}
void lift_setns(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
Value* sf = getFlag(builder, FLAG_SF);
Value* result =
createICMPFolder(builder, CmpInst::ICMP_EQ, sf,
ConstantInt::get(Type::getInt1Ty(context), 0));
Value* byteResult =
createZExtFolder(builder, result, Type::getInt8Ty(context));
SetOperandValue(builder, dest, byteResult);
}
void lift_setp(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* pf = getFlag(builder, FLAG_PF);
Value* result = createZExtFolder(builder, pf, Type::getInt8Ty(context));
auto dest = instruction.operands[0];
SetOperandValue(builder, dest, result);
}
void lift_setnp(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
Value* pf = getFlag(builder, FLAG_PF);
Value* resultValue = createZExtFolder(builder, builder.CreateNot(pf),
Type::getInt8Ty(context));
SetOperandValue(builder, dest, resultValue,
to_string(instruction.runtime_address));
}
void lift_setb(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
Value* cf = getFlag(builder, FLAG_CF);
Value* result = createZExtFolder(builder, cf, Type::getInt8Ty(context));
SetOperandValue(builder, dest, result);
}
void lift_sets(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* sf = getFlag(builder, FLAG_SF);
Value* result = createZExtFolder(builder, sf, Type::getInt8Ty(context));
auto dest = instruction.operands[0];
SetOperandValue(builder, dest, result);
}
void lift_stosx(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0]; // xdi
Value* destValue = GetOperandValue(builder, dest, dest.size);
Value* DF = getFlag(builder, FLAG_DF);
// if df is 1, +
// else -
auto destbitwidth = dest.size;
auto one = ConstantInt::get(DF->getType(), 1);
Value* Direction = builder.CreateSub(
builder.CreateMul(DF, builder.CreateAdd(DF, one)), one);
Value* result = createAddFolder(
builder, destValue,
builder.CreateMul(Direction,
ConstantInt::get(DF->getType(), destbitwidth)));
SetOperandValue(builder, dest, result);
}
void lift_setz(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
Value* zf = getFlag(builder, FLAG_ZF);
Value* extendedZF =
createZExtFolder(builder, zf, Type::getInt8Ty(context), "setz_extend");
SetOperandValue(builder, dest, extendedZF);
}
void lift_setnle(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
Value* zf = getFlag(builder, FLAG_ZF);
Value* sf = getFlag(builder, FLAG_SF);
Value* of = getFlag(builder, FLAG_OF);
Value* zfNotSet =
createICMPFolder(builder, CmpInst::ICMP_EQ, zf,
ConstantInt::get(Type::getInt1Ty(context), 0));
Value* sfEqualsOf = createICMPFolder(builder, CmpInst::ICMP_EQ, sf, of);
printvalue(zf) printvalue(sf) printvalue(of)
Value* combinedCondition =
createAndFolder(builder, zfNotSet, sfEqualsOf, "setnle-and");
Value* byteResult =
createZExtFolder(builder, combinedCondition, Type::getInt8Ty(context));
SetOperandValue(builder, dest, byteResult);
}
void lift_setle(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* zf = getFlag(builder, FLAG_ZF);
Value* sf = getFlag(builder, FLAG_SF);
Value* of = getFlag(builder, FLAG_OF);
Value* sf_ne_of = createICMPFolder(builder, CmpInst::ICMP_NE, sf, of);
Value* condition = createOrFolder(builder, zf, sf_ne_of, "setle-or");
Value* result =
createZExtFolder(builder, condition, Type::getInt8Ty(context));
auto dest = instruction.operands[0];
SetOperandValue(builder, dest, result);
}
void lift_setnl(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* sf = getFlag(builder, FLAG_SF);
Value* of = getFlag(builder, FLAG_OF);
Value* condition = createICMPFolder(builder, CmpInst::ICMP_EQ, sf, of);
Value* result =
createZExtFolder(builder, condition, Type::getInt8Ty(context));
auto dest = instruction.operands[0];
SetOperandValue(builder, dest, result);
}
void lift_setl(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* sf = getFlag(builder, FLAG_SF);
Value* of = getFlag(builder, FLAG_OF);
Value* condition = createICMPFolder(builder, CmpInst::ICMP_NE, sf, of);
Value* result =
createZExtFolder(builder, condition, Type::getInt8Ty(context));
auto dest = instruction.operands[0];
SetOperandValue(builder, dest, result);
}
void lift_bt(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto bitIndex = instruction.operands[1];
// If the bit base operand specifies a register, the instruction takes
// the modulo 16, 32, or 64 of the bit offset operand (modulo size
// depends on the mode and register size; 64-bit operands are available
// only in 64-bit mode). If the bit base operand specifies a memory
// location, the operand represents the address of the byte in memory
// that contains the bit base (bit 0 of the specified byte) of the bit
// string. The range of the bit position that can be referenced by the
// offset operand depends on the operand size. CF := Bit(BitBase,
// BitOffset);
auto Lvalue = GetOperandValue(builder, dest, dest.size);
auto bitIndexValue = GetOperandValue(builder, bitIndex, dest.size);
unsigned LvalueBitW = cast<IntegerType>(Lvalue->getType())->getBitWidth();
auto Rvalue = createAndFolder(
builder, bitIndexValue,
ConstantInt::get(bitIndexValue->getType(), LvalueBitW - 1));
auto shl = createShlFolder(
builder, ConstantInt::get(bitIndexValue->getType(), 1), Rvalue);
auto andd = createAndFolder(builder, shl, Lvalue);
auto cf = createICMPFolder(builder, CmpInst::ICMP_NE, andd,
ConstantInt::get(andd->getType(), 0));
setFlag(builder, FLAG_CF, cf);
printvalue(Rvalue);
printvalue(Lvalue);
printvalue(shl);
printvalue(andd);
printvalue(cf);
}
void lift_btr(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto base = instruction.operands[0];
auto offset = instruction.operands[1];
unsigned baseBitWidth = base.size;
Value* bitOffset = GetOperandValue(builder, offset, base.size);
Value* bitOffsetMasked = createAndFolder(
builder, bitOffset,
ConstantInt::get(bitOffset->getType(), baseBitWidth - 1),
"bitOffsetMasked");
Value* baseVal = GetOperandValue(builder, base, base.size);
Value* bit = createLShrFolder(
builder, baseVal, bitOffsetMasked,
"btr-lshr-" + to_string(instruction.runtime_address) + "-");
Value* one = ConstantInt::get(bit->getType(), 1);
bit = createAndFolder(builder, bit, one, "btr-and");
setFlag(builder, FLAG_CF, bit);
Value* mask =
createShlFolder(builder, ConstantInt::get(baseVal->getType(), 1),
bitOffsetMasked, "btr-shl");
mask = builder.CreateNot(mask); // invert mask
baseVal = createAndFolder(builder, baseVal, mask,
"btr-and-" +
to_string(instruction.runtime_address) + "-");
SetOperandValue(builder, base, baseVal);
printvalue(bitOffset);
printvalue(baseVal);
printvalue(mask);
}
void lift_bsr(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* Rvalue = GetOperandValue(builder, src, src.size);
Value* isZero = createICMPFolder(builder, CmpInst::ICMP_EQ, Rvalue,
ConstantInt::get(Rvalue->getType(), 0));
setFlag(builder, FLAG_ZF, isZero);
unsigned bitWidth = Rvalue->getType()->getIntegerBitWidth();
Value* index = ConstantInt::get(Rvalue->getType(), bitWidth - 1);
Value* zeroVal = ConstantInt::get(Rvalue->getType(), 0);
Value* oneVal = ConstantInt::get(Rvalue->getType(), 1);
Value* bitPosition = ConstantInt::get(Rvalue->getType(), -1);
for (unsigned i = 0; i < bitWidth; ++i) {
Value* mask = createShlFolder(builder, oneVal, index);
Value* test = createAndFolder(builder, Rvalue, mask, "bsrtest");
Value* isBitSet =
createICMPFolder(builder, CmpInst::ICMP_NE, test, zeroVal);
Value* tmpPosition =
createSelectFolder(builder, isBitSet, index, bitPosition);
Value* isPositionUnset =
createICMPFolder(builder, CmpInst::ICMP_EQ, bitPosition,
ConstantInt::get(Rvalue->getType(), -1));
bitPosition = createSelectFolder(builder, isPositionUnset, tmpPosition,
bitPosition);
index = createSubFolder(builder, index, oneVal);
}
SetOperandValue(builder, dest, bitPosition);
}
void lift_bsf(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
auto dest = instruction.operands[0];
auto src = instruction.operands[1];
Value* Rvalue = GetOperandValue(builder, src, src.size);
Value* isZero = createICMPFolder(builder, CmpInst::ICMP_EQ, Rvalue,
ConstantInt::get(Rvalue->getType(), 0));
setFlag(builder, FLAG_ZF, isZero);
Type* intType = Rvalue->getType();
uint64_t intWidth = intType->getIntegerBitWidth();
Value* result = ConstantInt::get(intType, intWidth);
Value* one = ConstantInt::get(intType, 1);
Value* continuecounting = ConstantInt::get(Type::getInt1Ty(context), 1);
for (uint64_t i = 0; i < intWidth; ++i) {
Value* bitMask =
createShlFolder(builder, one, ConstantInt::get(intType, i));
Value* bitSet = createAndFolder(builder, Rvalue, bitMask, "bsfbitset");
Value* isBitZero = createICMPFolder(builder, CmpInst::ICMP_EQ, bitSet,
ConstantInt::get(intType, 0));
// continue until isBitZero is 1
// 0010
// if continuecounting, select
Value* possibleResult = ConstantInt::get(intType, i);
Value* condition =
createAndFolder(builder, continuecounting, isBitZero, "bsfcondition");
continuecounting = builder.CreateNot(isBitZero);
result = createSelectFolder(builder, condition, result, possibleResult,
"updateResultOnFirstNonZeroBit");
}
SetOperandValue(builder, dest, result);
}
void lift_btc(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto base = instruction.operands[0];
auto offset = instruction.operands[1];
unsigned baseBitWidth = base.size;
Value* bitOffset = GetOperandValue(builder, offset, base.size);
Value* bitOffsetMasked = createAndFolder(
builder, bitOffset,
ConstantInt::get(bitOffset->getType(), baseBitWidth - 1),
"bitOffsetMasked");
Value* baseVal = GetOperandValue(builder, base, base.size);
Value* bit = createLShrFolder(
builder, baseVal, bitOffsetMasked,
"btc-lshr-" + to_string(instruction.runtime_address) + "-");
Value* one = ConstantInt::get(bit->getType(), 1);
bit = createAndFolder(builder, bit, one, "btc-and");
setFlag(builder, FLAG_CF, bit);
Value* mask =
createShlFolder(builder, ConstantInt::get(baseVal->getType(), 1),
bitOffsetMasked, "btc-shl");
baseVal = createXorFolder(builder, baseVal, mask,
"btc-and-" +
to_string(instruction.runtime_address) + "-");
SetOperandValue(builder, base, baseVal);
printvalue(bitOffset);
printvalue(baseVal);
printvalue(mask);
}
void lift_lahf(IRBuilder<>& builder) {
LLVMContext& context = builder.getContext();
auto sf = getFlag(builder, FLAG_SF);
auto zf = getFlag(builder, FLAG_ZF);
auto af = getFlag(builder, FLAG_AF);
auto pf = getFlag(builder, FLAG_PF);
auto cf = getFlag(builder, FLAG_CF);
printvalue(sf) printvalue(zf) printvalue(af) printvalue(pf) printvalue(cf);
cf = createZExtFolder(builder, cf, Type::getInt8Ty(context));
pf = createShlFolder(
builder, createZExtFolder(builder, pf, Type::getInt8Ty(context)),
FLAG_PF);
af = createShlFolder(
builder, createZExtFolder(builder, af, Type::getInt8Ty(context)),
FLAG_AF);
zf = createShlFolder(
builder, createZExtFolder(builder, zf, Type::getInt8Ty(context)),
FLAG_ZF);
sf = createShlFolder(
builder, createZExtFolder(builder, sf, Type::getInt8Ty(context)),
FLAG_SF);
Value* Rvalue =
createOrFolder(builder,
createOrFolder(builder, createOrFolder(builder, cf, pf),
createOrFolder(builder, af, sf)),
sf);
printvalue(sf) printvalue(zf) printvalue(af) printvalue(pf) printvalue(cf);
SetRegisterValue(builder, ZYDIS_REGISTER_AH, Rvalue);
}
void lift_stc(IRBuilder<>& builder) {
LLVMContext& context = builder.getContext();
setFlag(builder, FLAG_CF, ConstantInt::get(Type::getInt1Ty(context), 1));
}
void lift_cmc(IRBuilder<>& builder) {
Value* cf = getFlag(builder, FLAG_CF);
Value* one = ConstantInt::get(cf->getType(), 1);
setFlag(builder, FLAG_CF, createXorFolder(builder, cf, one));
}
void lift_clc(IRBuilder<>& builder) {
LLVMContext& context = builder.getContext();
Value* clearedCF = ConstantInt::get(Type::getInt1Ty(context), 0);
setFlag(builder, FLAG_CF, clearedCF);
}
void lift_cld(IRBuilder<>& builder) {
LLVMContext& context = builder.getContext();
Value* clearedDF = ConstantInt::get(Type::getInt1Ty(context), 0);
setFlag(builder, FLAG_DF, clearedDF);
}
void lift_cli(IRBuilder<>& builder) {
LLVMContext& context = builder.getContext();
Value* resetIF = ConstantInt::get(Type::getInt1Ty(context), 0);
setFlag(builder, FLAG_IF, resetIF);
}
void lift_bts(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
auto base = instruction.operands[0];
auto offset = instruction.operands[1];
unsigned baseBitWidth = base.size;
Value* bitOffset = GetOperandValue(builder, offset, base.size);
Value* bitOffsetMasked = createAndFolder(
builder, bitOffset,
ConstantInt::get(bitOffset->getType(), baseBitWidth - 1),
"bitOffsetMasked");
Value* baseVal = GetOperandValue(builder, base, base.size);
Value* bit = createLShrFolder(
builder, baseVal, bitOffsetMasked,
"bts-lshr-" + to_string(instruction.runtime_address) + "-");
Value* one = ConstantInt::get(bit->getType(), 1);
bit = createAndFolder(builder, bit, one, "bts-and");
setFlag(builder, FLAG_CF, bit);
Value* mask =
createShlFolder(builder, ConstantInt::get(baseVal->getType(), 1),
bitOffsetMasked, "bts-shl");
baseVal = createOrFolder(builder, baseVal, mask,
"bts-or-" +
to_string(instruction.runtime_address) + "-");
SetOperandValue(builder, base, baseVal);
printvalue(bitOffset);
printvalue(baseVal);
printvalue(mask);
}
void lift_cwd(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* ax = createZExtOrTruncFolder(
builder,
GetOperandValue(builder, instruction.operands[1],
instruction.operands[1].size),
Type::getInt16Ty(context));
Value* signBit = computeSignFlag(builder, ax);
Value* dx = createSelectFolder(
builder,
createICMPFolder(builder, CmpInst::ICMP_EQ, signBit,
ConstantInt::get(signBit->getType(), 0)),
ConstantInt::get(Type::getInt16Ty(context), 0),
ConstantInt::get(Type::getInt16Ty(context), 0xFFFF), "setDX");
SetOperandValue(builder, instruction.operands[0], dx);
}
void lift_cdq(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
// if eax is -, then edx is filled with ones FFFF_FFFF
Value* eax = createZExtOrTruncFolder(
builder,
GetOperandValue(builder, instruction.operands[1],
instruction.operands[1].size),
Type::getInt32Ty(context));
Value* signBit = computeSignFlag(builder, eax);
Value* edx = createSelectFolder(
builder,
createICMPFolder(builder, CmpInst::ICMP_EQ, signBit,
ConstantInt::get(signBit->getType(), 0)),
ConstantInt::get(Type::getInt32Ty(context), 0),
ConstantInt::get(Type::getInt32Ty(context), 0xFFFFFFFF), "setEDX");
SetOperandValue(builder, instruction.operands[0], edx);
}
void lift_cqo(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
// if rax is -, then rdx is filled with ones FFFF_FFFF_FFFF_FFFF
Value* rax = createZExtOrTruncFolder(
builder,
GetOperandValue(builder, instruction.operands[1],
instruction.operands[1].size),
Type::getInt64Ty(context));
Value* signBit = computeSignFlag(builder, rax);
Value* rdx = createSelectFolder(
builder,
createICMPFolder(builder, CmpInst::ICMP_EQ, signBit,
ConstantInt::get(signBit->getType(), 0)),
ConstantInt::get(Type::getInt64Ty(context), 0),
ConstantInt::get(Type::getInt64Ty(context), 0xFFFFFFFFFFFFFFFF),
"setRDX");
printvalue(rax) printvalue(signBit) printvalue(rdx)
SetOperandValue(builder, instruction.operands[0], rdx);
}
void lift_cbw(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* al = createZExtOrTruncFolder(
builder,
GetOperandValue(builder, instruction.operands[1],
instruction.operands[1].size),
Type::getInt8Ty(context));
Value* ax = createSExtFolder(builder, al, Type::getInt16Ty(context), "cbw");
SetOperandValue(builder, instruction.operands[0], ax);
}
void lift_cwde(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* ax = createZExtOrTruncFolder(
builder,
GetOperandValue(builder, instruction.operands[1],
instruction.operands[1].size),
Type::getInt16Ty(context));
printvalue(ax);
Value* eax =
createSExtFolder(builder, ax, Type::getInt32Ty(context), "cwde");
printvalue(eax);
SetOperandValue(builder, instruction.operands[0], eax);
}
void lift_cdqe(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction) {
LLVMContext& context = builder.getContext();
Value* eax = createZExtOrTruncFolder(
builder,
GetOperandValue(builder, instruction.operands[1],
instruction.operands[1].size),
Type::getInt32Ty(context), "cdqe-trunc");
Value* rax =
createSExtFolder(builder, eax, Type::getInt64Ty(context), "cdqe");
SetOperandValue(builder, instruction.operands[0], rax);
}
} // namespace flagOperation
void liftInstructionSemantics(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses,
bool& run) {
switch (instruction.info.mnemonic) {
// movs
case ZYDIS_MNEMONIC_MOVAPS: {
mov::lift_movaps(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_MOVUPS:
case ZYDIS_MNEMONIC_MOVZX:
case ZYDIS_MNEMONIC_MOVSX:
case ZYDIS_MNEMONIC_MOVSXD:
case ZYDIS_MNEMONIC_MOV: {
mov::lift_mov(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_MOVSB: {
mov::lift_movsb(builder, instruction);
break;
}
// cmov
case ZYDIS_MNEMONIC_CMOVZ: {
cmov::lift_cmovz(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVNZ: {
cmov::lift_cmovnz(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVL: {
cmov::lift_cmovl(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVB: {
cmov::lift_cmovb(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVNB: {
cmov::lift_cmovnb(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVNS: {
cmov::lift_cmovns(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVBE: {
cmov::lift_cmovbz(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVNBE: {
cmov::lift_cmovnbz(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVNL: {
cmov::lift_cmovnl(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVS: {
cmov::lift_cmovs(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVNLE: {
cmov::lift_cmovnle(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVLE: {
cmov::lift_cmovle(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVO: {
cmov::lift_cmovo(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVNO: {
cmov::lift_cmovno(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVP: {
cmov::lift_cmovp(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMOVNP: {
cmov::lift_cmovnp(builder, instruction);
break;
}
// branches
case ZYDIS_MNEMONIC_RET: {
branches::lift_ret(builder, instruction, blockAddresses, run);
break;
}
case ZYDIS_MNEMONIC_JMP: {
branches::lift_jmp(builder, instruction, blockAddresses, run);
break;
}
case ZYDIS_MNEMONIC_JNZ: {
branches::lift_jnz(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JZ: {
branches::lift_jz(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JS: {
branches::lift_js(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JNS: {
branches::lift_jns(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JNBE: {
branches::lift_jnbe(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JNB: {
branches::lift_jnb(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JB: {
branches::lift_jb(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JBE: {
branches::lift_jbe(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JNLE: {
branches::lift_jnle(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JLE: {
branches::lift_jle(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JNL: {
branches::lift_jnl(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JL: {
branches::lift_jl(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JO: {
branches::lift_jo(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JNO: {
branches::lift_jno(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JP: {
branches::lift_jp(builder, instruction, blockAddresses);
break;
}
case ZYDIS_MNEMONIC_JNP: {
branches::lift_jnp(builder, instruction, blockAddresses);
break;
}
// arithmetics and logical operations
case ZYDIS_MNEMONIC_XCHG: {
arithmeticsAndLogical::lift_xchg(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMPXCHG: {
arithmeticsAndLogical::lift_cmpxchg(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_NOT: {
arithmeticsAndLogical::lift_not(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_BSWAP: {
arithmeticsAndLogical::lift_bswap(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_NEG: {
arithmeticsAndLogical::lift_neg(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SAR: {
arithmeticsAndLogical::lift_sar(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SHL: {
arithmeticsAndLogical::lift_shl(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SHLD: {
arithmeticsAndLogical::lift_shld(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SHRD: {
arithmeticsAndLogical::lift_shrd(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SHR: {
arithmeticsAndLogical::lift_shr(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_RCR: {
arithmeticsAndLogical::lift_rcr(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_RCL: {
arithmeticsAndLogical::lift_rcl(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SBB: {
arithmeticsAndLogical::lift_sbb(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_ADC: {
arithmeticsAndLogical::lift_adc(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_XADD: {
arithmeticsAndLogical::lift_xadd(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_LEA: {
arithmeticsAndLogical::lift_lea(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_INC:
case ZYDIS_MNEMONIC_DEC: {
arithmeticsAndLogical::lift_inc_dec(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_MUL: {
arithmeticsAndLogical::lift_mul(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_IMUL: {
arithmeticsAndLogical::lift_imul(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_DIV: {
arithmeticsAndLogical::lift_div(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_IDIV: {
arithmeticsAndLogical::lift_idiv(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SUB:
case ZYDIS_MNEMONIC_ADD: {
arithmeticsAndLogical::lift_add_sub(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_XOR: {
arithmeticsAndLogical::lift_xor(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_OR: {
arithmeticsAndLogical::lift_or(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_AND: {
arithmeticsAndLogical::lift_and(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_ROR: {
arithmeticsAndLogical::lift_ror(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_ROL: {
arithmeticsAndLogical::lift_rol(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_PUSH: {
arithmeticsAndLogical::lift_push(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_PUSHFQ: {
arithmeticsAndLogical::lift_pushfq(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_POP: {
arithmeticsAndLogical::lift_pop(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_POPFQ: {
arithmeticsAndLogical::lift_popfq(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_TEST: {
arithmeticsAndLogical::lift_test(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CMP: {
arithmeticsAndLogical::lift_cmp(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_RDTSC: {
arithmeticsAndLogical::lift_rdtsc(builder);
break;
}
case ZYDIS_MNEMONIC_CPUID: {
arithmeticsAndLogical::lift_cpuid(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CALL: {
branches::lift_call(builder, instruction, blockAddresses);
break;
}
// set and flags
case ZYDIS_MNEMONIC_STOSB:
case ZYDIS_MNEMONIC_STOSW:
case ZYDIS_MNEMONIC_STOSD:
case ZYDIS_MNEMONIC_STOSQ: {
flagOperation::lift_stosx(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETZ: {
flagOperation::lift_setz(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETNZ: {
flagOperation::lift_setnz(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETO: {
flagOperation::lift_seto(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETNO: {
flagOperation::lift_setno(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETNB: {
flagOperation::lift_setnb(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETNBE: {
flagOperation::lift_setnbe(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETBE: {
flagOperation::lift_setbe(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETNS: {
flagOperation::lift_setns(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETP: {
flagOperation::lift_setp(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETNP: {
flagOperation::lift_setnp(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETB: {
flagOperation::lift_setb(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETS: {
flagOperation::lift_sets(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETNLE: {
flagOperation::lift_setnle(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETLE: {
flagOperation::lift_setle(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETNL: {
flagOperation::lift_setnl(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_SETL: {
flagOperation::lift_setl(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_BTR: {
flagOperation::lift_btr(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_BSR: {
flagOperation::lift_bsr(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_BSF: {
flagOperation::lift_bsf(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_BTC: {
flagOperation::lift_btc(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_LAHF: {
flagOperation::lift_lahf(builder);
break;
}
case ZYDIS_MNEMONIC_STC: {
flagOperation::lift_stc(builder);
break;
}
case ZYDIS_MNEMONIC_CMC: {
flagOperation::lift_cmc(builder);
break;
}
case ZYDIS_MNEMONIC_CLC: {
flagOperation::lift_clc(builder);
break;
}
case ZYDIS_MNEMONIC_CLD: {
flagOperation::lift_cld(builder);
break;
}
case ZYDIS_MNEMONIC_CLI: {
flagOperation::lift_cli(builder);
break;
}
case ZYDIS_MNEMONIC_BTS: {
flagOperation::lift_bts(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_BT: {
flagOperation::lift_bt(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CDQ: { // these are not related to flags at all
flagOperation::lift_cdq(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CWDE: {
flagOperation::lift_cwde(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CWD: {
flagOperation::lift_cwd(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CQO: {
flagOperation::lift_cqo(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CDQE: {
flagOperation::lift_cdqe(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_CBW: {
flagOperation::lift_cbw(builder, instruction);
break;
}
case ZYDIS_MNEMONIC_PAUSE:
case ZYDIS_MNEMONIC_NOP: {
break;
}
default: {
cout << "not implemented: " << instruction.info.mnemonic
<< " runtime: " << hex << instruction.runtime_address << " "
<< instruction.text << "\n";
std::string Filename = "output_notimplemented.ll";
std::error_code EC;
raw_fd_ostream OS(Filename, EC);
builder.GetInsertBlock()->getParent()->getParent()->print(OS, nullptr);
throw std::runtime_error("not implemented");
exit(-2);
}
}
}
void liftInstruction(IRBuilder<>& builder,
ZydisDisassembledInstruction& instruction,
shared_ptr<vector<BBInfo>> blockAddresses, bool& run) {
LLVMContext& context = builder.getContext();
// RIP gets updated before execution of the instruction.
auto val = ConstantInt::getSigned(Type::getInt64Ty(context),
instruction.runtime_address +
instruction.info.length);
SetRegisterValue(builder, ZYDIS_REGISTER_RIP, val);
auto rsp = GetRegisterValue(builder, ZYDIS_REGISTER_RSP);
printvalue(rsp);
// I hate how getFunctionInfo returns a string pointer
if (auto funcInfo =
funcsignatures::getFunctionInfo(instruction.runtime_address)) {
callFunctionIR(funcInfo->name.c_str(), builder, funcInfo);
cout << "calling: " << funcInfo->name.c_str() << "\n";
auto next_jump = popStack(builder);
// get [rsp], jump there
auto RIP_value = cast<ConstantInt>(next_jump);
auto jump_address = RIP_value->getZExtValue();
auto bb = BasicBlock::Create(context, "returnToOrgCF",
builder.GetInsertBlock()->getParent());
builder.CreateBr(bb);
blockAddresses->push_back(make_tuple(jump_address, bb, getRegisters()));
run = 0;
return;
}
uint64_t jump_address = instruction.runtime_address + instruction.info.length;
APInt temp;
if (!BinaryOperations::readMemory(jump_address, 1, temp) &&
cast<ConstantInt>(rsp)->getValue() != STACKP_VALUE) {
auto bb = BasicBlock::Create(context, "returnToOrgCF",
builder.GetInsertBlock()->getParent());
// actually call the function first
auto functionName = BinaryOperations::getName(jump_address);
cout << "calling : " << functionName << " addr: " << (uint64_t)jump_address
<< endl;
callFunctionIR(functionName, builder, nullptr);
auto next_jump = popStack(builder);
// get [rsp], jump there
auto RIP_value = cast<ConstantInt>(next_jump);
jump_address = RIP_value->getZExtValue();
builder.CreateBr(bb);
blockAddresses->push_back(make_tuple(jump_address, bb, getRegisters()));
run = 0;
return;
}
// do something for prefixes like rep here
liftInstructionSemantics(builder, instruction, blockAddresses, run);
}