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