首先用x64dbg附加扫雷程序
依照路径把扫雷程序复制出来,因为这个文件夹咱们没有权限
复制出来之后发现有il2cpp_data这个文件夹,之后发现global-metadata.dat,没有加密
就可以推断出这个是unity写的il2cpp加密的程序,而且是没有经过变形的
下载Il2CppDumper,点击Il2CppDumper.exe 依次选择游戏的GameAssembly.dll 和data文件夹下的global-metadata.dat
自动解析之后会生成DummyDll文件夹,把里面的Assembly-CSharp.dll拖进dnspy反汇编软件
然后我们把GameAssembly.dll拖入IDA中来进行分析,方便接下来看代码
接下来就是寻找各个数据,首先我们先看一下各个名称,依照名字来对比,可以看出来,挑战模式、网格数据、经典模式等
这里我以经典模式为例子,先总体都看一下代码,然后我们看到Gameplay.Board.Data里面的BoardConfigData有一个get_TileCount获取网格数量的并且是有高度和宽度的,我们点击这个函数,并在提示的位置,设置断点,然后跟过来看一下,刚好看到了我想要的数据,并同时 确定了这个位置就是我们需要的宽和高,还有中间的numberOfMines (雷的数量)
接下来就是寻找雷区数据的分布了,上面的还可以用ce来确定,但是雷区数量不是非常的方便用ce来寻找,
首先我们可以看到public class ClassicModeTileData : TileData, IClassicModeTileData, ITileData
ClassicModeTileData继承了这3个我们挨个看一下父类的代码,TileData里面的get_IsMine也许我们用的到,接下来我们在这个位置设置断点
我们可以看到已经断下来了,接着我们堆栈寻找ecx是如何来的,这个位置会来好几次,有好几个调用这个位置的代码,我们需要多测试几次,每个断点仔细的看一下
代码观察一下,会看到这个位置来了两遍,在结合之前看的反编译的代码,我们可以知道这是链表,它的意思是每一行一个链表然后再把链表在组合起来(个人猜测)
最后就是开始标志位,这个位置我就没有在代码里面找了,以为之前的几个数据要是找到了的话,那么必然的标志位在某一个指针内部,然后我通过逐级查看每一级的指针内存,看到在0xD8的位置上如果是0就说明还没有点击过,点击过之后就会生成雷区了
以下是我简易实现了一下8乘8的版本
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <vector>
uintptr_t
g_baseAddress = 0;
HANDLE
g_hProcess = NULL;
uintptr_t
GetModuleBaseAddress(
DWORD
processId,
const
wchar_t
* moduleName) {
HANDLE
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processId);
if
(hSnapshot == INVALID_HANDLE_VALUE) {
return
0;
}
MODULEENTRY32 moduleEntry;
moduleEntry.dwSize =
sizeof
(MODULEENTRY32);
if
(Module32First(hSnapshot, &moduleEntry)) {
do
{
if
(_wcsicmp(moduleEntry.szModule, moduleName) == 0) {
CloseHandle(hSnapshot);
return
reinterpret_cast
<
uintptr_t
>(moduleEntry.modBaseAddr);
}
}
while
(Module32Next(hSnapshot, &moduleEntry));
}
CloseHandle(hSnapshot);
return
0;
}
uintptr_t
uIsStart(_In_
HANDLE
hProcess,
uintptr_t
baseAddress)
{
bool
b =
false
;
std::vector<
uintptr_t
> offsets = { 0x03116DF0, 0x430, 0xa0, 0xd8 };
for
(
uintptr_t
offset : offsets) {
b = ReadProcessMemory(hProcess,
reinterpret_cast
<
LPCVOID
>(baseAddress + offset), &baseAddress,
sizeof
(baseAddress), NULL);
}
return
baseAddress;
}
uintptr_t
MinListPoint(_In_
HANDLE
hProcess,
uintptr_t
baseAddress)
{
std::vector<
uintptr_t
> offsets = { 0x03116DF0, 0x430, 0xa0, 0x70,0x10,0x10,0x10 };
for
(
uintptr_t
offset : offsets) {
ReadProcessMemory(hProcess,
reinterpret_cast
<
LPCVOID
>(baseAddress + offset), &baseAddress,
sizeof
(baseAddress), NULL);
}
return
baseAddress;
}
uintptr_t
MinListOnePoint(_In_
HANDLE
hProcess,
uintptr_t
baseAddress,
int
offsets)
{
ReadProcessMemory(hProcess,
reinterpret_cast
<
LPCVOID
>(baseAddress + 0x10), &baseAddress,
sizeof
(baseAddress), NULL);
ReadProcessMemory(hProcess,
reinterpret_cast
<
LPCVOID
>(baseAddress + 0x20 + offsets * 8), &baseAddress,
sizeof
(baseAddress), NULL);
return
baseAddress;
}
DWORD
WINAPI MyThreadFunction(
LPVOID
lpParam)
{
uintptr_t
mapMinListPointOld = 0;
uintptr_t
mapMinListPoint = 0;
while
(
true
)
{
uintptr_t
uStart = uIsStart(g_hProcess, g_baseAddress);
if
(uStart != 0)
{
mapMinListPoint = MinListPoint(g_hProcess, g_baseAddress);
if
(mapMinListPointOld != mapMinListPoint)
{
mapMinListPointOld = mapMinListPoint;
printf
(
"\n"
);
printf
(
"\n"
);
for
(
int
y = 7; y > -1; y--)
{
uintptr_t
mapMinListLinePoint = MinListOnePoint(g_hProcess, mapMinListPoint, y);
for
(
int
x = 0; x < 8; x++)
{
uintptr_t
mapMinListOnePoint = MinListOnePoint(g_hProcess, mapMinListLinePoint, x);
int
nMin = 0;
ReadProcessMemory(g_hProcess,
reinterpret_cast
<
LPCVOID
>(mapMinListOnePoint + 0x1c), &nMin,
sizeof
(nMin), NULL);
if
(nMin)
{
printf
(
"1"
);
}
else
{
printf
(
"0"
);
}
}
printf
(
"\n"
);
}
}
}
Sleep(1000);
}
return
0;
}
int
main() {
const
wchar_t
* processName = L
"Minesweeper.exe"
;
const
wchar_t
* moduleName = L
"GameAssembly.dll"
;
DWORD
processId = 0;
HANDLE
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if
(hProcessSnap != INVALID_HANDLE_VALUE) {
PROCESSENTRY32 processEntry;
processEntry.dwSize =
sizeof
(PROCESSENTRY32);
if
(Process32First(hProcessSnap, &processEntry)) {
do
{
if
(_wcsicmp(processEntry.szExeFile, processName) == 0) {
processId = processEntry.th32ProcessID;
break
;
}
}
while
(Process32Next(hProcessSnap, &processEntry));
}
CloseHandle(hProcessSnap);
}
if
(processId != 0) {
g_baseAddress = GetModuleBaseAddress(processId, moduleName);
if
(g_baseAddress != 0) {
std::wcout << L
"The base address of "
<< moduleName << L
" in "
<< processName << L
" is 0x"
<< std::hex << g_baseAddress << std::endl;
}
else
{
std::wcout << L
"Module "
<< moduleName << L
" not found in process "
<< processName << std::endl;
}
}
else
{
std::wcout << L
"Process "
<< processName << L
" not found"
<< std::endl;
}
g_hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
if
(g_hProcess == NULL) {
std::cerr <<
"Failed to open the process. Error code: "
<< GetLastError() << std::endl;
return
1;
}
HANDLE
hThread = CreateThread(
NULL,
0,
MyThreadFunction,
0,
0,
0);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(g_hProcess);
return
0;
}
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
#include <vector>
uintptr_t
g_baseAddress = 0;
HANDLE
g_hProcess = NULL;
uintptr_t
GetModuleBaseAddress(
DWORD
processId,
const
wchar_t
* moduleName) {
HANDLE
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processId);
if
(hSnapshot == INVALID_HANDLE_VALUE) {
return
0;
}
MODULEENTRY32 moduleEntry;
moduleEntry.dwSize =
sizeof
(MODULEENTRY32);
if
(Module32First(hSnapshot, &moduleEntry)) {
do
{
if
(_wcsicmp(moduleEntry.szModule, moduleName) == 0) {
CloseHandle(hSnapshot);
return
reinterpret_cast
<
uintptr_t
>(moduleEntry.modBaseAddr);
}
}
while
(Module32Next(hSnapshot, &moduleEntry));
}
CloseHandle(hSnapshot);
return
0;
}
uintptr_t
uIsStart(_In_
HANDLE
hProcess,
uintptr_t
baseAddress)
{
bool
b =
false
;
std::vector<
uintptr_t
> offsets = { 0x03116DF0, 0x430, 0xa0, 0xd8 };
for
(
uintptr_t
offset : offsets) {
b = ReadProcessMemory(hProcess,
reinterpret_cast
<
LPCVOID
>(baseAddress + offset), &baseAddress,
sizeof
(baseAddress), NULL);
}
return
baseAddress;
}
uintptr_t
MinListPoint(_In_
HANDLE
hProcess,
uintptr_t
baseAddress)
{
std::vector<
uintptr_t
> offsets = { 0x03116DF0, 0x430, 0xa0, 0x70,0x10,0x10,0x10 };
for
(
uintptr_t
offset : offsets) {
ReadProcessMemory(hProcess,
reinterpret_cast
<
LPCVOID
>(baseAddress + offset), &baseAddress,
sizeof
(baseAddress), NULL);
}
return
baseAddress;
}
uintptr_t
MinListOnePoint(_In_
HANDLE
hProcess,
uintptr_t
baseAddress,
int
offsets)
{
ReadProcessMemory(hProcess,
reinterpret_cast
<
LPCVOID
>(baseAddress + 0x10), &baseAddress,
sizeof
(baseAddress), NULL);
ReadProcessMemory(hProcess,
reinterpret_cast
<
LPCVOID
>(baseAddress + 0x20 + offsets * 8), &baseAddress,
sizeof
(baseAddress), NULL);
return
baseAddress;
}
DWORD
WINAPI MyThreadFunction(
LPVOID
lpParam)
{
uintptr_t
mapMinListPointOld = 0;
uintptr_t
mapMinListPoint = 0;
while
(
true
)
{
uintptr_t
uStart = uIsStart(g_hProcess, g_baseAddress);
if
(uStart != 0)
{
mapMinListPoint = MinListPoint(g_hProcess, g_baseAddress);
if
(mapMinListPointOld != mapMinListPoint)
{
mapMinListPointOld = mapMinListPoint;
printf
(
"\n"
);
printf
(
"\n"
);
for
(
int
y = 7; y > -1; y--)
{
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)