一、Linux基础知识
1. 根目录结构
linux中的一切都可以看成文件, Linux下的起点是在 根目录下, 都是从(/斜杆)开始向下延申的。一般情况下程序打开终端是处在你自己的文件夹下
linux的文件类型主要包含三种:
- 普通文件: 包含文本文件(只含 ASCII或Unicode字符,换行符为”\n”, 即十六进制0x0A)和二进制文件
- 目录: 包含一组链接的文件,其中每个链接都将一个文件名映射到一个文件,这个文件可能是另一个目录
- 特殊文件: 包括块文件、符号链接、管道、套接字等
目录层次结构中位置可以用绝对路径(从根节点开始)和相对路径(从当前目录开始)表示
(1)文件与目录的区别
目录:就相当于windows下的文件夹
文件:就是一群文件
(2)根目录与家目录的区别
家目录:一般打开终端的就是在家目录下,这里就是你这个用户存放的文件处
根目录:即最开始的目录,它下面存放着操作系统的一些信息,而且如果该系统存在多用户,在home目录下还会出现多个用户名
(3)linux的一些区别
linux下的文件格式不以文件名的后缀确定,而是有文件的文件头决定。也就是说它本事是一个压缩包,那么即使修改了它的后缀它仍然是一个压缩包
等等
2. 软链接(符号链接)与硬链接
软链接:类似于windows下的快捷键
硬链接:相当于复制一份文件
2. 字节序
计算机采用了两种字节存储机制:大端和小端。
其中大端规定在MSB在存储是放在地位,在传输时放在流的开始;LSB存储时放在高地址,在传输时放在流的末尾。
小端则正好相反。
小端: 常见的Intel处理器使用,做题时一般情况下都是小端
大端: PowerPC系列处理器、TCP/IP协议和Java虚拟机的字节序等等
以一个十六进制整数 0x12345678存入以 1000H 开始的内存为例,查看存储方式不同,可以发现大端存储就是我们日产生活中使用的形式,而小段则是相反的。这是因为······
3. ld-linux.so
ld-linux .so是linux下的动态库链接器/加载器。
当一个 需要动态链接 的程序被操作系统加载时, 系统要通过要ld-linux.so来定位 然后加载程序所需要的所有动态库文件。
此时 我们可以通过ldd命令来查看一个程序需要哪些依赖的动态库
4. 调用约定
函数调用约定是对函数调用时如何传递参数的一种约定。关于它的预定有许多种,下面从内核接口和用户接口两仿麦呢介绍32位和64位Linux的调用约定
(1)内核接口
- x86_32系统调用约定:32位程序主要通过寄存器传递参数。eax位syscall_number、ebx、ecx、edx、esi和ebp用于将6个参数传递给系统调用。返回值保存在eax中。所有寄存器都保留在int 0x80中
- 查看程序的系统调用
strace ./pwn
链接:http://blog.chinaunix.net/uid-69947851-id-5825847.html
- execve函数
5. 系统调用
系统调用就是:操作系统已经抽象好了的一个接口,你要怎么操控硬件,只能经过操作系统已经制定好了的系统调用规定的规则来操控硬件,不可直接访问它。
在Linux下可以查看32位、64位程序下的系统调用号
cat /usr/include/asm/unistd_32.h
cat /usr/include/asm/unistd_64.h
32位与64位程序之间的区别
① 32位与64位的系统调用号对应的内容不同
② 32位程序用的是, 而64位程序采用的是syscall
这里以64位程序为例
#ifndef _ASM_X86_UNISTD_64_H
#define _ASM_X86_UNISTD_64_H 1
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
#define __NR_close 3
#define __NR_stat 4
#define __NR_fstat 5
#define __NR_lstat 6
#define __NR_poll 7
#define __NR_lseek 8
#define __NR_mmap 9
#define __NR_mprotect 10
#define __NR_munmap 11
#define __NR_brk 12
#define __NR_rt_sigaction 13
#define __NR_rt_sigprocmask 14
#define __NR_rt_sigreturn 15
#define __NR_ioctl 16
#define __NR_pread64 17
#define __NR_pwrite64 18
#define __NR_readv 19
#define __NR_writev 20
#define __NR_access 21
#define __NR_pipe 22
#define __NR_select 23
#define __NR_sched_yield 24
#define __NR_mremap 25
#define __NR_msync 26
#define __NR_mincore 27
#define __NR_madvise 28
#define __NR_shmget 29
#define __NR_shmat 30
#define __NR_shmctl 31
#define __NR_dup 32
#define __NR_dup2 33
#define __NR_pause 34
#define __NR_nanosleep 35
#define __NR_getitimer 36
#define __NR_alarm 37
#define __NR_setitimer 38
#define __NR_getpid 39
#define __NR_sendfile 40
#define __NR_socket 41
#define __NR_connect 42
#define __NR_accept 43
#define __NR_sendto 44
#define __NR_recvfrom 45
#define __NR_sendmsg 46
#define __NR_recvmsg 47
#define __NR_shutdown 48
#define __NR_bind 49
#define __NR_listen 50
#define __NR_getsockname 51
#define __NR_getpeername 52
#define __NR_socketpair 53
#define __NR_setsockopt 54
#define __NR_getsockopt 55
#define __NR_clone 56
#define __NR_fork 57
#define __NR_vfork 58
#define __NR_execve 59
#define __NR_exit 60
···········
#endif /* _ASM_X86_UNISTD_64_H */
这里面最重要的一个系统调用是59号的execve,它的原型就是execve(“/bin/sh”, null, null)相当于system函数
它的调用方式是
- rax 59(系统调用号, 可以自己写,可以是程序本身的)
- rdi /bin/sh(参数1)
- rsi 0(参数2)
- rdx 0(参数3)
- syscall(调用方式:一个地址)
32位程序的话就是eax、ebx、ecx、edx以及int 80
二、linux基础命令
(1) 查看命令:
cat flag.txt # 查看flag.txt文件里面的内容
ll flag # 查看flag目录里的文件
ls flag # 查看flag目录下的文件
(2)mv命令
mv test.c test.zip # 修改test.c 的名字为 test.zip
mv ~/test.c ./ #将家目录下的test.c文件移动到当前目录下
(3)cd命令
cd flag # 进入当前目录下的flag目录
cd # 回到家目录
cd / # 回到根目录
cd ../ # 回到上一个目录
(4)clear命令
clear # 清理全屏
(4)rm命令
rm test.txt # 删除test.txt文件
rm -r test # 删除test目录
rm -f test.txt # 直接删除,无需确认
(5)cp命令
cp ~/test.c ./ # 将根目录下的test.c 文件复制到当前目录下
(6)易混淆的命令
./
(点号 + /):表示当前目录
~/
(波浪号 + /):表示家目录
/
(/):表示根目录
(7)不常见的命令:
strace ./pwn 查看程序的系统调用(学习链接:http://blog.chinaunix.net/uid-69947851-id-5825847.html)
三、Vi、Vim的操作
vim是从vi发展来的编辑器,相对来说更加友善。vim是一款比较常见的编辑器,在Linux操作系统下用纯命令行来实现功能。当然也可以下载其他的编辑器来实现,这样可能会更加方便、美观
VIM有三种模式:底线命令行模式、编辑模式、命令行模式。每一种模式都有它对应的命令行
命令模式:你刚启动vim时就是命令模式,此时你并不会输入一个字符,当你按下i以后才会进入编辑模式编辑
编辑模式:这种模式是来让你来进行修改文件的,
底线命令行模式:编辑模式以后按住:
就会进入底线命令行模式, 底线模式就是为了进行保存、推出的
wq:表示保存退出
q:表示放弃然后退出
q!:表示强制退出
%!xxd 查看二进制。
%!xxd -r 还原
四、Pwn中重要的命令
1. file文件
用于检测给定文件的类型,一般情况是不带参数的
参数: -z: 用于读取压缩文件的内容 -L:用于解析符号链接的文件类型
1. ROPgadget命令
# 获取pwn这个二进制文件的的 只带有 pop和ret指令的地址
ROPgadget --binary ./pwn --only “pop|ret”
# 寻找带有字符串/bin/sh的地址
ROPgadget --binary 【文件名】--string '/bin/sh
# 寻找int80的地址:
ROPgadget --binary 【文件名】--only int
#寻找文件中带有cat flag字符串的地址
ROPgadget --binary 文件名 --sting 'cat flag'
2. objdump命令
用于查看目标文件的信息,具备反汇编能力。但是其反汇编主要是依赖的是ELF文件头,而且不会进行控制流分析,其健壮性较差,常见的参数如下:
-s
:将目标文件转换成十六进制表示
-d
:用于对目标文件进行反汇编
-D
:用于对目标文件进行反汇编
-j
:指定具体的某一个节
常见的使用
① 查找函数GOT的地址,用于获取函数的真实地址
# 获取pwn这个二进制文件的的 只带有 pop和ret指令的地址
ROPgadget --binary ./pwn --only “pop|ret”
# 寻找带有字符串/bin/sh的地址
ROPgadget --binary 【文件名】--string '/bin/sh
# 寻找int80的地址:
ROPgadget --binary 【文件名】--only int
#寻找文件中带有cat flag字符串的地址
ROPgadget --binary 文件名 --sting 'cat flag'
3. readfile命令
用于解析ELF格式目标文件的信息。该工具和objdump类似,但是显示的内容更具体,且不依赖BFD库,常见的参数如下:
-h
:显示目标文件的文件头-l
:显示目标文件的程序头
-S
:显示目标文件的节区头信息
-s
:显示目标文件的符号表
--dyn-syms
:显示目标文件的动态符号表
常见的使用:
① 查看程序的文件头
②在libc中查看system函数的偏移量
4. ldd命令
ldd命令用于查看目标文件有哪些依赖库, 以及这些依赖库在系统中的位置。常见的参数:
-v
:用于打印出依赖关系的详细信息
常见的使用
① 在ret2_libc 当中,当使用本地调试时需要获取该程序的libcbanben
5. strace 命令
strace ./pwn:查看程序的系统调用(链接:http://blog.chinaunix.net/uid-69947851-id-5825847.html)
6. gcc编译程序
方法二:
gcc test.c -o test
gcc -Wall -g -o test test.c
-Wall 代表编译器在编译过程中会输出警告信息(Warning),比如有些变量你并没有使用,指针指向的类型有误,main 函数没有返回整数值等。这类信息虽然不是错误,不影响编译,但是很可能是程序 bug 的源头,也有助于你寻找代码中的错误,规范代码格式。所以建议每次编译时都加上 -Wall 参数。
-g 代表编译器会收集调试(debug)信息,这样如果你的程序运行出错,就可以通过 gdb 或者 lldb 等工具进行逐行调试,方便找出错误原因。如果你不是百分之百确定你的程序毫无问题,建议加上 -g 参数。这样 debug 的时候会方便很多。
-o 代表编译器会将编译完成后的可执行文件以你指定的名称输出到你指定的文件夹下。-o 的空格后的名称就是输出的文件的名称。例如我这里 -o 后是 test,就是说 gcc 会在编译成功后在我的当前目录下生成一个叫 test 的可执行文件。如果不加这个参数,每次编译后生成的可执行文件都会放在根目录下,名字叫做 a.out。每次编译成功后都会把上一次的 a.out 文件覆盖。所以建议加上 -o 参数,这样可以更加条理。
-m32:编译32位程序
-
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮箱至 1627319559@qq.com