mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
483 lines
15 KiB
483 lines
15 KiB
|
|
#include "ldrextrn.h"
|
|
#ifdef PMNT
|
|
#define INCL_32BIT
|
|
#include "pmnt.h"
|
|
extern PID PMNTPMShellPid;
|
|
#endif
|
|
|
|
/***LP ldrGetTgtMte - get target mte linear address
|
|
*
|
|
* Get MTE of module referenced by ordinal number passed. Use the
|
|
* ordinal number to index into the import module pointers table.
|
|
*
|
|
* ENTRY modord - ordinal number of module referenced
|
|
* pmte - pointer to mte
|
|
* pptgtmte - pointer to target mte
|
|
*
|
|
* EXIT int - return code (NO_ERROR if successful)
|
|
* ptgtmte - mte linear address
|
|
* if mte == 0 reference to DOSCALLS
|
|
*
|
|
* This procedure performs the following steps:
|
|
*
|
|
* - Check that module ordinal number is within module pointer table
|
|
* - Index into module pointer table and return linear address to mte
|
|
*/
|
|
|
|
APIRET ldrGetTgtMte(modord, pmte, pptgtmte)
|
|
ushort_t modord;
|
|
ldrmte_t *pmte;
|
|
ldrmte_t **pptgtmte;
|
|
{
|
|
modord--; /* normalize ordinal */
|
|
|
|
if (modord < (ushort_t) pmte->mte_impmodcnt) {
|
|
*pptgtmte = ((ldrmte_t *) ((ulong_t *) pmte->mte_modptrs)[modord]);
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
/*
|
|
* set error = ERROR_BAD_EXE_FORMAT
|
|
*/
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
|
|
/***LP ldrGetEntAddr - get entry point address
|
|
*
|
|
* For a given ordinal number, this routine locates the
|
|
* appropriate entry contained in the module's entry table.
|
|
* It returns a 48-bit pointer for the specified entry point.
|
|
*
|
|
* ENTRY entord - ordinal number
|
|
* pmte - pointer to target mte
|
|
* ptaddr - pointer to return target address (off,sel,flags)
|
|
* psrcste - pointer to source ste
|
|
* psrcmte - pointer to source mte
|
|
*
|
|
* EXIT entry point address
|
|
* global variable obj_ptr pointing to target segment
|
|
* global variable entry_ptr pointing to entry table entry
|
|
*
|
|
* This procedure performs the following steps:
|
|
*
|
|
* - Check for zero ordinal number
|
|
* - Normalize ordinal number
|
|
* - Checks and handles installable file system mte entry points
|
|
* - Checks and handles DOSCALLS mte entry points
|
|
* - Locates the correct bundle for the given ordinal
|
|
* - Creates the desired entry point address based on source and target
|
|
*/
|
|
|
|
APIRET ldrGetEntAddr(entord, pmte, ptaddr, psrcste, psrcmte)
|
|
ushort_t entord;
|
|
register ldrmte_t *pmte;
|
|
register struct taddr_s *ptaddr;
|
|
ldrste_t *psrcste;
|
|
ldrmte_t *psrcmte;
|
|
{
|
|
int fcallgate;
|
|
ulong_t objnum;
|
|
ldrsmte_t *psmte;
|
|
|
|
UNREFERENCED_PARAMETER(psrcmte);
|
|
|
|
psmte = pmte->mte_swapmte;
|
|
|
|
(ulong_t) ldrProcNameBuf = (ulong_t) entord;
|
|
|
|
if (entord == 0) {
|
|
return(ERROR_INVALID_ORDINAL);
|
|
}
|
|
#if PMNT
|
|
/*
|
|
* This process loads PMWIN.WinCreateMsgQueue()
|
|
*/
|
|
if (entord == 58 &&
|
|
5 == (USHORT) *((PCHAR )pmte->mte_modname) &&
|
|
! strncmp((PCHAR)(pmte->mte_modname+1),"PMWIN",5)) {
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_PMMSGQUE;
|
|
}
|
|
/*
|
|
* This process loads PMNT.PMNTSetPMshellFlag(), thus it is PM Shell.
|
|
*/
|
|
else if (entord == 12 &&
|
|
4 == (USHORT) *((PCHAR )pmte->mte_modname) &&
|
|
! strncmp((PCHAR)(pmte->mte_modname+1),"PMNT",4)) {
|
|
if (!PMNTPMShellPid) {
|
|
PMNTPMShellPid = CurrentThread->Process->ProcessId;
|
|
CurrentThread->Process->Flags |= OS2_PROCESS_IS_PMSHELL;
|
|
}
|
|
else {
|
|
// Do not allow another PMshell
|
|
return(ERROR_2ND_PMSHELL);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
--entord; /* Normalize object number */
|
|
|
|
ptaddr->fflags = 0; /* Clear forwarder flags */
|
|
fcallgate = FALSE; /* assume not a callgate entry */
|
|
|
|
if (ldrIsNE(pmte)) { /* check for 16-bit module */
|
|
|
|
register ldrste_t *pste;
|
|
register ldret_t *pbndl;
|
|
ldrcte_t *pcte;
|
|
ldrent_t *pent;
|
|
|
|
/*
|
|
* Find entry point, loop to determine which bundle the
|
|
* ordinal number belongs too.
|
|
*/
|
|
pbndl = (ldret_t *) psmte->smte_enttab;
|
|
|
|
while (TRUE) { /* find bundle ord is in */
|
|
if (pbndl->et_cnt == 0) { /* check for end of table */
|
|
return(ERROR_INVALID_ORDINAL);
|
|
}
|
|
|
|
if (entord < pbndl->et_cnt) /* is ord in this bundle? */
|
|
break;
|
|
|
|
entord -= pbndl->et_cnt;
|
|
pbndl = (ldret_t *)((char *) pbndl +
|
|
ldrSkipEnts(pmte, pbndl->et_type, pbndl->et_cnt));
|
|
}
|
|
|
|
if (pbndl->et_type == EMPTY) {/* check for empty bundle */
|
|
return(ERROR_INVALID_ORDINAL);
|
|
}
|
|
|
|
pent = (ldrent_t *)((char *) pbndl +
|
|
ldrSkipEnts(pmte, pbndl->et_type, (uchar_t) entord));
|
|
pcte = (ldrcte_t *) pent;
|
|
|
|
ptaddr->fflags |= FWD_ALIAS16; /* indicate tiled object */
|
|
if (pbndl->et_type == B16MOVABLE) { /* check for movable entry */
|
|
objnum = pcte->cte_obj;
|
|
/* get target object */
|
|
if (objnum == B16ABSOLUTE) { /* if absolute entry */
|
|
ptaddr->toff = (ulong_t) pcte->cte_off;
|
|
ptaddr->tsel = 0;
|
|
ptaddr->tflags = pcte->cte_flags;
|
|
return(NO_ERROR);
|
|
}
|
|
if (objnum > psmte->smte_objcnt) {
|
|
return(ERROR_INVALID_SEGMENT_NUMBER);
|
|
}
|
|
pste = (ldrste_t *) psmte->smte_objtab + objnum - 1;
|
|
ptaddr->toff = (ulong_t) pcte->cte_off;
|
|
//
|
|
// If the target object is a code segment which has IOPL (ring 2)
|
|
// create call gate emulation
|
|
//
|
|
if ((pcte->cte_sel != 0) &&
|
|
(pcte->cte_sel != 0x3fcd) &&
|
|
((psrcste == NULL) || // ldrDosGetProcAddress() calls with NULL
|
|
(((psrcste->ste_flags & STE_SEGDPL) == STE_RING_3) &&
|
|
((psrcste->ste_flags & STE_DATA) == 0))) // source is a code segment
|
|
) {
|
|
ptaddr->fflags |= FWD_IOPL;
|
|
ptaddr->toff = (ulong_t)pcte->cte_sel;
|
|
ptaddr->tsel = FLATTOSEL(R2XFER_BASE);
|
|
return(NO_ERROR);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* check for absolute entry
|
|
*/
|
|
else if (pbndl->et_type == B16ABSOLUTE) {
|
|
ptaddr->toff = (ulong_t) pent->ent_off;
|
|
ptaddr->tsel = 0;
|
|
ptaddr->tflags = pent->ent_flags;
|
|
return(NO_ERROR);
|
|
}
|
|
else { /* entry is fixed */
|
|
if((ulong_t) pbndl->et_type > psmte->smte_objcnt) {
|
|
return(ERROR_INVALID_SEGMENT_NUMBER);
|
|
}
|
|
|
|
/*
|
|
* get target object
|
|
*/
|
|
pste = (ldrste_t *) psmte->smte_objtab + pbndl->et_type - 1;
|
|
ptaddr->toff = (ulong_t) pent->ent_off;
|
|
}
|
|
|
|
ptaddr->tsel = pste->ste_selector | 7;
|
|
ptaddr->tflags = pent->ent_flags;
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
/***LP ldrGetOrdNum - get the ordinal number for procedure name
|
|
*
|
|
* Given a procedure name and a module table, checks to see if
|
|
* the procedure is in the resident or nonresident table. If the
|
|
* procedure is found in either of the tables, ldrGetOrdNum
|
|
* returns the corresponding ordinal number. A 0 ordinal is
|
|
* returned if the procedure is not found in either of the tables.
|
|
*
|
|
* ENTRY pmte - pointer to module table entry
|
|
* pprocnam - pointer to procedure name
|
|
* pentord - address to return ordinal number
|
|
* fstring - flag to tell if null terminated
|
|
* STRINGNULLTERM
|
|
* STRINGPREPENDED
|
|
*
|
|
* EXIT if found
|
|
* NO_ERROR
|
|
* else
|
|
* ERROR_NOT_ENOUGH_MEMORY
|
|
* ERROR_PROC_NOT_FOUND
|
|
*/
|
|
|
|
APIRET ldrGetOrdNum(pmte, pprocnam, pentord, fstring)
|
|
ldrmte_t *pmte;
|
|
uchar_t *pprocnam;
|
|
ushort_t *pentord;
|
|
int fstring;
|
|
{
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
PIO_STATUS_BLOCK pIoStatusBlock = &IoStatusBlock;
|
|
LARGE_INTEGER ByteOffset;
|
|
PVOID MemoryAddress;
|
|
ULONG RegionSize;
|
|
ulong_t cbread;
|
|
register ldrsmte_t *psmte;
|
|
ushort_t proclen;
|
|
char tname[MAX_PROC_LEN+1];
|
|
char *ptname;
|
|
int rc = NO_ERROR;
|
|
|
|
ptname = (char *) &tname;
|
|
psmte = pmte->mte_swapmte;
|
|
|
|
ldrProcNameBuf = (PUCHAR) (pprocnam + 1);
|
|
ldrProcNameBufL = proclen = (USHORT) (pprocnam[0]);
|
|
|
|
/*
|
|
* Check for 32-bit module
|
|
*/
|
|
if (ldrIsLE(pmte)) {
|
|
struct ExpHdr *pexpdir;
|
|
ulong_t *pexpnameptrs;
|
|
ushort_t *pexpordinals;
|
|
|
|
if (fstring == STRINGNONNULL) {
|
|
|
|
/*
|
|
* Since the procedure name strings in a 32-bit module are in
|
|
* the format of a null terminated string we need to convert
|
|
* the 16-bit formated string of a length followed by string
|
|
* to a null terminated string.
|
|
*/
|
|
proclen = pprocnam[0];
|
|
memcpy(pprocnam, pprocnam + 1, proclen);
|
|
pprocnam[proclen] = '\0';
|
|
}
|
|
pexpdir = (struct ExpHdr *) psmte->smte_expdir;
|
|
pexpnameptrs = (ulong_t *) pexpdir->exp_name;
|
|
pexpordinals = (ushort_t *) pexpdir->exp_ordinal;
|
|
// rc = ldrBinarySearchOrd(psmte,
|
|
// pprocnam,
|
|
// pexpnameptrs,
|
|
// pexpordinals,
|
|
// pexpdir->exp_namecnt,
|
|
// pentord);
|
|
/*
|
|
* Restore procedure name back to length followed by string.
|
|
*/
|
|
// if (fstring == STRINGNONNULL) {
|
|
// ldrStrCpyB(pprocnam + 1, pprocnam, proclen);
|
|
// pprocnam[0] = (uchar_t) proclen;
|
|
// }
|
|
|
|
return(rc);
|
|
}
|
|
|
|
/*
|
|
* Check for null terminated string passed. If it is we were called
|
|
* by ldrGetProcAddr and we may do this in place copy and not restore
|
|
* it because it is from the stack of ldrGetProcAddr
|
|
*/
|
|
if (fstring == STRINGNULLTERM) {
|
|
proclen = (ushort_t) strlen(pprocnam);
|
|
strncpy(&ptname[1], pprocnam, proclen);
|
|
ptname[0] = (uchar_t) proclen;
|
|
}
|
|
|
|
else {
|
|
strncpy(ptname, pprocnam, proclen + 1);
|
|
}
|
|
|
|
/*
|
|
* 16-bit module, first search the resident name table.
|
|
*/
|
|
if ((rc = ldrGetOrdNumSub((uchar_t *) psmte->smte_restab,
|
|
ptname,
|
|
pentord)) != ERROR_PROC_NOT_FOUND) {
|
|
return(rc);
|
|
}
|
|
#if DBG
|
|
IF_OL2_DEBUG ( FIXUP ) {
|
|
if (fstring == STRINGNONNULL) {
|
|
strncpy(&tname[0], &pprocnam[1], proclen);
|
|
tname[proclen] = '\0';
|
|
DbgPrint(
|
|
"Could not find Procedure %s in module %s in Resident name table\n",
|
|
&tname, (char *) (pmte->mte_modname+1));
|
|
}
|
|
else {
|
|
DbgPrint(
|
|
"Could not find Procedure %s in module %s in Resident name table\n",
|
|
pprocnam, (char *) (pmte->mte_modname+1));
|
|
}
|
|
|
|
if (fstring == STRINGNONNULL) {
|
|
strncpy(ptname, pprocnam, proclen + 1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* The procedure name was not found in the resident name table,
|
|
* need to search the non-resident name table.
|
|
* Do not do this for system dll's other than doscall
|
|
*/
|
|
|
|
if (pmte->mte_mflags & DOSMOD) {
|
|
return(ERROR_PROC_NOT_FOUND);
|
|
}
|
|
|
|
RegionSize = psmte->smte_cbnrestab;
|
|
MemoryAddress = 0;
|
|
if ((rc = NtAllocateVirtualMemory(NtCurrentProcess(),
|
|
&MemoryAddress,
|
|
0,
|
|
&RegionSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE)) != NO_ERROR) {
|
|
return(ERROR_PROC_NOT_FOUND);
|
|
}
|
|
|
|
/*
|
|
* read the non-resident nametable from the file into non-
|
|
* resident name table object.
|
|
*/
|
|
ByteOffset.LowPart = psmte->smte_nrestab;
|
|
ByteOffset.HighPart = 0;
|
|
cbread = psmte->smte_cbnrestab;
|
|
if ((rc = NtReadFile(pmte->mte_sfn,
|
|
0,
|
|
0,
|
|
0,
|
|
&IoStatusBlock,
|
|
(void *) MemoryAddress,
|
|
cbread,
|
|
&ByteOffset,
|
|
0)) != 0) {
|
|
return(ERROR_BAD_EXE_FORMAT);
|
|
}
|
|
|
|
if (IoStatusBlock.Information != cbread) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
goto returnstatus;
|
|
}
|
|
|
|
/*
|
|
* Now check if the procname is in the nonresident name table.
|
|
*/
|
|
rc = ldrGetOrdNumSub((uchar_t *) MemoryAddress,
|
|
ptname,
|
|
pentord);
|
|
returnstatus:
|
|
NtFreeVirtualMemory(NtCurrentProcess(),
|
|
&MemoryAddress,
|
|
&cbread,
|
|
MEM_RELEASE);
|
|
if (rc == NO_ERROR)
|
|
return(rc);
|
|
|
|
if (fstring == STRINGNONNULL) {
|
|
strncpy(&ptname[0], &pprocnam[1], proclen);
|
|
ptname[proclen] = '\0';
|
|
}
|
|
#if DBG
|
|
IF_OL2_DEBUG ( FIXUP ) {
|
|
DbgPrint(
|
|
"Could not find Procedure %s in module %s in Non-resident table\n",
|
|
ptname, (char *) (pmte->mte_modname+1));
|
|
}
|
|
#endif
|
|
return(ERROR_PROC_NOT_FOUND);
|
|
}
|
|
|
|
|
|
/***LP ldrGetOrdNumSub - get the ordinal number for procedure name
|
|
*
|
|
* Given a procedure name and a resident or nonresident name table
|
|
* containing the procedures exported by a module, checks to see
|
|
* if the procedure is in the table. If the procedure is found
|
|
* in the table, ldrGetOrdNumSub gets the corresponding ordinal
|
|
* number. A 0 ordinal value is returned if the procedure is not
|
|
* found in the table. The ordinal number for the module name string
|
|
* is set to zero, therefore matching strings with a 0 ordinal number
|
|
* are skipped.
|
|
*
|
|
* ENTRY pnt - pointer to resident or nonresident name table
|
|
* pprocnam - pointer to procedure name
|
|
* pentord - place to return ordinal
|
|
*
|
|
* EXIT if found
|
|
* NO_ERROR
|
|
* else
|
|
* ERROR_PROC_NOT_FOUND
|
|
* ERROR_BAD_EXE_FORMAT
|
|
*
|
|
* This procedure performs the following steps:
|
|
*
|
|
* - compare procedure name to each entry in table
|
|
* - if ordinal number is 0 skip to next string
|
|
* - return ordinal number if found
|
|
*/
|
|
|
|
APIRET ldrGetOrdNumSub(pnt, pprocnam, pentord)
|
|
register uchar_t *pnt;
|
|
register uchar_t *pprocnam;
|
|
ushort_t *pentord;
|
|
{
|
|
register int len;
|
|
|
|
|
|
/*
|
|
* remove typeinfo from length
|
|
*/
|
|
while ((len = (int) (*pnt /*& ~NT_TYPEINFO*/)) != 0) { // YOSEFD: The using of the flag
|
|
// harm the names that are longer
|
|
// then 0x7F. The description string
|
|
// can be longer.
|
|
/*
|
|
* include string size field
|
|
*/
|
|
if (memcmp(pnt, pprocnam, ++len) == 0)
|
|
|
|
if ((*(ushort_t *) (pnt + len)) != 0) {
|
|
/*
|
|
* return ordinal number
|
|
*/
|
|
*pentord = *(ushort_t *)(pnt + len);
|
|
return(NO_ERROR);
|
|
}
|
|
pnt += len + sizeof(ushort_t); /* skip to next string */
|
|
}
|
|
|
|
return(ERROR_PROC_NOT_FOUND); /* end of table, return not found */
|
|
}
|