继上次破解扫雷后,这是我上手破解的第二个小游戏,这次选择的目标是QQ连连看,但是并不是QQ游戏里面的网络版,是从网上找的单机版,毕竟我QQ号这么多年了,我怕他封我号{:301_980:}
水平有限,水平有限
破解连连看并不是说玩个小游戏都需要去使用作弊手段,只是为了学习思路和方法{:1_893:}
此游戏辅助功能实现仅为新手小白就是我,利用游戏自带的CALL实现的一些基础功能,没有大佬的深度学习,神经网络(这里的词汇是我想到的比较牛X的词汇,不一定与此相关),纯新手文章,不足之处还望各位大佬指出,感谢{:1_893:}
代码部分:
MFCLLK.zip
(2.71 MB, 下载次数: 382)
连连看游戏链接:链接:https://pan.baidu.com/s/176znO8k00sUM5Pc-BOCg9g 提取码:7gx9
PS:先展示一下最终成品辅助界面
一、数据分析
1.游戏时间
找到时间的地址,之后通过NOP时间可以实现0秒通关的效果。
1.1
2.方块数量
同样的搜索方法寻找到方块数量,其实这里最后也没用上。
1.2
二、游戏分析
1.在rand函数处下断点
由于连连看游戏每一局的方块排布都是不相同的,所以肯定会有Rand函数,这里就从Rand函数的位置下手
2.1.1
2.重新排列游戏时触法断点,通过栈回溯寻找数组基地址
2.2.1
3.在初始化数组的下方找到了疑似初始化操作的地址,循环结束后对比内存中的数据与游戏数据
这个位置需要多观察,尤其需要注意数据窗口的情况
2.3.1
4.循环结束后观察内存数据与游戏界面,可以发现相同值对应的图案也相同
2.4.1
5.接下来分析指南针道具,设置内存访问断点
2.5.1
6.程序断下来都进行栈回溯,因为不能明确具体是哪一个CALL,故将每个CALL都设置上断点,逐一尝试
2.6.1
2.6.2
7.找到指南针连接的两个地址
2.7.1
2.7.2
2.7.3
8.寻找ECX赋值的位置,此处复制ESI的值去CE中搜索
2.8.1
2.8.2
9.确定45DEBC为我们寻找的地址
2.9.1
三、DLL注入
1.使用PCHunter查看连连看程序的消息钩子
3.1.1
2.使用Spy++获取窗口名
3.1.2
3.编写对应功能代码
①指南针
1)指南针CALL调用顺序
调用道具CALL
0041DE5C |. FF50 28 CALL DWORD PTR DS:[EAX+0x28] ; 使用道具 41E691
调用指南针CALL
0041E696 . E8 C5960100 CALL kyodai1.00437D60 ; 指南针 41E76C
获取连接点
0041E76C . E8 CEAA0000 CALL kyodai1.0042923F ; 获取两个可以连接的点
2)测试代码
[C] 纯文本查看 复制代码 if (Msg == WM_DATA1)
{
//指南针
OutputDebugString(L"指南针");
//0x45DEBC
//0041DE4D | . 8B86 94040000 MOV EAX, DWORD PTR DS : [ESI + 0x494]
//0041DE53 | . 8D8E 94040000 LEA ECX, DWORD PTR DS : [ESI + 0x494] ; ECX赋值
//0041DE59 | . 52 PUSH EDX
//0041DE5A | . 53 PUSH EBX
//0041DE5B | . 53 PUSH EBX
//0041DE5C | .FF50 28 CALL DWORD PTR DS : [EAX + 0x28] ; 使用道具 41E691
_asm {
mov ecx,0x45DEBC
mov ecx, [ecx]
lea ecx,DWORD PTR ds:[ecx + 0x494]
push 0xF0
push 0
push 0
mov eax,0x0041E691
call eax
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
②实现单消
1)在连连看的数据窗口下一个内存写入断点
3.3.1
2)通过栈回溯找到调用的CALL
3.3.2
3)在反汇编代码中找到消除CALL
3.3.3
4)测试代码
[C] 纯文本查看 复制代码 if (Msg == WM_DATA2)
{
//0041E75E > \8B8E F0190000 MOV ECX, DWORD PTR DS : [ESI + 0x19F0] ; Case F0(BM_GETCHECK) of switch 0041E749
//0041E764 . 8D45 D8 LEA EAX, DWORD PTR SS : [EBP - 0x28]
//0041E767 . 50 PUSH EAX
//0041E768 . 8D45 E0 LEA EAX, DWORD PTR SS : [EBP - 0x20]
//0041E76B . 50 PUSH EAX
//0041E76C.E8 CEAA0000 CALL kyodai1.0042923F; 获取两个可以连接的点
//1.获取可以连接的两个点
POINT pt1 = { 0 };
POINT pt2 = { 0 };
_asm {
mov ecx, 0x45DEBC
mov ecx, [ecx]
lea ecx, DWORD PTR ds : [ecx + 0x494]
mov ecx, DWORD PTR ds : [ecx + 0x19F0]
lea eax, pt1.x
push eax
lea eax, pt2.x
push eax
mov eax, 0x0042923F
call eax //获取可以消除的图案坐标
}
CString strCode;
strCode.Format(L"pt1:%d,%d pt2:%d,%d", pt1.x, pt1.y, pt2.x, pt2.y);
OutputDebugString(strCode.GetBuffer());
//2.调用消除CALL
//00129BB8 00000000 0
//00129BBC 0012BB50 数组地址
//00129BC0 00129BEC 坐标点1
//00129BC4 00129BF4 坐标点2
//00129BC8 014AB930 坐标点数组
//00129BCC 00000002 数值
_asm {
mov ecx, 0x45DEBC
mov ecx, [ecx] //传递ecx的值
push 0x4 //参数1 固定值
lea eax, DWORD PTR ds : [ecx + 0x494] //0012BB50
mov eax, DWORD PTR ds : [eax + 0x19F0]
add eax, 0x40
push eax //参数2 变量地址 坐标数组地址
lea eax, pt1.x //参数3 点1地址
push eax
lea eax, pt2.x //参数4 点2地址
push eax
lea eax, DWORD PTR ds : [ecx + 0x494] //014AB930
mov eax, DWORD PTR ds : [eax + 0x19F0]
mov eax, DWORD PTR ds : [eax + 0x4]
push eax //参数5 数组地址
push 0 //参数6 0
mov eax, 0x0041C68E //CALL kyodai1.0041C68E
call eax //调用消除
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
③全屏消除
1)全屏消除原理是在单消的基础上增加一个循环,直至消除完成,则退出循环
3.3.4
2)测试代码
[C] 纯文本查看 复制代码 //全屏消除
CMFCLLKApp* pApp = (CMFCLLKApp*)AfxGetApp();
//循环消除
for (size_t i = 0; i < 100; i++)
{
int nRet = ::SendMessage(pApp->m_hWnd, WM_DATA2, 0, 0);
if (nRet == -1)
{
break;
}
}
//判断循环结束,即坐标点为0
if (pt1.x == 0 && pt1.x == pt1.y)
{
return -1;
}
④实现炸弹
1)寻找道具炸弹的参数
3.3.5
3.3.6
2)炸弹使用效果
3.3.7
3)测试代码
[C] 纯文本查看 复制代码 if (Msg == WM_DATA3)
{
//炸弹
OutputDebugString(L"炸弹");
_asm {
mov ecx, 0x45DEBC
mov ecx, [ecx]
lea ecx, DWORD PTR ds : [ecx + 0x494]
push 0xF4 //与指南针道理大致相同,仅道具的参数不同(指南针此处为0xF0)
push 0
push 0
mov eax, 0x0041E691
call eax
}
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
⑤道具拓展
代码部分均参考道具炸弹的修改部分,即可实现其余拓展道具功能
1)闹钟道具
3.5.1
3.5.2
2)镜子道具
3.5.3
3.5.4
3)禁手道具
3.5.5
4)蒙眼道具
3.5.6
5)障碍道具
3.5.7
6)重列道具
3.5.8
⑥无限时间
NOP时间关键代码,这里的时间比扫雷的还要简单一点
1)使用CE工具NOP掉DEC DWORD PTR DS:[ESI+0xC0]
3.6.1
2)根据CE原理编写NOP代码
这里的NOP代码和扫雷基本上是一致的,扫雷还需要NOP两个位置的时间自增,这里只有一个地方,更简单一点
[C] 纯文本查看 复制代码 //获取连连看进程ID
GetWindowThreadProcessId(hWnd, &Pid);
//获取连连看进程句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Pid);
//将时间自增的语句使用NOP填充
result = WriteProcessMemory(hProcess, (LPVOID)g_pTime, &szInc, 6, 0);
3)注入DLL
注入前
3.6.2
注入后
3.6.3
4)游戏效果图展示
3.6.4
|