| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 游戏开发 -> UE4引擎分析获取UWordGNameGetNameGObjectArray -> 正文阅读 |
|
[游戏开发]UE4引擎分析获取UWordGNameGetNameGObjectArray |
UE4引擎具有很多固定特征和特性所以我们在逆向UE4引擎开发的游戏的时候,可以利用这些特征和特性. 当然,正常思路逆向也是没问题的(例如我们的ttw课程全数据逆向),你就当多了一个针对于该引擎逆向的快捷方式 或则多了一个思路即可. 正常逆向+引擎分析,使逆向结果全面且快速. 了解一下我们的学习顺序, 先熟悉UE4特性,找到UWord,GName,GetName,GObject等关键数据(入门阶段不使用IDA,但是效率更快) 然后把这些数据跟正常逆向的关系对应清晰,以提高对UE4的熟悉 再学习UE4正向开发和源码,从根本上了解该引擎 最后完整性dump游戏数据,边角数据用逆向方式补全即可 1.查看游戏的引擎版本首先我们来查看游戏引擎版本 游戏启动程序所在目录如下:(任何UE4游戏都是类似目录) 我们可以右键属性查看游戏版本,如果长期分析经验以后,可以根据版本做出更多的判断 实际情况还是我们跟着最新版本即可,老版本等于淘汰. 下面这个4.26.2.0 已经是目前的新版本了 同时需要注意,附加进程也是 2.UWorld首先我们先来获取一下UE4引擎中的UWorld. UWorld其实就是世界数组基地址 . 世界数组基地址下面挂着一个包含所有对象的数组,这在我们讲FPS专题的时候已经讲解过了,忘了的同学可以翻回FPS转体复习一下. 根据ue4引擎世界对象数组的特点,我们可以采取以下方式来进行扫描, 例如 打枪数组对象数量 +1或则+2,拿出手雷 +1或者+2,也就是说出现新物品+不定数量,还有什么增加方式,大家可以找到以后多观察一下. 例如手雷增加,原本手雷不在模型上显示,打出的子弹也是有对象的,所以子弹打中某个碰撞体也会增加。 RPG也是相同,对象只会增加不会减少这是他的一个很容易被利用的特点,所以我们就利用这个道理进行扫描. 进入游戏,选择一个小地图,方便我们可以搜少点的值 搜索0-1000 像障碍物或则目标开枪 搜索增加的数值 增加可能是1可能是2 最终可以锁定地址 到OD中下断追表达式: r14+B0 往上继续追 得到表达式 r15+B0 追到函数头部 得到表达式 [rcx+30]+B0 返回,发现 [rax+30]+B0 此时RAX 来源于一个call 这地方有三种方法 第一种直接调call 取得的返回值就是 UWORD 里的值 第二种方法直接CE搜索就可以搜索到UWORD的基地址 UWorld = deathlystillnessgame-win64-shipping.exe+460F4F0 第三种也可以继续逆向来源 call 内来源 继续进call, 由于是虚表可以进入很多位置,算法也都不同 其中有一个是我们追熟悉的位置 再进call 好像发现了什么吗? 就是天堂W里类似取对象的call,可以参考天堂W,他的过程类似于一个加密过程,忘记了 可以回去看下天堂W课程 其实这里追不到UWORD的基地址,但是我们得到的加密表达式 是可以执行UWORD里的的,一样是可以当UWORD来使用. 相比之下,低版本的UE4的UWORD就比较好找了 例如 低版本吃鸡模拟器的世界数组数量如下: [["BattleRoyaleTrainer-Win64-Shipping.exe"+2AF0FB8] +138 ]+ b8 [["BattleRoyaleTrainer-Win64-Shipping.exe"+2AF0FB8 ] +30 ]+ b8 "BattleRoyaleTrainer-Win64-Shipping.exe"+2AF0FB8就是UWORD 经过了正常逆向,我们看看还有什么快捷方式来搜索到UWORD 就是引擎特征码了. 我们用XDBG 搜索所有模块字符串,需要等待一会,速度会比较慢,用IDA搜索这个速度更慢 xdbg搜索字符串: SeamlessTravel FlushLevelStreaming 剩余唯一一个结果 用IDA搜索这个速度慢,而且IDA搜索到的位置可能会不全,可以用xdbg搜索字符串,用IDA查看伪代码 跳转到这个地址向上翻可以得到btr edx,0x7,再向上遇到的第一个基地址,就是UWorld UWorld = deathlystillnessgame-win64-shipping.exe+460F4F0 跟我们正常逆向的结果一样的 当然,正常逆的方式是比较通用的,特征的方式很容易在几个版本之后失效,当然失效以后,我们可以在通过正向开发的方式找到新的特征不是吗? 有了UWORD ,实际上我们就能遍历到周围环境所有对象. 3.GName什么是GName?GName保存着UE4整个世界对象的名字 世界对象下只有Key(可以理解成名称ID),没有直接的名字的,所以想要获取名字必须要先搞定GName 说的直白点,GName是存放游戏里面所有名称字符串的基地址 分析清晰这些字符串的结构 然后通过GetName函数(也就是从Key到字符串的转换)调用取得名称字符串 名称字符串内存中的格式一般如下: None ByteProperty ... ... 前两个 一般是None 和ByteProperty CE扫描ByteProperty, 以后版本不是 ByteProperty怎么办? 可以正向编译一个最新版本,看看里面任意一个相对比较特殊的字符串即可,我们不是要一个精确的位置 一个大概的位置即可 所有地址拉下来 CTRL+b 挨个查看,找到连续字符串,并且开头第一个是None,当然目前所有版本都是这样,改动我们可以人为识别 观察结构 就是 2字节+一个字符串 再2字节 再一个字符串 以此类推(后面我们会知道这个2字节就是加密长度) 那么ByteProperty字符串 - 8 的位置应该就是结构头部 CE直接搜索 2024E3C0008 - 8 = 2024E3C0000 直接得到基地址 , 再 -10就是 GName GName = "DeathlyStillnessGame-Win64-Shipping.exe"+44BDB80 这里直接说他是GName视乎有些无赖,其实就是无赖... 那么我们用正常逆向的方法来追到GName以及GetName算法 4.GetName 我们对字符串下访问断,例如ByteProperty 小退或则开始游戏会断下 字符串下断
返回追rcx 追字符串是什么表达式指向的, 发现整个表达式都是由ID(也可以叫Key)决定的 全部分析流程如下:
返回是GName
整理公式: GName = "DeathlyStillnessGame-Win64-Shipping.exe"+44BDB80 GName+10040+n*40 Key结构体数组开始指针 n== 0 到 F 也可以根据 对象+18 里的值是否等于 GName 判断 $-18 0000000000000000 $-10 0000000000000000 $-8 0000000000000000 $ ==> 0000000000000000====从这开始 $+8 00001FFF0000142A $+10 0000029723510000 $+18 00007FF6F4FEDB80 $+20 000000250000142A $+28 0000000000000000 $+30 0000000000000000 $+38 0000000000000000 $+40 0000000000000000====第2个对象 $+48 00001FFF000013E0 $+50 0000029726CE0000 $+58 00007FF6F4FEDB80 $+60 0000002B000013E0 $+68 0000000000000000 $+70 0000000000000000 $+78 0000000000000000 $+80 0000000000000000====第3个对象 $+88 00001FFF00001407 $+90 0000029726D90000 $+98 00007FF6F4FEDB80 $+A0 0000002E00001407 $+A8 0000000000000000 $+B0 0000000000000000 $+B8 0000000000000000 每个对象 +10 进入 存放了1FFF个4字节的ID ID == [[GName+10040+n*40+10]+i*4] 最上面 拉到最下面了 [00007FF6F4FEDB80+10040+n*40+10]+ i*4 (n==0 到F i ==0到 1FFE) 这样可以取得游戏中的全部ID 取得所有ID,注意判断是否为0 ,0其实对应的就是None 得到ID以后: 第几页 = (ID and 0x1FFFFFFF)>>0x10 字符串偏移 =WORD (ID and 0x1FFFFFFF) 长度== WORD PTR :[[Gname+第几页*8+10]+字符串偏移*2 ] >> 6 内容地址 = [Gname+第几页*8+10]+字符串偏移*2 +2(头部2字节) 这样就可以遍历出全部字符串了 一共8W+ ,还是非常多的,运行不卡,输出会比较卡,怕卡的同学可以把字符串全部相加以后 一起输出. ps:可以观察一下 头部两字节/ 0x40 (>>6) 就是真实长度, 这种可能有不同的加密方法,通过上面的方法都是可以逆向出来的 GetName 其他的方法 当然找GetName我们也可以用IDA 或则 XDBG 搜索ByteProperty IDA搜索 ByteProperty,搜索到多个 IDA ctlr+X 转到引用,发现 连续字符串的就是我们要的 XDBG也一样 跳过去 跟IDA是一样的 同时告诉你们个秘密,还记得我们之前分析的位置吗 这个头部下断返回的是GName 如果我们在头部查找引用 会发现很多个引用,但是其实 除了我们返回GName的位置 其他都是一个地方 也就是 XDBG 和IDA 搜索字符串的位置 IDA中我们点F5 然后拉到函数头部 点X 查看调用 其中一个是getname,挨个分析下参数即可,当然XDBG也可以 具体算法和我们上面分析的差不多,不再赘述 这里注意: 我们通过这样方式找到的GetName函数只能静态观察,因为,他是访问不断的 因为他只有在游戏初始化的时候调用分配一次 而逆向的算法和他其实是一个,是可以随时断下查看的, 也就是说动态调试的方式是不能主动断到GetName的,但是可以断到算法 5.GObjectArrayGObject?是保存着世界的对象地址 我们先利用特征找到 xdbg扫描字符串CanvasObject 得到一个结果,跳转到该条代码,并向上翻找带有sar的代码 这一条下面的基地址就是Gobject Gobject=deathlystillnessgame-win64-shipping.exe+44D6128 发现没发现 这个基地址 贼眼熟 他就是之前 获取对象call,里面的基地址,这个数组套数组的基地址就是 GObject 6.旧版本UE4案例吃鸡模拟器----三件套分析游戏进程在..../Binaries/Win64内 UWorld xdbg搜索字符串: SeamlessTravel FlushLevelStreaming 用IDA搜索这个速度慢,而且IDA搜索到的位置可能会不全,可以用xdbg搜索字符串,用IDA查看伪代码 搜索字符串的过程比较缓慢,注意用xdbg找完UWorld不要把搜索到的字符串关掉,后面可能还需要找其他的数据 xdbg搜索得到一个结果 跳转到这个地址向上翻可以得到btr edx,0x7,再向上遇到的第一个基地址,就是UWorld UWorld = battleroyaletrainer-win64-shipping.exe+2AF0FB8 UWorld的找发是UE4通用的,新老版本一样 GName 找GName的关键词是ByteProperty 找Gname的目的是为了获取UE内的所有字符串及其对应的ID,ByteProperty通常是所有字符串中的第2个,也就是说其ID是1,ID为0的为None,当然这个ID并不绝对,可能会有改变 用CE扫描ByteProperty 在内存对每一个结果逐个进行观察,找到连续字符串 很幸运的是第一个结果就是这样的,而后面的挨个看了下没有这类结构的 其实我们用xdbg观察这个结构会更清晰 我们会发现,每一个字符串前面会空出0x10字节,并且这0x10字节的第一个DWORD数值是0,2,4,6,8......这种,那么我们可以猜到1E01C630000就是这个结果的头部,这时我们可以用CE对其进行扫描然后得到2个地址 这里我们选择第一个地址,由于我们扫描的none的地址,所以直接扫描两次,可以得到Gname 这两个地址都可以用,但是为了稳妥,我们用访问断的方式再追一次, 对名字下访问,然后关闭游戏时会访问这个名字, 返回追rcx 最终的来源时上面的CALL 在CALL里同样可以得到Gname 这种方法的好处是可以看到字符串的具体公式,并找到Gname的位置 出现数组的这一层,如果再向外返回,就可以来到getname的位置,getname需要传入2个参数 第一个参数是一个指向ID的指针,对于这种没有加密的老版本来说,ID传0-3FFF即可 第二个参数是一个空结构体,返回的字符串会写到这个结构体里 其实最好的方式并不是调用这个函数,因为这个函数只是为了取name字符串用,我们只要知道取name用的是什么样子的ID,然后用相应的算法和规则将所有字符串和ID一起遍历,并输出出来即可,并不一定需要调用函数,自己写的函数效率可能会高一些 Gname = battleroyaletrainer-win64-shipping.exe+2AD75C8 GObjectArray 在字符串中扫描Unexpected concurency while adding new object 这句话的含义是添加新对象时出现意外,而这句话的上面正是添加对象的判断代码, 随意找一条代码查看 仔细分析,可以发现上面的rdi+10是一个数组的起始地址,而下面一条就是添加对象的判断,在头部点击右键,查看引用可以很容易得到rdi的来源 当然,我们也可以用IDA查看伪代码 a1是函数的第一个参数,在函数处查看交叉引用,发现第一个参数就是基地址 142AD9F20-140000000=0x2AD9F20 GObject =battleroyaletrainer-win64-shipping.exe+0x2AD9F20+10 =battleroyaletrainer-win64-shipping.exe+0x2AD9F30 7.DUMP先简单说下DUMP 使用IDA静态分析前 ,先用xdbg 把游戏dump 一下 步骤如下: 选择进程 点DUMP 最后会有一个错的,delete即可 然后打开IDA dump 文件直接拖进 IDA ,出现对话框,直接取消取消即可. 然后我们就可以shift+F12 分析字符串了,当然这里分析的速度会比XDBG慢一些. 本章节内容就到这里,下一章我们继续研究DUMP,欢迎大家关注公众:任鸟飞逆向,共同学习讨论 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 | -2025/1/17 6:16:06- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |