fracker
驱动太牛
驱动太牛
  • 注册日期2001-06-28
  • 最后登录2021-03-30
  • 粉丝0
  • 关注0
  • 积分219分
  • 威望81点
  • 贡献值0点
  • 好评度23点
  • 原创分0分
  • 专家分1分
  • 社区居民
20楼#
发布于:2002-05-15 16:38
fracker你给的工程文件好象不全,在source里的文件好多都没有,why?编译通不过!指点!!


用VC++ 6.0打开工程编译,source已经是个没有用的文件了,不过你要编译之前要先设置好VC++哦,好像也就是几个环境变量。
monkeyy
驱动中牛
驱动中牛
  • 注册日期2001-12-06
  • 最后登录2010-10-10
  • 粉丝0
  • 关注0
  • 积分315分
  • 威望84点
  • 贡献值0点
  • 好评度32点
  • 原创分0分
  • 专家分0分
21楼#
发布于:2002-05-15 16:40
谢谢fracker的精彩回答。一定好好研究!! :cool: :cool:
听说老虎会吃人,所以从没想过去摸老虎的屁股。:( :(
.X.T.I.M.
驱动大牛
驱动大牛
  • 注册日期2001-09-22
  • 最后登录2021-08-25
  • 粉丝0
  • 关注0
  • 积分1分
  • 威望10点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
22楼#
发布于:2002-05-15 16:49
哈哈~~原来大家都在为这个烦恼啊??我已经解决了~~~最早是得到胡老大的帮助啦!后来呢,看了一份代码!相信就是大家要的!大家看看就可以迎刃而解了~~~

/* NT compatible DLL loader
 * See also http://www.sch.bme.hu/~marosi/dllnt.html (Hungarian)
 *
 * Copyright (C) 1996 Istvan Marosi <recosoft@mail.matav.hu>
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* Seen best at TABS=4 */

#include \"includes.h\"

#include \"dllnt.h\"

/* typedefs for syntax colouring: (jed extension)
 } uint; } word; } ulong; } hdll; } proc;
*/

/* functions for syntax colouring: (jed extension)
func open()
func close()
func read()
func lseek()
*/

#define CAST(tt,vv) *((tt *)&vv)

/***********************************************************************/

/* The library\'s main purpose is to load a Win32 DLL into memory. Also,
 * it may be compiled to write extensive commenting messages describing
 * the internal structure of the DLL.
 *
 * DLLs imported by the loaded DLL are automatically loaded and references
 * are resolved if found. If a reference (function) is not found, it is
 * substituted by a dummy one and no error code signalled. This dummy
 * function will write an informative run-time error message only when it
 * is called! (and the program will be immediately terminated...)
 *
 * Several macros are used for writing information to screen as the
 * program interprets the file. Generally the second parameter of these macros
 * are returned therefore it\'s easy for example to print interesting values
 * in expressions without disturbing the sructure of the program.
 *
 * Compile with these defines:
 *
 *   -D_QUIET_ : don\'t write anything. This is the real DLLNT library code.
 *
 *   -D_MESSAGES_ : write everything. Useful for examining contents of a dll
 *
 *   neither : write last tag if something is failed. Almost real DLLNT
 *             library, but writes error text, too.
 *
 * Conventions used in naming the macros:
 *
 *  SuperPrefix:
 * __: not printed, just remembered and printed if later failed
 *
 *  Prefix
 * <no>: the 2nd parameter is a number
 * TX: the 2nd parameter is a string
 * NULL: just an empty line
 *
 *  Body:
 * TAG: returns the 2nd parameter as value
 * MSG: does not return a value
 *
 *  Postfix:
 * INFO: no need to put OK after (if __TXMSG : even not remembered)
 * OKINFO: succeeds prev MSG [same line] (if __TXMSG : not remembered)
 * MAYBE: we are not sure, rather a warning -- only 1 param (type 2nd)
 * WARN: something strange, warning -- only 1 param (type 1st: text)
 * BAD: absolutely bad, give up -- no param
 */
#ifdef _QUIET_
# define __TAG(t,x) (x)
# define __TAGINFO(t,x) (x)
# define __TXTAG(t,tx) (tx)
# define __TXTAGINFO(t,tx) (tx)
# define __MSG(t,x) /**/
# define __MSGINFO(t,x) /**/
# define __MSGOKINFO(t,x) /**/
# define __TXMSG(t,tx) /**/
#else
# define __TAG(t,x) (tag_ = 1, tag_t = t, tag_x = (uint)x, x)
# define __TAGINFO(t,x) (tag_ = 1, tag_t = t, tag_x = (uint)x, x)
# define __TXTAG(t,tx) (tag_ = 2, tag_t = t, tag_tx = tx)
# define __TXTAGINFO(t,tx) (tag_ = 2, tag_t = t, tag_tx = tx)
# define __MSG(t,x) (tag_ = 1, tag_t = t, tag_x = (uint)x)
# define __MSGINFO(t,x) (tag_ = 1, tag_t = t, tag_x = (uint)x)
# define __MSGOKINFO(t,x)(tag_ = 1, tag_t = t, tag_x = (uint)x)
# define __TXMSG(t,tx) (tag_ = 2, tag_t = t, tag_tx = tx)
#endif
#define __TXMSGINFO(t,tx) /**/
#define __TXMSGOKINFO(t,tx) /**/
#define __NULLMSG /**/
#define __TAGMAYBE(x) (x)

#ifdef _MESSAGES_
# define TAG(t,x) (CheckTag(t,(uint)x,1), x)
# define TAGINFO(t,x) (CheckTag(t,(uint)x,0), x)
# define TXTAG(t,tx) (CheckTxTag(t,tx,1), tx)
# define TXTAGINFO(t,tx) (CheckTxTag(t,tx,0), tx)
# define MSG(t,x) (CheckTag(t,(uint)x,1))
# define MSGINFO(t,x) (CheckTag(t,(uint)x,0))
# define MSGOKINFO(t,x) (CheckTag(t,(uint)x,-1))
# define TXMSG(t,tx) (CheckTxTag(t,tx,1))
# define TXMSGINFO(t,tx) (CheckTxTag(t,tx,0))
# define TXMSGOKINFO(t,tx) (CheckTxTag(t,tx,-1))
# define NULLMSG (CheckTag(NULL,0,1))
# define TAGMAYBE(x) (MaybeTag(), x)
#else
# define TAG __TAG
# define TAGINFO __TAGINFO
# define TXTAG __TXTAG
# define TXTAGINFO __TXTAGINFO
# define MSG __MSG
# define MSGINFO __MSGINFO
# define MSGOKINFO __MSGOKINFO
# define TXMSG __TXMSG
# define TXMSGINFO __TXMSGINFO
# define TXMSGOKINFO __TXMSGOKINFO
# define NULLMSG __NULLMSG
# define TAGMAYBE __TAGMAYBE
#endif

#ifdef _QUIET_
#define MSGWARN(tx) /**/
#define MSGBAD      /**/
#else
#define MSGWARN(tx) (WarnTag(tx))
#define MSGBAD (BadTag())
#endif

#ifndef _QUIET_
static int TagOk = 0, tag_ = 0;
static int tag_x;
static const char *tag_t;
static const char *tag_tx;
#endif

/* Definition of COFF magic numbers, structures, and constant values: */

#define DOS_EXE 0x5a4d /* MZ */
#define PE_EXE 0x4550 /* PE */

#define COFF_PROC_I386 0x014c /* Coff magic */
#define COFF_DLL 0x2000
#define COFF_32_BIT 0x0100
#define COFF_EXEC 0x0002 /* valid, executable image */
#define COFF_BIG_ENDIAN 0x8000
#define COFF_NO_RELOCS 0x0001 /* should be loaded at preferred address */

#define COFF_NEEDED (COFF_DLL | COFF_32_BIT | COFF_EXEC)
#define COFF_INVALID (COFF_BIG_ENDIAN | COFF_NO_RELOCS)

#define OPT_NORMAL_EXE 0x010b /* Optional Header magic */

#define OPT_DATA_DIRS 0x0010 /* # of data directories */

#define MAX_PATH 260   /* max length of a filename */
#define MAX_DLLS 256   /* total allowed DLLs loaded */
#define PATH_SEP \'/\'
#define S_PATH_SEP \"/\"

#define VRA2A(type,vra) (type *)(pDll->DllBase + (vra)) /* Relocates a VRA */
#define VRA_A(type,vra) (type *)(DllBase + (vra)) /* Relocates a VRA */
/* In a created DLL VRAs contain the address itself: */
#define VRA_CR(type,vra) (type *)(vra)

typedef struct {
ulong VRA;   /* address */
ulong Size;
} datadir;

/* COFF header */
typedef struct {
short Machine;
word  nSections;
long  TimeStemp;
ulong oSymTab;
ulong nSymbols;
word  OptionSize;
word  Characteristic;

/* Optional Header: */

/* Standard Fields: */
short Magic;
char  LinkVersion[2];
ulong CodeSize;
ulong DataSize;
ulong BssSize;
ulong EntryPoint;
ulong CodeBase;
ulong DataBase;

/* NT specific Fields: */
ulong ImageBase;
ulong Alignment;
ulong FileAlignment;
short OsVersion[2];   /* 1.0 */
short DllVersion[2];
short SubSysVersion[2];   /* 4.0 */
long  Reserved1;
ulong ImageSize;
ulong HeaderSize;
long  CheckSum;
short SubSystem;
short DllFlags;   /* obsolate */
ulong StackReserve;
ulong StackCommit;
ulong HeapReserve;
ulong HeapCommit;
long  Flags; /* obsolate */
ulong nDataDirs;

/* Data Directories: */
datadir ExportTable;
datadir ImportTable;
datadir ResourceTable;
datadir ExceptionTable;
datadir SecurityTable;
datadir RelocTable;
datadir DebugData;
datadir Copyright;
datadir GlobalPtr;
datadir TlsTable;   /* ThreadLocalStorage */
datadir LoadConfigTable;
datadir Reserved2[5];
} coff;

/* Section record */
typedef struct {
char  Name[8];
ulong Size;   /* effective size in memory */
ulong VRA;   /* \"virtual\" relative address */
ulong RawSize;   /* size in file */
ulong oRaw;
ulong oRelocs;
ulong oLineNums;
word  nRelocs;
word  nLineNums;
long  Flags;
} section;

#define S_TEXT 1
#define S_DATA 2
#define S_IMPORT 3
#define S_EXPORT 4
#define S_RELOC  5
#define S_DEBUG  6

/* coff.RelocTable : */
typedef struct { /* Relocation Block Header */
ulong PageVRA;
ulong Size;
} rblock;

#define RELOC_TYPE 0xF000
#define RELOC_SKIP 0x0000
#define RELOC_32   0x3000
#define RELOC_OFFS 0x0FFF

/* coff.ExportTable : */
typedef struct { /* Export Directory Table */
long  ExportFlag;
long  TimeStemp;
short Version[2];
ulong DllNameVRA;
ulong OrdinalBase;
ulong nExports;
ulong nNames;   /* == nOrdinals */
ulong ExportsVRA;
ulong NamesVRA;
ulong OrdinalsVRA;
} etable;
#define MAX_ORDINAL 0x0fff   /* FIXME:
* What is it in NT? Linux\'s start
* address is 0x1000!!
*/
#define ORD_GAP 50   /* safety space for unordered
* SetDllNTProc() calls
*/
/* coff.ImportTable : */
typedef struct { /* Import Directory Table */
ulong LookupsVRA;   /* Import Lookup Table */
long  TimeStemp;
ulong ForwarderChainIndex;
ulong DllNameVRA;
ulong ImportsVRA;   /* Import Address Table */
} itable;
#define FLAG_ORDINAL 0x80000000
#define MASK_ORDINAL 0x7fffffff

typedef struct {
word  OrdHint;
char  Name[1];   /* more then 1, for sure :) */
} procname;

/* Main DLL housekeeping structure */
typedef struct {
char Name[MAX_PATH];
char Path[MAX_PATH];
int  Locks;   /* 0, if not valid */
ulong DllBase;
coff *pCoff;
section *pSection;
char *pImage;
} dll;

static struct {
int nDll;
dll *pDll[MAX_DLLS];   /* hdll is a 1 based index in this array*/
} AllDlls = {0, {NULL}};

#define OPC_PUSH_ECX \'\\x51\'      /* push ecx (ecx: this pointer) */
#define OPC_CALL_REL_1 \'\\xe8\'      /* call <proc_4_bytes> */
#define CALL1_SIZE (1+(1+4))

#define OPC_MOV_EAX_C_1 \'\\xb8\'      /* mov eax,<const_4_bytes> */
#define OPC_CALL_EAX_1 \'\\xff\'      /* call eax */
#define OPC_CALL_EAX_2 \'\\xd0\'              /* 11 010 000 */
#define OPC_ADD_ESP_B_1 \'\\x83\'      /* add esp,+04 */
#define OPC_ADD_ESP_B_2 \'\\xc4\'              /* 11 000 100 */
#define OPC_POP_ECX    \'\\x59\'      /* pop ecx */
#define OPC_JMP_NEAR \'\\xe9\'      /* jmp <pcrel_4_bytes> */
#define CALL2_SIZE ((1+4)+2+(2+1)+1+(1+4))

typedef struct {
char Call1Instr[CALL1_SIZE];
char flOrd; /* true, if (ulong)FuncName is an ordinal */
char flMsg; /* true, if this is a message proc (will return) */
char *DllName;
char *FuncName;
char *Caller;
char Call2Instr[CALL2_SIZE];
} dummy;

#define DUMMYBLOCK 4096   /* enough for >100 dummies */

typedef struct s_dummyhead {
struct s_dummyhead *Next;
dummy *pNomore;
dummy *pFree;
} dummyhead;

static dummyhead *pDummyChain = NULL;

static const char **dllpathes = NULL;

static char szPath[MAX_PATH];
static char szName[MAX_PATH];
/* Both can be global static. Used by LoadDllNT() and LoadImportedDlls().
 * Both functions are (or at least are calling) recursive code, but these
 * arrays are used only till OpenDllHeader(), and later (in the recursive
 * cycle) can be reused to store tha names of recursed dlls.
 */
/*************************************************************************/

#ifndef _QUIET_
static void CheckTag(const char *tag, uint value, int NeedOK)
{
if (NeedOK == -1)
fprintf(stderr, \" \");
else if (TagOk == 1)
fprintf(stderr, \" OK\\n\");

if (tag) {
fprintf(stderr, \"%s:\\t%04x\", tag, value);
TagOk = NeedOK;
} else {
TagOk = 0;
}

if (TagOk != 1) fprintf(stderr, \"\\n\");
tag_ = 0;   /* already printed */
}

static void CheckTxTag(const char *tag, const char *text, int NeedOK)
{
if (NeedOK == -1)
fprintf(stderr, \" \");
else if (TagOk == 1)
fprintf(stderr, \" OK\\n\");

fprintf(stderr, \"%s:\\t%s\", tag, text);
TagOk = NeedOK;

if (TagOk != 1) fprintf(stderr, \"\\n\");
tag_ = 0;   /* already printed */
}
#endif

#ifdef _MESSAGES_
static void MaybeTag(void)
{
if (tag_ == 1) CheckTag(tag_t, tag_x, 1);
if (tag_ == 2) CheckTxTag(tag_t, tag_tx, 1);

fprintf(stderr, \" ??\\n\");
TagOk = 0;
}
#endif

#ifndef _QUIET_
static void WarnTag(const char *text)
{
if (tag_ == 1) CheckTag(tag_t, tag_x, 1);
if (tag_ == 2) CheckTxTag(tag_t, tag_tx, 1);

fprintf(stderr, \" %s\\n\", text);
TagOk = 0;
}

static void BadTag(void)
{
if (tag_ == 1) CheckTag(tag_t, tag_x, 1);
if (tag_ == 2) CheckTxTag(tag_t, tag_tx, 1);

fprintf(stderr, \" BAD\\n\");
TagOk = 0;
}
#endif

/**************************************************************/


/* Allocates READ-WRITE-EXECUTE space for the DLL image */
static char *AllocDllSpace(size_t Bytes)
{
return malloc(Bytes);
}

static void FreeDllSpace(char *pDll)
{
free(pDll);
}

static void lowerstrcpy(char *dest, const char *source)
{
uchar ch;
for (; ch = (uchar)(*source++), ch > 0;) {
/* COMMENT: this works for A..Z only, but it\'s not a problem now */
if (ch >= (uchar)\'A\' && ch <= (uchar)\'Z\')
ch += (uchar)(\'a\' - \'A\');
*dest++ = (char)ch;
}
*dest++ = \'\\0\';
}

static bool isAnyBadSection(coff *pC, section *pS)
{
int i;
ulong offset = pC->CodeBase;
int nS = pC->nSections;

for (i=0; i<nS; i++) {
if (__TAG(\"# of Relocs\", pS.nRelocs) != 0) return 1;
if (__TAG(\"VRA\", pS.VRA) < offset) return 1;
offset = pS.VRA;
}
__NULLMSG;
return 0;
}

/* Opens the pDllName file and loads its headers to memory
 * If pDllName not found in pDllPath it tries to find
 * it in other places.. and changes *pDllPath */
static int OpenDllHeader(char *pDllPath, /* maybe written */
const char *pDllName,
int *pFd,
coff **ppCoff,
section **ppSection)
{
char DllName[MAX_PATH];
int  Fd;
int  RSize;
int  SSize;
word DosHeader[0x20];
coff *pCoff;
section *pSection;

int pathindex = 0;
for (;;) {
DllName[0]=0;
strncat(DllName, pDllPath, sizeof(DllName)-2);
strcat(DllName, S_PATH_SEP);
strncat(DllName, pDllName, sizeof(DllName)-1-strlen(DllName));
/* Well, no buffer overruns, but the name maybe strange :) */

Fd = open(DllName, O_RDONLY);

if (Fd != -1) break;

/* dll not found. Load it from the path: */
if (!dllpathes || !dllpathes[pathindex])
return DLL_NOTFOUND;
pDllPath[0] = 0;
strncat(pDllPath, dllpathes[pathindex++], MAX_PATH-1);
}
*pFd = Fd;

RSize = read(Fd, (char *)DosHeader, sizeof(DosHeader));
if (RSize == -1) return DLL_EACCESS;
if (   (RSize != sizeof(DosHeader))
|| (__TAG(\"EXE Magic\", DosHeader[0]) != DOS_EXE)
|| (__TAG(\"PE Pointer\", DosHeader[0x1e]) == 0)
|| (lseek(Fd, DosHeader[0x1e], SEEK_SET) == -1)
|| (read(Fd, (char *)DosHeader, 4) != 4)
|| (__TAG(\"PE Magic\", DosHeader[0]) != PE_EXE)
|| (DosHeader[1] != 0)) {
return DLL_UNKNOWN;
}
/* Now we are at the beginning of the COFF header */
__NULLMSG;

pCoff = (coff *)malloc(sizeof(coff));
if (pCoff == NULL) return DLL_NOMEM;
*ppCoff = pCoff;

RSize = read(Fd, (char *)pCoff, sizeof(coff));
if (RSize == -1) return DLL_EACCESS;
if (   (RSize != sizeof(coff))
|| (__TAG(\"COFF Machine\", pCoff->Machine) != COFF_PROC_I386)
|| (__TAG(\"Option Size\", pCoff->OptionSize) == 0) /* not an exe */
|| (__TAG(\"Needed Bits\", (pCoff->Characteristic & COFF_NEEDED)) != COFF_NEEDED
)
|| (__TAG(\"Invalid Bits\", (pCoff->Characteristic & COFF_INVALID)) != 0)
|| (__TAG(\"Optional Magic\", pCoff->Magic) != OPT_NORMAL_EXE)
|| (__TAG(\"Data Directories\", pCoff->nDataDirs) != OPT_DATA_DIRS)) {
return DLL_UNKNOWN;
}
__NULLMSG;
if (  /* (__TAG(\"Resources\", pCoff->ResourceTable.Size) != 0 )
||*/ (__TAG(\"Exceptions\", pCoff->ExceptionTable.Size) != 0)
|| (__TAG(\"Securities\", pCoff->SecurityTable.Size) != 0)
|| (__TAG(\"TaskLocals\", pCoff->TlsTable.Size) != 0)
|| (__TAG(\"LoadConfigs\", pCoff->LoadConfigTable.Size) != 0)) {
return DLL_NOTSUPP;
}
__NULLMSG;

/* Coff header seems to be OK */

SSize = pCoff->nSections * sizeof(section);
pSection = (section *)malloc(SSize);
if (pSection == NULL) return DLL_NOMEM;
*ppSection = pSection;

RSize = read(Fd, (char *)pSection, SSize);
if (RSize == -1) return DLL_EACCESS;
if (   (RSize != SSize)
|| (isAnyBadSection(pCoff, pSection))) {
return DLL_NOTSUPP;
}

/* Sections are OK */

return 0;
}

/* The return value of this function is NOT used for any serious purpose */
static int SectionKind(char *pSName)
{
__TXMSG(\"Section Name\", pSName);
if (0 == strcmp(pSName,\".text\")) return S_TEXT;
if (0 == strcmp(pSName,\".data\")) return S_DATA;
if (0 == strcmp(pSName,\".idata\")) return S_IMPORT;
if (0 == strcmp(pSName,\".edata\")) return S_EXPORT;
if (0 == strcmp(pSName,\".reloc\")) return S_RELOC;
return TAGMAYBE(S_DEBUG);
}

/* Loads all sections of the DLL to a newly allocated memory space */
static int ReadDllImage(int Fd,
coff *pCoff,
section *pSection,
char **ppDll)
{
char  *pDll;
int   i;
int   RSize;
ulong FirstRelAddr = pCoff->CodeBase; /* typically 0x1000 */
ulong ISize = pCoff->ImageSize - FirstRelAddr;

__MSGINFO(\"Code Base\", FirstRelAddr);
__MSGINFO(\"Image Size\", ISize);
__NULLMSG;

// FIXME: mmap should be used instead of this stuff...
pDll = AllocDllSpace(ISize);
if (pDll == NULL) return DLL_NOMEM;
*ppDll = pDll;

for (i = 0; i < pCoff->nSections; i++) {
char *pSectData;
int SKind;
uint FSize = pSection.RawSize;
uint MSize = pSection.Size;

SKind = SectionKind(pSection.Name);
if (SKind == 0) return DLL_NOTSUPP; /* ????????? */

__MSGINFO(\"Mem Size\", MSize);
__MSGINFO(\"Raw Size\", FSize);

if (FSize)
if (lseek(Fd,
 __TAGINFO(\"Raw Offset\", pSection.oRaw),
 SEEK_SET) == -1)
return DLL_EACCESS;

pSectData = pDll + (__TAGINFO(\"VRA\", pSection.VRA) - FirstRelAddr);

if (FSize) {
RSize = read(Fd, pSectData, FSize);
if (RSize != (int)FSize) return DLL_EACCESS;
}

if (MSize > FSize)
memset(pSectData + FSize, 0, MSize - FSize); /* BSS init */

__NULLMSG;
}

/* Image loaded to memory (Not relocated yet) */

return 0;
}

/* Relocates all references in DLL image loaded at DllBase */
static int RelocateImage(coff *pCoff, ulong DllBase)
{
ulong OldBase = pCoff->ImageBase;
int Diff = DllBase - OldBase;
rblock *pRBlock = VRA_A(rblock, pCoff->RelocTable.VRA);
int sTotal = pCoff->RelocTable.Size;

__MSGINFO(\"Reloc Size\", sTotal);

while (sTotal > 0) {
ulong PageRelAddr = pRBlock->PageVRA;
int sPage = pRBlock->Size;
word *pReloc = (word *)(pRBlock+1); /* pointer to relocation info word */

__MSGINFO(\"Reloc Block Size\", sPage);

for (sPage -= sizeof(rblock);
sPage > 0;
sPage -= sizeof(word), pReloc++) {
word RType = *pReloc & RELOC_TYPE;
ulong RRelAddr = (ulong)(*pReloc & RELOC_OFFS) + PageRelAddr;
long *p32bit = VRA_A(long, RRelAddr);
if (RType == RELOC_SKIP) {
__MSGINFO(\"Reloc Skip at\", RRelAddr);
} else if (RType != RELOC_32) {
__MSG(\"Reloc Type\", RType);
return DLL_NOTSUPP;
} else {
/* Do the relocation: */
__MSGINFO(\"Relocate at\", RRelAddr);
*p32bit += Diff;
}
}
if (sPage < 0) {
__MSG(\"Reloc Block Size\", sPage);
return DLL_CORRUPT;
}

/* Step to next block: */
sTotal -= pRBlock->Size;
pRBlock = (rblock *)pReloc;
}
if (sTotal < 0) {
__MSG(\"Reloc Size\", sTotal);
return DLL_CORRUPT;
}

__NULLMSG;
return 0;
}

/* Finds an already loaded DLL, or returns a new handle.
 * New handles are returned even if there is a freed slot
 * between loaded DLLs. Freed slots are reused only after
 * all slots are \"dirty\" */
static bool isLoadedDll(const char *Name, hdll *pHDll)
{
int n;

/* Name is already lowercase */

*pHDll = 0;
for (n=0; n < AllDlls.nDll; n++) {
dll *pDll = AllDlls.pDll[n];
if (pDll) {
if (strcmp(Name, pDll->Name) == 0) {
*pHDll = (hdll)(n+1);
MSG(\"Handle Found\", n+1);
return 1;
}
} else {
if (*pHDll == 0) {
/* This is the first already freed handle slot */
*pHDll = (hdll)(n+1);
}
}
}
if (n < MAX_DLLS) *pHDll = (hdll)(n+1);   /* next new available slot */
/* if all handles are occupied, *pHDll is left 0 */

return 0;
}

static int LockDll(hdll HDll)
{
dll *pDll;

pDll = AllDlls.pDll[(int)HDll-1];
pDll->Locks++;

return pDll->Locks;
}

static int UnlockDll(hdll HDll)
{
dll *pDll;

pDll = AllDlls.pDll[(int)HDll-1];
pDll->Locks--;

return pDll->Locks;
}

static void RegisterDll(hdll HDll, dll *pDll)
{
AllDlls.pDll[(int)HDll-1] = pDll;
if (AllDlls.nDll < MAX_DLLS) {
AllDlls.nDll++;
}
pDll->Locks = 1;
}

static dll *UnregisterDll(hdll HDll)
{
dll *pDll;
pDll = AllDlls.pDll[(int)HDll-1];

AllDlls.pDll[(int)HDll-1] = NULL;

/*   if (..last..) AllDlls.nDll--;
* not done, because we don\'t reuse handles till we run out of them */

return pDll;
}

static dll *ValidDll(hdll HDll)
{
dll *pDll;

if (   ((int)HDll < 1)
|| ((int)HDll > AllDlls.nDll)
|| ((pDll = AllDlls.pDll[(int)HDll-1]) == NULL)
|| (pDll->Locks == 0) /* ??? */ ) {
return NULL;
}
return pDll;
}

static void DummyNull(void)
{
fprintf(stderr, \"\\nFatal error: Unbound Imported Procedure Called!\\n\");
exit(100);
}

static void DummyProcedure(char *Call1RetAddr,
  uint pushedECX, uint retaddr, uint Par1, uint Par2)
{
dummy *pDummy = (dummy *)(Call1RetAddr - CALL1_SIZE);

if (pDummy->flMsg == 0) fprintf(stderr, \"\\nFatal error: \");
fprintf(stderr, \"`%s\'.\", pDummy->DllName);
if (pDummy->flOrd) {
fprintf(stderr, \"%i:0x%04x\", (int)pDummy->FuncName, (uint)pDummy->FuncName);
} else {
fprintf(stderr, pDummy->FuncName);
}
fprintf(stderr, \"(0x%04x[,0x%04x]) called by `%s\':0x%04x!\\n\",
  Par1, Par2, pDummy->Caller, retaddr);
if (pDummy->flMsg == 0) exit(100);
}

static proc AllocDummy(char *ImportedDllName, ulong ImportedFunc, dll *pDll,
  proc OrigProc)
{
char  *FuncName;
char  flOrd;
dummy *pDummy;
dummyhead *pAct, **ppLast;

/* OrigProc == 0:
* pDll wanted to import ImportedFunc from ImportedDllName, but couldn\'t */
/* OrigProc != 0:
* We must create a message thunk which prints the name at run-time */

if (ImportedFunc & FLAG_ORDINAL) {
FuncName = (char *)(ImportedFunc & MASK_ORDINAL);
flOrd = 1;
} else {
ulong DllBase = pDll->DllBase;
procname *pPN = VRA_A(procname, ImportedFunc);
FuncName = pPN->Name;
flOrd = 0;
}

for (ppLast = &pDummyChain; ; ) {
pAct = *ppLast;
if (pAct == NULL) {
pAct = malloc(DUMMYBLOCK);
if (pAct == NULL) {
/* Well, just return a bare procedure */
if (OrigProc) {
return OrigProc;
} else {
return DummyNull;
}
}
pAct->Next = NULL;
pAct->pNomore = (dummy*)(((char*)pAct) + DUMMYBLOCK);
pAct->pFree = (dummy*)(pAct + 1);
*ppLast = pAct;
break;
} else {
if (pAct->pFree + 1 <= pAct->pNomore) {
/* Suitable for at least one more dummy */
break;
}
}
ppLast = &(pAct->Next);
}
pDummy = (pAct->pFree)++;

pDummy->flOrd = flOrd;
pDummy->flMsg = OrigProc ? 1 : 0; /* if OrigProc exists, a message thunk */
pDummy->DllName = ImportedDllName;
pDummy->FuncName = FuncName;
pDummy->Caller = pDll->Name;

pDummy->Call1Instr[0] = OPC_PUSH_ECX;
pDummy->Call1Instr[1] = OPC_CALL_REL_1;
CAST(ulong, pDummy->Call1Instr[2]) = /* PC relative address of Call2Instr */
pDummy->Call2Instr - pDummy->Call1Instr - CALL1_SIZE;

pDummy->Call2Instr[0] = OPC_MOV_EAX_C_1;
CAST(proc, pDummy->Call2Instr[1]) = /* absolute address of DummyProcedure */
(proc)DummyProcedure;
pDummy->Call2Instr[5] = OPC_CALL_EAX_1;
pDummy->Call2Instr[6] = OPC_CALL_EAX_2;
pDummy->Call2Instr[7] = OPC_ADD_ESP_B_1;
pDummy->Call2Instr[8] = OPC_ADD_ESP_B_2;
pDummy->Call2Instr[9] = 4;
pDummy->Call2Instr[10] = OPC_POP_ECX;
pDummy->Call2Instr[11] = OPC_JMP_NEAR;
CAST(ulong, pDummy->Call2Instr[12]) = /* PC rel address of real procedure */
(char *)OrigProc - &(pDummy->Call2Instr[12]) - 4;

return (proc)pDummy;
}

hdll CreateDllNT(const char *Name)
{
hdll HDll;
dll *pDll;
coff *pCoff;
etable *pETable;

/* COMMENT: Name should be all characters lowercase! */

TXMSG(\"Creating DLL\",Name);

if (isLoadedDll(Name, &HDll)) {
/* Already created or loaded */
#ifndef _QUIET_
int Locks =
#endif
LockDll(HDll);
MSG(\"Lock Count\", Locks);
} else {
/* Should be created now */

if (HDll == 0) return DLL_NOMEM;

pDll = (dll *)malloc(sizeof(dll));
if (pDll == NULL) return DLL_NOMEM;

pDll->Locks = 0;
pDll->pCoff = NULL;
pDll->pSection = NULL;
pDll->pImage = NULL;   /* Will remain NULL */

strcpy(pDll->Name, Name);
*(pDll->Path) = \'\\0\';

pCoff = (coff *)malloc(sizeof(coff));
if (pCoff == NULL) {
free(pDll);
return DLL_NOMEM;
}
pDll->pCoff = pCoff;

pETable = (etable *)malloc(sizeof(etable));
if (pETable == NULL) {
free(pCoff);
free(pDll);
return DLL_NOMEM;
}
pDll->pSection = (section *)pETable;   /* !! */
/* We use this pointer \'cause it will be freed at the end */
pDll->DllBase = 0;   /* All the VRAs are memory addresses */
pCoff->ExportTable.VRA = (ulong)pETable;
pCoff->ExportTable.Size = sizeof(etable);
pETable->DllNameVRA = 0;
/* (ulong)-1 means that the ordinal numbers have no strict base,
* i.e. all ordinals are generated ones, the base can be defined later.
* GetDllNTProc(ORD) will return NULL !
*/
pETable->OrdinalBase = (ulong)-1;  /* No desired Ord.nums yet */
pETable->nExports = 0;
pETable->nNames = 0;
pETable->ExportsVRA = (ulong)(pETable)+sizeof(etable);
pETable->NamesVRA = (ulong)(pETable)+sizeof(etable);
pETable->OrdinalsVRA = (ulong)(pETable)+sizeof(etable);

MSG(\"New Handle\", HDll);

/* DLL is created, let\'s register it: */
RegisterDll(HDll, pDll);
}
NULLMSG;
return HDll;
}

static void RecalcPointer(char * *pPoi, char *pOld, char *pOldEnd, char *pNew)
{
if (*pPoi >= pOld && *pPoi < pOldEnd)
*pPoi += pNew - pOld;
}

static void ManagePointers(dll *pDll,
  char *pOld, char *pOldEnd, char *pNew)
{
/*
* An area inside a created DLL\'s export table moved from pOld to pNew
* Pointers should be recalculated.
*/
etable *pETable;
uint Index;
char **ppName;

if (pOld == pNew) return;

/* pDll is a created DLL ! (already checked by caller) */
pETable = (etable *)(pDll->pSection);

RecalcPointer(VRA_CR(char *,&(pETable->ExportsVRA)), pOld, pOldEnd, pNew);
RecalcPointer(VRA_CR(char *,&(pETable->NamesVRA)), pOld, pOldEnd, pNew);
RecalcPointer(VRA_CR(char *,&(pETable->OrdinalsVRA)), pOld, pOldEnd, pNew);

ppName = VRA_CR(char *,pETable->NamesVRA);
for (Index = 0; Index < pETable->nNames; Index++) {
RecalcPointer(&(ppName[Index]), pOld, pOldEnd, pNew);
}
}

static int EnlargeETable(dll *pDll, size_t PlusSize)
{
char *pOld;
size_t OldSize;
char *pNew;
coff *pCoff;

/* pDll is a created DLL ! (already checked by caller) */
pCoff = pDll->pCoff;
pOld = VRA_CR(char, pCoff->ExportTable.VRA);
OldSize = pCoff->ExportTable.Size;

pNew = realloc(pOld, OldSize + PlusSize);

if (pNew == 0) return DLL_NOMEM;

pCoff->ExportTable.Size += PlusSize;
pCoff->ExportTable.VRA = (ulong)pNew;
pDll->pSection = (section *)pNew;  /* Store here, too */

ManagePointers(pDll, pOld, pOld + OldSize + 1, pNew);
  /*     ^+1: if something points to the
* end (length=0!), recalc that, too
*/
return 0;
}

static char *InsertAndMove(size_t insert,
  void *mem, void *memend,
  char *newend,
  dll *pDll,
  ulong *pVRA)
{
/* both memend and newend point 1 byte next to the buffer!
*
* Original layout:
*
* |------------------| >
* ^mem [memsize] ^newend
*
* Final layout:
*
* [insert]
*   |========|------------------|>
* ^mem ^newend
*   ^return
*/
size_t memsize = (char *)memend - (char *)mem;
char *pNew = newend-memsize;
int flInsBeg = 0;

/* Insertion must be done to table *pVRA */
if (VRA_CR(void, *pVRA) == mem) flInsBeg = 1; /* Insert to the beginning */

/* memmove can move overlapped blocks */
memmove(pNew, mem, memsize);
/* When insertion is done to NamePointers, half of the pointers are
* already moved to new location - Anyway it\'s OK to run ManagePointers()
* even in this case, because no management other than OrdinalsVRA
* is needed that time; at the insertion to Ordinal table Name Pointers are
* already recalculated.
*/
ManagePointers(pDll, (char *)mem, (char *)memend, pNew);

if (flInsBeg) {
/* insertion is done to the beginning of a table;
* ManagePointers have moved the *pVRA pointer. Get it back:
*/
*pVRA = (ulong)(pNew - insert);
}
return pNew - insert;
}

static int FindInsertionIndex(dll *pDll, const char *Name)
{
etable *pETable;
uint   Index;
char * *ppName;

/* pDll is a created DLL ! (already checked by caller) */

pETable = (etable *)pDll->pSection;
/*
* Data next to fixed size etable:
* ->ExportsVRA = Proc Addresses [nExports] // in ORDINAL order
* ->NamesVRA   = Name Pointer Addresses [nNames] // in abc order
* ->OrdinalsVRA= Ordinal Indexes [nNames] // in abc order
* Name Strings [nNames] // not to be ordered
* This order is important because of the algorithm used by recalculating
* pointers!
*/
/* All the VRAs are simply pointers in a created DLL */
ppName = VRA_CR(char *,pETable->NamesVRA);
/* FIXME: linear search, could be changed to binary */
for (Index = 0; Index < pETable->nNames; Index++) {
char *pName = ppName[Index];
int cmp = strcmp(pName, Name);
if (cmp == 0) return DLL_ILLEGAL; /* Name already defined */
if (cmp > 0) {
/* Should be inserted before this name,
* so Index will be the new index
*/
break;
}
}
/* Index contains Name\'s new index, e.g. ->nNames */

return (int)Index;
}

static int AllocateOrdinalIndex(dll *pDll, int Ord)
{
etable *pETable;
int OrdInd;
ulong uOrd = (ulong)(uint)Ord;
ulong OrdBase;

/* pDll is a created DLL ! (already checked by caller) */

pETable = (etable *)pDll->pSection;

OrdBase = pETable->OrdinalBase;
if (Ord < 0) {
/* Ord can be freely assigned, we allocate the next slot at the end */
/* COMMENT: Instead of allocating a new slot, the already allocated
* ones maybe checked for an empty (unused) space. I don\'t know
* which method is better. If ordinals are specified intermixed with
* \'dontcare\'(-1) values, no one can guess the best method.
*/
OrdInd = (int)pETable->nExports;
} else {
if (OrdBase == (ulong)-1) {
/* Only \'dontcare\' ordinals till now (if any) */
if (pETable->nExports == 0) {
/* this will be the first ordinal */
OrdBase = uOrd;
} else if (pETable->nExports <= uOrd) {
/* we can reallocate all previous ordinals to precede Ord */
OrdBase = 0;
/* ++++++-------$----
* 0=Base Ord
* previous ordinals: +
* actual ordinal:  $
* unallocated space: -
*/
/* Another possibility would be: */
/* OrdBase = uOrd - pETable->nExports; */
/* |------++++++$----
* 0  Base Ord
*/
/* The first one seems to be more secure if ordinals are
* specified unordered.
* The later one occupies less space though!
*/
} else {
/* previous ordinals doesn\'t fit before Ord, let\'s create
* a zero based reallocation:
* |---$------++++++++---
* 0   Ord  Base
*/
OrdBase =  uOrd + (ulong)ORD_GAP;
/* COMMENT: ordinal value for a \'dontcare\' ordinal maybe
* gone over MAX_ORDINAL, but it\'s not a problem.
*/
}
pETable->OrdinalBase = OrdBase;
/* Up to now we just generated an OrdinalBase, data structures
* are unchanged. All previous \'dontcare\' ordinales fixed (no
* way to change their allocation further on).
*/
}

OrdInd = (int)(uOrd - OrdBase);
}

__MSGOKINFO(\"\\tSetOrdinal\",OrdBase==(ulong)-1 ? -1 : OrdBase+OrdInd);

/* COMMENT: With the used data structures there is no way of learning
* whether the ordinal occupying this slot is a \'dontcare\' one?
* Don\'t know whether an occupying ordinal can be safely reallocated.
* So do not do reallocations.
*/
return OrdInd;
}

static int SlotsToInsert(dll *pDll, int SlotInd)
{
/* Ordinal allocation up to now:
* $ $  $ $ <- different cases for uOrd placement
* -2 5  11 17 <- value of SlotInd
* |---++++---++++++++---
* 0   Base  nExports=15
*/
int Slots;

/* pDll is a created DLL ! (already checked by caller) */

if (SlotInd < 0) {
/* New slots to be inserted at the beginning */
Slots = -SlotInd;
} else {
etable *pETable = (etable *)pDll->pSection;
int    nExp = (int)pETable->nExports;

Slots = SlotInd - nExp + 1;
if (Slots <= 0) {
/* New ordinal fits into actual range */
Slots = 0;
if (((VRA_CR(proc, pETable->ExportsVRA))[SlotInd]) != (proc)0)
return DLL_INCOMPAT; /* already occupied! */
} /* else New slots (or at least this one) to be inserted at the end */
}
return Slots;
}

static void InsertOrdinal(dll *pDll, int Slots, int OrdInd /*signed*/,
 char *pEnd, char *pTop)
{
coff *pCoff;
etable *pETable;
int Count;
proc *pProc;
size_t TotalInsert = Slots * sizeof(proc);

/* pDll is a created DLL ! (already checked by caller) */
pCoff = pDll->pCoff;
pETable = VRA_CR(etable, pCoff->ExportTable.VRA);

if (OrdInd < 0) {
/* New slots to be inserted at the beginning */
word *pOrd;

InsertAndMove(TotalInsert,
 VRA_CR(void, pETable->ExportsVRA), pEnd, pTop,
 pDll, &pETable->ExportsVRA);

/* pProc points to the new first proc: */
pProc = VRA_CR(proc, pETable->ExportsVRA);

pETable->OrdinalBase += OrdInd;
/* prevoius ordinal indexes must be reassigned: */
pOrd = VRA_CR(word, pETable->OrdinalsVRA);
for (Count=pETable->nNames; Count > 0; Count--) {
*pOrd += (word)((uint)Slots);
pOrd++;
}
} else {
/* New slots (or at least this one) to be inserted at the end */

pProc = VRA_CR(proc, pETable->ExportsVRA) + pETable->nExports;

InsertAndMove(TotalInsert,
 pProc, pEnd, pTop,
 pDll, &pETable->ExportsVRA);
}
for (Count = Slots; Count > 0; Count--)
*(pProc++) = (proc)0; /* unallocated space */
pETable->nExports += Slots;
}

static int InsertNameAndProc(dll *pDll, uint Index,
const char *Name, int OrdInd, proc pProc)
{
etable *pETable;
coff   *pCoff;

word   *pInsertOrdI;
char * *pInsertPoi;
proc   *pInsertProc;

size_t OldSize;
char   *pOldEnd;

char   *pReady;
char   *pNewName;

size_t NameSize;
size_t TotalInsert;
size_t OrdsInsert;
size_t NamesInsert;
int    ErrorCode;
int    Slots;

/* pDll is a created DLL ! (already checked by caller) */
pCoff = pDll->pCoff;

OldSize = pCoff->ExportTable.Size;

if (Name) {
NameSize = strlen(Name) + 1;
OrdsInsert = sizeof(word);
NamesInsert = sizeof(char *);
TotalInsert = NameSize + OrdsInsert + NamesInsert;
} else {
NameSize = TotalInsert = OrdsInsert = NamesInsert = 0;
Index = 0; /* contains garbage if Name is NULL; move only, no insert */
}
Slots = SlotsToInsert(pDll, OrdInd);
if (Slots < 0) {
MSGBAD;
return Slots; /* Already allocated */
}
TotalInsert += Slots * sizeof(proc);

if (TotalInsert) {
if (0 != (ErrorCode = EnlargeETable(pDll, TotalInsert)))
return ErrorCode;
/* export table may have been moved, calculate pointers now: */
pETable = VRA_CR(etable, pCoff->ExportTable.VRA);
pOldEnd = (char *)pETable + OldSize;

/* Insertion is done from the end back to the beginning, so any byte is
* moved only exactly once.
*
* The algorithm depends on the fact that created DLLs have a strict
* table ordering rule.
*/

pNewName = (char *)(pETable) + pCoff->ExportTable.Size; /* EndOfBuff */
if (NameSize) {
/* Name will be copied to the end of etable buffer */
pNewName=memcpy(pNewName - NameSize, Name, NameSize);
} /* else Name is NULL */

pInsertOrdI = VRA_CR(word, pETable->OrdinalsVRA) + Index;
/*   InsertSize From FromEnd  MoveUpTo */
pReady = InsertAndMove(OrdsInsert, pInsertOrdI, pOldEnd, pNewName,
  pDll, &pETable->OrdinalsVRA);
if (OrdsInsert) *(word *)pReady = (word)OrdInd; /* maybe negative! */
/* All the NamePointers are recalculated now! */

/* Now insert to middle of NamePointers */
pInsertPoi = VRA_CR(char *, pETable->NamesVRA) + Index;
pReady = InsertAndMove(NamesInsert, pInsertPoi, pInsertOrdI, pReady,
  pDll, &pETable->NamesVRA);
if (NamesInsert) {
*(char * *)pReady = pNewName;
pETable->nNames += 1;
/* must be incremented only now (after 2*ins) */
}

if (Slots) {
InsertOrdinal(pDll, Slots, OrdInd, (char *)pInsertPoi, pReady);
}

} else {
pETable = VRA_CR(etable, pCoff->ExportTable.VRA);
}

/* Proc is copied to the OrdInd slot */
pInsertProc = VRA_CR(proc, pETable->ExportsVRA) + OrdInd;
/* this slot is empty for sure */
*pInsertProc = pProc;

return 0;
}

static hdll LoadDllFrom(char *pPath, const char *pName);

static int LoadImportedDlls(dll *pDll) {
coff *pCoff = pDll->pCoff;
ulong DllBase = pDll->DllBase;
if (pCoff->ImportTable.Size) {
/* There are imported functions! */
itable *pITable = VRA_A(itable, pCoff->ImportTable.VRA);
for (; pITable->LookupsVRA != 0; pITable++) {
ulong *pIFunc;
void* *pIAddr;
void *pProc;
char *pName = VRA_A(char, pITable->DllNameVRA);
hdll ImportDll;

TXMSGINFO(\"Dll requested by\", pDll->Name);
strcpy(szPath, pDll->Path); /* path may be changed in LoadDllFrom */
lowerstrcpy(szName, pName); /* name must be lowercase */
ImportDll = LoadDllFrom(szPath, szName);
/* The static szName cannot be used further on
* because of the recursive code!
*/
TXMSGINFO(\"Imports requested by\", pDll->Name);
if (((int)ImportDll) < 0) {
/* We issue a warning and continue with
*   ImportDll = 0;
* meaning all imported functions will be replaced by a dummy
* which will generate a run-time error if called */
TXMSGINFO(\"Imports made dummy for\", pName);
ImportDll = 0;
} else {
TXMSGINFO(\"Imports from\", pName);
}
pIFunc = VRA_A(ulong, pITable->LookupsVRA);
pIAddr = VRA_A(void*, pITable->ImportsVRA);
for (; *pIFunc != 0; pIFunc++, pIAddr++) {
if (*pIFunc & FLAG_ORDINAL) {
ulong ordnum = *pIFunc & MASK_ORDINAL;
MSG(\"Import Ordinal\", ordnum);
if (ordnum > MAX_ORDINAL) {
pProc = NULL;  /* FIXME */
MSGWARN(\"Ordinal number too large\");
} else
pProc = GetDllNTProc(ImportDll, ORDINAL(ordnum));
} else {
procname *pPN = VRA_A(procname, *pIFunc);
TXMSG(\"Import Procedure\", pPN->Name);
/* FIXME: Hint is not used! */
pProc = GetDllNTProc(ImportDll, pPN->Name);
}
if (pProc == NULL) {
/* Either ImportDll is 0 or the function is unknown.
* Address is replaced by a dummy function
* generating a run-time error if called */
pProc = TAGMAYBE(AllocDummy(pName, *pIFunc, pDll, pProc));
#ifdef _MESSAGES_
/* _MESSAGES_: Not the real thing, substitute everything with dummy, too */
} else {
if (ImportDll != 1) /* 1 is dllnt.interface */
pProc = AllocDummy(pName, *pIFunc, pDll, pProc);
#endif
}
/* Bind this import address slot to pProc */
*pIAddr = pProc;
}
NULLMSG;
}
}
return 0;
}

#ifdef _MESSAGES_
static char *GetDllInternalName(hdll HDll)
{
dll *pDll = ValidDll(HDll);
ulong DllBase;

if (pDll == NULL) return NULL;
DllBase = pDll->DllBase;

if (pDll->pCoff->ExportTable.VRA) {
etable *pETable = VRA_A(etable, pDll->pCoff->ExportTable.VRA);
 { /* INFO: Exports */
 uint OrdI;
 uint OrdBase = pETable->OrdinalBase;
 for (OrdI=0; OrdI < pETable->nExports; OrdI++) {
 MSG(\"Exported\", OrdI+OrdBase);
 GetDllNTProc(HDll, ORDINAL(OrdI+OrdBase));
 }
 }
if (pETable->DllNameVRA) {
return VRA_A(char, pETable->DllNameVRA);
}
}
return NULL;
}
#endif

#ifdef _MESSAGES_
static char *NameForOrdI(uint OrdI, ulong DllBase, etable *pETable)
{
uint Index;
word *pOrdI = VRA_A(word, pETable->OrdinalsVRA);

for (Index = 0; Index < pETable->nNames; Index++) {
/* linear search, but no faster can be done for ordinals */
if (pOrdI[Index] == OrdI) {
ulong *ppName = VRA_A(ulong, pETable->NamesVRA);
return VRA_A(char, ppName[Index]);
}
}
return NULL;   /* It\'s not a Named Ordinal */
}
#endif

/* Path maybe written */
static hdll LoadDllFrom(char *Path, const char *Name)
{
hdll HDll;
dll *pDll;

/* Name is already lowercase */

TXMSG(\"Loading DLL\",Name);

if (isLoadedDll(Name, &HDll)) {
/* Already loaded
* OR created
*/
#ifndef _QUIET_
int Locks =
#endif
LockDll(HDll);
MSG(\"Lock Count\", Locks);
} else {
/* Should be loaded now */
int Fd = 0;
int ErrorCode;

if (HDll == 0) return DLL_NOMEM;

pDll = (dll *)malloc(sizeof(dll));
if (pDll == NULL) return DLL_NOMEM;

pDll->Locks = 0;
pDll->pCoff = NULL;
pDll->pSection = NULL;
pDll->pImage = NULL;

if (   (ErrorCode = OpenDllHeader(Path, Name,
 &Fd, &(pDll->pCoff), &(pDll->pSection)))
|| (strcpy(pDll->Name, Name),
/* COMMENT: ExportTable contains an entry for DllName:
* what to do if this name differs from the filename of
* the DLL? Which one to use?
* Anyway: Name is converted to lowercase, while DllName
* maybe uppercase or mixed. Only lowercase works!
*/
strcpy(pDll->Path, Path), /* may have been changed! */
#ifdef _MESSAGES_
MSG(\"New Handle\", HDll),
#endif
ErrorCode = ReadDllImage(Fd, pDll->pCoff, pDll->pSection,
&(pDll->pImage)))
|| (close(Fd), Fd = 0,
pDll->DllBase = (ulong)pDll->pImage - pDll->pCoff->CodeBase,
ErrorCode = RelocateImage(pDll->pCoff, pDll->DllBase))) {

MSGBAD;
if (Fd) close(Fd);
if (pDll->pCoff) free(pDll->pCoff);
if (pDll->pSection) free(pDll->pSection);
if (pDll->pImage) FreeDllSpace(pDll->pImage);
free(pDll);

return ErrorCode;
}

/* DLL is loaded, let\'s register it: */
RegisterDll(HDll, pDll);
/* .Locks is 1 from now on, \'cause an imported DLL may refer
* back to this one. This new DLL isn\'t ready to run anyway! */

TXMSGINFO(\"Internal Name\", GetDllInternalName(HDll));

if ((ErrorCode = LoadImportedDlls(pDll))) {
/* This code won\'t run any time \'cause if a DLL or procedure
* isn\'t found, it\'s replaced by a dummy causing an error
* if later called. The code is, anyway: */
FreeDllNT(HDll);
return (hdll)ErrorCode;
}
}
NULLMSG;
return HDll;
}

static void SplitName(const char *PathName, char *Path, char *Name)
{
char *pSep;
if ((pSep = strrchr(PathName, PATH_SEP))) {
memcpy(Path, PathName, pSep-PathName);
lowerstrcpy(Name, pSep+1);
} else {
strcpy(Path, \".\");
lowerstrcpy(Name, PathName);
}
}

/****************************************************
 *
 *   Non-static (public) functions
 *
 ***************************************************/

/* Specify an array of path strings (terminated by a NULL) to look for
 * a DLL if not found on the specified location
 */
void SetDllNTPathes(const char **pathes)
{
dllpathes = pathes;
}

/* If the named DLL (only the name is important, path doesn\'t make a difference)
 * is already loaded, just increments the lock count. Otherwise loads the
 * DLL and any consecutive DLLs having functions imported by this one */
hdll LoadDllNT(const char *DllName)
{
SplitName(DllName, szPath, szName);
/* szName is lowercase now (DllName maybe mixedcase) */

return LoadDllFrom(szPath, szName); /* Load it from szPath or dllpathes */
}

int FreeDllNT(hdll HDll)
{
dll *pDll;
int Locks;

if (!ValidDll(HDll)) {
return DLL_ILLEGAL;
}

if ((Locks = UnlockDll(HDll)) == 0) {
/* FIXME: imported DLLs should be also freed! */
pDll = UnregisterDll(HDll);

TXMSG(\"Freeing DLL\",pDll->Name);

free(pDll->pCoff);
free(pDll->pSection);
if (pDll->pImage) FreeDllSpace(pDll->pImage);
free(pDll);

NULLMSG;

return 0;
} else {
/* FIXME: what to do with circular imports?
* Now those DLLs are never freed, \'cause .Locks=2 for the base DLL,
* now decremented to 1, but nobody else will decrement it any more */
return Locks;
}
}

/* Finds a procedure name or Ordinal Number in the export table */
proc GetDllNTProc(hdll HDll, const char *Name)
{
dll *pDll;
ulong DllBase;
ulong ETableVRA;
etable *pETable;
ulong ProcVRA;
ulong *pExports;

/*
* In a CREATED (not loaded) DLL only the following fields have values:
* pDll
* -> Name
* Path==0
* Locks
* DllBase==0 (=> VRA==address)
* pCoff
* -> ExportTable
* .VRA
* -> DllNameVRA==0
* OrdinalBase==-1  (=> not supported)
* nExports
* nNames
* ExportsVRA
* NamesVRA
* OrdinalsVRA
* .Size
* pSection
* -> (Not a section! Simply the ExportTable.VRA)
* pImage==0
*/

if ((pDll = ValidDll(HDll)) == NULL) return NULL;

DllBase = pDll->DllBase;

ETableVRA = pDll->pCoff->ExportTable.VRA;
if (   (ETableVRA == 0)
|| (pETable = VRA_A(etable, ETableVRA),
pETable->nExports == 0)) return NULL;

pExports = VRA_A(ulong, pETable->ExportsVRA);

if (((ulong)Name) <= MAX_ORDINAL) {
/* Get by Ordinal Number */
uint Ord = (uint)Name;
uint OrdBase = pETable->OrdinalBase;

if ((Ord < OrdBase) || (Ord >= (OrdBase+pETable->nExports))) {
return NULL;   /* Bad Ordinal */
}
ProcVRA = pExports[Ord - OrdBase];
TXMSGOKINFO(\"Name\", NameForOrdI(Ord - OrdBase, DllBase, pETable));
} else {
/* Get by Name */
uint Index;
word *pOrdI = VRA_A(word, pETable->OrdinalsVRA);
ulong *ppName = VRA_A(ulong, pETable->NamesVRA);
ProcVRA = 0;
for (Index = 0; Index < pETable->nNames; Index++) {
/* FIXME: linear search -- could be changed to binary */
char *pName = VRA_A(char, ppName[Index]);
if (strcmp(pName, Name) == 0) {
int OrdI = pOrdI[Index];
ProcVRA = pExports[OrdI];
break;
}
}
if (!ProcVRA) return NULL;   /* Name Not Found */
}
/* ProcVRA is the VRA of the procedure.
* If it points somewhere to this ExportTable,
* it should be interpreted as a forwarded
* address */
if (   (ProcVRA > ETableVRA)
&& (ProcVRA < (ETableVRA + pDll->pCoff->ExportTable.Size))) {
TXMSG(\"Forwarded\", VRA_A(char, ProcVRA));
/* FIXME: Forwarded export not supported */
return NULL;
}
return VRA_A(void, ProcVRA);
}

/* Creates a procedure name and ordinal number
 * in a created dll\'s export table.
 * If Ord==-1 (or other negative value), allocates an ordinal number.
 */
/* COMMENT: The most secure method is specifying procedures with fixed
 * ordinals first, than all others (with \'dontcare\' ordinals).
 */
int SetDllNTProc(hdll HDll, const char *Name, int Ord, proc ProcAddr)
{
dll *pDll;
int iIndex = 0;
int ErrorCode;
int OrdInd;

__TXMSGOKINFO(\"Adding Procedure\",Name);

if ((pDll = ValidDll(HDll)) == NULL) return DLL_ILLEGAL;

/* Name can be inserted in a created DLL only! */
if (pDll->pImage != NULL) return DLL_ILLEGAL; /* Not a created one */

if (Ord > MAX_ORDINAL) {
MSGWARN(\"Ordinal number too large\");
return DLL_INCOMPAT;
}

if (Name) {
iIndex = FindInsertionIndex(pDll, Name);
if (iIndex < 0) return iIndex; /* Already defined */
}

OrdInd = AllocateOrdinalIndex(pDll, Ord);
/* OrdInd < 0 means insert at the beginning */

ErrorCode = InsertNameAndProc(pDll, (uint)iIndex,
 Name, OrdInd, ProcAddr);

__NULLMSG;

return ErrorCode;
}

<IMG src="http://www.microsoft.com/traincert/images/logos/mcp.gif" border=0> <IMG src="http://www.microsoft.com/traincert/images/logos/mcdba.gif" border=0><br> <IMG src="http://www.microsoft.com/traincert/images/logos/mcse.gif" border=0> <IMG src="http://www.microsoft.com/traincert/images/logos/mcsd.gif" border=0>
fracker
驱动太牛
驱动太牛
  • 注册日期2001-06-28
  • 最后登录2021-03-30
  • 粉丝0
  • 关注0
  • 积分219分
  • 威望81点
  • 贡献值0点
  • 好评度23点
  • 原创分0分
  • 专家分1分
  • 社区居民
23楼#
发布于:2002-05-15 16:50
http://www.driverdevelop.com/forum/viewthread.php?tid=12387&PHPSESSID=a3e9aa6664df603ad6db2b79f93991a9
 


我看到你也是查询系统信息,从你的程序看得到的SYSTEM_MODULE_INFORMATION结构中的PVOID Base就指向模块映像,但是我调试的时候看到每一个结构的Base都等于零,很显然不可能每一个模块映像的base地址都一样,我实在想不通阿,还是想请教。
pjf
pjf
驱动中牛
驱动中牛
  • 注册日期2001-07-08
  • 最后登录2006-10-23
  • 粉丝0
  • 关注0
  • 积分42分
  • 威望4点
  • 贡献值0点
  • 好评度4点
  • 原创分0分
  • 专家分0分
24楼#
发布于:2002-05-15 17:07
我又运行了一下,我这儿得到的ndis.sys基址为0xfe17a000,没有问题,你再检查一下你的代码。
fracker
驱动太牛
驱动太牛
  • 注册日期2001-06-28
  • 最后登录2021-03-30
  • 粉丝0
  • 关注0
  • 积分219分
  • 威望81点
  • 贡献值0点
  • 好评度23点
  • 原创分0分
  • 专家分1分
  • 社区居民
25楼#
发布于:2002-05-15 17:21
我看明白了,你的结构指针是从缓冲区+4开始,而我的没加,所以有此一错,但不知道这开始的4个字节是干什么的?
pjf
pjf
驱动中牛
驱动中牛
  • 注册日期2001-07-08
  • 最后登录2006-10-23
  • 粉丝0
  • 关注0
  • 积分42分
  • 威望4点
  • 贡献值0点
  • 好评度4点
  • 原创分0分
  • 专家分0分
26楼#
发布于:2002-05-15 18:57
  for (ULONG i =0;i <*q;i++)
---------------------------------------------------
兄弟,看仔细一点嘛,第一个ULONG当然是模块的计数啦(或者说后面缓冲项数),要不怎么知道找到几个模块
monkeyy
驱动中牛
驱动中牛
  • 注册日期2001-12-06
  • 最后登录2010-10-10
  • 粉丝0
  • 关注0
  • 积分315分
  • 威望84点
  • 贡献值0点
  • 好评度32点
  • 原创分0分
  • 专家分0分
27楼#
发布于:2002-05-16 07:21
pjf兄!我开个帖子,你来拿分吧!!
听说老虎会吃人,所以从没想过去摸老虎的屁股。:( :(
上一页 下一页
游客

返回顶部