3 * Portable Executable Loader
\r
11 // === PROTOTYPES ===
\r
12 int PE_Install(char **Arguments);
\r
13 tBinary *PE_Load(int fp);
\r
14 tBinary *MZ_Open(int fp);
\r
15 int PE_Relocate(void *Base);
\r
16 int PE_GetSymbol(void *Base, const char *Name, Uint *Ret);
\r
19 MODULE_DEFINE(0, 0x0032, BinPE, PE_Install, NULL, NULL);
\r
20 const char *gsPE_DefaultInterpreter = "/Acess/Libs/ld-acess.so";
\r
21 tBinaryType gPE_Loader = {
\r
23 ('M'|('Z'<<8)), 0xFFFF, // 'MZ'
\r
25 PE_Load, PE_Relocate, PE_GetSymbol
\r
29 int PE_Install(char **Arguments)
\r
31 Binary_RegisterType(&gPE_Loader);
\r
32 return MODULE_ERR_OK;
\r
36 * \brief Loads a PE Binary
\r
38 tBinary *PE_Load(int FP)
\r
43 tPE_DOS_HEADER dosHdr;
\r
44 tPE_IMAGE_HEADERS peHeaders;
\r
45 tPE_SECTION_HEADER *peSections;
\r
46 char namebuf[9] = {0};
\r
51 // Read DOS header and check
\r
52 VFS_Read(FP, sizeof(tPE_DOS_HEADER), &dosHdr);
\r
53 if( dosHdr.Ident != ('M'|('Z'<<8)) ) {
\r
59 VFS_Seek(FP, dosHdr.PeHdrOffs, SEEK_SET);
\r
60 if( VFS_Tell(FP) != dosHdr.PeHdrOffs ) {
\r
65 VFS_Read(FP, sizeof(tPE_IMAGE_HEADERS), &peHeaders);
\r
67 // - Check PE Signature and pass on to the MZ Loader if invalid
\r
68 if( peHeaders.Signature != (('P')|('E'<<8)) ) {
\r
74 // Read Sections (Uses `count` as a temp variable)
\r
75 count = sizeof(tPE_SECTION_HEADER) * peHeaders.FileHeader.SectionCount;
\r
76 peSections = malloc( count );
\r
79 Warning("PE_Load - Unable to allocate `peSections`, 0x%x bytes", count);
\r
83 VFS_Read(FP, count, peSections);
\r
86 iSectCount = 1; // 1st page is headers
\r
87 for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )
\r
89 // Check if the section is loadable
\r
90 // (VA is zero in non-loadable sections)
\r
91 if(peSections[i].RVA + peHeaders.OptHeader.ImageBase == 0) continue;
\r
97 LOG("%i Sections", iSectCount);
\r
99 // Initialise Executable Information
\r
100 ret = malloc(sizeof(tBinary) + sizeof(tBinarySection)*iSectCount);
\r
102 ret->Entry = peHeaders.OptHeader.EntryPoint + peHeaders.OptHeader.ImageBase;
\r
103 ret->Base = peHeaders.OptHeader.ImageBase;
\r
104 ret->Interpreter = gsPE_DefaultInterpreter;
\r
105 ret->NumSections = iSectCount;
\r
107 LOG("Entry=%p, BaseAddress=0x%x\n", ret->Entry, ret->Base);
\r
109 ret->LoadSections[0].Virtual = peHeaders.OptHeader.ImageBase;
\r
110 ret->LoadSections[0].Offset = 0;
\r
111 ret->LoadSections[0].FileSize = 4096;
\r
112 ret->LoadSections[0].MemSize = 4096;
\r
113 ret->LoadSections[0].Flags = 0;
\r
116 j = 1; // Page Index
\r
117 for( i = 0; i < peHeaders.FileHeader.SectionCount; i++ )
\r
119 tBinarySection *sect = &ret->LoadSections[j];
\r
120 iVA = peSections[i].RVA + peHeaders.OptHeader.ImageBase;
\r
122 // Skip non-loadable sections
\r
123 if(iVA == 0) continue;
\r
125 // Create Name Buffer
\r
126 memcpy(namebuf, peSections[i].Name, 8);
\r
127 LOG("Section %i '%s', iVA = %p", i, namebuf, iVA);
\r
131 if(peSections[i].Flags & PE_SECTION_FLAG_MEM_EXECUTE)
\r
132 iFlags |= BIN_SECTFLAG_EXEC;
\r
133 if( !(peSections[i].Flags & PE_SECTION_FLAG_MEM_WRITE) )
\r
134 iFlags |= BIN_SECTFLAG_RO;
\r
136 sect->Virtual = iVA;
\r
137 sect->Offset = peSections[i].RawOffs;
\r
138 sect->FileSize = peSections[i].RawSize;
\r
139 sect->MemSize = peSections[i].VirtualSize;
\r
140 sect->Flags = iFlags;
\r
143 LOG("%i Name:'%s', RVA: 0x%x, Size: 0x%x (0x%x), Ofs: 0x%x, Flags: 0x%x",
\r
146 peSections[i].VirtualSize, peSections[i].RawSize, peSections[i].RawOffs,
\r
147 peSections[i].Flags
\r
151 // Free Executable Memory
\r
160 tBinary *MZ_Open(int FP)
\r
168 int PE_Relocate(void *Base)
\r
170 tPE_DOS_HEADER *dosHdr;
\r
171 tPE_IMAGE_HEADERS *peHeaders;
\r
172 tPE_SECTION_HEADER *peSections;
\r
173 tPE_DATA_DIR *directory;
\r
174 tPE_IMPORT_DIR *impDir;
\r
176 Uint iBase = (Uint)Base;
\r
182 ENTER("pBase", Base);
\r
184 peHeaders = (void*)( iBase + dosHdr->PeHdrOffs );
\r
185 LOG("Prefered Base %p", peHeaders->OptHeader.ImageBase);
\r
186 peSections = (void*)( iBase + sizeof(tPE_IMAGE_HEADERS) );
\r
188 directory = (void*)(peSections[0].RVA + iBase);
\r
190 // === Load Import Tables
\r
191 impDir = (void*)( directory[PE_DIR_IMPORT].RVA + iBase );
\r
192 for( i = 0; impDir[i].DLLName != NULL; i++ )
\r
194 impDir[i].DLLName += iBase;
\r
195 impDir[i].ImportLookupTable += iBase/4;
\r
196 impDir[i].ImportAddressTable += iBase/4;
\r
197 LOG("DLL Required '%s'(0x%x)", impDir[i].DLLName, impDir[i].DLLName);
\r
199 libPath = FindLibrary(impDir[i].DLLName);
\r
200 if(libPath == NULL)
\r
202 Warning("PE_Relocate - Unable to find library '%s'");
\r
206 LOG("DLL Path = '%s'", libPath);
\r
207 hLibrary = DynLib_Load(libPath, 0);
\r
211 for(i=0;i<PE_DIR_LAST;i++)
\r
212 LOG("directory[%i] = {RVA=0x%x,Size=0x%x}", i, directory[i].RVA, directory[i].Size);
\r
218 int PE_GetSymbol(void *Base, const char *Name, Uint *Ret)
\r