最近仔细研究了一下linux调试程序的原理.gdb是linux下最为强大的调试工具,而strace可以拦截程序执行过程中的系统调用.他们的背后都隐藏了一个强悍的支持函数ptrace().调试程序过程中我们可以单步执行,逐步检查程序的输入输出,从而判断程序错误,当然我们也可以抛弃gdb,自己实现一个"外挂程序",拦截主程序中我们感兴趣的东西,比如ssh或ftp登录密码.
先看一个简单的程序:
#include<stdio.h>
int main(void){
char buf[1024];
gets(buf);
puts(buf);
return 0;
}
我们感兴趣的是他输入了什么,使用strace输出如下(部分):
fstat64(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77a9000
read(0, AAAAAAAAAAAA
"AAAAAAAAAAAA\n", 1024) = 13
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77a8000
write(1, "AAAAAAAAAAAA\n", 13AAAAAAAAAAAA
) = 13
exit_group(0) = ?
+++ exited with 0 +++
可以看到,在系统调用层面,程序使用了read函数实现了数据输入,所以"外挂"程序可以利用这一点,只针对read调用进行拦截:
/*
*该程序仅能在32位x86 linux中使用.64位系统需要修改struct user_regs_struct regs中寄存器格式.
*/
#include<stdio.h>
#include<sys/ptrace.h>
#include<unistd.h>
#include<sys/wait.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
#include<sys/syscall.h>
#include<sys/user.h>
#include<strings.h>
void getdata(pid_t pid,long addr, char *str,int len){
int i;
long data;
for(i=0;i<(len+sizeof(long)-1)/sizeof(long);i++){
data=ptrac