1 #include "xbe.h"
2 #include "../../support/ordinals.h"
3 
4 #define XBE_XBOXKRNL_BASEADDRESS 0x80000000
5 
6 namespace REDasm {
7 
LOADER_PLUGIN_TEST(XbeLoader,XbeImageHeader)8 LOADER_PLUGIN_TEST(XbeLoader, XbeImageHeader)
9 {
10     if((header->Magic != XBE_MAGIC_NUMBER) || !header->SectionHeader || !header->NumberOfSections)
11         return false;
12 
13     return true;
14 }
15 
XbeLoader(AbstractBuffer * buffer)16 XbeLoader::XbeLoader(AbstractBuffer *buffer): LoaderPluginT<XbeImageHeader>(buffer) { }
assembler() const17 std::string XbeLoader::assembler() const { return "x86_32"; }
18 
load()19 void XbeLoader::load()
20 {
21     this->loadSections(this->memoryoffset<XbeSectionHeader>(m_header->SectionHeader));
22     address_t entrypoint = 0;
23 
24     if(!this->decodeEP(m_header->EntryPoint, entrypoint))
25     {
26         REDasm::log("Cannot decode Entry Point");
27         return;
28     }
29 
30     if(!this->loadXBoxKrnl())
31     {
32         REDasm::log("Cannot load XBoxKrnl Imports");
33         return;
34     }
35 
36     m_document->entry(entrypoint);
37     this->displayXbeInfo();
38 }
39 
displayXbeInfo()40 void XbeLoader::displayXbeInfo()
41 {
42     auto* certificate = this->memoryoffset<XbeCertificate>(m_header->CertificateAddress);
43     std::string title = REDasm::wtoa(&certificate->TitleName, XBE_TITLENAME_SIZE);
44 
45     if(!title.empty())
46         REDasm::log("Game Title: " + REDasm::quoted(title));
47 
48     std::string s;
49 
50     if(certificate->GameRegion & XBE_GAME_REGION_RESTOFWORLD)
51         s += "ALL";
52     else
53     {
54         if(certificate->GameRegion & XBE_GAME_REGION_JAPAN)
55             s += s.empty() ? "JAPAN" : ", JAPAN";
56 
57         if(certificate->GameRegion & XBE_GAME_REGION_NA)
58             s += s.empty() ? "NORTH AMERICA" : ", NORTH AMERICA";
59     }
60 
61     if(certificate->GameRegion & XBE_GAME_REGION_MANUFACTURING)
62         s += s.empty() ? "DEBUG" : ", DEBUG";
63 
64     if(!s.empty())
65         REDasm::log("Allowed Regions: " + s);
66 }
67 
decodeEP(u32 encodedep,address_t & ep)68 bool XbeLoader::decodeEP(u32 encodedep, address_t& ep)
69 {
70     ep = encodedep ^ XBE_ENTRYPOINT_XOR_RETAIL;
71     Segment* segment = m_document->segment(ep);
72 
73     if(!segment)
74     {
75         ep = encodedep ^ XBE_ENTRYPOINT_XOR_DEBUG;
76         segment = m_document->segment(ep);
77 
78         if(segment)
79             REDasm::log("Executable Type: DEBUG");
80     }
81     else
82         REDasm::log("Executable Type: RETAIL");
83 
84     return segment != nullptr;
85 }
86 
decodeKernel(u32 encodedthunk,u32 & thunk)87 bool XbeLoader::decodeKernel(u32 encodedthunk, u32 &thunk)
88 {
89     thunk = encodedthunk ^ XBE_KERNEL_XOR_RETAIL;
90     Segment* segment = m_document->segment(thunk);
91 
92     if(!segment)
93     {
94         thunk = encodedthunk ^ XBE_KERNEL_XOR_DEBUG;
95         segment = m_document->segment(thunk);
96     }
97 
98     return segment != nullptr;
99 }
100 
loadSections(XbeSectionHeader * sectionhdr)101 void XbeLoader::loadSections(XbeSectionHeader *sectionhdr)
102 {
103     for(u32 i = 0; i < m_header->NumberOfSections; i++)
104     {
105         std::string sectname = this->memoryoffset<const char>(sectionhdr[i].SectionName);
106         SegmentType secttype = SegmentType::None;
107 
108         if(sectionhdr[i].Flags.Executable)
109         {
110             if((sectname[0] == '.') && (sectname.find("data") != std::string::npos))
111                 secttype = SegmentType::Data;
112             else
113                 secttype = SegmentType::Code;
114         }
115         else
116             secttype = SegmentType::Data;
117 
118         if(!sectionhdr[i].RawSize)
119             secttype = SegmentType::Bss;
120 
121         m_document->segment(sectname, sectionhdr[i].RawAddress, sectionhdr[i].VirtualAddress, sectionhdr[i].RawSize, secttype);
122     }
123 
124     m_document->segment("XBOXKRNL", 0, XBE_XBOXKRNL_BASEADDRESS, 0x10000, SegmentType::Bss);
125 }
126 
loadXBoxKrnl()127 bool XbeLoader::loadXBoxKrnl()
128 {
129     OrdinalsMap ordinals;
130     REDasm::loadordinals(REDasm::makeLoaderPath("xbe", "xboxkrnl.json"), ordinals);
131     u32 kernelimagethunk;
132 
133     if(!this->decodeKernel(m_header->KernelImageThunk, kernelimagethunk))
134         return false;
135 
136     offset_location thunkoffset = this->offset(kernelimagethunk);
137 
138     if(!thunkoffset.valid)
139         return false;
140 
141     u32* pthunk = this->pointer<u32>(thunkoffset);
142 
143     while(*pthunk)
144     {
145         std::string ordinalname = REDasm::ordinal(ordinals, *pthunk ^ XBE_ORDINAL_FLAG, "XBoxKrnl!");
146         m_document->lock(*pthunk, ordinalname, SymbolType::Import);
147         pthunk++;
148     }
149 
150     return true;
151 }
152 
153 } // namespace REDasm
154