实验: 将静态字符串转换为栈字符串
以下代码在LLVM8-18下测试, 仅使用NewPass. 注意本节只是为了验证静态转栈的可行性, 不推荐实际使用.
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Pass.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Support/raw_ostream.h"
#if LLVM_VERSION_MAJOR <= 15
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#endif
using namespace llvm;
#define PASSNAME "MyPassDemo"
static void doModule(Module& M);
// ---------------- New Pass ---------------- //
#if LLVM_VERSION_MAJOR <= 13
#define OptimizationLevel PassBuilder::OptimizationLevel
#endif
class MyPassDemo : public PassInfoMixin<MyPassDemo> {
public:
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
doModule(M);
return PreservedAnalyses::all();
};
static bool isRequired() { return true; }
};
extern "C" LLVM_ATTRIBUTE_WEAK ::llvm:assPluginLibraryInfo llvmGetPassPluginInfo() {
return {
.APIVersion = LLVM_PLUGIN_API_VERSION,
.PluginName = PASSNAME,
.PluginVersion = "1.0",
.RegisterPassBuilderCallbacks = [](PassBuilder &B) {
PB.registerPipelineStartEPCallback(
[](ModulePassManager &MPM
#if LLVM_VERSION_MAJOR >= 12
, OptimizationLevel Level
#endif
) {
MPM.addPass(MyPassDemo());
});
PB.registerPipelineParsingCallback(
[](StringRef Name, ModulePassManager& MPM, ArrayRef<assBuilder:ipelineElement>) {
MPM.addPass(MyPassDemo());
return true;
});
}
};
}
// ---------------- New Pass ---------------- //
#include <vector>
class TodoItem {
public:
Instruction* inst;
unsigned idx;
StringRef data;
};
void doModule(Module& M) {
std::vector<TodoItem> todo_list;
auto handle_gv = [&todo_list](Instruction* I, unsigned i, GlobalVariable* GV) {
if (GV->isConstant() && GV->hasInitializer()) {
Constant* GVI = GV->getInitializer();
ConstantDataArray* CDA = dyn_cast<ConstantDataArray>(GVI);
if (CDA != 0) {
StringRef data = CDA->getAsString(); // 如果是字符串则包括'\0'
if (data.size() >= 2) {
errs() << "Add todo_list: " << data << "\n";
todo_list.push_back({I, i, data});
}
}
}
};
for (Function& F : M) {
for (BasicBlock& bb : F) {
for (Instruction& I : bb) {
for (unsigned i = 0; i < I.getNumOperands(); i++) {
Value* v = I.getOperand(i);
unsigned valueID = v->getValueID();
if (valueID == Value::GlobalVariableVal) { // LLVM>=15
GlobalVariable* GV = dyn_cast<GlobalVariable>(v);
handle_gv(&I, i, GV);
// @printf(ptr noundef @.str) -> @printf(ptr noundef %str)
} else if (valueID == Value::ConstantExprVal) { // LLVM<=14
ConstantExpr* CE = dyn_cast<ConstantExpr>(v);
unsigned op = CE->getOpcode();
if (op == Instruction::GetElementPtr) {
Value* v0 = CE->getOperand(0);
Value* v1 = CE->getOperand(1);
Value* v2 = CE->getOperand(2);
unsigned vID0 = v0->getValueID();
unsigned vID1 = v1->getValueID();
unsigned vID2 = v2->getValueID();
if (vID0 == Value::GlobalVariableVal && vID1 == Value::ConstantIntVal && vID2 == Value::ConstantIntVal ) {
if (dyn_cast<ConstantInt>(v1)->getSExtValue() == 0 && dyn_cast<ConstantInt>(v2)->getSExtValue() == 0) {
GlobalVariable* GV = dyn_cast<GlobalVariable>(v0);
handle_gv(&I, 0, GV);
// @printf(i8* noundef getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i64 0, i64 0)) -> @printf(i8* noundef %str)
}
}
}
}
}
}
}
}
for (TodoItem& item : todo_list) {
Instruction* inst = item.inst;
unsigned idx = item.idx;
StringRef data = item.data;
BasicBlock* bb = inst->getParent();
IRBuilder<> IRB(&bb->front());
AllocaInst* alloca = IRB.CreateAlloca(IRB.getInt8Ty(), IRB.getInt32(data.size()));
for (unsigned i = 0; i < data.size(); i++) {
Value* gep = IRB.CreateConstGEP1_64(IRB.getInt8Ty(), alloca, i);
Constant* n = ConstantInt::get(IRB.getInt8Ty(), data[i]);
IRB.CreateStore(n, gep);
}
inst->setOperand(idx, alloca);
}
}
测试
// /tmp/1.cpp
#include <stdio.h>
int main(int argc, char** argv) {
printf("helloworld");
return 0;
}
编译为Debug
llvm15/build/bin/clang -isysroot `xcrun --sdk iphoneos --show-sdk-path` -arch arm64 -fpass-plugin=build/MyPassDemo15.dylib -o /tmp/1.bin /tmp/1.cpp
__text:0000000100007E8C SUB X0, X29, #-var_13 ; char *
__text:0000000100007E90 MOV W9, #0x68
__text:0000000100007E94 STURB W9, [X29,#var_13]
__text:0000000100007E98 MOV W9, #0x65
__text:0000000100007E9C STURB W9, [X29,#var_12]
__text:0000000100007EA0 MOV W9, #0x6C
__text:0000000100007EA4 STURB W9, [X29,#var_11]
__text:0000000100007EA8 STURB W9, [X29,#var_10]
__text:0000000100007EAC MOV W10, #0x6F
__text:0000000100007EB0 STURB W10, [X29,#var_F]
__text:0000000100007EB4 MOV W11, #0x77
__text:0000000100007EB8 STURB W11, [X29,#var_E]
__text:0000000100007EBC STURB W10, [X29,#var_D]
__text:0000000100007EC0 MOV W10, #0x72
__text:0000000100007EC4 STURB W10, [X29,#var_C]
__text:0000000100007EC8 STURB W9, [X29,#var_B]
__text:0000000100007ECC MOV W9, #0x64
__text:0000000100007ED0 STURB W9, [X29,#var_A]
__text:0000000100007ED4 STURB WZR, [X29,#var_9]
__text:0000000100007ED8 STR WZR, [SP,#0x30+var_18]
__text:0000000100007EDC STR W8, [SP,#0x30+var_1C]
__text:0000000100007EE0 STR X1, [SP,#0x30+var_28]
__text:0000000100007EE4 BL _printf
// IDA伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
v4 = 104;
v5 = 101;
v6 = 108;
v7 = 108;
v8 = 111;
v9 = 119;
v10 = 111;
v11 = 114;
v12 = 108;
v13 = 100;
printf(&v4);
return 0;
}
注意:此结果为IDA7.0版生成,如果使用IDA7.7+则识别为strcpy
llvm15/build/bin/clang -isysroot `xcrun --sdk macosx --show-sdk-path` -fpass-plugin=build/MyPassDemo15.dylib -o /tmp/1.bin /tmp/1.cpp
__text:0000000100003F06 mov [rbp+var_13], 68h
__text:0000000100003F0A mov [rbp+var_12], 65h
__text:0000000100003F0E mov [rbp+var_11], 6Ch
__text:0000000100003F12 mov [rbp+var_10], 6Ch
__text:0000000100003F16 mov [rbp+var_F], 6Fh
__text:0000000100003F1A mov [rbp+var_E], 77h
__text:0000000100003F1E mov [rbp+var_D], 6Fh
__text:0000000100003F22 mov [rbp+var_C], 72h
__text:0000000100003F26 mov [rbp+var_B], 6Ch
__text:0000000100003F2A mov [rbp+var_A], 64h
__text:0000000100003F2E mov [rbp+var_9], 0
__text:0000000100003F32 mov [rbp+var_18], 0
__text:0000000100003F39 mov [rbp+var_1C], edi
__text:0000000100003F3C mov [rbp+var_28], rsi
__text:0000000100003F40 lea rdi, [rbp+var_13] ; char *
__text:0000000100003F44 mov al, 0
__text:0000000100003F46 call _printf
// IDA伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
v4 = 104;
v5 = 101;
v6 = 108;
v7 = 108;
v8 = 111;
v9 = 119;
v10 = 111;
v11 = 114;
v12 = 108;
v13 = 100;
v14 = 0;
printf(&v4, argv, envp);
result = __stack_chk_guard;
if ( __stack_chk_guard == v15 )
result = 0;
return result;
}
编译为Release
llvm15/build/bin/clang -isysroot `xcrun --sdk iphoneos --show-sdk-path` -arch arm64 -fpass-plugin=build/MyPassDemo15.dylib -o /tmp/1.bin /tmp/1.cpp -O3
__text:0000000100007ED8 LDR D0, =0x726F776F6C6C6568
__text:0000000100007EDC STR D0, [SP,#0x20+var_18]
__text:0000000100007EE0 MOV W8, #0x646C
__text:0000000100007EE4 STRH W8, [SP,#0x20+var_10]
__text:0000000100007EE8 STRB WZR, [SP,#0x20+var_E]
__text:0000000100007EEC ADD X0, SP, #0x20+var_18 ; char *
__text:0000000100007EF0 BL _printf
// IDA伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
strcpy(v4, "helloworld");
result = printf(v4, argv, envp);
if ( __stack_chk_guard == v5 )
result = 0;
return result;
}
注意:此时IDA已经把上述指令集识别成内部函数的strcpy, 这里strcpy非动态库里的那个函数
llvm15/build/bin/clang -isysroot `xcrun --sdk macosx --show-sdk-path` -fpass-plugin=build/MyPassDemo15.dylib -o /tmp/1.bin /tmp/1.cpp -O3
__text:0000000100003F46 mov rax, 726F776F6C6C6568h
__text:0000000100003F50 mov qword ptr [rbp+var_18], rax
__text:0000000100003F54 mov [rbp+var_10], 646Ch
__text:0000000100003F5A mov [rbp+var_E], 0
__text:0000000100003F5E lea rdi, [rbp+var_18] ; char *
__text:0000000100003F62 xor eax, eax
__text:0000000100003F64 call _printf
// IDA伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
strcpy(v4, "helloworld");
printf(v4, argv, envp);
if ( __stack_chk_guard != v5 )
__stack_chk_fail();
return 0;
}
介入时机指定为EP_OptimizerLast,编译为Release
llvm15/build/bin/clang -isysroot `xcrun --sdk iphoneos --show-sdk-path` -arch arm64 -fpass-plugin=build/MyPassDemo15.dylib -o /tmp/1.bin /tmp/1.cpp -O3
__text:0000000100007ED4 MOV X8, #0x6568
__text:0000000100007ED8 MOVK X8, #0x6C6C,LSL#16
__text:0000000100007EDC MOVK X8, #0x776F,LSL#32
__text:0000000100007EE0 MOVK X8, #0x726F,LSL#48
__text:0000000100007EE4 STUR X8, [SP,#0x20+var_13]
__text:0000000100007EE8 MOV W8, #0x646C
__text:0000000100007EEC STURH W8, [SP,#0x20+var_B]
__text:0000000100007EF0 STRB WZR, [SP,#0x20+var_9]
__text:0000000100007EF4 ADD X0, SP, #0x20+var_13 ; char *
__text:0000000100007EF8 BL _printf
// IDA伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
strcpy(v4, "helloworld");
result = printf(v4, argv, envp);
if ( __stack_chk_guard == v5 )
result = 0;
return result;
}
llvm15/build/bin/clang -isysroot `xcrun --sdk macosx --show-sdk-path` -fpass-plugin=build/MyPassDemo15.dylib -o /tmp/1.bin /tmp/1.cpp -O3
__text:0000000100003F46 mov rax, 726F776F6C6C6568h
__text:0000000100003F50 mov qword ptr [rbp+var_13], rax
__text:0000000100003F54 mov [rbp+var_B], 646Ch
__text:0000000100003F5A mov [rbp+var_9], 0
__text:0000000100003F5E lea rdi, [rbp+var_13] ; char *
__text:0000000100003F62 xor eax, eax
__text:0000000100003F64 call _printf
// IDA伪代码
int __cdecl main(int argc, const char **argv, const char **envp)
{
// [COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL-"+" TO EXPAND]
strcpy(v4, "helloworld");
printf(v4, argv, envp);
if ( __stack_chk_guard != v5 )
__stack_chk_fail();
return 0;
}