Registration Code (Part 1): w%kQ6
Registration Code (Part 2): b<#$1[*(cw~
In order to register on this forum, you must use the codes above. Combine them into one code (copy paste).

Parsing NSgtdData.NOS

Topics regarding the online game Nostale.
Post Reply
User avatar
atom0s
Site Admin
Posts: 410
Joined: Sun Jan 04, 2015 11:23 pm
Location: 127.0.0.1
Contact:

Parsing NSgtdData.NOS

Post by atom0s » Mon Aug 15, 2016 12:43 pm

This is a post containing some information to parse the NSgtdData.NOS file.
This file contains a few other important files that many feel are important for things like private server development.

If you open the file in a hex editor, this is the layout of the file:

Code: Select all

+ 0x0000 = File Entry Count (The number of files stored in this .NOS file.)
Each file after that is in the following format: (+4 from the start of the file)

Code: Select all

+ 0x0000 = File Index
+ 0x0004 = File Name Length
+ 0x0008 = File Name
+ 0x00?? = File Flags (Used for compression / encryption.)
+ 0x00?? = File Size
+ 0x00?? = File Data
In a pseudo structure format:

Code: Select all

struct FileEntry
{
    uint32_t FileIndex;
    uint32_t FileNameLength;
    uint8_t  FileName[FileNameLength];
    uint32_t FileFlags;
    uint32_t FileSize;
    uint8_t  FileData[FileSize];
};
The end of the file is used for validation. These are specific to each file and are handled internally in the client. The last 12 bytes are reserved for validation in two methods:
FileSize - 0x04 = 'Checksum' Validation (4 byte long checksum, unsure how this valid is determined currently.)
FileSize - 0x0C = 'Timestamp' Validation (8 byte long timestamp in OLETIME format.)

This can be seen happening here:

Code: Select all

CODE:004B392C ; =============== S U B R O U T I N E =======================================
CODE:004B392C
CODE:004B392C ; Attributes: bp-based frame
CODE:004B392C
CODE:004B392C sub_4B392C      proc near               ; CODE XREF: sub_6814B8+52Ep
CODE:004B392C                                         ; sub_6814B8+5FBp ...
CODE:004B392C
CODE:004B392C var_10          = dword ptr -10h
CODE:004B392C var_C           = dword ptr -0Ch
CODE:004B392C var_8           = qword ptr -8
CODE:004B392C
CODE:004B392C                 push    ebp
CODE:004B392D                 mov     ebp, esp
CODE:004B392F                 add     esp, 0FFFFFFF0h
CODE:004B3932                 push    ebx
CODE:004B3933                 mov     ebx, eax
CODE:004B3935                 push    0Ch
CODE:004B3937                 push    0
CODE:004B3939                 push    0
CODE:004B393B                 push    0
CODE:004B393D                 mov     cx, 0Bh
CODE:004B3941                 mov     dx, 0Ch
CODE:004B3945                 mov     ax, 7D4h
CODE:004B3949                 call    sub_4AD060                    <=== Prepares a file time.
CODE:004B394E                 fstp    [ebp+var_8]
CODE:004B3951                 wait
CODE:004B3952                 push    40h
CODE:004B3954                 mov     ecx, ebx
CODE:004B3956                 mov     dl, 1
CODE:004B3958                 mov     eax, off_41A328
CODE:004B395D                 call    sub_41E558                    <=== Creates the file stream instance to parse the file.
CODE:004B3962                 mov     [ebp+var_C], eax
CODE:004B3965                 xor     eax, eax
CODE:004B3967                 push    ebp
CODE:004B3968                 push    offset loc_4B39E8
CODE:004B396D                 push    dword ptr fs:[eax]
CODE:004B3970                 mov     fs:[eax], esp                 <=== Exception Filter
CODE:004B3973                 mov     eax, [ebp+var_C]
CODE:004B3976                 mov     edx, [eax]
CODE:004B3978                 call    dword ptr [edx]               <=== Gets the file size of the file.
CODE:004B397A                 sub     eax, 4                        <=== Subtracts 4 from the file size.
CODE:004B397D                 sbb     edx, 0
CODE:004B3980                 push    edx
CODE:004B3981                 push    eax
CODE:004B3982                 mov     eax, [ebp+var_C]
CODE:004B3985                 call    sub_41E0C4                    <=== Sets the file pointer to fileSize - 4
CODE:004B398A                 lea     edx, [ebp+var_10]
CODE:004B398D                 mov     ecx, 4
CODE:004B3992                 mov     eax, [ebp+var_C]
CODE:004B3995                 mov     ebx, [eax]
CODE:004B3997                 call    dword ptr [ebx+0Ch]           <=== Reads the 'checksum' value from the end of the file.
CODE:004B399A                 mov     eax, [ebp+var_10]
CODE:004B399D                 cmp     eax, ds:dword_68D4E0          <=== Compares the 'checksum' value to an internal hard-coded value. (Currently: 0x01323EEE)
CODE:004B39A3                 jnz     short loc_4B39D2
CODE:004B39A5                 mov     eax, [ebp+var_C]
CODE:004B39A8                 mov     edx, [eax]
CODE:004B39AA                 call    dword ptr [edx]
CODE:004B39AC                 sub     eax, 4
CODE:004B39AF                 sbb     edx, 0
CODE:004B39B2                 sub     eax, 8
CODE:004B39B5                 sbb     edx, 0
CODE:004B39B8                 push    edx
CODE:004B39B9                 push    eax
CODE:004B39BA                 mov     eax, [ebp+var_C]
CODE:004B39BD                 call    sub_41E0C4                    <=== Sets the file pointer to fileSize - 12
CODE:004B39C2                 lea     edx, [ebp+var_8]
CODE:004B39C5                 mov     ecx, 8
CODE:004B39CA                 mov     eax, [ebp+var_C]
CODE:004B39CD                 mov     ebx, [eax]
CODE:004B39CF                 call    dword ptr [ebx+0Ch]           <=== Reads the file timestamp from the end of the file.
CODE:004B39D2
CODE:004B39D2 loc_4B39D2:                             ; CODE XREF: sub_4B392C+77j
CODE:004B39D2                 xor     eax, eax
CODE:004B39D4                 pop     edx
CODE:004B39D5                 pop     ecx
CODE:004B39D6                 pop     ecx
CODE:004B39D7                 mov     fs:[eax], edx
CODE:004B39DA                 push    offset loc_4B39EF
CODE:004B39DF
CODE:004B39DF loc_4B39DF:                             ; CODE XREF: sub_4B392C+C1j
CODE:004B39DF                 mov     eax, [ebp+var_C]
CODE:004B39E2                 call    sub_403E54
CODE:004B39E7                 retn
CODE:004B39E8 ; ---------------------------------------------------------------------------
CODE:004B39E8
CODE:004B39E8 loc_4B39E8:                             ; DATA XREF: sub_4B392C+3Co
CODE:004B39E8                 jmp     loc_4045BC
CODE:004B39ED ; ---------------------------------------------------------------------------
CODE:004B39ED                 jmp     short loc_4B39DF
CODE:004B39EF ; ---------------------------------------------------------------------------
CODE:004B39EF
CODE:004B39EF loc_4B39EF:                             ; CODE XREF: sub_4B392C+BBj
CODE:004B39EF                                         ; DATA XREF: sub_4B392C+AEo
CODE:004B39EF                 fld     [ebp+var_8]
CODE:004B39F2                 pop     ebx
CODE:004B39F3                 mov     esp, ebp
CODE:004B39F5                 pop     ebp
CODE:004B39F6                 retn
CODE:004B39F6 sub_4B392C      endp
The current file list is:

Code: Select all

kr_abuse.lst         - Index: 0001 - Flags: 0000 - Size: 00040196
act_desc.dat         - Index: 0002 - Flags: 0001 - Size: 00000393
BCard.dat            - Index: 0003 - Flags: 0001 - Size: 00028729
Card.dat             - Index: 0004 - Flags: 0001 - Size: 00252389
Item.dat             - Index: 0005 - Flags: 0001 - Size: 01212714
monster.dat          - Index: 0006 - Flags: 0001 - Size: 01467426
npctalk.dat          - Index: 0007 - Flags: 0001 - Size: 00540964
Skill.dat            - Index: 0008 - Flags: 0001 - Size: 00606545
quest.dat            - Index: 0009 - Flags: 0001 - Size: 00360250
qstprize.dat         - Index: 0010 - Flags: 0001 - Size: 00064414
tutorial.dat         - Index: 0011 - Flags: 0001 - Size: 00049041
kr_nosmall.dat       - Index: 0012 - Flags: 0001 - Size: 00358243
shoptype.dat         - Index: 0013 - Flags: 0001 - Size: 00004338
MapIDData.dat        - Index: 0014 - Flags: 0001 - Size: 00008368
MapPointData.dat     - Index: 0015 - Flags: 0001 - Size: 00002500
de_nosmall.dat       - Index: 0016 - Flags: 0001 - Size: 00371589
fr_nosmall.dat       - Index: 0017 - Flags: 0001 - Size: 00371589
gsp_nosmall.dat      - Index: 0018 - Flags: 0001 - Size: 00277354
hk_nosmall.dat       - Index: 0019 - Flags: 0001 - Size: 00369901
in_nosmall.dat       - Index: 0020 - Flags: 0001 - Size: 00232884
jp_nosmall.dat       - Index: 0021 - Flags: 0001 - Size: 00298585
my_nosmall.dat       - Index: 0022 - Flags: 0001 - Size: 00362157
tw_nosmall.dat       - Index: 0023 - Flags: 0001 - Size: 00264860
uk_nosmall.dat       - Index: 0024 - Flags: 0001 - Size: 00371589
de_abuse.lst         - Index: 0025 - Flags: 0000 - Size: 00000004
fr_abuse.lst         - Index: 0026 - Flags: 0000 - Size: 00000004
gsp_abuse.lst        - Index: 0027 - Flags: 0000 - Size: 00001369
hk_abuse.lst         - Index: 0028 - Flags: 0000 - Size: 00051554
in_abuse.lst         - Index: 0029 - Flags: 0000 - Size: 00000004
jp_abuse.lst         - Index: 0030 - Flags: 0000 - Size: 00000004
my_abuse.lst         - Index: 0031 - Flags: 0000 - Size: 00001303
tw_abuse.lst         - Index: 0032 - Flags: 0000 - Size: 00000004
uk_abuse.lst         - Index: 0033 - Flags: 0000 - Size: 00000004
it_nosmall.dat       - Index: 0034 - Flags: 0001 - Size: 00371589
it_abuse.lst         - Index: 0035 - Flags: 0000 - Size: 00000004
th_nosmall.dat       - Index: 0036 - Flags: 0001 - Size: 00371589
th_abuse.lst         - Index: 0037 - Flags: 0000 - Size: 00000607
cn_nosmall.dat       - Index: 0038 - Flags: 0001 - Size: 00219999
cn_abuse.lst         - Index: 0039 - Flags: 0000 - Size: 00013766
pl_nosmall.dat       - Index: 0040 - Flags: 0001 - Size: 00371589
pl_abuse.lst         - Index: 0041 - Flags: 0000 - Size: 00000000
es_nosmall.dat       - Index: 0042 - Flags: 0001 - Size: 00371589
es_abuse.lst         - Index: 0043 - Flags: 0000 - Size: 00000000
kr_se_nosmall.dat    - Index: 0044 - Flags: 0001 - Size: 00056947
kr_se_abuse.lst      - Index: 0045 - Flags: 0000 - Size: 00040631
qstnpc.dat           - Index: 0046 - Flags: 0001 - Size: 00008028
Derp~
Need a great web host? Check out: AnHonestHost.com


Donations can be made via Paypal:
https://www.paypal.me/atom0s
User avatar
atom0s
Site Admin
Posts: 410
Joined: Sun Jan 04, 2015 11:23 pm
Location: 127.0.0.1
Contact:

Re: Parsing NSgtdData.NOS

Post by atom0s » Mon Aug 15, 2016 1:00 pm

Next, the file is processed by the following:
  1. int __usercall sub_4C6630@<eax>(char *a1@<eax>, void (__fastcall *a2)(char *, int)@<edx>, char *a3@<ecx>)
  2. {
  3.   int v3; // ebx@1
  4.   int v4; // ebx@4
  5.   int v5; // ecx@5
  6.   int v6; // eax@5
  7.   int v7; // eax@8
  8.   int v9; // [sp-18h] [bp-54h]@3
  9.   void *v10; // [sp-14h] [bp-50h]@3
  10.   int *v11; // [sp-10h] [bp-4Ch]@3
  11.   unsigned int v12; // [sp-Ch] [bp-48h]@1
  12.   int *v13; // [sp-8h] [bp-44h]@1
  13.   int *v14; // [sp-4h] [bp-40h]@1
  14.   void *v15; // [sp+0h] [bp-3Ch]@13
  15.   int *v16; // [sp+Ch] [bp-30h]@3
  16.   int v17; // [sp+10h] [bp-2Ch]@3
  17.   _DWORD *v18; // [sp+14h] [bp-28h]@3
  18.   int v19; // [sp+18h] [bp-24h]@1
  19.   char *v20; // [sp+1Ch] [bp-20h]@1
  20.   int v21; // [sp+20h] [bp-1Ch]@3
  21.   int v22; // [sp+24h] [bp-18h]@5
  22.   signed int v23; // [sp+28h] [bp-14h]@5
  23.   int v24; // [sp+2Ch] [bp-10h]@7
  24.   int v25; // [sp+30h] [bp-Ch]@5
  25.   char *v26; // [sp+34h] [bp-8h]@1
  26.   void (__fastcall *v27)(char *, int); // [sp+38h] [bp-4h]@1
  27.   int savedregs; // [sp+3Ch] [bp+0h]@1
  28.  
  29.   v20 = 0;
  30.   v19 = 0;
  31.   v26 = a3;
  32.   v27 = a2;
  33.   v3 = (int)a1;
  34.   v14 = &savedregs;
  35.   v13 = (int *)&loc_4C6831;
  36.   v12 = __readfsdword(0);
  37.   __writefsdword(0, (unsigned int)&v12);
  38.   if ( sub_40C350(a1) && v27 )
  39.   {
  40.     v16 = (int *)sub_403E24((int)off_41A174, 1);
  41.     v17 = sub_403E24((int)off_41A464, 1);
  42.     v18 = sub_41E558((int)off_41A374, 1, v3, 0);
  43.     v11 = &savedregs;
  44.     v10 = &loc_4C680F;
  45.     __writefsdword(0, (unsigned int)&v9);
  46.  
  47.     // Read the total file count within the .NOS file..
  48.     (*(void (__fastcall **)(signed int, int *, unsigned __int32, void *, int *, unsigned int))(*v18 + 12))(
  49.       4,
  50.       &v21,
  51.       __readfsdword(0),
  52.       &loc_4C680F,
  53.       &savedregs,
  54.       v12);
  55.  
  56.     // Ensure we have files to parse..
  57.     if ( v21 - 1 >= 0 )
  58.     {
  59.       // Store the file count in v4 to loop through each file entry..
  60.       v4 = v21;
  61.       do
  62.       {
  63.         // Read the file index..
  64.         (*(void (__fastcall **)(signed int, int *))(*v18 + 12))(4, &v25);
  65.  
  66.         // Read the file name length and prepare a string buffer..
  67.         (*(void (__fastcall **)(signed int, char *))(*v18 + 12))(4, (char *)&v23);
  68.         sub_4052FC(v5, v23);
  69.         v6 = sub_4051C8();
  70.  
  71.         // Read the file name into the new buffer..
  72.         (*(void (__fastcall **)(signed int, int))(*v18 + 12))(v23, v6);
  73.         sub_404FBC(&v20, v26, v20);
  74.  
  75.         // Read the file flags..
  76.         (*(void (__fastcall **)(signed int, int *))(*v18 + 12))(4, &v22);
  77.  
  78.         // Read the file size..
  79.         (*(void (__fastcall **)(signed int, char *))(*v18 + 12))(4, (char *)&v23);
  80.  
  81.         // Ensure there is file data to read..
  82.         if ( v23 > 0 )
  83.         {
  84.           (*(void (__stdcall **)(int *, int *))(*v16 + 68))(v13, v14);
  85.           sub_41E824();
  86.           sub_41E128(v23, (unsigned __int64)v23 >> 32);
  87.           sub_41E0C4((_DWORD *)v17, 0, 0);
  88.           (*(void (__fastcall **)(signed int, _DWORD))(*v18 + 12))(v23, *(_DWORD *)(v17 + 4));
  89.  
  90.           // Check if the file flags are set..
  91.           if ( v22 )
  92.           {
  93.             v24 = 0;
  94.             while ( v24 <= v23 )
  95.             {
  96.               v14 = (int *)51;
  97.               v13 = &v19;
  98.               v7 = *(_DWORD *)(v17 + 4);
  99.               sub_4ACDF0(&v19, 51);
  100.               (*(void (__fastcall **)(int, int))(*v16 + 56))(*v16, v19);
  101.             }
  102.           }
  103.           else
  104.           {
  105.             sub_41E0C4((_DWORD *)v17, 0, 0);
  106.             (*(void (__fastcall **)(int, int))(*v16 + 108))(*v16, v17);
  107.           }
  108.           v14 = (int *)v17;
  109.           v13 = v16;
  110.           v27(v20, v22);
  111.         }
  112.         --v4;
  113.       }
  114.       while ( v4 );
  115.     }
  116.     __writefsdword(0, (unsigned int)v13);
  117.     v15 = &loc_4C6816;
  118.     sub_403E54(v18);
  119.     sub_403E54((_DWORD *)v17);
  120.     sub_403E54(v16);
  121.   }
  122.   __writefsdword(0, v12);
  123.   v14 = (int *)&loc_4C6838;
  124.   return sub_404CC4((int)&v19, 2);
  125. }
I've commented the code flow with what is happening to the file as it's being processed.
I'll add more details later when I have some more free time.
Derp~
Need a great web host? Check out: AnHonestHost.com


Donations can be made via Paypal:
https://www.paypal.me/atom0s
User avatar
atom0s
Site Admin
Posts: 410
Joined: Sun Jan 04, 2015 11:23 pm
Location: 127.0.0.1
Contact:

Re: Parsing NSgtdData.NOS

Post by atom0s » Mon Aug 15, 2016 1:19 pm

Decryption is handled via:

Code: Select all

int __userpurge sub_4ACDF0@<eax>(int a1@<eax>, _DWORD *a2@<edx>, int a3@<ecx>, _DWORD *a4, int a5)
{
  _DWORD *v5; // ebx@1
  int v6; // esi@3
  int v7; // edx@7
  int v8; // edx@7
  unsigned int v10; // [sp-Ch] [bp-30h]@1
  void *v11; // [sp-8h] [bp-2Ch]@1
  int *v12; // [sp-4h] [bp-28h]@1
  char *v13; // [sp+Ch] [bp-18h]@1
  char *v14; // [sp+10h] [bp-14h]@1
  char *v15; // [sp+14h] [bp-10h]@1
  char v16; // [sp+19h] [bp-Bh]@7
  char v17; // [sp+1Ah] [bp-Ah]@7
  char v18; // [sp+1Bh] [bp-9h]@2
  int v19; // [sp+1Ch] [bp-8h]@1
  int v20; // [sp+20h] [bp-4h]@1
  int savedregs; // [sp+24h] [bp+0h]@1

  v13 = 0;
  v14 = 0;
  v15 = 0;
  v19 = a3;
  v5 = a2;
  v20 = a1;
  v12 = &savedregs;
  v11 = &loc_4ACF30;
  v10 = __readfsdword(0);
  __writefsdword(0, (unsigned int)&v10);
  sub_404CA0(a4);
LABEL_16:
  while ( *v5 <= v19 )
  {
    v18 = *(_BYTE *)(v20 + (*v5)++);
    if ( v18 == -1 )
      break;
    v6 = v18 & 0x7F;
    if ( v18 & 0x80 )
    {
      while ( v6 > 0 )
      {
        if ( *v5 <= v19 )
        {
          v7 = v20;
          v18 = *(_BYTE *)(v20 + (*v5)++);
          v17 = byte_689738[(v18 & 0xF0u) >> 4];
          v16 = byte_689738[v18 & 0xF];
          LOBYTE(v7) = v17;
          sub_404E88((int *)&v15, v7);
          sub_404F78((char **)a4, v15);
          if ( v6 <= 1 )
            goto LABEL_16;
          LOBYTE(v8) = v16;
          sub_404E88((int *)&v14, v8);
          sub_404F78((char **)a4, v14);
          v6 -= 2;
        }
        else
        {
          --v6;
        }
      }
    }
    else
    {
      while ( v6 > 0 )
      {
        if ( *v5 <= v19 )
        {
          sub_404E88((int *)&v13, a5 ^ *(_BYTE *)(v20 + *v5));
          sub_404F78((char **)a4, v13);
          --v6;
          ++*v5;
        }
        else
        {
          --v6;
        }
      }
    }
  }
  __writefsdword(0, v10);
  v12 = (int *)&loc_4ACF37;
  return sub_404CC4((int)&v13, 3);
}
EAX = Buffer to the file entry data.
EDX = Pointer to a temp buffer.
ECX = Size of the buffer of the file entry data. (EAX buffer size)
a4 = Output buffer pointer
a5 = 0x33 (static value passed to the decryptor)
Derp~
Need a great web host? Check out: AnHonestHost.com


Donations can be made via Paypal:
https://www.paypal.me/atom0s
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest