打开一个 运行 二进制文件
open a running binary file
我用基本的 c 编写精简程序,为参数中传递的二进制文件中的每个字节添加(或减去)偏移量。这适用于所有其他 ELF,但是当我尝试 运行 :
$ ./a.out a.out 1
(每个字节加0x01),
fopen()
崩溃并显示错误消息 "Text file busy"。
我检查了 lsof
,但未在文件系统上打开。
我认为当一个可执行文件是 运行ning 时,文件的图像被加载到 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");
}
}
}
Unix 文件系统——用于 Unix、BSD、macOS、Linux 等的文件系统——依赖于 inodes。多个文件名可以引用同一个inode。
如果文件名被删除,但索引节点在一个或多个进程中仍然打开,则索引节点没有引用它的文件名。您仍然可以正常使用打开的文件——例如扩展它——但没有其他进程可以打开它(除非您以某种方式向它们提供打开的文件描述符)。
执行ELF二进制文件时,底层inode被内核锁定。注意:被锁定的是inode,不是文件名。
这是因为大多数系统不是将数据 "loading" 放入内存,而是简单地对数据进行内存映射。例如,在 Linux 中,这意味着无论您有多少个可执行文件或动态库副本 运行,RAM 中只存在一个二进制副本。
实际上,这意味着您不能在执行 ELF 二进制文件时对其进行修改。但是,您可以重命名甚至删除该文件,因为它是文件名所指的索引节点,而不是被内核锁定的文件名。 (当然,即使正在执行 ELF 二进制文件,您也可以很好地读取它们;您只需要确保以只读方式打开它们,因为以读写方式打开它们会失败。这是因为大多数 Unix 文件系统只检查访问权限在开放时间。)
您可以做的是创建一个新文件;写入修改后的数据;可选择复制所有者、组、模式、上次访问和上次修改时间戳,and/or 扩展属性 (xattrs);最后重命名或硬链接旧文件名上的新文件名。 (对现有文件进行重命名或硬链接只会更改现有文件名所指的 inode,因此不会违反 inode 锁定。)
这有一个额外的好处,即(旧二进制文件的)替换是原子的。无论其他进程何时打开或执行旧二进制文件,它们总是只会看到旧 inode 或新 inode,而不会看到某种中间版本。
您实际上无法以写入模式打开任何 C 程序正在使用的文件。即使您打开文件,您在程序中对文件所做的更改也不会出现,直到您对该文件调用 fflush()
或 fclose()
。
我用基本的 c 编写精简程序,为参数中传递的二进制文件中的每个字节添加(或减去)偏移量。这适用于所有其他 ELF,但是当我尝试 运行 :
$ ./a.out a.out 1
(每个字节加0x01),
fopen()
崩溃并显示错误消息 "Text file busy"。
我检查了 lsof
,但未在文件系统上打开。
我认为当一个可执行文件是 运行ning 时,文件的图像被加载到 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");
}
}
}
Unix 文件系统——用于 Unix、BSD、macOS、Linux 等的文件系统——依赖于 inodes。多个文件名可以引用同一个inode。
如果文件名被删除,但索引节点在一个或多个进程中仍然打开,则索引节点没有引用它的文件名。您仍然可以正常使用打开的文件——例如扩展它——但没有其他进程可以打开它(除非您以某种方式向它们提供打开的文件描述符)。
执行ELF二进制文件时,底层inode被内核锁定。注意:被锁定的是inode,不是文件名。
这是因为大多数系统不是将数据 "loading" 放入内存,而是简单地对数据进行内存映射。例如,在 Linux 中,这意味着无论您有多少个可执行文件或动态库副本 运行,RAM 中只存在一个二进制副本。
实际上,这意味着您不能在执行 ELF 二进制文件时对其进行修改。但是,您可以重命名甚至删除该文件,因为它是文件名所指的索引节点,而不是被内核锁定的文件名。 (当然,即使正在执行 ELF 二进制文件,您也可以很好地读取它们;您只需要确保以只读方式打开它们,因为以读写方式打开它们会失败。这是因为大多数 Unix 文件系统只检查访问权限在开放时间。)
您可以做的是创建一个新文件;写入修改后的数据;可选择复制所有者、组、模式、上次访问和上次修改时间戳,and/or 扩展属性 (xattrs);最后重命名或硬链接旧文件名上的新文件名。 (对现有文件进行重命名或硬链接只会更改现有文件名所指的 inode,因此不会违反 inode 锁定。)
这有一个额外的好处,即(旧二进制文件的)替换是原子的。无论其他进程何时打开或执行旧二进制文件,它们总是只会看到旧 inode 或新 inode,而不会看到某种中间版本。
您实际上无法以写入模式打开任何 C 程序正在使用的文件。即使您打开文件,您在程序中对文件所做的更改也不会出现,直到您对该文件调用 fflush()
或 fclose()
。