pwn常用函数解析

文章发布时间:

最后更新时间:

文章总字数:
2.2k

预计阅读时间:
8 分钟

页面浏览:加载中...

64位传参顺序

6个参数及以内时

参数从左到右加入寄存器时:rdi,rsi,rdx,rcx,r8,r9

当参数为7个以上时

前6个与前面一样,但后面的依次从起,当参数对齐7个时,参数从左到右加入寄存器时:rdi,rsi,rdx,rcx,r8,r9。六个以上的内容加入栈中,即和32位组装一样。

函数原型

open(open64)函数

1
int open(const char *path, int access, int mode);

参数解释:
path:要打开的文件路径和名称。
access:访问模式,宏定义和含义如下:
– O_RDONLY(1):只读打开;
– O_WRONLY(2):只写打开;
– O_RDWR(4):读写打开;
还可选择以下模式与以上3种基本模式相与:
– O_CREAT(0x0100)创建一个文件并打开;
– O_TRUNC(0x0200)打开一个已存在的文件并将文件长度设置为0,其他属性保持;
– O_EXCL(0x0400)未使用;
– O_APPEND(0x0800)追加打开文件;
– O_TEXT(0x4000)打开文本文件翻译CR-LF控制字符;
– O_BINARY(0x8000)打开二进制字符,不作CR-LF翻译;
mode:该参数仅在access=O_CREAT方式下使用,其取值如下:
– S_IFMT(0xF000):文件类型掩码;
– S_IFDIR(0x4000):目录;
– S_IFIFO(0x1000):FIFO 专用;
– S_IFCHR(0x2000):字符专用;
– S_IFBLK(0x3000):块专用;
– S_IFREG(0x8000):只为0x0000;
– S_IREAD(0x0100):可读;
– S_IWRITE(0x0080):可写;
– S_IEXEC(0x0040):可执行;

fopen函数

函数原型:

1
**FILE *fopen(char *filename, char *mode);**

参数解释:
– filename:文件名称。
– mode:打开模式:
r:只读方式打开一个文本文件(该文件必须存在);
r+:可读可写方式打开一个文本文件(该文件必须存在);
w:只写方式打开一个文本文件(若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件);
w+:可读可写方式创建一个文本文件(若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件);
a:追加方式打开一个文本文件(若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留));
a+:可读可写追加方式打开一个文本文件(若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留));
rb:只读方式打开一个二进制文件(使用法则同r);
rb+:可读可写方式打开一个二进制文件(使用法则同r+);
wb:只写方式打开一个二进制文件(使用法则同w);
wb+:可读可写方式生成一个二进制文件(使用法则同w+);
ab:追加方式打开一个二进制文件(使用法则同a);
ab+:可读可写方式追加一个二进制文件(使用法则同a+);
返回参数: 文件顺利打开后,指向该流的文件指针就会被返回。若果文件打开失败则返回NULL,并把错误代码存在errno 中。一般而言,打开文件后会作一些文件读取或写入的动作,若打开文件失败,接下来的读写动作也无法顺利进行,所以在fopen()后请作错误判断及处理。

两者的区别

前者属于低级IO,后者是高级IO。 前者返回一个文件描述符,后者返回一个文件指针。 前者无缓冲,后者有缓冲。 前者与 read, write 等配合使用, 后者与 fread, fwrite等配合使用。 后者是在前者的基础上扩充而来的,在大多数情况下,用后者。

write函数原型

**

1
ssize_t write(int fd, const void *buf, size_t count);

调用该函数时,需要有三个参数,下面简单的介绍下这三个参数的含义。

fd:要操作的文件的文件描述符,通过open函数打开文件时获取。

buf:指定写入数据对应的缓冲区,可以将需要的写入的内容存放到buf中,再将其写入文件里。

count:指定写入的字节数,单位是字节。

返回值:如果写操作顺利完成,则会返回写入的字节数;如果返回值为0,则表示未向文件中写入任何字符;如果写入出错,则会返回-1。

一般来说

fd=1时标准输出,fd=文件fd时输出到文件

read函数原型

C语言中,read函数是用于从文件描述符中读取数据的函数,其原型如下:

1
2
3
#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

read函数的参数如下:

  1. fd:文件描述符,指定要读取的文件或套接字的标识符。
  2. buf:指向存储读取数据的缓冲区的指针。
  3. count:要读取的最大字节数。

read函数的返回值是实际读取的字节数。如果返回值为0,表示已到达文件末尾;如果返回值为-1,表示读取出错。

需要注意的是,read函数是一个阻塞函数,当没有数据可读时,它会一直等待直到有数据可读或出现错误。如果需要非阻塞读取数据,可以使用selectpoll等函数进行操作。

一般来说

fd=0时标准输入,fd=文件fd时读取文件

fd描述符

0,1,2 这三个 fd 值已经被赋予特殊含义,分别是标准输入( STDIN_FILENO ),标准输出( STDOUT_FILENO ),标准错误( STDERR_FILENO )

puts函数

1
int puts(const char *s);

printf函数

printf 函数原型为

1
int printf(const char *fmt, ...)

后面的参数以fmt的内容定

mprotect函数

1
2
3
#include <unistd.h>   
#include <sys/mmap.h>
int mprotect(const void *start, size_t len, int prot);

mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。

prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:

1)PROT_READ:表示内存段内的内容可读;

2)PROT_WRITE:表示内存段内的内容可写;

3)PROT_EXEC:表示内存段中的内容可执行;

4)PROT_NONE:表示内存段中的内容根本没法访问。

需要指出的是,锁指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。

如果执行成功,则返回0;如果执行失败,则返回-1,并且设置errno变量,说明具体因为什么原因造成调用失败。错误的原因主要有以下几个:

1)EACCES

该内存不能设置为相应权限。这是可能发生的,比如,如果你 mmap(2) 映射一个文件为只读的,接着使用 mprotect() 标志为 PROT_WRITE。

2)EINVAL

start 不是一个有效的指针,指向的不是某个内存页的开头。

3)ENOMEM

内核内部的结构体无法分配。

4)ENOMEM

进程的地址空间在区间 [start, start+len] 范围内是无效,或者有一个或多个内存页没有映射。

如果调用进程内存访问行为侵犯了这些设置的保护属性,内核会为该进程产生 SIGSEGV (Segmentation fault,段错误)信号,并且终止该进程。

Memset

1
void *memset(void *str, int c, size_t n)

复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。其返回值是一个指向 str 的指针

Sprintf

1
int sprintf(char *str, const char *format, ...) 

发送格式化输出到 str 所指向的字符串。

第二第三个参数对应了 printf 的第一第二个参数,只是多了个输出到的位置,以及检查标签个数和参数个数相同。

如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

Strncmp

1
int strncmp(const char *str1, const char *str2, size_t n)

把 str1 和 str2 进行比较,最多比较前 n 个字节。

这个比较是通过逐个比较ascii码实现的,遇到ascii码不同直接返回

如果返回值 < 0,则表示 str1 小于 str2。

如果返回值 > 0,则表示 str1 大于 str2。

如果返回值 = 0,则表示 str1 等于 str2。

fgets

fgets函数功能为从指定的流中读取数据,每次读取一行。其原型为:

1
char *fgets(char *str, int n, FILE *stream);

从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

scanf()

原型:

1
`int scanf(const char *format, ...);`