Jump to content

Glitch Karts UE4 HTML5 DATA Extraction


Go to solution Solved by Hazza12555,

Recommended Posts

  • Members
Posted

I want to extract from the web browser game Glitch Karts. I first went to developer mode and the networking tab and extracted any data i saw there that was of interest.

The biggest file was a .data file (around 180MB) which i'd assume hold's most/if not all of the assets.

I confirmed this to be UE4 from the various .js scripts i also downloaded.

I have tried with FModel, QuickBMS and UModel all of which couldn't find anything.

I know HTML 5 Unreal Engine files are different to the normal .pak's .ucas etc but i can't figure where to start.

If anyone could help or has knowledge on this, it would be greatly appreciated!

Files (all maybe useful data i could find): https://gofile.io/d/hunaWl
 

Posted

No way, I've been trying to do the same exact thing! The file size for that .data file on the server has shrunk, which means that the 182MB .data file we both have contains possibly some type of unused content.

  • Members
  • Solution
Posted
50 minutes ago, YoungTechJunkie said:

No way, I've been trying to do the same exact thing! The file size for that .data file on the server has shrunk, which means that the 182MB .data file we both have contains possibly some type of unused content.

I found the solution.

Use the pak.py python script (i uploaded) in the same directory as the .data file

This will extract the UE4 .pak file from the .data file

Since the version is 4.27, use the QuickBMS 4.27 Unreal Engine Script to extract all data! Then you can use UModel to extract models/audio etc!


 

# Unreal Engine 4 - Unreal Tournament 4 (*WindowsNoEditor.pak) (script 0.4.27e)
# script for QuickBMS http://quickbms.aluigi.org

math NO_TAIL_INFO = 0   # set it to 1 for archives with corrupt/missing tail information (extract without index)
math VERSION = 3        # set it to 3 if NO_TAIL_INFO = 1 for most of modern games

quickbmsver "0.12"
callfunction QUICKBMS_4GB_CHECK 1

# set your AES_KEY here as umodel hex ("0x1122...") or C string ("\x11\x22...")
# don't change AES_KEY_IS_SET, it will be handled automatically
set AES_KEY binary ""

math TOC_FILE = 0
math ALTERNATIVE_MODE = 0
math AES_KEY_IS_SET = 0
math BASE_PATH_INCLUDED = 1
math DIR_FLAG = 1
math NAME_FROM_ARRAY = 0
math SKIP_COUNT = 0

get ARCHIVE_NAME basename
get ARCHIVE_PATH FILEPATH

math CHUNK_OFFSET_ABSOLUTE = -1 # default, enabled

# 1 = HIT
math WORKAROUND = 0

if NO_TAIL_INFO != 0
    get OFFSET asize
    math ALTERNATIVE_MODE = 1
else
	goto -0xcc  # version 11 (4.26-4.27)
	savepos MAGIC_OFF
	get MAGIC long

    get VERSION long
    endian guess VERSION
    get OFFSET longlong
    get SIZE longlong
    getdstring HASH 20
	xmath SIZE "MAGIC_OFF - OFFSET - 1"
	
	get FSIZE asize
	savepos CUR_POS
	if CUR_POS = FSIZE
		string COMP1 = ""
	else
		get CHECK byte
		if CHECK > 1
			goto -1 0 SEEK_CUR
		endif
		getdstring COMP1 32
		getdstring COMP2 32
		string COMP1 l COMP1
		string COMP2 l COMP2
	endif

    if VERSION >= 3
        goto MAGIC_OFF
        goto -1 0 SEEK_CUR
        get ENCRYPTED byte
        if ENCRYPTED != 0
            callfunction SET_AES_KEY 1
            log MEMORY_FILE5 OFFSET SIZE
            encryption "" ""
        else
			log MEMORY_FILE5 OFFSET SIZE
        endif
		math TOC_FILE5 = -5
    endif

    goto 0
    callfunction GET_BASE_PATH 1
endif

get FILES long TOC_FILE5
getdstring DUMMY 12 TOC_FILE5
get HASHES_OFFSET longlong TOC_FILE5
math HASHES_OFFSET - OFFSET
get HASHES_SIZE longlong TOC_FILE5
getdstring DUMMY 24 TOC_FILE5
get NAMES_OFFSET longlong TOC_FILE5
math NAMES_OFFSET - OFFSET
get NAMES_SIZE longlong TOC_FILE5
getdstring DUMMY 24 TOC_FILE5
savepos BASE_INDEX_OFF TOC_FILE5
goto NAMES_OFFSET TOC_FILE5

math CHUNK_SIZE = 0x10000   # just in case...
for i = 0 < FILES
	callfunction GET_NAME_AND_OFFSET 1
	if NAME = ""
		continue NEXT0
	endif
	
	savepos TMP_OFF TOC_FILE
	
	get OFFSET longlong TOC_FILE
	get ZSIZE longlong TOC_FILE
	get SIZE longlong TOC_FILE
	get ZIP long TOC_FILE
    getdstring HASH 20 TOC_FILE
	
    math CHUNKS = 0
    math ENCRYPTED = 0
    if VERSION >= 3
        if ZIP != 0
            get CHUNKS long TOC_FILE
            for x = 0 < CHUNKS
                get CHUNK_OFFSET longlong TOC_FILE
                get CHUNK_END_OFFSET longlong TOC_FILE
                putarray 0 x CHUNK_OFFSET
                putarray 1 x CHUNK_END_OFFSET
            next x
        endif
        get ENCRYPTED byte TOC_FILE
        get CHUNK_SIZE long TOC_FILE
    endif
	
    #if ALTERNATIVE_MODE != 0
        savepos TMP_OFF TOC_FILE
        math OFFSET + TMP_OFF
    #endif

    #comtype copy    
	callfunction COMPRESSION_TYPE 1

    if CHUNKS > 0
        log NAME 0 0
        append
        math TMP_SIZE = SIZE
		if CHUNK_OFFSET_ABSOLUTE < 0 && OFFSET != 0
			getarray CHUNK_OFFSET 0 0
			if CHUNK_OFFSET u< OFFSET
				math CHUNK_OFFSET_ABSOLUTE = 0
			else
				math CHUNK_OFFSET_ABSOLUTE = 1
			endif
		endif
        for x = 0 < CHUNKS
            getarray CHUNK_OFFSET 0 x
            getarray CHUNK_END_OFFSET 1 x
            math CHUNK_ZSIZE = CHUNK_END_OFFSET
            math CHUNK_ZSIZE - CHUNK_OFFSET
            math CHUNK_XSIZE = CHUNK_ZSIZE
            if ENCRYPTED != 0
                callfunction SET_AES_KEY 1
                math CHUNK_XSIZE x 16
            endif
            if TMP_SIZE u< CHUNK_SIZE
                math CHUNK_SIZE = TMP_SIZE
            endif
            math CHUNK_OFFSET = OFFSET

			if ZIP == 0
				log NAME CHUNK_OFFSET CHUNK_SIZE 0 CHUNK_XSIZE	
			else
				clog NAME CHUNK_OFFSET CHUNK_ZSIZE CHUNK_SIZE 0 CHUNK_XSIZE
			endif			
			
            math TMP_SIZE - CHUNK_SIZE
			math OFFSET + CHUNK_XSIZE
        next x
        append
		
    else
        # the file offset points to an entry containing
        # the "same" OFFSET ZSIZE SIZE ZIP HASH ZERO fields,
        # just an additional backup... so let's skip them
        savepos BASE_OFF TOC_FILE
        math BASE_OFF - TMP_OFF
        math OFFSET + BASE_OFF
        math XSIZE = ZSIZE
        if ENCRYPTED != 0
            callfunction SET_AES_KEY 1
            math XSIZE x 16
        endif	
		if ZIP == 0
			math BLOCK = 0x40000000
			xmath FSIZE "OFFSET + ZSIZE" 
			log NAME 0 0
			append
			for OFFSET = OFFSET < FSIZE
				xmath DIFF "FSIZE - OFFSET"
				if DIFF < BLOCK
					math XSIZE = DIFF
					if ENCRYPTED != 0
						math XSIZE x 16
					endif
					log NAME OFFSET DIFF 0 XSIZE
				else
					log NAME OFFSET BLOCK
				endif
				math OFFSET + BLOCK
			next
			append
		else
			clog NAME OFFSET ZSIZE SIZE 0 XSIZE
		endif
    endif
    encryption "" ""

    if ALTERNATIVE_MODE != 0
		if CHUNKS == 0
			math OFFSET + XSIZE
		endif
		goto OFFSET

		get TMP1 longlong
		get CHECK byte
		if TMP1 == 0 && CHECK != 0
			goto OFFSET
			continue NEXT1
		else
			goto OFFSET
		endif
		xmath CHECK "0x800 - (OFFSET % 0x800)"
		if CHECK <= 16
			padding 0x800
		endif	
		
		savepos OFFSET
		get TMP1 longlong
		get TMP2 longlong
		if TMP2 == 0
			padding 0x800
		else
			goto OFFSET
		endif
		
		label NEXT1
    endif
	
	label NEXT0
next i

print "\nEntries ignored: %SKIP_COUNT%"
for i = 0 < SKIP_COUNT
	getarray NAME 7 i
	print "Ignored entry: %NAME%"
next i

startfunction SET_AES_KEY_ASK
    math AES_KEY_IS_SET = 1
    print "The archive is encrypted, you need to provide the key"
	if AES_KEY == ""
		set KEY unknown "???"
	else
		set KEY binary AES_KEY
	endif
	
    if KEY == ""
        math AES_KEY_IS_SET = -1
        set AES_KEY string "No key provided, encryption disabled"
    elif KEY strncmp "0x"
        string KEY << 2
        string AES_KEY h KEY
    else
        set AES_KEY binary KEY
    endif
    print "KEY: %AES_KEY%"
endfunction

startfunction SET_AES_KEY
    if AES_KEY_IS_SET == 0
        callfunction SET_AES_KEY_ASK 1
    endif
    if AES_KEY_IS_SET > 0
        encryption aes AES_KEY "" 0 32
    endif
endfunction

startfunction GET_BASE_PATH
    get NAMESZ long TOC_FILE5
	getdstring BASE_PATH NAMESZ TOC_FILE5
	if NAMESZ != 0x0A && NAMESZ < 0xFF
		string BASE_PATH | "../../../"
		math BASE_PATH_INCLUDED = 0
	endif
endfunction

startfunction CHECK_UNICODE
	if NAMESZ >= 0
		getdstring RESULT NAMESZ TOC_FILE5
	else
		math NAMESZ n NAMESZ
		math NAMESZ * 2
		getdstring RESULT NAMESZ TOC_FILE5
		set RESULT unicode RESULT
	endif
endfunction

startfunction GET_NAME_AND_OFFSET
	if NAME_FROM_ARRAY = 1
		if CURR_NAME < DIR_FILES
			getarray NAME 5 CURR_NAME
			getarray OFFSET 6 CURR_NAME
			goto OFFSET
			math CURR_NAME + 1
			if CURR_NAME = DIR_FILES
				math NAME_FROM_ARRAY = 0
			endif
		endif
	else	
		if DIR_FLAG = 1
			get DIR_COUNT long TOC_FILE5
			math DIR_FLAG = 0
		endif
		
		if DIR_COUNT = 0
			math DIR_FLAG = 1
			callfunction GET_NAME_AND_OFFSET 1
		else
			math DIR_COUNT - 1
			get NAMESZ signed_long TOC_FILE5
			callfunction CHECK_UNICODE 1
			string DIR_NAME = RESULT
			get DIR_FILES long TOC_FILE5
			if DIR_FILES = 0
				callfunction GET_NAME_AND_OFFSET 1
			else 
				for y = 0 < DIR_FILES
					get NAMESZ signed_long TOC_FILE5
					callfunction CHECK_UNICODE 1
					string NAME = RESULT
					string NAME p "%s%s" DIR_NAME NAME
					if BASE_PATH_INCLUDED == 0
						string NAME p "%s%s" BASE_PATH NAME
					endif
					putarray 5 y NAME
					
					get OFFSET long TOC_FILE5
					savepos TMP_INDEX_OFF TOC_FILE5
					if OFFSET != 0x80000000 && OFFSET != 0x7FFFFFFF 
						xmath INDEX_OFF "BASE_INDEX_OFF + OFFSET"
						goto INDEX_OFF TOC_FILE5
						get FLAGS long TOC_FILE5
						xmath HAS_SIZE "FLAGS & 0x3F"	
						xmath IS_64 "FLAGS >> 28"
						if HAS_SIZE = 0x3F
							get CHUNK_SIZE long TOC_FILE5
						endif
						if IS_64 = 0xE
							get OFFSET long TOC_FILE5
						else
							get OFFSET longlong TOC_FILE5							
						endif
					else 
						putarray 7 SKIP_COUNT NAME
						math SKIP_COUNT + 1
						string NAME = ""
						putarray 5 y NAME
					endif
					putarray 6 y OFFSET
					goto TMP_INDEX_OFF TOC_FILE5
				next y
				math NAME_FROM_ARRAY = 1
				math CURR_NAME = 0
				callfunction GET_NAME_AND_OFFSET 1
			endif
		endif
	endif
endfunction

startfunction COMPRESSION_TYPE
	if COMP1 = ""
		comtype zlib
	endif
	
	if ZIP = 1 && COMP1 = "zlib"
		comtype zlib
	elif ZIP = 1 && COMP1 = "zstd"
		comtype zstd
	elif ZIP = 1 && COMP1 = "oodle"
		comtype oodle
	elif ZIP = 1 && COMP1 = "lz4"
		comtype lz4
	elif ZIP = 1 && COMP1 = "gzip"
		comtype gzip
	elif ZIP = 2 && COMP2 = "zlib"
		comtype zlib
	elif ZIP = 2 && COMP2 = "zstd"
		comtype zstd
	elif ZIP = 2 && COMP2 = "oodle"
		comtype oodle
	elif ZIP = 2 && COMP2 = "lz4"
		comtype lz4
	elif ZIP = 2 && COMP2 = "gzip"
		comtype gzip
	elif ZIP = 3 || ZIP = 4 || ZIP = 0x10 # 3 - Faith of Danschant, 4 - Days Gone, 10 - Ashen
		comtype oodle
		if WORKAROUND == 2
			comtype lz4
		endif
	endif
endfunction

startfunction QUICKBMS_4GB_CHECK
    math TMP64 = 0x10000000
    math TMP64 * 16
    if TMP64 == 0
        print "You must use quickbms_4gb_files.exe with this script!"
        cleanexit
    endif
endfunction

 

pak.py

  • Like 1
Posted (edited)

This is so weird.. there is a WHOLE FULLY CONSTRUCTED OTHER GAME in the file! Called NMKart. From what I've been able to see, it seems awfully dark and grim. All the maps share a 

dark and grim feel, along with all of the voice acting for the game. I'm gonna use UnrealPak to try to extract the .pak file, rework the NMKart part of the game, and then recompile it.

For all I know, since UnrealPak comes with Unreal Engine, it shouldn't miss any files. Oh yeah, I think I'll have to use UModel to extract media files too. Glitch seems to have made a whole game and then tossed it but took the same idea for their current shows, but then just did it under the same project file?

Edited by YoungTechJunkie

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...