使用Pin监控,解析connect()系统调用获取服务器端IP

使用Pin监控,解析connect()系统调用获取服务器端IP

connect()函数:

#include <sys/types.h>    
#include <sys/socket.h>

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

connect()函数通常用于客户端建立tcp连接。
参数列表:
sockfd:指定数据发送的套接字。
serv_addr:指定数据发送的目的地,包括套接字sockfd想要连接的主机地址和端口号。
addrlen:指定serv_addr结构体的长度。
返回值:
成功则返回0,失败返回-1,错误原因存于errno中。

既然serv_addr中存放了服务器端的IP地址,所以我们要从客户端获取服务器端的IP地址,只要得到connect()函数的addr参数就可以了。

struct sockaddr *addr:

struct sockaddr {
    unsigned  short  sa_family;     /* address family, AF_xxx */
    char  sa_data[14];              /* 14 bytes of protocol address */
};

sa_family是地址家族,一般都是“AF_xxx”的形式。好像通常大多用的是都是AF_INET。
sa_data是14字节协议地址。
此数据结构用做bind、connect、recvfrom、sendto等函数的参数,指明地址信息。

但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构

struct  sockaddr_in {
    short  int  sin_family;               /* Address family */
    unsigned  short  int  sin_port;       /* Port number */
    struct  in_addr  sin_addr;            /* Internet address */
    unsigned  char  sin_zero[8];          /* Same size as struct sockaddr */
};

struct  in_addr {
    unsigned  long  s_addr;
};

sockaddr_in和sockaddr是并列的结构,指向sockaddr_in的结构体的指针也可以指向sockadd的结构体,并代替它。也就是说,我们可以使用sockaddr_in建立所需要的信息,在最后用进行类型转换就可以了。

我们要的IP地址就在s_addr中。


在Pin中获取IP地址

查看unistd_64.h得到connect()的系统调用号为42,所以使用Pin监控Client端的运行,并筛选出42号系统调用。结果如下:

0x7ff9a794561e: 42(0x4, 0x7fff1466d780, 0x10, 0x0, 0x0, 0x4)returns: 0x0

这个就是我们要得到的connect()系统调用的相关信息。显然第二个参数是serv_addr结构体的内存地址,所以我们现在要做的是从这块内存中提取出IP地址,即serv_addr的第三个成员变量值sin_addr。sin_addr也是一个in_addr类型的结构体,所以最终要拿到的数据还是unsigned long s_addr

获得s_addr有两种方法:

  • 直接用内存操作
    这是我最开始想到的方法,主要思路是既然有了内存地址,那么就可以根据结构体的定义来计算成员变量的偏移量,然后直接将内存数据取出。

    这种方法不但麻烦,而且有一个致命的问题,那就是数据对齐。许多计算机系统对基本数据类型合法地址做出了一些限制,要求某种类型对象的地址必须是某个K(2、4或8)值的倍数。不一样的操作系统(比如Linux和Windows)的强制对齐规则是不一样的,对于结构体类型我们直接计算变量的偏移很有可能会得到错误的值。关于数据对齐的知识在《深入理解计算机系统》一书中有详细的介绍。

  • 使用指针访问
    既然知道了结构体的内存地址,那我可以在程序中声明一个sockaddr_in结构体变量,然后将内存地址进行强制类型转换赋给该变量,这样就可以通过直接访问该结构体变量来访问成员变量,而不需要进行直接的内存操作了。
    最后要使用inet_ntoa()函数将in_addr类型的IP地址转换为点分十进制,并打印出来。
    代码如下:

if(num == 42)
    {
        fprintf(trace,"0x%lx: %ld(0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx)",
             (unsigned long)ip,
             (long)num,
             (unsigned long)arg0,
             (unsigned long)arg1,
             (unsigned long)arg2,
             (unsigned long)arg3,
             (unsigned long)arg4,
             (unsigned long)arg5);

        struct sockaddr_in addr;
        addr =  *((sockaddr_in *)arg1);
        fprintf(trace,"\nIP:%s\n",inet_ntoa(addr.sin_addr));
    }
}

结果如下:

0x7fca80ee061e: 42(0x4, 0x7fffeb46b2c0, 0x10, 0x0, 0x0, 0x4)
IP:127.0.0.1
returns: 0x0
一款改自IPHookIP数据包监控过滤程序 By ccc 2009-6-13 完成(ch2zh1@tom.com) IP包过滤程序采用IPHook驱动器程序,在内核层用钩子回调函数(IpHookFilter)勾住系统自带的IP过滤驱动器(System32\Drivers\IpFltDrv.sys),从而返回过滤驱动器传输的所有IP包数据。可以通过回调函数的返回值(PF_DROP、PF_FORWARD、PF_PASS),指示滤波驱动器对包的处理,是抛弃还是通过。 应用启动驱动器过程可以使用驱动器的安装,或使用系统的服务控制器(ServiceControl)直接启动和停止驱动程序。 服务控制器利用OpenSCManager等服务控制函数控制驱动程序的加载与卸载。这就使得应用程序可以在运行时自动加载和卸载需要的驱动程序。而不必设置驱动程序的安装过程。 初始的IPHook.sys只提供了IP包的监视过程即,仅仅返回IP头信息。在应用中解释并显示这个头信息。经过写改的IPHook增加了对IP包的过滤处理,有几个设置命令: START_IP_HOOK :启动钩子过滤命令,建立连接IP滤波器的回调函数(原始命令) STOP_IP_HOOK :停止钩子过滤命令,撤销IP滤波器回调函数(原始命令) ADD_IP_HOOKADDR :添加过滤IP地址,回调函数判断IP包,以决定是放弃还是通过(新命令) DEL_IP_HOOKADDR :删除过滤IP地址(新命令) ADD_IP_HOOKPORT :添加过滤端口号(新命令) DEL_IP_HOOKPORT :删除过滤端口号(新命令) ADD_IP_OVER_HOOK :添加置换的IP地址,用于对指定目的的IP包置换源地址和端口号(New) DEL_IP_OVER_HOOKIP地址置换。(New) 应用程序可一次设置和删除对个滤波地址和端口号。对于重复设置,IPHook可以正确识别并加以剔除。这是一个演示程序主要想说明windows2000驱动程序编程过程,及应用自动加载和卸载驱动的方式。 驱动程序的源码在DrvChecked.rar中,要想正确编译,必须安装windows2000 DDK,并在VS2003下设置包含目录指向DDK的目录,库目录也要指向DDK的库目录: C:\NTDDK\inc C:\NTDDK\inc\ddk C:\NTDDK\libchk\i386 并且在排列上一定要排在头两个位置上。 这个驱动程序在VC++下是可以正确编译通过的。驱动程序名:DrvChecked.sys。使用时应该改为:iphook.sys。delphi下的应用程序为:IPPacketMonitor.exe,它使用IPHook.sys。 任何人可以自己编译和修改这个驱动程序,使之能够按照一定的方式运行,这里给出的只是本人的一个想法,希望能给各位带来一点帮助。任何应用程序都可以想打开文件一样使用这个驱动程序,关于使用方法请参考Release Notes.htm提供的线索。 有什么问题和建议请电邮:ch2zh1@tom.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值