打开正在运行的二进制文件

时间:2017-03-12 10:49:08

标签: c fopen binaryfiles

我在基本c中编写lite程序,为参数中传递的二进制文件中的每个字节添加(或子)偏移量。这项工作适用于所有其他ELF,但是当我试图运行时:
$ ./a.out a.out 1 (每个字节加0x01),
fopen()崩溃并显示错误消息“文本文件繁忙” 我使用lsof进行了检查,但未在文件系统上打开 我认为当一个可执行文件正在运行时,文件的图像被加载到RAM中并且文件是可访问的 如果有人知道那件事,我会接受它! 感谢您抽出宝贵时间阅读我!

以下是代码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void usage (char *pgr_name); // print usage and exit
void fatal(char *s); // print s, call perror("") and exit(-1)

// lite hexdump ([0xff] x16 | ...a...b...c...d )
void dump (const unsigned char *data_buffer, const unsigned int len);

int main(int argc, char **argv) {
    FILE *my, *crypted;
    void *content;
    unsigned char *ascii;
    char output[256] = "";
    int i, bytes_read, offset;

    if (argc < 3)
        usage(argv[0]);

    offset = atoi(argv[2]);
    if (offset < -255 || offset > 0xff) {
        printf("bad offset\n");
        usage(argv[0]);
    }

    printf("offset %d\n", offset);

    // open src
    if ((my = fopen(argv[1], "rb+")) == NULL)
        fatal("in opening argv[1]");

    // alloc memory for src
    if ((content = malloc (10000)) == NULL)
        fatal("in malloc");

    // read src
    bytes_read = fread(content, 1, 9999, my);
    printf("%d bytes read\n", bytes_read);

    // for reading easily
    ascii = (unsigned char *) content;

    dump(content, bytes_read);

    // apply offset on each bytes
    for (i=0; i<bytes_read; i++)
        ascii[i] = ascii[i] + offset;
    printf("\n\ntranslation complete\n\n");

    dump(content, bytes_read);

    strncpy(output, argv[1], 250);
    strcat(output, ".cry");

    // open dest
    if ((crypted = fopen(output, "wb+")) == NULL)
        fatal("in open crypted");

    // write src translated in dest
    bytes_read = fwrite(content, 1, bytes_read, crypted);
    printf("%d bytes written\n", bytes_read);

    // terminate pgrm
    fclose(crypted);
    fclose(my);
    free(content);

    return 0;
}

void fatal(char *s) {
    if (s) {
        fprintf(stderr, "[!] Fatal [!] : %s\n", s);
    }
    perror("");
    exit(-1);
}

void usage (char *pgr_name) {
    printf("Usage : %s <binary input> <offset [-255:255]>\n\n", pgr_name);
    exit(0);
}

void dump (const unsigned char *data_buffer, const unsigned int len) {
    unsigned char byte;
    unsigned int i, j;
    for (i=0; i<len; i++) {
        byte = data_buffer[i];
        printf("%02x ", data_buffer[i]);
        if (((i%16) == 15 ) || (i==len-1)) {
            for (j=0; j < 15-(i%16); j++) 
                printf("   ");
            printf("|  ");
            for (j=(i-(i%16)); j<=i; j++) {
                byte = data_buffer[j];
                if (byte > 31 && byte < 127)
                    printf("%c", byte);
                else
                    printf(".");
            }
            printf("\n");
        }
    }
}

2 个答案:

答案 0 :(得分:2)

Unix文件系统 - 在Unix,BSD,macOS,Linux等中使用的 - 依赖于inodes。多个文件名可以引用相同的inode。

如果删除了文件名,但inode仍在一个或多个进程中打开,则inode没有引用它的文件名。您仍然可以正常使用打开的文件 - 例如扩展它 - 但是没有其他进程可以打开它(除非您以某种方式为它们提供打开的文件描述符)。

执行ELF二进制文件时,内核会锁定底层的inode。注意:它是锁定的inode,而不是文件名。

这是因为而不是&#34; loading&#34;将数据存入内存,大多数系统只是对数据进行内存映射。例如,在Linux中,这意味着无论您运行的可执行文件或动态库有多少副本,RAM中只存在一个二进制文件副本。

实际上,这意味着您无法在执行ELF二进制文件时修改它。但是,您可以重命名甚至删除该文件,因为它是文件名引用的inode,而不是内核锁定的文件名。 (当然,你可以读取ELF二进制文件就好了,即使它们正被执行;你只需要确保以只读方式打开它们,因为打开它们读写会失败。这是因为大多数Unix文件系统只检查访问权限在开放时间。)

你可以做的是创建一个新文件;写修改后的数据;可选地复制所有者,组,模式,上次访问和上次修改时间戳,和/或扩展属性(xattrs);最后在旧文件名上重命名或硬链接新文件名。 (重命名或硬链接现有文件只会更改现有文件名引用的inode,因此不会违反inode锁定。)

这具有替换(旧二进制)原子的额外好处。无论其他进程何时打开或执行旧二进制文件,它们始终只能看到旧的inode或新的inode,而不是某种中间版本。

答案 1 :(得分:0)

您无法在写入模式下实际打开C中任何程序正在使用的文件。即使您打开文件,在您在该文件上调用fflush()fclose()之前,您在程序中对文件所做的更改也不会显示。