调试模式
图形界面布局和OllyDBG很相似。
方法论。定位代码段还是不外两种方法:静态,动态。
1)静态
实现端口通信功能时有些基础函数会被调用,在定位接收数据的代码时可以对这些基础函数进行搜索,查看对应的调用代码,很多情况下都能直接定位到接收数据的代码段,有时即使无法一下就确定,也可以极大地缩小范围。 关键函数:
accept:从队列中接受一个连接,该函数会在就收数据之前调用,一般该函数到接收函数之间会进行一些初始化或限制ip等工作。
recv:一般是tcp链接中接收数据的函数。
recvfrom:一般是udp链接中接收数据的函数。
recvmsg:通用接收数据的函数。
read:有些时候也会用于接收链接中的数据流。
方法概述: 使用IDA加载程序文件,在Imports表中搜索recv,查看程序是否调用了recv、recvfrom或recvmsg函数,根据要分析的端口类型(tcp/udp)选择对应的接收函数,查看_recv函数的被调用地方,如果只有一处,那么很有可能就是对应的地方,如果有多处,那么可以查看调用之前对应的代码,查看监听的端口是否为对应的端口,不过在可以进行动态调试的情况下不推荐这么做。之后通过动态调试的方式进一步定位和确认是很方便的。
2)动态定位
方法概述: 通过静态定位端口通信的关键函数,并在对应函数在plt表中的位置下断点,之后向端口发送任意数据包,程序如果中断在接收函数出,则让程序执行到retrn处(快捷键Ctrl+F7),返回后的位置即是接收数据的代码段;如果没有中断,可能有两种情况,一是程序在对应端口接收数据时没有调用对应的函数,此时需要寻找其它函数下断点尝试,二是程序没有运行到接收数据的分支,这个原因可能是在accept之后对客户端ip地址进行了限制,此时可以在_accept处下断点,看函数是否会中断,分析中断的代码端分析什么原因导致没有进行接收。
实战 1)通过静态分析和动态调试相结合的方式定位tcp端口接收数据的代码段 使用IDA加载端口程序,在Imports页面搜索recv
因为是tcp端口,首先分析recv函数的调用情况。双击recv,查看recv的引用
双击进入,在got表中双击进入plt表中的_recv
查看_recv函数的调用关系
发现该程序总共有五处地方调用了_recv函数,很大的概率运行中的程序接收数据的代码段就在其中。为了进一步定位和确认,需要进行动态调试。 在_recv函数处下断点
将IDA附加到端口的进程上,F9继续运行
向对应端口发送任意数据包,观察程序是否暂停
可以看到程序暂停在_recv函数处,让程序执行到返回(快捷键Ctrl+F7),可以看到程序调用_recv函数的代码段
该位置即为程序实际接收数据的代码段 2)在accept函数之后限制客户端ip的tcp端口的程序 使用IDA加载端口程序文件,在Imports页面下搜索recv
只有一个recv函数,查看_recv函数的调用情况
只有两个调用,在_recv函数出下断点,让IDA调试器附加到端口的进程上,并向端口发送数据包
发现程序没有中断,表示程序没有运行到_recv的分支,取消_recv的断点,在_accept函数处下断点
再次向端口发送任意数据,发现程序中断在了_accept处,运行到返回处
分析对客户端ip地址的处理逻辑
从截图中可以看出,如果CPipdConfig::IsEnableLB()返回值为假时,客户端IP地址只能为127.0.0.1。经过调试可以发现进程运行是它的返回值为假,所以远程IP的链接都会被强制中断。 3)没有调用recv函数接收数据的tcp端口程序 使用IDA加载端口程序文件,在Imports页面下搜索recv
发现没有recv相关函数,而该程序又确实监听端口,这时只能猜测程序没有使用recv函数接收数据(或封装在其它库文件中进行调用,这种情况很少),搜索另一个基础函数accept
发现存在,然后查看_accept函数相关调用
可以看到,只有一个调用,基本可以确定这里是和客户端建立链接的开始,正向追踪_accept的返回值
在sub_4048C5函数中作为参数使用了_accept的返回值(sub_403306函数经过确认,函数内没有接收数据相关内容),进入sub_4048C5函数
发现使用read函数读取了套接字里面的数据,所以该处为接收端口数据的代码段。