天天看點

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

QQ連連看單機版輔助制作全流程

最近在15PB學習逆向,分析了個小遊戲并寫出了輔助工具,在這裡總結下全流程。

遊戲:QQ連連看(單機版1.2)

完成目标:

1.去除廣告

2.完成指南針、炸彈消除的功能

3.編寫注入程式和遊戲輔助的DLL

使用工具:VS2017、OD、CE、PEID、Spy++

分析環境:Win7虛拟機

首先在百度上搜尋“QQ連連看單機版”随便下了個V1.2版的,把它解壓到桌面然後進入檔案夾。

仔細觀察下都有些什麼檔案,這很重要,有可能得到一些有利于破解的資訊。

**1.**在這裡觀察到有兩個可執行的EXE檔案、兩個音樂檔案夾,這都是比較重要的資訊。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**2.**用PEID擦看下這兩個EXE程式基本資訊,得以得出"kyodai.exe"程式是VC6.0的編譯器編寫的,遊戲一般都是C++語言編寫,而"QQ連連看單機版V1.2.exe"是一個加殼的程式,常見壓縮殼ASpack這就忽略它,也能分析。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程
QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**3.**輕按兩下"kyodai.exe"程式後回崩潰如圖。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**4.**那麼就确定了開始遊戲的程式"QQ連連看單機版V1.2.exe",打開之後會彈出廣告視窗,再之後遊戲就運作了。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**5.**退出遊戲,打開”任務管理器”,在運作遊戲觀察程序的變化,發現在彈出廣告視窗時隻有一個與遊戲相關的程序”QQ連連看單機版V1.2.exe”

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**6.**點選繼續進入遊戲之後發現此程序消失,而多了另一個很熟悉程序"kyodai.exe"

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**7.**由于最終運作的還是"kyodai.exe"程式,但是點選它又運作不了。而通過其他程式卻可運作它, 由此猜想"kyodai.exe"在運作時,”QQ連連看單機版V1.2.exe”打開它并對它的記憶體進行了修改,使他能正常運作。在這說明下這是老編譯器寫的遊戲不存在随機基址,很多位址都是固定的。

猜想它可能使用了CreateProcessA\W函數打開程序,那麼開始調試,使用OD開打”QQ連連看單機版V1.2.exe”,Ctrl+G搜尋CreateProcessA\W在2個函數上都按F2設定斷點,運作之後發現在CreateProcessA函數上斷下,觀察堆棧資料,發現"kyodai.exe"程式被它以挂起的方式打開了。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**8.**很多惡意程式都是這樣的套路,那麼就容易猜想了,挂起了程式之後就可能修改記憶體資料,之後恢複程式,那再就來搜尋一下修改記憶體資料函數WriteProcessMemory下斷點,運作,在次停下了再觀察堆棧資料,發現3個重要的資料,意為在"kyodai.exe"程式中的0043817A 位址處修改1個位元組的資料。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**9.**選中該Buffer右鍵檢視其内容是”0”。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**10.**然後在搜尋一個喚醒線程的函數ResumeThread下斷點,運作之後果然走到了這裡。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**11.**那麼我們現在就已經分析出了”QQ連連看單機版V1.2.exe”的運作機制,它首先彈出廣告,然後再執行CreateProcessA -> WriteProcessMemory -> ResumeThread操作打開"kyodai.exe"程式,那麼我們現在就可以模拟它的執行流程編寫程式打開它

打開VS2017編寫程式如下

#include "pch.h"
#include <iostream>
#include <windows.h>

//kyodai.exe程式的路徑
#define CATALOG L"C:\\Users\\15pb-win7\\Desktop\\連連看\\kyodai.exe"
int main()
{
	STARTUPINFO si = {};
	//操作程序的資訊結構體
	PROCESS_INFORMATION pi = {};
	//打開程序
	CreateProcess((LPWSTR)CATALOG, 0, 0, 0, FALSE,
		CREATE_SUSPENDED,//此參數為挂起主線程
		0, 0, &si, &pi);
	DWORD dwWrite = 0;
	//修改1位元組的資料
	WriteProcessMemory(pi.hProcess, (LPVOID)0x43817A, "\x0", 1, &dwWrite);
	//恢複線程
	ResumeThread(pi.hThread);
	return 0;
}
           

**12.**本人認為這段程式對咱們新手來說比較有用。在這裡要注意的是”kyodai.exe”所在路徑每個人的可能都不一樣,編譯程式後運作,打開遊戲成功!

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**13.**當然也可以直接使用16進制檔案編輯器直接找到3817A(因為預設加載基址0x400000需要減去)位址把裡面的資料改為“00”,我使用的工具是010Editor。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**14.**接下來正式分析遊戲關鍵功能了,正常的程式彙編中CALL xxx基本都是函數,運作遊戲之後多玩幾把測試一下遊戲玩法,遊戲右上角道具欄有指南針,多重新整理幾次地圖可能會出現炸彈,把炸彈消除掉道具欄裡會出現炸彈,而且道具有數量限制。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**15.**我用了CE工具查找道具基址,很遺憾找了10多分鐘沒找到,隻有換一種方法了,點選道具的時候會發出聲音,那麼音樂檔案的名字是字元串,搜尋字元串可以是個切入點。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**16.**還有點選練習的時候地圖會随機重新整理,那麼肯定會用到rand這個随機函數,親測兩種方法都能達到一樣的效果找到關鍵點,在這裡總結下查找API的方法,使用OD打開或者附加”kyodai.exe”程式先運作起來,再在OD中Ctrl+G搜尋rand函數下斷點,點選遊戲中的練習後斷了下來。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**17.**然後點選OD菜單欄上的”K”進行棧回溯分析。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

觀察發現有2個上層調用(有程式的名字的2個),他們的關系是0x41A080處的函數調用0x41CAF2的函數,0x41CAF2的函數調用rand。這裡說的比較啰嗦,反正在”K”中越靠下就越是外層的函數。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**18.**輕按兩下進入第一個位址并在上面設定斷點,然後再點K輕按兩下進入第2個位址設定斷點然後把之前rand的斷點删除

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程
QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**19.**F9運作後再次在遊戲中點選練習會在第一個斷點0x41A080位址上停下這裡是一個函數(CALL),要重點關注一下它上面行代碼MOV ECX, EDI 由于這是C++所寫的程式,它都會使用ECX這個寄存器傳遞this指針也就是傳遞一個對象,之後看見隻要對ECX寄存器操作的代碼都要留意一下。按F7進入這個函數,先Ctrl+A讓OD幫我們分析一下該子產品,發現一開始把ECX的值給了ESI,先不管這繼續單步然後沒幾步就看見了熟悉的字元串”strat.wav”(字元串搜尋也能定位到這個函數裡來),這已經證明這個函數就是初始化遊戲的函數。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**20.**然後再快速單步很快就能發現剛才所下的第二個斷點,發現rand下面有一個 memcpy複制記憶體的函數,先大緻走一遍注意觀察OD中右上角寄存器的變化,觀察寄存器上的值的記憶體的變化,走完了好像什麼也沒發現…然後再重新運作再多單步跟蹤幾次這個函數總會發現一些什麼的。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**21.**再次跟蹤這個函數,實際上剛才說過要注意ECX的值的傳遞,在這個函數裡ECX傳遞給了ESI,那麼我們要對所有操作ESI的代碼留意一下,在加上我們下的第二個斷點0x41CAF2所在附近,我們就要對它附近ESI重點關注了,在0041CAFC 位址處的這一行代碼對ESI進行了通路,走一步之後我們發現EAX的是0012BB50。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**22.**那麼再選中它右鍵->資料視窗跟随 檢視0012BB50位址裡面有些什麼資料。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**23.**然後走到0041CB10 位址處,這裡會調用memcpy複制記憶體,走一步觀察0012BB50位址裡的資料除了第一個DC 00…沒變,後面都被填充成某種規律的010101…

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**24.**在繼續走兩步經過0041CB20 位址出的函數後驚訝的發現0012BB50位址裡那一大串資料又被重新整理,到此我們大膽猜測0012BB50這就是遊戲的地圖數組基位址。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**25.**為了驗證是否正确按F9把遊戲運作起來觀察地圖與該記憶體資料的是否有聯系(觀察地圖和該記憶體時重新整理出一個特點鮮明的地圖較好,比如地圖右上角有兩個靠的近相同的東西等)我多重新整理了幾次得到一個左上角和右下角都被填滿了的地圖,觀察OD中的記憶體(記得點選下OD資料才會重新整理)也跟着改變了,貌似還找到了數組的邊界!0012BB58(第一個點)

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**26.**再重新整理幾次地圖找到第一行有兩個連着的相同的東西,發現地圖和OD中的記憶體非常相似。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**27.**為了确認 我們把遊戲中的物品點選消除掉在觀察記憶體發現果然被清0了那麼可以确定0012BB50這就是地圖數組基位址了,并且我們得到了0012BB58就是地圖資料的起始位置。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**28.**接下來分析指南針和炸彈,指南針功能是可以幫助玩家找到2個相同物品,炸彈是找到2個相同的物品并消除,這2個道具不管是誰都會周遊地圖數組,才能實作他們的功能,是以在0012BB58位址處右鍵下一個記憶體通路斷點。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**29.**先在OD中按ALT+B把其他斷點禁止或者删掉,然後運作遊戲點選指南針,程式會停下來。點選”K”進行棧回溯分析觀察他的上幾層調用函數發現有5個那麼每個都點進去設定上斷點,然後右鍵選中先把0012BB58的記憶體斷點給删除掉。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程
QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**30.**再F9運作OD再運作幾次發現都停在004292A5 位址上那麼這肯定是不需要的函數把它斷點去掉,再運作2次,點不動了需要點選遊戲界面,一點就在OD中斷下來了 是以判斷0040CACA斷點也不是我們想要的,同樣的繼續運作幾次還是都停在了0041AF11 處,這也是無用位址去掉斷點,再F9遊戲就運作起來了,這個過程多調試幾次就會明白的。

是以0041DE5C和0041E76C 處的函數就可能是我們能利用關鍵函數,現在想要寫代碼完成指南針的功能,隻要找到這兩處位址的函數調用時所需要的參數,那就可以模拟出指南針的功能。

重新運作起來,點選遊戲中的指南針,會在0041DE5C 處的代碼斷下,選中這一行按Enter建進入這個函數一直往下拉找到末尾RETN觀察傳回值發現RETN 0xC 也就是說0041DE5C 位址處的函數調用需要3個參數,在觀察堆棧得出參數是 0,0,F0。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程
QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**31.**為了确認這3個參數是不是可變的,再次運作遊戲,再點選指南針,再次在0041DE5C 停下發現堆棧裡的參數還是這麼多沒有改變,那我就決定調用了這個函數模拟指南針功能了,寫好注釋。 其實在第2個斷點0041E76C 處的參數更少,隻有2個,但是在那裡斷下來之後檢視堆棧裡的參數也不知道是些什麼,是以放棄它把它的斷點去掉。

相同的原理我再找到炸彈的調用位址,多重新整理幾次遊戲,找到有可以消除炸彈地圖,把炸彈消除了道具欄中就出現了炸彈。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**32.**同樣運作遊戲之後在0012BB58下記憶體通路斷點,再點選遊戲道具欄裡的炸彈,斷下之後再次按”K”進行棧回溯分析,發現這幾個位址很眼熟,和之前找指南針的棧回溯基本一緻 隻有一個不一樣,那麼無用幾個位址不用管他,我們在0041DE5C 處下斷點,重新整理遊戲地圖找到一個有炸彈的地圖,再使用炸彈之後停下觀察堆棧參數的變化,發現參數是0,0,F4。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

由此我們可以對比下兩次調用這個函數的參數

調用指南針是0,0,F0

調用炸彈是0,0,F4

得出結論第3個參數就是遊戲的道具類型,0041DE5C 位址處的函數功能應該就是使用道具。

**33.**談一下我對輔助中的的DLL,注入程式,原程式(這裡就是遊戲程式)他們關系的了解:我們想要DLL裡面的功能在原程式種實作,直接來是不行的,需要通過注入程式把DLL注入到原程式中,這時DLL功能才會對原程式産生影響。 這就像熱發燒了打針一樣,針筒裡的藥水就是DLL,針筒就是注入程式,人體就是原程式。

**34.**接下裡就是編寫輔助了,在這需要實作指南針和炸彈的功能,之需要模拟調用0041DE5C 位址處的函數就OK了。

我用的是VS2017首先建立一個MFC的DLL程式,選擇在靜态庫中使用MFC,這個選項也可以在屬性->正常裡面更改。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程
QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**35.**使用到的關鍵API如下

FindWindow擷取視窗句柄

SetWindowLong設定視窗回調

_beginthreadex建立線程便于彈窗

因為要在遊戲中彈出一個視窗,是以要添加一個資源Dialog

視窗回掉原型為

LRESULT

CALLBACK

DefWindowProc(

​ In HWND hWnd,

​ In UINT Msg,

​ In WPARAM wParam,

​ In LPARAM lParam);

要實作的輔助功能主要就是在這個視窗回掉函數裡面實作。

**36.**現在先使用VS中的自帶工具Spy++先查找遊戲的,視窗名,和類名,用于的FindWindow函數擷取視窗句柄。

把Spy++中的望遠鏡拖到遊戲視窗上可以可到,視窗名。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程
QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**37.**再次分析下0041DE5C 位址的函數這裡的參數是3個但之前也說過C++使用ECX傳遞對象,是以我們必須得到ECX的值,經過多次運作發現右上角的ECX值一直是0012A688是以我們直接使用這個固定值。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**38.**使用_asm内嵌彙編調用那個關鍵函數,0041DE5C 位址處彙編是CALL [EAX+0x28] ,在記憶體視窗中Ctrl+G搜尋EAX+0x28 裡面的值為0041E691(以小端方式讀) 這就是需要調用函數的位址。

LRESULT
CALLBACK
MyDefWindowProc(
	_In_ HWND hWnd,
	_In_ UINT Msg,
	_In_ WPARAM wParam,
	_In_ LPARAM lParam)
{
	//指南針消息
	if (Msg == WM_SIGN1)
	{
		_asm
		{
			MOV ECX, 0X12A688;    //this指針
			PUSH 0XF0;            //參數3是道具類型
			PUSH 0;               //參數2
			PUSH 0;               //參數1
			MOV EAX, 0X0041E691;
			CALL EAX;             //指南針函數
		}		
		return DefWindowProc(hWnd, Msg, wParam, lParam);
	}

	if (Msg == WM_SIGN2)
	{
		_asm
		{
			MOV ECX, 0X12A688;
			PUSH 0XF4;
			PUSH 0;
			PUSH 0;
			MOV EAX, 0X0041E691;
			CALL EAX;//炸彈函數
		}
		return DefWindowProc(hWnd, Msg, wParam, lParam);
	}
	return CallWindowProc(g_OldProc, hWnd, Msg, wParam, lParam);
}
           

**39.**說明一下,為了在輔助程式的視窗發送消息,我在頭檔案stdafx.h中自定義了兩個消息,然後編譯生成DLL就OK。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程
QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程
QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

40.最後編寫遠端注入程式,就建立一個控制台程式就行了,要注意的是在這裡要在屬性裡選擇C+±>代碼生成把運作庫改為多線程調試(\MTd) 就跟上面的DLL靜态編譯一樣,如果不這樣,我們寫的程式在别人的電腦上可能就運作不了。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**41.**遠端線程注入的代碼基本都固定,死記硬背就行了,在此貼上。

#include "pch.h"
#include <windows.h>
#include <string.h>

//注入DLL函數
void InjectDll(HWND hWnd, const char* DllPath)
{
	//擷取要注入的程序的PID并打開它
	DWORD dwPid = 0;
	GetWindowThreadProcessId(hWnd, &dwPid);
	HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
	if (!hProcess)
	{
		printf("打開程序失敗\n");
		getchar();
		return;
	}

	//在注入的程序中配置設定一塊虛拟記憶體
	LPVOID lpAddr = VirtualAllocEx(hProcess,
		NULL, MAX_PATH, MEM_COMMIT, PAGE_READWRITE);
	if (!lpAddr)
	{
		printf("配置設定記憶體失敗\n");
		CloseHandle(hProcess);
		getchar();
		return;
	}

	//把dll路徑寫入到目标程序空間中
	DWORD dwWrite = 0;
	WriteProcessMemory(hProcess, lpAddr, DllPath,
		strlen(DllPath) + 1, &dwWrite);
	if (strlen(DllPath) + 1 != dwWrite)
	{
		printf("dll路徑寫入失敗\n");
		VirtualFreeEx(hProcess, lpAddr, 0, MEM_RELEASE);
		CloseHandle(hProcess);
		getchar();
		return;
	}

	//建立遠端線程
	HANDLE hThread = CreateRemoteThread(hProcess, 0, 0,
		(LPTHREAD_START_ROUTINE)LoadLibraryA,
		lpAddr, 0, 0);
	if (!hThread)
	{
		printf("遠端線程建立失敗\n");
		VirtualFreeEx(hProcess, lpAddr, 0, MEM_RELEASE);
		CloseHandle(hProcess);
		getchar();
		return;
	}

	//等待線程結束(無窮大毫秒)
	WaitForSingleObject(hThread, INFINITE);

	//釋放
	VirtualFreeEx(hProcess, lpAddr, 0, MEM_RELEASE);
	CloseHandle(hThread);
	CloseHandle(hProcess);
}

//動态庫DLL的名字
#define DLLNAME "\\01連連看輔助.dll"

int main()
{
	//dll的全路徑名
	char dllNamePath[256] = {};
	//擷取DLL的全路徑
	GetCurrentDirectoryA(sizeof(dllNamePath), dllNamePath);
	strcat_s(dllNamePath, DLLNAME);	
	//擷取遊戲視窗句柄
	HWND Handle = FindWindow(NULL, L"QQ連連看");
	//調用遠端注入函數
	InjectDll(Handle, dllNamePath);
	return 0;
}
           

**42.**這裡說下遊戲輔助常用的API函數GetCurrentDirectoryA這個API可以擷取到本程式的目前目錄的字元串,隻要把要DLL放在與注入程式同一個目錄了,直接運作注入程式就注入DLL了,這個非常友善。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

**43.**把DLL檔案和注入程式生成放在同一個目錄下,先打開遊戲,然後點選注入程式,單機版連連看的輔助就順利完成了,運作秒殺效果如圖。

QQ連連看單機版輔助制作全流程QQ連連看單機版輔助制作全流程

最後感謝15PB的栽培

遊戲和源碼網盤連結:

連結:https://pan.baidu.com/s/1LyAn27Y__beBpCewMIr-WA

提取碼:oq08

繼續閱讀