上一個內容:14.數據包分析工具界面與通信設計
碼云地址(master 分支):https://gitee.com/dye_your_fingers/titan
碼云版本號:2d6491e3c51a1a7ab4da0ee6dc4cf566a80fd6e1
代碼下載地址,在 titan 目錄下,文件名為:titan-發送通信數據包至分析工具.zip
鏈接:https://pan.baidu.com/s/1W-JpUcGOWbSJmMdmtMzYZg
提取碼:q9n5
--來自百度網盤超級會員V4的分享
HOOK引擎,文件名為:黑兔sdk升級版.zip
鏈接:https://pan.baidu.com/s/1IB-Zs6hi3yU8LC2f-8hIEw
提取碼:78h8
--來自百度網盤超級會員V4的分享
以 14.數據包分析工具界面與通信設計 它的代碼為基礎進行修改
效果圖:
新加 CAnly.h文件:
#define Anly
#ifdef Anly
#pragma once
class CAnly
{
public:LRESULT SendData(int type, void* buff, unsigned len);
};
#endif
?新加 CAnly.cpp文件:
#include "pch.h"
#include "CAnly.h"
#ifdef Anly
LRESULT CAnly::SendData(int type, void* buff, unsigned len)
{HWND hWnd = FindWindow(L"#32770", L"DataAnly");COPYDATASTRUCT copydata{};copydata.dwData = type;copydata.cbData = len;copydata.lpData = buff;if (hWnd) {//MessageBoxA(0, "222222222222", "0", MB_OK);return SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)©data);}return 0;
}
#endif
GameWinSock.cpp文件的修改:修改了 OnConnect函數、OnSend函數、OnRecving函數
#include "pch.h"
#include "GameWinSock.h"
#include "extern_all.h"GameWinSock::PROC GameWinSock::_OnConnect{};
GameWinSock::PROC GameWinSock::_OnSend{};
GameWinSock::PROC GameWinSock::_OnRecv{};
// 這個函數攔截了游戲的連接
bool GameWinSock::OnConnect(char* ip, unsigned port)
{wchar_t buff[]{ L"OnConnect函數連接網絡。。。" };COPYDATASTRUCT copydata{};/*這里的0表示字符串0具體是什么要看 WM_COPYDATA消息處理函數怎樣寫的*/copydata.dwData = 0;copydata.cbData = sizeof(buff);copydata.lpData = buff;HWND hWnd = FindWindow(L"#32770", L"DataAnly");SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)©data);// this是ecx,HOOK的點已經有ecx了WinSock = this;bool b = (this->*_OnConnect)(ip, port);// 下方注釋的代碼時為了防止多次注入,導致虛函數地址不恢復問題導致死循環,通過一次性HOOK也能解決/*unsigned* vtable = (unsigned*)this;vtable = (unsigned*)vtable[0];union {unsigned value;bool(GameWinSock::* _proc)(char*, unsigned);} vproc;vproc._proc = _OnConnect;DWORD oldPro, backProc;VirtualProtect(vtable, 0x10x00, PAGE_EXECUTE_READWRITE, &oldPro);vtable[0x34 / 4] = vproc.value;VirtualProtect(vtable, 0x10x00, oldPro, &backProc);*/return b;
}bool GameWinSock::OnSend(char* buff, unsigned len)
{/*這里就可以監控游戲發送的數據了*/
#ifdef Anlyanly->SendData(0, buff, len);
#endifreturn (this->*_OnSend)(buff, len);
}bool GameWinSock::OnRecving(char* buff, unsigned len)
{// MessageBoxA(0, "11111111111111", "0", MB_OK);/*監控游戲接收的數據包*/
#ifdef Anlyanly->SendData(1, buff, len);
#endifreturn true;
}bool GameWinSock::OnRecv(char* buff, unsigned len)
{
//#ifdef Anly
// anly->SendData(1, buff, len);
//#endifreturn (this->*_OnRecv)(buff, len);
}
extern_all.h文件的修改:新加 anly變量
/*此文件是用來存放全局變量、全局函數(通用函數)
*/
#pragma once
#include "GameWinSock.h"
#include "GameProc.h"
#include "CAnly.h"extern GameWinSock* WinSock;
extern GameProc* PGameProc;
extern void InitClassProc(LPVOID proc_addr, unsigned value);#ifdef Anly
extern CAnly* anly;
#endif
extern_all.cpp文件的修改:新加 anly變量
/*此文件是用來存放全局變量、全局函數(通用函數)
*/
#include "pch.h"
#include "extern_all.h"
GameWinSock* WinSock = nullptr;
GameProc* PGameProc = nullptr;
#ifdef Anly
CAnly* anly = nullptr;
#endifvoid InitClassProc(LPVOID proc_addr, unsigned value)
{unsigned* writer = (unsigned*)proc_addr;writer[0] = value;
}
GameProc.cpp文件的修改:修改了 _OnRecv函數
#include "pch.h"
#include "GameProc.h"
#include "extern_all.h"// typedef bool(GameWinSock::* U)(char*, unsigned);bool _OnRecv(HOOKREFS2) {unsigned* _esp = (unsigned*)_ESP;_EAX = WinSock->RecvPoint;WinSock->OnRecving((char*)_esp[1], _esp[2]);return true;
}bool _OnConnect(HOOKREFS2) {/*根據虛函數表做HOOK的操作截取 ecx 獲取 winsock 的值(指針)*/unsigned* vtable = (unsigned*)_EDX;//WinSock = (GameWinSock *)_ECX;/*聯合體的特點是共用一個內存由于 GameWinSock::OnConnect 的 OnConnect函數是 GameWinSock類的成員函數直接 vtable[0x34 / 4] = (unsigned)&GameWinSock::OnConnect; 這樣寫語法不通過所以使用聯合體,讓語法通過*/union {unsigned value;bool(GameWinSock::* _proc)(char*, unsigned);} vproc;DWORD oldPro, backProc;VirtualProtect(vtable, 0x100, PAGE_EXECUTE_READWRITE, &oldPro);/*vproc._proc = &GameWinSock::OnConnect; 這一句是把我們自己寫的調用connect函數的地址的出來*/ vproc._proc = &GameWinSock::OnConnect; /*InitClassProc函數里做的是給指針賦值的操作InitClassProc(&GameWinSock::_OnConnect, vtable[0x34/4]);這一句的意思是把GameWinSock類里的_OnConnect變量的值賦值成vtable[0x34/4],這個 vtable[0x34/4] 是虛表里的函數vtable[0x34/4]是游戲中調用connect函數的函數地址,經過之前的分析調用connect是先調用了虛表中的一個函數,然后從這個函數中調用了connect函數*/InitClassProc(&GameWinSock::_OnConnect, vtable[0x34/4]);vtable[0x34 / 4] = vproc.value;vproc._proc = &GameWinSock::OnSend;InitClassProc(&GameWinSock::_OnSend, vtable[0x3C / 4]);vtable[0x3C / 4] = vproc.value;VirtualProtect(vtable, 0x100, oldPro, &backProc);return true;
}GameProc::GameProc()
{hooker = new htd::hook::htdHook2();Init();InitInterface();
}void GameProc::LoadBase()
{LoadLibraryA("fxnet2.dll");
}void GameProc::Init()
{
#ifdef anlyanly = new CAnly();
#endif}void GameProc::InitInterface()
{LoadBase();// MessageBoxA(0, "1", "1", MB_OK);// 只會HOOK一次,一次性的HOOKhooker->SetHook((LPVOID)0x10617046, 0x1, _OnConnect, 0, true);/*第一個參數是HOOK的位置第二個參數是HOOK的位置的匯編代碼的長度(用于保證執行的匯編代碼完整)第三個參數是HOOK之后當游戲執行到第一個參數的位置的時候跳轉的位置*/hooker->SetHook((LPVOID)0x10618480, 0x1, _OnRecv);/*在這里綁定游戲處理數據包函數(0x10618480函數)然后0x10618480函數在上面一行代碼已經進行了HOOK所以在調用_OnRecv函數指針時,它就會進入我們HOOK*/InitClassProc(&GameWinSock::_OnRecv, 0x10618480);
}
DataAnlyDlg.cpp文件的修改:修改了 OnCopyData函數
?
// DataAnlyDlg.cpp: 實現文件
//#include "pch.h"
#include "framework.h"
#include "DataAnly.h"
#include "DataAnlyDlg.h"
#include "afxdialogex.h"#ifdef _DEBUG
#define new DEBUG_NEW
#endif// 用于應用程序“關于”菜單項的 CAboutDlg 對話框class CAboutDlg : public CDialogEx
{
public:CAboutDlg();// 對話框數據
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_ABOUTBOX };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 實現
protected:DECLARE_MESSAGE_MAP()
};CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()// CDataAnlyDlg 對話框CDataAnlyDlg::CDataAnlyDlg(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_DATAANLY_DIALOG, pParent)
{m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}void CDataAnlyDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_LIST1, lstView);
}BEGIN_MESSAGE_MAP(CDataAnlyDlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDOK, &CDataAnlyDlg::OnBnClickedOk)ON_WM_COPYDATA()
END_MESSAGE_MAP()// CDataAnlyDlg 消息處理程序BOOL CDataAnlyDlg::OnInitDialog()
{CDialogEx::OnInitDialog();// 將“關于...”菜單項添加到系統菜單中。// IDM_ABOUTBOX 必須在系統命令范圍內。ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != nullptr){BOOL bNameValid;CString strAboutMenu;bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動// 執行此操作SetIcon(m_hIcon, TRUE); // 設置大圖標SetIcon(m_hIcon, FALSE); // 設置小圖標// ShowWindow(SW_MAXIMIZE); // 設置最大號啟動// TODO: 在此添加額外的初始化代碼auto lStyle = GetWindowLongPtr(lstView.m_hWnd, GWL_STYLE); // 獲取窗口樣式lStyle |= LVS_REPORT; // 設置為報表模式SetWindowLongPtr(lstView.m_hWnd, GWL_STYLE, lStyle);// 給窗口設置樣式auto dStyle = lstView.GetExtendedStyle(); // 獲取擴展樣式dStyle |= LVS_EX_FULLROWSELECT; // 設置選擇時選擇一行dStyle |= LVS_EX_GRIDLINES; // 畫網格線lstView.SetExtendedStyle(dStyle); // 設置擴展樣式/*lstView.InsertColumn(0, L"類型", 0, 100);lstView.InsertColumn(1, L"內容", 0, 700);lstView.InsertColumn(2, L"長度", 0, 50);lstView.InsertColumn(3, L"時間", 0, 100);lstView.InsertColumn(4, L"備注", 0, 100);這幾行代碼意思是設置表頭*/lstView.InsertColumn(0, L"類型", 0, 100);lstView.InsertColumn(1, L"內容", 0, 700);lstView.InsertColumn(2, L"長度", 0, 50);lstView.InsertColumn(3, L"時間", 0, 100);lstView.InsertColumn(4, L"備注", 0, 100);return TRUE; // 除非將焦點設置到控件,否則返回 TRUE
}void CDataAnlyDlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialogEx::OnSysCommand(nID, lParam);}
}// 如果向對話框添加最小化按鈕,則需要下面的代碼
// 來繪制該圖標。 對于使用文檔/視圖模型的 MFC 應用程序,
// 這將由框架自動完成。void CDataAnlyDlg::OnPaint()
{if (IsIconic()){CPaintDC dc(this); // 用于繪制的設備上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使圖標在工作區矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 繪制圖標dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();}
}//當用戶拖動最小化窗口時系統調用此函數取得光標
//顯示。
HCURSOR CDataAnlyDlg::OnQueryDragIcon()
{return static_cast<HCURSOR>(m_hIcon);
}void CDataAnlyDlg::OnBnClickedOk()
{wchar_t buff[]{ L"我愛阿民" };COPYDATASTRUCT copydata{};/*這里的0表示字符串0具體是什么要看 WM_COPYDATA消息處理函數怎樣寫的*/copydata.dwData = 0;copydata.cbData = sizeof(buff);copydata.lpData = buff;SendMessage(WM_COPYDATA, 0, (LPARAM)©data);
}BOOL CDataAnlyDlg::OnCopyData(CWnd* pWnd, COPYDATASTRUCT* p)
{int type = p->dwData;CString _result;if (MsgType[type]) {// 轉換為buffunsigned char* buff = (unsigned char*)p->lpData;CString _tmp;for (int i = 0; i < p->cbData;i++) {_tmp.Format(L"%.2X", buff[i]);_result = _result + L" " + _tmp;}}else {// 顯示文本_result.Format(L"%s", p->lpData);}CString wlen;wlen.Format(L"%d", p->cbData);lstView.InsertItem(0, MsgName[type]);lstView.SetItemText(0, 1, _result);lstView.SetItemText(0, 2, wlen);lstView.SetItemText(0, 3, wlen);return CDialogEx::OnCopyData(pWnd, p);
}
DataAnlyDlg.h文件的修改:新加 MsgType變量、MsgName變量
// DataAnlyDlg.h: 頭文件
//#pragma once// CDataAnlyDlg 對話框
class CDataAnlyDlg : public CDialogEx
{
// 構造
public:CDataAnlyDlg(CWnd* pParent = nullptr); // 標準構造函數// 對話框數據
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_DATAANLY_DIALOG };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 實現
protected:HICON m_hIcon;// 生成的消息映射函數virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP()
public:CListCtrl lstView;afx_msg void OnBnClickedOk();afx_msg BOOL OnCopyData(CWnd* pWnd, COPYDATASTRUCT* pCopyDataStruct);bool MsgType[5]{ // 意思看使用它的代碼true, true, false, false, false};wchar_t MsgName[5][0xFF]{// 意思看使用它的代碼L"發送",L"接收",L"發送解析",L"接收解析",L"日志"};/*0 發送數據1 接收數據2 發送數據解析3 接收數據解析4 日志*/
};