欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 产业 > 【软件逆向】QQ 连连看小游戏去广告与一键消除实现

【软件逆向】QQ 连连看小游戏去广告与一键消除实现

2025/3/11 12:29:09 来源:https://blog.csdn.net/linshantang/article/details/146151295  浏览:    关键词:【软件逆向】QQ 连连看小游戏去广告与一键消除实现

目录

一、背景介绍

二、去广告实现

2.1 分析广告加载流程

2.2 逆向分析广告加载逻辑

2.3 去广告方案

三、一键消除外挂实现

3.1 分析游戏逻辑

3.2 编写外挂插件

3.3 注入外挂:

四、一键消除效果展示

五、额外扩展


一、背景介绍

        QQ 连连看是一款经典的休闲小游戏,但部分版本中嵌入了广告,影响了用户体验。本文将详细介绍如何通过逆向工程和编程技术,去除游戏中的广告,并实现一键消除功能。

二、去广告实现

2.1 分析广告加载流程

1. 运行程序:
        双击 `qqllk.exe`,弹出第一个广告窗口。
        点击“开始游戏”按钮,弹出第二个广告窗口(百度广告)。
        点击“继续”按钮后,真正的游戏窗口 `kyodai.exe` 启动。


        通过 PChunter32 查看可知 qqllk.ocx 是 qqllk.exe 的子进程广告程序,qqllk.exe 又是 explorer.exe 的子进程。在百度广告窗口点击继续按钮就打开了真正的游戏窗口 kyodai.exe。

2.程序结构:
使用 `PEid` 扫描程序文件夹,发现以下文件:
        `qqllk.exe`:Delphi 编写的程序。
        `qqllk.ocx`:是一个加 aps 壳可执行文件,负责广告加载。
        `kyodai.exe`:真正的游戏程序。

火绒剑检测 Qqllk.ocx 行为,发现修改了 Keyodai.exe
直接运行 `kyodai.exe` 无法启动游戏,因为 `qqllk.ocx` 修改了 `kyodai.exe` 的行为。

2.2 逆向分析广告加载逻辑

1. 使用 OD(OllyDbg)调试:
        将 `qqllk.exe` 拖入 OD,在 `CreateWindowExW` 和 `CreateProcessW` API 下断点。
        分析广告窗口的创建和游戏进程的启动过程。

2. 广告窗口分析:
        第一个广告窗口通过 `CreateWindowExW` 创建。


        第二个广告窗口通过 `CreateProcessW` 启动 `qqllk.ocx`。

        下图是第二个程序进程

        第二个广告窗口

        打开第二个 OD,附加或者直接打开第二个广告程序,但是要先设置 strongOD 才能调试多个

然后重启 OD。CreateprocessA 或 W 下断点

查看到 kyodai.exe 被创建即被挂起

直接用另一个 OD 打开游戏程序找到 winmain 函数

跟进去看看,一看貌似没有恢复

当执行完第二个广告后 Winmain 代码被改变,游戏程序便能正常执行

猜测是第二个广告程序在创建游戏进程挂起的时候修改了 winmian 的地方。
那么我们可以在 Qqllk.ocx 程序中的 resumethread 和 writeprocessmemory 下断点

然后执行唤起操作

总结游戏进程修改:
        `qqllk.ocx` 在启动 `kyodai.exe` 时,将其挂起并修改其内存(如 `WinMain` 函数)。
        使用 OD 附加 `kyodai.exe`,发现 `WinMain` 函数在广告加载后被修改。

2.3 去广告方案

由此去广告暂时有了两个方案:
1、只要启动 keyoai.exe 到指定的 0x43817A 地址上修改,使用 loadPE 计算出这个地址在文件
中的位置,然后将其值修改成 0 就可以了。
2、通过运行第二个广告程序后,运行到游戏程序的 OEPC 处直接 dump。

直接用第二种方式:
现在第一个 OD 运行 Qqllk.ocx,执行到唤起处,
另外一个 OD 附加 keyoai.exe,然后查看内存,查看 PE 头,找到 OEP 下断,
第一个 OD 继续执行,另外一个 OD 继续执行到 OEP 处直接 dump 出来即可。

到此处 dump

然后可以直接双击打开运行 dump 出来的程序,即可正常运行。

三、一键消除外挂实现

3.1 分析游戏逻辑

思路一 : 指南针 配合清除函数
1.根据 ce 搜索到减少道具数值的地方
2.跟出减少道具数值函数
3.来到 调用减少道具数值函数的地方

4.查找是谁调用的减少道具数值函数
5.即可找到关键点 道具分发函数 f0-fb 间
6.可以通过该函数调用多个道具

思路二 : 查找炸弹函数

可以先从简单的思路二入手,尝试查找炸弹函数,内联汇编调用
经过观察,可以通过炸弹的声效文件 flystar.wav 查找所有参考文本字串

查找所有命令 push 00459250

全部命令下断点,再次运行游戏,玩到点击炸弹的时候,断点在下图

然后查看堆栈调用

回车,在此下断点,重新运行游戏(注意每次运行游戏可以选 A 级别然后点击练习可以简
单点),玩到获得炸弹道具后,点击炸弹道具,运行到此后单步步过执行

执行到此发现 edx 发生变化,多次执行其他道具可以发现

指南针对应 edx = F0
重列对应 edx = F1
炸弹对应 edx = F4
执行完 0041de5c 处后断到 0041ec07,执行完后炸弹减少,两个卡牌消失
在此往上找到 case F4,可知是道具分支调用

因此 0041de5c 处 call 的是道具分发函数
由此内嵌调用以下汇编代码即可调用炸弹做出一个小外挂

0041DE4D |. 8B86 94040000 MOV EAX,DWORD PTR DS:[ESI+0x494] ; dump.0044CE70
0041DE53 |. 8D8E 94040000 LEA ECX,DWORD PTR DS:[ESI+0x494]
0041DE59 |. 52 PUSH EDX
0041DE5A |. 53 PUSH EBX
0041DE5B |. 53 PUSH EBX
0041DE5C |. FF50 28 CALL DWORD PTR DS:[EAX+0x28]

据观察,edx,ebx的赋值容易,但是要找esi的值。

但是由于栈保存的值不是固定的,所以要找到固定的。

可以打开CE软件,打开调试进程查找12A1F4,找到几个静态地址

经过测试上面三个绿色地址都可以赋值给esi。

3.2 编写外挂插件

1. 创建 MFC DLL 工程:
        使用 Visual Studio 创建 MFC DLL 项目,命名为 `QQPlugin`。

2. 关键代码实现:
        在 `QQPlugin.cpp` 中实现炸弹功能的调用:    

#include "stdafx.h"#include "QQPlugin.h"#include "QQPlugindll.h"#ifdef _DEBUG#define new *DEBUG_NEW*#endif// CQQPluginApp*BEGIN_MESSAGE_MAP*(CQQPluginApp, *CWinApp*)*END_MESSAGE_MAP*()// CQQPluginApp 构造CQQPluginApp::CQQPluginApp(){// TODO:  在此处添加构造代码,// 将所有重要的初始化放置在 InitInstance 中}// 唯一的一个 CQQPluginApp 对象CQQPluginApp theApp;// CQQPluginApp 初始化#define WM_MOD_WINNAME *WM_USER*+110*LRESULT* *CALLBACK* WindowProc(*HWND* hWnd, *UINT* uMsg,*WPARAM* wParam, *LPARAM* lParam){if (uMsg== WM_MOD_WINNAME){*OutputDebugString*(L"ok");}else if (uMsg== *WM_KEYDOWN*){if (wParam== *VK_F**1*){int BaseAddr = 0x45DEBC;int m_Esi = *(int*)BaseAddr;_asm{mov esi, [m_Esi];mov eax, dword *ptr* ds : [esi + 0x494];lea ecx, dword *ptr* ds : [esi + 0x494];*push* 0xf4;*push* ebx;*push* ebx;*call*dword *ptr* ds : [eax + 0x28];}}return *DefWindowProc*(hWnd, uMsg, wParam, lParam);}return *CallWindowProc*(theApp.m_pOldProc, hWnd, uMsg, wParam, lParam);}*UINT* __stdcall ThreadProc(*PVOID* pVar){// 初始化,防止崩溃*AFX_MANAGE_STATE*(*AfxGetStaticModuleState*());QQPlugindll* pDlg= new QQPlugindll;pDlg->*Create*(IDD_DIALOG1);pDlg->*ShowWindow*(*SW_SHOW*);pDlg->*RunModalLoop*();return 0;}*BOOL* CQQPluginApp::InitInstance(){//CWinApp::InitInstance();*OutputDebugString*(L"InitInstance");m_hMainWnd= *FindWindow*(*NULL*, L"QQ连连看");m_pOldProc = (*WNDPROC*)*SetWindowLongPtr*(m_hMainWnd, *GWLP_WNDPROC*,(*LONG_PTR*)WindowProc);::*SendMessage*(m_hMainWnd, WM_MOD_WINNAME, 0, 0);// 创建线程,在线程中启动一个对话框*_beginthreadex*(0, 0, ThreadProc, this, 0, 0);return *TRUE*;}

        在 `QQPlugindll.cpp` 中实现一键消除功能:

#include "stdafx.h"#include "QQPlugin.h"#include "QQPlugindll.h"#include "afxdialogex.h"// QQPlugindll 对话框*IMPLEMENT_DYNAMIC*(QQPlugindll, *CDialogEx*)QQPlugindll::QQPlugindll(*CWnd** pParent /*=NULL*/): *CDialogEx*(IDD_DIALOG1, pParent){}QQPlugindll::~QQPlugindll(){}void QQPlugindll::DoDataExchange(*CDataExchange** pDX){*CDialogEx*::*DoDataExchange*(pDX);}*BEGIN_MESSAGE_MAP*(QQPlugindll, *CDialogEx*)*ON_BN_CLICKED*(IDC_BUTTON1, &QQPlugindll::OnBnClickedButton1)*END_MESSAGE_MAP*()// QQPlugindll 消息处理程序//循环炸弹void QQPlugindll::OnBnClickedButton1(){// TODO: 在此添加控件通知处理程序代码for (int i= 0; i< 100; i++){::*SendMessage*(theApp.m_hMainWnd, *WM_KEYDOWN*, *VK_F**1*, 0);}}

3.3 注入外挂:

        使用注入工具将生成的 DLL 文件注入到游戏进程中。
        运行游戏后,点击外挂窗口的“一键消除”按钮,即可实现一键消除功能。

四、一键消除效果展示

        一键消除效果:点击外挂窗口的按钮,快速消除所有卡牌。

五、额外扩展

一键消除解决完后,可以再说说思路一的做法:

每次按练习后都会随机生成地图,由此可以给关键api函数下断,bp rand

找到地图数据

483AC8 地图数据地址

483AC8内存拷贝给12BB50

12BB50=[Esi+0x195C] 地图地址

地图数组首地址是12BB50,但是数据开始的地方是12BB58,前面八个字节没用。

在点击游戏中两张相同卡牌或点击指南针之前,找两个相同数字靠在一起的下硬件访问断点

尝试断下来通过栈回溯找指南针函数和消除函数的地方

总结

        通过逆向分析和编程技术,我们成功去除了 QQ 连连看中的广告,并实现了一键消除功能。本文详细介绍了去广告和外挂实现的思路与步骤,希望对读者有所帮助。需要注意的是,此类技术仅用于学习和研究,请勿用于非法用途。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词