source: trunk/src/peldr/pe.cpp@ 4807

Last change on this file since 4807 was 4501, checked in by sandervl, 25 years ago

build special VIO version of PE loader

File size: 11.4 KB
Line 
1/* $Id: pe.cpp,v 1.24 2000-10-20 11:45:25 sandervl Exp $ */
2
3/*
4 * PELDR main exe loader code
5 *
6 * Copyright 1998-2000 Sander van Leeuwen (sandervl@xs4all.nl)
7 *
8 * Command line options:
9 * /OPT:[x1=y,x2=z,..]
10 * x = CURDIR -> set current directory to y
11 * (not other options available at this time)
12 *
13 * Project Odin Software License can be found in LICENSE.TXT
14 *
15 */
16#define INCL_DOSFILEMGR /* File Manager values */
17#define INCL_DOSERRORS /* DOS Error values */
18#define INCL_DOSPROCESS /* DOS Process values */
19#define INCL_DOSMISC /* DOS Miscellanous values */
20#define INCL_DOSMODULEMGR
21#define INCL_WIN
22#include <os2.h>
23#include <bseord.h>
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <string.h>
28#include <assert.h>
29#include <win32type.h>
30#include <misc.h>
31#include <wprocess.h>
32#include <win\peexe.h>
33#include "pe.h"
34
35char INFO_BANNER[] = "Usage: PE winexe commandline";
36char szErrorTitle[] = "Odin";
37char szLoadErrorMsg[] = "Can't load executable";
38char szFileErrorMsg[] = "File IO error";
39char szPEErrorMsg[] = "Not a valid win32 exe. (perhaps 16 bits windows)";
40char szCPUErrorMsg[] = "Executable doesn't run on x86 machines";
41char szExeErrorMsg[] = "File isn't an executable";
42char szInteralErrorMsg[]= "Internal Error";
43char szNoKernel32Msg[] = "Can't load/find kernel32.dll (rc=%d)";
44char szDosInfoBlocks[] = "DosInfoBlocks failed!";
45
46char fullpath[CCHMAXPATH];
47
48typedef HAB (* APIENTRY WININITIALIZEPROC)(ULONG flOptions);
49typedef BOOL (* APIENTRY WINTERMINATEPROC)(HAB hab);
50typedef HMQ (* APIENTRY WINCREATEMSGQUEUEPROC) (HAB hab, LONG cmsg);
51typedef BOOL (* APIENTRY WINDESTROYMSGQUEUEPROC) (HMQ hmq);
52typedef ULONG (* APIENTRY WINMESSAGEBOXPROC) (HWND hwndParent,
53 HWND hwndOwner,
54 PCSZ pszText,
55 PCSZ pszCaption,
56 ULONG idWindow,
57 ULONG flStyle);
58typedef void (* KRNL32EXCEPTPROC) (void *exceptframe);
59
60WININITIALIZEPROC MyWinInitialize = 0;
61WINTERMINATEPROC MyWinTerminate = 0;
62WINCREATEMSGQUEUEPROC MyWinCreateMsgQueue = 0;
63WINDESTROYMSGQUEUEPROC MyWinDestroyMsgQueue = 0;
64WINMESSAGEBOXPROC MyWinMessageBox = 0;
65KRNL32EXCEPTPROC Krnl32SetExceptionHandler = 0;
66KRNL32EXCEPTPROC Krnl32UnsetExceptionHandler = 0;
67
68//should be the same as in ..\kernel32\winexepeldr.h
69typedef BOOL (* WIN32API WIN32CTOR)(char *, char *, char *, ULONG, BOOL, BOOL);
70
71WIN32CTOR CreateWin32Exe = 0;
72ULONG reservedMemory = 0;
73BOOL fConsoleApp = FALSE;
74
75void AllocateExeMem(char *filename);
76
77//******************************************************************************
78//******************************************************************************
79int main(int argc, char *argv[])
80{
81 HAB hab = 0; /* PM anchor block handle */
82 HMQ hmq = 0; /* Message queue handle */
83 char exeName[CCHMAXPATH];
84 char fullpath[CCHMAXPATH];
85 APIRET rc;
86 HMODULE hmodPMWin = 0, hmodKernel32 = 0;
87 PTIB ptib;
88 PPIB ppib;
89 char *cmdline, *win32cmdline, *peoptions, *newcmdline;
90 BOOL fQuote = FALSE, fVioConsole;
91 int nrTries = 1;
92
93 if(argc >= 2) {
94 if(DosGetInfoBlocks(&ptib, &ppib) == 0) {
95tryagain:
96 cmdline = ppib->pib_pchcmd;
97 cmdline += strlen(cmdline)+1; //skip pe.exe
98 peoptions = strstr(cmdline, "/OPT:[");
99 if(peoptions) {
100 newcmdline = strchr(peoptions, ']');
101 if(newcmdline) {
102 cmdline = newcmdline+1;
103 }
104 else DebugInt3(); //should not happen!
105 }
106 while(*cmdline == ' ') cmdline++; //skip leading space
107 if(*cmdline == '"') {
108 cmdline++;
109 fQuote = TRUE;
110 }
111 win32cmdline = cmdline;
112
113 strncpy(exeName, cmdline, sizeof(exeName)-1);
114 exeName[sizeof(exeName)-1] = 0;
115 char *p = exeName;
116 if(fQuote) {
117 while(*p != '"' && *p != 0) p++;
118 }
119 else {
120 for(int i=0;i<nrTries;i++) {
121 while(*p != ' ' && *p != 0) p++;
122 if(*p == 0) break;
123 if(i != nrTries-1) {
124 while(*p == ' ' && *p != 0) p++;
125 }
126 }
127 }
128 *p = 0;
129 strupr(exeName);
130 cmdline = strstr(exeName, ".EXE");
131 if(cmdline) {
132 cmdline[4] = 0;
133 win32cmdline += ((ULONG)cmdline - (ULONG)exeName) + 4;
134 }
135 else {
136 win32cmdline += strlen(exeName);
137 if(strstr(exeName, ".") == NULL) {
138 strcat(exeName, ".EXE");
139 }
140 }
141 if(fQuote) win32cmdline++;
142 while(*win32cmdline == ' ') win32cmdline++; //skip spaces
143 if(*win32cmdline == '"') {
144 win32cmdline++;
145 cmdline = win32cmdline + strlen(win32cmdline) - 1;
146 while(*cmdline == ' ') cmdline--;
147 if(*cmdline == '"') {
148 *cmdline = 0;
149 }
150 }
151 cmdline = exeName + strlen(exeName) - 1;
152 while(*cmdline == ' ') cmdline--;
153 cmdline[1] = 0;
154 if(DosQueryPathInfo(exeName, FIL_QUERYFULLNAME, (PVOID)fullpath, sizeof(fullpath)) == 0) {
155 strcpy(exeName, fullpath);
156 }
157 FILESTATUS3 fstat3;
158 if(DosQueryPathInfo(exeName, FIL_STANDARD, (PVOID)&fstat3, sizeof(fstat3)))
159 {
160 nrTries++;
161 if(*win32cmdline != NULL && !fQuote) {
162 goto tryagain;
163 }
164 }
165 }
166 else {//should never happen!
167filenotfound:
168 DebugInt3();
169 rc = DosLoadModule(exeName, sizeof(exeName), "PMWIN.DLL", &hmodPMWin);
170 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32MESSAGEBOX, NULL, (PFN *)&MyWinMessageBox);
171 MyWinMessageBox(HWND_DESKTOP, NULL, szDosInfoBlocks, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
172 goto fail;
173 }
174 AllocateExeMem(exeName);
175 }
176
177#ifdef COMMAND_LINE_VERSION
178 if(DosGetInfoBlocks(&ptib, &ppib) == 0) {
179 //switch process type to PM so the command line app can create PM
180 //windows
181 ppib->pib_ultype = 3;
182 }
183#endif
184
185 rc = DosLoadModule(exeName, sizeof(exeName), "PMWIN.DLL", &hmodPMWin);
186 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32INITIALIZE, NULL, (PFN *)&MyWinInitialize);
187 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32TERMINATE, NULL, (PFN *)&MyWinTerminate);
188 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32CREATEMSGQUEUE, NULL, (PFN *)&MyWinCreateMsgQueue);
189 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32DESTROYMSGQUEUE, NULL, (PFN *)&MyWinDestroyMsgQueue);
190 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32MESSAGEBOX, NULL, (PFN *)&MyWinMessageBox);
191
192 if ((hab = MyWinInitialize(0)) == 0L) /* Initialize PM */
193 goto fail;
194
195 hmq = MyWinCreateMsgQueue(hab, 0);
196
197 if(argc < 2) {
198 MyWinMessageBox(HWND_DESKTOP, NULL, INFO_BANNER, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
199 goto fail;
200 }
201
202 rc = DosLoadModule(exeName, sizeof(exeName), "KERNEL32.DLL", &hmodKernel32);
203 if(rc) {
204 sprintf(exeName, szNoKernel32Msg, rc);
205 MyWinMessageBox(HWND_DESKTOP, NULL, exeName, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
206 goto fail;
207 }
208 rc = DosQueryProcAddr(hmodKernel32, 0, "_CreateWin32PeLdrExe@24", (PFN *)&CreateWin32Exe);
209
210#ifdef COMMAND_LINE_VERSION
211 fVioConsole = TRUE;
212#else
213 fVioConsole = FALSE;
214#endif
215 if(CreateWin32Exe(exeName, win32cmdline, peoptions, reservedMemory, fConsoleApp, fVioConsole) == FALSE) {
216 goto fail;
217 }
218
219 if(hmq) MyWinDestroyMsgQueue( hmq ); /* Tidy up... */
220 MyWinTerminate( hab ); /* Terminate the application */
221
222 DosFreeModule(hmodPMWin);
223 DosFreeModule(hmodKernel32);
224 return 0;
225
226fail:
227 if(hmq) MyWinDestroyMsgQueue( hmq ); /* Tidy up... */
228 if(hab) MyWinTerminate( hab ); /* Terminate the application */
229
230 if(hmodPMWin) DosFreeModule(hmodPMWin);
231 if(hmodKernel32) DosFreeModule(hmodKernel32);
232 return(1);
233}
234//******************************************************************************
235//SvL: Reserve memory for win32 exes without fixups
236// This is done before any Odin or PMWIN dll is loaded, so we'll get
237// a very low virtual address. (which is exactly what we want)
238//******************************************************************************
239void AllocateExeMem(char *filename)
240{
241 HFILE dllfile = 0;
242 char szFileName[CCHMAXPATH], *tmp;
243 char szResult[CCHMAXPATH];
244 ULONG action, ulRead, signature;
245 APIRET rc;
246 IMAGE_DOS_HEADER doshdr;
247 IMAGE_OPTIONAL_HEADER oh;
248 IMAGE_FILE_HEADER fh;
249 ULONG address = 0;
250 ULONG *memallocs;
251 ULONG alloccnt = 0;
252 ULONG diff, i, baseAddress;
253 ULONG ulSysinfo, flAllocMem = 0;
254
255 strcpy(szFileName, filename);
256
257 rc = DosOpen(szFileName, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
258 if(rc != 0) {
259 if(!strstr(szFileName, ".EXE")) {
260 strcat(szFileName,".EXE");
261 }
262 }
263 else DosClose(dllfile);
264
265 rc = DosOpen(szFileName, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
266 if(rc) {
267 if(DosSearchPath(SEARCH_IGNORENETERRS|SEARCH_ENVIRONMENT, "PATH",
268 szFileName, szResult, sizeof(szResult)) != 0) {
269 goto end; //oops
270 }
271 rc = DosOpen(szResult, &dllfile, &action, 0, FILE_READONLY, OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW, OPEN_SHARE_DENYNONE|OPEN_ACCESS_READONLY, NULL);
272 if(rc) {
273 goto end; //oops
274 }
275 }
276
277 //read dos header
278 if(DosRead(dllfile, (LPVOID)&doshdr, sizeof(doshdr), &ulRead)) {
279 goto end;
280 }
281 if(DosSetFilePtr(dllfile, doshdr.e_lfanew, FILE_BEGIN, &ulRead)) {
282 goto end;
283 }
284 //read signature dword
285 if(DosRead(dllfile, (LPVOID)&signature, sizeof(signature), &ulRead)) {
286 goto end;
287 }
288 //read pe header
289 if(DosRead(dllfile, (LPVOID)&fh, sizeof(fh), &ulRead)) {
290 goto end;
291 }
292 //read optional header
293 if(DosRead(dllfile, (LPVOID)&oh, sizeof(oh), &ulRead)) {
294 goto end;
295 }
296 if(doshdr.e_magic != IMAGE_DOS_SIGNATURE || signature != IMAGE_NT_SIGNATURE) {
297 goto end;
298 }
299 fConsoleApp = (oh.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
300
301 // check for high memory support
302 rc = DosQuerySysInfo(QSV_VIRTUALADDRESSLIMIT, QSV_VIRTUALADDRESSLIMIT, &ulSysinfo, sizeof(ulSysinfo));
303 if (rc == 0 && ulSysinfo > 512) //VirtualAddresslimit is in MB
304 {
305 flAllocMem = PAG_ANY; // high memory support. Let's use it!
306 }
307
308 //Reserve enough space to store 4096 pointers to 1MB memory chunks
309 memallocs = (ULONG *)alloca(4096*sizeof(ULONG *));
310 if(memallocs == NULL) {
311 goto end; //oops
312 }
313
314 if(oh.ImageBase < 512*1024*1024) {
315 flAllocMem = 0;
316 }
317 else {
318 if(flAllocMem == 0) {
319 goto end; //no support for > 512 MB
320 }
321 }
322 while(TRUE) {
323 rc = DosAllocMem((PPVOID)&address, FALLOC_SIZE, PAG_READ | flAllocMem);
324 if(rc) break;
325
326 if(address + FALLOC_SIZE >= oh.ImageBase) {
327 if(address > oh.ImageBase) {//we've passed it!
328 DosFreeMem((PVOID)address);
329 break;
330 }
331 //found the right address
332 DosFreeMem((PVOID)address);
333
334 diff = oh.ImageBase - address;
335 if(diff) {
336 rc = DosAllocMem((PPVOID)&address, diff, PAG_READ | flAllocMem);
337 if(rc) break;
338 }
339 rc = DosAllocMem((PPVOID)&baseAddress, oh.SizeOfImage, PAG_READ | PAG_WRITE | flAllocMem);
340 if(rc) break;
341
342 if(diff) DosFreeMem((PVOID)address);
343
344 reservedMemory = baseAddress;
345 break;
346 }
347 memallocs[alloccnt++] = address;
348 }
349 for(i=0;i<alloccnt;i++) {
350 DosFreeMem((PVOID)memallocs[i]);
351 }
352end:
353 if(dllfile) DosClose(dllfile);
354 return;
355}
356//******************************************************************************
357//******************************************************************************
Note: See TracBrowser for help on using the repository browser.