update chapter1_basic.tex

This commit is contained in:
skyel1u 2018-01-29 17:56:49 +08:00
parent ca913232b9
commit bbdabed1a5
2 changed files with 101 additions and 1 deletions

Binary file not shown.

View File

@ -467,15 +467,115 @@ db-peda$ x/s 0xffffd584
\indent 在 Linux 系统中一切皆可以看成是文件文件又分为普通文件、目录文件、链接文件和设备文件。文件描述符file descriptor是内核管理已被打开的文件所创建的索引使用一个非负整数来指代被打开的文件。
\indent 标准文件描述符如下:
\indent \\
\begin{tabular}[ht]{|c|c|c|}
\hline
文件描述符 & 用途 & stdio 流 \\
\hline
0 & 标准输入 & stdin \\
\hline
1 & 标准输出 & stdout \\
\hline
2 & 标准错误 & stderr \\
\hline
\end{tabular}
\indent 当一个程序使用 \verb+fork()+ 生成一个子进程后,子进程会继承父进程所打开的文件表,此时,父子进程使用同一个文件表,这可能导致一些安全问题。如果使用 \verb+vfork()+,子进程虽然运行于父进程的空间,但拥有自己的进程表项。
\indent 当一个程序使用 \verb+fork+ 生成一个子进程后,子进程会继承父进程所打开的文件表,此时,父子进程使用同一个文件表,这可能导致一些安全问题。如果使用 \verb+fork()+,子进程虽然运行于父进程的空间,但拥有自己的进程表项。
\subsubsection{核心转储}
\indent \setlength{\parindent}{2em}
\indent 当程序运行的过程中异常终止或崩溃操作系统会将程序当时的内存、寄存器状态、堆栈指针、内存管理信息等记录下来保存在一个文件中这种行为就叫做核心转储Core Dump
\indent 会产生核心转储的信号:
\begin{tabular}{|c|c|c|}
\hline
Signal & Action & Comment \\
\hline
SIGQUIT & Core & Quit from keyboard \\
\hline
SIGILL & Core & Illegal Instruction \\
\hline
SIGABRT & Core & Abort signal from abort \\
\hline
SIGSEGV & Core & Invalid memory reference \\
\hline
SIGTRAP & Core & Trace/breakpoint trap \\
\hline
\end{tabular}
\indent 开启核心转储:
\indent \begin{itemize}
\item 输入命令 \verb+ulimit -c+,输出结果为 0说明默认是关闭的。
\item 输入命令 \verb+ulimit -c unlimited+ 即可在当前终端开启核心转储功能。
\item 如果想让核心转储功能永久开启,可以修改文件 \verb+/etc/security/limits.conf+,增加一行:
\item \verb+#<domain> <type> <item> <value>+
\item \verb+* soft core unlimited+
\end{itemize}
\indent
\indent 修改转储文件保存路径:
\begin{itemize}
\item 通过修改 \verb+/proc/sys/kernel/core_uses_pid+,可以使生成的核心转储文件名变为 \verb+core.[pid]+ 的模式:
\item \verb+# echo 1 > /proc/sys/kernel/core_uses_pid+
\item 还可以修改 \verb+/proc/sys/kernel/core_pattern+ 来控制生成核心转储文件的保存位置和文件名格式:
\item \verb+# echo /tmp/core-%e-%p-%t > /proc/sys/kernel/core_pattern+
\end{itemize}
\indent 此时生成的文件保存在 /tmp/ 目录下,文件名格式为 core-[filename]-[pid]-[time]。
\indent 例子:
\begin{lstlisting}[language=bash, style=customStyleBashDark, caption=内存转储示例]
$ cat core.c
#include <stdio.h>
void main(int argc, char **argv) {
char buf[5];
scanf("%s", buf);
}
$ gcc -m32 -fno-stack-protector core.c
$ ./a.out
AAAAAAAAAAAAAAAAAAAA
Segmentation fault (core dumped)
$ file /tmp/core-a.out-12444-1503198911
/tmp/core-a.out-12444-1503198911: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, from './a.out', real uid: 1000, effective uid: 1000, real gid: 1000, effective gid: 1000, execfn: './a.out', platform: 'i686'
$ gdb a.out /tmp/core-a.out-12444-1503198911 -q
Reading symbols from a.out...(no debugging symbols found)...done.
[New LWP 12444]
Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x5655559b in main ()
gdb-peda$ info frame
Stack level 0, frame at 0x41414141:
eip = 0x5655559b in main; saved eip = <not saved>
Outermost frame: Cannot access memory at address 0x4141413d
Arglist at 0x41414141, args:
Locals at 0x41414141, Previous frame's sp is 0x41414141
Cannot access memory at address 0x4141413d
\end{lstlisting}
\subsubsection{调用约定}
\indent \setlength{\parindent}{2em}
\indent 函数调用约定是对函数调用时如何传递参数的一种约定。关于它的约定有许多种,下面我们分别从内核接口和用户接口介绍 32 位和 64 位 Linux 的调用约定。
\indent 内核接口
\indent x86-32 系统调用约定Linux 系统调用使用寄存器传递参数。
\indent \verb+eax+ 为 \verb+syscall_number+\verb+ebx+、\verb+ecx+、\verb+edx+、\verb+esi+、\verb+ebp+ 用于将 6 个参数传递给系统调用。返回值保存在 eax 中。所有其他寄存器(包括 \verb+EFLAGS+)都保留在 \verb+int 0x80+ 中。
\indent x86-64 系统调用约定:内核接口使用的寄存器有:\verb+rdi+、\verb+rsi+、\verb+rdx+、\verb+r10+、\verb+r8+、\verb+r9+。系统调用通过 \verb+syscall+ 指令完成。除了 \verb+rcx+、\verb+r11+ 和 \verb+rax+,其他的寄存器都被保留。系统调用的编号必须在寄存器 \verb+rax+ 中传递。系统调用的参数限制为 6 个,不直接从堆栈上传递任何参数。返回时,\verb+rax+ 中包含了系统调用的结果。而且只有 \verb+INTEGER+ 或者 \verb+MEMORY+ 类型的值才会被传递给内核。
\indent 用户接口
\indent x86-32 函数调用约定:
\indent 参数通过栈进行传递。最后一个参数第一个被放入栈中,直到所有的参数都放置完毕,然后执行 \verb+call+ 指令。这也是 Linux 上 C 语言函数的方式。
\indent x86-64 函数调用约定:
\indent x86-64 下通过寄存器传递参数,这样做比通过栈有更高的效率。它避免了内存中参数的存取和额外的指令。根据参数类型的不同,会使用寄存器或传参方式。如果参数的类型是 \verb+MEMORY+,则在栈上传递参数。如果类型是 \verb+INTEGER+,则顺序使用 \verb+rdi+、\verb+rsi+、\verb+rdx+、\verb+rcx+、\verb+r8+ 和 \verb+r9+。所以如果有多于 6 个的 \verb+INTEGER+ 参数,则后面的参数在栈上传递。
\subsubsection{环境变量}
\indent \setlength{\parindent}{2em}