gdb是支持脚本的,不过他支持的是命令序列。
网上的这样的文章也不多。我在这里就来个gdb脚本反反调试的实验。

实际上要实现起来也不是很难。ok!我们在原来的基础上多加几次反调试的语句。但并没有增加技术上难度。
我在这里体现的不是反调试的方法而只是如何利用shell script和gdb script 配合进行调试。学习进行中.....
首先还是给出被测试程序的源代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int get_name_by_pid(pid_t pid, char* name)
{
int fd;
char buf[1024] = {0};
snprintf(buf, 1024, "/proc/%d/cmdline", pid);
if ((fd = open(buf, O_RDONLY)) == -1)
return -1;
read(fd, buf, 1024);
strncpy(name, buf, 1023);
return 0;
}
int check_user()
{
char *password="123",user[5]="";
printf("password:");
scanf("%s",user);
if(!strcmp(password,user))
{printf("success!\n");return 0;}
else
{printf("Error!\n");return -1;}
}

int main(void)
{

char name[1024];
pid_t ppid = getppid();
if (get_name_by_pid(ppid, name))
return -1;

if (strcmp(name,"bash")==0||strcmp(name,"init")==0)
{
pid_t ppid = getppid();
if (get_name_by_pid(ppid, name))
return -1;
if (strcmp(name,"bash")==0||strcmp(name,"init")==0)
{
check_user();
}
else if (strcmp(name,"gdb")==0 || strcmp(name,"strace")==0 || strcmp(name,"ltrace") == 0)
printf("Traced!\n");
else
printf("Unknown! Maybe traced!\n");
}
else if (strcmp(name,"gdb")==0 || strcmp(name,"strace")==0 || strcmp(name,"ltrace") == 0)
printf("Traced!\n");
else
printf("Unknown! Maybe traced!\n");

return 0;
}


源码没有很大变化,只是在检测getppid次数上增加一次。用来说明GDB script的自动调试方法

gdb 的脚本的使用方法也很简单直接在gdb的命令行中输入source filename

脚本的内容

echo ----------welcome useing MyScript--------------\n
echo --------------Gdb Script ----------------------\n
echo -----------------------------------Beijihu-----\n
r
b getppid
commands
rep
end
define rep
next
shell echo `ps -A |grep "bash"` >./gdb.Temp
shell echo 'print $eax=arr' >./anti.temp
shell sed -i s@arr@`awk -F' ' '{ print $1}' ./gdb.Temp`@g ./anti.temp
source ./anti.temp
shell rm ./*.temp
c
end

详细解释一下具体命令的含义:
---------------------------------beijihu's split-line------------------------------------------------------
r #第一次运行。这个上次说为什么不知道这样做的原因大概是因为第一次运行需要加载器解决程序的共享函数库的重定向的问题
b getppid #在 getppid 函数调用下断
commands #定义 getppid 断点的调用命令序列
rep #自定义的命令
end
define rep #定义一个命令序列
next #步过,相当于OD的F8
shell echo `ps -A |grep "bash"` >./gdb.temp
#Shell 命令
shell echo 'print $eax=arr' >./anti.temp
#shell 命令临时 建立一个gbd script
shell sed -i s@arr@`awk -F' ' '{ print $1}' ./gdb.temp`@g ./anti.temp
#shell 命令 置换arr为bash的pid
source ./anti.temp
#执行临时建的gdb脚本。实际上就是一个 print $eax=pid
shell rm ./*.temp
#清理现场
c #继续运行
end #命令序列结束
---------------------------------beijihu's split-line------------------------------------------------------
脚本调用...
(gdb) source anti.gdb


运行脚本后以下输出

----------welcome useing MyScript--------------
--------------Gdb Script ----------------------
-----------------------------------Beijihu-----
(no debugging symbols found)
(no debugging symbols found)
(no debugging symbols found)
Traced!

Program exited normally.
Breakpoint 1 at 0xcc6880


(gdb) r

 

 

shell echo `ps -A |grep "bash"` >./gdb.temp
#Shell 命令
shell echo 'print $eax=arr' >./anti.temp
#shell 命令临时 建立一个gbd script
shell sed -i s@arr@`awk -F' ' '{ print $1}' ./gdb.temp`@g ./anti.temp
#shell 命令 置换arr为bash的pid

这里可以简化
shell echo print \$eax=`ps -A|grep bash|sed -n '1p'|awk '{print $1}'`>anti.temp

 

常用的gdb命令   

backtrace     显示程序中的当前位置和表示如何到达当前位置的栈跟踪(同义词:where)     
breakpoint     在程序中设置一个断点     
cd     改变当前工作目录   
clear     删除刚才停止处的断点     
commands     命中断点时,列出将要执行的命令     
continue     从断点开始继续执行     
delete     删除一个断点或监测点;也可与其他命令一起使用   
display     程序停止时显示变量和表达时     
down     下移栈帧,使得另一个函数成为当前函数     
frame     选择下一条continue命令的帧   
info     显示与该程序有关的各种信息     
jump     在源程序中的另一点开始运行   
kill   异常终止在gdb   控制下运行的程序   
list   列出相应于正在执行的程序的原文件内容   
next   执行下一个源程序行,从而执行其整体中的一个函数     
print   显示变量或表达式的值   
pwd   显示当前工作目录   
pype     显示一个数据结构(如一个结构或C++类)的内容   
quit   退出gdb     
reverse-search     在源文件中反向搜索正规表达式   
run   执行该程序     
search   在源文件中搜索正规表达式     
set   variable     给变量赋值     
signal     将一个信号发送到正在运行的进程     
step     执行下一个源程序行,必要时进入下一个函数   
undisplay   display   命令的反命令,不要显示表达式   
until     结束当前循环     
up     上移栈帧,使另一函数成为当前函数     
watch     在程序中设置一个监测点(即数据断点)   
whatis     显示变量或函数类型     

 

 

 

在使用gdb 调试 程序 的时候,有时候需要设定多个断点,重复执行某些操作,而这些操作写起来比较麻烦,这个时候就应该想起来用gdb命令 脚本了,它能够很好的完成这些工作。
以设置多个断点为例,我写的命令脚本为
---------------------------------------------------
#filename: .gdbinit
#gdb will read it when starting
file test_gdbscript
set args hello
b main
b foo
r
---------------------------------------------------
有两种方式来使用这个脚本: 
1)启动gdb时候
gdb在启动的时候,会在当前目录 下查找".gdbinit"这个文件 ,并把它的内容作为gdb命令进行解释,所以如果我把脚本命名为".gdbinit",这样在启动的时候就会处理这些命令。
2)gdb运行期间
可以使用 source script-file 来解释gdb命令脚本script-file

 

 

在.gdbinit里面设置了断点,但是如果这些断点在某些动态库里 ,gdb会报错:

Make breakpoint pending on future shared library load? (y or [n]) [answered N; input not from terminal ]

可以这样解决这个问题

"set breakpoint pending on" 

(gdb) help set breakpoint pending 
Set debugger's behavior regarding pending breakpoints. 
If on, an unrecognized breakpoint location will cause gdb to create a 
pending breakpoint. If off, an unrecognized breakpoint location results in 
an error. If auto, an unrecognized breakpoint location results in a 
user-query to see if a pending breakpoint should be created.