18.游戏逆向-pxxx-使用ida分析UProperty结构中的offset和size解密

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动!

本次游戏没法给

内容参考于:微尘网络安全

上一个内容:17.游戏逆向-pxxx-分析UProperty结构

上一个内容中Size和Offset的值是会被加密的,指不定那次更新就被加密了,所以这次写如果被加密了该怎么办

首先在UE源码中打开UProperty类中

先找Offset_Internal,也就是Offset,跟之前的找法一样,先找到一个在ida中可以用于搜索的字符串,然后通过字符串找到相关的函数,从而找到相关的内容,ida的使用基本上就这么一套流程,其它游戏也一样

搜索Offset_Internal,查看有哪些地方调用了它,然后再看调用它的地方哪里有字符串,只能这样硬找,所以这个过程是一个漫长的过程可能要找两三天才能找到

这里直接说答案,如果没有答案是要把搜索到的结果一个一个的查看,通过下图蓝框的搜索结果找到下图红框的函数

然后搜索 GetOffset_ForUFunction,然后通过下图蓝框得到下图红框的函数

然后搜索 InitializeDerivedMembers,然后通过下图蓝框找到下图红框,在它的父类中有一个字符串可以使用ida搜索

下图红框的字符串,可以看到知道答案找起来还是很费劲,如果不知道答案找两三天是短的

搜出来下图红框的就是,Scriptserializatio

然后点击下图红框进行跳转

跳转之后直接按F5

这里把F5后的代码保存下来,后续可以找特征

c++ 复制代码
__int64 __fastcall sub_7FF7A1F3123C(unsigned int *a1, __int64 a2)
{
  __int64 v4; // rax
  __int64 v5; // r8
  unsigned __int64 v6; // rdx
  __int64 v7; // r9
  __int64 result; // rax
  __int64 v9; // rcx
  __int64 v10; // r12
  __int64 v11; // rcx
  _BYTE *v12; // r14
  __int64 v13; // rdx
  int v14; // r13d
  __int64 v15; // rax
  int v16; // r8d
  __int64 v17; // r14
  __int64 v18; // r15
  __int64 v19; // rcx
  __int64 v20; // rsi
  __int64 v21; // r14
  __int64 (__fastcall *v22)(); // r8
  __int64 v23; // rdx
  __int64 v24; // rcx
  unsigned int v25; // eax
  signed int v26; // r9d
  __int64 v27; // rdi
  __int64 v28; // rdx
  __int64 v29; // [rsp+20h] [rbp-99h]
  __int64 v30; // [rsp+30h] [rbp-89h] BYREF
  __int64 v31; // [rsp+38h] [rbp-81h]
  _BYTE v32[208]; // [rsp+40h] [rbp-79h] BYREF
  unsigned int v33; // [rsp+120h] [rbp+67h] BYREF
  signed int v34; // [rsp+128h] [rbp+6Fh] BYREF
  __int64 v35; // [rsp+130h] [rbp+77h] BYREF

  sub_7FF7A1B5A5E8();
  (*(void (__fastcall **)(__int64, unsigned int *))(*(_QWORD *)a2 + 40LL))(a2, a1 + 10);
  (*(void (__fastcall **)(unsigned int *, __int64))(*(_QWORD *)a1 + 672LL))(a1, a2);
  (*(void (__fastcall **)(__int64, unsigned int *))(*(_QWORD *)a2 + 40LL))(a2, a1 + 54);
  if ( (*(_BYTE *)(a2 + 40) & 1) != 0 )
  {
    sub_7FF7A1F31350(&v30, a1, a2);
    sub_7FF7A1F3143C(&v30, a1, a2);
    v4 = sub_7FF7A1B6271C();
    v5 = 0x3868F90A279CB28ALL;
    v6 = (((*((_QWORD *)a1 + 1) ^ 0x9A6C533B35CDE3BFuLL) & 0xFFFFFFFFFFFF8000uLL) << 17)
       ^ 0x3868F90A279CB28ALL
       ^ __ROR8__(*((_QWORD *)a1 + 1) ^ 0x9A6C533B35CDE3BFuLL, 15);
    v7 = v4 + 224;
    result = *(int *)(v4 + 232);
    if ( (int)result > *(_DWORD *)(v6 + 232)
      || (v9 = result, result = *(_QWORD *)(v6 + 224), *(_QWORD *)(result + 8 * v9) != v7)
      || !a1 )
    {
      if ( (*(_DWORD *)(a2 + 48) & 0x1000) == 0 )
      {
        LOBYTE(v5) = 1;
        return (*(__int64 (__fastcall **)(unsigned int *, __int64, __int64))(*(_QWORD *)a1 + 600LL))(a1, a2, v5);
      }
    }
    return result;
  }
  result = a1[40];
  v33 = a1[40];
  v10 = -1;
  if ( (*(_BYTE *)(a2 + 40) & 2) != 0 )
  {
    v11 = *(_QWORD *)(a2 + 8);
    if ( (unsigned __int64)(*(_QWORD *)v11 + 4LL) > *(_QWORD *)(v11 + 8) )
    {
      (*(void (__fastcall **)(__int64, unsigned int *, __int64))(*(_QWORD *)a2 + 72LL))(a2, &v33, 4);
      v12 = (_BYTE *)(a2 + 41);
      if ( (*(_BYTE *)(a2 + 41) & 8) != 0 )
        sub_7FF7A3FD352C(a2, &v33, 4);
    }
    else
    {
      v33 = **(_DWORD **)v11;
      *(_QWORD *)v11 += 4LL;
      v12 = (_BYTE *)(a2 + 41);
    }
    v34 = 0;
    result = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)a2 + 136LL))(a2);
    v10 = result;
    v13 = *(_QWORD *)(a2 + 8);
    if ( (unsigned __int64)(*(_QWORD *)v13 + 4LL) > *(_QWORD *)(v13 + 8) )
    {
      result = (*(__int64 (__fastcall **)(__int64, signed int *, __int64))(*(_QWORD *)a2 + 72LL))(a2, &v34, 4);
      if ( (*v12 & 8) != 0 )
        result = sub_7FF7A3FD352C(a2, &v34, 4);
    }
    else
    {
      v34 = **(_DWORD **)v13;
      *(_QWORD *)v13 += 4LL;
    }
  }
  if ( !byte_7FF7B2C29202 )
  {
    v34 = 0;
    v14 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)a2 + 136LL))(a2);
    if ( (*(_BYTE *)(a2 + 40) & 0x20) == 0 || !(*(__int64 (__fastcall **)(__int64))(*(_QWORD *)a2 + 128LL))(a2) )
    {
      while ( 1 )
      {
        result = v33;
        v26 = v34;
        if ( v34 >= (int)v33 )
          break;
        (*(void (__fastcall **)(unsigned int *, signed int *, __int64))(*(_QWORD *)a1 + 648LL))(a1, &v34, a2);
      }
      goto LABEL_47;
    }
    v15 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)a2 + 128LL))(a2);
    v17 = v15;
    if ( !v15 || *(_DWORD *)(v15 + 152) != 2 )
      v17 = 0;
    v18 = *(_QWORD *)(v17 + 728);
    v30 = 0;
    v31 = 0;
    v35 = 0;
    LOBYTE(v16) = (*(_BYTE *)(a2 + 40) & 0x20) != 0;
    sub_7FF7A1EB1ED8((unsigned int)v32, (unsigned int)&v30, v16, 0, 0);
    *(_QWORD *)(v17 + 728) = v32;
    while ( v34 < (int)v33 )
      (*(void (__fastcall **)(unsigned int *, signed int *, __int64))(*(_QWORD *)a1 + 648LL))(a1, &v34, a2);
    *(_QWORD *)(v17 + 728) = v18;
    (*(void (__fastcall **)(__int64, __int64, _QWORD))(*(_QWORD *)a2 + 72LL))(a2, v30, (int)v31);
    v19 = *(_QWORD *)(v17 + 584);
    if ( v19 && (_DWORD)v31 )
      sub_7FF7A1C73ABC(v19, v30);
    sub_7FF7A1B3BD78(v32);
    v20 = v30;
    if ( !v30 )
    {
LABEL_44:
      result = v33;
      v26 = v34;
LABEL_47:
      if ( v26 != (_DWORD)result )
      {
        sub_7FF7A3FD30A8(
          "D:\\wk\\cwd1b\\build\\UnrealEngine\\Engine\\Source\\Runtime\\CoreUObject\\Private\\UObject\\Class.cpp",
          1310,
          L"Script serialization mismatch: Got %i, expected %i");
        LODWORD(v29) = v34;
        result = sub_7FF7A3FD2B00(
                   (unsigned int)&unk_7FF7B0A7288E,
                   (unsigned int)"D:\\wk\\cwd1b\\build\\UnrealEngine\\Engine\\Source\\Runtime\\CoreUObject\\Private\\UObject\\Class.cpp",
                   1310,
                   (unsigned int)L"Script serialization mismatch: Got %i, expected %i",
                   v29,
                   v33);
      }
      if ( (*(_BYTE *)(a2 + 40) & 2) != 0 )
      {
        v27 = (*(__int64 (__fastcall **)(__int64))(*(_QWORD *)a2 + 136LL))(a2);
        (*(void (__fastcall **)(__int64, __int64))(*(_QWORD *)a2 + 168LL))(a2, v10);
        LODWORD(v35) = v27 - v14;
        v28 = *(_QWORD *)(a2 + 8);
        if ( (unsigned __int64)(*(_QWORD *)v28 + 4LL) > *(_QWORD *)(v28 + 8) )
        {
          (*(void (__fastcall **)(__int64, __int64 *, __int64))(*(_QWORD *)a2 + 72LL))(a2, &v35, 4);
          if ( (*(_BYTE *)(a2 + 41) & 8) != 0 )
            sub_7FF7A3FD352C(a2, &v35, 4);
        }
        else
        {
          LODWORD(v35) = **(_DWORD **)v28;
          *(_QWORD *)v28 += 4LL;
        }
        return (*(__int64 (__fastcall **)(__int64, __int64))(*(_QWORD *)a2 + 168LL))(a2, v27);
      }
      return result;
    }
    v21 = qword_7FF7B25C14B0;
    if ( !qword_7FF7B25C14B0 )
    {
      sub_7FF7A24A9C94();
      (*(void (__fastcall **)(__int64, __int64))(*(_QWORD *)qword_7FF7B25C14B0 + 32LL))(qword_7FF7B25C14B0, v20);
      goto LABEL_44;
    }
    v22 = *(__int64 (__fastcall **)())(*(_QWORD *)qword_7FF7B25C14B0 + 32LL);
    if ( v22 != sub_7FF7A28FCF50 )
    {
      ((void (__fastcall *)(__int64, __int64))v22)(qword_7FF7B25C14B0, v30);
      goto LABEL_44;
    }
    if ( (_WORD)v30 )
    {
      if ( dword_7FF7B25B90A4 )
      {
        v23 = MEMORY[0x7FFBFB544510]();
        if ( v23 )
        {
          if ( *(_BYTE *)((v20 & 0xFFFFFFFFFFFF0000uLL) + 3) == 0xE3 )
          {
            v24 = 32LL * *(unsigned __int8 *)((v20 & 0xFFFFFFFFFFFF0000uLL) + 2);
            v25 = *(_DWORD *)(v24 + v23 + 16);
            if ( v25 < 0x40 && *(unsigned __int16 *)(v20 & 0xFFFFFFFFFFFF0000uLL) * v25 < 0x10000 )
              goto LABEL_41;
            if ( !*(_QWORD *)(v24 + v23 + 24) )
            {
              *(_OWORD *)(v24 + v23 + 24) = *(_OWORD *)(v24 + v23 + 8);
              *(_QWORD *)(v24 + v23 + 8) = 0;
              *(_DWORD *)(v24 + v23 + 16) = 0;
LABEL_41:
              *(_QWORD *)v20 = *(_QWORD *)(v24 + v23 + 8);
              *(_QWORD *)(v24 + v23 + 8) = v20;
              *(_DWORD *)(v20 + 8) = ++*(_DWORD *)(v24 + v23 + 16);
              goto LABEL_44;
            }
          }
        }
      }
    }
    sub_7FF7A28FD010(v21, v20);
    goto LABEL_44;
  }
  return result;
}

鼠标左键单击下图红框,然后按X可以看有哪些地方调用了它,可以记录一下从别处找它的方式

这里通过上图蓝框找下图红框的函数,注意上图是在下图蓝框的函数中

首先看下图红框的,双击下图红框跳转

来到最后,如下图红框,看着大体逻辑可以对的起来Ar=a2,a1=InitializeDerivedMembers的this

然后看下一个

它的代码逻辑对不上

然后下一个

第三个如下图红框,通过三个对比,它是最符合的,也就是说 7FF7A1F32BFC是InitializeDerivedMembers

鼠标左键单击下图红框,给它改名InitializeDerivedMembers,然后双击下图红框进入InitializeDerivedMembers

通过下图红框可以看出找对了,Next的偏移正是40

然后如下图红框,它正好有Size

GetSize里也有我们要找的ElementSize,所以这俩都在一起,可以一起找

还能看到PropertyFlags的偏移

首先找GetOffset_ForUFunction,如下图红框有一个++可以定位到NumParms++

下图红框的就是GetOffset_ForUFunction和 ArrayDim和ElementSize偏移,这里是没有加密的,如果有加密的话,下图红框的后面就是加密算法,会很复杂

如下图是一个加密版本v9就是offset,通过一个Switch语句进行不同的解密,这个代码很长

解密代码很长,但是这些解密都会统一调用某一个函数,在上图找到的位置我们没办法使用,我们期望的是给一个函数传入加密后的offset,然后得到解密后的offset,UE源码中找不到这样的函数,但是在ida中通过对统一调用的解密函数按X,得到调用它的位置,然后一个一个去看,就能找到一个传进加密的offset得到一个解密的offset

然后再通过特征码定位解密函数的地址,但这种方式需要注入

如果上述的话,读了一遍没有画面,那就说明,没有使用过ida中的x


相关推荐
AA陈超6 天前
ASC学习笔记0027:直接设置属性的基础值,而不会影响当前正在生效的任何修饰符(Modifiers)
c++·笔记·学习·ue5·虚幻引擎
开发游戏的老王6 天前
UE5.6 C++项目升级UE5.7时用Rider加载项目失败的解决办法
ue5·游戏引擎·虚幻·虚幻引擎·rider·ue5.7·target.cs
AA陈超6 天前
ASC学习笔记0020:用于定义角色或Actor的默认属性值
c++·笔记·学习·ue5·虚幻引擎
AA陈超7 天前
使用UnrealEngine引擎,实现鼠标点击移动
c++·笔记·学习·ue5·虚幻引擎
AA陈超7 天前
Lyra源码分析:LyraCharacterMovementComponent
c++·笔记·学习·ue5·虚幻引擎·lyra
AA陈超7 天前
UE5笔记:GetWorld()->SpawnActorDeferred()
c++·笔记·学习·ue5·虚幻引擎
AA陈超8 天前
ASC学习笔记0025:移除所有属性集
c++·笔记·学习·ue5·虚幻引擎
炫云云渲染9 天前
虚幻引擎 5.7 现已发布
虚幻·虚幻引擎·虚幻引擎 5.7·ue5.7发布
AA陈超9 天前
ASC学习笔记0007:用于与GameplayAbilities系统交互的核心ActorComponent
c++·笔记·学习·ue5·虚幻引擎