【软件逆向-Win10扫雷分析】此文章归类为:软件逆向。
首先用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的版本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
#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,
// default security attributes
0,
// use default stack size
MyThreadFunction,
// thread function name
0,
// argument to thread function
0,
// use default creation flags
0);
// returns the thread identifier
WaitForSingleObject(hThread, INFINITE);
CloseHandle(g_hProcess);
return
0;
}
|
更多【软件逆向-Win10扫雷分析】相关视频教程:www.yxfzedu.com