示例#1
0
// ******************************************************************
// * constructor
// ******************************************************************
EmuExe::EmuExe(Xbe *x_Xbe, DebugMode x_debug_mode, char *x_debug_filename, HWND hwndParent) : Exe()
{
    ConstructorInit();

    printf("EmuExe::EmuExe: Generating Exe file...\n");

    // ******************************************************************
    // * generate pe header
    // ******************************************************************
    {
        printf("EmuExe::EmuExe: Generating PE header...");

        m_Header.m_magic                    = *(uint32 *)"PE\0\0";                      // magic number : "PE\0\0"
        m_Header.m_machine                  = IMAGE_FILE_MACHINE_I386;                  // machine type : i386
        m_Header.m_sections                 = (uint16)(x_Xbe->m_Header.dwSections + 2); // xbe sections + .cxbximp + .cxbxplg
        m_Header.m_timedate                 = x_Xbe->m_Header.dwTimeDate;               // time/date stamp
        m_Header.m_symbol_table_addr        = 0;                                        // unused
        m_Header.m_symbols                  = 0;                                        // unused
        m_Header.m_sizeof_optional_header   = sizeof(OptionalHeader);                   // size of optional header
        m_Header.m_characteristics          = 0x010F;                                   // should be fine..

        printf("OK\n");
    }

    // ******************************************************************
    // * generate optional header
    // ******************************************************************
    {
        printf("EmuExe::EmuExe: Generating Optional Header...");

        m_OptionalHeader.m_magic = 0x010B;         // magic number : 0x010B

        // ******************************************************************
        // * abitrary linker version : 6.0
        // ******************************************************************
        m_OptionalHeader.m_linker_version_major = 0x06;
        m_OptionalHeader.m_linker_version_minor = 0x00;

        // ******************************************************************
        // * size of headers
        // ******************************************************************
        m_OptionalHeader.m_sizeof_headers  = sizeof(bzDOSStub) + sizeof(m_Header);
        m_OptionalHeader.m_sizeof_headers += sizeof(m_OptionalHeader) + sizeof(*m_SectionHeader)*m_Header.m_sections;
        m_OptionalHeader.m_sizeof_headers  = RoundUp(m_OptionalHeader.m_sizeof_headers, PE_FILE_ALIGN);

        m_OptionalHeader.m_image_base = x_Xbe->m_Header.dwBaseAddr;

        m_OptionalHeader.m_section_alignment = PE_SEGM_ALIGN;
        m_OptionalHeader.m_file_alignment    = PE_FILE_ALIGN;

        // ******************************************************************
        // * OS version : 4.0
        // ******************************************************************
        m_OptionalHeader.m_os_version_major  = 0x0004;
        m_OptionalHeader.m_os_version_minor  = 0x0000;

        // ******************************************************************
        // * image version : 0.0
        // ******************************************************************
        m_OptionalHeader.m_image_version_major = 0x0000;
        m_OptionalHeader.m_image_version_minor = 0x0000;

        // ******************************************************************
        // * subsystem version : 4.0
        // ******************************************************************
        m_OptionalHeader.m_subsystem_version_major = 0x0004;
        m_OptionalHeader.m_subsystem_version_minor = 0x0000;

        m_OptionalHeader.m_win32_version   = 0x00000000;
        m_OptionalHeader.m_checksum        = 0x00000000;
        m_OptionalHeader.m_subsystem       = IMAGE_SUBSYSTEM_WINDOWS_GUI;

        // ******************************************************************
        // * no special dll characteristics are necessary
        // ******************************************************************
        m_OptionalHeader.m_dll_characteristics = 0x0000;

        // ******************************************************************
        // * TODO: for each of these, check for bad values and correct them
        // ******************************************************************
        m_OptionalHeader.m_sizeof_stack_reserve = 0x00100000;
        m_OptionalHeader.m_sizeof_stack_commit  = x_Xbe->m_Header.dwPeStackCommit;
        m_OptionalHeader.m_sizeof_heap_reserve  = x_Xbe->m_Header.dwPeHeapReserve;
        m_OptionalHeader.m_sizeof_heap_commit   = x_Xbe->m_Header.dwPeHeapCommit;

        // ******************************************************************
        // * this member is obsolete, so we'll just set it to zero
        // ******************************************************************
        m_OptionalHeader.m_loader_flags = 0x00000000;

        // ******************************************************************
        // * we'll set this to the typical 0x10 (16)
        // ******************************************************************
        m_OptionalHeader.m_data_directories = 0x10;

        // ******************************************************************
        // * clear all data directories (we'll setup some later)
        // ******************************************************************
        for(uint32 d=0;d<m_OptionalHeader.m_data_directories;d++)
        {
            m_OptionalHeader.m_image_data_directory[d].m_virtual_addr = 0;
            m_OptionalHeader.m_image_data_directory[d].m_size = 0;
        }

        printf("OK\n");
    }

    // ******************************************************************
    // * generate section headers
    // ******************************************************************
    {
        printf("EmuExe::EmuExe: Generating Section Headers...\n");

        m_SectionHeader = new SectionHeader[m_Header.m_sections];

        // ******************************************************************
        // * start appending section headers at this point
        // ******************************************************************
        uint32 dwSectionCursor = x_Xbe->m_SectionHeader[0].dwRawAddr;

        // ******************************************************************
        // * generate xbe section headers
        // ******************************************************************
        {
            for(uint32 v=0;v<x_Xbe->m_Header.dwSections;v++)
            {
                printf("EmuExe::EmuExe: Generating Section Header 0x%.04X...", v);

                // ******************************************************************
                // * generate xbe section name
                // ******************************************************************
                {
                    memset(m_SectionHeader[v].m_name, 0, 8);

                    for(int c=0;c<8;c++)
                    {
                        m_SectionHeader[v].m_name[c] = x_Xbe->m_szSectionName[v][c];

                        if(m_SectionHeader[v].m_name[c] == '\0')
                            break;
                    }
                }

                // ******************************************************************
                // * generate xbe section virtual size / addr
                // ******************************************************************
                {
                    uint32 VirtSize = x_Xbe->m_SectionHeader[v].dwVirtualSize;
                    uint32 VirtAddr = x_Xbe->m_SectionHeader[v].dwVirtualAddr - x_Xbe->m_Header.dwBaseAddr;

                    m_SectionHeader[v].m_virtual_size = VirtSize;
                    m_SectionHeader[v].m_virtual_addr = VirtAddr;
                }

                // ******************************************************************
                // * generate xbe section raw size / addr
                // ******************************************************************
                {
                    // TODO: get this working such that m_sizeof_raw can be the actual raw size, not virtual size
                    uint32 RawSize = RoundUp(x_Xbe->m_SectionHeader[v].dwVirtualSize, PE_FILE_ALIGN);
                    uint32 RawAddr = dwSectionCursor;

                    m_SectionHeader[v].m_sizeof_raw = RawSize;
                    m_SectionHeader[v].m_raw_addr   = RawAddr;

                    dwSectionCursor += RawSize;
                }

                // ******************************************************************
                // * relocation / line numbers will not exist
                // ******************************************************************
                {
                    m_SectionHeader[v].m_relocations_addr = 0;
                    m_SectionHeader[v].m_linenumbers_addr = 0;

                    m_SectionHeader[v].m_relocations = 0;
                    m_SectionHeader[v].m_linenumbers = 0;
                }

                // ******************************************************************
                // * generate flags for this xbe section
                // ******************************************************************
                {
                    uint32 flags = IMAGE_SCN_MEM_READ;

                    if(x_Xbe->m_SectionHeader[v].dwFlags.bExecutable)
                    {
                        flags |= IMAGE_SCN_MEM_EXECUTE;
                        flags |= IMAGE_SCN_CNT_CODE;
                    }
                    else
                    {
                        flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
                    }

                    if(x_Xbe->m_SectionHeader[v].dwFlags.bWritable)
                        flags |= IMAGE_SCN_MEM_WRITE;

                    m_SectionHeader[v].m_characteristics = flags;
                }

                printf("OK\n");
            }
        }

        // ******************************************************************
        // * generate .cxbximp section header
        // ******************************************************************
        {
            uint32 i = m_Header.m_sections - 2;

            printf("EmuExe::EmuExe: Generating Section Header 0x%.04X (.cxbximp)...", i);

            memcpy(m_SectionHeader[i].m_name, ".cxbximp", 8);

            // ******************************************************************
            // * generate .cxbximp section virtual size / addr
            // ******************************************************************
            {
                uint32 virt_size = RoundUp(0x6E, PE_SEGM_ALIGN);
                uint32 virt_addr = RoundUp(m_SectionHeader[i-1].m_virtual_addr + m_SectionHeader[i-1].m_virtual_size, PE_SEGM_ALIGN);

                m_SectionHeader[i].m_virtual_size = virt_size;
                m_SectionHeader[i].m_virtual_addr = virt_addr;
            }

            // ******************************************************************
            // * generate .cxbximp section raw size / addr
            // ******************************************************************
            {
                uint32 raw_size = RoundUp(m_SectionHeader[i].m_virtual_size, PE_FILE_ALIGN);

                m_SectionHeader[i].m_sizeof_raw  = raw_size;
                m_SectionHeader[i].m_raw_addr    = dwSectionCursor;

                dwSectionCursor += raw_size;
            }

            // ******************************************************************
            // * relocation / line numbers will not exist
            // ******************************************************************
            {
                m_SectionHeader[i].m_relocations_addr = 0;
                m_SectionHeader[i].m_linenumbers_addr = 0;

                m_SectionHeader[i].m_relocations = 0;
                m_SectionHeader[i].m_linenumbers = 0;
            }

            // ******************************************************************
            // * make this section readable initialized data
            // ******************************************************************
            m_SectionHeader[i].m_characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA;

            // ******************************************************************
            // * update import table directory entry
            // ******************************************************************
            m_OptionalHeader.m_image_data_directory[IMAGE_DIRECTORY_ENTRY_IMPORT].m_virtual_addr = m_SectionHeader[i].m_virtual_addr + 0x08;
            m_OptionalHeader.m_image_data_directory[IMAGE_DIRECTORY_ENTRY_IMPORT].m_size = 0x28;

            // ******************************************************************
            // * update import address table directory entry
            // ******************************************************************
            m_OptionalHeader.m_image_data_directory[IMAGE_DIRECTORY_ENTRY_IAT].m_virtual_addr = m_SectionHeader[i].m_virtual_addr;
            m_OptionalHeader.m_image_data_directory[IMAGE_DIRECTORY_ENTRY_IAT].m_size = 0x08;

            printf("OK\n");
        }

        // ******************************************************************
        // * generate .cxbxplg section header
        // ******************************************************************
        {
            uint32 i = m_Header.m_sections - 1;

            printf("EmuExe::EmuExe: Generating Section Header 0x%.04X (.cxbxplg)...", i);

            memcpy(m_SectionHeader[i].m_name, ".cxbxplg", 8);

            // ******************************************************************
            // * generate .cxbxplg section virtual size / addr
            // ******************************************************************
            {
                uint32 virt_size = RoundUp(m_OptionalHeader.m_image_base + 0x100 + x_Xbe->m_Header.dwSizeofHeaders + 260
                                        + sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions + sizeof(Xbe::TLS)
                                        + (x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr), 0x1000);
                uint32 virt_addr = RoundUp(m_SectionHeader[i-1].m_virtual_addr + m_SectionHeader[i-1].m_virtual_size, PE_SEGM_ALIGN);

                m_SectionHeader[i].m_virtual_size = virt_size;
                m_SectionHeader[i].m_virtual_addr = virt_addr;

                // our entry point should be the first bytes in this section
                m_OptionalHeader.m_entry = virt_addr;
            }

            // ******************************************************************
            // * generate .cxbxplg section raw size / addr
            // ******************************************************************
            {
                uint32 raw_size = RoundUp(m_SectionHeader[i].m_virtual_size, PE_FILE_ALIGN);

                m_SectionHeader[i].m_sizeof_raw = raw_size;
                m_SectionHeader[i].m_raw_addr   = dwSectionCursor;

                dwSectionCursor += raw_size;
            }

            // ******************************************************************
            // * relocation / line numbers will not exist
            // ******************************************************************
            {
                m_SectionHeader[i].m_relocations_addr = 0;
                m_SectionHeader[i].m_linenumbers_addr = 0;

                m_SectionHeader[i].m_relocations = 0;
                m_SectionHeader[i].m_linenumbers = 0;
            }

            // ******************************************************************
            // * make this section readable and executable
            // ******************************************************************
            m_SectionHeader[i].m_characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;

            printf("OK\n");
        }
    }

    // ******************************************************************
    // * generate sections
    // ******************************************************************
    {
        printf("EmuExe::EmuExe: Generating Sections...\n");

        m_bzSection = new uint08*[m_Header.m_sections];

        // ******************************************************************
        // * generate xbe sections
        // ******************************************************************
        {
            uint32 kt = x_Xbe->m_Header.dwKernelImageThunkAddr;

            // ******************************************************************
            // * decode kernel thunk address
            // ******************************************************************
            {
                if((kt ^ XOR_KT_DEBUG) > 0x01000000)
                    kt ^= XOR_KT_RETAIL;
                else
                    kt ^= XOR_KT_DEBUG;
            }

            // ******************************************************************
            // * generate xbe sections
            // ******************************************************************
            for(uint32 v=0;v<x_Xbe->m_Header.dwSections;v++)
            {
                printf("EmuExe::EmuExe: Generating Section 0x%.04X...", v);

                uint32 SectionSize = m_SectionHeader[v].m_sizeof_raw;

                m_bzSection[v] = new uint08[SectionSize];

                memset(m_bzSection[v], 0, SectionSize);

                memcpy(m_bzSection[v], x_Xbe->m_bzSection[v], x_Xbe->m_SectionHeader[v].dwSizeofRaw);

                printf("OK\n");
            }

        }

        // ******************************************************************
        // * generate .cxbximp section
        // ******************************************************************
        {
            uint32 i = m_Header.m_sections - 2;

            printf("EmuExe::EmuExe: Generating Section 0x%.04X (.cxbximp)...", i);

            uint32 dwVirtAddr = m_SectionHeader[i].m_virtual_addr;

            uint32 dwRawSize = m_SectionHeader[i].m_sizeof_raw;

            m_bzSection[i] = new uint08[dwRawSize];

            memset(m_bzSection[i], 0, dwRawSize);

            *(uint32*)&m_bzSection[i][0x00] = dwVirtAddr + 0x38;
            *(uint32*)&m_bzSection[i][0x04] = 0;
            *(uint32*)&m_bzSection[i][0x08] = dwVirtAddr + 0x30;
            *(uint32*)&m_bzSection[i][0x0C] = 0;

            *(uint32*)&m_bzSection[i][0x10] = 0;
            *(uint32*)&m_bzSection[i][0x14] = dwVirtAddr + 0x4A;
            *(uint32*)&m_bzSection[i][0x18] = dwVirtAddr + 0x00;
            *(uint32*)&m_bzSection[i][0x1C] = 0;

            *(uint32*)&m_bzSection[i][0x20] = 0;
            *(uint32*)&m_bzSection[i][0x24] = 0;
            *(uint32*)&m_bzSection[i][0x28] = 0;
            *(uint32*)&m_bzSection[i][0x2C] = 0;

            *(uint32*)&m_bzSection[i][0x30] = dwVirtAddr + 0x38;
            *(uint32*)&m_bzSection[i][0x34] = 0;
            *(uint16*)&m_bzSection[i][0x38] = 0x0001;

            #ifdef _DEBUG
            memcpy(&m_bzSection[i][0x3A], "CxbxKrnlNoFunc\0\0CxbxKrnl.dll\0\0", 30);
            #else
            memcpy(&m_bzSection[i][0x3A], "CxbxKrnlNoFunc\0\0Cxbx.dll\0\0\0\0\0\0", 30);
            #endif

            printf("OK\n");
        }

        // ******************************************************************
        // * generate .cxbxplg section
        // ******************************************************************
        {
            uint32 ep = x_Xbe->m_Header.dwEntryAddr;
            uint32 i  = m_Header.m_sections - 1;

            printf("EmuExe::EmuExe: Generating Section 0x%.04X (.cxbxplg)...", i);

            // ******************************************************************
            // * decode entry point
            // ******************************************************************
            if( (ep ^ XOR_EP_RETAIL) > 0x01000000)
                ep ^= XOR_EP_DEBUG;
            else
                ep ^= XOR_EP_RETAIL;

            m_bzSection[i] = new uint08[m_SectionHeader[i].m_sizeof_raw];

            uint08 *pWriteCursor = m_bzSection[i];

            // ******************************************************************
            // * append prolog section
            // ******************************************************************
            memcpy(pWriteCursor, Prolog, 0x1000);
            pWriteCursor += 0x100;

            // ******************************************************************
            // * append xbe header
            // ******************************************************************
            memcpy(pWriteCursor, &x_Xbe->m_Header, sizeof(Xbe::Header));
            pWriteCursor += sizeof(Xbe::Header);

            // ******************************************************************
            // * append xbe extra header bytes
            // ******************************************************************
            memcpy(pWriteCursor, x_Xbe->m_HeaderEx, x_Xbe->m_Header.dwSizeofHeaders - sizeof(Xbe::Header));
            pWriteCursor -= sizeof(Xbe::Header);
            pWriteCursor += x_Xbe->m_Header.dwSizeofHeaders;

            // ******************************************************************
            // * append x_debug_filename
            // ******************************************************************
            memcpy(pWriteCursor, x_debug_filename, 260);
            pWriteCursor += 260;

            // ******************************************************************
            // * append library versions
            // ******************************************************************
            if(x_Xbe->m_LibraryVersion != 0)
            {
                memcpy(pWriteCursor, x_Xbe->m_LibraryVersion, sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions);
                pWriteCursor += sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions;
            }

            // ******************************************************************
            // * append TLS data
            // ******************************************************************
            if(x_Xbe->m_TLS != 0)
            {
                memcpy(pWriteCursor, x_Xbe->m_TLS, sizeof(Xbe::TLS));
                pWriteCursor += sizeof(Xbe::TLS);
                memcpy(pWriteCursor, x_Xbe->GetTLSData(), x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr);
                pWriteCursor += x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr;
            }

            // ******************************************************************
            // * patch prolog function parameters
            // ******************************************************************
            uint32 WriteCursor = m_SectionHeader[i].m_virtual_addr + m_OptionalHeader.m_image_base + 0x100;

            // Function Pointer
            *(uint32 *)((uint32)m_bzSection[i] + 1)  = (uint32)CxbxKrnlInit;

            // Param 8 : Entry
            *(uint32 *)((uint32)m_bzSection[i] + 6)  = (uint32)ep;

            // Param 7 : dwXbeHeaderSize
            *(uint32 *)((uint32)m_bzSection[i] + 11) = (uint32)x_Xbe->m_Header.dwSizeofHeaders;

            // Param 6 : pXbeHeader
            *(uint32 *)((uint32)m_bzSection[i] + 16) = WriteCursor;
            WriteCursor += x_Xbe->m_Header.dwSizeofHeaders;

            // Param 5 : szDebugFilename
            *(uint32 *)((uint32)m_bzSection[i] + 21) = WriteCursor;
            WriteCursor += 260;

            // Param 4 : DbgMode
            *(uint32 *)((uint32)m_bzSection[i] + 26) = x_debug_mode;

            // Param 3 : pLibraryVersion
            if(x_Xbe->m_LibraryVersion != 0)
            {
                *(uint32 *)((uint32)m_bzSection[i] + 31) = WriteCursor;
                WriteCursor += sizeof(Xbe::LibraryVersion) * x_Xbe->m_Header.dwLibraryVersions;
            }
            else
            {
                *(uint32 *)((uint32)m_bzSection[i] + 31) = 0;
            }

            // Param 2 : pTLS
            if(x_Xbe->m_TLS != 0)
            {
                *(uint32 *)((uint32)m_bzSection[i] + 36) = WriteCursor;
                WriteCursor += sizeof(Xbe::TLS);
            }
            else
            {
                *(uint32 *)((uint32)m_bzSection[i] + 36) = 0;
            }

            // Param 1 : pTLSData
            if(x_Xbe->m_TLS != 0)
            {
                *(uint32 *)((uint32)m_bzSection[i] + 41) = WriteCursor;
                WriteCursor += x_Xbe->m_TLS->dwDataEndAddr - x_Xbe->m_TLS->dwDataStartAddr;
            }
            else
            {
                *(uint32 *)((uint32)m_bzSection[i] + 41) = 0;
            }

            // Param 0 : hwndParent
            *(uint32 *)((uint32)m_bzSection[i] + 46) = (uint32)hwndParent;

            printf("OK\n");
        }
    }

    // ******************************************************************
    // * patch kernel thunk table
    // ******************************************************************
    {
        printf("EmuExe::EmuExe: Hijacking Kernel Imports...\n");

        uint32 kt = x_Xbe->m_Header.dwKernelImageThunkAddr;

        // ******************************************************************
        // * decode kernel thunk address
        // ******************************************************************
        {
            if( (kt ^ XOR_KT_DEBUG) > 0x01000000)
                kt ^= XOR_KT_RETAIL;
            else
                kt ^= XOR_KT_DEBUG;
        }

        // ******************************************************************
        // * locate section containing kernel thunk table
        // ******************************************************************
        for(uint32 v=0;v<x_Xbe->m_Header.dwSections;v++)
        {
            uint32 imag_base = m_OptionalHeader.m_image_base;

            uint32 virt_addr = m_SectionHeader[v].m_virtual_addr;
            uint32 virt_size = m_SectionHeader[v].m_virtual_size;

            // ******************************************************************
            // * modify kernel thunk table, if found
            // ******************************************************************
            if(kt >= virt_addr + imag_base && kt < virt_addr + virt_size + imag_base)
            {
                printf("EmuExe::EmuExe: Located Thunk Table in Section 0x%.04X (0x%.08X)...\n", v, kt);

                uint32 *kt_tbl = (uint32*)&m_bzSection[v][kt - virt_addr - imag_base];

                for(int k=0;kt_tbl[k] != 0;k++)
                {
                    int t = kt_tbl[k] & 0x7FFFFFFF;

                    kt_tbl[k] = CxbxKrnl_KernelThunkTable[t];

                    if(t != -1)
                        printf("EmuExe::EmuExe: Thunk %.03d : *0x%.08X := 0x%.08X\n", t, kt + k*4, kt_tbl[k]);
                }

                break;
            }
        }
    }

    // ******************************************************************
    // * update imcomplete header fields
    // ******************************************************************
    {
        printf("EmuExe::EmuExe: Finalizing Exe file...");

        // ******************************************************************
        // * calculate size of code / data / image
        // ******************************************************************
        {
            uint32 sizeof_code   = 0;
            uint32 sizeof_data   = 0;
            uint32 sizeof_undata = 0;
            uint32 sizeof_image  = 0;

            for(uint32 v=0;v<m_Header.m_sections;v++)
            {
                uint32 characteristics = m_SectionHeader[v].m_characteristics;

                if( (characteristics & IMAGE_SCN_MEM_EXECUTE) || (characteristics & IMAGE_SCN_CNT_CODE) )
				{
					sizeof_code += m_SectionHeader[v].m_sizeof_raw;
				}
				else if( (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) )
				{
                    sizeof_data += m_SectionHeader[v].m_sizeof_raw;
				}
				else if( (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) )
				{
						sizeof_data += m_SectionHeader[v].m_sizeof_raw;
				}
            }

            // ******************************************************************
            // * calculate size of image (INCORRECT!)
            // ******************************************************************
            sizeof_image = sizeof_undata + sizeof_data + sizeof_code + m_OptionalHeader.m_sizeof_headers;
            sizeof_image  = RoundUp(sizeof_image, PE_SEGM_ALIGN);

            // ******************************************************************
            // * update optional header as necessary
            // ******************************************************************
            m_OptionalHeader.m_sizeof_code                 = sizeof_code;
            m_OptionalHeader.m_sizeof_initialized_data     = sizeof_data;
            m_OptionalHeader.m_sizeof_uninitialized_data   = sizeof_undata;
            m_OptionalHeader.m_sizeof_image                = sizeof_image;
        }

        // ******************************************************************
        // * we'll set code base as the virtual address of the first section
        // ******************************************************************
        m_OptionalHeader.m_code_base = m_SectionHeader[0].m_virtual_addr;

        // ******************************************************************
        // * we'll set data base as the virtual address of the first section
        // * that is not marked as containing code or being executable
        // ******************************************************************
        for(uint32 v=0;v<m_Header.m_sections;v++)
        {
            uint32 characteristics = m_SectionHeader[v].m_characteristics;

            if( !(characteristics & IMAGE_SCN_MEM_EXECUTE) || !(characteristics & IMAGE_SCN_CNT_CODE) )
            {
                m_OptionalHeader.m_data_base = m_SectionHeader[v].m_virtual_addr;
                break;
            }
        }

        printf("OK\n");
    }
}
示例#2
0
文件: Exe.cpp 项目: OpenXDK/cxbe
// construct via Exe file
Exe::Exe(const char *x_szFilename)
{
    ConstructorInit();

    std::cout << std::setfill('0') << std::hex;
    std::cout << "Exe::Exe: Opening Exe file...";

    FILE *ExeFile = fopen(x_szFilename, "rb");

    // verify Exe file was opened
    if(ExeFile == 0)
    {
        SetError("Could not open Exe file.", true);
        return;
    }

    std::cout << "OK\n";

    // ignore dos stub (if exists)
    {
        std::cout << "Exe::Exe: Reading DOS stub...";

        if(fread(&m_DOSHeader.m_magic, sizeof(m_DOSHeader.m_magic), 1, ExeFile) != 1)
        {
            SetError("Unexpected read error while reading magic number", true);
            goto cleanup;
        }

        if(m_DOSHeader.m_magic == *reinterpret_cast<const uint16_t*>("MZ"))
        {
            std::cout << "Found, Ignoring...";

            if(fread(&m_DOSHeader.m_cblp, sizeof(m_DOSHeader)-2, 1, ExeFile) != 1)
            {
                SetError("Unexpected read error while reading DOS stub", true);
                goto cleanup;
            }

            fseek(ExeFile, m_DOSHeader.m_lfanew, SEEK_SET);

            std::cout << "OK\n";
        }
        else
        {
            std::cout << "None (OK)\n";
        }
    }

    // read PE header
    {
        std::cout << "Exe::Exe: Reading PE header...";

        if(fread(&m_Header, sizeof(m_Header), 1, ExeFile) != 1)
        {
            SetError("Unexpected read error while reading PE header", true);
            goto cleanup;
        }

        if(m_Header.m_magic != *reinterpret_cast<const uint32_t*>("PE\0\0"))
        {
            SetError("Invalid file (could not locate PE header)", true);
            goto cleanup;
        }

        std::cout << "OK\n";
    }

    // read optional header
    {
        std::cout << "Exe::Exe: Reading Optional Header...";

        if(fread(&m_OptionalHeader, sizeof(m_OptionalHeader), 1, ExeFile) != 1)
        {
            SetError("Unexpected read error while reading PE optional header", true);
            goto cleanup;
        }

        if(m_OptionalHeader.m_magic != 0x010B)
        {
            SetError("Invalid file (could not locate PE optional header)", true);
            goto cleanup;
        }

         std::cout << "OK\n";
    }

    // read section headers
    {
        m_SectionHeader = new SectionHeader[m_Header.m_sections];

        std::cout << "Exe::Exe: Reading Section Headers...\n";

        for(uint32_t v=0;v<m_Header.m_sections;v++)
        {
            std::cout << "Exe::Exe: Reading Section Header 0x" << std::setw(4) << v << "...";

            if(fread(&m_SectionHeader[v], sizeof(SectionHeader), 1, ExeFile) != 1)
            {
                char buffer[255];
                sprintf(buffer, "Could not read PE section header %d (%Xh)", v, v);
                SetError(buffer, true);
                goto cleanup;
            }

            std::cout << "OK\n";
        }
    }

    // read sections
    {
        std::cout << "Exe::Exe: Reading Sections...\n";

        m_bzSection = new uint8_t*[m_Header.m_sections];

        for(uint32_t v=0;v<m_Header.m_sections;v++)
        {
            std::cout << "Exe::Exe: Reading Section 0x" << std::setw(4) << v << "...";

            uint32_t raw_size = m_SectionHeader[v].m_sizeof_raw;
            uint32_t raw_addr = m_SectionHeader[v].m_raw_addr;

            m_bzSection[v] = new uint8_t[raw_size];

            memset(m_bzSection[v], 0, raw_size);

            if(raw_size == 0)
            {
                std::cout << "OK\n";
                continue;
            }

            // read current section from file (if raw_size > 0)
            {
                fseek(ExeFile, raw_addr, SEEK_SET);

                if(fread(m_bzSection[v], raw_size, 1, ExeFile) != 1)
                {
                    char buffer[255];
                    sprintf(buffer, "Could not read PE section %d (%Xh)", v, v);
                    SetError(buffer, true);
                    goto cleanup;
                }
            }

            std::cout << "OK\n";
        }
    }

    std::cout << "Exe::Exe: Exe was successfully opened.\n";

cleanup:

    if(GetError() != 0)
    {
        std::cout << "FAILED!\n";
        std::cout << "Exe::Exe: ERROR -> " << GetError() << "\n";
    }

    fclose(ExeFile);
}
示例#3
0
文件: Xbe.cpp 项目: OpenXDK/cxbe
// construct via Xbe file
Xbe::Xbe(const char *x_szFilename)
{
    char szBuffer[260];

    ConstructorInit();

    std::cout << "Xbe::Xbe: Opening Xbe file...";

    FILE *XbeFile = fopen(x_szFilename, "rb");

    // verify Xbe file was opened successfully
    if(XbeFile == 0)
    {
        SetError("Could not open Xbe file.", true);
        return;
    }

    std::cout << "OK\n";

    // remember the Xbe path
    {
        std::cout << "Xbe::Xbe: Storing Xbe Path...";

        strcpy(m_szPath, x_szFilename);

        int v=0, c=0;

        while(m_szPath[v] != '\0')
        {
            if(m_szPath[v] == '\\')
                c = v+1;
            v++;
        }

        m_szPath[c] = '\0';
    }

    std::cout << "OK\n";

    // read Xbe image header
    {
        std::cout << "Xbe::Xbe: Reading Image Header...";

        if(fread(&m_Header, sizeof(m_Header), 1, XbeFile) != 1)
        {
            SetError("Unexpected end of file while reading Xbe Image Header", true);
            goto cleanup;
        }

        if(m_Header.dwMagic != *reinterpret_cast<const uint32_t*>("XBEH"))
        {
            SetError("Invalid magic number in Xbe file", true);
            goto cleanup;
        }

        std::cout << "OK\n";
    }

    // read Xbe image header extra bytes
    if(m_Header.dwSizeofHeaders > sizeof(m_Header))
    {
        std::cout << "Xbe::Xbe: Reading Image Header Extra Bytes...";

        uint32_t ExSize = RoundUp(m_Header.dwSizeofHeaders, 0x1000) - static_cast<uint32_t>(sizeof(m_Header));

        m_HeaderEx = new char[ExSize];

        if(fread(m_HeaderEx, ExSize, 1, XbeFile) != 1)
        {
            SetError("Unexpected end of file while reading Xbe Image Header (Ex)", true);
            goto cleanup;
        }

        std::cout << "OK\n";
    }

    // read Xbe certificate
    {
        std::cout << "Xbe::Xbe: Reading Certificate...";

        fseek(XbeFile, m_Header.dwCertificateAddr - m_Header.dwBaseAddr, SEEK_SET);

        if(fread(&m_Certificate, sizeof(m_Certificate), 1, XbeFile) != 1)
        {
            SetError("Unexpected end of file while reading Xbe Certificate", true);
            goto cleanup;
        }

        setlocale( LC_ALL, "English" );

        //wcstombs(m_szAsciiTitle, m_Certificate.wszTitleName, 40);
        for (int i=0; i<40 && m_Certificate.wszTitleName[i] != 0; i++)
			m_szAsciiTitle[i] = static_cast<uint8_t>(m_Certificate.wszTitleName[i]);


        std::cout << "OK\n";

        std::cout << "Xbe::Xbe: Title identified as " << m_szAsciiTitle << "\n";
    }

    // read Xbe section headers
    {
        std::cout << "Xbe::Xbe: Reading Section Headers...\n";

        fseek(XbeFile, m_Header.dwSectionHeadersAddr - m_Header.dwBaseAddr, SEEK_SET);

        m_SectionHeader = new SectionHeader[m_Header.dwSections];

        for(uint32_t v=0;v<m_Header.dwSections;v++)
        {
            std::cout << "Xbe::Xbe: Reading Section Header 0x" << std::setfill('0') << std::hex << std::setw(4) << v << "...";

            if(fread(&m_SectionHeader[v], sizeof(*m_SectionHeader), 1, XbeFile) != 1)
            {
                sprintf(szBuffer, "Unexpected end of file while reading Xbe Section Header %d (%Xh)", v, v);
                SetError(szBuffer, true);
                goto cleanup;
            }

            std::cout << "OK\n";
        }
    }

    // read Xbe section names
    {
        std::cout << "Xbe::Xbe: Reading Section Names...\n";

        m_szSectionName = new char[m_Header.dwSections][9];
        for(uint32_t v=0;v<m_Header.dwSections;v++)
        {
            std::cout << "Xbe::Xbe: Reading Section Name 0x" << std::setfill('0') << std::hex << std::setw(4) << v << "...";

            uint8_t *sn = GetAddr(m_SectionHeader[v].dwSectionNameAddr);

            memset(m_szSectionName[v], 0, 9);

            if(sn != 0)
            {
                for(int b=0;b<8;b++)
                {
                    m_szSectionName[v][b] = sn[b];

                    if(m_szSectionName[v][b] == '\0')
                        break;
                }
            }

            std::cout << "OK (" << m_szSectionName[v] << ")\n";
        }
    }

    // read Xbe library versions
    if(m_Header.dwLibraryVersionsAddr != 0)
    {
        std::cout << "Xbe::Xbe: Reading Library Versions...\n";

        fseek(XbeFile, m_Header.dwLibraryVersionsAddr - m_Header.dwBaseAddr, SEEK_SET);

        m_LibraryVersion = new LibraryVersion[m_Header.dwLibraryVersions];

        for(uint32_t v=0;v<m_Header.dwLibraryVersions;v++)
        {
            std::cout << "Xbe::Xbe: Reading Library Version 0x" << std::setfill('0') << std::hex << std::setw(4) << v << "...";

            if(fread(&m_LibraryVersion[v], sizeof(*m_LibraryVersion), 1, XbeFile) != 1)
            {
                sprintf(szBuffer, "Unexpected end of file while reading Xbe Library Version %d (%Xh)", v, v);
                SetError(szBuffer, true);
                goto cleanup;
            }

            std::cout << "OK\n";
        }

        // read Xbe kernel library version
        {
            std::cout << "Xbe::Xbe: Reading Kernel Library Version...";

            if(m_Header.dwKernelLibraryVersionAddr == 0)
            {
                SetError("Could not locate kernel library version", true);
                goto cleanup;
            }

            fseek(XbeFile, m_Header.dwKernelLibraryVersionAddr - m_Header.dwBaseAddr, SEEK_SET);

            m_KernelLibraryVersion = new LibraryVersion;

            if(fread(m_KernelLibraryVersion, sizeof(*m_LibraryVersion), 1, XbeFile) != 1)
            {
                SetError("Unexpected end of file while reading Xbe Kernel Version", true);
                goto cleanup;
            }

            std::cout << "OK\n";
        }

        // read Xbe Xapi library version
        {
            std::cout << "Xbe::Xbe: Reading Xapi Library Version...";

            if(m_Header.dwXAPILibraryVersionAddr == 0)
            {
                SetError("Could not locate Xapi Library Version", true);
                goto cleanup;
            }

            fseek(XbeFile, m_Header.dwXAPILibraryVersionAddr - m_Header.dwBaseAddr, SEEK_SET);

            m_XAPILibraryVersion = new LibraryVersion;

            if(fread(m_XAPILibraryVersion, sizeof(*m_LibraryVersion), 1, XbeFile) != 1)
            {
                SetError("Unexpected end of file while reading Xbe Xapi Version", true);
                goto cleanup;
            }

            std::cout << "OK\n";
        }
    }

    // read Xbe sections
    {
        std::cout << "Xbe::Xbe: Reading Sections...\n";

        m_bzSection = new uint8_t*[m_Header.dwSections];

        memset(m_bzSection, 0, m_Header.dwSections);

        for(uint32_t v=0;v<m_Header.dwSections;v++)
        {
            std::cout << "Xbe::Xbe: Reading Section 0x" << std::setfill('0') << std::hex << std::setw(4) << v << "...\n";

            uint32_t RawSize = m_SectionHeader[v].dwSizeofRaw;
            uint32_t RawAddr = m_SectionHeader[v].dwRawAddr;

            m_bzSection[v] = new uint8_t[RawSize];

            fseek(XbeFile, RawAddr, SEEK_SET);

            if(RawSize == 0)
            {
                std::cout << "OK\n";
                continue;
            }

            if(fread(m_bzSection[v], RawSize, 1, XbeFile) != 1)
            {
                sprintf(szBuffer, "Unexpected end of file while reading Xbe Section %d (%Xh) (%s)", v, v, m_szSectionName[v]);
                SetError(szBuffer, true);
                goto cleanup;
            }

            std::cout << "OK\n";
        }
    }

    // read Xbe thread local storage
    if(m_Header.dwTLSAddr != 0)
    {
        std::cout << "Xbe::Xbe: Reading Thread Local Storage...";

        void *Addr = GetAddr(m_Header.dwTLSAddr);

        if(Addr == 0)
        {
            SetError("Could not locate Thread Local Storage", true);
            goto cleanup;
        }

        m_TLS = new TLS;

        memcpy(m_TLS, Addr, sizeof(*m_TLS));

        std::cout << "OK\n";
    }

cleanup:

    if(GetError() != 0)
    {
        std::cout << "FAILED!\n";
        std::cout << "Xbe::Xbe: ERROR -> " << GetError() << "\n";
    }

    fclose(XbeFile);

    return;
}
示例#4
0
文件: Exe.cpp 项目: JayFoxRox/OpenXDK
// construct via Exe file
Exe::Exe(const char *x_szFilename)
{
    ConstructorInit();

    printf("Exe::Exe: Opening Exe file...");

    FILE *ExeFile = fopen(x_szFilename, "rb");

    // verify Exe file was opened
    if(ExeFile == 0)
    {
        SetError("Could not open Exe file.", true);
        return;
    }

    printf("OK\n");

    // ignore dos stub (if exists)
    {
        printf("Exe::Exe: Reading DOS stub...");

        if(fread(&m_DOSHeader.m_magic, sizeof(m_DOSHeader.m_magic), 1, ExeFile) != 1)
        {
            SetError("Unexpected read error while reading magic number", true);
            goto cleanup;
        }

        if(m_DOSHeader.m_magic == *(uint16*)"MZ")
        {
            printf("Found, Ignoring...");

            if(fread(&m_DOSHeader.m_cblp, sizeof(m_DOSHeader)-2, 1, ExeFile) != 1)
            {
                SetError("Unexpected read error while reading DOS stub", true);
                goto cleanup;
            }

            fseek(ExeFile, m_DOSHeader.m_lfanew, SEEK_SET);

            printf("OK\n");
        }
        else
        {
            printf("None (OK)\n");
        }
    }

    // read PE header
    {
        printf("Exe::Exe: Reading PE header... (%i bytes)",sizeof(m_Header));

        if(fread(&m_Header, sizeof(m_Header), 1, ExeFile) != 1)
        {
            SetError("Unexpected read error while reading PE header", true);
            goto cleanup;
        }

        if(m_Header.m_magic != *(uint32*)"PE\0\0")
        {
            SetError("Invalid file (could not locate PE header)", true);
            goto cleanup;
        }

        printf("OK\n");
    }

    // read optional header
    {
        printf("Exe::Exe: Reading Optional Header...");

        if(fread(&m_OptionalHeader, sizeof(m_OptionalHeader), 1, ExeFile) != 1)
        {
            SetError("Unexpected read error while reading PE optional header", true);
            goto cleanup;
        }

        if(m_OptionalHeader.m_magic != 0x010B)
        {
            SetError("Invalid file (could not locate PE optional header)", true);
            goto cleanup;
        }

         printf("OK\n");
    }

    // read section headers
    {
        m_SectionHeader = new SectionHeader[m_Header.m_sections];

        printf("Exe::Exe: Reading Section Headers...\n");

        for(uint32 v=0;v<m_Header.m_sections;v++)
        {
            printf("Exe::Exe: Reading Section Header 0x%.04X...", v);

            if(fread(&m_SectionHeader[v], sizeof(SectionHeader), 1, ExeFile) != 1)
            {
                char buffer[255];
                sprintf(buffer, "Could not read PE section header %d (%Xh)", v, v);
                SetError(buffer, true);
                goto cleanup;
            }

            printf("OK\n", v);
        }
    }

    // read sections
    {
        printf("Exe::Exe: Reading Sections...\n");

        m_bzSection = new uint08*[m_Header.m_sections];

        for(uint32 v=0;v<m_Header.m_sections;v++)
        {
            printf("Exe::Exe: Reading Section 0x%.04X...", v);

            uint32 raw_size = m_SectionHeader[v].m_sizeof_raw;
            uint32 raw_addr = m_SectionHeader[v].m_raw_addr;

            m_bzSection[v] = new uint08[raw_size];

            memset(m_bzSection[v], 0, raw_size);

            if(raw_size == 0)
            {
                printf("OK\n");
                continue;
            }

            // read current section from file (if raw_size > 0)
            {
                fseek(ExeFile, raw_addr, SEEK_SET);

                if(fread(m_bzSection[v], raw_size, 1, ExeFile) != 1)
                {
                    char buffer[255];
                    sprintf(buffer, "Could not read PE section %d (%Xh)", v, v);
                    SetError(buffer, true);
                    goto cleanup;
                }
            }

            printf("OK\n");
        }
    }

    printf("Exe::Exe: Exe was successfully opened.\n", x_szFilename);

cleanup:

    if(GetError() != 0)
    {
        printf("FAILED!\n");
        printf("Exe::Exe: ERROR -> %s\n", GetError());
    }

    fclose(ExeFile);
}
示例#5
0
文件: Xbe.cpp 项目: OpenXDK/cxbe
// construct via Exe file object
Xbe::Xbe(class Exe *x_Exe, const char *x_szTitle, bool x_bRetail)
{
    ConstructorInit();

    time_t CurrentTime;

    time(&CurrentTime);

    std::cout << "Xbe::Xbe: Pass 1 (Simple Pass)...";

    // pass 1
    {
        // standard Xbe magic number
        //m_Header.dwMagic = *reinterpret_cast<const uint32_t*>(reinterpret_cast<const char*>("XBEH"));
        m_Header.dwMagic = *reinterpret_cast<const uint32_t*>("XBEH");

        // nobody has the private key yet, so zero this out
        memset(m_Header.pbDigitalSignature, 0, 256);

        // we'll only allow 0x00010000 for now
        m_Header.dwBaseAddr = 0x00010000;

        // this is a constant value
        m_Header.dwSizeofImageHeader = sizeof(m_Header);

        // we'll have the same number of sections as the Exe
        m_Header.dwSections = x_Exe->m_Header.m_sections;

        // TODO: allow configuration
        {
            memset(&m_Header.dwInitFlags, 0, sizeof(m_Header.dwInitFlags));

            m_Header.dwInitFlags.bLimit64MB = true;
            m_Header.dwInitFlags.bDontSetupHarddisk = false;
            m_Header.dwInitFlags.bMountUtilityDrive = true;
        }

        // various PE copies
        {
            m_Header.dwPeStackCommit = 0x00010000; //x_Exe->m_OptionalHeader.m_sizeof_stack_commit;
            m_Header.dwPeHeapReserve = x_Exe->m_OptionalHeader.m_sizeof_heap_reserve;
            m_Header.dwPeHeapCommit  = x_Exe->m_OptionalHeader.m_sizeof_heap_commit;
            m_Header.dwPeSizeofImage = x_Exe->m_OptionalHeader.m_sizeof_image;
            m_Header.dwPeChecksum     = 0x00000000;
            m_Header.dwPeTimeDate     = x_Exe->m_Header.m_timedate;
        }

        // build time/date
        m_Header.dwTimeDate = static_cast<uint32_t>(CurrentTime);

        // TODO: generate valid addr if necessary
        m_Header.dwNonKernelImportDirAddr = 0;

        // TODO: generate these values
        m_Header.dwLibraryVersions = 0;
        m_Header.dwLibraryVersionsAddr = 0;
        m_Header.dwKernelLibraryVersionAddr = 0;
        m_Header.dwXAPILibraryVersionAddr = 0;
    }

    std::cout << "OK\n";

    std::cout << "Xbe::Xbe: Pass 2 (Calculating Requirements)...";

    // pass 2
    {
        // make-room cursor
        uint32_t mrc = m_Header.dwBaseAddr + static_cast<uint32_t>(sizeof(m_Header));

        // make room for certificate
        {
            m_Header.dwCertificateAddr = mrc;

            mrc += static_cast<uint32_t>(sizeof(m_Certificate));
        }

        // make room for section headers
        {
            m_Header.dwSectionHeadersAddr = mrc;

            mrc += m_Header.dwSections * static_cast<uint32_t>(sizeof(*m_SectionHeader));

            // make room for head/tail reference count words
            mrc += (m_Header.dwSections+1)*2;

            // make room for section names
            for(uint32_t v=0;v<m_Header.dwSections;v++)
            {
                uint32_t s = 0;

                while(s < 8 && x_Exe->m_SectionHeader[v].m_name[s] != '\0')
                    s++;

                mrc += s + 1;
            }
        }

        // TODO: make room for library versions
        {
        }

        // make room for debug path / debug file names
        {
            // TODO: allow this to be configured, right now we will just null out these values
            m_Header.dwDebugUnicodeFilenameAddr = mrc;
            m_Header.dwDebugPathnameAddr = mrc;
            m_Header.dwDebugFilenameAddr = mrc;

            mrc += 2;
        }

        // make room for largest possible logo bitmap
        {
            mrc = RoundUp(mrc, 0x10);

            m_Header.dwLogoBitmapAddr = mrc;
            m_Header.dwSizeofLogoBitmap = 100*17;    // Max Possible

            mrc += m_Header.dwSizeofLogoBitmap;
        }

        // update size of headers
        m_Header.dwSizeofHeaders = mrc - m_Header.dwBaseAddr;
    }

    std::cout << "OK\n";

    std::cout << "Xbe::Xbe: Pass 3 (Generating Xbe)...\n";

    // pass 3
    {
        m_Header.dwPeBaseAddr = m_Header.dwBaseAddr + RoundUp(m_Header.dwSizeofHeaders, 0x1000) - x_Exe->m_SectionHeader[0].m_virtual_addr;

        // encode entry point
        {
            std::cout << "Xbe::Xbe: Encoding " << (x_bRetail?"Retail":"Debug") << " Entry Point...";

            uint32_t ep = x_Exe->m_OptionalHeader.m_entry + m_Header.dwPeBaseAddr;

            if(x_bRetail)
                ep ^= XOR_EP_RETAIL;
            else
                ep ^= XOR_EP_DEBUG;

            m_Header.dwEntryAddr = ep;

            std::cout << "OK (0x" << std::setfill('0') << std::hex << std::setw(8) << ep << ")\n";
        }

        // header write cursor
        uint32_t hwc = m_Header.dwBaseAddr + static_cast<uint32_t>(sizeof(m_Header));

        // check if we need to store extra header bytes (we always will)
        if(m_Header.dwSizeofHeaders > sizeof(m_Header))
        {
            std::cout << "Xbe::Xbe: Found Extra Header Bytes...";

            uint32_t ExSize = RoundUp(m_Header.dwSizeofHeaders - static_cast<uint32_t>(sizeof(m_Header)), 0x1000);

            m_HeaderEx = new char[ExSize];

            std::cout << "OK\n";
        }

        // start a write buffer inside of m_HeaderEx
        char *szBuffer = m_HeaderEx;

        // write certificate
        {
            // certificate size is a constant
            m_Certificate.dwSize = sizeof(m_Certificate);

            m_Certificate.dwTimeDate = static_cast<uint32_t>(CurrentTime);

            // TODO: generate in the form CX-9999
            m_Certificate.dwTitleId = 0xFFFF0002;

            // title name
            memset(m_Certificate.wszTitleName, 0, 40);
            for (int i=0; i<40 && x_szTitle[i] != 0; i++)
				m_Certificate.wszTitleName[i] = x_szTitle[i];

            // zero out alternate ids
            {
                for(uint32_t c=0;c<0x10;c++)
                    m_Certificate.dwAlternateTitleId[c] = 0;
            }

            // for now we'll just allow any media you could want
            m_Certificate.dwAllowedMedia = XBEIMAGE_MEDIA_TYPE_HARD_DISK | XBEIMAGE_MEDIA_TYPE_DVD_CD | XBEIMAGE_MEDIA_TYPE_MEDIA_BOARD
	                                   | XBEIMAGE_MEDIA_TYPE_NONSECURE_HARD_DISK | XBEIMAGE_MEDIA_TYPE_NONSECURE_MODE;

            // TODO: allow configuration
            m_Certificate.dwGameRegion = XBEIMAGE_GAME_REGION_MANUFACTURING | XBEIMAGE_GAME_REGION_NA | XBEIMAGE_GAME_REGION_JAPAN | XBEIMAGE_GAME_REGION_RESTOFWORLD;

            // TODO: allow configuration
            m_Certificate.dwGameRatings = 0xFFFFFFFF;

            // always disk 0, AFAIK
            m_Certificate.dwDiskNumber = 0;

            // TODO: allow configuration
            m_Certificate.dwVersion = 0;

            // generate blank LAN, signature, and alternate signature keys
            {
                for(uint32_t v=0;v<0x10;v++)
                    m_Certificate.bzLanKey[v] = m_Certificate.bzSignatureKey[v] = 0;

                for(uint32_t x=0;x<0x10;x++)
                    for(uint32_t y=0;y<0x10;y++)
                        m_Certificate.bzTitleAlternateSignatureKey[x][y] = 0;

            }

            // write certificate
            {
                memcpy(szBuffer, &m_Certificate, sizeof(m_Certificate));

                szBuffer += sizeof(m_Certificate);

                hwc += static_cast<uint32_t>(sizeof(m_Certificate));
            }
        }

        // generate ascii title from certificate title name
        setlocale( LC_ALL, "English" );
        //wcstombs(m_szAsciiTitle, m_Certificate.wszTitleName, 40);
        for (int i=0; i<40 && m_Certificate.wszTitleName[i] != 0; i++)
			m_szAsciiTitle[i] = static_cast<uint8_t>(m_Certificate.wszTitleName[i]);



        // write section headers / section names
        {
            m_szSectionName = new char[m_Header.dwSections][9];

            m_SectionHeader = new SectionHeader[m_Header.dwSections];

            uint32_t SectionCursor = RoundUp(m_Header.dwSizeofHeaders, 0x1000);

            // head/tail reference count write buffer
            uint16_t *htrc = reinterpret_cast<uint16_t*>(szBuffer + m_Header.dwSections*sizeof(*m_SectionHeader));

            // section write buffer
            char *secn = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(htrc) + (m_Header.dwSections+1)*2);

            // head/tail reference count write cursor
            uint32_t hwc_htrc = hwc + m_Header.dwSections*static_cast<uint32_t>(sizeof(*m_SectionHeader));

            // section write cursor
            uint32_t hwc_secn = hwc_htrc + (m_Header.dwSections+1)*2;

            std::cout << "Xbe::Xbe: Generating Section Headers...\n";

            for(uint32_t v=0;v<m_Header.dwSections;v++)
            {
                std::cout << "Xbe::Xbe: Generating Section Header " << std::setfill('0') << std::hex << std::setw(4) << v << "...";

                uint32_t characteristics = x_Exe->m_SectionHeader[v].m_characteristics;

                memset(&m_SectionHeader[v].dwFlags, 0, sizeof(m_SectionHeader->dwFlags));

                if(characteristics & IMAGE_SCN_MEM_WRITE)
                    m_SectionHeader[v].dwFlags.bWritable =  true;

                if( (characteristics & IMAGE_SCN_MEM_EXECUTE) || (characteristics & IMAGE_SCN_CNT_CODE) )
                    m_SectionHeader[v].dwFlags.bExecutable = true;

                m_SectionHeader[v].dwFlags.bPreload = true;
                m_SectionHeader[v].dwVirtualAddr = x_Exe->m_SectionHeader[v].m_virtual_addr + m_Header.dwPeBaseAddr;

                if(v < m_Header.dwSections-1)
                    m_SectionHeader[v].dwVirtualSize = x_Exe->m_SectionHeader[v+1].m_virtual_addr - x_Exe->m_SectionHeader[v].m_virtual_addr;
                else
                    m_SectionHeader[v].dwVirtualSize = RoundUp(x_Exe->m_SectionHeader[v].m_virtual_size, 4);

                m_SectionHeader[v].dwRawAddr = SectionCursor;

                // calculate sizeof_raw by locating the last non-zero value in the raw section data
                {
                    uint32_t r = x_Exe->m_SectionHeader[v].m_sizeof_raw;
                    if (r > 0) r--;

                    while(r > 0)
                    {
                        if(x_Exe->m_bzSection[v][r--] != 0)
                            break;
                    }

                    // word aligned
                    m_SectionHeader[v].dwSizeofRaw = RoundUp(r+2, 4);
                }

                SectionCursor += RoundUp(m_SectionHeader[v].dwSizeofRaw, 0x1000);

                // head/tail reference count
                {
                    m_SectionHeader[v].dwHeadSharedRefCountAddr = hwc_htrc;
                    htrc[v] = 0;

                    hwc_htrc += 2;

                    m_SectionHeader[v].dwTailSharedRefCountAddr = hwc_htrc;
                    htrc[v+1] = 0;
                }

                // section name
                {
                    uint32_t s = 0;

                    memset(secn, 0, 8);

                    m_SectionHeader[v].dwSectionNameAddr = hwc_secn;
                    while(s < 8 && x_Exe->m_SectionHeader[v].m_name[s] != '\0')
                    {
                        m_szSectionName[v][s] = secn[s] = x_Exe->m_SectionHeader[v].m_name[s];
                        s++;
                    }

                    m_szSectionName[v][s] = '\0';

                    secn += s+1;
                    hwc_secn += s+1;
                }

                m_SectionHeader[v].dwSectionRefCount = 0;

                // write section digest (just zeros)
                memset(m_SectionHeader[v].bzSectionDigest, 0, 20);

                // write section header
                memcpy(szBuffer, &m_SectionHeader[v], sizeof(*m_SectionHeader));

                szBuffer += sizeof(*m_SectionHeader);

                std::cout << "OK\n";
            }

            hwc = hwc_secn;
        }

        // write debug path / debug file names
        {
            *reinterpret_cast<uint16_t*>(szBuffer) = 0x0000;

            szBuffer += 2;
            hwc      += 2;
        }

        // write default "OpenXDK" logo bitmap
        {
            std::cout << "Xbe::Xbe: Generating \"OpenXDK\" Logo Bitmap...";

            uint8_t *RawAddr = GetAddr(m_Header.dwLogoBitmapAddr);

            memset(RawAddr, 0, 100*17);

            memcpy(RawAddr, OpenXDK, dwSizeOfOpenXDK);

            m_Header.dwSizeofLogoBitmap = dwSizeOfOpenXDK;

            std::cout << "OK\n";
        }

        // write sections
        {
            std::cout << "Xbe::Xbe: Generating Sections...\n";

            m_bzSection = new uint8_t*[m_Header.dwSections];

            memset(m_bzSection, 0, m_Header.dwSections);

            for(uint32_t v=0;v<m_Header.dwSections;v++)
            {
                std::cout << "Xbe::Xbe: Generating Section " << std::setfill('0') << std::hex << std::setw(4) << v << "...";

                uint32_t RawSize = m_SectionHeader[v].dwSizeofRaw;

                m_bzSection[v] = new uint8_t[RawSize];

                memcpy(m_bzSection[v], x_Exe->m_bzSection[v], RawSize);

                std::cout << "OK\n";
            }
        }
    }

    std::cout << "Xbe::Xbe: Pass 4 (Finalizing)...\n";

    // pass 4
    {
        m_Header.dwSizeofImage = m_SectionHeader[m_Header.dwSections-1].dwVirtualAddr + m_SectionHeader[m_Header.dwSections-1].dwVirtualSize - m_Header.dwBaseAddr;

        m_Header.dwTLSAddr = 0;

        // relocate to base : 0x00010000
        {
            std::cout << "Xbe::Xbe: Relocating to Base 0x00010000...";

            uint32_t fixCount = 0;

            uint32_t relo_addr = x_Exe->m_OptionalHeader.m_image_data_directory[5].m_virtual_addr;
            uint32_t relo_size = x_Exe->m_OptionalHeader.m_image_data_directory[5].m_size;

            uint32_t dwBaseDiff = m_Header.dwPeBaseAddr - x_Exe->m_OptionalHeader.m_image_base;

            uint8_t *reloc = GetAddr(relo_addr + m_Header.dwPeBaseAddr);

            // relocate, if necessary
            if(reloc != 0)
            {
                uint32_t v = 0;

                // relocate each relocation block
                while(v < relo_size)
                {
                    uint32_t block_addr = *reinterpret_cast<uint32_t*>(&reloc[v+0]);
                    uint32_t block_stop = *reinterpret_cast<uint32_t*>(&reloc[v+4]) + v;

                    v += 8;

                    // relocate each rva
                    while(v < block_stop && v < relo_size)
                    {
                        uint16_t data = *reinterpret_cast<uint16_t*>(&reloc[v]);

                        uint32_t type = (data & 0xF000) >> 12;

                        if(type == 0)
                        {
                            v+=2;
                            break;
                        }

                        // 32-bit field relocation
                        if(type == IMAGE_REL_BASED_HIGHLOW)
                        {
                            fixCount++;

                            uint32_t dwFixAddr = block_addr + (data & 0x0FFF) + m_Header.dwPeBaseAddr;

                            uint8_t *bzModRVA = GetAddr(dwFixAddr);

                            if(bzModRVA != 0)
                                *reinterpret_cast<uint32_t*>(bzModRVA) += dwBaseDiff;
                        }
                        else
                        {
                            SetError("Unsupported relocation type", true);
                            goto cleanup;
                        }

                        v+=2;
                    }
                }
            }

            std::cout << "OK (" << std::dec << fixCount << " Fixups)\n";
        }

        // locate kernel thunk table
        {
            // unfortunately, GCC doesn't populate the IAT entry in the data directory
            // so if the value is 0, then it could mean there are no imports, or it
            // could mean the EXE was compiled by GCC
            uint32_t ktRVA = x_Exe->m_OptionalHeader.m_image_data_directory[12].m_virtual_addr;

            if(ktRVA == 0)
            {
                // lets check to see if there is an import section. if so, look at offset 16
                // for the RVA of the Import Address Table
                uint32_t importRVA = x_Exe->m_OptionalHeader.m_image_data_directory[1].m_virtual_addr;

                if(importRVA != 0)
                {
                    uint8_t *importSection = GetAddr(importRVA + m_Header.dwPeBaseAddr);

                    ktRVA = *reinterpret_cast<uint32_t*>(&importSection[16]);
                }
            }

            uint32_t kt = ktRVA + m_Header.dwPeBaseAddr;

            kt ^= (x_bRetail ? XOR_KT_RETAIL : XOR_KT_DEBUG );

            m_Header.dwKernelImageThunkAddr = kt;
        }
    }