Реверс-инжиниринг Il2cpp: расшифровка глобальных метаданных
Реверс-инжиниринг Il2cpp: расшифровка глобальных метаданных

Предисловие

 В Интернете много информации об Il2cpp,суммируя,Il2cpp — это новый метод упаковки, используемый Unity для замены исходной виртуальной машины Mono.,Сначала он генерирует IL (промежуточный язык).,Затем преобразуйте его в файл CPP.,Повысьте эксплуатационную эффективность и одновременно повысьте безопасность. Исходный метод упаковки, основанный на Mono, чрезвычайно легко отменить.,Новые игры, представленные сейчас на рынке, в основном упаковываются с использованием Il2cpp.,Конечно, существует также множество руководств по обратному инжинирингу для Il2cpp.,Но они все одинаковые,Научит пользоваться, написано домашним начальникомIl2cppDumperидтиdumpВот и все,Технического содержания нет. фактически,Потому что этот инструмент настолько известен,Многие производители игр приняли контрмеры,В результате, даже если вы будете следовать руководству,В большинстве случаев это не удастся. Поэтому я планирую изучить технологии атаки и защиты, связанные с Il2cpp.,Итак, я нашел один в ИнтернетеIl2cppизCTFВопросы для практики。Источник вопроса:n1ctf-2018

baby unity3d

 Требования к вопросам очень ясны,Просто введите правильный флаг. Теперь, когда мы знаем, что это программа Unity, использующая Il2cpp.,Тогда просто прямоидтинайди этоизlibil2cpp.soа такжеglobal-metadata.datдокумент,Затем попробуйте проанализировать с помощью Il2cppDumper.,Конечно, анализ не удастся. Причина сбоя парсинга должна быть в этих двух файлах.,По крайней мере один файл зашифрован,В результате нормальный анализ выполнить невозможно. Этот вопрос относительно простой,Только зашифрованноеglobal-metadata.datдокумент,может бытьglobal-metadata.datПеретащите010EditorПроверять,нормальныйизglobal-metadata.datначалоиз Четыре байта должны бытьAF 1B B1 FA,И этот вопросизglobal-metadata.datОчевидно, оно было зашифровано.,Так что для завершения разбора его нужно только расшифровать,Последующая проблема с флагом легко решается.

  Хочу расшифроватьglobal-metadata.datУ нас есть две идеи,Один из них — сбросить результат расшифровки,Другой — анализировать алгоритмы шифрования. Для первой идеи,Вот скрипт фриды

Язык кода:javascript
копировать
function frida_Memory(pattern)
{
Java.perform(function ()
{
    console.log("Идентификатор заголовка:" + pattern);
    var addrArray = Process.enumerateRanges("r--");
    for (var i = 0; i < addrArray.length; i++)
    {
        var addr = addrArray[i];
        Memory.scan(addr.base, addr.size, pattern,
        {
            onMatch: function (address, size)
            {
                console.log('Найти ' + pattern + " Адрес:" + address.toString());
                console.log(hexdump(address,
                    {
                        offset: 0,
                        length: 64,
                        header: true,
                        ansi: true
                    }
                    ));
                //0x108, 0x10C Если не работает, замените на 0x100, 0x104
                var DefinitionsOffset = parseInt(address, 16) + 0x108;
                var DefinitionsOffset_size = Memory.readInt(ptr(DefinitionsOffset));

                var DefinitionsCount = parseInt(address, 16) + 0x10C;
                var DefinitionsCount_size = Memory.readInt(ptr(DefinitionsCount));

                //Получаем размер глобальных метаданных на основе двух смещений
                var global_metadata_size = DefinitionsOffset_size + DefinitionsCount_size
                    console.log("Размер:", global_metadata_size);
                var file = new File("/data/data/" + get_self_process_name() + "/global-metadata.dat", "wb");
                file.write(Memory.readByteArray(address, global_metadata_size));
                file.flush();
                file.close();
                console.log('Экспорт завершен...');
            },
            onComplete: function ()
            {
                //console.log("Поиск завершен")
            }
        }
        );
    }
}
);
}
setImmediate(frida_Memory("AF 1B B1 FA")); //функции заголовка global-metadata.dat

Вероятно, процесс заключается в использовании магии для определения начального адреса файла в памяти.,Затем вычислите размер файла, анализируя заголовок файла.,продолжать последнимdump。Сценарийиз Применимые условия:global-metadata.datсуществовать解密后必须要有нормальныйиз Магия - этоAF 1B B1 FAВ противном случае позиционирование,При этом информация заголовка файла должна быть корректной, иначе размер файла невозможно будет вычислить. Этот скрипт имеет определенное ссылочное значение,Однако это не работает для этой проблемы,Начальный адрес не был найден после выполнения скрипта.,Кажется, даже после расшифровки,В памяти тоже нетAF 1B B1 FAсуществовать。Итак, этот генерализdumpЭтот метод, вероятно, больше не будет работать,можно найти толькоglobal-metadata.datизфункция загрузки,Подождите, пока расшифровка завершится, прежде чем выгружать файл.,Поэтому нам нужноglobal-metadata.datиз Загрузить процесс для анализа。

global-metadata.dat加载流程

  这篇文章IL2CPP Tutorial: Finding loaders for obfuscated global-metadata.dat filesверноglobal-metadata.datПроцесс загрузки очень подробный.изпредставлять,Определенно стоит прочитать. Позвольте мне кратко изложить это здесь,существоватьlibil2cpp.soЕсть один внутриil2cpp_initфункция是функция загрузки调用链中из Нет.одинфункция,Вся цепочка вызовов такая

Язык кода:javascript
копировать
il2cpp_init
  -> il2cpp::vm::Runtime::Init
    -> il2cpp::vm::MetadataCache::Initialize
      -> il2cpp::vm::MetadataLoader::LoadMetadataFile

  мы можемсуществоватьlibil2cpp.soИскать внутриil2cpp_initИли во всей цепочке вызововиз Ключевые слова для таргетингаодинфункция,Самый простойизпутем поискаglobal-metadata.datчтобы найти непосредственноMetadataCache::Initialize,Но этот вопрос не работает,Потому что спрашивающий намеренно поставилglobal-metadata.datЭта строка зашифрована,Так что его невозможно найти。Итак, мы ищемil2cpp_initПриходитьверно Согласно исходному коду, перейдите вниз кMetadataCache::Initialize

Что делать, если ни одна из вышеперечисленных функций не найдена?,Собственно, в статье выше об этом тоже упоминалось,существоватьlibunity.soБудетверноil2cpp_initВыполните анализ символов,возьмиизадрес。Просто обратитесь к статье выше для получения подробной информации.。Другой пример в этой статье:il2cpp_initбыло сделаноROT-5иметь дело с,Имя функции становитсяnq2huu_nsny,Затемя Обнаружитьсуществоватья自己找из НекоторыйcaseИскать здесьnq2huu_nsnyтакже можно найти,Итак, этоnq2huu_nsnyТакже стоит попробовать。

il2cpp_init

Язык кода:javascript
копировать
int __fastcall il2cpp_init(int a1)
{
  setlocale(6, "");
  return sub_4C4770(a1, "v2.0.50727");
}

sub_4C4770

Язык кода:javascript
копировать
int __fastcall sub_4C4770(int a1)
{
.......

  v1 = nullsub_3();
  v2 = nullsub_1(v1);
  v3 = sub_514E34(v2);
  dword_695A80 = (int)"2.0";
  v4 = sub_4F8468(v3);
  v5 = sub_5171B8(v4);
  v6 = sub_4B5564(v5);
  v7 = sub_501A60(v6);
  v8 = sub_4FA8B8(v7);
  v9 = sub_4E0D84(v8);
  sub_4D566C(v9);
  memset(&dword_695AB0, 0, 0x13Cu);
  v10 = sub_5017E4("mscorlib.dll");
  dword_695AB0 = il2cpp_assembly_get_image_0(v10);
  dword_695AB4 = ((int (*)(void))il2cpp_class_from_name_0)();
  dword_695ABC = il2cpp_class_from_name_0(dword_695AB0, "System", "Void");
  dword_695AC0 = il2cpp_class_from_name_0(dword_695AB0, "System", "Boolean");
  dword_695AB8 = il2cpp_class_from_name_0(dword_695AB0, "System", "Byte");
  dword_695AC4 = il2cpp_class_from_name_0(dword_695AB0, "System", &unk_5BA5E1);
  dword_695AC8 = il2cpp_class_from_name_0(dword_695AB0, "System", "Int16");
  dword_695ACC = il2cpp_class_from_name_0(dword_695AB0, "System", &unk_5BA5E7);
  dword_695AD0 = il2cpp_class_from_name_0(dword_695AB0, "System", "Int32");

......

Нажмите, чтобы увидеть по одному,Обнаружитьsub_4B5564На самом деле этоMetadataCache::Initialize

Язык кода:javascript
копировать
void sub_4B5564()
{
  void *v0; // r4
  int v1; // r4
  unsigned int v2; // r7
  int v3; // r0
  int v4; // lr
  int v5; // r2
  int v6; // r4
  int v7; // r3
  _DWORD *v8; // r1
  int v9; // r6
  int v10; // r0
  unsigned int v11; // r3
  int v12; // r7
  int v13; // r1
  unsigned int v14; // r1
  unsigned int v15; // r9
  int v16; // r6
  unsigned __int16 v17; // r0
  unsigned __int16 *v18; // r6
  int v19; // t1
  _DWORD *v20; // r7
  unsigned __int16 v21; // r4
  int v22; // r2
  int v23; // r1
  int v24; // r0
  int v25; // r6
  int v26; // r7
  int v27; // r1
  int v28; // [sp+8h] [bp-48h]
  unsigned int v29; // [sp+Ch] [bp-44h]
  int v30; // [sp+10h] [bp-40h]
  int v31; // [sp+14h] [bp-3Ch]
  int v32[2]; // [sp+18h] [bp-38h] BYREF
  int v33; // [sp+20h] [bp-30h] BYREF
  int v34; // [sp+24h] [bp-2Ch]
  double v35; // [sp+28h] [bp-28h] BYREF
  int v36; // [sp+30h] [bp-20h]

  v0 = (void *)sub_4B5518("CLKFIL\rMETIDITI\nDIT", 19);
  dword_6959CC = sub_513060();
  free(v0);
  dword_6959D0 = dword_6959CC;
  v28 = dword_6959CC + *(_DWORD *)(dword_6959CC + 184);
  if ( *(_DWORD *)(dword_6959CC + 188) >= 0x44u )
  {
    v1 = dword_6959CC + *(_DWORD *)(dword_6959CC + 184);
    v2 = 0;
    do
    {
      sub_5019F8(v1);
      v1 += 68;
      ++v2;
    }
    while ( v2 < *(_DWORD *)(dword_6959D0 + 188) / 0x44u );
  }
  dword_6959D4 = sub_5169D4(*(_DWORD *)(dword_6959C4 + 24), 4);
  dword_6959D8 = sub_5169D4(*(_DWORD *)(dword_6959D0 + 164) / 0x68u, 4);
  dword_6959DC = sub_5169D4(*(_DWORD *)(dword_6959D0 + 52) / 0x38u, 4);
  dword_6959E0 = sub_5169D4(*(_DWORD *)(dword_6959C4 + 32), 4);
  dword_6959E4 = *(_DWORD *)(dword_6959D0 + 180) / 0x18u;
  v3 = sub_5169D4(dword_6959E4, 28);
  dword_6959E8 = v3;
  if ( dword_6959E4 >= 1 )
  {
    v4 = dword_6959CC;
    v5 = 0;
    v6 = dword_6959D0;
    v7 = 12;
    v8 = (_DWORD *)(*(_DWORD *)(dword_6959D0 + 176) + dword_6959CC + 12);
    while ( 1 )
    {
      v9 = v3 + v7;
      ++v5;
      *(_DWORD *)(v9 - 12) = v4 + *(_DWORD *)(v6 + 24) + *(v8 - 3);
      *(_DWORD *)(v9 - 8) = *(v8 - 2);
      *(_DWORD *)(v9 - 4) = *(v8 - 1);
      *(_DWORD *)(v3 + v7) = *v8;
      *(_DWORD *)(v9 + 4) = v8[1];
      *(_DWORD *)(v9 + 12) = v8[2];
      if ( v5 >= dword_6959E4 )
        break;
      v7 += 28;
      v8 += 6;
      v6 = dword_6959D0;
      v4 = dword_6959CC;
      v3 = dword_6959E8;
    }
  }
  sub_4B5A28();
  v35 = 0.0;
  v36 = 0;
  v10 = dword_6959D0;
  if ( *(_DWORD *)(dword_6959D0 + 188) >= 0x44u )
  {
    v11 = 0;
    v31 = dword_6959CC + *(_DWORD *)(dword_6959D0 + 160);
    do
    {
      v12 = 0;
      v13 = *(_DWORD *)(v28 + 68 * v11);
      if ( v13 != -1 )
        v12 = dword_6959E8 + 28 * v13;
      v30 = v12;
      v14 = *(_DWORD *)(v12 + 12);
      if ( v14 )
      {
        v15 = 0;
        v29 = v11;
        do
        {
          v16 = v31 + 104 * (*(_DWORD *)(v12 + 8) + v15);
          v19 = *(unsigned __int16 *)(v16 + 80);
          v18 = (unsigned __int16 *)(v16 + 80);
          v17 = v19;
          if ( v19 )
          {
            v20 = (_DWORD *)(v31 + 104 * (*(_DWORD *)(v12 + 8) + v15) + 52);
            v21 = 0;
            do
            {
              v22 = *(_DWORD *)(dword_6959D0 + 48);
              v34 = *v20 + v21;
              v23 = *(_DWORD *)(dword_6959CC + v22 + 56 * v34 + 24);
              if ( v23 == -1 )
              {
                v33 = 0;
              }
              else
              {
                v33 = *(_DWORD *)(*(_DWORD *)(dword_6959C0 + 4) + 4 * v23);
                if ( v33 )
                {
                  sub_4B5CFC(&v35, &v33);
                  v17 = *v18;
                }
              }
              ++v21;
            }
            while ( v21 < (unsigned int)v17 );
            v12 = v30;
            v14 = *(_DWORD *)(v30 + 12);
          }
          ++v15;
        }
        while ( v15 < v14 );
        v11 = v29;
        v10 = dword_6959D0;
      }
      ++v11;
    }
    while ( v11 < *(_DWORD *)(v10 + 188) / 0x44u );
  }
  v24 = dword_6959C4;
  if ( *(int *)(dword_6959C4 + 16) >= 1 )
  {
    v25 = 0;
    v26 = 0;
    do
    {
      v27 = *(_DWORD *)(v24 + 20);
      v32[1] = *(_DWORD *)(*(_DWORD *)(v24 + 36) + 12 * *(_DWORD *)(v27 + v25));
      v32[0] = *(_DWORD *)(*(_DWORD *)(dword_6959C0 + 20) + 4 * *(_DWORD *)(v27 + v25 + 4));
      sub_4B5CFC(&v35, v32);
      v24 = dword_6959C4;
      v25 += 12;
      ++v26;
    }
    while ( v26 < *(_DWORD *)(dword_6959C4 + 16) );
  }
  sub_4C70FC(&v35);
  if ( LODWORD(v35) )
    operator delete((void *)LODWORD(v35));
}

Среди них этотsub_4B5518("CLKFIL\rMETIDITI\nDIT", 19);Просто расшифруйте строку вglobal-metadata.datиз Расположение。

Язык кода:javascript
копировать
_BYTE *__fastcall sub_4B5518(char *a1, int a2)
{
  _BYTE *result; // r0
  int v5; // r1
  _BYTE *v6; // r2
  char v7; // t1

  result = malloc(a2 + 1);
  if ( a2 >= 1 )
  {
    v5 = a2;
    v6 = result;
    do
    {
      v7 = *a1++;
      --v5;
      *v6++ = (v7 - 2) ^ 0x26;
    }
    while ( v5 );
  }
  result[a2] = 0;
  return result;
}

Затемsub_513060тогда это на самом делеMetadataLoader::LoadMetadataFile

Язык кода:javascript
копировать
int __fastcall sub_513060(const char *a1)
{
  void *v2; // r0
  int v3; // r4
  int v4; // r6
  size_t v5; // r5
  int v6; // r8
  unsigned int *v7; // r2
  int v8; // r1
  void *v9; // r0
  void *v10; // r0
  unsigned int *v12; // r2
  int v13; // r1
  unsigned int *v14; // r2
  int v15; // r1
  int v16; // [sp+Ch] [bp-4Ch] BYREF
  int v17[2]; // [sp+10h] [bp-48h] BYREF
  int v18; // [sp+18h] [bp-40h] BYREF
  int v19[2]; // [sp+1Ch] [bp-3Ch] BYREF
  int v20; // [sp+24h] [bp-34h] BYREF
  int v21; // [sp+28h] [bp-30h] BYREF
  int v22[2]; // [sp+2Ch] [bp-2Ch] BYREF
  int v23[2]; // [sp+34h] [bp-24h] BYREF

  sub_4C5B40(&v20);
  v19[0] = (int)"Metadata";
  v19[1] = 8;
  v22[0] = v20;
  v22[1] = *(_DWORD *)(v20 - 12);
  sub_4C7F74(&v21, v22, v19);
  v2 = (void *)(v20 - 12);
  if ( (_UNKNOWN *)(v20 - 12) != &unk_6A25F4 )
  {
    v7 = (unsigned int *)(v20 - 4);
    __dmb(0xBu);
    do
      v8 = __ldrex(v7);
    while ( __strex(v8 - 1, v7) );
    __dmb(0xBu);
    if ( v8 <= 0 )
      j_operator delete(v2);
  }
  v17[0] = (int)a1;
  v17[1] = strlen(a1);
  v23[0] = v21;
  v23[1] = *(_DWORD *)(v21 - 12);
  sub_4C7F74(&v18, v23, v17);
  v3 = 0;
  v16 = 0;
  v4 = sub_4CDA80(&v18, 3, 1, 1, 0, &v16);
  if ( !v16 )
  {
    v5 = sub_4CDE4C(v4, &v16);
    if ( !v16 )
    {
      v6 = sub_5163A8(v4, 0, 0);
      sub_4CDCF4(v4, &v16);
      if ( v16 )
      {
        v3 = 0;
        sub_516540(v6, 0);
      }
      else
      {
        v3 = sub_512FDC(v6, v5);
      }
    }
  }
  v9 = (void *)(v18 - 12);
  if ( (_UNKNOWN *)(v18 - 12) != &unk_6A25F4 )
  {
    v12 = (unsigned int *)(v18 - 4);
    __dmb(0xBu);
    do
      v13 = __ldrex(v12);
    while ( __strex(v13 - 1, v12) );
    __dmb(0xBu);
    if ( v13 <= 0 )
      j_operator delete(v9);
  }
  v10 = (void *)(v21 - 12);
  if ( (_UNKNOWN *)(v21 - 12) != &unk_6A25F4 )
  {
    v14 = (unsigned int *)(v21 - 4);
    __dmb(0xBu);
    do
      v15 = __ldrex(v14);
    while ( __strex(v15 - 1, v14) );
    __dmb(0xBu);
    if ( v15 <= 0 )
      j_operator delete(v10);
  }
  return v3;
}

верночем исходный код Обнаружитьэтотsub_512FDCЭто функция расшифровки

Язык кода:javascript
копировать
char *__fastcall sub_512FDC(int a1, size_t size)
{
  char *result; // r0
  size_t v5; // r2

  result = (char *)malloc(size);
  if ( size )
  {
    v5 = 0;
    do
    {
      *(_DWORD *)&result[v5 & 0xFFFFFFFC] = *(_DWORD *)(a1 + (v5 & 0xFFFFFFFC)) ^ dword_5DCF6C[(v5 + v5 / 0x84) % 0x84];
      v5 += 4;
    }
    while ( v5 < size );
  }
  return result;
}

Напишите скрипт расшифровки

Язык кода:javascript
копировать
import struct
f = open('global-metadata.dat', 'rb')
a = ""
a = f.read()
key = [0xF83DA249, 0x15D12772, 0x40C50697, 0x984E2B6B, 0x14EC5FF8, 0xB2E24927,
       0x3B8F77AE, 0x472474CD, 0x5B0CE524, 0xA17E1A31, 0x6C60852C, 0xD86AD267, 0x832612B7, 0x1CA03645, 0x5515ABC8,
       0xC5FEFF52, 0xFFFFAC00, 0x0FE95CB6, 0x79CF43DD, 0xAA48A3FB, 0xE1D71788, 0x97663D3A, 0xF5CFFEA7, 0xEE617632,
       0x4B11A7EE, 0x040EF0B5, 0x0606FC00, 0xC1530FAE, 0x7A827441, 0xFCE91D44, 0x8C4CC1B1, 0x7294C28D, 0x8D976162,
       0x8315435A, 0x3917A408, 0xAF7F1327, 0xD4BFAED7, 0x80D0ABFC, 0x63923DC3, 0xB0E6B35A, 0xB815088F, 0x9BACF123,
       0xE32411C3, 0xA026100B, 0xBCF2FF58, 0x641C5CFC, 0xC4A2D7DC, 0x99E05DCA, 0x9DC699F7, 0xB76A8621, 0x8E40E03C,
       0x28F3C2D4, 0x40F91223, 0x67A952E0, 0x505F3621, 0xBAF13D33, 0xA75B61CC, 0xAB6AEF54, 0xC4DFB60D, 0xD29D873A,
       0x57A77146, 0x393F86B8, 0x2A734A54, 0x31A56AF6, 0x0C5D9160, 0xAF83A19A, 0x7FC9B41F, 0xD079EF47, 0xE3295281,
       0x5602E3E5, 0xAB915E69, 0x225A1992, 0xA387F6B2, 0x7E981613, 0xFC6CF59A, 0xD34A7378, 0xB608B7D6, 0xA9EB93D9,
       0x26DDB218, 0x65F33F5F, 0xF9314442, 0x5D5C0599, 0xEA72E774, 0x1605A502, 0xEC6CBC9F, 0x7F8A1BD1, 0x4DD8CF07,
       0x2E6D79E0, 0x6990418F, 0xCF77BAD9, 0xD4FE0147, 0xFEF4A3E8, 0x85C45BDE, 0xB58F8E67, 0xA63EB8D7, 0xC69BD19B,
       0xDA442DCA, 0x3C0C1743, 0xE6F39D49, 0x33568804, 0x85EB6320, 0xDA223445, 0x36C4A941, 0xA9185589, 0x71B22D67,
       0xF59A2647, 0x3C8B583E, 0xD7717DED, 0xDF05699C, 0x4378367D, 0x1C459339, 0x85133B7F, 0x49800CE2, 0x3666CA0D,
       0xAF7AB504, 0x4FF5B8F1, 0xC23772E3, 0x3544F31E, 0x0F673A57, 0xF40600E1, 0x7E967417, 0x15A26203, 0x5F2E34CE,
       0x70C7921A, 0xD1C190DF, 0x5BB5DA6B, 0x60979C75, 0x4EA758A4, 0x078FE359, 0x1664639C, 0xAE14E73B, 0x2070FF03]
with open('decrypt', 'wb') as fp:
    n = 0
    while n < len(a):
        num = struct.unpack("<I", a[n:n + 4])[0]
        num = num ^ key[(n + n // 0x84) % 0x84]
        d = struct.pack('I', num)
        fp.write(d)
        n = n + 4

После завершения расшифровки я обнаружил, что Il2cppDumper по-прежнему нельзя использовать.,Поместите расшифрованный файл в редактор 010 и обнаружите, что магическое число неверно.,Изменить наAF 1B B1 FAВот и все,Оказывается, он убрал этап проверки магического числа.,Таким образом, вы можете изменить магическое число,Это предотвращает сброс с помощью универсального скрипта frida, упомянутого ранее.

Решение

 Использовав Il2cppDumper для его анализа, мы обнаружили, что он имеет следующие функции:

Язык кода:javascript
копировать
public Void .ctor() { }
// RVA: 0x518834 VA: 0xc575a834
private Void Start() { }
// RVA: 0x518838 VA: 0xc575a838
private Void Update() { }
// RVA: 0x51883c VA: 0xc575a83c
public Void Click() { }
// RVA: 0x518a24 VA: 0xc575aa24
private Boolean CheckFlag(String input) { }
// RVA: 0x518b54 VA: 0xc575ab54
public static String AESEncrypt(String text, String password, String iv) { }
// RVA: 0x518ee4 VA: 0xc575aee4
public static String AESDecrypt(String text, Byte[] password, Byte[] iv) { }
// RVA: 0x5191f0 VA: 0xc575b1f0
private static Void .cctor() { }

CheckFlagиз Смещение0x518a24,Пучокlibil2cpp.soпомещатьIDAвнутри Затемв соответствии сGПрыгнул мимоидти,Просмотр функций

Язык кода:javascript
копировать
int __fastcall sub_518A24(int a1, int a2)
{
  int v3; // r0
  int v4; // r4

  if ( !byte_69C825 )
  {
    sub_4B82BC(1279);
    byte_69C825 = 1;
  }
  v3 = dword_698140;
  if ( (*(_BYTE *)(dword_698140 + 178) & 1) != 0 && !*(_DWORD *)(dword_698140 + 96) )
  {
    il2cpp_runtime_class_init_0();
    v3 = dword_698140;
  }
  v4 = sub_518B54(
         *(_DWORD *)(v3 + 80),
         a2,
         *(_DWORD *)(*(_DWORD *)(v3 + 80) + 4000),
         *(_DWORD *)(*(_DWORD *)(v3 + 80) + 2364));
  if ( (*(_BYTE *)(dword_696FB8 + 178) & 1) != 0 && !*(_DWORD *)(dword_696FB8 + 96) )
    il2cpp_runtime_class_init_0();
  return sub_7D644(0, v4, dword_69B7F0, 0);
}

вот этоsub_518B54функция На самом деле этоAESDecrypt,Вы можете использовать сценарий IDA Il2cppDumper для восстановления имени функции.,Я тут просто ленюсь и не восстанавливаю.,Общая логика кода заключается в шифровании входных данных и последующем сравнении их с флагом.,Поэтому мы просто распечатываем ключ и флаг AES и расшифровываем их.

Другие методы

Существует несколько продвинутых инструментов, которые могут помочь нам выполнить обратный анализ Il2cpp, что также очень удобно для решения этой проблемы.

  • Zygisk-Il2CppDumper:одинMagiskплагин,Вы можете динамически выгружать имена функций и смещения функций.,Изначально вам необходимо самостоятельно настроить среду разработки Android.,сейчассуществовать Вместо этого автор используетgithub Действие: просто создайте его и введите имя пакета, чтобы скомпилировать и использовать его, что очень удобно.
  • frida-il2cpp-bridge:одинfridaБиблиотека,Очень мощный,Имеет не только функцию динамического дампа имен функций и смещений функций.,Также есть трассировка, перехват и другие функции.,Определенно стоит попробовать.

Reference

unity3d Принципиальный анализ il2cpp и обратный анализ IL2CPP Tutorial: Finding loaders for obfuscated global-metadata.dat files Анализ IL2CPP Unity Baby unity3D Исходный код Il2cpp

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода