作者:迎风奔跑的狼 | 来源:互联网 | 2022-12-02 09:03
对于C语言中的实验学校,我们必须编写一个进程(我们将称之为A),需要连接到另一个进程(B)并在函数中放置一个陷阱(陷阱指令是0xCC),所以我们做了但是当B输入是这个函数时,我们有一个分段错误
所以这是附加到其他进程的进程A.
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[]) {
pid_t pidTargetProgram;
FILE *file;
int buf;
char path[50];
long long int address;
if (argc == 2) {
fprintf(stderr, "Argument waited !\n");
exit(1);
}
// The second argument is the PID of the program
pidTargetProgram = atoi(argv[1]);
// The third argument is the address of the function where we are going to put a trap
address = strtoll(argv[2], NULL, 16);
// We put the path to the file mem of the program
sprintf(path, "/proc/%s/mem", argv[1]);
// We attach to the other program
if(ptrace(PTRACE_ATTACH, pidTargetProgram, NULL, NULL) <0) {
perror("Error with ptrace_attach !");
exit(1);
}
// We wait it to be synchronize
if (waitpid(pidTargetProgram, NULL, WUNTRACED) <0) {
perror("Error with waitpid !\n");
exit(0);
}
// We open the file mem in read and write mode
if ((file = fopen(path, "r+")) == NULL) {
perror("Error during the opening of mem file from process !");
exit(1);
}
// We place our cursor on the address of the function
fseek(file, address, SEEK_SET);
char trap[] = {0xCC, 0x00, 0x00, 0x00};
// We put the trap in the foo function
if (fwrite(trap, 1, 5, file) <1) {
perror("Error to write !");
exit(1);
}
int counter = 0;
fseek(file, address, SEEK_SET);
// We print the other function's memory
while (fread(&buf, 4, 1, file) > 0) {
printf("Line n°%d : 0x%x\n", counter++, buf);
}
// We close the file
if (fclose(file) != 0) {
perror("Error during the closing !");
exit(1);
}
// We said to continue to the other program
if (ptrace(PTRACE_CONT, pidTargetProgram, NULL, NULL) <0) {
perror("Error during ptrace_cont !\n");
exit(1);
}
printf("continued !\n");
// We wait the other program stop
if (waitpid(pidTargetProgram, NULL, WUNTRACED) <0) {
perror("Error with waitpid !\n");
exit(0);
}
printf("Trace declenched !\n");
// We detach
if (ptrace(PTRACE_DETACH, pidTargetProgram, NULL, NULL) <0) {
perror("Error during ptrace_detach !");
exit(1);
}
printf("detach success ! \n");
return 0;
}
这是程序B:
#include
#include
#include
#include
// Function to execute to take the trap
void foo(){
int i = 0;
printf("foo :::: %d", i);
}
int main(int argc, char *argv[]) {
char text[10];
pid_t pidProgram;
// We get the PID
pidProgram = getpid();
// We print the PID
fprintf(stdout, "PID's program : %d\n", pidProgram);
// We print the address of foo()
fprintf(stdout, "foo address : %p\n", &(foo));
// We stop the program to lunch the other program
fgets(text, 10, stdin);
int i;
for(i = 0 ; i <100 ; i++){
foo(i);
}
return 0;
}
为了执行此操作,我们首先启动B,因此它为我们提供了PID和地址,并在fgets处暂停.所以在那之后,我们启动程序A,我们给它PID和地址,它停在第二个waitpid.之后我们继续B并写一些东西,我们有一个分段错误并停止.我们不明白为什么因为在内存中我们可以清楚地看到陷阱(0xCC)并且它不起作用但是在程序A中,我们有Trace declenched!分离成功!
因此A上没有错误但B有分段错误
你对此有什么想法吗?我们使用Centos作为操作系统.对不起我的英语不好.
谢谢
朱利安
1> Ctx..:
该计划按预期工作:
首先,将运行过程映像更改为0xcc
在函数开始时设置foo
,这会触发断点/陷阱.
然后,在进程跟踪进程时调用此函数a
.所以这个电话
waitpid(pidTargetProgram, NULL, WUNTRACED) <0) // Process a
回报.现在你从进程b中分离出来
ptrace(PTRACE_DETACH, pidTargetProgram, NULL, NULL);
但是,您之前没有恢复过程中的覆盖指令!因此,下一条指令已损坏并导致您观察到的段错误.此外,该过程在下一条指令PC + 1(直接在0xcc之后)重新启动,因此您需要使用一个字节将PC设置回一个字节PTRACE_GETREGS/PTRACE_SETREGS
顺便说一句.使用ptrace接口设置和重置断点指令PTRACE_POKETEXT
而不是使用/proc/pid/mem
方式更优雅.
TL; DR:您需要首先恢复原始指令并在重新启动进程b之前重置PC,然后它应该按预期工作.