def extract_directx9_shader(file, date, shader_size, headers, section_offset, section_size, shader): bin = file.read(shader_size) align( file, 4 ) # Seems ok without this - looks like the shader binary is always a multiple of 4 bytes assert ( bin[8:12] in (b'CTAB', b'DBUG') ) # XXX: May fail for shaders without embedded constant tables. Debug section seen in Salt Hidden_GlobalFog hash = zlib.crc32(bin) extract_unity_shaders._add_shader_hash_asm_crc(shader.sub_program, zlib.crc32(bin)) path_components = extract_unity_shaders.export_filename_combined_short( shader) dest = extract_unity_shaders.path_components_to_dest(path_components) dump_raw_bind_info(file, dest, section_offset, section_size) # Have not fully deciphered the data around this point, and depending # on the values the size can vary. Making a best guess based on # obsevations that DX9 ends in 0, 0. Values seem to be in pairs. Suspect # they are related to the generic "Bind" statements in previous Unity # versions, but can't make heads or tails of them. undeciphered3 = list(struct.unpack('<I', file.read(4))) undeciphered3.extend(consume_until_double_zero(file)) add_header(headers, ('undeciphered3:' + ' {}' * len(undeciphered3)).format(*undeciphered3)) decode_dx9_bind_info(file, date, headers) assert (file.tell() - section_size - section_offset == 0) delay_writing_dx9_shader(hash, dest, bin, headers, shader.sub_program)
def extract_directx9_shader(file, date, shader_size, headers, section_offset, section_size, shader): bin = file.read(shader_size) align(file, 4) # Seems ok without this - looks like the shader binary is always a multiple of 4 bytes assert(bin[8:12] in (b'CTAB', b'DBUG')) # XXX: May fail for shaders without embedded constant tables. Debug section seen in Salt Hidden_GlobalFog hash = zlib.crc32(bin) extract_unity_shaders._add_shader_hash_asm_crc(shader.sub_program, zlib.crc32(bin)) path_components = extract_unity_shaders.export_filename_combined_short(shader) dest = extract_unity_shaders.path_components_to_dest(path_components) dump_raw_bind_info(file, dest, section_offset, section_size) # Have not fully deciphered the data around this point, and depending # on the values the size can vary. Making a best guess based on # obsevations that DX9 ends in 0, 0. Values seem to be in pairs. Suspect # they are related to the generic "Bind" statements in previous Unity # versions, but can't make heads or tails of them. undeciphered3 = list(struct.unpack('<I', file.read(4))) undeciphered3.extend(consume_until_double_zero(file)) add_header(headers, ('undeciphered3:' + ' {}'*len(undeciphered3)).format(*undeciphered3)) decode_dx9_bind_info(file, date, headers) assert(file.tell() - section_size - section_offset == 0) delay_writing_dx9_shader(hash, dest, bin, headers, shader.sub_program)
def extract_opengl_shader(file, shader_size, headers, shader): shader.sub_program.shader_asm = file.read(shader_size).decode('utf-8') try: hash = {} for program_name in ('fp', 'vp'): shader.program.name = program_name; hash[program_name] = extract_unity_shaders.hash_gl_crc(shader.sub_program) add_header(headers, ('{} hash: {:x}'.format(program_name, hash[program_name]))) for program_name in ('fp', 'vp'): # FIXME: Write out any with duplicate hashes in case we ever have # an autofix that needs to e.g. find all PS corresponding with a # given VS hash, where that hash appears in multiple distinct # shaders (e.g. Internal-PrePassLighting and # Internal-DeferredReflection share the same VS, but have differing PS) if hash[program_name] in processed: continue processed.add(hash[program_name]) shader.program.name = program_name; extract_unity_shaders._add_shader_hash_gl_crc(shader.sub_program, hash[program_name]) path_components = extract_unity_shaders.export_filename_combined_short(shader) dest = extract_unity_shaders.path_components_to_dest(path_components) print('Extracting %s.glsl...' % dest) with open('%s.glsl' % dest, 'w') as out: out.write(extract_unity_shaders.fixup_glsl_like_unity(shader.sub_program)) with open('%s.info' % dest, 'w') as f: f.write('\n'.join(headers)) except extract_unity_shaders.BogusShader: return
def extract_unknown_shader(file, shader_size, headers, shader): raw = file.read(shader_size) hash = zlib.crc32(raw) extract_unity_shaders._add_shader_hash_unknown(shader.sub_program, hash) path_components = extract_unity_shaders.export_filename_combined_short(shader) dest = extract_unity_shaders.path_components_to_dest(path_components) print('Extracting %s.raw...' % dest) with open('%s.raw' % dest, 'wb') as out: out.write(raw) with open('%s.headers' % dest, 'w') as f: f.write('\n'.join(headers))
def extract_directx11_shader(file, shader_size, headers, section_offset, section_size, shader, date): # Is this the correct way to detect this? Could be a file version, but it # looks suspiciously like a date (but 2015? Last year for an update # released this year?), so I'm not certain this is correct. If not this, # maybe just check the Unity version for 5.4? if date == 201509030: # Unity 5.3 u8len = 5 elif date >= 201510240: # Unity 5.4+ u8len = 6 else: assert (False) u8 = struct.unpack('<%ib' % u8len, file.read(u8len)) add_header(headers, 'undeciphered2: {}'.format(' '.join(map( str, u8)))) # Think this is related to the bindings bin = file.read(shader_size - u8len) align(file, 4) assert (bin[:4] == b'DXBC') hash = extract_unity_shaders.fnv_3Dmigoto_shader(bin) extract_unity_shaders._add_shader_hash_fnv(shader.sub_program, hash) path_components = extract_unity_shaders.export_filename_combined_short( shader) dest = extract_unity_shaders.path_components_to_dest(path_components) # print('Extracting %s.bin...' % dest) # with open('%s.bin' % dest, 'wb') as out: # out.write(bin) dump_raw_bind_info(file, dest, section_offset, section_size) # Have not fully deciphered the data around this point, and depending # on the values the size can vary. Making a best guess based on # obsevations that DX11 ends in num_sections, 0, 0, 0. If first value != 0 # it is followed by two 0s. Values seem to be in pairs. Suspect they are # related to the generic "Bind" statements in previous Unity versions, but # can't make heads or tails of them. undeciphered3 = list(struct.unpack('<2I', file.read(8))) if undeciphered3[1]: undeciphered3.extend(struct.unpack('<2I', file.read(8))) num_sections = consume_until_dx11_num_sections(file, undeciphered3) add_header(headers, ('undeciphered3:' + ' {}' * len(undeciphered3)).format(*undeciphered3)) decode_dx11_bind_info(file, date, num_sections, headers) assert (file.tell() - section_size - section_offset == 0) delay_writing_dx11_shader(hash, dest, bin, headers, shader.sub_program)
def extract_unknown_shader(file, shader_size, headers, shader): raw = file.read(shader_size) hash = zlib.crc32(raw) extract_unity_shaders._add_shader_hash_unknown(shader.sub_program, hash) path_components = extract_unity_shaders.export_filename_combined_short( shader) dest = extract_unity_shaders.path_components_to_dest(path_components) print('Extracting %s.raw...' % dest) with open('%s.raw' % dest, 'wb') as out: out.write(raw) with open('%s.headers' % dest, 'w') as f: f.write('\n'.join(headers))
def extract_directx11_shader(file, shader_size, headers, section_offset, section_size, shader, date): # Is this the correct way to detect this? Could be a file version, but it # looks suspiciously like a date (but 2015? Last year for an update # released this year?), so I'm not certain this is correct. If not this, # maybe just check the Unity version for 5.4? if date == 201509030: # Unity 5.3 u8len = 5 elif date >= 201510240: # Unity 5.4+ u8len = 6 else: assert(False) u8 = struct.unpack('<%ib' % u8len, file.read(u8len)) add_header(headers, 'undeciphered2: {}'.format(' '.join(map(str, u8)))) # Think this is related to the bindings bin = file.read(shader_size - u8len) align(file, 4) assert(bin[:4] == b'DXBC') hash = extract_unity_shaders.fnv_3Dmigoto_shader(bin) extract_unity_shaders._add_shader_hash_fnv(shader.sub_program, hash) path_components = extract_unity_shaders.export_filename_combined_short(shader) dest = extract_unity_shaders.path_components_to_dest(path_components) # print('Extracting %s.bin...' % dest) # with open('%s.bin' % dest, 'wb') as out: # out.write(bin) dump_raw_bind_info(file, dest, section_offset, section_size) # Have not fully deciphered the data around this point, and depending # on the values the size can vary. Making a best guess based on # obsevations that DX11 ends in num_sections, 0, 0, 0. If first value != 0 # it is followed by two 0s. Values seem to be in pairs. Suspect they are # related to the generic "Bind" statements in previous Unity versions, but # can't make heads or tails of them. undeciphered3 = list(struct.unpack('<2I', file.read(8))) if undeciphered3[1]: undeciphered3.extend(struct.unpack('<2I', file.read(8))) num_sections = consume_until_dx11_num_sections(file, undeciphered3) add_header(headers, ('undeciphered3:' + ' {}'*len(undeciphered3)).format(*undeciphered3)) decode_dx11_bind_info(file, date, num_sections, headers) assert(file.tell() - section_size - section_offset == 0) delay_writing_dx11_shader(hash, dest, bin, headers, shader.sub_program)
def extract_opengl_shader(file, shader_size, headers, shader): shader.sub_program.shader_asm = file.read(shader_size).decode('utf-8') try: hash = {} for program_name in ('fp', 'vp'): shader.program.name = program_name hash[program_name] = extract_unity_shaders.hash_gl_crc( shader.sub_program) add_header( headers, ('{} hash: {:x}'.format(program_name, hash[program_name]))) for program_name in ('fp', 'vp'): # FIXME: Write out any with duplicate hashes in case we ever have # an autofix that needs to e.g. find all PS corresponding with a # given VS hash, where that hash appears in multiple distinct # shaders (e.g. Internal-PrePassLighting and # Internal-DeferredReflection share the same VS, but have differing PS) if hash[program_name] in processed: continue processed.add(hash[program_name]) shader.program.name = program_name extract_unity_shaders._add_shader_hash_gl_crc( shader.sub_program, hash[program_name]) path_components = extract_unity_shaders.export_filename_combined_short( shader) dest = extract_unity_shaders.path_components_to_dest( path_components) print('Extracting %s.glsl...' % dest) with open('%s.glsl' % dest, 'w') as out: out.write( extract_unity_shaders.fixup_glsl_like_unity( shader.sub_program)) with open('%s.info' % dest, 'w') as f: f.write('\n'.join(headers)) except extract_unity_shaders.BogusShader: return