调试网络程序
来源:互联网 发布:广东网络干部学院 编辑:程序博客网 时间: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;}
- 程序调试和网络调试
- 调试网络程序
- Android通过网络调试程序
- Android通过网络调试程序
- 工具软件:TCP网络调试程序(附源代码)
- Android 中用 tcpdump 调试网络程序
- 开发网络程序的调试方法
- 记录几个网络程序调试的命令
- 关于使用strace调试网络程序
- BlackBerry网络诊断程序,调试网络必备工具
- VS2005 无网络环境下调试mobile 程序
- 如何调试手机上使用WAP网络的程序
- android程序调试和访问网络进行下载
- main.box源码用网络盒子本地调试Asp程序
- gdb 调试网络程序发现connect 失败(interrupted system call)
- 网络调试
- 调试网络
- 调试程序
- 项目后的感想
- [C++]数据结构:跳表SkipList的实现与使用
- ArcGIS 10.1 for Desktop新特性 之 搜索
- linux c编程之UDP
- 导入导出用户数据
- 调试网络程序
- [汇编]产生随机数
- hdu 1505&1506&2870&2830
- ubuntu+eclipse+sdcc 搭建C51开发环境
- BIM(biologically inspired model)小结
- TFTP 配置和使用
- v4l2采集视频 framebuffer显示 左上角显示logo
- java经典算法_034打乱数据顺序
- How to detect Safari, Chrome, IE, Firefox and Opera browser?