Created
October 27, 2015 21:07
-
-
Save rr-/3300b8e2e8202b56fb58 to your computer and use it in GitHub Desktop.
Shiina Rio .exe decoder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/python3 | |
import struct | |
import argparse | |
# tested on: | |
# - Sorcery Jokers (works) | |
# - Tekoire Princess (needs manual tweaks to work) | |
# so it's only semi-automatic. | |
def read_u16(data, offset): | |
return struct.unpack('<H', data[offset:offset + 2])[0] | |
def read_s32(data, offset): | |
return struct.unpack('<l', data[offset:offset + 4])[0] | |
def read_u32(data, offset): | |
return struct.unpack('<L', data[offset:offset + 4])[0] | |
def write_u16(data, offset, what): | |
data[offset:offset + 2] = struct.pack('<H', what) | |
def write_u32(data, offset, what): | |
data[offset:offset + 4] = struct.pack('<L', what) | |
def decrypt(data, key, section): | |
source_offset = section['rva'] | |
for i in range(min(section['virt-size'], section['size'])): | |
key = (key * 5 + 0x3711) & 0xFFFFFFFF | |
data[section['rva'] + i] ^= key & 0xFF | |
return key | |
def decode(input_path, output_path): | |
with open(input_path, 'rb') as ifh: | |
data = bytearray(ifh.read()) | |
file_header_size = 0x14 | |
optional_header_size = 0x60 | |
section_size = 0x28 | |
lfa_new = struct.unpack('<L', data[0x3C:0x40])[0] | |
file_header_offset = lfa_new + 4 | |
optional_header_offset = lfa_new + 4 + file_header_size | |
number_of_sections = read_u16(data, file_header_offset + 2) | |
image_base = read_u32(data, optional_header_offset + 28) | |
number_of_rva_and_sizes = read_u32(data, optional_header_offset + 0x5C) | |
rva_and_sizes_offset = optional_header_offset + optional_header_size | |
sections_offset = rva_and_sizes_offset + number_of_rva_and_sizes * 8 | |
sections = {} | |
for i in range(number_of_sections): | |
section_offset = sections_offset + section_size * i | |
name = (data[section_offset:section_offset+8] | |
.decode('ascii').rstrip('\x00')) | |
section = \ | |
{ | |
'name': name, | |
'offset': image_base + read_u32(data, section_offset + 12), | |
'rva': read_u32(data, section_offset + 20), | |
'virt-size': read_u32(data, section_offset + 8), | |
'size': read_u32(data, section_offset + 16), | |
} | |
sections[name] = section | |
print('%+8s rva:%8x offset:%8x size:%8x(real:%8x)' % ( | |
section['name'], | |
section['rva'], | |
section['offset'], | |
section['virt-size'], | |
section['size'])) | |
i = 0 | |
key = None | |
while i < sections['.riox']['size'] - 4: | |
if read_u32(data, sections['.riox']['rva'] + i) == sections['.text']['virt-size']: | |
key = read_u32(data, sections['.riox']['rva'] + i + 5) | |
break | |
i += 1 | |
program_start_proc = None | |
while i < sections['.riox']['size'] - 4: | |
if read_u32(data, sections['.riox']['rva'] + i) == 0xDDB8BCD6: | |
program_start_proc = sections['.riox']['offset'] + i + 8 + 4 + read_s32(data, sections['.riox']['rva'] + i + 8) | |
break | |
i += 1 | |
if not key: | |
raise RuntimeError('Failed to guess the key, proceed manually') | |
print('Key: %08x' % key) | |
print('OEP: %08x' % program_start_proc) | |
key = decrypt(data, key, sections['.text']) | |
decrypt(data, key, sections['.data']) | |
decrypt(data, key, sections['.riox']) | |
decryptor_rva = sections['.riox']['rva'] | |
data[decryptor_rva] = 0x68 # x86 "push" | |
write_u32(data, decryptor_rva + 1, program_start_proc) | |
data[decryptor_rva + 5] = 0xC3 # x86 "ret" | |
with open(output_path, 'wb') as ofh: | |
ofh.write(data) | |
def main(): | |
parser = argparse.ArgumentParser( | |
description='Decode ShiinaRio encoded executables') | |
parser.add_argument('INPUT_FILE', help='Path to the input .exe file') | |
parser.add_argument('OUTPUT_FILE', help='Path where to save output .exe') | |
args = parser.parse_args() | |
decode(args.INPUT_FILE, args.OUTPUT_FILE) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment