Unpacked upgrade.lgu

furb3t

Forero Novato
Ubicación
Marte
Motor TL
2.0 CRDi 136 CV
Versión TL
Kosmo Aut. 4x4
Color TL
Platinum Silver
Sorry in advance, but I don't speak Spanish, so I'll write in English and then I'll translate with google translator the text.
I'd like to analyze file upgrade.lgu but this file is packed; looking around in the www, I tried (on xda) a file lgu2dir but it's not able to unpack our file because the system is changed. I saw that jdk changed this file for his radiologos (2byte!?!?! is an address?!?!) so I ask to him if there a program or a way to unpack the lgu file and have all the structure visible.
Thanks

Translation with google translate.
Lo siento por adelantado, pero yo no hablo español, así que voy a escribir en Inglés y luego voy a traducir con google traductor el texto.
Me gustaría analizar el archivo upgrade.lgu pero este archivo está lleno; mirando alrededor en el www, he intentado (en xda) un archivo lgu2dir pero no es capaz de desempaquetar nuestro archivo porque el sistema se cambia. Vi que jdk cambiaba este fichero por sus radiologos (2byte!?!?! Es una dirección?!?!) Así que le pregunto si hay un programa o una forma de desempaquetar el fichero lgu y tener toda la estructura visible.
Gracias
 

JKD

Forero Experto
Motor TL
2.0 CRDi 136 CV
Versión TL
Tecno Aut. 4x4
Color TL
Thunder Gray
Sorry in advance, but I don't speak Spanish, so I'll write in English and then I'll translate with google translator the text.
I'd like to analyze file upgrade.lgu but this file is packed; looking around in the www, I tried (on xda) a file lgu2dir but it's not able to unpack our file because the system is changed. I saw that jdk changed this file for his radiologos (2byte!?!?! is an address?!?!) so I ask to him if there a program or a way to unpack the lgu file and have all the structure visible.
Thanks
I didn't find any program to unpack our lgu files. Aerith performs that task. Some time ago I took a look at Aerith's code trying to know how lgu files are encoded and it seems a bit complex. LGU files are not only packed but also ciphered using ARC4 encryption algorithm. It's ciphered using the MD5 hash of different keywords, depending on the block of 512 bytes to work with. Aerith gets the MD5 hash of each keyword before ciphering/deciphering each block. These are keywords that I've found:

  • MERCURY9171 - TITIAN6849 - TITIAN6921 - VENUS4923 - HYPERION6991
  • EARTH8938 - PANDORA5327 - MARS6657 - MIMAS7831
  • JUPITER9486 - GANYMEDE1486 - SATURN1296 - PAN9387
  • URANUS7235 - NEPTUNE1387 - PLUTO6849 - MOON6912
  • EUROPA7337 - SUN5327

As I had other priorities I couldn't complete this analysis.
 

furb3t

Forero Novato
Ubicación
Marte
Motor TL
2.0 CRDi 136 CV
Versión TL
Kosmo Aut. 4x4
Color TL
Platinum Silver
Thank you jdk, I appreciate very much your information. Just my curiosity, in your radiologos file you have emptied upgrade.lgu with only 2 bytes (why these bytes, maybe upgrade.lgu shouldn't be null?) and then (I suppose) you have written and recompiled a new aerith, is it true?
For my analysis, I'll start to decompiled with IDA the original aerith file to found the exact algo to decipher each block.
 

JKD

Forero Experto
Motor TL
2.0 CRDi 136 CV
Versión TL
Tecno Aut. 4x4
Color TL
Thunder Gray
Thank you jdk, I appreciate very much your information. Just my curiosity, in your radiologos file you have emptied upgrade.lgu with only 2 bytes (why these bytes, maybe upgrade.lgu shouldn't be null?) and then (I suppose) you have written and recompiled a new aerith, is it true?
For my analysis, I'll start to decompiled with IDA the original aerith file to found the exact algo to decipher each block.
No matter how many bytes has upgrade.lgu file. The only purpose of those lgu files is that system locates one of them to start software update process. Just in case system detects an empty file, provided lgu files are filled with one or two bytes. This works by now.

I use IDA too to perform reversing but always with death code because I'm not able to debug software using a Wince emulator (provided by platform builder 6) with IDA.
 

furb3t

Forero Novato
Ubicación
Marte
Motor TL
2.0 CRDi 136 CV
Versión TL
Kosmo Aut. 4x4
Color TL
Platinum Silver
Well, i'll do some test with Ida and if I'll have a good disasm, I'll give you ;)
Thanks
 

furb3t

Forero Novato
Ubicación
Marte
Motor TL
2.0 CRDi 136 CV
Versión TL
Kosmo Aut. 4x4
Color TL
Platinum Silver
Ok, let's go to the "jump table for the switch statement" used to calculate hash; program can be switched between 11 cases, where each case can contain from 1 to 3 word that you found, in this way:
Case 0 ( "MECURY9171", "TITIAN6849" , "TITIAN6921" as default)
Case 1 ("VENUS4923","HYPERION6991","HYPERION6991" as default) (yes word is repeat it's not an error)
Case 2 ("EARTH8938","PANDORA5327","PANDORA5327" as default)
Case 3 ("MARS6657", "MIMAS7831","MIMAS7831" as default)
Case 4 ("JUPITER9486", "GANYMEDE1486", "GANYMEDE1486" as default)
Case 5 ("SATURN1296", "PAN9387","PAN9387" as default)
Case 6 ("URANUS7235" as default)
Case 7 ("NEPTUNE1387" as default)
Case 8 ("PLUTO6849" as default)
Case 9 ("MOON6912", "EUROPA7337", "EUROPA7337" as default)
Case 10 ("SUN5327" as default)
The argument passed in function are 2, the case selection and the position of the word in the selected case; from my analysis the only case always recalled is the 0 (R1) and the words recalled (R2) for 3 time are in this sequence: 0,1,2....
In the spoiler a little bit of related code (in asm of course) :)

.text:0001AC60 MOV R2, #0
.text:0001AC64 MOV R1, #0
.text:0001AC68 STR R5, [SP,#0x470+lpOverlapped]
.text:0001AC6C BL JumpTable_per_Hash
.text:0001AC70 LDR R0, =unk_1D69C5
.text:0001AC74 ADD R3, SP, #0x470+var_428
.text:0001AC78 MOV R2, #1
.text:0001AC7C MOV R1, #0
.text:0001AC80 STR R5, [SP,#0x470+lpOverlapped]
.text:0001AC84 BL JumpTable_per_Hash
.text:0001AC88 LDR R0, =unk_1D69C5
.text:0001AC8C MOV R3, #0x20
.text:0001AC90 STR R3, [SP,#0x470+lpOverlapped]
.text:0001AC94 ADD R3, SP, #0x470+Buffer
.text:0001AC98 MOV R2, #2
.text:0001AC9C MOV R1, #0
.text:0001ACA0 BL JumpTable_per_Hash
.text:0001ACA4 LDR R4, [SP,#0x470+var_44C]
.text:00

.text:000321CC JumpTable_per_Hash ; CODE XREF: sub_1A990+2DCp
.text:000321CC ; sub_1A990+2F4p ...
.text:000321CC
.text:000321CC arg_0 = 0
.text:000321CC
.text:000321CC STMFD SP!, {R4,LR}
.text:000321D0 MOV R4, R3
.text:000321D4 CMP R1, #0xA ; switch 11 cases
.text:000321D8 BHI locret_32364 ; default
.text:000321DC MOV LR, R1,LSL#1
.text:000321E0 ADD LR, LR, PC
.text:000321E4 LDRH LR, [LR,#4]
.text:000321E8 ADD PC, PC, LR ; switch jump
.text:000321E8 ; ---------------------------------------------------------------------------
.text:000321EC DCW loc_32204 - off_321F0 ; jump table for switch statement
.text:000321EE DCW loc_3222C - off_321F0 ; jumptable 000321E8 case 1
.text:000321F0 off_321F0 DCW loc_32254 - off_321F0 ; DATA XREF: JumpTable_per_Hash+20o
.text:000321F0 ; JumpTable_per_Hash+22o ...
.text:000321F0 ; jumptable 000321E8 case 2
.text:000321F2 DCW loc_3227C - off_321F0 ; jumptable 000321E8 case 3
.text:000321F4 DCW loc_322A4 - off_321F0 ; jumptable 000321E8 case 4
.text:000321F6 DCW loc_322CC - off_321F0 ; jumptable 000321E8 case 5
.text:000321F8 DCW loc_322F4 - off_321F0 ; jumptable 000321E8 case 6
.text:000321FA DCW loc_32304 - off_321F0 ; jumptable 000321E8 case 7
.text:000321FC DCW loc_32314 - off_321F0 ; jumptable 000321E8 case 8
.text:000321FE DCW loc_32324 - off_321F0 ; jumptable 000321E8 case 9
.text:00032200 DCW loc_3234C - off_321F0 ; jumptable 000321E8 case 10
.text:00032202 DCW 0x15C
.text:00032204 ; ---------------------------------------------------------------------------
.text:00032204
.text:00032204 loc_32204 ; CODE XREF: JumpTable_per_Hash+1Cj
.text:00032204 ; DATA XREF: JumpTable_per_Hash+20o
.text:00032204 CMP R2, #0 ; jumptable 000321E8 case 0
.text:00032208 LDREQ R3, =aMecury9171 ; "MECURY9171"
.text:0003220C BEQ loc_32358
.text:00032210 CMP R2, #1
.text:00032214 LDREQ R3, =aTitian6849 ; "TITIAN6849"
.text:00032218 BEQ loc_32358
.text:0003221C CMP R2, #2
.text:00032220 BNE locret_32364 ; default
.text:00032224 LDR R3, =aTitian6921 ; "TITIAN6921"
.text:00032228 B loc_32358
.text:0003222C ; ---------------------------------------------------------------------------
.text:0003222C
.text:0003222C loc_3222C ; CODE XREF: JumpTable_per_Hash+1Cj
.text:0003222C ; DATA XREF: JumpTable_per_Hash+22o
.text:0003222C CMP R2, #0 ; jumptable 000321E8 case 1
.text:00032230 LDREQ R3, =aVenus4923 ; "VENUS4923"
.text:00032234 BEQ loc_32358
.text:00032238 CMP R2, #1
.text:0003223C LDREQ R3, =aHyperion6991 ; "HYPERION6991"
.text:00032240 BEQ loc_32358
.text:00032244 CMP R2, #2
.text:00032248 BNE locret_32364 ; default
.text:0003224C LDR R3, =aHyperion6991 ; "HYPERION6991"
.text:00032250 B loc_32358
.........................

In the crypto function is recalled the algo "Microsoft Enhanced Cryptographic Provider v1.0"...study to be continued :)
 
Última edición por un moderador:

JKD

Forero Experto
Motor TL
2.0 CRDi 136 CV
Versión TL
Tecno Aut. 4x4
Color TL
Thunder Gray
In the crypto function is recalled the algo "Microsoft Enhanced Cryptographic Provider v1.0"...study to be continued :)
I prefer the decompiled code :sneaky:

aerith.png
This is part of decrypt function.
  • On line 27, the fourth argument ( 1u ) specifies the algorithm provider. In this case, 1u is PROV_RSA_FULL
  • The fifth argument is a flag that may be 0 (for testing purpose I guess).
  • On line 29, checks that the result is not 0x80090016 which is the constant of NTE_BAD_KEYSET
  • So these lines are just a test.
  • On line 35, starts setting key, specifying provider PROV_RSA_FULL again. The flag is 8 ( CRYPT_NEWKEYSET )

At this point it's able to create md5 hash.
  • On line 45, CryptCreateHash uses as algorithm id the constant 0x8003 which is CALG_MD5 . You can find ids at this link

aerith2.png
  • On line 51, sets the keyword stored in v4 whose md5 hash is to be generated. v11 is the keyword's length. The md5 hash is stored in phHash which is passed to line 53.

  • On line 53, the second argument 0x6801 is the constant id for algorithm RC4 (CALG_RC4) . The fourth argument is the key type to be generated. According to Microsoft, " Thus, if a 128-bit RC4session key is to be generated, the value 0x00800000 is combined with any other dwFlags predefined value with a bitwise-OR operation", so we know that the algorithm used is "128-bit RC4".

  • On line 55, it decrypts the buffer passed in v5, returning result on the same variable. v19 contains the length of buffer before decryption. After decryption, v19 contains the length of the resulting buffer. The second argument from CryptDecrypt sets that no hash has to be generated. The third one sets that there won't be any more data to decrypt and the fourth one is not used in this case. The fact that decrypted buffer is stored in the same memory allocation points me that resulting buffer length will never be bigger than the original data. Length will be equal or less. Otherwise a memory exception would raise.
So, decrypt function parameters are:
  • signed int __fastcall decrypt(int a1, BYTE *buffer, DWORD len, const wchar_t *key)
The type of each argument is set automatically by IDA.
It returns 1 if success or 0 if fail

--

Para los que no entienden inglés o no están versados en informática, estos posts tratan sobre la forma en la que el programa Aerith.exe descodifica los archivos de actualización .lgu. Si se completa el análisis de este proceso se podrá extraer el contenido de dichos archivos y, con suerte, poder modificarlos/generarlos tras realizar los cambios que se crean oportunos.
 
Última edición:

furb3t

Forero Novato
Ubicación
Marte
Motor TL
2.0 CRDi 136 CV
Versión TL
Kosmo Aut. 4x4
Color TL
Platinum Silver
This is the routine called to open file (address 0x1BFBC) (sorry I used to rename function):
Insertar CODE, HTML o PHP:
signed int __fastcall OpenFile_xDecrypt(int a1)
{
  int v1; // r6@1
  signed int v2; // r11@1
  int v3; // r4@1
  int v4; // r2@1
  BOOL v5; // r0@2
  signed int v6; // r3@2
  BOOL v7; // r5@2
  int v8; // r5@19
  int i; // r2@29
  int v11; // r1@33
  DWORD NumberOfBytesRead; // [sp+4h] [bp-234h]@1
  int v13; // [sp+8h] [bp-230h]@1
  char v14; // [sp+Ch] [bp-22Ch]@1
  char Buffer; // [sp+10h] [bp-228h]@1
  char v16; // [sp+11h] [bp-227h]@1
  int v17; // [sp+210h] [bp-28h]@1

  v1 = a1;
  v17 = dword_1B203C;
  NumberOfBytesRead = 0;
  Buffer = 0;
  v2 = 0;
  v3 = 0;
  memset(&v16, 0, 0x1FFu);
  v4 = *(_DWORD *)(v1 + 20);
  v13 = 977490499;
  v14 = 0;
  if ( v4 == -1 )
    goto LABEL_26;
  NKDbgPrintfW(L"S Area: %d\r\n", *(_DWORD *)(v1 + 28));
  SetFilePointer(*(HANDLE *)(v1 + 20), 0, 0, 0);
  sub_1B53C(v1, *(_DWORD *)(v1 + 28));
  v5 = ReadFile(*(HANDLE *)(v1 + 20), &Buffer, 0x200u, &NumberOfBytesRead, 0);
  v6 = *(_DWORD *)(v1 + 28);
  v7 = v5;
  if ( v6 > 7 )
  {
    switch ( v6 )
    {
      case 8:
        Key_xdecrypt((int)&unk_1D69C4, 4, 1, (BYTE *)&Buffer, 0x200u);
        break;
      case 9:
        Key_xdecrypt((int)&unk_1D69C4, 5, 1, (BYTE *)&Buffer, 0x200u);
        break;
      case 104:
        Key_xdecrypt((int)&unk_1D69C4, 9, 1, (BYTE *)&Buffer, 0x200u);
        break;
    }
  }
  else if ( v6 == 7 )
  {
    Key_xdecrypt((int)&unk_1D69C4, 3, 1, (BYTE *)&Buffer, 0x200u);
  }
  else if ( v6 == 3 )
  {
    Key_xdecrypt((int)&unk_1D69C4, 0, 1, (BYTE *)&Buffer, 0x200u);
  }
  else if ( v6 > 3 )
  {
    if ( v6 <= 5 )
    {
      Key_xdecrypt((int)&unk_1D69C4, 1, 1, (BYTE *)&Buffer, 0x200u);
    }
    else if ( v6 == 6 )
    {
      Key_xdecrypt((int)&unk_1D69C4, 2, 1, (BYTE *)&Buffer, 0x200u);
    }
  }
  sub_1B53C(v1, *(_DWORD *)(v1 + 28));
  if ( !v7 )
    goto LABEL_26;
  v8 = 0;
  while ( *(&Buffer + v8) != (char)v13
       || *(&Buffer + v8 + 1) != SBYTE1(v13)
       || *(&Buffer + v8 + 2) != SBYTE2(v13)
       || *(&Buffer + v8 + 3) != SBYTE3(v13) )
  {
    if ( ++v8 >= 512 )
      goto LABEL_25;
  }
  if ( (unsigned __int8)((v8 + 1 < 0) ^ __OFADD__(v8, 1)) | (v8 == -1) )
  {
LABEL_25:
    NKDbgPrintfW(L"Cant Find CRC code\r\n", &Buffer, (char)v13);
LABEL_26:
    sub_32D2C(v17);
    return -1;
  }
  NKDbgPrintfW(L"Find CRC code: %d\r\n", v8, (char)v13);
  for ( i = v8 + 4; i < v8 + 68; ++i )
  {
    if ( *(_DWORD *)(v1 + 28) != 3 || dword_1D1E10 != 1 && dword_1D1E20 != 1 )
    {
      v11 = *(&Buffer + i);
      if ( v11 == 35 )
        break;
    }
    else
    {
      v11 = *(&Buffer + i);
      if ( v11 == 35 )
      {
        if ( v2 )
          break;
        v2 = 1;
        v3 = 0;
        continue;
      }
    }
    if ( v3 )
      v3 *= 10;
    v3 = v11 + v3 - 48;
  }
  NKDbgPrintfW(L"CRC value: %u\r\n", v3);
  sub_32D2C(v17);
  return v3;
}
so v6 value is the case to calculate which keyword in the table use to crypt....

..... at address 0x31CF0....
Insertar CODE, HTML o PHP:
int __fastcall Key_xdecrypt(int result, int a2, int a3, BYTE *a4, DWORD len)
{
  BYTE *v5; // r4@1
  const wchar_t *v6; // r3@3

  v5 = a4;
  switch ( a2 )
  {
    case 0:
      if ( !a3 )
      {
        v6 = L"MECURY9171";
        goto LABEL_52;
      }
      if ( a3 == 1 )
      {
        v6 = L"TITIAN6849";
        goto LABEL_52;
      }
      if ( a3 == 2 )
      {
        v6 = L"TITIAN6921";
        goto LABEL_52;
      }
      break;
    case 1:
      if ( !a3 )
      {
        v6 = L"VENUS4923";
        goto LABEL_52;
      }
      if ( a3 == 1 )
      {
        v6 = L"HYPERION6991";
        goto LABEL_52;
      }
      if ( a3 == 2 )
      {
        v6 = L"HYPERION6991";
        goto LABEL_52;
      }
      break;
    case 2:
      if ( !a3 )
      {
        v6 = L"EARTH8938";
        goto LABEL_52;
      }
      if ( a3 == 1 )
      {
        v6 = L"PANDORA5327";
        goto LABEL_52;
      }
      if ( a3 == 2 )
      {
        v6 = L"PANDORA5327";
        goto LABEL_52;
      }
      break;
    case 3:
      if ( !a3 )
      {
        v6 = L"MARS6657";
        goto LABEL_52;
      }
      if ( a3 == 1 )
      {
        v6 = L"MIMAS7831";
        goto LABEL_52;
      }
      if ( a3 == 2 )
      {
        v6 = L"MIMAS7831";
        goto LABEL_52;
      }
      break;
    case 4:
      if ( !a3 )
      {
        v6 = L"JUPITER9486";
        goto LABEL_52;
      }
      if ( a3 == 1 )
      {
        v6 = L"GANYMEDE1486";
        goto LABEL_52;
      }
      if ( a3 == 2 )
      {
        v6 = L"GANYMEDE1486";
        goto LABEL_52;
      }
      break;
    case 5:
      if ( !a3 )
      {
        v6 = L"SATURN1296";
        goto LABEL_52;
      }
      if ( a3 == 1 )
      {
        v6 = L"PAN9387";
        goto LABEL_52;
      }
      if ( a3 == 2 )
      {
        v6 = L"PAN9387";
        goto LABEL_52;
      }
      break;
    case 6:
      if ( !a3 )
      {
        v6 = L"URANUS7235";
        goto LABEL_52;
      }
      break;
    case 7:
      if ( !a3 )
      {
        v6 = L"NEPTUNE1387";
        goto LABEL_52;
      }
      break;
    case 8:
      if ( !a3 )
      {
        v6 = L"PLUTO6849";
        goto LABEL_52;
      }
      break;
    case 9:
      if ( !a3 )
      {
        v6 = L"MOON6912";
        goto LABEL_52;
      }
      if ( a3 == 1 )
      {
        v6 = L"EUROPA7337";
        goto LABEL_52;
      }
      if ( a3 == 2 )
      {
        v6 = L"EUROPA7337";
        goto LABEL_52;
      }
      break;
    case 10:
      if ( !a3 )
      {
        v6 = L"SUN5327";
LABEL_52:
        result = DecryptF(result, v5, len, v6);
      }
      break;
    default:
      return result;
  }
  return result;
}
So this function returs as "result"= DecryptF(result, v5, len, v6) ....

DecryptF is the function that you have analysed in previous post (at address 0x31A68)
 
Última edición por un moderador:
  • Me Gusta
Reacciones: JKD

furb3t

Forero Novato
Ubicación
Marte
Motor TL
2.0 CRDi 136 CV
Versión TL
Kosmo Aut. 4x4
Color TL
Platinum Silver
...continue...
this is the routine to open file .lgu:
Insertar CODE, HTML o PHP:
int __fastcall LoadDumpLGU(int a1, int a2, int a3, int a4)
{
  signed int v4; // r4@1
  void *v5; // r0@6
  int v6; // lr@7
  int *v7; // r4@9
  void *v8; // r1@9
  int v9; // r2@9
  int v10; // r0@9
  int v11; // r1@10
  int v12; // r2@10
  int v13; // r3@10
  int v14; // r0@10
  void *v15; // r4@11
  void *v16; // r0@13
  int v17; // lr@14
  void *v18; // r0@17
  int v19; // lr@18
  void *v20; // r0@21
  int v21; // lr@22
  int v22; // r1@24
  int v23; // r2@24
  int v24; // r3@24
  int v25; // r0@24
  int result; // r0@30

  v4 = a2;
  sub_12918((int)L"Get DumpImage -> State: %d\r\n", a2, a3, a4);
  if ( v4 < 3 )
    goto LABEL_30;
  if ( v4 <= 9 )
  {
    v20 = operator new(0x834u);
    if ( v20 )
      v21 = sub_1A384((int)v20);
    else
      v21 = 0;
    dword_1B21E8 = v21;
    sub_1A620(v21, (int)&unk_1D17C0, v4, 6);
    if ( v25 == 1 )
    {
      Check_LguHeader_Structure(dword_1B21E8);  // Here check header (use Words in Table x decryt) and structure of LGU
      CreateDumpImage(dword_1B21E8);            // Here load Eu20_upgrade.lgu
    }
    else
    {
      sub_12918((int)L"NOT upgrade.lgu..!!\r\n", v22, v23, v24);
    }
    v15 = (void *)dword_1B21E8;
  }
  else
  {
    if ( v4 == 150 )
    {
      v18 = operator new(0x834u);
      if ( v18 )
        v19 = sub_1A384((int)v18);
      else
        v19 = 0;
      v7 = &dword_1B21E8;
      dword_1B21E8 = v19;
      sub_1A620(v19, (int)&unk_1D17C0, 150, 2);
LABEL_11:
      CreateDumpImage(*v7);
      v15 = (void *)*v7;
      goto LABEL_28;
    }
    if ( v4 == 151 )
    {
      v16 = operator new(0x834u);
      if ( v16 )
        v17 = sub_1A384((int)v16);
      else
        v17 = 0;
      v7 = &dword_1B21E8;
      v8 = &unk_1D17C0;
      v9 = 151;
      v10 = v17;
      dword_1B21E8 = v17;
    }
    else
    {
      if ( v4 != 152 )
        goto LABEL_30;
      v5 = operator new(0x834u);
      if ( v5 )
        v6 = sub_1A384((int)v5);
      else
        v6 = 0;
      v7 = &dword_1B21E8;
      v8 = &unk_1D17C0;
      v9 = 152;
      v10 = v6;
      dword_1B21E8 = v6;
    }
    sub_1A620(v10, (int)v8, v9, 6);
    if ( v14 == 1 )
      goto LABEL_11;
    sub_12918((int)L"NOT upgrade.lgu..!!\r\n", v11, v12, v13);
    v15 = (void *)*v7;
  }
LABEL_28:
  if ( v15 )
  {
    sub_1BCA8(v15);
    operator delete(v15);
  }
LABEL_30:
  result = dword_1B21DC;
  if ( dword_1B21DC )
    result = sub_14FF4((HWND *)dword_1B21DC, 1019, 1);
  return result;
}
..to be continued....
 

furb3t

Forero Novato
Ubicación
Marte
Motor TL
2.0 CRDi 136 CV
Versión TL
Kosmo Aut. 4x4
Color TL
Platinum Silver
...continue..
looks routine Check_LguHeader_Structure...
Insertar CODE, HTML o PHP:
signed int __fastcall Check_LguHeader_Structure(int a1)
{
  int v1; // r8@1
  int v2; // r9@1
  int v3; // r1@1
  int v4; // r2@1
  void *v5; // r0@1
  int v6; // r6@2
  signed int v7; // r5@3
  signed int v8; // r7@3
  int v9; // r2@5
  int v10; // r4@6
  int v11; // r1@22
  int v12; // r2@22
  DWORD NumberOfBytesRead; // [sp+4h] [bp-42Ch]@1
  char Buffer; // [sp+8h] [bp-428h]@1
  char v16; // [sp+9h] [bp-427h]@1
  char v17; // [sp+208h] [bp-228h]@1
  _BYTE v18[3]; // [sp+209h] [bp-227h]@1
  int v19; // [sp+408h] [bp-28h]@1

  v1 = a1;
  v19 = dword_1B203C;
  Buffer = 0;
  memset(&v16, 0, 0x1FFu);
  v17 = 0;
  NumberOfBytesRead = 0;
  v2 = 0;
  memset(v18, 0, 0x1FFu);
  v5 = *(void **)(v1 + 20);
  if ( v5 != (void *)-1 )
  {
    SetFilePointer(v5, 0, 0, 0);
    v6 = 0;
    while ( 1 )
    {
      v7 = 0;
      ReadFile(*(HANDLE *)(v1 + 20), &Buffer, 0x200u, &NumberOfBytesRead, 0);
      Key_xdecrypt((int)&unk_1D69C4, v6, 0, (BYTE *)&Buffer, 0x200u);
      v8 = strlen(&Buffer);
      if ( v8 <= 0 )
        break;
      sub_12BFC(&Buffer, &v17, 0, 15);
      if ( strcmp("LGE#EU20#AERITH", &v17) )
        break;
      NKDbgPrintfW(L"[LGE Header] Valid key header\r\n");
      v9 = 0;
      if ( v8 > 0 )
      {
        do
        {
          v10 = v9 + 1;
          if ( *((_BYTE *)&NumberOfBytesRead + v9 + 4) == 35 )
          {
            if ( ++v7 % 2 )
            {
              if ( v7 <= 17 )
              {
                sub_12BFC(&Buffer, &v17, v2, v9);
                sub_1B190(v1, v6, v7, &v17);
              }
            }
            else
            {
              v2 = v9 + 1;
            }
          }
          v9 = v10;
        }
        while ( v10 < v8 );
      }
      if ( ++v6 >= 11 )
      {
        v4 = 2098176;
        if ( dword_1D1E68 == 2098176 )
        {
          v4 = dword_1D1E6C;
          if ( dword_1D1E6C == 62423040 && dword_1D1E70 == 146800640 )
          {
            v4 = dword_1D1E74;
            if ( dword_1D1E74 == 786432000 && dword_1D1E78 == 52428800 )
            {
              v4 = dword_1D1E7C;
              if ( dword_1D1E7C == 1740800000 && dword_1D1E80 == 52428800 )
              {
                v4 = dword_1D1E84;
                if ( dword_1D1E84 == 216912896 )
                {
                  if ( strlen((const char *)&unk_1D2D30) )
                  {
                    dword_1D2B6C = sub_2C034(&dword_1D2AB8, &unk_1D2D30);
                    NKDbgPrintfW(L"[LGE Header] Valid lgu structure\r\n");
                    FailureLoadError(v19, v11, v12);
                    return 1;
                  }
                }
              }
            }
          }
        }
        break;
      }
    }
  }
  FailureLoadError(v19, v3, v4);
  return 0;
}
 

JKD

Forero Experto
Motor TL
2.0 CRDi 136 CV
Versión TL
Tecno Aut. 4x4
Color TL
Thunder Gray
...continue..
looks routine Check_LguHeader_Structure...
Insertar CODE, HTML o PHP:
signed int __fastcall Check_LguHeader_Structure(int a1)
{
...
      ReadFile(*(HANDLE *)(v1 + 20), &Buffer, 0x200u, &NumberOfBytesRead, 0);
      Key_xdecrypt((int)&unk_1D69C4, v6, 0, (BYTE *)&Buffer, 0x200u);
      v8 = strlen(&Buffer);
      if ( v8 <= 0 )
        break;
      sub_12BFC(&Buffer, &v17, 0, 15);
      if ( strcmp("LGE#EU20#AERITH", &v17) )
        break;
...}
One year ago, when I was analyzing this function, I tried to reproduce these steps in my linux (qt creator/c++) reading my own lgu image backup but I couldn't get "LGE#EU20#AERITH" string after the first block's decrytion. Perhaps there were some differences setting up RC4 algorithm. Then, Menavrus came to our lives and my attention pointed to other projects. You are in the right direction. It would be much easier if you could execute aerith step by step. It's important to know if all file needs to be decrypted. I see in that function what I think they are pointers to serveral partitions.
 
Arriba