4.游戏逆向-pxxx-得到GName偏移
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!
本次游戏没法给
内容参考于:微尘网络安全
上一个内容:3.游戏逆向-pxxx-对照UE源码和IDA分析GName偏移(ida中calloff开头地址的说明)
上一个内容中通过下图红框找到了一段代码,那段代码应该是用来给GName解密的

如下图红框三行代码,首先sub_7FF7C24A7100是AddZeroed函数,然后AddZeroed函数是GName调用的,通过下图的传参可以看出v2是GName,v2的值通过off_7FF7CF1A9028得到的,在上一个内容使用CE查看了off_7FF7CF1A9028的代码,没有发现GName,然后off_7FF7CF1A9028的参数有一个v1,然后v1的值来自于sub_7FF7C24A7450,所以GName可能就在sub_7FF7C24A7450里面

双击sub_7FF7C24A7450进入,它里面很乱

通过返回值来推断谁是GName,返回值来自于下图红框的off_7FF7CF1B4120,所以接下来还是要进入到CE中查看

ida中现在的基址是0x7FF7BFF60000,得到偏移0xF254120

然后在CE中使用偏移得到 off_7FF7CF1B4120

添加完默认是十进制显示,右击选择Show as hexadecimal(中文意思是显示十六进制)

注意下图红框的才是函数地址,因为ida中off表示的偏移也就是mov rax [0xxxxx] call rax这样的代码,然后双击下图红框会弹出一个对话框,然后就可以复制地址了

然后右击选择Disassmble thhis memory region

然后会打开下图的窗口

然后按CTRL+G,把上方复制的地址,粘贴到下图红框,然后点击ok

就来到下图红框的代码

代码说明:这类操作常见于数据混淆、简单加密或校验逻辑
Address Bytes Opcode Comment 7FF465601608 48 8D 05 A17D0000 lea rax,[7FF4656093B0] 将地址 7FF4656093B0加载到RAX寄存器(但后续未使用该地址,可能是冗余或调试残留)7FF46560160F 48 8B CA mov rcx,rdx 将输入参数( RDX寄存器,x64 调用约定中常用作第 2 个参数)的值复制到RCX寄存器,后续操作基于RCX进行7FF465601612 C0 C1 27 rol cl,39 对 CL(RCX的低 8 位)执行循环左移 39 位。x86-64 中 8 位寄存器移位时,实际移位位数为39 mod 8 = 7,即等效于循环左移 7 位7FF465601615 48 33 C9 34894998 xor rcx,FFFFFFFF98498934 对 RCX(64 位)与立即数FFFFFFFF98498934执行异或运算,结果存回RCX7FF46560161C C0 C1 25 rol cl,37 再次对 CL(RCX的低 8 位)执行循环左移 37 位。实际移位位数为37 mod 8 = 5,即等效于循环左移 5 位7FF46560161F 48 33 C9 F80B6FF0 xor rcx,FFFFFFFFF06F0BF8 对 RCX(64 位)与立即数FFFFFFFFF06F0BF8执行异或运算,结果存回RCX7FF465601626 48 8B C1 mov rax,rcx 将处理后的 RCX值复制到RAX寄存器(x64 调用约定中RAX用于存放返回值)7FF465601629 C3 ret 函数返回,最终结果通过 RAX传出
可以看出off_7FF7CF1B4120是一个加密操作,这里就有一个问题,为什么加密代码这么简单,这么短的代码进行加密很容易就给破解了,这个原因是,当前的代码位于UE引擎频繁调用的位置(反射机制),它不可能它也没办法去写复杂的加密,这样会影响性能,游戏玩起来会很卡,所以它只能写这种很简单的加密,然后还是没找到GName,写来继续看,如下图off_7FF7CF1B4120里有一个v32参数来自于off_7FF7CF1B4128,所以接下来就看off_7FF7CF1B4128

得到off_7FF7CF1B4128的偏移 7FF7BFF60000

进入CE使用偏移

如下图红框

代码说明:这段代码与上方off_7FF7CF1B4120的汇编逻辑完全互逆,off_7FF7CF1B4120是用来加密的,下方是用来解密的
Address Bytes Opcode Comment 7FF46560162A 48 8D 05 817D0000 lea rax,[7FF4656093B0] 将地址 7FF4656093B0加载到RAX寄存器(后续未使用该值,可能为冗余代码)7FF465601631 48 8B CA mov rcx,rdx 将输入参数( RDX寄存器,x64 调用约定中第 2 个参数)复制到RCX,后续操作基于RCX进行7FF465601634 48 33 C9 F80B6FF0 xor rcx,FFFFFFFFF06F0BF8 对 RCX(64 位)与立即数FFFFFFFFF06F0BF8执行异或运算,结果存回RCX7FF46560163B C0 C1 DD rol cl,-37 对 CL(RCX低 8 位)执行循环左移 - 37 位(等效于循环右移 37 位)。8 位寄存器移位时实际位数为37 mod 8 = 5,即等效循环右移 5 位7FF46560163E 48 33 C9 34894998 xor rcx,FFFFFFFF98498934 对 RCX(64 位)与立即数FFFFFFFF98498934执行异或运算,结果存回RCX7FF465601645 C0 C1 DB rol cl,-39 对 CL(RCX低 8 位)执行循环左移 - 39 位(等效于循环右移 39 位)。实际位数为39 mod 8 = 7,即等效循环右移 7 位7FF465601648 48 8B C1 mov rax,rcx 将处理后的 RCX值复制到RAX寄存器(x64 调用约定中RAX用于返回结果)7FF46560164B C3 ret 函数返回,结果通过 RAX传出
然后通过参数可以找到一个全局变量,如下图,通过代码的逻辑可以看出,qword_7FF7D0BEF370它是最原始的GName,qword_7FF7D0BEF390是通过qword_7FF7D0BEF370加解密得到的,qword_7FF7D0BEF390所以也会是GName

说明:
为什么说qword_7FF7D0BEF370它是最原始的GName呢,它就不能是别的吗?这些都是通过经验猜测的,没有任何一个人可以通过下方的代码就确定它是GName,也没办法确定,我们没有源代码,没有源代码就没办法确定游戏中获取GName的代码特征,如果想要物理层面的确定只能去一点一点的调试,猜测也是猜对了,猜测的基本逻辑,首先UE源码中GName调用了AddZeroed,调用之前先调用了GetNames函数得到GName,从这一点可以看出AddZeroed上方附近的代码必定有一个是GetNames,并且附近的逻辑肯定都是为了去调用AddZeroed函数,如下图通过返回值的观察也验证了这个想法
![]()
然后通过分析sub_7FF7C24A7450函数里面的代码,发现是加解密,然后结合参数,最终找到了qword_7FF7D0BEF370和qword_7FF7D0BEF390,它俩又是全局变量,我们又是通过AddZeroed一点一点追到的,所以就猜测qword_7FF7D0BEF370是原始的GName
这里有一个论坛:https://www.unknowncheats.me/forum/index.php,里面有很多游戏的基址和分析,如下图当前游戏的基址偏移0x10C8F370,它用的是qword_7FF7D0BEF370

qword_7FF7D0BEF370的偏移:

qword_7FF7D0BEF390的偏移


