首页
社区
课程
招聘
[原创]IPPack封包拦截工具源代码简单分析
发表于: 2013-5-1 15:13 24660

[原创]IPPack封包拦截工具源代码简单分析

2013-5-1 15:13
24660

        一个IPPack封包截获工具,书上讲的太简单,干脆心一横自己慢慢分析,在我看来这个程序还是有点复杂的,今天总算是了解了它的大致流程。。。
        怕自己以后给忘了,所以写下来分析的过程同时也可以加深自己对这个程序的理解,肯定有很多错误的地方,大神勿喷。。。

        此工具分两部分,一部分为exe,一部分为dll

        第一部分动作有初始化全局变量、界面及其按钮的动作,注入以及卸载dll还有接收数据等工作

        首先,要解决有全局dll发送的消息的接收问题,可以自定义消息映射,当dll发送某类型消息时触发什么事件

这是自定义的消息处理函数
  // 处理DLL发送过来的HM_RECEIVE和HM_SEND消息
  afx_msg long OnReceive(WPARAM wParam, LPARAM lParam);
  afx_msg long OnSend(WPARAM wParam, LPARAM lParam);
  他们添加在
  //{{AFX_MSG(CSDlg)
  //}}AFX_MSG
        这中间,这是ms定义的宏注释,MFC中有一种特殊的注释,叫注释宏。注释宏一般由VC自动加入到你的代码中。它是为class wizard服务的,class wizard通过它来定位各种系统自动添加代码的添加位置。若要使用类向导添加成员变量和成员函数,则要保留注释宏;否则,必须手动添加。如果你把它删了,classwizad就不能自动生成代码了 。 你添加消息响应的时候是不是发现源代码里多了些代码??那些代码为什么会在那里出现?为什么不在别的文件里出现?就是因为那里有注释宏它要将代码生成在相应注释宏之间 。 (这个注释是让ClassWizard能够分辨出哪些代码是它生成的,哪些是你自己写的。你自己写的代码要在这个注释之外,这样ClassWizard再修改消息映射的时候就不会管你的代码了。新版本vc(vs)已经没有注释宏了。)

        然后在消息映射表中添加dll发送消息过来时有什么函数进行处理

    映射表象添加在
BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
END_MESSAGE_MAP()之间

// 两个自定义消息
ON_MESSAGE(HM_RECEIVE, OnReceive)
ON_MESSAGE(HM_SEND, OnSend)

这样,当有dll消息过来时就会触发自定义的消息了,这样,之定义消息处理就解决了

下面就是这个程序真正的动作了。。。。

     首先设置状态栏、初始化列表框以及注册热键

  // 创建状态栏,设置它的属性(CStatusBarCtrl类封装了对状态栏控件的操作)
  m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, CRect(0, 0, 0, 0), this, 101);
  m_bar.SetBkColor(RGB(0xa6, 0xca, 0xf0));    // 背景色
  int arWidth[] = { 250, -1 };
  m_bar.SetParts(2, arWidth);        // 分栏
  m_bar.SetText(" Windows程序设计进阶之路!", 1, 0);  // 第二个栏的文本

  // 取得列表视图窗口的控制权,设置它的分栏
  m_listData.SubclassWindow(::GetDlgItem(m_hWnd, IDC_LISTDATA));
  m_listData.SetExtendedStyle(LVS_EX_FULLROWSELECT);
  m_listData.InsertColumn(0, "编号", LVCFMT_LEFT, 38);
  m_listData.InsertColumn(2, "类型", LVCFMT_LEFT, 80);
  m_listData.InsertColumn(3, "数据", LVCFMT_LEFT, 180);

  // 注册热键CTRL+F9。当用户按此热键时,主窗口显示或者隐藏
  if(!::RegisterHotKey(m_hWnd, 11, MOD_CONTROL, VK_F9))
  {
    MessageBox("注册热键CTRL+F9失败!");
  }
  
然后就开始初始化状态数据及更新界面

  // 初始化状态数据
  InitData();
  // 更新用户界面
  UIControl();
  
整个app的初始化就到此结束了。下面为各个按钮的动作函数

1.打开进程列表并选择一个进程进行远程dll注入

  首先判断m_bOpen是否为真,如果是,则已经安装了钩子,要先卸载SetHook(FALSE);,然后初始化其状态InitData();

  然后进行注入SetHook(TRUE, dlg.m_dwThreadId, m_hWnd),传入【用户选择的进程】的线程以及进程句柄
  
2.dll注入阶段

  此函数为dll的导出函数,这里采用的动态加载方式
  GetModuleHandle(szDll)--->>LoadLibrary(szDll)---->>PFNSETHOOK mSetHook = GetProcAddress(hModule, "SetHook")
  使用sethook函数注入mSetHook(bInstall, dwThreadId, hWndCaller);
  这时程序已经跳到dll里面去执行了,现在我们不分析dll,且看app里面各个控件的功能
  
3.接收dll发送的数据

  接收目标程序接收或发送的封包并显示
  dll只是发送触发消息让app去读取共享数据内存
  OnReceive(WPARAM wParam, LPARAM lParam)
  OnSend(WPARAM wParam, LPARAM lParam)
  着这里检查用户是否暂停,然后显示获取的数据IsDlgButtonChecked()
  这里只显示一部分,将完整的数据保存到共享数据段,当用户单击此项再读取并显示完整消息
  显示发送的封包是同上

4.当用户单击列表框某项是触发OnClickListData()
  显示完整封包信息

5.OnClear()清除列表框

6.OnCancel()  OnClose()  

7.OnPause()    OnTopMost()

8.打开进程列表框时先遍历系统内进程并建立索引,用户点击某一项是返回此进程索引,并每隔一段时间刷新此列表

9.另外两个文件是共享数据段类的定义

第二部分为dll过程解析,上面分析到app执行到dll中的sethook函数,那么,就从这里下手吧
  这个函数到底干了什么能让注入dll到目标进程呢?
  首先函数获取目标进程的进程以及主线程句柄,并将主进程句柄保存到共享数据段中
  然后函数在目标线程内安装一个钩子SetWindowsHookEx,回调函数为GetMsgProc,如果此时bInstall为false则卸载钩子UnhookWindowsHookEx
  注意,此时程序任然是在app的进程地址空间,并没有进入目标进程
  
        安装钩子后当目标进程调用WH_GETMESSAGE消息时就会触发钩子,windows此时将dll注入到目标进程并在目标进程中调用回调函数GetMsgProc

        此时,目标进程就真正进入了我们的dll的代码上去了,也就是说dll获得了此进程的执行权限
但是,在回调函数中通常我们什么都不去做,仅仅将消息传递到钩子链中的下一个节点

问题是此时dll真的什么都没做吗?答案当然是否

回到dll被windows注入到目标进程空间的时候。。。

当windows检测到目标进程的特定消息被调用时,windows会将在这个消息上的所有钩子函数遍历一次,如果不调用CallNextHookEx这个消息就不会传递到真正响应这个消息的函数上去了

再回到这里,当windows遍历到我们的钩子上时,dll就会被windows强行加载到目标进程空间,在此时,dll完成初始化

这个时候
CULHook g_send("Ws2_32.dll", "send", (PROC)hook_send);
CULHook g_sendto("Ws2_32.dll", "sendto", (PROC)hook_sendto);
CULHook g_recv("Ws2_32.dll", "recv", (PROC)hook_recv);
CULHook g_recvfrom("Ws2_32.dll", "recvfrom", (PROC)hook_recvfrom);

这些类的实例被同时初始化,类初始化调用的是类的构造函数,这是我们自定义的

CULHook(LPSTR pszModName, LPSTR pszFuncName, PROC pfnHook)
// jmp eax == 0xFF, 0xE0
  // 生成新的执行代码
  BYTE btNewBytes[8] = { 0xB8, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xE0, 0x00 }; 
  memcpy(m_btNewBytes, btNewBytes, 8);
  *(DWORD *)(m_btNewBytes + 1) = (DWORD)pfnHook; 

  // 加载指定模块,取得API函数地址
  m_hModule = ::LoadLibrary(pszModName);
  if(m_hModule == NULL)
  {
    m_pfnOrig = NULL;
    return;
  }
  m_pfnOrig = ::GetProcAddress(m_hModule, pszFuncName);

  // 修改原API函数执行代码的前8个字节,使它跳向我们的函数
  if(m_pfnOrig != NULL)
  {
    DWORD dwOldProtect;
    MEMORY_BASIC_INFORMATION    mbi;
    ::VirtualQuery( m_pfnOrig, &mbi, sizeof(mbi) );
    ::VirtualProtect(m_pfnOrig, 8, PAGE_READWRITE, &dwOldProtect);

    // 保存原来的执行代码
    memcpy(m_btOldBytes, m_pfnOrig, 8);
    // 写入新的执行代码
    ::WriteProcessMemory(::GetCurrentProcess(), (void *)m_pfnOrig, 
            m_btNewBytes, sizeof(DWORD)*2, NULL); 
  
    ::VirtualProtect(m_pfnOrig, 8, mbi.Protect, 0);
  }

。。。。函数是通过字节码覆盖API首地址为内联汇编代码,直接跳到我们自己的函数上去了,这是我们在不同的函数里面就可以做不同的事了。。。。

函数传入要进行覆盖的函数以及我们自定义的函数地址

下面是目标进程调用这6个函数时跳转到的函数的定义

int WINAPI hook_send(SOCKET s, const char FAR *buf, int len, int flags)
int WINAPI hook_sendto(SOCKET s, const char* buf,int len, int flags, const struct sockaddr* to, int tolen)
int WINAPI hook_recv(SOCKET s, char FAR *buf, int len, int flags)
int WINAPI hook_recvfrom(SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen)

CULHook g_WSARecv("Ws2_32.dll", "WSARecv", (PROC)hook_WSARecv);
CULHook g_WSARecvFrom("Ws2_32.dll", "WSARecvFrom", (PROC)hook_WSARecvFrom);
int WINAPI hook_WSARecv(
  SOCKET s,                                               
  LPWSABUF lpBuffers,                                     
  DWORD dwBufferCount,                                    
  LPDWORD lpNumberOfBytesRecvd,                           
  LPDWORD lpFlags,                                        
  LPWSAOVERLAPPED lpOverlapped,                           
  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine  
)
int WINAPI hook_WSARecvFrom(
  SOCKET s,                                               
  LPWSABUF lpBuffers,                                     
  DWORD dwBufferCount,                                    
  LPDWORD lpNumberOfBytesRecvd,                           
  LPDWORD lpFlags,                                        
  struct sockaddr FAR *lpFrom,                            
  LPINT lpFromlen,                                        
  LPWSAOVERLAPPED lpOverlapped,                           
  LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine  
)

。。。

似乎完了。。。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 6
支持
分享
最新回复 (23)
雪    币: 87
活跃值: (110)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
楼主大神。特来顶一下
2013-5-1 15:33
0
雪    币: 141
活跃值: (318)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
一段工具的分析啊
2013-5-1 16:13
0
雪    币: 796
活跃值: (370)
能力值: ( LV9,RANK:380 )
在线值:
发帖
回帖
粉丝
4
全局钩子 hook~~mark
2013-5-1 17:19
0
雪    币: 134
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
不错,楼主辛苦了,多谢分享。
2013-5-1 19:00
0
雪    币: 18
活跃值: (33)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
学习中 ......
2013-5-1 21:16
0
雪    币: 425
活跃值: (816)
能力值: ( LV9,RANK:553 )
在线值:
发帖
回帖
粉丝
7
这04年的代码是撸主大神写的吗,还是精华了
2013-5-1 22:56
0
雪    币: 92
活跃值: (100)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
8
淡定,这代码不是我写的,我只是分析而已。。。
2013-5-1 23:03
0
雪    币: 78
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
汗死,我用它hook firefox,直接崩溃了。。。。
2013-5-2 01:08
0
雪    币: 92
活跃值: (100)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
10
呵呵,是滴,我只是简单分析下它的原理,这个问题我也不知道为什么,求大神赐教
2013-5-2 01:27
0
雪    币: 34
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
对QQ进行注入截包会发生错误,请问怎么解决?
2013-5-2 10:00
0
雪    币: 142
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
拦什么崩什么。。。。
2013-5-2 14:28
0
雪    币: 92
活跃值: (100)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
13
我这边拦截qq的消息正常啊,没有崩溃,但是浏览器就不行了,我也不知道什么情况,程序的原理我觉得应该是没问题的,而且这个工具也是书上给的。。。还请知道错误原因的话告诉我一下,谢谢~
2013-5-2 17:46
0
雪    币: 92
活跃值: (100)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
14
很抱歉。。。
2013-5-2 17:47
0
雪    币: 92
活跃值: (100)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
15
如果是想用这个工具的话建议大家不要下载了,因为会导致被注入的程序崩溃,在此表示歉意
2013-5-2 17:53
0
雪    币: 44
活跃值: (25)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
16
这个工具好像在 王艳萍的 windows程序设计中 有。。。。。
2013-5-6 09:35
0
雪    币: 55
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
哦,我试试下,多谢分享
2013-5-6 09:41
0
雪    币: 92
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
我的路飞啊  !!!!!!!!!!!!!!
2013-5-7 14:20
0
雪    币: 13
活跃值: (657)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
我的毕设做的也是毕设,我设计的也是Jmp法。但是抓不到包,而且有些Bug,我不知道哪儿出错了,求楼主指导指导!!
上传的附件:
2013-5-7 22:20
0
雪    币: 13
活跃值: (657)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
楼主好人,有时间联系我哦,354297417@qq.com
2013-5-7 22:21
0
雪    币: 92
活跃值: (100)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
21
我简单看了下你的代码,开始抓包这个过程调用的是本进程空间中被加载的dll里的,不是目标进程中dll的过程(不知道你到底想调用哪个进程里的dll),进程间通信要WM_COPYDATA或者创建共享数据段,一般是在dll初始化的时候就进行API的hook
2013-5-8 14:06
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
正需要这个。谢谢楼主。
2013-12-12 19:52
0
雪    币: 489
活跃值: (112)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
23
楼主大神,这个代码貌似不是多线程安全的吧?没仔细看。。
2014-1-13 18:20
0
雪    币: 77
活跃值: (48)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
24
mark
2014-1-17 09:20
0
游客
登录 | 注册 方可回帖
返回
//