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

Last change on this file since 8706 was 7991, checked in by sandervl, 24 years ago

bugfix for errors

File size: 14.5 KB
Line 
1/* $Id: pe.cpp,v 1.33 2002-02-23 10:48:19 sandervl Exp $ */
2
3/*
4 * PELDR main exe loader code
5 *
6 * Copyright 1998-2001 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_DOSSESMGR
22#define INCL_WIN
23#include <os2.h>
24#include <bseord.h>
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include <string.h>
29#include <assert.h>
30#include <win32type.h>
31#include <misc.h>
32#include <wprocess.h>
33#include <win\peexe.h>
34#include "pe.h"
35
36char INFO_BANNER[] = "Usage: PE winexe commandline";
37char szErrorTitle[] = "Odin";
38char szLoadErrorMsg[] = "Can't load executable";
39char szFileNotFound[] = "File not found.";
40char szFileErrorMsg[] = "File IO error";
41char szPEErrorMsg[] = "Not a valid win32 exe. (perhaps 16 bits windows)";
42char szCPUErrorMsg[] = "Executable doesn't run on x86 machines";
43char szExeErrorMsg[] = "File isn't an executable";
44char szInteralErrorMsg[]= "Internal Error";
45char szNoKernel32Msg[] = "Can't load/find kernel32.dll (rc=%d, module %s)";
46char szDosInfoBlocks[] = "DosInfoBlocks failed!";
47char szErrDosStartSession[] = "Failed to start win16 session (rc=%d)";
48
49char fullpath[CCHMAXPATH];
50
51typedef HAB (* APIENTRY WININITIALIZEPROC)(ULONG flOptions);
52typedef BOOL (* APIENTRY WINTERMINATEPROC)(HAB hab);
53typedef HMQ (* APIENTRY WINCREATEMSGQUEUEPROC) (HAB hab, LONG cmsg);
54typedef BOOL (* APIENTRY WINDESTROYMSGQUEUEPROC) (HMQ hmq);
55typedef ULONG (* APIENTRY WINMESSAGEBOXPROC) (HWND hwndParent,
56 HWND hwndOwner,
57 PCSZ pszText,
58 PCSZ pszCaption,
59 ULONG idWindow,
60 ULONG flStyle);
61typedef void (* KRNL32EXCEPTPROC) (void *exceptframe);
62
63WININITIALIZEPROC MyWinInitialize = 0;
64WINTERMINATEPROC MyWinTerminate = 0;
65WINCREATEMSGQUEUEPROC MyWinCreateMsgQueue = 0;
66WINDESTROYMSGQUEUEPROC MyWinDestroyMsgQueue = 0;
67WINMESSAGEBOXPROC MyWinMessageBox = 0;
68KRNL32EXCEPTPROC Krnl32SetExceptionHandler = 0;
69KRNL32EXCEPTPROC Krnl32UnsetExceptionHandler = 0;
70
71//should be the same as in ..\kernel32\winexepeldr.h
72typedef BOOL (* WIN32API WIN32CTOR)(char *, char *, char *, ULONG, BOOL, BOOL);
73
74WIN32CTOR CreateWin32Exe = 0;
75ULONG reservedMemory = 0;
76BOOL fConsoleApp = FALSE;
77
78BOOL AllocateExeMem(char *filename, BOOL *fNEExe);
79
80//******************************************************************************
81//******************************************************************************
82int main(int argc, char *argv[])
83{
84 HAB hab = 0; /* PM anchor block handle */
85 HMQ hmq = 0; /* Message queue handle */
86 char exeName[CCHMAXPATH];
87 char fullpath[CCHMAXPATH];
88 char errorMod[CCHMAXPATH];
89 char *pszErrorMsg = NULL;
90 APIRET rc;
91 HMODULE hmodPMWin = 0, hmodKernel32 = 0;
92 PTIB ptib;
93 PPIB ppib;
94 char *cmdline, *win32cmdline, *peoptions, *newcmdline;
95 BOOL fQuote = FALSE, fVioConsole, fIsNEExe, fEndOfCmdLine = FALSE;
96 int nrTries = 1;
97
98 if(argc >= 2) {
99 if(DosGetInfoBlocks(&ptib, &ppib) == 0) {
100tryagain:
101 cmdline = ppib->pib_pchcmd;
102 cmdline += strlen(cmdline)+1; //skip pe.exe
103 peoptions = strstr(cmdline, "/OPT:[");
104 if(peoptions) {
105 newcmdline = strchr(peoptions, ']');
106 if(newcmdline) {
107 cmdline = newcmdline+1;
108 }
109#ifdef DEBUG
110 else _interrupt(3); //should not happen!
111#endif
112 }
113 while(*cmdline == ' ') cmdline++; //skip leading space
114 if(*cmdline == '"') {
115 cmdline++;
116 fQuote = TRUE;
117 }
118 win32cmdline = cmdline;
119
120 strncpy(exeName, cmdline, sizeof(exeName)-1);
121 exeName[sizeof(exeName)-1] = 0;
122 char *p = exeName;
123 if(fQuote) {
124 while(*p != '"' && *p != 0) p++;
125 }
126 else {
127 for(int i=0;i<nrTries;i++) {
128 while(*p != ' ' && *p != 0) p++;
129 if(*p == 0) break;
130 if(i != nrTries-1) {
131 while(*p == ' ' && *p != 0) p++;
132 }
133 }
134 if(nrTries > 1 && *p == 0) {
135 fEndOfCmdLine = TRUE;
136 }
137 }
138 *p = 0;
139 strupr(exeName);
140 cmdline = strstr(exeName, ".EXE");
141 if(cmdline) {
142 cmdline[4] = 0;
143 win32cmdline += ((ULONG)cmdline - (ULONG)exeName) + 4;
144 }
145 else {
146 win32cmdline += strlen(exeName);
147 if(strstr(exeName, ".") == NULL) {
148 strcat(exeName, ".EXE");
149 }
150 }
151 if(fQuote) win32cmdline++;
152 while(*win32cmdline == ' ') win32cmdline++; //skip spaces
153
154 cmdline = exeName + strlen(exeName) - 1;
155 while(*cmdline == ' ') cmdline--;
156 cmdline[1] = 0;
157
158 char drive[_MAX_DRIVE];
159 char dir[_MAX_DIR];
160 char fname[_MAX_FNAME];
161 char ext[_MAX_EXT];
162 char exeShortName[_MAX_FNAME+_MAX_EXT];
163 _splitpath(exeName, drive, dir, fname, ext);
164
165 strcpy(fullpath, drive);
166 strcat(fullpath, dir);
167
168 strcpy(exeShortName, fname);
169 strcat(exeShortName, ext);
170
171 if ( strlen(fullpath) == 0 )
172 {
173 char newExeName[CCHMAXPATH];
174
175 if(DosSearchPath( SEARCH_CUR_DIRECTORY | SEARCH_ENVIRONMENT | SEARCH_IGNORENETERRS
176 , "WINDOWSPATH" /* environment value */
177 , exeShortName /* Name of file to look for */
178 , newExeName /* Result of the search */
179 , sizeof(newExeName) /* Length of search buffer */
180 ) == NO_ERROR)
181 {
182 strcpy(exeName, newExeName);
183 }
184 }
185
186 FILESTATUS3 fstat3;
187 if(DosQueryPathInfo(exeName, FIL_STANDARD, (PVOID)&fstat3, sizeof(fstat3)))
188 {
189 nrTries++;
190 if(fEndOfCmdLine) {
191 pszErrorMsg = szFileNotFound;
192 goto failerror;
193 }
194
195 if(*win32cmdline != NULL && !fQuote) {
196 goto tryagain;
197 }
198 }
199 }
200 else {//should never happen!
201 pszErrorMsg = szDosInfoBlocks;
202 goto failerror;
203 }
204 AllocateExeMem(exeName, &fIsNEExe);
205 if(fIsNEExe) {
206 STARTDATA sdata = {0};
207 ULONG idSession;
208 PID pid;
209
210 sdata.Length = sizeof(sdata);
211 sdata.PgmName = "w16odin.exe";
212 strcpy(fullpath, exeName);
213 strcat(fullpath, " ");
214 strcat(fullpath, win32cmdline);
215 sdata.PgmInputs = fullpath;
216 sdata.FgBg = SSF_FGBG_FORE;
217 sdata.SessionType = SSF_TYPE_WINDOWEDVDM;
218 rc = DosStartSession(&sdata, &idSession, &pid);
219 if(rc) {
220 sprintf(fullpath, szErrDosStartSession, rc);
221 pszErrorMsg = fullpath;
222 goto failerror;
223 }
224 return 0;
225 }
226 }
227
228#ifdef COMMAND_LINE_VERSION
229 if(DosGetInfoBlocks(&ptib, &ppib) == 0) {
230 //switch process type to PM so the command line app can create PM
231 //windows
232 ppib->pib_ultype = 3;
233 }
234#endif
235
236 rc = DosLoadModule(exeName, sizeof(exeName), "PMWIN.DLL", &hmodPMWin);
237 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32INITIALIZE, NULL, (PFN *)&MyWinInitialize);
238 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32TERMINATE, NULL, (PFN *)&MyWinTerminate);
239 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32CREATEMSGQUEUE, NULL, (PFN *)&MyWinCreateMsgQueue);
240 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32DESTROYMSGQUEUE, NULL, (PFN *)&MyWinDestroyMsgQueue);
241 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32MESSAGEBOX, NULL, (PFN *)&MyWinMessageBox);
242
243 if ((hab = MyWinInitialize(0)) == 0L) /* Initialize PM */
244 goto fail;
245
246 hmq = MyWinCreateMsgQueue(hab, 0);
247
248 if(argc < 2) {
249 MyWinMessageBox(HWND_DESKTOP, NULL, INFO_BANNER, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
250 goto fail;
251 }
252
253 errorMod[0] = 0;
254 rc = DosLoadModule(errorMod, sizeof(errorMod), "KERNEL32.DLL", &hmodKernel32);
255 if(rc) {
256 sprintf(fullpath, szNoKernel32Msg, rc, errorMod);
257 MyWinMessageBox(HWND_DESKTOP, NULL, fullpath, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
258 goto fail;
259 }
260 rc = DosQueryProcAddr(hmodKernel32, 0, "_CreateWin32PeLdrExe@24", (PFN *)&CreateWin32Exe);
261
262#ifdef COMMAND_LINE_VERSION
263 fVioConsole = TRUE;
264#else
265 fVioConsole = FALSE;
266#endif
267 if(CreateWin32Exe(exeName, win32cmdline, peoptions, reservedMemory, fConsoleApp, fVioConsole) == FALSE) {
268 goto fail;
269 }
270
271 if(hmq) MyWinDestroyMsgQueue( hmq ); /* Tidy up... */
272 MyWinTerminate( hab ); /* Terminate the application */
273
274 DosFreeModule(hmodPMWin);
275 DosFreeModule(hmodKernel32);
276 return 0;
277
278fail:
279 if(hmq) MyWinDestroyMsgQueue( hmq ); /* Tidy up... */
280 if(hab) MyWinTerminate( hab ); /* Terminate the application */
281
282 if(hmodPMWin) DosFreeModule(hmodPMWin);
283 if(hmodKernel32) DosFreeModule(hmodKernel32);
284 return(1);
285
286failerror:
287 rc = DosLoadModule(exeName, sizeof(exeName), "PMWIN.DLL", &hmodPMWin);
288 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32INITIALIZE, NULL, (PFN *)&MyWinInitialize);
289 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32TERMINATE, NULL, (PFN *)&MyWinTerminate);
290 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32CREATEMSGQUEUE, NULL, (PFN *)&MyWinCreateMsgQueue);
291 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32DESTROYMSGQUEUE, NULL, (PFN *)&MyWinDestroyMsgQueue);
292 rc = DosQueryProcAddr(hmodPMWin, ORD_WIN32MESSAGEBOX, NULL, (PFN *)&MyWinMessageBox);
293 if(rc == 0) {
294 if ((hab = MyWinInitialize(0)) == 0L) /* Initialize PM */
295 goto fail;
296
297 hmq = MyWinCreateMsgQueue(hab, 0);
298
299 MyWinMessageBox(HWND_DESKTOP, NULL, pszErrorMsg, szErrorTitle, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
300 }
301 if(hmq) MyWinDestroyMsgQueue( hmq ); /* Tidy up... */
302 if(hab) MyWinTerminate( hab ); /* Terminate the application */
303 if(hmodPMWin) DosFreeModule(hmodPMWin);
304 return 1;
305}
306//******************************************************************************
307//SvL: Reserve memory for win32 exes without fixups
308// This is done before any Odin or PMWIN dll is loaded, so we'll get
309// a very low virtual address. (which is exactly what we want)
310//******************************************************************************
311BOOL AllocateExeMem(char *filename, BOOL *fNEExe)
312{
313 HFILE dllfile = 0;
314 char szFileName[CCHMAXPATH], *tmp;
315 char szResult[CCHMAXPATH];
316 ULONG action, ulRead, signature;
317 APIRET rc;
318 IMAGE_DOS_HEADER doshdr;
319 IMAGE_OPTIONAL_HEADER oh;
320 IMAGE_FILE_HEADER fh;
321 ULONG address = 0;
322 ULONG *memallocs;
323 ULONG alloccnt = 0;
324 ULONG diff, i, baseAddress;
325 ULONG ulSysinfo, flAllocMem = 0;
326 BOOL ret = FALSE;
327
328 *fNEExe = FALSE;
329 strcpy(szFileName, filename);
330
331 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);
332 if(rc != 0) {
333 if(!strstr(szFileName, ".EXE")) {
334 strcat(szFileName,".EXE");
335 }
336 }
337 else DosClose(dllfile);
338
339 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);
340 if(rc) {
341 if(DosSearchPath(SEARCH_IGNORENETERRS|SEARCH_ENVIRONMENT, "PATH",
342 szFileName, szResult, sizeof(szResult)) != 0) {
343 goto end; //oops
344 }
345 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);
346 if(rc) {
347 goto end; //oops
348 }
349 }
350
351 //read dos header
352 if(DosRead(dllfile, (LPVOID)&doshdr, sizeof(doshdr), &ulRead)) {
353 goto end;
354 }
355 if(DosSetFilePtr(dllfile, doshdr.e_lfanew, FILE_BEGIN, &ulRead)) {
356 goto end;
357 }
358 //read signature dword
359 if(DosRead(dllfile, (LPVOID)&signature, sizeof(signature), &ulRead)) {
360 goto end;
361 }
362 //read pe header
363 if(DosRead(dllfile, (LPVOID)&fh, sizeof(fh), &ulRead)) {
364 goto end;
365 }
366 //read optional header
367 if(DosRead(dllfile, (LPVOID)&oh, sizeof(oh), &ulRead)) {
368 goto end;
369 }
370 if(doshdr.e_magic != IMAGE_DOS_SIGNATURE || signature != IMAGE_NT_SIGNATURE) {
371 if(LOWORD(signature) == IMAGE_OS2_SIGNATURE) {
372 *fNEExe = TRUE;
373 }
374 goto end;
375 }
376 fConsoleApp = (oh.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI);
377
378 // check for high memory support
379 rc = DosQuerySysInfo(QSV_VIRTUALADDRESSLIMIT, QSV_VIRTUALADDRESSLIMIT, &ulSysinfo, sizeof(ulSysinfo));
380 if (rc == 0 && ulSysinfo > 512) //VirtualAddresslimit is in MB
381 {
382 flAllocMem = PAG_ANY; // high memory support. Let's use it!
383 }
384
385 //Reserve enough space to store 4096 pointers to 1MB memory chunks
386 memallocs = (ULONG *)alloca(4096*sizeof(ULONG *));
387 if(memallocs == NULL) {
388 goto end; //oops
389 }
390
391 if(oh.ImageBase < 512*1024*1024) {
392 flAllocMem = 0;
393 }
394 else {
395 if(flAllocMem == 0) {
396 goto end; //no support for > 512 MB
397 }
398 }
399 while(TRUE) {
400 rc = DosAllocMem((PPVOID)&address, FALLOC_SIZE, PAG_READ | flAllocMem);
401 if(rc) break;
402
403 if(address + FALLOC_SIZE >= oh.ImageBase) {
404 if(address > oh.ImageBase) {//we've passed it!
405 DosFreeMem((PVOID)address);
406 break;
407 }
408 //found the right address
409 DosFreeMem((PVOID)address);
410
411 diff = oh.ImageBase - address;
412 if(diff) {
413 rc = DosAllocMem((PPVOID)&address, diff, PAG_READ | flAllocMem);
414 if(rc) break;
415 }
416 rc = DosAllocMem((PPVOID)&baseAddress, oh.SizeOfImage, PAG_READ | PAG_WRITE | flAllocMem);
417 if(rc) break;
418
419 if(diff) DosFreeMem((PVOID)address);
420
421 reservedMemory = baseAddress;
422 break;
423 }
424 memallocs[alloccnt++] = address;
425 }
426 for(i=0;i<alloccnt;i++) {
427 DosFreeMem((PVOID)memallocs[i]);
428 }
429 ret = TRUE;
430end:
431 if(dllfile) DosClose(dllfile);
432 return ret;
433}
434//******************************************************************************
435//******************************************************************************
Note: See TracBrowser for help on using the repository browser.