5

我正在做一个任务,我们应该对一个用糟糕的加密算法加密的 PDF 进行加密分析。

教授提供的代码使用fd=open(filename, O_CREAT|O_WRONLY, S_IRUSR|S_IWUSR).

在我尝试解密的代码中,我使用fd_in=open(file, O_RDONLY).

问题是当我尝试从文件中读取时,我收到“错误的文件描述符”错误。我使用 stat 尝试获取有关文件描述符对已打开文件的“想法”的更多信息,它表明该文件的长度为 0,而实际上它只有几百 KB。

我正在使用的调试代码是:

if (0 > (len = read(fd_in, (char*)&read_buff, BITE))) {    // BITE is defined as 8
  printf("Error occured grabbing first bite of %s.\n", file);
  printf("%s.\n", strerror(errno));

  struct stat fileStat;
  int stat = fstat(fd_in, &fileStat);

  printf("fstat returned: %d.\n", stat);      // Consistently printing 0
  printf("Information for %s\n",file);
  printf("---------------------------\n");
  printf("File Size: \t\t%d bytes\n",fileStat.st_size);
  printf("Number of Links: \t%d\n",fileStat.st_nlink);
  printf("File inode: \t\t%d\n",fileStat.st_ino);

  printf("File Permissions: \t");
  printf( (S_ISDIR(fileStat.st_mode)) ? "d" : "-");
  printf( (fileStat.st_mode & S_IRUSR) ? "r" : "-");
  printf( (fileStat.st_mode & S_IWUSR) ? "w" : "-");
  printf( (fileStat.st_mode & S_IXUSR) ? "x" : "-");
  printf( (fileStat.st_mode & S_IRGRP) ? "r" : "-");
  printf( (fileStat.st_mode & S_IWGRP) ? "w" : "-");
  printf( (fileStat.st_mode & S_IXGRP) ? "x" : "-");
  printf( (fileStat.st_mode & S_IROTH) ? "r" : "-");
  printf( (fileStat.st_mode & S_IWOTH) ? "w" : "-");
  printf( (fileStat.st_mode & S_IXOTH) ? "x" : "-");
  printf("\n\n");

  return 1;

}

我得到的结果是:

Error occured grabbing first bite of enc.pdf.
Bad file descriptor.
Information for enc.pdf
---------------------------
File Size:      0 bytes
Number of Links:    1
File inode:         16441996
File Permissions:   -rw-------

ls 将文件报告为

-rw-------  1 matt  matt   157887 Oct 29 03:01 enc.pdf

与打开文件相关的代码:

int fd_in=open(file, O_RDONLY);
if(fd_in<0) {
   printf("Failed to open the input file %s.\n", file);
   return 1;
} else {
    printf("File open, descriptor is: %d.\n", fd_in);
}

这一直打印出字段描述符的值 3。

有一些关于 read_buff 的问题。加密/解密过程涉及对读取的值进行异或。因此,缓冲区被声明为 aunsigned long long并且为了读入它,我获取地址并将其转换为 (char*)。这种策略直接来自于教授创建加密文件的代码。

我什至添加了一个带有 printf 的 else 来验证文件描述符是否有效。目前它似乎始终如一3,这绝对不是-1

4

3 回答 3

2

您可能想检查调用open()和之间的堆栈是否损坏read(),以便更改文件描述符的值fd_in

于 2012-10-29T14:16:01.627 回答
0

您忽略了检查各种运算符的结果。fd_in == -1在上面列出的代码中,我非常确定。

要使用低级 I/O 打开数据文件,您需要执行以下操作:

#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>

...

    int  fd;

    do {
        fd = open(filename, O_RDONLY | O_NOCTTY);
    } while (fd == -1 && errno == EINTR);
    if (fd == -1) {
        const char *const errmsg = strerror(errno);
        fprintf(stderr, "%s: %s.\n", filename, errmsg);
        exit(1);
    }

这是因为open()总是可以被打断。

read()也可以被打断,但通常它只返回一个简短的计数。

不,您不能只说“但它通常会读取我所要求的所有内容,如果发生这种情况我会在稍后修复”,因为它实际上取决于系统详细信息 - 特别是文件恰好驻留在哪个文件系统上. 在不同的系统上运行会产生不同的结果——更不用说它不是文件而是命名管道或字符设备。只有白痴会假设read()总是(甚至通常)会阅读您要求的所有内容。

稳健的方法是使用辅助函数,可能类似于

#include <unistd.h>
#include <sys/types.h>
#include <sched.h>
#include <errno.h>

/* Read between minimum and maximum bytes (inclusive)
 * from descriptor to buffer. Save the number of bytes
 * read into *bytes if bytes is not NULL.
 * The function returns 0 if successful, errno error otherwise.
 * If there is less input than minimum bytes, the function
 * will return ENOENT.
*/
static inline int readfd(const int descriptor,
                         void *const buffer,
                         const size_t minimum,
                         const size_t maximum,
                         size_t *const bytes)
{
    size_t   have = 0;
    ssize_t  n;

    while (have < minimum) {

        n = read(descriptor, (char *)buffer + have, maximum - have);
        if (n > (ssize_t)0) {
            have += n;
            if (bytes)
                *bytes = have;

        } else
        if (n == (ssize_t)0) {
            /* EOF, and have < minimum. */
            return errno = ENOENT;

        } else
        if (n != (ssize_t)-1) {
            /* A rare I/O error (Linux kernel bug). */
            return errno = EIO;

        } else
        if (errno == EWOULDBLOCK || errno == EAGAIN) {
            /* Nonblocking descriptor; ouch. Busy-loop. */
            sched_yield();

        } else
        if (errno != EINTR)
            return errno;
    }

    return 0;
}

该函数将使用指定的文件读取指定的字节minimummaximum字节之间的内容。如果成功,它将返回 0,否则返回非零。如果没有足够的数据来满足最小值,它将返回。bufferdescriptorerrnoENOENT

它甚至可以在非阻塞描述符上工作,通过对非阻塞描述符进行忙循环(每次重试和失败时只产生当前时间片)。这意味着不建议将其与非阻塞描述符一起使用,但如果出于某种奇怪的原因需要,您可以. 你只是不应该需要。(事实上​​,我个人放弃了那个位—— EAGAIN/EWOULDBLOCK检查和sched_yield()——所以如果描述符是或必须是非阻塞的,我会注意到并修复我的代码以使用正确的方法。)

于 2012-10-29T11:15:09.247 回答
0

对不起,这应该是一个评论。无法从这里发表评论。什么是 read_buff?为什么要转换为 char* ?

如果read_buff 定义为char *read_buff;then(fd, &read_buff, LEN);可以执行缓冲区溢出,覆盖您的自动变量。

于 2012-10-29T11:40:54.250 回答