11.Learn C++ with Step by Step Guide(一步步学习C++)

学校课程已经学习过了基本的内容,在GH中,C++有这些优势

  1. C/C++ 是非常低级的,它尽可能接近汇编。与学习解释型语言相比,通过学习 C/C++,您将与汇编有更密切的关系。
  2. 如果你想绕过内核反作弊,你需要学习制作内核驱动程序,这些驱动程序是用 C/C++ 制作的。

入门必看课程:
点击学习C++的前二十课,作者讲的非常好,人也很帅,看完受益匪浅,但是没有做记录,日后有时间再看再记录吧。
learncpp.com,去这个网站完成前12章节

12.Understanding Strings Unicode, TCHAR, MBCS(理解字符串)

字符串在所有工作中都是一个必不可少且重要且混乱的东西。
一天内搞懂所有字符串相关的内容不现实也没必要。
通读这些链接,之后需要用的时候再做查询即可

The Private Lives of Strings — Cunning Planning
Unicode & Windows - CunningPlanning
Unicode — Cunning Planning
The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
The Complete Guide to C++ Strings, Part I - Win32 Character Encodings - CodeProject
String and character literals (C++)
UTF-8 Everywhere

13.Get Module Base Address Tutorial dwGetModuleBaseAddress(获取基地址函数教程)

无论是internal还是external,获取module基址都是必要的。
本次课程主要学习从外部获取基地址。
还记得我们上次说的ASLR技术吗
地址空间布局随机化 - ASLR
当某些东西的地址总是在同一个地方时,很容易制造病毒和漏洞。所以大多数操作系统都添加了 ASLR 作为额外的安全层,但这是 25 年前发明的,到 2021 年基本上一文不值。ASLR 使 .exe 加载到随机虚拟地址中。
要绕过这个,您所要做的就是在运行时获取模块基地址并添加相对偏移量。
比如ac_client.exe+0x9ADBD,仅此而已。

重点内容是理解并学习使用winapi函数。
在此之前,必须介绍几个windows中的重要概念。

  1. process,module,thread的关系
    一个进程可以有多个模块,一个模块可以有多个线程,模块是相对独立的,可以是一个DLL或是EXE,线程是进程运行的最小执行单位。
    exe,dll都是module
  2. handle是什么?
    单纯翻译的话就是句柄,但是要真正讲清楚什么是句柄,很难很难,我现在也属于一知半解。
    贴出一些参考资料,通读之,未来用到继续详细看

wiki-eng
what is handle - stackoverfloat
msdn
中文wiki
百度百科

写一下自己的理解吧,handle是windows系统中非常重要的一个概念。

OBJECT and HANDLE
一个对象是一个数据结构,它表示一种系统资源,例如文件,线程或图形图像。应用程序不能直接访问对象数据或对象所代表的系统资源。相反,应用程序必须获得一个对象句柄,它可以用来检查或修改系统资源。每个句柄在内部维护的表中都有一个条目。这些条目包含资源的地址和识别资源类型的方法。

不确切不负责任的说,handle是windows中各种资源,窗口,模块,进程等等的“智能指针”。
说是“指针”是因为,它在C层面上,用户层上,面向程序员是透明的,使用起来和指针很像,都算是windows中一个实例的指针,给了Windows中各种东西一个标识。
说是“智能”是因为,他在内核层面上,操作系统通过进程句柄列表来进行维护。
更详细的,请自行查看上述资料,本人目前理解有限。
3. dll是什么?和exe的关系?怎么工作?最后给出一个dll的实际使用的C++代码。

动态链接库(英语:Dynamic-link library,缩写为DLL)是微软公司在windows系统中实现共享函数库概念的一种实现方式。
所谓动态链接,就是把一些经常会共享的代码(静态链接的OBJ程序库)制作成DLL档,当可执行文件调用到DLL档内的函数时,Windows操作系统才会把DLL档加载存储器内,DLL档本身的结构就是可执行档,当程序有需求时函数才进行链接。通过动态链接方式,存储器浪费的情形将可大幅降低。静态链接库则是直接链接到可执行文件。

尽管 DLL 和应用程序都是可执行模块,但它们在几个方面有所不同。最明显的区别是您不能运行 DLL。从系统的角度来看,应用程序和 DLL 之间有两个根本区别:
1.一个应用程序可以同时在系统中运行多个自身实例。一个 DLL 只能有一个实例。
2.应用程序可以作为进程加载。它可以拥有诸如堆栈、执行线程、全局内存、文件句柄和消息队列之类的东西。DLL 不能拥有这些东西。

个人浅薄不负责任的解释:dll就是一个面向对象概念下的产物,是一个库,库里存了一些函数代码和数据,在exe程序运行的时候可以动态调用。
更细节的东西可以自行搜索百度百科,wiki,msdn,Stack Overflow,都有很好的解释。
dll和exe的关系
DLL中虽然包含了可执行代码却不能单独执行,而应由Windows应用程序直接或间接调用。很多时候,exe缺少了某个dll就无法运行。dll will be atached to exe

Walkthrough: Create and use your own Dynamic Link Library (C++)
教程:演练:创建和使用您自己的动态链接库 (C++)

上面的教程很重要,我学习到了很多技巧,代码不是最重要的,最重要的是设置。
首先是"设置">“C/C++”>“常规”>“附加包含目录”
这里是添加.h头文件目录的
然后是"设置">“链接器”>“常规”>“附加库目录”
这里是添加.lib头文件目录的

使用dll需注意三个文件:

•.h头文件,包含dll中说明输出的类或符号原型或数据结构的.h文件。应用程序调用dll时,需要将该文件包含入应用程序的源文件中。
•.LIB文件,是dll在编译、链接成功之后生成的文件,作用是当其他应用程序调用dll时,需要将该文件引入应用程序,否则产生错误(如果不想用lib文件或者没有lib文件,可以用WIN32
API函数LoadLibrary、GetProcAddress装载)。
•dll文件,真正的可执行文件,开发成功后的应用程序在发布时,只需要有.exe文件和.dll文件,并不需要.lib文件和.h头文件。

“设置”>“链接器”>“输入”>“附加依赖项”
输入lib的名字

最重要的就是:“生成事件”选项设置
我们可以设置项目在build前后的操作。
这里使用一行简单的xcopy命令,将dll目录的dll复制到当前目录下,以便执行程序。


前情提要似乎有点过长了。。
dll代码中需要理解的就是下面这几个宏定义

#ifdef DLL_TEST_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endifextern "C" MATHLIBRARY_API unsigned long long fibonacci_current();extern "C" MATHLIBRARY_API unsigned fibonacci_index();

第一行的DLL_TEST是dll的名称,默认在生成项目的时候会预定义,之后用MATHLIBRARY_API关键字定义的函数就可以被外部exe调用了。

现在我们回归正题,来看看dwGetModuleBaseAddress函数是如何实现的。

DWORD GetProcId(const wchar_t* procName)
{DWORD procId = 0;HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);if (hSnap != INVALID_HANDLE_VALUE){PROCESSENTRY32 procEntry;procEntry.dwSize = sizeof(procEntry);if (Process32First(hSnap, &procEntry)) {do{if (!_wcsicmp(procEntry.szExeFile, procName)) {procId = procEntry.th32ProcessID;break;}} while (Process32Next(hSnap,&procEntry));}}CloseHandle(hSnap);return procId;
}uintptr_t GetMoudleBaseAddress(DWORD procId, const wchar_t* modName)
{uintptr_t modBaseAddr = 0;HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);if (hSnap != INVALID_HANDLE_VALUE){MODULEENTRY32 modEntry;modEntry.dwSize = sizeof(modEntry);if (Module32First(hSnap, &modEntry)){do{if (!_wcsicmp(modEntry.szModule, modName)){modBaseAddr = (uintptr_t)modEntry.modBaseAddr;break;}} while (Module32Next(hSnap,&modEntry));}CloseHandle(hSnap);return modBaseAddr;}return 0;
}
int main()
{//get procId of the processDWORD procId = GetProcId(L"sauerbraten.exe");//get moduleBaseAddressuintptr_t moduleBase = GetMoudleBaseAddress(procId, L"sauerbraten.exe");
}

因为是学习笔记,所以我就用自己的方式来解释和记录,获取最准确的资料请自行上google使用关键词+msdn搜索即可。
首先要使用GetProcId函数获取进程的ID,这个过程用到了几个关键的winapi

  • CreateToolhelp32Snapshot获取指定进程的快照,以及这些进程使用的堆、模块和线程。当使用TH32CS_SNAPPROCESS作为参数时,生成一个系统中的所有进程的快照。
  • Process32Next从系统快照中找到下一个进程信息。
  • PROCESSENTRY32是一个结构体,用于描述快照中进程的entry。
  • CloseHandle是一个用于关闭一个打开的句柄的函数。

函数整体思路就是,获取当前所有进程的句柄,遍历,根据进程名找到procId并返回。
其中DWORD,uintptr_t都是自适应的无符号型整数型变量。
字符串前加L表明是unicode编码的文本。

有了procId,我们就可以找进程地址了。
这里的思路和上面类似,对进程的modules做个快照,然后遍历,对比名字,从modentry结构体中确定基地址。
使用的部分windowsAPI:

  • Module32First是用来检索有关与进程关联的第一个模块的信息。
  • MODULEENTRY32是一个结构体,用于描述某个特定proc一系列module的entry。

这个过程都是外部的,如果在内部,简单调用一个windowsAPI函数即可

uintptr_t pEngine = (uintptr_t)GetModuleHandle("engine.dll");

14.FindDMAAddy - C++ Multilevel Pointer Function(使用C++多级指针找到动态地址)

多级指针的理解,简单讲就是多个结构体之间用指针链接起来,偏移的含义其实就是每个结构体内到当前指针或者数值前分配了多少内存空间。
下面是外部的根据多级指针获取动态地址的函数

uintptr_t FindDMAddress(HANDLE hProc, uintptr_t ptr, std::vector<unsigned int> offsets)
{uintptr_t addr = ptr;for (unsigned int i = 0; i < offsets.size(); i++) {ReadProcessMemory(hProc, (BYTE*)addr, &addr, sizeof(addr), nullptr);addr += offsets[i];}return addr;
}//get handle of the processHANDLE hProcess = 0;hProcess = OpenProcess(PROCESS_ALL_ACCESS, NULL, procId);//resolve base address of pointer chainuintptr_t dynamicPtrBaseAddr = moduleBase + 0x312930;std::cout<< "DynamicPtrBaseAddr= " << "0x" <<std::hex << dynamicPtrBaseAddr << std::endl;//resolve our health chainstd::vector<unsigned int> healthOffsets = { 0x0, 0x118, 0x340 };uintptr_t healthAddr = FindDMAddress(hProcess, dynamicPtrBaseAddr, healthOffsets);std::cout << "healthAddr= " << "0x" << std::hex << healthAddr << std::endl;//read health value int healthValue = 0;ReadProcessMemory(hProcess, (BYTE*)healthAddr, &healthValue, sizeof(healthAddr), nullptr);std::cout << "Current health = " << std::dec << healthValue << std::endl;//write to itint superHealth = 2021;WriteProcessMemory(hProcess, (BYTE*)healthAddr, &superHealth, sizeof(healthAddr), nullptr);//read ammo againReadProcessMemory(hProcess, (BYTE*)healthAddr, &healthValue, sizeof(healthAddr), nullptr);std::cout << "Current health = " << std::dec << healthValue << std::endl;

上面的代码中涉及了几个在外部非常重要的WindowsAPI

  • ReadProcessMemoryWriteProcessMemory,这两个函数的功能是根据proc句柄和地址读写内存数据,读的时候句柄必须具有对进程的 PROCESS_VM_READ 访问权限。
    写的时候句柄必须具有对进程的 PROCESS_VM_WRITE 和 PROCESS_VM_OPERATION 访问权限。
  • OpenProcess用于打开一个现在存在的进程对象,返回其句柄,参数可以设置具体的句柄权限

当然FindDMAAddress的内部版本就很简单了

uintptr_t FindDMAAddress(uintptr_t ptr, std::vector<unsigned int> offsets)
{uintptr_t addr = ptr;for (unsigned int i = 0; i < offsets.size() ; ++i){addr = *(uintptr_t*)addr;addr += offsets[i];}return addr;
}

15.How to Hack Any Game Tutorial C++ Trainer #1 - External(外部trainer教程1)

已经没什么好写的了,最后给出一个多级指针模板吧

Address = Value = ?

base ptr -> address + offset4 = address
base ptr -> address + offset3 = address
base ptr -> address +> offset2 = address
static base -> address + offset1 = address

源代码地址

游戏黑客圣经GHB1学习笔记 part3(11-15)相关推荐

  1. 游戏黑客圣经GHB1学习笔记 part1(1-5)

    游戏黑客圣经(Game Hacking Bible1) 我在这里记录我所有课程的学习笔记,包括一些小技巧以及源码,俗话说好记性不如烂笔头,写在这里,用于温故而知新. 前言 学习游戏黑客的必备条件 智力 ...

  2. 游戏黑客圣经GHB1学习笔记 part4(16-20)

    16.How to Hack Any Game Tutorial C++ Trainer #2 - External v2(如何破解游戏-外部2) 这次我们需要记住的是两个比较重要的WindowsAP ...

  3. 《游戏设计艺术(第2版)》——学习笔记(11)第11章 玩家的动机驱使着玩家的脑

    <游戏设计艺术(第2版)>学习笔记(11) 第11章 玩家的动机驱使着玩家的脑 需求 更多需求 内在动机.外在动机 想做与得做 创新 评断 第11章 玩家的动机驱使着玩家的脑 我们先来面对 ...

  4. 《Go语言圣经》学习笔记 第十一章 测试

    <Go语言圣经>学习笔记 第十一章 测试 目录 go test 测试函数 测试覆盖率 基准测试 剖析 示例函数 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. Go语 ...

  5. 《Go语言圣经》学习笔记 第十章 包和工具

    <Go语言圣经>学习笔记 第十章 包和工具 目录 包简介 导入路径 包声明 导入声明 包的匿名导入 包和命名 工具 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. G ...

  6. 《Go语言圣经》学习笔记 第九章 基于共享变量的并发

    <Go语言圣经>学习笔记 第九章 基于共享变量的并发 目录 竞争条件 sync.Mutex互斥锁 syn.RWMutex读写锁 内存同步 syn.Once初始化 竞争条件检测 示例:并发的 ...

  7. 《Go语言圣经》学习笔记 第八章 Groroutines和Channels

    <Go语言圣经>学习笔记 第八章 Groroutines和Channels 目录 Goroutines 实例:并发的Clock服务 实例:并发的Echo服务 Channels 并发的循环 ...

  8. 《Go语言圣经》学习笔记 第五章函数

    <Go语言圣经>学习笔记 第五章 函数 目录 函数声明 递归 多返回值 匿名函数 可变参数 Deferred函数 Panic异常 Recover捕获异常 注:学习<Go语言圣经> ...

  9. 《Go语言圣经》学习笔记 第七章 接口

    <Go语言圣经>学习笔记 第七章 接口 目录 接口是合约 接口类型 实现接口的条件 flag.Value接口 接口值 sort.Interface接口 http.Handle接口 erro ...

最新文章

  1. Leetcode 173. 二叉搜索树迭代器 解题思路及C++实现
  2. input失去焦点验证格式_input获取、失去焦点对输入内容做验证
  3. 沈石溪事件持续发酵 韩国将严查体育界暴力事件
  4. 脸书令牌怎么使用_网工知识角|QOS技术令牌桶算法一分钟速记,考试无忧
  5. oracle01144,ORA-01144
  6. alpha and beta in statistics
  7. testbench文件显示波形_十大基本功之testbench
  8. 社交网络影响力最大化
  9. nginx HTML网页乱码
  10. 电动车整车控制器VCU控制: 信号处理、车辆状态控制及扭矩计算控制、附件控制、
  11. 我是怎么打开车库门的:ASK/OOK手动解码及重放
  12. Pymoo:优化算法收敛性的实例分析
  13. java习题小分享【关于statis你知道多少】
  14. JAVA学习日记DAY09--javaweb的一些简单应用
  15. 最短路——最短路(spfa)
  16. 转:数据可视化之美:经典案例与实践解析
  17. AB32VG1项目之智能晾衣架
  18. 深入浅出IOC和DI---学习记录
  19. 汽车创新人士Rick Tewell晋升为Velodyne Lidar首席运营官
  20. 浏览器原理 39 # 页面性能工具:如何使用 Performance?

热门文章

  1. 深度解析微信移动支付跨平台软件架构
  2. SEO伪原创工具图片转文字ocr识别工具
  3. LWN: 5.12 合并窗口,第一部分!
  4. 动物猜测专家系统——实现二叉树查找
  5. golang管道chan
  6. 利用IO流一次性读取文件中的所有内容,利用IO流下载文件
  7. 《安检违禁品图像生成与评价网络模型研究》阅读笔记
  8. 关于系统开发(软件工程框架构建)的一点迷思
  9. 有工程师思维吗?什么是工程师思维?
  10. 第一次取 Google 西联汇款的辛酸经历