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+n40+10]+i4]
最上面
拉到最下面了
[00007FF6F4FEDB80+10040+n40+10]+ i4 (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,欢迎大家关注公众:任鸟飞逆向,共同学习讨论
版权归原作者 任鸟飞逆向~ 所有, 如有侵权,请联系我们删除。