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

Last change on this file since 9536 was 9536, checked in by sandervl, 23 years ago

Error handling changes

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