为什么编辑 .fini_array 不会改变程序的进程?
Why editing .fini_array doesn't change course of program?
我正在尝试查看 .fini_array
的编辑将如何导致程序流程发生变化,但似乎更改此条目不会导致任何变化。我的 main
是:
void cleanup() __attribute__((destructor));
int main() {
printf("In main\n");
exit(1);
}
void cleanup(){
printf("Cleanning Up\n");
}
void fini_exec(){
printf("FINI\n");
}
运行宁nm test
:000000000000119e T fini_exec
而 cleenup
: 0000000000001187 T cleanup
运行宁objdump -s -j .fini_array test
:
Contents of section .fini_array:
3db0 20110000 00000000 87110000 00000000 ...............
使用十六进制编辑器并转到我从 readelf
获得的 2db0
的字节,并在编辑 [=43= 后将 87110000
编辑为 9e110000
(印度语) ]再次objdump
Contents of section .fini_array:
3db0 20110000 00000000 9e110000 00000000 ...............
然后保存并重新 运行 仍然导致 cleanup
到 运行,我不知道为什么。 .fini_array
不应该是 运行 后跟 .fini
但似乎在其他地方还有另一个引用 cleanup
导致 fini_exec
不是 运行.
我分别用 void cleanup() __attribute__((destructor));
和 void fini_exec() __attribute__((destructor));
创建了两个单独的可执行文件 a.out.1 和 a.out.2:
#include <stdio.h>
#include <stdlib.h>
void cleanup() __attribute__((destructor));
//void fini_exec() __attribute__((destructor));
int main() {
printf("In main\n");
exit(1);
}
void cleanup(){
printf("Cleanning Up\n");
}
void fini_exec(){
printf("FINI\n");
}
我生成了十六进制转储:
$ hexdump a.out.1 > a.out.1.hex
$ hexdump a.out.2 > a.out.2.hex
我比较了十六进制转储,可以看到标记为析构函数的函数的偏移量(0x119e 和 0x1187)出现在 2 个地方(偏移量 0x580 和 0x2db8):
$ diff a.out.1.hex a.out.2.hex
55,56c55,56
< 0000360 0003 0000 4e47 0055 5b7f a631 6798 4fc1
< 0000370 d865 85fc 1cc6 c187 eaab 06ab 0004 0000
---
> 0000360 0003 0000 4e47 0055 4bec d49a 80fc b24e
> 0000370 0d44 2dd5 81c9 82cb fe22 f498 0004 0000
89c89
< 0000580 119e 0000 0000 0000 4008 0000 0000 0000
---
> 0000580 1187 0000 0000 0000 4008 0000 0000 0000
173c173
< 0002db0 1120 0000 0000 0000 119e 0000 0000 0000
---
> 0002db0 1120 0000 0000 0000 1187 0000 0000 0000
所以,我写了一个简单的修补程序工具,它将一个可执行文件名称和一组偏移量作为参数,用于修补字节(即打开(可执行文件)、lseek(偏移量)、写入(字节)、关闭(可执行文件) ):
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int ac, char *av[])
{
int fd;
char *fname = av[1];
unsigned char byte;
int offset;
int i;
int rc;
if (!fname) {
fprintf(stderr, "Usage: %s {offseth byteh...}\n", av[0]);
return 1;
}
fd = open(fname, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open(%s): '%m' (%d)\n", fname, errno);
return 1;
}
i = 2;
while (av[i] && av[i + 1]) {
offset = strtol(av[i], NULL, 0);
byte = strtol(av[i + 1], NULL, 0);
printf("Patching @0x%x: 0x%02x\n", offset, byte);
rc = lseek(fd, offset, SEEK_SET);
if (rc != offset) {
fprintf(stderr, "lseek(%s): '%m' (%d)\n", fname, errno);
return 1;
}
rc = write(fd, &byte, 1);
if (rc != 1) {
fprintf(stderr, "write(%s): '%m' (%d)\n", fname, errno);
return 1;
}
i += 2;
} // End while
close(fd);
return 0;
} // main
当我用它修补两个地方时,析构函数被更改并按预期工作:
$ gcc patch.c -o patch
$ patch ./a.out.1 0x580 0x87 0x2db8 0x87 # cleanup()'s offset (0x1187)
Patching @0x580: 0x87
Patching @0x2db8: 0x87
$ ./a.out.1
In main
Cleanning Up
$ ./patch ./a.out.1 0x580 0x9e 0x2db8 0x9e # fini_exec()'s offset (0x119e)
Patching @0x580: 0x9e
Patching @0x2db8: 0x9e
$ ./a.out.1
In main
FINI
我正在尝试查看 .fini_array
的编辑将如何导致程序流程发生变化,但似乎更改此条目不会导致任何变化。我的 main
是:
void cleanup() __attribute__((destructor));
int main() {
printf("In main\n");
exit(1);
}
void cleanup(){
printf("Cleanning Up\n");
}
void fini_exec(){
printf("FINI\n");
}
运行宁nm test
:000000000000119e T fini_exec
而 cleenup
: 0000000000001187 T cleanup
运行宁objdump -s -j .fini_array test
:
Contents of section .fini_array:
3db0 20110000 00000000 87110000 00000000 ...............
使用十六进制编辑器并转到我从 readelf
获得的 2db0
的字节,并在编辑 [=43= 后将 87110000
编辑为 9e110000
(印度语) ]再次objdump
Contents of section .fini_array:
3db0 20110000 00000000 9e110000 00000000 ...............
然后保存并重新 运行 仍然导致 cleanup
到 运行,我不知道为什么。 .fini_array
不应该是 运行 后跟 .fini
但似乎在其他地方还有另一个引用 cleanup
导致 fini_exec
不是 运行.
我分别用 void cleanup() __attribute__((destructor));
和 void fini_exec() __attribute__((destructor));
创建了两个单独的可执行文件 a.out.1 和 a.out.2:
#include <stdio.h>
#include <stdlib.h>
void cleanup() __attribute__((destructor));
//void fini_exec() __attribute__((destructor));
int main() {
printf("In main\n");
exit(1);
}
void cleanup(){
printf("Cleanning Up\n");
}
void fini_exec(){
printf("FINI\n");
}
我生成了十六进制转储:
$ hexdump a.out.1 > a.out.1.hex
$ hexdump a.out.2 > a.out.2.hex
我比较了十六进制转储,可以看到标记为析构函数的函数的偏移量(0x119e 和 0x1187)出现在 2 个地方(偏移量 0x580 和 0x2db8):
$ diff a.out.1.hex a.out.2.hex
55,56c55,56
< 0000360 0003 0000 4e47 0055 5b7f a631 6798 4fc1
< 0000370 d865 85fc 1cc6 c187 eaab 06ab 0004 0000
---
> 0000360 0003 0000 4e47 0055 4bec d49a 80fc b24e
> 0000370 0d44 2dd5 81c9 82cb fe22 f498 0004 0000
89c89
< 0000580 119e 0000 0000 0000 4008 0000 0000 0000
---
> 0000580 1187 0000 0000 0000 4008 0000 0000 0000
173c173
< 0002db0 1120 0000 0000 0000 119e 0000 0000 0000
---
> 0002db0 1120 0000 0000 0000 1187 0000 0000 0000
所以,我写了一个简单的修补程序工具,它将一个可执行文件名称和一组偏移量作为参数,用于修补字节(即打开(可执行文件)、lseek(偏移量)、写入(字节)、关闭(可执行文件) ):
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int ac, char *av[])
{
int fd;
char *fname = av[1];
unsigned char byte;
int offset;
int i;
int rc;
if (!fname) {
fprintf(stderr, "Usage: %s {offseth byteh...}\n", av[0]);
return 1;
}
fd = open(fname, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open(%s): '%m' (%d)\n", fname, errno);
return 1;
}
i = 2;
while (av[i] && av[i + 1]) {
offset = strtol(av[i], NULL, 0);
byte = strtol(av[i + 1], NULL, 0);
printf("Patching @0x%x: 0x%02x\n", offset, byte);
rc = lseek(fd, offset, SEEK_SET);
if (rc != offset) {
fprintf(stderr, "lseek(%s): '%m' (%d)\n", fname, errno);
return 1;
}
rc = write(fd, &byte, 1);
if (rc != 1) {
fprintf(stderr, "write(%s): '%m' (%d)\n", fname, errno);
return 1;
}
i += 2;
} // End while
close(fd);
return 0;
} // main
当我用它修补两个地方时,析构函数被更改并按预期工作:
$ gcc patch.c -o patch
$ patch ./a.out.1 0x580 0x87 0x2db8 0x87 # cleanup()'s offset (0x1187)
Patching @0x580: 0x87
Patching @0x2db8: 0x87
$ ./a.out.1
In main
Cleanning Up
$ ./patch ./a.out.1 0x580 0x9e 0x2db8 0x9e # fini_exec()'s offset (0x119e)
Patching @0x580: 0x9e
Patching @0x2db8: 0x9e
$ ./a.out.1
In main
FINI