调试网络程序

来源:互联网 发布:广东网络干部学院 编辑:程序博客网 时间:2024/06/11 00:21

首现可以通过OllyDbg把程序的通讯过程进行一次分析,得到一些基础的数据,也大概能看出来逻辑流向。

这里使用了OllySocketTrace这个插件,引用

“The socket operations currently supported are: WSASocket, WSAAccept, WSAConnect, WSARecv, WSARecvFrom, WSASend, WSASendTo, WSAAsyncSelect, WSAEventSelect, WSACloseEvent, listen, ioctlsocket, connect, bind, accept, socket, closesocket, shutdown, recv, recvfrom, send and sendto.”

基本上常用的Socket都能够被记录下来,下载地址:http://bbs.pediy.com/showthread.php?t=71334

插件有打Log的功能,这里随便加载了程序能够看出大概的一些方式。


现在想要完成加密数据包还原,但是现在需要调试WSASend函数,虽然有思路但是细节实践起来还是挺麻烦的,这里先把前期的工作完成一下。

WSASend->WSPSend->NtDeviceIoControlFile->AFDSend(Tdi Client)->TcpSendData(Tdi Server)->TdiSend->TcpSend->IPTransmit(Network Layer)->SendIPPacket->下面进入链路层


数据流具体是怎么进行组装,逐层往下发,这个过程并不care。


对于这个部分不管HOOK哪个函数,最核心是要能抓住原始数据,根据协议,去修改对应的数据,至于后续是如何完成先不考虑,先通过调试来了解这个原始数据吧。

看了看wsock32.dll,ws2_32.dll都被调用到,这里根据OD的跟踪,主要调用了ws2_32.dll里面的WSARecv,WSARecvFrom,WSASend,WSASendTo。


01.int WSAAPI WSASend (  02.  SOCKET s,  03.  LPWSABUF lpBuffers,  04.  DWORD dwBufferCount,  05.  LPDWORD lpNumberOfBytesSent,  06.  int iFlags,  07.  LPWSAOVERLAPPED lpOverlapped,  08.  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine  09.  );  

s:标识一个已连接套接口的描述字。

lpBuffers:一个指向WSABUF结构数组的指针。每个WSABUF结构包含缓冲区的指针和缓冲区的大小。

dwBufferCount:lpBuffers数组中WSABUF结构的数目。

lpNumberOfBytesSent:如果发送操作立即完成,则为一个指向所发送数据字节数的指针。

iFlags:标志位。

lpOverlapped:指向WSAOVERLAPPED结构的指针(对于非重叠套接口则忽略)。

lpCompletionRoutine:一个指向发送操作完成后调用的完成例程的指针。(对于非重叠套接口则忽略)。


具体的内容,还要看动态调试时栈的内容了,现在看来都是各种push eXx,还要分析。但是第二个参数是很重要的内容,可以以此为重点,下内存断点,往上回溯。


一般游戏函数调用流程是这样的:

功能函数(打坐)->明文发包函数(明文包)->加密函数(密文包)->通讯函数(send等通讯函数发送密文包..)

通讯函数(recv等通讯函数收到密文包..)->解密函数(密文包)->解密明文包(解密后的明文包)


所以对于这部分的内容分析,会是一重点... 

但是抓住抓住明文,也得需要密钥,经过加密处理才能被服务器接收,这个地方又牵扯到,服务器动态下发密钥。

....都是烦人,烦心的东西,不过这里看到MJ的一段代码, 唉,只能膜拜,只能膜拜....


#include "windows.h"#include "winnt.h"PVOID pNtDeviceIoControl  = NULL ; #define AFD_RECV 0x12017#define AFD_SEND 0x1201ftypedef struct AFD_WSABUF{  UINT  len ;  PCHAR  buf ;}AFD_WSABUF , *PAFD_WSABUF;typedef struct AFD_INFO {  PAFD_WSABUF  BufferArray ;   ULONG  BufferCount ;   ULONG  AfdFlags ;  ULONG  TdiFlags ;} AFD_INFO,  *PAFD_INFO;typedef LONG NTSTATUS;#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)const CHAR GetXX[] = "GET ";const CHAR PostXX[] = "POST ";const CHAR HttpXX[] = "HTTP";////////////////////////////////////////////////////////////////////////////// LookupSendPacket// 检查Send包// 目前实现了过滤HTTP请求(GET AND POST)////////////////////////////////////////////////////////////////////////////BOOL LookupSendPacket(PVOID Buffer , ULONG Len){  if (Len < 5)  {    return FALSE ;   }  //外层已有异常捕获  if (memcmp(Buffer , GetXX , 4) == 0     ||    memcmp(Buffer , PostXX , 5) == 0 )  {    return TRUE ;   }  return FALSE ; }  ////////////////////////////////////////////////////////////////////////////// LookupRecvPacket//// 检查Recv包// 在这里可以实现Recv包查字典功能// 目前实现了过滤HTTP返回数据包的功能///////////////////////////////////////////////////////////////////////////////BOOL LookupRecvPacket(PVOID Buffer , ULONG Len){  if (Len < 4)  {    return FALSE ;   }  if (memcmp(Buffer , HttpXX , 4) == 0 )  {    return TRUE ;   }  return FALSE ; }////////////////////////////////////////////////////////////////////////////// NtDeviceIoControlFile的HOOK函数 // ws2_32.dll的send , recv最终会调用到mswsock.dll内的数据发送函数// mswsock.dll会调用NtDeviceIoControlFile向TDI Client驱动发送Send Recv指令// 我们在这里做拦截,可以过滤所有的TCP 收发包(UDP之类亦可,不过要更改指令)////////////////////////////////////////////////////////////////////////////NTSTATUS __stdcall NewNtDeviceIoControlFile(             HANDLE FileHandle,             HANDLE Event OPTIONAL,             PVOID ApcRoutine OPTIONAL,             PVOID ApcContext OPTIONAL,             PVOID IoStatusBlock,             ULONG IoControlCode,             PVOID InputBuffer OPTIONAL,             ULONG InputBufferLength,             PVOID OutputBuffer OPTIONAL,             ULONG OutputBufferLength    ){    //先调用原始函数  LONG stat ;   __asm  {    push  OutputBufferLength    push  OutputBuffer    push  InputBufferLength    push  InputBuffer     push  IoControlCode    push  IoStatusBlock     push  ApcContext    push  ApcRoutine    push  Event    push  FileHandle    call  pNtDeviceIoControl    mov    stat ,eax  }  //如果原始函数失败了(例如RECV无数据)  if (!NT_SUCCESS(stat))  {    return stat ;   }  //检查是否为TCP收发指令  if (IoControlCode != AFD_SEND && IoControlCode != AFD_RECV)  {    return stat ;   }  //访问AFD INFO结构,获得SEND或RECV的BUFFER信息  //这里可能是有问题的BUFFER,因此我们要加TRY EXCEPT  __try  {    //从InputBuffer得到Buffer和Len    PAFD_INFO AfdInfo = (PAFD_INFO)InputBuffer ;     PVOID Buffer = AfdInfo->BufferArray->buf ;     ULONG Len = AfdInfo->BufferArray->len;    if (IoControlCode == AFD_SEND)    {      if (LookupSendPacket(Buffer , Len))      {        //输出包内容        //这里输出调试信息,可以用DbgView查看,如果有UI可以做成SendMessage形式        OutputDebugString("SendPacket!\n");            OutputDebugString((char*)Buffer);      }    }    else    {      if (LookupRecvPacket(Buffer , Len))      {        OutputDebugString("RecvPacket!\n");        OutputDebugString((char*)Buffer);      }    }  }  __except(EXCEPTION_EXECUTE_HANDLER)  {    return stat ;   }  return stat ;   }//////////////////////////////////////////////////////////////////////////////  Hook mswsock.dll导出表的Ntdll!NtDeviceIoControlFile//  并过滤其对TDI Cilent的请求来过滤封包//  稳定,隐蔽,RING3下最底层的包过滤~////////////////////////////////////////////////////////////////////////////void SuperHookDeviceIoControl(){  //得到ws2_32.dll的模块基址  HMODULE hMod = LoadLibrary("mswsock.dll");  if (hMod == 0 )  {    return ;  }  //得到DOS头  PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod ;   //如果DOS头无效  if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)  {    return ;   }  //得到NT头  PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((ULONG)hMod + pDosHeader->e_lfanew);  //如果NT头无效  if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE)  {    return ;   }  //检查输入表数据目录是否存在  if (pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress == 0 ||    pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size == 0 )  {    return ;   }  //得到输入表描述指针  PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((ULONG)hMod + pNtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);  PIMAGE_THUNK_DATA ThunkData ;   //检查每个输入项  while(ImportDescriptor->FirstThunk)  {    //检查输入表项是否为ntdll.dll    char* dllname = (char*)((ULONG)hMod + ImportDescriptor->Name);        //如果不是,则跳到下一个处理    if (stricmp(dllname , "ntdll.dll") !=0)    {      ImportDescriptor ++ ;       continue;    }        ThunkData = (PIMAGE_THUNK_DATA)((ULONG)hMod + ImportDescriptor->OriginalFirstThunk);    int no = 1;    while(ThunkData->u1.Function)    {      //检查函数是否为NtDeviceIoControlFile      char* functionname = (char*)((ULONG)hMod + ThunkData->u1.AddressOfData + 2);      if (stricmp(functionname , "NtDeviceIoControlFile") == 0 )      {        //        //如果是,那么记录原始函数地址        //HOOK我们的函数地址        //        ULONG myaddr = (ULONG)NewNtDeviceIoControlFile;        ULONG btw ;         PDWORD lpAddr = (DWORD *)((ULONG)hMod + (DWORD)ImportDescriptor->FirstThunk) +(no-1);        pNtDeviceIoControl = (PVOID)(*(ULONG*)lpAddr) ;         WriteProcessMemory(GetCurrentProcess() , lpAddr , &myaddr , sizeof(ULONG), &btw );        return ;       }      no++;      ThunkData ++;    }    ImportDescriptor ++;  }  return ; }////////////////////////////////////////////////////////////////////////////// CheckProcess 检查是否是需要挂钩的进程//////////////////////////////////////////////////////////////////////////////BOOL CheckProcess(){  //在此加入你的进程过滤  return TRUE ;}BOOL APIENTRY DllMain( HANDLE hModule,                        DWORD  ul_reason_for_call,                        LPVOID lpReserved           ){  //当加载DLL时,进行API HOOK  if (ul_reason_for_call == DLL_PROCESS_ATTACH)  {      //检查是否是要过滤的进程    if (CheckProcess() == FALSE)    {        //如果不是,返回FALSE,将自身从进程中卸除      return FALSE ;     }    //HOOK API    SuperHookDeviceIoControl();  }    return TRUE;}


原创粉丝点击