Ejemplo n.º 1
0
        private void LoadHeaders()
        {
            ImageData imageData = xexData;

            xexData.header = rdr.ReadStruct <XexHeader>();

            XexHeader header = xexData.header;

            switch (header.magic)
            {
            case XEX2_MAGIC:
            case XEX1_MAGIC:
                break;

            default:
                throw new BadImageFormatException("Invalid XEX Magic");
            }

            for (uint i = 0; i < header.header_count; i++)
            {
                bool add = true;
                XexOptionalHeader st_optionalHeader = rdr.ReadStruct <XexOptionalHeader>();
                OptionalHeader    optionalHeader    = new OptionalHeader(st_optionalHeader);

                switch ((byte)optionalHeader.key)
                {
                // just the data
                case 0x00:
                case 0x01:
                    optionalHeader.value  = optionalHeader.offset;
                    optionalHeader.offset = 0;
                    break;

                case 0xFF:
                    optionalHeader.length = rdr.ReadAt <UInt32>(optionalHeader.offset, (r) =>
                    {
                        return(r.ReadUInt32());
                    });
                    optionalHeader.offset += 4;

                    if (optionalHeader.length + optionalHeader.offset > rdr.Bytes.Length)
                    {
                        decompilerEventListener.Warn(
                            new NullCodeLocation(""),
                            $"Optional header {i} (0x{optionalHeader.key:X}) crosses file boundary. Will not be read"
                            );
                        add = false;
                    }
                    break;

                default:
                    optionalHeader.length = ((uint)(byte)optionalHeader.key) * 4;

                    if (optionalHeader.length + optionalHeader.offset > rdr.Bytes.Length)
                    {
                        decompilerEventListener.Warn(
                            new NullCodeLocation(""),
                            $"Optional header {i} (0x{optionalHeader.key:X}) crosses file boundary. Will not be read"
                            );
                        add = false;
                    }
                    break;
                }

                if (add)
                {
                    optional_headers.Add(optionalHeader);
                }
            }

            for (int i = 0; i < optional_headers.Count; i++)
            {
                OptionalHeader opt = optional_headers[i];

                // go to the header offset
                if (opt.length > 0 && opt.offset != 0)
                {
                    rdr.Offset = opt.offset;
                }

                // process the optional headers
                switch (opt.key)
                {
                case XEXHeaderKeys.XEX_HEADER_SYSTEM_FLAGS:
                    imageData.system_flags = (XEXSystemFlags)opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_RESOURCE_INFO:
                    uint count = (opt.length - 4) / 16;
                    xexData.resources = new List <XexResourceInfo>((int)count);

                    for (uint n = 0; n < count; n++)
                    {
                        xexData.resources.Insert(i, rdr.ReadStruct <XexResourceInfo>());
                    }
                    break;

                case XEXHeaderKeys.XEX_HEADER_EXECUTION_INFO:
                    imageData.execution_info = rdr.ReadStruct <XexExecutionInfo>();
                    break;

                case XEXHeaderKeys.XEX_HEADER_GAME_RATINGS:
                    break;

                case XEXHeaderKeys.XEX_HEADER_TLS_INFO:
                    imageData.tls_info = rdr.ReadStruct <XexTlsInfo>();
                    break;

                case XEXHeaderKeys.XEX_HEADER_IMAGE_BASE_ADDRESS:
                    imageData.exe_address = opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_ENTRY_POINT:
                    imageData.exe_entry_point = opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_DEFAULT_STACK_SIZE:
                    imageData.exe_stack_size = opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_DEFAULT_HEAP_SIZE:
                    imageData.exe_heap_size = opt.value;
                    break;

                case XEXHeaderKeys.XEX_HEADER_FILE_FORMAT_INFO:
                    XexEncryptionHeader encHeader = rdr.ReadStruct <XexEncryptionHeader>();

                    imageData.file_format_info.encryption_type  = encHeader.encryption_type;
                    imageData.file_format_info.compression_type = encHeader.compression_type;

                    switch (encHeader.compression_type)
                    {
                    case XEXCompressionType.XEX_COMPRESSION_NONE:
                        break;

                    case XEXCompressionType.XEX_COMPRESSION_DELTA:
                        throw new NotImplementedException("XEX: image::Binary is using unsupported delta compression");

                    case XEXCompressionType.XEX_COMPRESSION_BASIC:
                        uint block_count = (opt.length - 8) / 8;
                        imageData.file_format_info.basic_blocks = new List <XexFileBasicCompressionBlock>((int)block_count);

                        for (int ib = 0; ib < block_count; ib++)
                        {
                            imageData.file_format_info.basic_blocks.Insert(ib, rdr.ReadStruct <XexFileBasicCompressionBlock>());
                        }
                        break;

                    case XEXCompressionType.XEX_COMPRESSION_NORMAL:
                        imageData.file_format_info.normal = rdr.ReadStruct <XexFileNormalCompressionInfo>();
                        break;
                    }

                    if (encHeader.encryption_type != XEXEncryptionType.XEX_ENCRYPTION_NONE)
                    {
                        //
                    }
                    break;

                case XEXHeaderKeys.XEX_HEADER_IMPORT_LIBRARIES:
                    XexImportLibraryBlockHeader blockHeader = rdr.ReadStruct <XexImportLibraryBlockHeader>();

                    long string_table = rdr.Offset;
                    for (int j = 0; j < blockHeader.count; j++)
                    {
                        string name = rdr.ReadCString(PrimitiveType.Char, Encoding.ASCII).ToString();
                        imageData.libNames.Add(name);
                    }
                    rdr.Offset = string_table + blockHeader.string_table_size;

                    for (int m = 0; m < blockHeader.count; m++)
                    {
                        XexImportLibaryHeader imp_header = rdr.ReadStruct <XexImportLibaryHeader>();

                        string name       = null;
                        int    name_index = (byte)imp_header.name_index;
                        if (name_index < blockHeader.count)
                        {
                            name = imageData.libNames[name_index];
                        }

                        for (uint ri = 0; ri < imp_header.record_count; ++ri)
                        {
                            UInt32 recordEntry = rdr.ReadUInt32();
                            xexData.import_records.Add(recordEntry);
                        }
                    }
                    break;
                }
            }

            // load the loader info
            {
                rdr.Offset = header.security_offset;

                switch (header.magic)
                {
                case XEX1_MAGIC:
                    Xex1LoaderInfo info1 = rdr.ReadStruct <Xex1LoaderInfo>();
                    xexData.loader_info.aes_key = info1.aes_key;
                    break;

                case XEX2_MAGIC:
                    Xex2LoaderInfo info2 = rdr.ReadStruct <Xex2LoaderInfo>();
                    xexData.loader_info.aes_key = info2.aes_key;
                    break;
                }
            }

            // load the sections
            {
                rdr.Offset = header.security_offset + 0x180;

                UInt32 sectionCount = rdr.ReadUInt32();
                xexData.sections = new List <XexSection>((int)sectionCount);

                for (int si = 0; si < sectionCount; si++)
                {
                    xexData.sections.Insert(0, rdr.ReadStruct <XexSection>());
                }
            }

            // decrypt the XEX key
            {
                byte[] keyToUse = xe_xex2_devkit_key;
                if (header.magic != XEX1_MAGIC && xexData.execution_info.title_id != 0)
                {
                    keyToUse = xe_xex2_retail_key;
                }

                Rijndael aes = new RijndaelManaged()
                {
                    BlockSize = 128,
                    KeySize   = 128,
                    Mode      = CipherMode.ECB,
                    Key       = keyToUse,
                    Padding   = PaddingMode.None
                };

                xexData.session_key = aes
                                      .CreateDecryptor()
                                      .TransformFinalBlock(xexData.loader_info.aes_key, 0, 16);
                decompilerEventListener.Info(
                    new NullCodeLocation(""),
                    "XEX Session key: " + BitConverter.ToString(xexData.session_key).Replace("-", "")
                    );
            }
        }