7

绕过操作系统,c语言直接读写ext2

 3 years ago
source link: https://blog.popkx.com/c-read-and-write-ext2-1/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
    本节用 C语言,绕过 linux 操作系统,直接操作 ext2 文件系统, 写出读写前面几讲中的用来模拟 ext2 文件系统的 disk 文件。
    disk 的 0x430 位置是一个日期,我们用 C 对其读取和修改。

用到的系统函数:

1. open 函数


  • 功能描述:用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数。
  • 所需头文件: <sys/types.h> <sys/stat.h> <fcntl.h>
  • 函数原型:int open(const char* pathname, int flags, int perms)
 · pathname: 被打开的文件名(可包括路径名如"dev/ttyS0")
 · flags: 文件打开方式,
 · O_RDONLY:以只读方式打开文件
 · O_WRONLY:以只写方式打开文件
 · O_RDWR:以读写方式打开文件
 · O_CREAT:如果改文件不存在,就创建一个新的文件,并用第三个参数为其设置权限
 · O_EXCL:如果使用O_CREAT时文件存在,则返回错误消息。这一参数可测试文件是否存在。此时open是原子操作,防止多个进程同时创建同一个文件
 · O_NOCTTY:使用本参数时,若文件为终端,那么该终端不会成为调用open()的那个进程的控制终端
 · O_TRUNC:若文件已经存在,那么会删除文件中的全部原有数据,并且设置文件大小为0
 · O_APPEND:以添加方式打开文件,在打开文件的同时,文件指针指向文件的末尾,即将写入的数据添加到文件的末尾
 · O_NONBLOCK: 如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式。
 · O_SYNC:使每次write都等到物理I/O操作完成。
 · O_RSYNC:read 等待所有写入同一区域的写操作完成后再进行
在open()函数中,falgs参数可以通过“|”组合构成,但前3个标准常量(O_RDONLY,O_WRONLY,和O_RDWR)不能互相组合。
 · perms:被打开文件的存取权限,可以用两种方法表示,可以用一组宏定义:S_I(R/W/X)(USR/GRP/OTH),其中R/W/X表示读写执行权限,
 · USR/GRP/OTH分别表示文件的所有者/文件所属组/其他用户,如S_IRUUR|S_IWUUR|S_IXUUR,(-rex------),也可用八进制800表示同样的权限
 · 成功:返回文件描述符
 · 失败:返回-1

2. close 函数


  • 功能描述: 用于关闭一个被打开的的文件

  • 所需头文件: <unistd.h>

  • 函数原型: int close(int fd)

  • 参数:fd文件描述符

  • 函数返回值:0成功,-1出错

3. read 函数


  • 功能描述: 从文件读取数据。

  • 所需头文件: <unistd.h>

  • 函数原型:ssize_t read(int fd, void * buf, size_t count);

 · fd: 将要读取数据的文件描述词。
 · buf:指缓冲区,即读取的数据会被放到这个缓冲区中去。
 · count: 表示调用一次read操作,应该读多少数量的字符。
  • 返回值:返回所读取的字节数;0(读到EOF);-1(出错)。

以下几种情况会导致读取到的字节数小于 count :

    A. 读取普通文件时,读到文件末尾还不够 count 字节。例如:如果文件只有 30 字节,而我们想读取 100 字节,那么实际读到的只有 30 字节,read 函数返回 30 。此时再使用 read 函数作用于这个文件会导致 read 返回 0 。
    B. 从终端设备(terminal device)读取时,一般情况下每次只能读取一行。
    C. 从网络读取时,网络缓存可能导致读取的字节数小于 count字节。
    D. 读取 pipe 或者 FIFO 时,pipe 或 FIFO 里的字节数可能小于 count 。
    E. 从面向记录(record-oriented)的设备读取时,某些面向记录的设备(如磁带)每次最多只能返回一个记录。
    F. 在读取了部分数据时被信号中断。
读操作始于 cfo 。在成功返回之前,cfo 增加,增量为实际读取到的字节数。

4. write 函数


  • 功能描述: 向文件写入数据。
  • 所需头文件:<unistd.h>
  • 函数原型:ssize_t write(int fd, void * buf, size_t count);
  • 返回值:写入文件的字节数(成功);-1(出错)
write 函数向 filedes 中写入 count 字节数据,数据来源为 buf 。返回值一般总是等于 count,否则就是出错了。常见的出错原因是磁盘空间满了或者超过了文件大小限制。

对于普通文件,写操作始于 cfo 。如果打开文件时使用了 O_APPEND,则每次写操作都将数据写入文件末尾。成功写入后,cfo 增加,增量为实际写入的字节数。

5. lseek 函数


  • 功能描述: 用于在指定的文件描述符中将将文件指针定位到相应位置。
  • 所需头文件:<unistd.h>,<sys/types.h>
  • 函数原型:off_t lseek(int fd, off_t offset,int whence);
 · fd:文件描述符
 · offset:偏移量,每一个读写操作所需要移动的距离,单位是字节,可正可负(向前移,向后移)
 · whence:
SEEK_SET:当前位置为文件的开头,新位置为偏移量的大小
SEEK_CUR:当前位置为指针的位置,新位置为当前位置加上偏移量
SEEK_END:当前位置为文件的结尾,新位置为文件大小加上偏移量的大小
成功:返回当前位移
失败:返回-1
  • 其实就是简单的调用上面几个函数

MFile.h

#ifndef __CMFILE_H__
#define __CMFILE_H__

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <stdarg.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>

#include <sys/types.h>
#include <sys/stat.h>


#define     MFILE_OK           0
#define     MFILE_OPEN         -1
#define     MFILE_SEEK         -2
#define     MFILE_READ         -3
#define     MFILE_WRITE        -4

int             MFileOpen(char* cpFileName);
int             MFileClose();

int             MFileRead(void* vpOutBuf, unsigned int uiReadLen, off_t liFrom);
int             MFileWrite(void* vpInBuf, unsigned int uiWriteLen, off_t liFrom);
unsigned char   MFileReadByte(off_t liFrom);
int             MFileWriteByte(unsigned char ucWriteData, off_t liFrom);




#endif

MFile.c

 #include "../include/CMFile.h"

static int m_fd = 0;

int MFileOpen(char* cpFileName)
{
    m_fd = open(cpFileName, O_RDWR);
    if(0 > m_fd){
        printf("%s open error, Message: %s\n", __FUNCTION__, strerror(errno));
        return MFILE_OPEN;
    }
    return MFILE_OK;    
}

int MFileClose()
{
    if(0 < m_fd){
        close(m_fd);
    }

    return MFILE_OK;
}

int MFileRead(void* vpOutBuf, unsigned int uiReadLen, off_t liFrom)
{
    off_t addr = lseek(m_fd, liFrom, SEEK_SET);
    if(-1 == addr){
        printf("%s lseek error, Message: %s\n", __FUNCTION__, strerror(errno));
        return MFILE_SEEK;
    }

    // memset(vpOutBuf, 0, sizeof(vpOutBuf));

    int num = read(m_fd, vpOutBuf, uiReadLen);
    if(-1 == num){
        printf("%s read error, Message: %s\n", __FUNCTION__, strerror(errno));
        return MFILE_READ;
    }

    return num;
}

int MFileWrite(void* vpInBuf, unsigned int uiWriteLen, off_t liFrom)
{
    off_t addr = lseek(m_fd, liFrom, SEEK_SET);
    if(-1 == addr){
        printf("%s lseek error, Message: %s\n", __FUNCTION__, strerror(errno));
        return MFILE_SEEK;
    }

    int num = write(m_fd, vpInBuf, uiWriteLen);
    if(-1 == num){
        printf("%s write error, Message: %s\n", __FUNCTION__, strerror(errno));
        return MFILE_WRITE;
    }

    return num;
}

unsigned char MFileReadByte(off_t liFrom)
{
    unsigned char rtn = 0;

    if(-1 == MFileRead(&rtn, 1, liFrom)){
        printf("%s read error, Message: %s\n", __FUNCTION__, strerror(errno));
        return MFILE_READ;
    }

    return rtn;
}

int MFileWriteByte(unsigned char ucWriteData, off_t liFrom)
{
    if(-1 == MFileWrite(&ucWriteData, 1, liFrom)){
        printf("%s write error, Message: %s\n", __FUNCTION__, strerror(errno));
        return MFILE_WRITE;
    }

    return MFILE_OK;
}

main.c

#include "../include/CMFile.h"

int main()
{
    char fileName[] = "../../tmp/disk";
    unsigned char rbuf[128] = {0};
    unsigned char wbuf[] = {123, 221, 222, 111};    // 原来0x430 起的四个字节为 32, 207, 235, 90

    if(0 > MFileOpen(fileName)){
        printf("MFileOpen error\n");
        return -1;
    }

    // 测试连续读取
    printf("\ntest MFileRead ------------------------------\n");
    int num = MFileRead(rbuf, 4, 0x430);
    printf("read %s %d bytes from addr: %x, res: \n", fileName, num, 0x430);
    for(int i=0; i<num; i++){
        printf("%d ", rbuf[i]);
    }
    printf("\n");

    // 测试连续写入
    printf("\ntest MFileWrite ------------------------------\n");
    num = MFileWrite(wbuf, 4, 0x430);
    printf("write %s %d bytes from addr: %x, res: \n", fileName, num, 0x430);    
    num = MFileRead(rbuf, 4, 0x430);
    printf("read %s %d bytes from addr: %x, res: \n", fileName, num, 0x430);
    for(int i=0; i<num; i++){
        printf("%d ", rbuf[i]);
    }
    printf("\n");

    // 测试单字节读取
    printf("\ntest MFileReadByte ------------------------------\n");
    unsigned char res = MFileReadByte(0x430);
    printf("read byte: %d\n", res);

    // 测试单字节写入
    printf("\ntest MFileWriteByte ------------------------------\n");
    MFileWriteByte(32, 0x430);
    res = MFileReadByte(0x430);
    printf("read byte: %d\n", res);

    MFileClose();

    return 0;
}

  • 结果如下:

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK