UE4引擎无法启动,
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UE4引擎无法启动,相关的知识,希望对你有一定的参考价值。
UE4无法启动,加载页面有,但是没有启动除了登录器
请问一下我的UE4.22.2在官方下载的 点击出来加载页面,加载完就弹出登录器的界面了,请问一下怎么解决呀
现在的情况是低版本也不能打开了只要是UE4引擎系统除了登录器都不能开启也没有任何的显示报错什么的就是在加载界面之前那里,界面有点半透明,加载的时候是正常的,加载完事就弹出了登录器的界面就没有了。不可能没有一个人有这个问题吧
我的电脑配置是 I9 9900K 16G内存 2080ti显卡 Win10 64位
这种情况我真的无语了,连老师都不知道怎么办
如果重装系统就更麻烦了,我的Win10是正版的在加上之前装的模型软件一大堆都要重装吗?能不能给一个靠谱的答案这样至少有人遇到这个问题的时候知道怎么办而不是盲目蛮干啊。
这个错误对话框是系统在提示内存错误,但是具体原因不清楚,解决方法不一样,你可以都试试:
1、你下载一个DirectX Repair修复工具或者修复增加版修复一下。
2、检查一下你系统是多少位的,32位的应用程序要链接32位下的动态链接库*.dl。
3、装个高版本的Visual Studio、Microsoft Visual C++运行库和.net运行库,32位系统只安装32位的即可,而对于64位系统,32位和64位的最好都装。
操作工具
虚幻的编辑器(UnrealEd)是一个以“所见即所得”为设计理念的操作工具,它可以很好地弥补一些在3D Studio Max和Maya中无法实现的不足,并很好地运用到游戏开发里去。
在可视化的编辑窗口中游戏开发人员可以直接对游戏中角色,NPC,物品道具,AI的路点及光源进行自由的摆放和属性的控制,并且全部是实时渲染的。并且这种实时渲染还有动态的光影效果。
并且还有完整的数据属性编辑功能,可以让关卡设计人员自由地对游戏中的物件进行设置或是由程序人员通过脚本编写的形式直接进行优化设置。
参考技术A 这个错误对话框是系统在提示内存错误,但是具体原因不清楚,解决方法不一样,你可以都试试:1、你下载一个DirectX Repair修复工具或者修复增加版修复一下。
2、检查一下你系统是多少位的,32位的应用程序要链接32位下的动态链接库*.dl。
3、装个高版本的Visual Studio、Microsoft Visual C++运行库和.net运行库,32位系统只安装32位的即可,而对于64位系统,32位和64位的最好都装。
求采纳谢谢。追问
哥没有用都试过了
追答那在下也无能为力了,抱歉。
本回答被提问者采纳UE4引擎分析获取UWord,GName,GetName,GObjectArray
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
小退或则开始游戏会断下
字符串下断
| CC | int3 |
| CC | int3 |
| CC | int3 |
| 48:895C24 08 | mov qword ptr ss:[rsp+0x8],rbx |
| 4D:8BD0 | mov r10,r8 |
| 4C:8BCA | mov r9,rdx | rcx
| 4C:8BD9 | mov r11,rcx | rcx -rdx + r9
| 4D:85C0 | test r8,r8 |
| 74 23 | je deathlystillnessgame-win64-shipping.7FF6F18A3EF6 |
| 4C:2BDA | sub r11,rdx | r11+ r9 = r11-rdx + r9
| 48:8D1D D3DC6F02 | lea rbx,qword ptr ds:[0x7FF6F3FA1BB0] |
| 0F1F00 | nop dword ptr ds:[rax],eax |
| 43:0FB6040B | movzx eax,byte ptr ds:[r11+r9] | r11+r9 r9是堆栈地址 R11只是堆栈和真实地址的偏移
| 45:0FB601 | movzx r8d,byte ptr ds:[r9] | 断下的位置
| 4D:8D49 01 | lea r9,qword ptr ds:[r9+0x1] |
| 41:3AC0 | cmp al,r8b |
| 75 0C | jne deathlystillnessgame-win64-shipping.7FF6F18A3EFE |
| 84C0 | test al,al |
| 75 2C | jne deathlystillnessgame-win64-shipping.7FF6F18A3F22 |
| 33C0 | xor eax,eax |
| 48:8B5C24 08 | mov rbx,qword ptr ss:[rsp+0x8] |
| C3 | ret |
| 41:0FBED0 | movsx edx,r8b |
| 0FBEC8 | movsx ecx,al |
| 0BD1 | or edx,ecx |
| F7C2 80FFFFFF | test edx,0xFFFFFF80 |
| 75 21 | jne deathlystillnessgame-win64-shipping.7FF6F18A3F30 |
返回追rcx
追字符串是什么表达式指向的, 发现整个表达式都是由ID(也可以叫Key)决定的
全部分析流程如下:
| 48:895C24 20 | mov qword ptr ss:[rsp+0x20],rbx |
| 55 | push rbp |
| 56 | push rsi |
| 57 | push rdi |
| 41:56 | push r14 |
| 41:57 | push r15 |
| 48:8D6C24 C9 | lea rbp,qword ptr ss:[rsp-0x37] |
| 48:81EC A0000000 | sub rsp,0xA0 |
| 48:8B05 E9105703 | mov rax,qword ptr ds:[0x7FF6F4F2B7B8] |
| 48:33C4 | xor rax,rsp |
| 48:8945 2F | mov qword ptr ss:[rbp+0x2F],rax |
| 41:0F1000 | movups xmm0,xmmword ptr ds:[r8] |
| 4C:8BF2 | mov r14,rdx |
| 48:8BD9 | mov rbx,rcx | rcx==rbx==GName 返回可得
| 0F10C8 | movups xmm1,xmm0 |
| 0F2945 D7 | movaps xmmword ptr ss:[rbp-0x29],xmm0 |
| 48:8B55 D7 | mov rdx,qword ptr ss:[rbp-0x29] |
| 66:0F73D9 08 | psrldq xmm1,0x8 |
| 6648:0F7EC8 | movq rax,xmm1 |
| 6641:0F7EC8 | movd r8d,xmm1 |
| 48:C1E8 20 | shr rax,0x20 |
| 0F1145 07 | movups xmmword ptr ss:[rbp+0x7],xmm0 |
| 84C0 | test al,al |
| 75 0B | jne deathlystillnessgame-win64-shipping.7FF6F19BA711 | 0
| 48:8D4D E7 | lea rcx,qword ptr ss:[rbp-0x19] |
| E8 F11DFFFF | call deathlystillnessgame-win64-shipping.7FF6F19AC50 |
| EB 09 | jmp deathlystillnessgame-win64-shipping.7FF6F19BA71A | 1
| 48:8D4D D7 | lea rcx,qword ptr ss:[rbp-0x29] |
| E8 D61EFFFF | call deathlystillnessgame-win64-shipping.7FF6F19AC5F |
| 0F1000 | movups xmm0,xmmword ptr ds:[rax] |
| C645 2B 00 | mov byte ptr ss:[rbp+0x2B],0x0 | 00007FF6F4FEDB80
| 66:0F7EC7 | movd edi,xmm0 | rbx==Gname Gname+10040+0*40
| 0F1145 17 | movups xmmword ptr ss:[rbp+0x17],xmm0 | [[rbx+10040+040+10]+n*4]
| 48:81C7 01040000 | add rdi,0x401 | [[rbx+(rdi+401)*40+10]+n*4]
| 48:C1E7 06 | shl rdi,0x6 | [[rbx+rdi*40+10]+n*4]
| 48:03FB | add rdi,rbx | [[rdi+rbx+10]+n*4]
| 48:8BCF | mov rcx,rdi |
| FF15 E0D04202 | call qword ptr ds:[<&RtlAcquireSRWLockExclusive>] |
| 8B5D 1B | mov ebx,dword ptr ss:[rbp+0x1B] |
| 48:8B47 10 | mov rax,qword ptr ds:[rdi+0x10] | rax = [[rdi+10]+n*4]
| 44:8B7F 0C | mov r15d,dword ptr ds:[rdi+0xC] |
| 41:23DF | and ebx,r15d |
| 48:8D3498 | lea rsi,qword ptr ds:[rax+rbx4] |
| 8B0498 | mov eax,dword ptr ds:[rax+rbx4] | 数组中取ID 给eax 这里rbx是多少不用管,因为我们要遍历全部
| 85C0 | test eax,eax |
| 0F84 DE000000 | je deathlystillnessgame-win64-shipping.7FF6F19BA83B | 不跳>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
| 0F1F00 | nop dword ptr ds:[rax],eax |
| 8BC8 | mov ecx,eax |
| 81E1 000000E0 | and ecx,0xE0000000 |
| 3B4D 1F | cmp ecx,dword ptr ss:[rbp+0x1F] |
| 0F85 9D000000 | jne deathlystillnessgame-win64-shipping.7FF6F19BA80E | 不跳>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
| 25 FFFFFF1F | and eax,0x1FFFFFFF | and 1FFFFFFF
| 8BD0 | mov edx,eax | eax>>0x10 第几页
| 0FB7C8 | movzx ecx,ax | ax 字符串偏移
| C1EA 10 | shr edx,0x10 | edx>>0x10 第几页
| 8955 C7 | mov dword ptr ss:[rbp-0x39],edx |
| 894D CB | mov dword ptr ss:[rbp-0x35],ecx |实际是这 ecx字符串偏移
| 48:8B45 C7 | mov rax,qword ptr ss:[rbp-0x39] |来源于这
| 48:8B4F 18 | mov rcx,qword ptr ds:[rdi+0x18] |
| 48:C1E8 20 | shr rax,0x20 | (rax>>0x20)*2 字符串字符串数*2 ==前面字符串长度
| 44:8D0400 | lea r8d,qword ptr ds:[rax+rax] | r8 ==前面字符串长度
| 4C:0344D1 10 | add r8,qword ptr ds:[rcx+rdx8+0x10] | 字符串==[rcx+rdx*8+10]+r8(前面字节长度)+2(头部2字节)
| 41:0FB710 | movzx edx,word ptr ds:[r8] | 头部两字节
| 66:3B55 23 | cmp dx,word ptr ss:[rbp+0x23] |
| 75 6B | jne deathlystillnessgame-win64-shipping.7FF6F19BA80E | 不跳>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
| 0FB7C2 | movzx eax,dx | 头部两字节给了 eax
| 49:8D48 02 | lea rcx,qword ptr ds:[r8+0x2] | 字符串== r8+2 跳过 头部2字节 因为我们之前知道 字符串前面有2字节长度
| C1E8 06 | shr eax,0x6 | 头部两字节>>6 解密长度 >>6以后我们知道哦 原来是字符串长度 不难观察哦
| F6C2 01 | test dl,0x1 |
| 74 11 | je deathlystillnessgame-win64-shipping.7FF6F19BA7C3 | 来源都是rcx 字符串== rcx
| 8945 FF | mov dword ptr ss:[rbp-0x1],eax |
| 48:8D45 F7 | lea rax,qword ptr ss:[rbp-0x9] |
| 48:894D F7 | mov qword ptr ss:[rbp-0x9],rcx | rcx 来源一
| C645 03 01 | mov byte ptr ss:[rbp+0x3],0x1 |
| EB 0F | jmp deathlystillnessgame-win64-shipping.7FF6F19BA7D2 |
| 8945 DF | mov dword ptr ss:[rbp-0x21],eax |
| 48:8D45 D7 | lea rax,qword ptr ss:[rbp-0x29] |
| 48:894D D7 | mov qword ptr ss:[rbp-0x29],rcx | rcx 来源二
| C645 E3 00 | mov byte ptr ss:[rbp-0x1D],0x0 |
| 0F1000 | movups xmm0,xmmword ptr ds:[rax] | 字符串==[rax]
| 48:8B55 07 | mov rdx,qword ptr ss:[rbp+0x7] |
| 0F2945 E7 | movaps xmmword ptr ss:[rbp-0x19],xmm0 | 字符串==XMM0
| 48:8B4D E7 | mov rcx,qword ptr ss:[rbp-0x19] | 字符串==[rbp-19]
| 66:0F73D8 08 | psrldq xmm0,0x8 |
| 66:0F7EC0 | movd eax,xmm0 |
| 4C:63C0 | movsxd r8,eax |
| 48:8B45 0F | mov rax,qword ptr ss:[rbp+0xF] |
| 48:C1E8 20 | shr rax,0x20 |
| 84C0 | test al,al |
| 75 07 | jne deathlystillnessgame-win64-shipping.7FF6F19BA800 |
| E8 C296EEFF | call deathlystillnessgame-win64-shipping.7FF6F18A3EC | 返回call====上面是从这里返回的
| EB 05 | jmp deathlystillnessgame-win64-shipping.7FF6F19BA805 |
| E8 BB97EEFF | call deathlystillnessgame-win64-shipping.7FF6F18A3FC |
| 85C0 | test eax,eax |
| 0F94C0 | sete al |
返回是GName
00007FF69D0ECD66 | 803D B7D76203 00 | cmp byte ptr ds:[0x7FF6A071A524],0x0 |
00007FF69D0ECD6D | 74 09 | je deathlystillnessgame-win64-shipping.7FF69D0ECD78 |
00007FF69D0ECD6F | 48:8D05 0A0E6403 | lea rax,qword ptr ds:[0x7FF6A072DB80] | Gname 在这里
00007FF69D0ECD76 | EB 13 | jmp deathlystillnessgame-win64-shipping.7FF69D0ECD8B |
00007FF69D0ECD78 | 48:8D0D 010E6403 | lea rcx,qword ptr ds:[0x7FF6A072DB80] |
00007FF69D0ECD7F | E8 6C050000 | call deathlystillnessgame-win64-shipping.7FF69D0ED2F0 |
00007FF69D0ECD84 | C605 99D76203 01 | mov byte ptr ds:[0x7FF6A071A524],0x1 |
00007FF69D0ECD8B | 0F1003 | movups xmm0,xmmword ptr ds:[rbx] |
00007FF69D0ECD8E | 4C:8D4424 20 | lea r8,qword ptr ss:[rsp+0x20] |
00007FF69D0ECD93 | 48:8BC8 | mov rcx,rax |
00007FF69D0ECD96 | 48:8D5424 30 | lea rdx,qword ptr ss:[rsp+0x30] |
00007FF69D0ECD9B | 0F294424 20 | movaps xmmword ptr ss:[rsp+0x20],xmm0 |
00007FF69D0ECDA0 | E8 0BD90000 | call deathlystillnessgame-win64-shipping.7FF69D0FA6B0 | 返回call 2
00007FF69D0ECDA5 | 48:8B5C24 58 | mov rbx,qword ptr ss:[rsp+0x58] |
00007FF69D0ECDAA | 8B08 | mov ecx,dword ptr ds:[rax] |
00007FF69D0ECDAC | 48:8BC7 | mov rax,rdi |
00007FF69D0ECDAF | 890F | mov dword ptr ds:[rdi],ecx |
整理公式:
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.GObjectArray
GObject 是保存着世界的对象地址
我们先利用特征找到
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,欢迎大家关注公众:任鸟飞逆向,共同学习讨论
以上是关于UE4引擎无法启动,的主要内容,如果未能解决你的问题,请参考以下文章