Mac OS (10.13.1) task_for_pid for forked process "(os/kern) failure"
Mac OS (10.13.1) task_for_pid for forked process "(os/kern) failure"
上次我尝试编写简单的基因模糊器(严格使用 Mac OS,只是为了好玩)。我的想法是这样的:
-> 控制分叉进程的主程序
--> 分叉进程从磁盘加载二进制代码并跳入其中。
-> 父请求任务 (task_for_pid(mach_task_self(),childPID,&task))
-> parent try catch traps (0xcc), 检查我们之前是否去过那里,就像 AFL 工作一样(当然是简化)
--> 子加载一些原始二进制代码(在我的示例中必须是 System V ABI)
我得到如下错误:
16:10|domin568[15] ~/Desktop/experiments/Instrumentation $ ./run.sh
PARENT 3866
task_for_pid() failed with message (os/kern) failure !
CHILD 3867
run.sh :
#!/bin/sh
clang -sectcreate __TEXT __info_plist Info.plist -o server server.c
codesign -s instrument ./server
./server
"instrument" 出现在我的钥匙链上,并且 Always Trust 用于代码唱歌,所以我认为不应该是这种情况。
Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SecTaskAccess</key>
<array>
<string>allowed</string>
<string>debug</string>
</array>
</dict>
</plist>
当然我的代码只对特定情况有用,它试图模糊一个输入为字符串的函数并将其与其他字符串进行比较。
server.c :
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <mach/mach.h>
#include <stdlib.h>
int main (int argc,char ** argv)
{
pid_t pid = fork();
pid_t parentPID, childPID; //maybe it's not really safe, nevermind
int status;
if (pid == 0)
{
printf ("CHILD %i\n",getpid());
childPID = getpid();
FILE * f = fopen(argv[1],"rb");
if (f == NULL)
{
return -2;
puts ("Cannot open file specified\n");
}
int from,to = 0;
sscanf(argv[2],"%x",&from);
sscanf(argv[3],"%x",&to);
if (from >= to)
{
puts ("R u out of your mind ? check your range of bytes within the file... \n");
return -3;
}
int fileSize = to - from;
void * mem = mmap (NULL,fileSize,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE,fileno(f),0);
if (mem == MAP_FAILED)
{
puts ("[!] Cannot allocate memory for file");
return -4;
}
printf ("[-] File mapped to virtual memory : [%p]\n",mem);
int (*pFunc)(char * str) = (int(*)(char *))(mem+from);
int ret = pFunc("AAAAA");
printf ("Returned : %d\n",ret);
}
else
{
printf ("PARENT %i\n",getpid());
parentPID = getpid();
kern_return_t kret;
mach_port_t task;
mach_port_t target_exception_port;
kret = task_for_pid (mach_task_self(),childPID,&task);
if (kret != KERN_SUCCESS)
{
printf ("task_for_pid() failed with message %s !\n",mach_error_string(kret));
sleep(100000);
}
//save the set of exception ports registered in the process
exception_mask_t saved_masks[EXC_TYPES_COUNT];
mach_port_t saved_ports[EXC_TYPES_COUNT];
exception_behavior_t saved_behaviors[EXC_TYPES_COUNT];
thread_state_flavor_t saved_flavors[EXC_TYPES_COUNT];
mach_msg_type_number_t saved_exception_types_count;
task_get_exception_ports(task,
EXC_MASK_ALL,
saved_masks,
&saved_exception_types_count,
saved_ports,
saved_behaviors,
saved_flavors);
//allocate and authorize a new port
mach_port_allocate(mach_task_self(),
MACH_PORT_RIGHT_RECEIVE,
&task);
mach_port_insert_right(mach_task_self(),
target_exception_port,
target_exception_port,
MACH_MSG_TYPE_MAKE_SEND);
//register the exception port with the target process
task_set_exception_ports(task,
EXC_MASK_ALL,
target_exception_port,
EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
THREAD_STATE_NONE);
ptrace (PT_ATTACHEXC, childPID,0,0);
}
return 0;
}
为什么会输出错误?这是 fork 在 OSX 下如何工作的情况吗?那里有什么问题?我不是 osx 如何在底层工作的专家,所以也许我错过了一些东西。感谢您的帮助:) !
多米尼克
您调用 pid_t pid = fork();
因此父进程中子进程的 PID 存储在 pid
变量中而不是 childPID
中。
childPID
变量仅根据您的示例代码在子进程中初始化。
task_for_pid()
调用正在使用 childPID
- 基本上您使用的是未初始化的内存。
除了使用未初始化pid
的另一个答案中提到的问题外,看起来你没有将文件作为输入参数传递,是什么导致子进程立即终止并成为僵尸(因为parent 不等待它的 pid)并且你不能执行 task_for_pid
终止进程(即使它仍然在进程 table 中列出)
基本上,您需要更仔细地在父子之间进行同步,但是作为第一步,为了查明问题,我建议在检查文件是否正确打开之前放置sleep
,即应解决 task_for_pid 中的错误。
上次我尝试编写简单的基因模糊器(严格使用 Mac OS,只是为了好玩)。我的想法是这样的:
-> 控制分叉进程的主程序
--> 分叉进程从磁盘加载二进制代码并跳入其中。
-> 父请求任务 (task_for_pid(mach_task_self(),childPID,&task))
-> parent try catch traps (0xcc), 检查我们之前是否去过那里,就像 AFL 工作一样(当然是简化)
--> 子加载一些原始二进制代码(在我的示例中必须是 System V ABI)
我得到如下错误:
16:10|domin568[15] ~/Desktop/experiments/Instrumentation $ ./run.sh
PARENT 3866
task_for_pid() failed with message (os/kern) failure !
CHILD 3867
run.sh :
#!/bin/sh
clang -sectcreate __TEXT __info_plist Info.plist -o server server.c
codesign -s instrument ./server
./server
"instrument" 出现在我的钥匙链上,并且 Always Trust 用于代码唱歌,所以我认为不应该是这种情况。
Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SecTaskAccess</key>
<array>
<string>allowed</string>
<string>debug</string>
</array>
</dict>
</plist>
当然我的代码只对特定情况有用,它试图模糊一个输入为字符串的函数并将其与其他字符串进行比较。
server.c :
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <mach/mach.h>
#include <stdlib.h>
int main (int argc,char ** argv)
{
pid_t pid = fork();
pid_t parentPID, childPID; //maybe it's not really safe, nevermind
int status;
if (pid == 0)
{
printf ("CHILD %i\n",getpid());
childPID = getpid();
FILE * f = fopen(argv[1],"rb");
if (f == NULL)
{
return -2;
puts ("Cannot open file specified\n");
}
int from,to = 0;
sscanf(argv[2],"%x",&from);
sscanf(argv[3],"%x",&to);
if (from >= to)
{
puts ("R u out of your mind ? check your range of bytes within the file... \n");
return -3;
}
int fileSize = to - from;
void * mem = mmap (NULL,fileSize,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE,fileno(f),0);
if (mem == MAP_FAILED)
{
puts ("[!] Cannot allocate memory for file");
return -4;
}
printf ("[-] File mapped to virtual memory : [%p]\n",mem);
int (*pFunc)(char * str) = (int(*)(char *))(mem+from);
int ret = pFunc("AAAAA");
printf ("Returned : %d\n",ret);
}
else
{
printf ("PARENT %i\n",getpid());
parentPID = getpid();
kern_return_t kret;
mach_port_t task;
mach_port_t target_exception_port;
kret = task_for_pid (mach_task_self(),childPID,&task);
if (kret != KERN_SUCCESS)
{
printf ("task_for_pid() failed with message %s !\n",mach_error_string(kret));
sleep(100000);
}
//save the set of exception ports registered in the process
exception_mask_t saved_masks[EXC_TYPES_COUNT];
mach_port_t saved_ports[EXC_TYPES_COUNT];
exception_behavior_t saved_behaviors[EXC_TYPES_COUNT];
thread_state_flavor_t saved_flavors[EXC_TYPES_COUNT];
mach_msg_type_number_t saved_exception_types_count;
task_get_exception_ports(task,
EXC_MASK_ALL,
saved_masks,
&saved_exception_types_count,
saved_ports,
saved_behaviors,
saved_flavors);
//allocate and authorize a new port
mach_port_allocate(mach_task_self(),
MACH_PORT_RIGHT_RECEIVE,
&task);
mach_port_insert_right(mach_task_self(),
target_exception_port,
target_exception_port,
MACH_MSG_TYPE_MAKE_SEND);
//register the exception port with the target process
task_set_exception_ports(task,
EXC_MASK_ALL,
target_exception_port,
EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
THREAD_STATE_NONE);
ptrace (PT_ATTACHEXC, childPID,0,0);
}
return 0;
}
为什么会输出错误?这是 fork 在 OSX 下如何工作的情况吗?那里有什么问题?我不是 osx 如何在底层工作的专家,所以也许我错过了一些东西。感谢您的帮助:) !
多米尼克
您调用 pid_t pid = fork();
因此父进程中子进程的 PID 存储在 pid
变量中而不是 childPID
中。
childPID
变量仅根据您的示例代码在子进程中初始化。
task_for_pid()
调用正在使用 childPID
- 基本上您使用的是未初始化的内存。
除了使用未初始化pid
的另一个答案中提到的问题外,看起来你没有将文件作为输入参数传递,是什么导致子进程立即终止并成为僵尸(因为parent 不等待它的 pid)并且你不能执行 task_for_pid
终止进程(即使它仍然在进程 table 中列出)
基本上,您需要更仔细地在父子之间进行同步,但是作为第一步,为了查明问题,我建议在检查文件是否正确打开之前放置sleep
,即应解决 task_for_pid 中的错误。