游戏安全入门-扫雷分析远程线程注入

前言

无论学习什么,首先,我们应该有个目标,那么入门windows游戏安全,脑海中浮现出来的一个游戏 – 扫雷,一款家喻户晓的游戏,虽然已经被大家分析的不能再透了,但是我觉得自己去分析一下还是极好的,把它作为一个小目标再好不过了。

我们编写一个妙妙小工具,工具要求实现以下功能:时间暂停、修改表情、透视、一键扫雷等等。

本文所用工具:

Cheat Engine、x32dbg(ollydbg)、Visual Studio 2019

扫雷游戏分析

游戏数据在内存中是地址,那么第一个任务,找内存地址

打开CE修改器

修改时间->时间暂停

计数器的时间是一个精确的值,所以我们通过精确数值扫描出来,游戏开始之前计数器上的数是0,所以我们扫描0。

image.png

时间在变化,选择介于什么数值之间再次扫描

image.png

可得 0x100579c — winmine.exe+579C

image.png

我们发现这个数据都是直接通过基址 + 固定偏移能直接得到的。

然后我们对数据去找 是什么改写了这个地址,得到一个指令和指针:

image.png

时间:0x100579c

修改表情 - 没啥用

修改表情这个功能怎么搞我觉得还是很容易想到的,这个按钮的作用是重新开始游戏,开始游戏,游戏胜利,游戏失败。

(表情的状态被分成了两个变量(4byte)来控制)

所以它是一种状态,所以我们通过0和1进行扫描,游戏进行状态输入1进行扫描,还原游戏之后输入0进行扫描。

首先是游戏进行状态,输入1进行扫描

image.png

再点击表情,将游戏还原,输入0开始扫描

image.png

如此反复进行扫描,得到表情的内存地址

0x1005164 – winmine.exe+5164

image.png

但是嘞,修改成2或者3,表情没有心得反应,所以控制游戏胜利和游戏失败的是其他的地址,我们知道,一般来说,一个功能的代码在内存中基本上都是连续的,(就像你修改一个游戏的血量,浏览血量内存块,你可以发现怒气,蓝量等内存地址)

所以,我们浏览内存

image.png

image.png

0x1005164-4 = 0x1005160

修改为3,发现出现了戴墨镜的表情(游戏胜利)

但是这个胜利知识一个状态,并不能说明扫雷完成.

image.png

表情:0x1005160与0x1005164

帮助网安学习,全套资料S信免费领取:
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

透视 - 显示雷区

思考游戏结束的时候会自动显示所有的雷,因此我们动态调试,看看在哪个函数调用之后会显示所有的雷

image.png

image.png

经过几次的动态调试之后发现:0x2F80函数是我们要找的结果。

image.png

一键扫雷

通过透视,我们玩一把游戏,使得游戏胜利(点完最后一个)

image.png

image.png

然后后两个函数,是破纪录跟英雄榜的函数

image.png

image.png

ret来到了这儿,游戏通关了,来到了这儿,可以知道,这个0x347c就是判断输赢的函数

并且通过调试发现由一个参数 0 1 来控制,所以跟透视差不多,带个参数线程回调就完了

image.png

编写妙妙小工具

怎么实现这个工具呢,当然是选择DLL注入

那么dll 怎么注入进去呢,这里选择远程线程注入

这里先简单介绍下什么是远程线程注入

前置知识-动态调用dll

主要就是这几个个 API:

LoadLibraryA

加载指定 DLL 并返回模块句柄,参数为字符串,就是 dll 的路径。

GetProcAddress

获取指定 dll 的导出函数的地址。

第一个参数是模块句柄,第二个参数是模块函数,返回值为函数的地址。

通过这两个函数,我们可以拿到所有函数的地址,然后就能进行调用。

CreateThread - 远程线程注入

里面几乎只有一个参数,那就是线程回调函数,然后当然还有返回地址,返回线程 id 啥的,这里我们都可以不用管,几乎是与 Linux 的创建线程函数一致。

还有一个远程版本的叫 CreateRemoteThread,它可以给别的进程创建一个线程并可以在本进程创建那个进程调用的回调函数。我们可以在回调函数中加载指定的 dll,在 dllmain 的入口当中,有一个 switch 的四个选项。

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"BOOL APIENTRY DllMain( HMODULE hModule,//指向自身的句柄DWORD  ul_reason_for_call,//调用原因LPVOID lpReserved//隐式加载or显式加载)
{switch (ul_reason_for_call){case DLL_PROCESS_ATTACH://附加到进程上时执行case DLL_THREAD_ATTACH://附加到线程上时执行case DLL_THREAD_DETACH://从线程上剥离时执行case DLL_PROCESS_DETACH://从进程上剥离时执行break;}return TRUE;
}

我们可以在 DLL_PROCESS_ATTACH 的选项中加入代码,让它在加载的时候调用执行。

那么我们的步骤是:

  1. 打开指定进程获得句柄
  2. 开辟远程进程的空间,分配可读可写段。
  3. 调用 WriteProcessMemory 将 dll 路径写入该内存区域。
  4. 创建远程线程,回调函数使用 LoadLibrary 加载指定 dll。
  5. 等待返回(loadLibrary返回)
  6. 释放空间
  7. 释放句柄
  8. 返回结果
demo:
void Inject(DWORD ProcessId, const char* szPath)
{//1.打开目标进程获取句柄HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);printf("进程句柄:%p\n", hProcess);//2.在目标进程体内申请空间LPVOID lpAddress = VirtualAllocEx(hProcess, NULL, 0x100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);//3.写入DLL路径SIZE_T dwWriteLength = 0;WriteProcessMemory(hProcess, lpAddress, szPath, strlen(szPath), &dwWriteLength);//4.创建远程线程,回调函数使用 LoadLibrary 加载指定 dllHANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryA, lpAddress, NULL, NULL);//5.等待返回(loadLibrary返回)WaitForSingleObject(hThread, -1);//6.释放空间VirtualFreeEx(hProcess, lpAddress, 0, MEM_RELEASE);//7.释放句柄CloseHandle(hProcess);CloseHandle(hThread);//返回结果AfxMessageBox(L"完成");
}

编写DLL注入器

#include<windows.h>
#include<iostream>
#include<time.h>
#include<stdlib.h>
#include<TlHelp32.h>
DWORD FindProcess() {HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);PROCESSENTRY32 pe32;pe32 = { sizeof(pe32) };BOOL ret = Process32First(hSnap, &pe32);while (ret){if (!wcsncmp(pe32.szExeFile, L"mine.exe", 11)) {printf("Find winmine.exe Process %d\n", pe32.th32ProcessID);return pe32.th32ProcessID;}ret = Process32Next(hSnap, &pe32);}return 0;
}
void Inject(DWORD ProcessId, const char* szPath)
{//1.打开目标进程获取句柄HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);printf("进程句柄:%p\n", hProcess);//2.在目标进程体内申请空间LPVOID lpAddress = VirtualAllocEx(hProcess, NULL, 0x100, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);//3.写入DLL路径SIZE_T dwWriteLength = 0;WriteProcessMemory(hProcess, lpAddress, szPath, strlen(szPath), &dwWriteLength);//4.创建远程线程,回调函数使用 LoadLibrary 加载指定 dllHANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryA, lpAddress, NULL, NULL);//5.等待返回(loadLibrary返回)WaitForSingleObject(hThread, -1);//6.释放空间VirtualFreeEx(hProcess, lpAddress, 0, MEM_RELEASE);//7.释放句柄CloseHandle(hProcess);CloseHandle(hThread);
}int main() {DWORD ProcessId = FindProcess();while (!ProcessId) {printf("未找到扫雷程序,等待两秒中再试\n");Sleep(2000);ProcessId = FindProcess();}printf("开始注入进程...\n");Inject(ProcessId, "E:\\CODE\\wimine\\Mine\\release\\Mine.dll");printf("注入完毕\n");}

编写DLL

这里我们采用MFC DLL 基于对话框 (dialog)的方式编写(简单),使用静态编译的方式

image.png

image.png

然后我们需要在资源窗体,新建一个 Dialog ,简单包装一个界面

image.png

这样我们在加载窗体的时候需要创建一个窗体类对象用它的 DoModal 方法去显示,用线程回调的方式加载并且初始化InitInstance

DWORD WINAPI DlgThreadCallBack(LPVOID lp) {MineDlg* Dlg;Dlg = new MineDlg();Dlg->DoModal();delete Dlg;FreeLibraryAndExitThread(theApp.m_hInstance, 1);return 0;
}
// CMineApp 初始化
BOOL CMineApp::InitInstance()
{CWinApp::InitInstance();::CreateThread(NULL, NULL, DlgThreadCallBack, NULL, NULL, NULL);return TRUE;
}

时间暂停

上面我们找到了它控制时间增加的指令,我们把它们全部 NOP 掉,就可以实现时间暂停

写两个按钮,创建下面的事件实现时间暂停开关。

image.png

DWORD GetBaseAddr() {HMODULE hMode = GetModuleHandle(nullptr);//LPWSTR s = (LPWSTR)malloc(0x100);//wsprintf(s, L"基址:%p", hMode);//AfxMessageBox(s);return (DWORD)hMode;
}void MineDlg::OnBnClickedButton1() // 时间暂停
{// TODO: 在此添加控件通知处理程序代码auto BaseAddr=GetBaseAddr();DWORD TimeOffset = 0x579C;DWORD TimeInsOffset = 0x2FF5;DWORD InsLen = 6;DWORD old;VirtualProtect((void*)(BaseAddr + TimeInsOffset), InsLen, PAGE_EXECUTE_READWRITE, &old);BYTE INS[] = { 0x90,0x90,0x90,0x90,0x90,0x90 };memcpy((void *)(BaseAddr + TimeInsOffset), INS, InsLen);VirtualProtect((void*)(BaseAddr + TimeInsOffset), InsLen, old, &old);
}void MineDlg::OnBnClickedButton2() // 恢复字节即可取消时间暂停
{// TODO: 在此添加控件通知处理程序代码auto BaseAddr = GetBaseAddr();DWORD TimeOffset = 0x579C;DWORD TimeInsOffset = 0x2FF5;DWORD InsLen = 6;DWORD old;VirtualProtect((void*)(BaseAddr + TimeInsOffset), InsLen, PAGE_EXECUTE_READWRITE, &old);BYTE INS[] = { 0xFF,0x05,0x9C,0x57,0x00,0x01 };memcpy((void*)(BaseAddr + TimeInsOffset), INS, 6);VirtualProtect((void*)(BaseAddr + TimeInsOffset), InsLen, old, &old);
}

测试

image.png

透视

经过上面动态调试我们得出结论:0x2F80函数是踩雷函数。

我们如果调用这个函数,是不是就能够实现透视了呢?

我们依旧采取线程回调的方式

void MineDlg::OnBnClickedButton3()
{// TODO: 在此添加控件通知处理程序代码DWORD ESPOffset = 0x2f80;DWORD FuncAddr = GetBaseAddr() + ESPOffset;// 创建不带参数的线程CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FuncAddr, NULL, 0, NULL);
}

测试

image.png

一键扫雷

跟透视差不多,只不过创建带参数的线程回调

void MineDlg::OnBnClickedButton4()
{// TODO: 在此添加控件通知处理程序代码DWORD ESPOffset = 0x347C;DWORD FuncAddr = GetBaseAddr() + ESPOffset;//创建带参数的线程struct { int a; } s = { 0 };CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)FuncAddr, &s, NULL, NULL);}

测试

image.png

总结

通过这个小项目,对WIN游戏安全有初步的认识,并且加强对软件的逆向思维,增强动态调试的能力,找到软件关键的基地址,通过CE修改器,初步pojie软件,了解软件的状态,修改时间(时间暂停等等),理解几个重要的API,FindWindow获取句柄,WriteProcessMemory写入内存信息,LoadLibraryA加载指定 DLL 并返回模块句柄,GetProcAddress,获取指定 dll 的导出函数的地址,CreateThread 线程回调函数等等。多写,多做,多调,多实验,加油,互勉。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHPStorm 环境配置与应用详解

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; PHPStorm 是 JetBrains 出品的一款专业 PHP 集成开发环境&#xff08;IDE&#xff09;&#xff0c;凭借其智能的代码补全、调试功能、深度框架支持和前端开发工具&#xff0c;为用户提供了丰富的功能和工具…

Systools Outlook PST Recovery Outlook PST邮箱邮件数据修复工具下载

可正常激活使用&#xff0c;非常强大好用的PST邮箱邮件数据文件修复工具 下载地址(资源制作整理不易&#xff0c;下载使用需付费&#xff0c;不能接受请勿浪费时间下载) 链接&#xff1a;https://pan.baidu.com/s/1bfkVNrgdaVS2MkTnW19Zqw?pwdu2sj 提取码&#xff1a;u2sj

Linux进程间通信学习记录(无名管道)

0.Linux进程间通信的方式 &#xff08;1&#xff09;.从UNIX继承过来的通信方式 无名管道&#xff08;pipe&#xff09; 有名管道&#xff08;fifo&#xff09; 信号&#xff08;signal&#xff09; &#xff08;2&#xff09;.System V IPC 共享内存 消息队列 信号灯集 &am…

Python环境安装及PIP安装(Mac OS版)

官网 https://www.python.org/downloads/ 安装python python-3.12.1-macos11.pkg下载后&#xff0c;安装一直下一步即可 验证是否安装成功&#xff0c;执行python3命令和pip3命令 配置环境变量 获取python3安装位置并配置在.bash_profile #查看python路径 which python3#…

centos8以上系统安装docker环境

由于docker官方更新了相关镜像路由&#xff0c;导致国内用户无法正常手段安装使用docker&#xff0c;本人推荐使用下面操作进行安装。 1.docker-ce安装 # 添加docker-ce仓库&#xff0c;本次使用的是阿里云的仓库 dnf config-manager --add-repo https://mirrors.aliyun.com/do…

CoCoOp(论文解读):Conditional Prompt Learning for Vision-Language Models

摘要 随着预训练的视觉语言模型&#xff08;如 CLIP&#xff09;的兴起&#xff0c;研究使这些模型适应下游数据集的方法变得至关重要。最近CoOp方法将NLP领域中的提示学习引入到视觉领域中&#xff0c;来调整预训练的视觉语言模型。具体来说&#xff0c;CoOp 将提示中的上下文…

【C语言初阶】C语言指针全攻略:解锁C语言深层奥秘的钥匙

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C语言 “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;C语言操作符 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀指针 &#x1f4d2;1. 指针和指…

前端各种文本文件预览 文本编辑excel预览编辑 pdf预览word预览 excel下载pdf下载word下载

前端各种文本文件预览 文本编辑excel预览编辑 pdf预览word预览 excel下载pdf下载word下载 各种文本文件预览&#xff08;pdf, xlsx, docx, cpp, java, sql, py, vue, html, js, json, css, xml, rust, md, txt, log, fa, fasta, tsv, csv 等各种文本文件&#xff09; 其中 除p…

C 408—《数据结构》算法题基础篇—数组(通俗易懂)

目录 Δ前言 一、数组的合并 0.题目&#xff1a; 1.算法设计思想&#xff1a; 2.C语言描述&#xff1a; 3.算法的时间和空间复杂度 : 二、数组元素的倒置 0.题目 : 1.算法设计思想 : 2.C语言描述 : 3.算法的时间和空间复杂度 : 三、数组中特定值元素的删除 0.题目 : …

SpringBoot3 + Flowable7 工作流引擎使用笔记

目录 Flowable 简介流程设计器安装使用 SpringBoot 3 整合表结构流程部署启动流程流程审批流程挂起和激活任务分配固定分配表达式分配值表达式方法表达式 监听器分配 流程变量运行时变量历史变量 身份服务候选人拾取任务归还任务指派给别人候选人组创建用户创建用户组用户关联用…

VueUse 基于 Vue 3 Composition API 的高质量 Hooks 库

VueUse 是什么? VueUse 是基于 Vue 3 Composition API 的高质量 Hooks 库。例如获取滚动的距离 VueUse 官网:VueUse | VueUse VueUse 什么使用? 1、通过npm安装 VueUse npm i @vueuse/core 2、搜索需要使用的函数,例如搜索 useScroll 滚动 3、使用useScroll 滚动函数 …

C语言传递指针给函数

C 语言允许您传递指针给函数&#xff0c;只需要简单地声明函数参数为指针类型即可。 下面的实例中&#xff0c;我们传递一个无符号的 long 型指针给函数&#xff0c;并在函数内改变这个值 实例1&#xff1a;获取系统的时间值 能接受指针作为参数的函数&#xff0c;也能接受数…

为什么Pandas是最流行的Python数据分析库?

本文将从Python生态、Pandas历史背景、Pandas核心语法、Pandas学习资源四个方面去聊一聊Pandas&#xff0c;期望能带给大家一点启发。 一、Python生态里的Pandas 五月份TIOBE编程语言排行榜&#xff0c;Python追上Java又回到第二的位置。Python如此受欢迎一方面得益于它崇尚简…

零成本 API 服务搭建,用 GitHub Actions 自动爬取文章?

前言 本着将成本降到最低&#xff0c;我目前做的应用或小程序都是单机的&#xff0c;也就是不用请求接口&#xff0c;只要一上架就没有任何支出。但是写死的数据毕竟有限&#xff0c;应用的内容单一无法紧跟时事热点&#xff0c;每次打开一个样&#xff0c;自然就没有留存。遇…

Redis13-多级缓存

目录 概述 JVM进程缓存 Caffeine 实现进程缓存 Lua语法 初识Lua 变量和循环 Lua的数据类型 声明变量 循环 条件控制、函数 函数 条件控制 实现多级缓存 安装OpenResty OpenResty快速入门 请求参数处理 查询Tomcat 发送http请求的API 封装http工具 CJSON工…

CSS小玩意儿:文字适配背景

一&#xff0c;效果 二&#xff0c;代码 1&#xff0c;搭个框架 添加一张背景图片&#xff0c;在图片中显示一行文字。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" conte…

【Python】高效的Web自动化测试利器—Python+Playwright快速上手自动化实战指南(限时开放)

文章目录 前言一.playwright是什么二.python引入playwright1.安装2.playwright命令行参数3.playwright codegen自动生成代码4.Chrome和Chromium有什么关系&#xff1f; 三.基本概念1. 无头浏览器&#xff08;Headless Browser&#xff09;2.同步和异步模式操作playwright2.1.同…

SQL每日一练-0815

今日SQL题难度&#xff1a;&#x1f31f;☆☆☆☆☆☆☆☆☆ 1、题目要求 计算每个产品类别在每个月的总销售额和总销量。找出每个月销售额最高的产品类别&#xff0c;显示类别名称、销售月份、总销售额和总销量。 2、表和虚拟数据 现有两个表&#xff1a;Products 和…

RockerMQ学习

消息中间件以前常用RabbitMQ和ActiveMQ&#xff0c;由于业务需要&#xff0c;后期业务偏向大数据&#xff0c;现着重学习一下RocketMQ&#xff08;RocketqMQ原理同ctg-mq&#xff09;&#xff0c;后续更新Kafka 一、RocketMQ特性 Kafka特性 &#xff08;高性能分布式&#xff…

day34-nginx常用模块

## 0. 网络面试题 网络面试题: TCP三次握手 TCP四次挥手 DNS解析流程 OSI七层模型 抓包工具 tcpdump RAID级别区别 开机启动流程 如何实现不同的网段之间通信(路由器) ip route add 192.168.1.0 255.255.255.0 下一跳的地址或者接口 探测服务器开启了哪些端口(无法登录服务器…