Higurashi no Naku Koro ni Sui - data.rom

Extraction and unpacking of game archives and compression, encryption, obfuscation, decoding of unknown files
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Higurashi no Naku Koro ni Sui - data.rom

Post by AlphaTwentyThree »

Hello there! This game only consists of a 5gb+ data.rom file. Can somebody take a quick look? Here's the first and last 16mb: http://*USE_ANOTHER_FILEHOSTING*/86cc4cd ... d69/rom.7z

Thanks for your help!
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by aluigi »

http://aluigi.org/papers/bms/others/hig ... u_koro.bms

The directory tree is not handled, I was on rush and it wasn't clear.
AlphaTwentyThree
Posts: 909
Joined: Sat Aug 09, 2014 11:21 am

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by AlphaTwentyThree »

Thanks a lot, luigi! Don't worry about the folder structure, I'm only after the music as you might have guessed. ;)
nate37
Posts: 2
Joined: Fri Jul 17, 2015 7:37 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by nate37 »

https://mega.co.nz/#!zx5GiKQI!qfyyjPWBC ... tQdR8Qwlbs (snr file)
https://mega.co.nz/#!WtxxQCbC!iccIyHTmo ... aqM9OuEuVQ (txa file)

Thank you for ROM extractor, then I want to extract script from some files.
These files seem to include script file.
aluigi
Site Admin
Posts: 12984
Joined: Wed Jul 30, 2014 9:32 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by aluigi »

They don't seem archives.
zander1995
Posts: 20
Joined: Tue Oct 11, 2016 7:26 am

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by zander1995 »

I hope it's okay to respond to an old thread, I didn't see anything about it in the rules, but it's not an archive. It's a single script file with all of the text included.

The problem is that it uses a custom character table somewhat different than base Shift JIS. Kanji and han/dakuten gojuuon are in base Shift JIS, but Hiragana and Katakana have completely different hex values.

With an edited Shift JIS table.
Image

With plain Shift JIS
Image
aaa801
Posts: 48
Joined: Wed Oct 12, 2016 12:22 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by aaa801 »

Handles dir structure, xyz made this script

Code: Select all

from sys import argv
import struct
import os


def hexdump(src, length=16, sep='.'):
    FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or sep for x in range(256)])
    lines = []
    for c in xrange(0, len(src), length):
        chars = src[c:c+length]
        hex = ' '.join(["%02x" % ord(x) for x in chars])
        if len(hex) > 24:
            hex = "%s %s" % (hex[:24], hex[24:])
        printable = ''.join(["%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or sep) for x in chars])
        lines.append("%08x:  %-*s  |%s|\n" % (c, length*3, hex, printable))
    print ''.join(lines)

def u8(b, off=0):
    return ord(b[off])

def u16(b, off=0):
    return struct.unpack("<H", b[off:off+2])[0]

def u32(b, off=0):
    return struct.unpack("<I", b[off:off+4])[0]

def c_str(b, off=0):
    part = b[off:]
    term = part.find("\x00")
    if term == -1:
        print "full dump:"
        hexdump(b)
        print "part dump (offset 0x{:x})".format(off)
        hexdump(part)
        raise Exception("failed to find C-string here")
    return part[:term]


folder_map = dict()


class File():

    def __init__(self, data, parent_data):
        name_off = u32(data[0:3] + "\x00")
        self.name = c_str(parent_data, name_off)
        self.flags = u8(data, 3)
        self.offset = u32(data, 4)
        self.size = u32(data, 8)


class Info():

    def __init__(self, data):
        self.num_files = u32(data, 0)

        self.files = []
        for x in range(self.num_files):
            start = 4 + x * 0xC
            file_info = data[start:start+0xC]
            self.files.append(File(file_info, data))

        for file in self.files:
            if file.name == ".":
                folder_map[file.offset] = self
            elif file.name == "..":
                self.parent = folder_map[file.offset]

fin = None


def extract_folder(folder, path):
    os.mkdir(path)
    for file in folder.files:
        if file.name in [".", ".."]:
            continue
        print "{}/{}{}".format(path, file.name, "/" if file.flags & 0x80 else "")
        if file.flags & 0x80:
            extract_folder(folder_map[file.offset], os.path.join(path, file.name))
        else:
            fin.seek(file.offset * 0x800)
            fout = open(os.path.join(path, file.name), "wb")
            fout.write(fin.read(file.size))
            fout.close()


def main():
    global fin
    fin = open(argv[1], "rb")
    assert fin.read(4) == "ROM "
    assert u16(fin.read(2)) == 1
    assert u16(fin.read(2)) == 2
    header_size = u32(fin.read(4))
    unk1 = fin.read(4)

    folders = []

    while fin.tell() < header_size:
        start = fin.tell()
        fin.seek(start + 0xC)
        info_size = u32(fin.read(4))
        fin.seek(start)
        data = fin.read(info_size)
        # hexdump(data)
        info = Info(data)
        folders.append(info)
       
        end = start + info_size
        # align to 0x10
        end = (end + 0xF) & ~0xF
        fin.seek(end)

    extract_folder(folders[0], path="extract")


if __name__ == "__main__":
    main()
zander1995
Posts: 20
Joined: Tue Oct 11, 2016 7:26 am

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by zander1995 »

aaa801 wrote:Handles dir structure, xyz made this script


How do we use that script? QuickBMS throws up errors when attempting to run it.
aaa801
Posts: 48
Joined: Wed Oct 12, 2016 12:22 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by aaa801 »

zander1995 wrote:
aaa801 wrote:Handles dir structure, xyz made this script


How do we use that script? QuickBMS throws up errors when attempting to run it.

its a python script, python blabla.py data.rom out
i don't really get on with quickbms enough to convert it
zander1995
Posts: 20
Joined: Tue Oct 11, 2016 7:26 am

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by zander1995 »

aaa801 wrote:
zander1995 wrote:
aaa801 wrote:Handles dir structure, xyz made this script


How do we use that script? QuickBMS throws up errors when attempting to run it.

its a python script, python blabla.py data.rom out
i don't really get on with quickbms enough to convert it


Oh, cool. Thanks.
aaa801
Posts: 48
Joined: Wed Oct 12, 2016 12:22 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by aaa801 »

forgot to mention,
the game uses binary search so the entries need to be in alphabetical order.
ever17
Posts: 5
Joined: Wed Jan 11, 2017 8:51 am

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by ever17 »

aaa801 wrote:Python script[/code]


It give me error:
1.py data.rom
File "1.py", line 16
print ''.join(lines)
^
SyntaxError: invalid syntax


I try it on vita data.rom file
Python36-32
Help?
Acewell
Posts: 706
Joined: Fri Aug 08, 2014 1:06 am

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by Acewell »

looks like the script was written for Python 2.x by the looks of the print statements, but you should be able to
fix that error by adding parenthesis around all the print statements and just use Python 3.x to run it.

for example change this

Code: Select all

print ''.join(lines)

to this

Code: Select all

print(''.join(lines))
ever17
Posts: 5
Joined: Wed Jan 11, 2017 8:51 am

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by ever17 »

Acewell wrote:looks like the script was written for Python 2.x by the looks of the print statements, but you should be able to
fix that error by adding parenthesis around all the print statements and just use Python 3.x to run it.

for example change this

Code: Select all

print ''.join(lines)

to this

Code: Select all

print(''.join(lines))

Thanks, would test it later!
masagrator
Posts: 82
Joined: Sat Dec 22, 2018 10:03 am

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by masagrator »

Sorry for bumping, but Switch version Higurashi has new data.rom that has at the beginning ROM2

Here are first and last chunk of file (Whole archive is 7.04 GiB big)
https://drive.google.com/file/d/1t9ebtA ... sp=sharing

If someone could update script (and if it's Python - please write in Python 3)
Last edited by masagrator on Mon Feb 25, 2019 11:49 am, edited 1 time in total.
wwwklopar
Posts: 23
Joined: Sat Dec 08, 2018 7:53 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by wwwklopar »

Searching script for Switch version of Higurashi too
voddler
Posts: 1
Joined: Sat Oct 26, 2019 5:26 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by voddler »

Also looking for a script for the switch version file above, please help us out. We'd appreciate it! :D
wwwklopar
Posts: 23
Joined: Sat Dec 08, 2018 7:53 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by wwwklopar »

I can add link to full archive if it will help.
Link
aaa801
Posts: 48
Joined: Wed Oct 12, 2016 12:22 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by aaa801 »

Heres more python 2 for ya, handles the newer files (switch) (anyone feel free to convert it to python 3, I tried.. its a panful time)

Might attempt to convert it over to bms eventually..

Code: Select all

from sys import argv
import struct
import os

def hexdump(src, length=16, sep='.'):
    FILTER = ''.join([(len(repr(chr(x))) == 3) and chr(x) or sep for x in range(256)])
    lines = []
    for c in xrange(0, len(src), length):
        chars = src[c:c+length]
        hex = ' '.join(["%02x" % ord(x) for x in chars])
        if len(hex) > 24:
            hex = "%s %s" % (hex[:24], hex[24:])
        printable = ''.join(["%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or sep) for x in chars])
        lines.append("%08x:  %-*s  |%s|\n" % (c, length*3, hex, printable))
    print ''.join(lines)

def u8(b, off=0):
    return ord(b[off])

def u16(b, off=0):
    return struct.unpack("<H", b[off:off+2])[0]

def u32(b, off=0):
    return struct.unpack("<I", b[off:off+4])[0]

def c_str(b, off=0):
    part = b[off:]
    term = part.find("\x00")
    if term == -1:
        print "full dump:"
        hexdump(b)
        print "part dump (offset 0x{:x})".format(off)
        hexdump(part)
        raise Exception("failed to find C-string here")
    return part[:term]


folder_map = dict()


class File():

    def __init__(self, data, parent_data):
        name_off = u32(data[0:3] + "\x00")
        self.name = c_str(parent_data, name_off)
        self.flags = u8(data, 3)
        self.offset = u32(data, 4)
        self.size = u32(data, 8)
        print "name " + self.name + " offset "+"{}".format(self.offset) + " size "+"{}".format(self.size)


class Info():

    def __init__(self, data):
        self.num_files = u32(data, 0)

        self.files = []
        for x in range(self.num_files):
            start = 4 + x * 0xC
            file_info = data[start:start+0xC]
            self.files.append(File(file_info, data))

        for file in self.files:
            if file.name == ".":
                folder_map[file.offset] = self
            elif file.name == "..":
                self.parent = folder_map[file.offset]

fin = None


def extract_folder(folder, path):
    try:
      os.mkdir(path)
    except OSError as error:
      print(error)
    for file in folder.files:
        if file.name in [".", ".."]:
            continue
        print "{}/{}{}".format(path, file.name, "/" if file.flags & 0x80 else "")
        if file.flags & 0x80:
            extract_folder(folder_map[file.offset], os.path.join(path, file.name))
        else:
            if file.offset * offsetMultiplier + file.size >= archiveSize:
              print "Skipping file as archive is to small!"
              continue
            print "saving"  + file.name + " offset "+"{}".format(file.offset * offsetMultiplier) + " size "+"{}".format(file.size)
            fin.seek(file.offset * offsetMultiplier)
            fout = open(os.path.join(path, file.name), "wb")
            fout.write(fin.read(file.size))
            fout.close()


def main():
    global fin
    fin = open(argv[1], "rb")
    global archiveSize
    archiveSize = os.path.getsize(argv[1])
      
    magic = fin.read(4)
    assert magic == "ROM " or magic == "ROM2"
   
    global fileStart
    global offsetMultiplier

    if magic == "ROM ":
      fileStart = 0x10
      offsetMultiplier = 0x800
    elif magic == "ROM2":
      fileStart = 0x20
      offsetMultiplier = 0x200
    else:
     print "oh no"
     exit()
    
    fin.read(4)
    header_size = u32(fin.read(4))
    unk1 = fin.read(4)

    folders = []

    fin.seek(fileStart)
    while fin.tell() < header_size:
        start = fin.tell()
        fin.seek(start + 0xC)
        info_size = u32(fin.read(4))
        fin.seek(start)
        data = fin.read(info_size)
        # hexdump(data)
        info = Info(data)
        folders.append(info)
       
        end = start + info_size
        # align to 0x10
        end = (end + 0xF) & ~0xF
        fin.seek(end)

    extract_folder(folders[0], path="extract")


if __name__ == "__main__":
    main()
aaa801
Posts: 48
Joined: Wed Oct 12, 2016 12:22 pm

Re: Higurashi no Naku Koro ni Sui - data.rom

Post by aaa801 »

Here is a truly awful quickbms script for these..

Code: Select all

# Higurashi data.rom
# Script for QuickBMS http://quickbms.aluigi.org

idstring ROM
get VERSION byte

if VERSION == 0x20
   # Original version
   set INFO_START = 0x10
   set OFFSET_MULTIPLIER = 0x800
   print "Original format"
else if VERSION == 0x32
   # Newer version (switch)
   set INFO_START = 0x20
   set OFFSET_MULTIPLIER = 0x200
   print "New format"
else
   print "Unsupported version"
endif

get UNK long
get HEADER_SIZE long

goto SEEK_END
savepos INPUT_END

# Go to the start of file entry table
goto INFO_START

set TOTAL_ENTRIES 0
set TOTAL_FOLDERS 0

# Read info
savepos LAST_POS
Do
   print "Reading info at %LAST_POS% / %HEADER_SIZE%"
   savepos START
   savepos BASE_LOC

   get NUM_FILES long

   xmath TMP "START + 0x0C"
   goto TMP
   
   get INFO_SIZE long
   goto START
   
   # Read info
   callfunction readInfo 1
   
   xmath END "START + INFO_SIZE"
   print "start %START% %END%"

   goto END
   padding 0x10
      
   savepos LAST_POS
   # print "start was %START% info_size was %INFO_SIZE%"
   print "-"
while LAST_POS < HEADER_SIZE

callfunction dumpFiles

# Ugh.. bms is a pain for stuff like this..
# need to store info for each file..
# arrays,
# 0 = name
# 1 = flags
# 2 = offset
# 3 = size
# --
# 4 = is_folder
# 5 = FOLDER_OFFSET
# 6 = PARENT_FOLDER_OFFSET
# -- these are for folder entries
# 7 = folder name
# 8 = folder offset
# 9 = parent folder offset

startfunction readInfo
   #get NUM_FILES long
   print "Files %NUM_FILES%"
   print "Baseloc %BASE_LOC%"
      
   for i = 0 < NUM_FILES
      xmath FILE_ENTRY_START "4 + i * 0xC"
      xmath FILE_ENTRY_START "FILE_ENTRY_START + BASE_LOC"
      #print "File %i% info at %FILE_ENTRY_START%"
      #print "TOTAL_ENTRIES %TOTAL_ENTRIES%"   
      savepos TMP
      
      goto FILE_ENTRY_START
      get NAME_OFF THREEBYTE
      get FLAGS byte
      get OFFSET long
      get SIZE long
      
      # print "raw_name_off %NAME_OFF%"
      xmath NAME_LOC "BASE_LOC + NAME_OFF"
        # print "File %i% name_off %NAME_LOC%"
      goto NAME_LOC
      get NAME string
      
      PutArray 0 TOTAL_ENTRIES NAME
      PutArray 1 TOTAL_ENTRIES FLAGS
      PutArray 2 TOTAL_ENTRIES OFFSET
      PutArray 3 TOTAL_ENTRIES SIZE
      
      if FLAGS & 0x80
            math IS_FOLDER = 1
         if NAME != "." && NAME != ".."
            PutArray 7 TOTAL_FOLDERS NAME
            PutArray 8 TOTAL_FOLDERS OFFSET
            PutArray 9 TOTAL_FOLDERS FOLDER_OFFSET
            xmath TOTAL_FOLDERS "TOTAL_FOLDERS+1"
         endif
        else
            math IS_FOLDER = 0
        endif
      PutArray 4 TOTAL_ENTRIES IS_FOLDER
      
      if NAME == "."
         set FOLDER_OFFSET OFFSET
      elif NAME == ".."
         set PARENT_FOLDER_OFFSET OFFSET
      endif
      
      goto TMP
      xmath TOTAL_ENTRIES "TOTAL_ENTRIES+1"
   next i
   
   # set folder offsets
   for i = 0 < NUM_FILES
      xmath INDEX "TOTAL_ENTRIES - NUM_FILES + i"
      PutArray 5 INDEX FOLDER_OFFSET
      PutArray 6 INDEX PARENT_FOLDER_OFFSET
   next i
   
endfunction

startfunction dumpFiles
   
   callfunction dumpFolders
   
   print "dumpFiles"

   print "Total entries: %TOTAL_ENTRIES%"

   # set full paths
   for i = 0 < TOTAL_ENTRIES   
      getarray FILE_NAME 0 i
      getarray FILE_FLAGS 1 i
      getarray FILE_OFFSET 2 i
      getarray FILE_SIZE 3 i
      getarray FILE_IS_FOLDER 4 i
      getarray FILE_FOLDER_OFFSET 5 i
      getarray FILE_PARENT_FOLDER_OFFSET 6 i
      
      # testing skip
      if FILE_NAME != "hse_31.nxa"
      # se/hse/hse_31.nxa
         #continue
      endif
   
      math FILE_OFFSET u* OFFSET_MULTIPLIER

      print "Name %FILE_NAME% Folder %FILE_IS_FOLDER% Flags %FILE_FLAGS% Offset %FILE_OFFSET% Size %FILE_SIZE% Folder_offset %FILE_FOLDER_OFFSET% parent_folder_offset %FILE_PARENT_FOLDER_OFFSET%"

      if FILE_IS_FOLDER == 1
         continue
      endif
      
      
      set FOLDER_PATH ""
      set CUR_SEARCH_FOLDER_OFFSET FILE_FOLDER_OFFSET
      callfunction getPath 1
      #print "FOLDER_PATH %FOLDER_PATH%"
      
      set FILE_PATH ""
      String FILE_PATH + FOLDER_PATH
      String FILE_PATH + FILE_NAME
      #print "FILE_PATH %FILE_PATH%"

      set END_OFFSET FILE_OFFSET
      math END_OFFSET u+ FILE_SIZE
      print "end %END_OFFSET% INPUT_END %INPUT_END%"
      
      # Explodes on 32bit runover.. -_-
      if END_OFFSET u> INPUT_END
         print "Skipping file as archive is too small!"
      else
         log FILE_PATH FILE_OFFSET FILE_SIZE
      endif

      
   next i
   
   
endfunction

startfunction dumpFolders
   print "dumpFolders %TOTAL_FOLDERS%"

   for aaa = 0 < TOTAL_FOLDERS
       getarray FOLDER_NAME 7 aaa
      getarray FOLDER_OFFSET 8 aaa
      getarray PARENT_FOLDER_OFFSET 9 aaa
      #print "fname %FOLDER_NAME% foffset %FOLDER_OFFSET% pfoffset %PARENT_FOLDER_OFFSET%"
   next aaa
endfunction

startfunction getPath
   #print "ugh paths"
   if CUR_SEARCH_FOLDER_OFFSET == 0
      #print "heh....."
   else
      for aaa = 0 < TOTAL_FOLDERS
         getarray FOLDER_NAME 7 aaa
         getarray FOLDER_OFFSET 8 aaa
         getarray PARENT_FOLDER_OFFSET 9 aaa
         
         #print "looking for.. foffset %CUR_SEARCH_FOLDER_OFFSET%"
         #print "fname %FOLDER_NAME% foffset %FOLDER_OFFSET% parent_foffset %PARENT_FOLDER_OFFSET%"
         
         if CUR_SEARCH_FOLDER_OFFSET == FOLDER_OFFSET
            set TMP_PATH ""
            String TMP_PATH + FOLDER_NAME
            String TMP_PATH + "/"
            String TMP_PATH + FOLDER_PATH

            set FOLDER_PATH TMP_PATH
            
            #String FOLDER_PATH + FOLDER_NAME
            #String FOLDER_PATH + "/"
            
            if PARENT_FOLDER_OFFSET != 0
               #print "brrrrr"
               set CUR_SEARCH_FOLDER_OFFSET PARENT_FOLDER_OFFSET
               callfunction getPath 1
            endif
            break
         endif
      next aaa
   endif

endfunction