【发布时间】:2019-04-03 05:14:57
【问题描述】:
我有一组输入,我想用它们来测试我的程序,看看哪些输入会遇到断点。我想创建一个脚本来一一测试这些输入,如果它遇到断点,打印或将结果保存到文件中。 请让我知道它是否可能,如果是,我该怎么做。谢谢。
【问题讨论】:
标签: linux debugging testing assembly gdb
我有一组输入,我想用它们来测试我的程序,看看哪些输入会遇到断点。我想创建一个脚本来一一测试这些输入,如果它遇到断点,打印或将结果保存到文件中。 请让我知道它是否可能,如果是,我该怎么做。谢谢。
【问题讨论】:
标签: linux debugging testing assembly gdb
我不确定我是否完全理解您的要求。但如果我理解正确,你想写一个程序:
我不知道这是否可以使用gdb,但可以编写自己的调试器:
fork和exec函数之一(如execlp)启动要测试的程序exec 函数调用之前ptrace(PTRACE_TRACEME,0,0,0)
waitpid;如果exec 成功,程序将立即停止。 waitpid 返回的“状态码”(第二个参数)将为 0x57F(假设是 x86 CPU)。waitpid 返回另一个退出代码,exec 失败,您无法继续。ptrace(PTRACE_PEEKTEXT,...) 和ptrace(PTRACE_POKETEXT,...) 修改程序:通过用“断点”指令替换该地址处的指令(在x86 CPU 上:int3,即字节@987654335 @)ptrace() 将0xCC 写入每个地址。
因为PTRACE_POKETEXT一次只能修改4个字节(x86_32)或8个字节(x86_64),你首先要使用PTRACE_PEEKTEXT读取这4个或8个字节的旧值,修改4个或8个字节中的1个并写入所有4 或 8 个字节。PTRACE_PEEKUSER):它应该是程序入口点的(实际)地址。 ptrace(PTRACE_CONT,pid,0,0)启动正在测试的程序waitpid等待程序停止或退出waitpid 返回 0x57F 作为“状态码”,则您处于断点中。您现在可以使用kill(pid, SIGKILL) 来停止您的程序。PTRACE_PEEKUSER 来检查程序计数器的值(x86-64 上的rip),以便知道哪个断点被命中。注意,程序计数器可能是断点的地址加1,所以如果0x12340000地址处的断点被命中,rip可能是0x12340001。waitpid返回低字节为0x7F的任何其他值,则程序引发异常。您应该使用kill(pid,SIGKILL) 最终阻止它。waitpid返回的低字节不是0x7F),程序已经结束,没有引发异常,也没有遇到任何断点。这里有一些示例代码:
int pid, code;
long tmpLong;
pid=fork();
if(!pid)
{
ptrace(PTRACE_TRACEME,0,0,0);
execlp("program_to_be_tested","program_to_be_tested",NULL);
exit(123);
}
waitpid(pid,&code,0);
if(code!=0x57F)
{
/* Starting the program failed ... */
}
else
{
/* Set breakpoints - here assuming x86-64 */
tmpLong=ptrace(PTRACE_PEEKDATA,pid,(void *)(address&~7),0);
((char *)&tmpLong)[address&7]=0xCC;
ptrace(PTRACE_POKEDATA,pid,(void *)(address&~7),(void *)tmpLong);
/* Continue the program */
ptrace(PTRACE_CONT,pid,0,0);
waitpid(pid,&code,0);
if((code&0xFF)!=0x7F)
{
/* Program did not hit a breakpoint
* and did not cause an exception */
}
else if(code==0x57F)
{
/* Breakpoint hit */
kill(pid,SIGKILL);
}
else
{
/* Program caused an exception */
kill(pid,SIGKILL);
}
}
要将输入传递给您的程序,您有两种可能的选择:
多次运行调试器:
echo "Input to be tested" | ./myDebugger
因为您的调试器不从 STDIN 读取,所以输入将被传递给要测试的程序。
创建子进程时使用pipe和dup2:
...
pipe(pipes);
pid=fork();
if(!pid)
{
dup2(pipes[0],0);
close(pipes[0]);
close(pipes[1]);
...
}
close(pipes[0]);
write(pipes[1],"Input to be sent to program", ...);
...
【讨论】: