LLVM程序分析日记之getIntNTy()
LLVM IR中惯用的IntegerType主要是:
Int8TyInt16TyInt32TyInt64Ty
但是,今天注意到了一个有意思的API:
static IntegerType * getIntNTy (LLVMContext &C, unsigned N)
从而,我们可以定义任意长度的IntegerType,能够更加灵活地使用LLVM玩出花样。以下给出一个例子,在这个例子中,我们希望提取字符串的前N字节(N <= 8)。
Instrument Training
原始程序demo.c:
unsigned long long str2hex(char *buf) {
return 0;
}
int main() {
char buf[32];
scanf("%s", buf);
printf("Hex: %8llx\n", str2hex(buf));
return 0;
}
我们的目标是插桩democ.c的str2hex()函数,使该函数返回char *buf的前N = 6个字节的Hex形式。
为了实现该目标,我们需要编写一个LLVM Pass,其中主要逻辑如下:
for (llvm::Function &F : M) {
if (F.getName() != "str2hex") continue;
IntegerType *IntNTy = IntegerType::getIntNTy(C, 48); // 6 * 8 = 48 bits
IntegerType *Int64Ty = IntegerType::getInt64Ty(C);
BasicBlock::iterator IP = F.getEntryBlock().getFirstInsertionPt();
Value* arg = &(*F.arg_begin());
IRBuilder<> IRB(&(*IP));
Value *ptr = IRB.CreateBitCast(IRB.CreateGEP(arg, ConstantInt::get(Int64Ty, 0)), IntNTy->getPointerTo());
Value *hex = IRB.CreateLoad(ptr);
hex = IRB.CreateZExt(hex, Int64Ty);
for (auto &I : *IP->getParent()) {
if (dyn_cast<llvm::ReturnInst>(&I)) {
llvm::ReturnInst *new_inst = llvm::ReturnInst::Create(m->getContext(), hex);
ReplaceInstWithInst(&I, new_inst);
break;
}
}
}
插桩后的demo.ll如下:
define i64 @str2hex(i8*) #3 {
%2 = getelementptr i8, i8* %0, i64 0
%3 = bitcast i8* %2 to i48*
%4 = load i48, i48* %3
%5 = zext i48 %4 to i64
%6 = alloca i8*, align 8
store i8* %0, i8** %6, align 8
ret i64 %5
}
运行lli demo_instrumented.bc,输入abcdefghijk,输出666564636261,成功!
IntNTy在x86上的实现方式
之所以Int8Ty、Int16Ty、Int32Ty更常用,是因为它们对应了Byte、Word、Dword等类型,可以直接通过汇编指令表示。为了探究IntNTy,即任意长度的整型在x86汇编中的实现,我们将上一小节中的demo.c编译成可执行文件,并通过gdb反汇编来查看插桩代码的实现:
push rbp
mov rbp,rsp
mov eax,DWORD PTR [rdi]
mov ecx,eax
movzx eax,WORD PTR [rdi+0x4]
mov edx,eax
shl rdx,0x20
or rcx,rdx
mov QWORD PTR [rbp-0x8],rdi
mov rax,rcx
pop rbp
ret
可以看到,对于6字节的IntNTy,汇编中首先读取一个4字节的Dword,接着读取一个2字节的Word,然后通过“移位”与“或”操作组合成一个6字节的值。
总结
显然,IntNty提供了更方便的方式,让我们可以在插桩时使用一个任意长度的整型值。但是,从汇编角度,当LLVM IR最终编译成汇编代码时,IntNTy仍然是基于Byte、Dword等类型实现,并且仍然需要引入额外的开销来进行组合。LLVM IR只不过是将基础类型“组合”的部分进行了封装,提供了便捷但并不会提升效率。

浙公网安备 33010602011771号