標籤:push 管理系 載入 工位 out als widget 提示框 顯示
聲明:本文只是為了初學C++的,能夠做出一些實用的東西,跳出管理系統的束縛,提升學習的興趣,在這裡選取了單機遊戲,請不要嘗試線上遊戲,違發而已未必可行。
序:首先我們需要一個Qt+VS環境
Qt從http://download.qt.io/archive/中下載,第一個和第三個,在裡面選擇對應版本。然後就是配環境了,這裡提供2013+Qt5.5.1的環境配置,如果環境不同,請自行百度。這點解決問題能力都沒有,就別學C++了...
我的環境是2013+Qt5.5.1,不同版本可能略有差異,不過大同小異。
首先開啟VS建立工程,點確定,然後一直下一步
選擇QWidget,點完成
然後就建立了一個工程,我們來說說這個工程。
一:main函數和C++的很像
然後再看看剛才建立的Qt視窗類別
先是標頭檔
然後是CPP檔案
再看看一些“奇怪”的檔案
下面這兩個是Qt的moc檔案,是編譯時間自動產生和更新的,所以不用管
下面第一個是資源檔的代碼CPP,自動產生的,不用管
第二個是UI檔案的標頭檔,自動產生的,不用管
資源檔,用來載入圖片等一些資源,這裡沒用到,不用管
這個就是上面提到的UI檔案,相當於可視化介面設計器,用來設計介面的。
雙擊點開XXXXX.UI檔案
二:接下來開始介面設計
在控制項盒子中左鍵選中一個檔案標籤,一個文字輸入框,一個按鈕,然後往介面設計器裡面拖。檔案標籤在左,文字輸入框在中,一個按鈕在右。
ctrl+滑鼠左鍵點選三個控制項,然後在任意一個控制項上右鍵,選擇布局->水平布局
開始介面布局
右鍵大視窗,選擇布局->垂直布局
然後滑鼠放到介面設計器的邊框邊緣,按住左鍵拖動到合適大小
在對象查看器裡左鍵點選大視窗,然後屬性視窗往下拖,在WindowTitle裡修改視窗標題
雙擊控制項修改控制項的文本
記錄控制項的對應關係,把金錢技能和屬性對應的輸入框和按鈕記錄下來
在這裡我金錢的輸入框是lineEdit,金錢修改按鈕是pushButton,技能點則分別是lineEdit_2和pushButton_2,屬性點則是lineEdit_3和pushButton_3
然後點儲存,注意一定要儲存
三:實現前的知識普及
1:遊戲記憶體修改的知識普及
一般遊戲資料有一個地址值,但是這個地址值是動態,每次遊戲重啟都會發生變化,所以我們要找到不變的一級基址,和兩個不變的位移量,來得到最新的遊戲資料地址。
2:Qt訊號槽知識普及
①Qt訊號
訊號是指一種通知,形象地比喻下:比如你帶了許多巧克力去公司,然後在群裡告訴大家,“我帶了很多巧克力,要的來我工位拿”,這裡公司群就是你的應用程式,群員就是程式裡的執行個體化對象,你說的話這就是一種訊號;可能有些人會無視,有些人根本沒看見,有些人會來要,有些人會轉告其他人,你只負責發出一個通知,你不關心別人看到你的通知會作何反應。
② Qt槽函數
槽指的是一種行為函數,定義了收到訊號通知後,應該做出何種反應,上面巧克力的例子,無視,轉告和要巧克力,都是一種對於訊號通知的響應行為。
③ Qt的connect函數
就是對訊號和槽進行關聯,A發的訊號通知B做出某種響應行為。
④ Qt的QTimer
定時器,按照你設定的時間間隔,不間斷髮出timeout()訊號通知。
⑤ QMessageBox::information()
顯示一個提示視窗
⑥ ui控制項的指標怎麼找
UI控制項的指標和objectname同名,而objectname就是在介面設計器點選對應控制項,屬性裡第一個
使用的時候用ui.objectname或者ui->objectname,用哪種取決於h檔案裡的ui變數是對象還是指標。這裡就是ui.objectname。
四:基址和位移量尋找
①現在我們要用到一個軟體,名字叫cheat engine,我的是6.6中文版。遊戲以騎馬與砍殺為例,首先修改金錢。
②把金錢資料輸入ce,點擊新的掃描
③想辦法改變金錢數,輸入CE,點擊再次掃描,不斷重複這條,直到資料只有一個
(注意:有可能會遇到一直有2個的情況,這樣的情況試著改下資料就行了,哪個生效就是哪個)
④這裡得到的就是一個遊戲資料記憶體,可以改遊戲資料值,但他是動態,遊戲重啟就失效了,我們需要找的是基址。
⑤滑鼠右鍵這個遊戲資料地址,尋找什麼改變了這個值。
⑥然後出現這個介面,一開始是沒有資料的,需要改變下遊戲資料(這裡是金錢數)
⑦雙擊這條資料,這裡的5D0就是第一個位移量,4B4C1024就是下一個要尋找的地址。
⑧開啟一個新的掃描
⑨選擇需要的的地址尋找是什麼訪問了這個地址,有時候有很多個,一般是比較特殊的那個(就是其他地址開頭都是一樣的,就他不一樣),或者一個個看,有資料的就是我們需要的那個地址(注意無需改變遊戲資料就有資料)
⑩隨便雙擊一個mov指令資料,這裡的140EC就是第二個位移值,48D2E010就是下一個要尋找的地址
①①用新拿到的推薦地址重複第⑧步,尋找的綠色地址就是一級基址了
①②開始效驗這個基址
①③ 修改這個地址的數值,如果錢發生變化的話就找對了
同理,用這個方法尋找技能點
找出來的一級基址是009D5E2C,位移是5D0 2BC,發現沒有,一級基址和第二次位移是一樣的,所以之後尋找,找一次位移就可以了。
【特別注意】網上有些攻略說一級基址+第二次位移量+第一次位移量就是遊戲資料地址,其實是錯的,應該是一級基址裡儲存的值+第二次位移量得到二級基址,二級基址裡儲存的值+第一次位移量才是遊戲資料地址。
五:代碼實現部分,教程以注釋展現
只實現了技能點和金錢
#ifndef GAMEEDITOR_H#define GAMEEDITOR_H#include <QtWidgets/QWidget>#include "ui_gameeditor.h"//讀寫遊戲記憶體所必須的標頭檔#include <windows.h>class QTimer;class GameEditor : public QWidget{Q_OBJECTpublic:GameEditor(QWidget *parent = 0);~GameEditor();//slots就是表示槽函數protected slots:void connectGame();void updateGameMoney();void updateGamePerks();private:Ui::GameEditorClass ui;//計時器指標,見5-2-4QTimer* timer;//金錢地址DWORD moueyAdress;//技能點地址DWORD perksAdress;//進程PIDDWORD pid;HWND hwnd;//進程控制代碼HANDLE handle;};#endif // GAMEEDITOR_H
#include "gameeditor.h"//定時器標頭檔#include <QTimer>//提示框標頭檔#include <QMessageBox>GameEditor::GameEditor(QWidget *parent): QWidget(parent){ui.setupUi(this);pid = 0;hwnd = 0;handle = 0;//金錢一級基址moueyAdress = 0x009D5E2C;//技能點一級基址perksAdress = 0x009D5E2C;//建立一個定時器,見5-2-4timer = new QTimer;//設定時間間隔為1000毫秒timer->setInterval(1000);//timeout為計時器內建訊號,時間一到自動發送//connect為關聯訊號槽,詳細見前面的知識普及內容//connect(訊號寄件者指標,SIGNAL(訊號), this, SLOT(槽實現函數));connect(timer, SIGNAL(timeout()), this, SLOT(connectGame()));//clicked為按鈕內建訊號,點擊自動發送//還記得嗎,ui.pushButton是金錢修改按鈕,ui.pushButton_2是技能點修改按鈕connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(updateGameMoney()));connect(ui.pushButton_2, SIGNAL(clicked()), this, SLOT(updateGamePerks()));ui.label_4->setText(QString::fromLocal8Bit("正在等待遊戲程式...."));//計時器開始計時timer->start();}GameEditor::~GameEditor(){}void GameEditor::connectGame(){//尋找視窗並返回視窗控制代碼hwnd = FindWindow(0, L"Mount&Blade Warband");if (!hwnd){return;}//通過視窗控制代碼擷取pidGetWindowThreadProcessId(hwnd, &pid);if (!pid){return;}//通過pid開啟一個進程並擷取進程控制代碼handle = OpenProcess(PROCESS_ALL_ACCESS, false, pid);if (!handle){return;}//通過金錢一級基址讀取裡面的資料DWORD newMoneyAdress = 0;ReadProcessMemory(handle, (LPVOID)moueyAdress, &newMoneyAdress, sizeof(newMoneyAdress), 0);//讀取不到說明你開了遊戲,但是沒有開始if (moueyAdress <= 0){return;}ui.label_4->setText(QString::fromLocal8Bit("遊戲程式串連成功!"));//停止計時器timer->stop();//金錢一級基址裡的值+第二個位移量=金錢二級基址moueyAdress = newMoneyAdress;moueyAdress += 0x140EC;//通過金錢二級基址讀取裡面的資料ReadProcessMemory(handle, (LPVOID)moueyAdress, &newMoneyAdress, sizeof(newMoneyAdress), 0);//金錢二級基址裡的值+第一個位移量=遊戲資料地址(動態),遊戲資料地址裡的值就是遊戲資料moueyAdress = newMoneyAdress;moueyAdress += 0x5D0;//同理通過技能點一級基址和位移量擷取遊戲資料地址DWORD newPerksAdress = 0;ReadProcessMemory(handle, (LPVOID)perksAdress, &newPerksAdress, sizeof(newPerksAdress), 0);perksAdress = newPerksAdress;perksAdress += 0x140EC;ReadProcessMemory(handle, (LPVOID)perksAdress, &newPerksAdress, sizeof(newPerksAdress), 0);perksAdress = newPerksAdress;perksAdress += 0x2BC;}//金錢的修改按鈕被點擊void GameEditor::updateGameMoney(){//還記得嗎,ui.lineEdit就是金錢的文本輸入框,text()表示擷取輸入框的文本,toInt()表示轉化為int資料DWORD money = ui.lineEdit->text().toInt();//修改遊戲資料地址裡的值DWORD pref=WriteProcessMemory(handle, (LPVOID)moueyAdress, &money, sizeof(money), 0);//QString是Qt裡的字串QString informationStr;if (pref){informationStr = QString::fromLocal8Bit("修改成功");}else{informationStr = QString::fromLocal8Bit("修改失敗");}//資訊氣球,第一個參數是父視窗,填寫this或者0都可以,第二個參數是標題,第三個參數是提示內容QMessageBox::information(this, QString::fromLocal8Bit("提示"), informationStr);}//技能點的修改按鈕被點擊void GameEditor::updateGamePerks(){DWORD perks = ui.lineEdit_2->text().toInt();DWORD pref = WriteProcessMemory(handle, (LPVOID)perksAdress, &perks, sizeof(perks), 0);QString informationStr;if (pref){informationStr = QString::fromLocal8Bit("修改成功");}else{informationStr = QString::fromLocal8Bit("修改失敗");}//資訊氣球,第一個參數是父視窗,填寫this或者0都可以,第二個參數是標題,第三個參數是提示內容QMessageBox::information(this, QString::fromLocal8Bit("提示"), informationStr);}
只需要一點點C++基礎,新手也可以製作單機遊戲記憶體修改器