【软件逆向】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 连连看中的广告,并实现了一键消除功能。本文详细介绍了去广告和外挂实现的思路与步骤,希望对读者有所帮助。需要注意的是,此类技术仅用于学习和研究,请勿用于非法用途。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/984506.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小白学Agent技术[5](Agent框架)

文章目录 Agent框架Single Agent框架BabyAGIAutoGPTHuggingGPTHuggingGPT工作原理说明GPT-EngineerAppAgentOS-Copilot Multi-Agent框架斯坦福虚拟小镇TaskWeaverMetaGPT微软UFOAgentScope现状 常见Agent项目比较概述技术规格和能力实际应用案例开发体验比较ChatChain模式 Agen…

AI写论文提示词指令大全,快速写论文

目录 一、十大学术写作提示词1、研究主题2、研究问题3、论文架构4、学术论证5、文献关键要素6、专业文本可读性转换7、学术语言规范化8、提高语言准确性9、多维度、深层论证10、优化文本结构 二、快速写论文提示词1、确认研究选题2、整理相关资料3、快速完成论文大纲4、整合文献…

电子电气架构 ---常见车规MCU安全启动方案

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…

HCIP第二讲作业

一、连接拓扑图 二、配置要求 1.学校内部的HTTP客户端可以正常通过域名www.baidu.com访问到百度网络中的HTTP服务器 2.学校网络内部网段基于192.168.1.0/24划分&#xff0c;PC1可以正常访问3.3.3.0/24网段&#xff0c;但是PC2不允许 3.学校内部路由使用静态路由&#xff0c;R1…

Linux第六讲:进程控制

Linux第六讲&#xff1a;进程控制 1.进程创建1.1回顾fork1.2写时拷贝 2.进程终止2.1exit与_exit 3.进程等待3.1进程等待的方法&#xff08;wait和waitpid&#xff09; 4.进程程序替换4.1自定义shell的编写4.1.1输出命令行提示符4.1.2获取用户输入的命令4.1.3命令行分析4.1.4指令…

BI 工具响应慢?可能是 OLAP 层拖了后腿

在数据驱动决策的时代&#xff0c;BI 已成为企业洞察业务、辅助决策的必备工具。然而&#xff0c;随着数据量激增和分析需求复杂化&#xff0c;BI 系统“卡”、“响应慢”的问题日益突出&#xff0c;严重影响分析效率和用户体验。 本文将深入 BI 性能问题的根源&#xff0c;并…

PPT内视频播放无法播放的原因及解决办法

PPT内视频无法播放&#xff0c;通常是视频编解码的问题。目前我遇到的常见的视频编码格式有H.264&#xff0c;H.265&#xff0c;VP9&#xff0c;AV1这4种。H.264编解码的视频&#xff0c;Windows原生系统可以直接播放&#xff0c;其他的视频编码格式需要安装对应的视频编解码插…

【AIGC系列】6:HunyuanVideo视频生成模型部署和代码分析

AIGC系列博文&#xff1a; 【AIGC系列】1&#xff1a;自编码器&#xff08;AutoEncoder, AE&#xff09; 【AIGC系列】2&#xff1a;DALLE 2模型介绍&#xff08;内含扩散模型介绍&#xff09; 【AIGC系列】3&#xff1a;Stable Diffusion模型原理介绍 【AIGC系列】4&#xff1…

Navigation的进阶知识与拦截器配置

Navigation的进阶知识与拦截器配置 写的不是很详细&#xff0c;后续有时间会补充&#xff0c;建议参考官方文档食用 1.如何配置路由信息 1.1 创建工程结构 src/main/ets ├── pages │ └── navigation │ ├── views │ │ ├── Mine.ets //…

多模态推理模型相关开源工作

多模态推理模型相关开源工作 1. 训练策略1.1 R1-V① 介绍② 训练流程③ 关键注意点④ 主要问题⑤ 是否可以去掉 KL 约束&#xff1f; 1.2 open-r1-multimodal① 介绍② 代码改进 1.3 VisualThinker-R1-Zero① 研究意义② 训练方法③ 结论④ 代码改进⑤ 其他发现 1.4 Efficient-…

LaTex安装流程(附安装包)LaTex超详细保姆级图文安装教程

文章目录 前言一、LaTex下载二、Texlive 2024安装教程三、Texstudio安装教程 前言 本安装流程将以清晰、易懂的方式&#xff0c;详细的价绍 LaTeX安装教程&#xff0c;助你顺利踏入专业排版的大门 。 一、LaTex下载 LaTeX 是由美国计算机科学家莱斯利・兰伯特&#xff08;Les…

Ultravox:融合whisper+llama实现audio2text交互

Ultravox是由Fixie AI开发的一种创新型多模态大语言模型,专为实时语音交互设计。与传统的语音交互系统不同,Ultravox无需单独的语音识别(ASR)阶段,可以直接理解文本和人类语音,实现更快速、更自然的交互体验。Ultravox v0.5在语音理解基准测试中超越了OpenAI的GPT-4o Realt…

KL散度详解与应用

前言 本文隶属于专栏《机器学习数学通关指南》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见《机器学习数学通关指南》 ima 知识库 知识库广场搜索&#…

【Java并发】【synchronized】适合初学者体质入门的synchronized

&#x1f44b;hi&#xff0c;我不是一名外包公司的员工&#xff0c;也不会偷吃茶水间的零食&#xff0c;我的梦想是能写高端CRUD &#x1f525; 2025本人正在沉淀中… 博客更新速度 &#x1f44d; 欢迎点赞、收藏、关注&#xff0c;跟上我的更新节奏 &#x1f4da;欢迎订阅专栏…

数据库的搭建

一、MySQL的安装 第一种&#xff1a; 直接下载相应的软件&#xff1a; 比如说MySQL installer、或者phpstudy第二种&#xff1a; 1.压缩包下载 下载地址&#xff1a;https://downloads.mysql.com/archives/community/ 2.解压软件包 将MySQL软件包解压在没有中文和空格的目…

React:类组件(上)

kerwin老师我来了 类组件的创建 class组件&#xff0c;js里的类命名首字符大写&#xff0c;类里面包括构造函数&#xff0c;方法 组件类要继承React.Component才有效 必须包含render方法 import React from react class App extends React.Component{render() {return <…

以教育之道御AI之术:培养未来人才的关键策略

在当今这个人工智能(AI)技术日新月异的时代,AI已经渗透到我们生活的方方面面,教育领域也不例外。然而,面对AI的浪潮,我们不仅要学会利用它来提升教学效率,更要坚守教育的本质,即“以教育之道御AI之术”,培养出能够适应未来社会需求的创新型人才。 AI技术为教育带来的…

基于qiime2的16S数据分析全流程:从导入数据到下游分析一条龙

目录 创建metadata 把数据导入qiime2 去除引物序列 双端合并 &#xff08;dada2不需要&#xff09; 质控 &#xff08;dada2不需要&#xff09; 使用deblur获得特征序列 使用dada2生成代表序列与特征表 物种鉴定 可视化物种鉴定结果 构建进化树&#xff08;ITS一般不构建进化树…

DeepSeek V3 并行训练、推理优化点(一)

训练优化1&#xff0c; FP8计算 DeepSeek-V3在训练过程中统一使用E4M3格式&#xff0c;并通过细粒度的per-tile&#xff08;1x128&#xff09;和per-group&#xff08;128x128&#xff09;量化来降低误差。 FP8的好处还体现在节省显存上&#xff08;尤其是激活值&#xff09;…

comctl32!ListView_OnSetItem函数分析LISTSUBITEM结构中的image表示图标位置

第一部分&#xff1a; BOOL ListView_SetSubItem(LV* plv, const LV_ITEM* plvi) { LISTSUBITEM lsi; BOOL fChanged FALSE; int i; int idpa; HDPA hdpa; if (plvi->mask & ~(LVIF_DI_SETITEM | LVIF_TEXT | LVIF_IMAGE | LVIF_STATE)) { …