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

Last change on this file since 21940 was 21940, checked in by dmik, 14 years ago

Fix Indentation.

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