网络安全学习第16篇 - CE游戏动态内存修改器
???????????????????????????????????????????????????????????????????????????????????????? CE程序設(shè)計(jì)
注:參考網(wǎng)上程序,和實(shí)驗(yàn)15大同小異
相關(guān)知識(shí):
?
CE(Cheat Engine )是眾多游戲修改工具的其中之一,也是一款開(kāi)源軟件。運(yùn)行之后的界面,估計(jì)大多數(shù)人看見(jiàn)了都不知所謂,一對(duì)對(duì)數(shù)字描述了游戲的內(nèi)存地址和對(duì)應(yīng)的數(shù)值。不過(guò)對(duì)于普通用戶(hù)來(lái)說(shuō),這些都不需要去了解和理解,只需要把游戲中想要修改的數(shù)值找到對(duì)應(yīng)的地址,并修改成想要的數(shù)值就可以了。
?
尋找數(shù)值對(duì)應(yīng)地址的方法一般是:運(yùn)行1.CE->2.運(yùn)行游戲->3.打開(kāi)游戲進(jìn)程->4.首次搜索一個(gè)數(shù)值->5.回游戲中讓這個(gè)數(shù)值增加或減少 ->6.回CE按數(shù)值增減的情況再次搜索->7.重復(fù)5和6直到得到一個(gè)或很少的幾個(gè)結(jié)果->8.在這幾個(gè)結(jié)果中判斷哪一個(gè)是真正的結(jié)果(一般來(lái)說(shuō),搜索幾次之后,基本就剩下一個(gè)修改地址了)。
?
參考:https://baike.baidu.com/item/CE%E5%86%85%E5%AD%98%E4%BF%AE%E6%94%B9%E5%99%A8/9225930?fr=aladdin?- CE內(nèi)存修改器
代碼實(shí)現(xiàn):
?
內(nèi)存查找類(lèi)
#ifndef __MEMFINDER_H__ #define __MEMFINDER_H__ #define _CRT_SECURE_NO_WARNINGS#include <windows.h>class CMemFinder { public:CMemFinder(DWORD dwProcessId);virtual ~CMemFinder();// 屬性 public:BOOL IsFirst() const { return m_bFirst; }BOOL IsValid() const { return m_hProcess != NULL; }int GetListCount() const { return m_nListCnt; }DWORD operator [](int nIndex) { return m_arList[nIndex]; }// 操作virtual BOOL FindFirst(DWORD dwValue);virtual BOOL FindNext(DWORD dwValue);virtual BOOL WriteMemory(DWORD dwAddr, DWORD dwValue);// 實(shí)現(xiàn) protected:virtual BOOL CompareAPage(DWORD dwBaseAddr, DWORD dwValue);DWORD m_arList[1024]; // 地址列表int m_nListCnt; // 有效地址的個(gè)數(shù)HANDLE m_hProcess; // 目標(biāo)進(jìn)程句柄BOOL m_bFirst; // 是不是第一次搜索 };->OpenProcess 函數(shù)用來(lái)打開(kāi)一個(gè)已存在的進(jìn)程對(duì)象,并返回進(jìn)程的句柄。 CMemFinder::CMemFinder(DWORD dwProcessId) {m_nListCnt = 0;m_bFirst = TRUE;m_hProcess = ::OpenProcess(PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, FALSE, dwProcessId); }CMemFinder::~CMemFinder() {if(m_hProcess != NULL)::CloseHandle(m_hProcess); }->從打開(kāi)的進(jìn)程開(kāi)始查找查找的數(shù)據(jù)的地址 BOOL CMemFinder::FindFirst(DWORD dwValue) {const DWORD dwOneGB = 1024*1024*1024; // 1GBconst DWORD dwOnePage = 4*1024; // 4KBif(m_hProcess == NULL)return FALSE;// 查看操作系統(tǒng)類(lèi)型,以決定開(kāi)始地址DWORD dwBase;OSVERSIONINFO vi = { sizeof(vi) };::GetVersionEx(&vi);if (vi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)dwBase = 4*1024*1024; // Windows 98系列,4MB elsedwBase = 640*1024; // Windows NT系列,64KB// 在開(kāi)始地址到2GB的地址空間進(jìn)行查找for(; dwBase < 2*dwOneGB; dwBase += dwOnePage){// 比較1頁(yè)大小的內(nèi)存CompareAPage(dwBase, dwValue);}m_bFirst = FALSE;return TRUE; }->比較一頁(yè)內(nèi)存(指定范圍),查看值是否相等,相等保存到全局?jǐn)?shù)組中 BOOL CMemFinder::CompareAPage(DWORD dwBaseAddr, DWORD dwValue) {// 讀取1頁(yè)內(nèi)存BYTE arBytes[4096];if(!::ReadProcessMemory(m_hProcess, (LPVOID)dwBaseAddr, arBytes, 4096, NULL))return FALSE; // 此頁(yè)不可讀// 在這1頁(yè)內(nèi)存中查找DWORD* pdw;for(int i=0; i<(int)4*1024-3; i++){pdw = (DWORD*)&arBytes[i];if(pdw[0] == dwValue) // 等于要查找的值?{if(m_nListCnt >= 1024)return FALSE;// 添加到全局變量中m_arList[m_nListCnt++] = dwBaseAddr + i;}}return TRUE; }->查找全局?jǐn)?shù)組中下一個(gè)地址的數(shù)據(jù) BOOL CMemFinder::FindNext(DWORD dwValue) {// 保存m_arList數(shù)組中有效地址的個(gè)數(shù),初始化新的m_nListCnt值int nOrgCnt = m_nListCnt;m_nListCnt = 0; // 在m_arList數(shù)組記錄的地址處查找BOOL bRet = FALSE; // 假設(shè)失敗 DWORD dwReadValue;for(int i=0; i<nOrgCnt; i++){if(::ReadProcessMemory(m_hProcess, (LPVOID)m_arList[i], &dwReadValue, sizeof(DWORD), NULL)){if(dwReadValue == dwValue){m_arList[m_nListCnt++] = m_arList[i];bRet = TRUE;}}}return bRet; }->修改內(nèi)存中的數(shù)據(jù) BOOL CMemFinder::WriteMemory(DWORD dwAddr, DWORD dwValue) {return ::WriteProcessMemory(m_hProcess, (LPVOID)dwAddr, &dwValue, sizeof(DWORD), NULL); }// 下面的CMsgMemFinder類(lèi)在搜索內(nèi)存時(shí)還會(huì)不斷處理消息// 在等待期間處理消息 void WaitForIdle() {MSG msg; while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)){::TranslateMessage(&msg);::DispatchMessage(&msg);} }class CMsgMemFinder : public CMemFinder { public:CMsgMemFinder(DWORD dwProcessId) : CMemFinder(dwProcessId){ m_bIsWorking = FALSE;}// 是否在工作BOOL IsWorking() const { return m_bIsWorking; }// 開(kāi)始查找virtual BOOL FindFirst(DWORD dwValue){m_bIsWorking = TRUE;BOOL b = CMemFinder::FindFirst(dwValue);m_bIsWorking = FALSE;return b;}protected:// 比較1頁(yè)內(nèi)存前,先處理消息virtual BOOL CompareAPage(DWORD dwBaseAddr, DWORD dwValue){WaitForIdle();return CMemFinder::CompareAPage(dwBaseAddr, dwValue);}BOOL m_bIsWorking; };#endif // __MEMFINDER_H__-----------------------------------------------各控件的作用---------------------------------------BOOL CMainDialog::OnInitDialog() {CDialog::OnInitDialog();// 設(shè)置圖標(biāo)SetIcon(theApp.LoadIcon(IDI_MAIN), FALSE);m_comboList.SubclassWindow(::GetDlgItem(m_hWnd, IDC_PROLIST));m_btnUpdate.SubclassWindow(*GetDlgItem(IDC_UPDATE));m_listAddr.SubclassWindow(*GetDlgItem(IDC_ADDRLIST));m_pFinder = NULL;// 創(chuàng)建狀態(tài)欄,設(shè)置它的屬性(CStatusBarCtrl類(lèi)封裝了對(duì)狀態(tài)欄控件的操作)m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, CRect(0, 0, 0, 0), this, 10);m_bar.SetBkColor(RGB(0xa6, 0xca, 0xf0)); // 背景色int arWidth[] = { 145, -1 };// 更新進(jìn)程列表OnUpdate();// 更新界面UIControl();return FALSE; }void CMainDialog::OnSearch() {// 創(chuàng)建查找對(duì)象if(m_pFinder == NULL){DWORD dwId = m_comboList.GetItemData(m_comboList.GetCurSel());m_pFinder = new CMsgMemFinder(dwId);UIControl();}if(m_pFinder->IsWorking())return;CString sText;GetDlgItem(IDC_EDITSEARCH)->GetWindowText(sText);if(!sText.IsEmpty()){DWORD dwSearch = atoi(sText);if(m_pFinder->IsFirst()){m_bar.SetText("正在搜索,請(qǐng)耐心等待...", 0, 0); // 長(zhǎng)時(shí)間操作m_pFinder->FindFirst(dwSearch);}else{m_pFinder->FindNext(dwSearch); }sText.Format("搜索到%d個(gè)結(jié)果", m_pFinder->GetListCount());m_bar.SetText(sText, 0, 0);}else{if(m_pFinder->IsValid()){m_bar.SetText("打開(kāi)目標(biāo)進(jìn)程成功!", 0, 0);}else{m_bar.SetText("打開(kāi)目標(biāo)進(jìn)程失敗!", 0, 0);}}UIControl(); }void CMainDialog::OnRestart() {if(m_pFinder != NULL){if(m_pFinder->IsWorking())return;delete m_pFinder;m_pFinder = NULL;}m_bar.SetText("空閑", 0, 0);UIControl(); }void CMainDialog::UIControl() {m_comboList.EnableWindow(m_pFinder == NULL);m_btnUpdate.EnableWindow(m_pFinder == NULL);GetDlgItem(IDC_MODIFY)->EnableWindow(m_pFinder != NULL);// 列出搜索結(jié)果if(m_pFinder != NULL){CString s;m_listAddr.ResetContent();for(int i=0; i<m_pFinder->GetListCount(); i++){s.Format("%08lX", (*m_pFinder)[i]);m_listAddr.AddString(s);}} }void CMainDialog::OnUpdate() {// 刪除所有的項(xiàng)m_comboList.ResetContent();int nItem = 0; // 項(xiàng)計(jì)數(shù)PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) }; HANDLE hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(hProcessSnap == INVALID_HANDLE_VALUE) return; if(Process32First(hProcessSnap, &pe32)) { do { CString szText;szText.Format("%s (%d)", pe32.szExeFile, pe32.th32ProcessID);m_comboList.InsertString(nItem, szText);m_comboList.SetItemData(nItem, pe32.th32ProcessID);nItem++;} while(Process32Next(hProcessSnap, &pe32)); }::CloseHandle(hProcessSnap);m_comboList.SetCurSel(nItem-1); }void CMainDialog::OnModify() {CString sText;DWORD dwValue;GetDlgItem(IDC_EDITMODIFY)->GetWindowText(sText);if(sText.IsEmpty()){MessageBox("請(qǐng)輸入一個(gè)你想要的值!");return;}dwValue = (DWORD)atoi(sText);GetDlgItem(IDC_SELADDR)->GetWindowText(sText);if(sText.IsEmpty()){MessageBox("請(qǐng)輸入你要將哪個(gè)地址的值改為:%s", sText);return;}DWORD dwAddr;sscanf(sText, "%x", &dwAddr);if(m_pFinder != NULL){if(m_pFinder->WriteMemory(dwAddr, dwValue))m_bar.SetText("修改成功!", 0, 0);elsem_bar.SetText("修改失敗!", 0, 0);} }void CMainDialog::OnSelectChange() {CString sText;int nSel = m_listAddr.GetCurSel();m_listAddr.GetText(nSel, sText);GetDlgItem(IDC_SELADDR)->SetWindowText(sText); }void CMainDialog::OnCancel() {OnRestart();CDialog::OnCancel(); }簡(jiǎn)單的說(shuō)一下:
PROCESSENTRY32?pe32 = { sizeof(PROCESSENTRY32) };
HANDLE?hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
?
HANDLE?hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
注:CreateToolhelp32Snapshot可以通過(guò)獲取進(jìn)程信息為指定的進(jìn)程、進(jìn)程使用的堆[HEAP]、模塊[MODULE]、線程建立一個(gè)快照。說(shuō)到底,可以獲取系統(tǒng)中正在運(yùn)行的進(jìn)程信息,線程信息,等。
?
?
2.通過(guò)選擇進(jìn)程,打開(kāi)指定進(jìn)程的句柄:使用
CMemFinder::CMemFinder(DWORD?dwProcessId)
{
m_nListCnt = 0;
m_bFirst = TRUE;
m_hProcess = ::OpenProcess(PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_VM_OPERATION, FALSE, dwProcessId);
}
?
BOOL?CMemFinder::CompareAPage(DWORD?dwBaseAddr, DWORD?dwValue)
{
// 讀取1頁(yè)內(nèi)存
BYTE?arBytes[4096];
if(!::ReadProcessMemory(m_hProcess, (LPVOID)dwBaseAddr, arBytes, 4096, NULL))
return?FALSE; // 此頁(yè)不可讀
?
// 在這1頁(yè)內(nèi)存中查找
DWORD* pdw;
for(int?i=0; i<(int)4*1024-3; i++)
{
pdw = (DWORD*)&arBytes[i];
if(pdw[0] == dwValue) // 等于要查找的值?
{
if(m_nListCnt >= 1024)
return?FALSE;
// 添加到全局變量中
m_arList[m_nListCnt++] = dwBaseAddr?+ i;
}
}
?
return?TRUE;
}
?
4.然后寫(xiě)入值修改該地址存放的數(shù)據(jù)。
?
BOOL?CMemFinder::WriteMemory(DWORD?dwAddr, DWORD?dwValue)
{
return?::WriteProcessMemory(m_hProcess, (LPVOID)dwAddr, &dwValue, sizeof(DWORD), NULL);
}
?
內(nèi)存修改成功!!!
此次試驗(yàn)與實(shí)驗(yàn)15游戲內(nèi)存修改原理基本相同,實(shí)驗(yàn)15的內(nèi)存修改步驟大致如下:
?
獲得窗口句柄->獲得該窗口的進(jìn)程(在內(nèi)存中)->打開(kāi)進(jìn)程->修改內(nèi)存
?
使用的函數(shù)分別有:
?
FindWindow(NULL, L"shooting")->GetSafeHwnd();
函數(shù)功能:該函數(shù)獲得一個(gè)頂層窗口的句柄,該窗口的類(lèi)名和窗口名與給定的字符串相匹配。這個(gè)函數(shù)不查找子窗口。在查找時(shí)不區(qū)分大小寫(xiě)。
?
GetWindowThreadProcessId(hWnd, &Pid);
函數(shù)功能:GetWindowThreadProcessId是一種計(jì)算機(jī)函數(shù),功能是找出某個(gè)窗口的創(chuàng)建者(線程或進(jìn)程),返回創(chuàng)建者的標(biāo)志符,函數(shù)原型是DWORD GetWindowThreadProcessId。
?
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
函數(shù)功能:OpenProcess 函數(shù)用來(lái)打開(kāi)一個(gè)已存在的進(jìn)程對(duì)象,并返回進(jìn)程的句柄。
?
result = WriteProcessMemory(hProcess, (LPVOID)Address, &Score, 4, 0);
函數(shù)功能:WriteProcessMemory是計(jì)算機(jī)語(yǔ)言中的一種函數(shù)。此函數(shù)能寫(xiě)入某一進(jìn)程的內(nèi)存區(qū)域(直接寫(xiě)入會(huì)出Access Violation錯(cuò)誤),故需此函數(shù)入口區(qū)必須可以訪問(wèn),否則操作將失敗。
?
而此次試驗(yàn)是在實(shí)驗(yàn)15基礎(chǔ)上進(jìn)行改進(jìn),它不是使用獲取窗口句柄打開(kāi)進(jìn)程,而是通過(guò)獲取系統(tǒng)中的所有進(jìn)程句柄,找到運(yùn)行的游戲,這個(gè)其實(shí)改進(jìn)了一下,但使用窗口句柄代開(kāi)進(jìn)程也未嘗不可。
而最大的不同,且最重要的點(diǎn)是:它通過(guò)比較進(jìn)程中的所有地址中的數(shù)據(jù),通過(guò)游戲的數(shù)值變化,使用該數(shù)值對(duì)內(nèi)存中的進(jìn)行過(guò)濾(保存地址,逐步減少選中的地址數(shù)量),最后找到想要修改的地址,方法高明了不止一籌。
?
實(shí)驗(yàn)步驟為:
?
獲取系統(tǒng)所有進(jìn)程句柄 -> 打開(kāi)指定進(jìn)程 -> 觀察游戲值的變化輸入值比較內(nèi)存中所有地址的數(shù)據(jù),篩選出相等數(shù)據(jù)的地址,重復(fù)操作過(guò)濾到只剩一個(gè)地址 -> 修改內(nèi)存
?通過(guò)參考網(wǎng)上資料,進(jìn)行此次實(shí)驗(yàn),學(xué)會(huì)了CE動(dòng)態(tài)內(nèi)存修改器的制作,也算是對(duì)這個(gè)學(xué)期網(wǎng)絡(luò)安全課程的一個(gè)總結(jié)。通過(guò)這學(xué)期網(wǎng)絡(luò)安全的學(xué)習(xí),對(duì)網(wǎng)絡(luò)有了更深一步的了解,也對(duì)自己以后從事IT行業(yè)打下了一定安全基礎(chǔ)。我感覺(jué)這門(mén)課是大學(xué)為數(shù)不多真正學(xué)到東西的一門(mén)課。老師講課條理清楚,而且結(jié)合他生活中的例子,把我們帶進(jìn)了神秘未知的安全世界,網(wǎng)絡(luò)安全是程序員捍衛(wèi)自己地位的權(quán)杖。俗話說(shuō)師傅領(lǐng)進(jìn)門(mén),修行在個(gè)人,想要真正成為網(wǎng)絡(luò)安全的專(zhuān)家也不僅僅是通過(guò)十多節(jié)課就可以達(dá)到,更需要自己去專(zhuān)研,但姜曄老師把我們從門(mén)外漢領(lǐng)進(jìn)了安全的大門(mén),我們以后要進(jìn)行網(wǎng)絡(luò)安全的深入學(xué)習(xí)可以是少了很多攔路石,少走了不知道多少?gòu)澛贰?/p>
感謝老師一學(xué)期的教導(dǎo)~
致謝!
總結(jié)
以上是生活随笔為你收集整理的网络安全学习第16篇 - CE游戏动态内存修改器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: premiere(Pr)制作逐字出现效果
- 下一篇: 根据中文字符串查询拼音声母