[0x00 ~ 0x03] 4E 58 50 4B Magic Number: NXPK
[0x04 ~ 0x13] Not Important
[0x14 ~ 0x17] Pointer to List of Files: Little Endian
[0x18 ~ A Byte before List of Files] File Data
[First Byte of List of Files ~ EOF] List of Files
=====
List of Files:
Every file uses 7 Bytes
=====
File:
[0x00 ~ 0x03] Hash of Filename (Included Path): Little Endian
[0x04 ~ 0x07] File Offset: Little Endian
[0x08 ~ 0x0B] File Compressed Length (Acutual Length): Little Endian
[0x0C ~ 0x0F] File Original Length: Little Endian
[0x10 ~ 0x1B] Hash of File Content: Not Importan
And Not Important
=====
File Data:
File Data of every File is always stored regularly, e.g.
[LAST BUT TWO BYTES BEFORE EOF OF LAST FILE] ~
0xFF 0xFF 0x00 0x00 ~ 0xAA 0xAA 0xAA 0xAA ~
[FIFTH BYTE OF NEXT FILE]
File Data can be compressed or not compressed.
Compressed Data will use zlib with default setting (0x789C)
=====
All Hashes are calculated use a private algorithm from NetEase, it can even be implemented differently.
You can call it by DEBUGGING.
=====
A Example of Extracting Files using Python:
import os
import sys
import zlib
# File to open
# filename = "/home/test/TEST.NPK"
filename = input("File: ")
NPKSIGNATURE = NPKSIGNATURE = [0x4E, 0x58, 0x50, 0x4B]
all_bytes = open(args.input_file, "rb").read()
if list(all_bytes[:4]) != NPKSIGNATURE:
print_fail("Failed to load file, bad signature")
sys.exit()
print()
print("NeoX Package File: " + filename )
print("============================")
filecount = little_endian_to_int(all_bytes[4:6])
count = 0
listoffset = little_endian_to_int(all_bytes[0x14:0x18])
print("- Data Count: %d" % filecount)
print("- List Offset: " + hex_upper_with_0x(listoffset))
print("============================")
for i in range(listoffset, len(all_bytes), 28):
filesign = all_bytes[i:i+4]
fileoffset = little_endian_to_int(all_bytes[i+4:i+8])
filelength = little_endian_to_int(all_bytes[i+8:i+12])
fileoriginallength = little_endian_to_int(all_bytes[i+12:i+16])
filehash = all_bytes[i+16:i+24]
fileunknown = all_bytes[i+24:i+28]
count += 1
print("- File %.6d: " % count)
print("-- Unknown: " + filesign.hex().upper())
print("-- Offset: " + hex_upper_with_0x(fileoffset))
print("-- Length: " + hex_upper_with_0x(filelength) + " (%d)" % filelength)
print(
"-- Original Length: " +
hex_upper_with_0x(fileoriginallength) +
" (%d)" % fileoriginallength
)
print("-- Hash: " + filehash.hex().upper())
print("-- Unknown: " + fileunknown.hex().upper())
if args.pause:
pause()
filecontent = all_bytes[fileoffset:fileoffset + filelength]
if args.content:
print_bytes(filecontent)
# if extract_flag:
if True:
print()
print("-- = Start Extraction =")
if filelength != fileoriginallength:
filecontent = zlib.decompress(filecontent)
print("\nDecompressed: ")
if args.content:
print_bytes(filecontent)
# extracttype = get_ext_by_filecontents(filecontent)
extracttype = "bin"
print()
extractname = (
os.path.basename(filename) +
"." + filesign.hex().upper() +
"." + extracttype
)
extractpath = os.path.join(extract_folder, extractname)
open(extractpath, "wb").write(filecontent)
print("--- Saved as " + extractpath)
print()