diff --git a/SUMMARY.md b/SUMMARY.md index 0ac88a2..15959e7 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -95,7 +95,7 @@ GitHub 地址:https://github.com/firmianay/CTF-All-In-One * [5.3.3 KLEE](doc/5.3.3_klee.md) * [5.3.4 S²E](doc/5.3.4_s2e.md) * 5.4 - * 5.5 + * [5.5 Clang](doc/5.5_clang.md) * [5.6 LLVM](doc/5.6_llvm.md) * [5.7 Capstone/Keystone](doc/5.7_cap-keystone.md) * [5.8 SAT/SMT](doc/5.8_sat-smt.md) diff --git a/doc/4.8_dynelf.md b/doc/4.8_dynelf.md index cf293ea..ef912fa 100644 --- a/doc/4.8_dynelf.md +++ b/doc/4.8_dynelf.md @@ -80,7 +80,7 @@ DynELF 使用了两种技术: - ELF 文件会从如 libc.so 库中导入符号,有一系列的表给出了导出符号名、导出符号地址和导出符号的哈希值。通过对某个符号名做哈希,可以定位到哈希表中,然后哈希表的位置又提供了字符串表(strtab)和符号表(symtab)的索引。 - 假设我们有了 libc.so 的基地址,解析 printf 地址的方法是定位 symtab、strtab 和 hash 表。对字符串"printf"做哈希,然后定位到哈希表中的某一条,然后从 symtab 中得到其在 libc.so 的偏移。 - 解析库地址 - - 如果我们有一个指向动态链接的可执行文件的指针,就可以利用一二称为 link map 的内部链接器结构。这是一个链表结构,包含了每个被加载的库的信息,包括完整路径和基地址。 + - 如果我们有一个指向动态链接的可执行文件的指针,就可以利用一个称为 link map 的内部链接器结构。这是一个链表结构,包含了每个被加载的库的信息,包括完整路径和基地址。 - 有两种方法可以找到这个指向 link map 的指针。两者都是从 DYNAMIC 数组条目中得到的。 - 在 non-RELOAD 的二进制文件中,该指针在 `.got.plt` 区域中。这是通过 `DT_PLTGOT` 找到的。 - 在所有二进制文件中,可以在 `DT_DEBUG` 描述的区域中找到该指针,甚至在 stripped 之后也不例外。 diff --git a/doc/5.5_clang.md b/doc/5.5_clang.md new file mode 100644 index 0000000..a0a3823 --- /dev/null +++ b/doc/5.5_clang.md @@ -0,0 +1,15 @@ +# 5.5 Clang + +- [简介](#简介) +- [初步使用](#初步使用) +- [参考资料](#参考资料) + + +## 简介 +Clang 一个基于 LLVM 的编译器前端,支持 C/C++/Objective-C 等语言。其开发目标是替代 GCC。 + + +## 初步使用 + +## 参考资料 +- [llvm documentation](http://llvm.org/docs/index.html) diff --git a/doc/5.6_llvm.md b/doc/5.6_llvm.md index c90d6ed..09c662e 100644 --- a/doc/5.6_llvm.md +++ b/doc/5.6_llvm.md @@ -1 +1,132 @@ # 5.6 LLVM + +- [简介](#简介) +- [初步使用](#初步使用) +- [参考资料](#参考资料) + + +## 简介 +LLVM 是当今炙手可热的编译器基础框架。它从一开始就采用了模块化设计的思想,使得每一个编译阶段都被独立出来,形成了一系列的库。LLVM 使用面向对象的 C++ 语言开发,为编译器开发人员提供了易用而丰富的编程接口和 API。 + + +## 初步使用 +首先我们通过著名的 helloWorld 来熟悉下 LLVM 的使用。 +```c +#include +int main() +{ + printf("hello, world\n"); +} +``` + +将 C 源码转换成 LLVM 汇编码: +``` +$ clang -emit-llvm -S hello.c -o hello.ll +``` +生成的 LLVM IR 如下: +``` +; ModuleID = 'hello.c' +source_filename = "hello.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@.str = private unnamed_addr constant [14 x i8] c"hello, world\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone sspstrong uwtable +define i32 @main() #0 { + %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i32 0, i32 0)) + ret i32 0 +} + +declare i32 @printf(i8*, ...) #1 + +attributes #0 = { noinline nounwind optnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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"="+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" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.module.flags = !{!0, !1, !2} +!llvm.ident = !{!3} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"PIC Level", i32 2} +!2 = !{i32 7, !"PIE Level", i32 2} +!3 = !{!"clang version 5.0.1 (tags/RELEASE_501/final)"} +``` +该过程从词法分析开始,将 C 源码分解成 token 流,然后传递给语法分析器,语法分析器在 CFG(上下文无关文法)的指导下将 token 流组织成 AST(抽象语法树),接下来进行语义分析,检查语义正确性,最后生成 IR。 + +LLVM bitcode 有两部分组成:位流,以及将 LLVM IR 编码成位流的编码格式。使用汇编器 llvm-as 将 LLVM IR 转换成 bitcode: +``` +$ llvm-as hello.ll -o hello.bc +``` +结果如下: +``` +$ file hello.bc +hello.bc: LLVM IR bitcode +$ xxd -g1 hello.bc | head -n5 +00000000: 42 43 c0 de 35 14 00 00 05 00 00 00 62 0c 30 24 BC..5.......b.0$ +00000010: 49 59 be 66 ee d3 7e 2d 44 01 32 05 00 00 00 00 IY.f..~-D.2..... +00000020: 21 0c 00 00 4d 02 00 00 0b 02 21 00 02 00 00 00 !...M.....!..... +00000030: 13 00 00 00 07 81 23 91 41 c8 04 49 06 10 32 39 ......#.A..I..29 +00000040: 92 01 84 0c 25 05 08 19 1e 04 8b 62 80 10 45 02 ....%......b..E. +``` + +反过来将 bitcode 转回 LLVM IR 也是可以的,使用反汇编器 llvm-dis: +``` +$ llvm-dis hello.bc -o hello.ll +``` + +其实 LLVM 可以利用工具 lli 的即时编译器(JIT)直接执行 bitcode 格式的程序: +``` +$ lli hello.bc +hello, world +``` + +接下来使用静态编译器 llc 命令可以将 bitcode 编译为特定架构的汇编语言: +``` +$ llc -march=x86-64 hello.bc -o hello.s +``` +也可以使用 clang 来生成,结果是一样的: +``` +$ clang -S hello.bc -o hello.s -fomit-frame-pointer +``` +结果如下: +```asm + .text + .file "hello.c" + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main + .cfi_startproc +# BB#0: + pushq %rbp +.Lcfi0: + .cfi_def_cfa_offset 16 +.Lcfi1: + .cfi_offset %rbp, -16 + movq %rsp, %rbp +.Lcfi2: + .cfi_def_cfa_register %rbp + movabsq $.L.str, %rdi + movb $0, %al + callq printf + xorl %eax, %eax + popq %rbp + retq +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .type .L.str,@object # @.str + .section .rodata.str1.1,"aMS",@progbits,1 +.L.str: + .asciz "hello, world\n" + .size .L.str, 14 + + + .ident "clang version 5.0.1 (tags/RELEASE_501/final)" + .section ".note.GNU-stack","",@progbits +``` + + +## 参考资料 +- [llvm documentation](http://llvm.org/docs/index.html) diff --git a/doc/5_advanced.md b/doc/5_advanced.md index bd18dec..3ffc9d8 100644 --- a/doc/5_advanced.md +++ b/doc/5_advanced.md @@ -10,7 +10,7 @@ - [5.3.3 KLEE](5.3.3_klee.md) - [5.3.4 S²E](5.3.4_s2e.md) - 5.4 -- 5.5 +- [5.5 Clang](5.5_clang.md) - [5.6 LLVM](5.6_llvm.md) - [5.7 Capstone/Keystone](5.7_cap-keystone.md) - [5.8 SAT/SMT](5.8_sat-smt.md) diff --git a/src/Others/5.6_llvm/hello.bc b/src/Others/5.6_llvm/hello.bc new file mode 100644 index 0000000..7310d6f Binary files /dev/null and b/src/Others/5.6_llvm/hello.bc differ diff --git a/src/Others/5.6_llvm/hello.c b/src/Others/5.6_llvm/hello.c new file mode 100644 index 0000000..dc9ce02 --- /dev/null +++ b/src/Others/5.6_llvm/hello.c @@ -0,0 +1,5 @@ +#include +int main() +{ + printf("hello, world\n"); +} diff --git a/src/Others/5.6_llvm/hello.ll b/src/Others/5.6_llvm/hello.ll new file mode 100644 index 0000000..5efd246 --- /dev/null +++ b/src/Others/5.6_llvm/hello.ll @@ -0,0 +1,25 @@ +; ModuleID = 'hello.c' +source_filename = "hello.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@.str = private unnamed_addr constant [14 x i8] c"hello, world\0A\00", align 1 + +; Function Attrs: noinline nounwind optnone sspstrong uwtable +define i32 @main() #0 { + %1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i32 0, i32 0)) + ret i32 0 +} + +declare i32 @printf(i8*, ...) #1 + +attributes #0 = { noinline nounwind optnone sspstrong uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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"="+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" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "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"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.module.flags = !{!0, !1, !2} +!llvm.ident = !{!3} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"PIC Level", i32 2} +!2 = !{i32 7, !"PIE Level", i32 2} +!3 = !{!"clang version 5.0.1 (tags/RELEASE_501/final)"} diff --git a/src/Others/5.6_llvm/hello.s b/src/Others/5.6_llvm/hello.s new file mode 100644 index 0000000..3ec4108 --- /dev/null +++ b/src/Others/5.6_llvm/hello.s @@ -0,0 +1,35 @@ + .text + .file "hello.c" + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main + .cfi_startproc +# BB#0: + pushq %rbp +.Lcfi0: + .cfi_def_cfa_offset 16 +.Lcfi1: + .cfi_offset %rbp, -16 + movq %rsp, %rbp +.Lcfi2: + .cfi_def_cfa_register %rbp + movabsq $.L.str, %rdi + movb $0, %al + callq printf + xorl %eax, %eax + popq %rbp + retq +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .type .L.str,@object # @.str + .section .rodata.str1.1,"aMS",@progbits,1 +.L.str: + .asciz "hello, world\n" + .size .L.str, 14 + + + .ident "clang version 5.0.1 (tags/RELEASE_501/final)" + .section ".note.GNU-stack","",@progbits