Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. # Unreal Engine 4 - Unreal Tournament 4 (*WindowsNoEditor.pak) (script 0.4.27e)
  2. # script for QuickBMS http://quickbms.aluigi.org
  3.  
  4. math NO_TAIL_INFO = 0 # set it to 1 for archives with corrupt/missing tail information (extract without index)
  5. math VERSION = 3 # set it to 3 if NO_TAIL_INFO = 1 for most of modern games
  6.  
  7. quickbmsver "0.12"
  8. callfunction QUICKBMS_4GB_CHECK 1
  9.  
  10. # set your AES_KEY here as umodel hex ("0x1122...") or C string ("\x11\x22...")
  11. # don't change AES_KEY_IS_SET, it will be handled automatically
  12. set AES_KEY binary "0xEA9051DDACE1CCF98A0510F0E370BD986A75C74756E0309E6A578A47AF564255"
  13.  
  14. math TOC_FILE = 0
  15. math ALTERNATIVE_MODE = 0
  16. math AES_KEY_IS_SET = 0
  17. math BASE_PATH_INCLUDED = 1
  18. math DIR_FLAG = 1
  19. math NAME_FROM_ARRAY = 0
  20. math SKIP_COUNT = 0
  21.  
  22. get ARCHIVE_NAME basename
  23. get ARCHIVE_PATH FILEPATH
  24.  
  25. math CHUNK_OFFSET_ABSOLUTE = -1 # default, enabled
  26.  
  27. # 1 = HIT
  28. math WORKAROUND = 0
  29.  
  30. if NO_TAIL_INFO != 0
  31. get OFFSET asize
  32. math ALTERNATIVE_MODE = 1
  33. else
  34. goto -0xcc # version 11 (4.26-4.27)
  35. savepos MAGIC_OFF
  36. get MAGIC long
  37.  
  38. get VERSION long
  39. endian guess VERSION
  40. get OFFSET longlong
  41. get SIZE longlong
  42. getdstring HASH 20
  43. xmath SIZE "MAGIC_OFF - OFFSET - 1"
  44.  
  45. get FSIZE asize
  46. savepos CUR_POS
  47. if CUR_POS = FSIZE
  48. string COMP1 = ""
  49. else
  50. get CHECK byte
  51. if CHECK > 1
  52. goto -1 0 SEEK_CUR
  53. endif
  54. getdstring COMP1 32
  55. getdstring COMP2 32
  56. string COMP1 l COMP1
  57. string COMP2 l COMP2
  58. endif
  59.  
  60. if VERSION >= 3
  61. goto MAGIC_OFF
  62. goto -1 0 SEEK_CUR
  63. get ENCRYPTED byte
  64. if ENCRYPTED != 0
  65. callfunction SET_AES_KEY 1
  66. log MEMORY_FILE5 OFFSET SIZE
  67. encryption "" ""
  68. else
  69. log MEMORY_FILE5 OFFSET SIZE
  70. endif
  71. math TOC_FILE5 = -5
  72. endif
  73.  
  74. goto 0
  75. callfunction GET_BASE_PATH 1
  76. endif
  77.  
  78. get FILES long TOC_FILE5
  79. getdstring DUMMY 12 TOC_FILE5
  80. get HASHES_OFFSET longlong TOC_FILE5
  81. math HASHES_OFFSET - OFFSET
  82. get HASHES_SIZE longlong TOC_FILE5
  83. getdstring DUMMY 24 TOC_FILE5
  84. get NAMES_OFFSET longlong TOC_FILE5
  85. math NAMES_OFFSET - OFFSET
  86. get NAMES_SIZE longlong TOC_FILE5
  87. getdstring DUMMY 24 TOC_FILE5
  88. savepos BASE_INDEX_OFF TOC_FILE5
  89. goto NAMES_OFFSET TOC_FILE5
  90.  
  91. math CHUNK_SIZE = 0x10000 # just in case...
  92. for i = 0 < FILES
  93. callfunction GET_NAME_AND_OFFSET 1
  94. if NAME = ""
  95. continue NEXT0
  96. endif
  97.  
  98. savepos TMP_OFF TOC_FILE
  99.  
  100. get OFFSET longlong TOC_FILE
  101. get ZSIZE longlong TOC_FILE
  102. get SIZE longlong TOC_FILE
  103. get ZIP long TOC_FILE
  104. getdstring HASH 20 TOC_FILE
  105.  
  106. math CHUNKS = 0
  107. math ENCRYPTED = 0
  108. if VERSION >= 3
  109. if ZIP != 0
  110. get CHUNKS long TOC_FILE
  111. for x = 0 < CHUNKS
  112. get CHUNK_OFFSET longlong TOC_FILE
  113. get CHUNK_END_OFFSET longlong TOC_FILE
  114. putarray 0 x CHUNK_OFFSET
  115. putarray 1 x CHUNK_END_OFFSET
  116. next x
  117. endif
  118. get ENCRYPTED byte TOC_FILE
  119. get CHUNK_SIZE long TOC_FILE
  120. endif
  121.  
  122. #if ALTERNATIVE_MODE != 0
  123. savepos TMP_OFF TOC_FILE
  124. math OFFSET + TMP_OFF
  125. #endif
  126.  
  127. #comtype copy
  128. callfunction COMPRESSION_TYPE 1
  129.  
  130. if CHUNKS > 0
  131. log NAME 0 0
  132. append
  133. math TMP_SIZE = SIZE
  134. if CHUNK_OFFSET_ABSOLUTE < 0 && OFFSET != 0
  135. getarray CHUNK_OFFSET 0 0
  136. if CHUNK_OFFSET u< OFFSET
  137. math CHUNK_OFFSET_ABSOLUTE = 0
  138. else
  139. math CHUNK_OFFSET_ABSOLUTE = 1
  140. endif
  141. endif
  142. for x = 0 < CHUNKS
  143. getarray CHUNK_OFFSET 0 x
  144. getarray CHUNK_END_OFFSET 1 x
  145. math CHUNK_ZSIZE = CHUNK_END_OFFSET
  146. math CHUNK_ZSIZE - CHUNK_OFFSET
  147. math CHUNK_XSIZE = CHUNK_ZSIZE
  148. if ENCRYPTED != 0
  149. callfunction SET_AES_KEY 1
  150. math CHUNK_XSIZE x 16
  151. endif
  152. if TMP_SIZE u< CHUNK_SIZE
  153. math CHUNK_SIZE = TMP_SIZE
  154. endif
  155. math CHUNK_OFFSET = OFFSET
  156.  
  157. if ZIP == 0
  158. log NAME CHUNK_OFFSET CHUNK_SIZE 0 CHUNK_XSIZE
  159. else
  160. clog NAME CHUNK_OFFSET CHUNK_ZSIZE CHUNK_SIZE 0 CHUNK_XSIZE
  161. endif
  162.  
  163. math TMP_SIZE - CHUNK_SIZE
  164. math OFFSET + CHUNK_XSIZE
  165. next x
  166. append
  167.  
  168. else
  169. # the file offset points to an entry containing
  170. # the "same" OFFSET ZSIZE SIZE ZIP HASH ZERO fields,
  171. # just an additional backup... so let's skip them
  172. savepos BASE_OFF TOC_FILE
  173. math BASE_OFF - TMP_OFF
  174. math OFFSET + BASE_OFF
  175. math XSIZE = ZSIZE
  176. if ENCRYPTED != 0
  177. callfunction SET_AES_KEY 1
  178. math XSIZE x 16
  179. endif
  180. if ZIP == 0
  181. math BLOCK = 0x40000000
  182. xmath FSIZE "OFFSET + ZSIZE"
  183. log NAME 0 0
  184. append
  185. for OFFSET = OFFSET < FSIZE
  186. xmath DIFF "FSIZE - OFFSET"
  187. if DIFF < BLOCK
  188. math XSIZE = DIFF
  189. if ENCRYPTED != 0
  190. math XSIZE x 16
  191. endif
  192. log NAME OFFSET DIFF 0 XSIZE
  193. else
  194. log NAME OFFSET BLOCK
  195. endif
  196. math OFFSET + BLOCK
  197. next
  198. append
  199. else
  200. clog NAME OFFSET ZSIZE SIZE 0 XSIZE
  201. endif
  202. endif
  203. encryption "" ""
  204.  
  205. if ALTERNATIVE_MODE != 0
  206. if CHUNKS == 0
  207. math OFFSET + XSIZE
  208. endif
  209. goto OFFSET
  210.  
  211. get TMP1 longlong
  212. get CHECK byte
  213. if TMP1 == 0 && CHECK != 0
  214. goto OFFSET
  215. continue NEXT1
  216. else
  217. goto OFFSET
  218. endif
  219. xmath CHECK "0x800 - (OFFSET % 0x800)"
  220. if CHECK <= 16
  221. padding 0x800
  222. endif
  223.  
  224. savepos OFFSET
  225. get TMP1 longlong
  226. get TMP2 longlong
  227. if TMP2 == 0
  228. padding 0x800
  229. else
  230. goto OFFSET
  231. endif
  232.  
  233. label NEXT1
  234. endif
  235.  
  236. label NEXT0
  237. next i
  238.  
  239. print "\nEntries ignored: %SKIP_COUNT%"
  240. for i = 0 < SKIP_COUNT
  241. getarray NAME 7 i
  242. print "Ignored entry: %NAME%"
  243. next i
  244.  
  245. startfunction SET_AES_KEY_ASK
  246. math AES_KEY_IS_SET = 1
  247. print "The archive is encrypted, you need to provide the key"
  248. if AES_KEY == ""
  249. set KEY unknown "???"
  250. else
  251. set KEY binary AES_KEY
  252. endif
  253.  
  254. if KEY == ""
  255. math AES_KEY_IS_SET = -1
  256. set AES_KEY string "No key provided, encryption disabled"
  257. elif KEY strncmp "0x"
  258. string KEY << 2
  259. string AES_KEY h KEY
  260. else
  261. set AES_KEY binary KEY
  262. endif
  263. print "KEY: %AES_KEY%"
  264. endfunction
  265.  
  266. startfunction SET_AES_KEY
  267. if AES_KEY_IS_SET == 0
  268. callfunction SET_AES_KEY_ASK 1
  269. endif
  270. if AES_KEY_IS_SET > 0
  271. encryption aes AES_KEY "" 0 32
  272. endif
  273. endfunction
  274.  
  275. startfunction GET_BASE_PATH
  276. get NAMESZ long TOC_FILE5
  277. getdstring BASE_PATH NAMESZ TOC_FILE5
  278. if NAMESZ != 0x0A && NAMESZ < 0xFF
  279. string BASE_PATH | "../../../"
  280. math BASE_PATH_INCLUDED = 0
  281. endif
  282. endfunction
  283.  
  284. startfunction CHECK_UNICODE
  285. if NAMESZ >= 0
  286. getdstring RESULT NAMESZ TOC_FILE5
  287. else
  288. math NAMESZ n NAMESZ
  289. math NAMESZ * 2
  290. getdstring RESULT NAMESZ TOC_FILE5
  291. set RESULT unicode RESULT
  292. endif
  293. endfunction
  294.  
  295. startfunction GET_NAME_AND_OFFSET
  296. if NAME_FROM_ARRAY = 1
  297. if CURR_NAME < DIR_FILES
  298. getarray NAME 5 CURR_NAME
  299. getarray OFFSET 6 CURR_NAME
  300. goto OFFSET
  301. math CURR_NAME + 1
  302. if CURR_NAME = DIR_FILES
  303. math NAME_FROM_ARRAY = 0
  304. endif
  305. endif
  306. else
  307. if DIR_FLAG = 1
  308. get DIR_COUNT long TOC_FILE5
  309. math DIR_FLAG = 0
  310. endif
  311.  
  312. if DIR_COUNT = 0
  313. math DIR_FLAG = 1
  314. callfunction GET_NAME_AND_OFFSET 1
  315. else
  316. math DIR_COUNT - 1
  317. get NAMESZ signed_long TOC_FILE5
  318. callfunction CHECK_UNICODE 1
  319. string DIR_NAME = RESULT
  320. get DIR_FILES long TOC_FILE5
  321. if DIR_FILES = 0
  322. callfunction GET_NAME_AND_OFFSET 1
  323. else
  324. for y = 0 < DIR_FILES
  325. get NAMESZ signed_long TOC_FILE5
  326. callfunction CHECK_UNICODE 1
  327. string NAME = RESULT
  328. string NAME p "%s%s" DIR_NAME NAME
  329. if BASE_PATH_INCLUDED == 0
  330. string NAME p "%s%s" BASE_PATH NAME
  331. endif
  332. putarray 5 y NAME
  333.  
  334. get OFFSET long TOC_FILE5
  335. savepos TMP_INDEX_OFF TOC_FILE5
  336. if OFFSET != 0x80000000 && OFFSET != 0x7FFFFFFF
  337. xmath INDEX_OFF "BASE_INDEX_OFF + OFFSET"
  338. goto INDEX_OFF TOC_FILE5
  339. get FLAGS long TOC_FILE5
  340. xmath HAS_SIZE "FLAGS & 0x3F"
  341. xmath IS_64 "FLAGS >> 28"
  342. if HAS_SIZE = 0x3F
  343. get CHUNK_SIZE long TOC_FILE5
  344. endif
  345. if IS_64 = 0xE
  346. get OFFSET long TOC_FILE5
  347. else
  348. get OFFSET longlong TOC_FILE5
  349. endif
  350. else
  351. putarray 7 SKIP_COUNT NAME
  352. math SKIP_COUNT + 1
  353. string NAME = ""
  354. putarray 5 y NAME
  355. endif
  356. putarray 6 y OFFSET
  357. goto TMP_INDEX_OFF TOC_FILE5
  358. next y
  359. math NAME_FROM_ARRAY = 1
  360. math CURR_NAME = 0
  361. callfunction GET_NAME_AND_OFFSET 1
  362. endif
  363. endif
  364. endif
  365. endfunction
  366.  
  367. startfunction COMPRESSION_TYPE
  368. if COMP1 = ""
  369. comtype zlib
  370. endif
  371.  
  372. if ZIP = 1 && COMP1 = "zlib"
  373. comtype zlib
  374. elif ZIP = 1 && COMP1 = "zstd"
  375. comtype zstd
  376. elif ZIP = 1 && COMP1 = "oodle"
  377. comtype oodle
  378. elif ZIP = 1 && COMP1 = "lz4"
  379. comtype lz4
  380. elif ZIP = 1 && COMP1 = "gzip"
  381. comtype gzip
  382. elif ZIP = 2 && COMP2 = "zlib"
  383. comtype zlib
  384. elif ZIP = 2 && COMP2 = "zstd"
  385. comtype zstd
  386. elif ZIP = 2 && COMP2 = "oodle"
  387. comtype oodle
  388. elif ZIP = 2 && COMP2 = "lz4"
  389. comtype lz4
  390. elif ZIP = 2 && COMP2 = "gzip"
  391. comtype gzip
  392. elif ZIP = 3 || ZIP = 4 || ZIP = 0x10 # 3 - Faith of Danschant, 4 - Days Gone, 10 - Ashen
  393. comtype oodle
  394. if WORKAROUND == 2
  395. comtype lz4
  396. endif
  397. endif
  398. endfunction
  399.  
  400. startfunction QUICKBMS_4GB_CHECK
  401. math TMP64 = 0x10000000
  402. math TMP64 * 16
  403. if TMP64 == 0
  404. print "You must use quickbms_4gb_files.exe with this script!"
  405. cleanexit
  406. endif
  407. endfunction
  408.