Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

740 lines
21 KiB

/*************************** Module Header **********************************
* winres.c
* Functions used to read windows 3.0 .exe/.drv files and obtain
* the information contained within their resources. Also handles
* NT format files, and processes them transparently.
*
* HISTORY:
* 09:18 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
* Created it, after investigating Windows/DOS etc.
*
* Copyright (C) 1990 Microsoft Corporation
*
****************************************************************************/
#include <stddef.h>
#include <windows.h>
#include <string.h>
#include "winres.h"
#include "newexe.h"
#include "libproto.h"
/*
* Some defines to maintain old names used in the above structure.
*/
#define hFile uh.hFILE
#define hMod uh.hMOD
#define pResData ur.pRESDATA
#define hLoadRes ur.hLOAD
/*
* Private function prototypes.
*/
static int GetExeHeader( WINRESDATA *, NEW_EXE * );
static BOOL GetExeResTab( WINRESDATA * );
static long ResDataSum( WINRESDATA * );
static BOOL LoadWinResData( WINRESDATA * );
/* !!!LindsayH: quick & dirty unicode conversion */
#define AtoWc( x ) ((x) & 0xff)
/************************** Function Header ********************************
* iLoadStringW
* Function to return a copy of a null terminated string from a
* minidriver resource. Similiar to windows function of same name.
*
* RETURNS:
* Number of (wide) chars in string (NOT including null). 0 if missing.
*
* HISTORY:
* 10:03 on Mon 09 Mar 1992 -by- Lindsay Harris [lindsayh]
* Converted to use UNICODE NT resources & convert Win 3.X
*
* 15:17 on Thu 27 Jun 1991 -by- Lindsay Harris [lindsayh]
* Moved from specdata.c - prepare to split from rasdd in toto.
*
* 12:04 on Fri 30 Nov 1990 -by- Lindsay Harris [lindsayh]
* Created it.
*
***************************************************************************/
int
iLoadStringW( pWRD, iID, wstrBuf, cBuf )
WINRESDATA *pWRD; /* Key to the data */
int iID; /* Resource "name" */
PWSTR wstrBuf; /* Place to put data */
UINT cBuf; /* Bytes in above */
{
/*
* The string resources are stored in groups of 16. SO, the
* 4 LSBs of iID select which of the 16, while the remainder
* select the group.
* Each string resource contains a count byte followed by that
* many bytes of data WITHOUT A NULL. Entries that are missing
* have a 0 count.
*/
UINT iSize;
BYTE *pb;
WCHAR *pwch; /* The wide version */
RES_ELEM RInfo; /* Resource information */
if( !GetWinRes( pWRD, (iID >> 4) + 1, WINRT_STRING, &RInfo ) ||
cBuf < sizeof( WCHAR ) )
{
return 0;
}
iID &= 0xf; /* The string within this resource element */
/*
* cBuf has some limit on sensible sizes. For one, it should be
* a multiple of sizeof( WCHAR ). Secondly, we want to put a 0
* to terminate the string, so add that in now.
*/
cBuf = (cBuf & ~(sizeof( WCHAR ) - 1)) - sizeof( WCHAR );
if( pWRD->fStatus & WRD_NT_DLL )
{
/*
* This means we are UNICODE to start with. It also means
* we have 16 bits widths too!
*/
pwch = RInfo.pvResData;
while( --iID >= 0 )
pwch += 1 + *pwch;
if( iSize = *pwch )
{
/* There is a string: so copy it across */
if( iSize > cBuf )
iSize = cBuf;
wstrBuf[ iSize ] = (WCHAR)0;
iSize *= sizeof( WCHAR ); /* Into bytes */
memcpy( wstrBuf, ++pwch, iSize );
}
}
else
{
/*
* Byte data: Scan looking for the desired element.
*/
pb = RInfo.pvResData; /* Start of data segment */
while( --iID >= 0 )
pb += 1 + *pb; /* Skip count and string (if any) */
if( iSize = *pb )
{
/* Got some data!! */
int iI;
iSize *= sizeof( WCHAR ); /* Into WCHARs */
if( iSize > cBuf )
iSize = cBuf;
for( pwch = wstrBuf, iI = iSize; iI > 0; iI -= sizeof( WCHAR ) )
*pwch++ = AtoWc( *++pb );
*pwch = (WCHAR)0;
}
}
return iSize;
}
/************************ Function Header **********************************
* GetWinRes
* Returns a pointer to the selected resource from a windows minidriver.
* Note that the return value is only valid until the next call
* to this function.
*
* RETURNS:
* TRUE/FALSE - TRUE for success.
*
* HISTORY:
* 09:50 on Fri 30 Nov 1990 -by- Lindsay Harris [lindsayh]
* Created it.
*
***************************************************************************/
BOOL
GetWinRes( pWRD, iName, iType, pRInfo )
WINRESDATA *pWRD; /* All the info we need */
int iName; /* The specific entry */
int iType; /* Type (e.g. string, menu etc */
RES_ELEM *pRInfo; /* Full details of results */
{
/*
* The WinResData passed in contains all the information we need
* about the resource data, and so we can consulting the resource
* table it contains and so determine the location in the file/memory
* where the data is located.
*/
int iLoop;
WORD wID;
RSRC_TYPEINFO *pRSType;
RSRC_NAMEINFO *pRNType;
if( pWRD->fStatus & WRD_NT_DLL )
{
/* NT style DLL, so we can use the standard calls for this one. */
HANDLE hRes;
if( pWRD->hLoadRes )
{
/* Unlock any resource locked last time through */
UnlockResource( pWRD->hLoadRes );
FreeResource( pWRD->hLoadRes );
pWRD->hLoadRes = 0; /* Mark it as free */
}
if( !(hRes = FindResource( pWRD->hFile, (LPCTSTR)iName, (LPCTSTR)iType )) ||
!(pWRD->hLoadRes = LoadResource( pWRD->hFile, hRes )) ||
!(pRInfo->pvResData = LockResource( pWRD->hLoadRes )) )
return FALSE;
pRInfo->iResLen = SizeofResource( pWRD->hFile, hRes );
return TRUE;
}
wID = (WORD)(iType | RSORDID); /* Only type we can handle */
/*
* Scan the resource table data, looking for the desired type.
*/
pRSType = (RSRC_TYPEINFO *)pWRD->paResTab;
while( pRSType->rt_id && pRSType->rt_id != wID )
{
/*
* Find the next entry. The data layout is explained in the
* WinResSize() function.
*/
pRSType = (RSRC_TYPEINFO *)((char *)pRSType + pRSType->rt_nres * sizeof( RSRC_NAMEINFO ));
++pRSType;
}
if( pRSType->rt_id == 0 )
{
SetLastError( ERROR_BAD_FORMAT );
return FALSE; /* Nothing there */
}
/*
* Now have the resource type, we need to find the specific piece
* of data requested by the caller. This requires looping through the
* name structures following the type structure we are looking at.
*/
iLoop = pRSType->rt_nres;
pRNType = (RSRC_NAMEINFO *)++pRSType;
wID = (WORD)(iName | RSORDID);
while( --iLoop >= 0 && pRNType->rn_id != wID )
++pRNType;
if( iLoop < 0 )
{
/* Not available here, so skip report the bad news */
SetLastError( ERROR_BAD_FORMAT );
return FALSE;
}
/*
* Now a little fiddling with addresses, and we have the data
* to return to our caller. pRNType contains an offset and length
* field - these need to be shifted to turn into real numbers.
*/
pRInfo->iResLen = pRNType->rn_length << pWRD->iShift;
pRInfo->pvResData = (char *)pWRD->pResData +
(pRNType->rn_offset << pWRD->iShift) - pWRD->lResOffset;
return TRUE;
}
/************************ Function Header **********************************
* InitWinResData
* Opens the named file and initialises the resource table information.
* Requires a partially filled in WINRESDATA structure. This needs
* to have the heap handle initialised. Then allocate storage and
* load the data from the file.
*
* RETURNS:
* TRUE - file opened, data read, structures initialised.
* FALSE - none of the above.
*
* HISTORY:
* 13:35 on Fri 26 Apr 1991 -by- Lindsay Harris [lindsayh]
* Try NT format dll first, then Windows 16 if NT fails
*
* 13:08 on Fri 26 Apr 1991 -by- Lindsay Harris [lindsayh]
* Changed name; called LoadWinResData to load resources
*
* 09:30 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
* First version.
*
***************************************************************************/
BOOL
InitWinResData( pWinResData, hHeap, pwstrDllName )
register WINRESDATA *pWinResData; /* Data area to fill in */
HANDLE hHeap; /* For heap access */
PWSTR pwstrDllName; /* Name to try opening as a DLL */
{
/*
* We may have an NT or a Windows 16 minidriver to process!
* Assume that it is an NT minidriver - until proven wrong. So
* try LoadLibrary on it, then a GetProcAddr. If both of these
* succeed, it is presumed to be an NT module, and so all
* that is needed is to return the module handle in pWinResData,
* and set the flag saying it is an NT DLL!
*/
DWORD dwOldErrMode; /* Save it for later */
memset( pWinResData, 0, sizeof( WINRESDATA ) );
pWinResData->hHeap = hHeap; /* For later */
dwOldErrMode = SetErrorMode( SEM_FAILCRITICALERRORS );
pWinResData->hMod = LoadLibraryEx( pwstrDllName, NULL,
DONT_RESOLVE_DLL_REFERENCES );
SetErrorMode( dwOldErrMode ); /* Restore error mode */
if( pWinResData->hMod )
{
/* So far, so good! Look for the magic entry point */
if( GetProcAddress( pWinResData->hMod, "bInitProc" ) )
{
/* Assume it's good, so set the flag & return */
pWinResData->fStatus = WRD_NT_DLL;
return TRUE;
}
FreeLibrary( pWinResData->hMod ); /* No good! */
}
/*
* Next step is to open the file and read in the header info.
* The first header contains little information that is of use
* to us. Basically it contains the file address of the new header.
* The new header contains the location of the resource data.
*/
pWinResData->hFile = CreateFileW( pwstrDllName, GENERIC_READ,
FILE_SHARE_READ, 0, OPEN_EXISTING,
0, 0 );
if( pWinResData->hFile == (HANDLE)~0 )
return FALSE;
pWinResData->fStatus = WRD_FOPEN; /* Know that we need to close */
if( !GetExeResTab( pWinResData ) )
{
WinResClose( pWinResData );
return FALSE;
}
/*
* Allocate memory and read the data in.
*/
if( !LoadWinResData( pWinResData ) )
{
WinResClose( pWinResData );
return FALSE;
}
return TRUE;
}
/************************** Function Header *******************************
* LoadWinResData
* Retrieve the resource data from the minidriver file.
*
* RETURNS:
* TRUE for success, FALSE for failure.
*
* HISTORY
* 13:09 on Fri 26 Apr 1991 -by- Lindsay Harris [lindsayh]
* Changed name from GetWinResData; made local function only
*
* 13:39 on Thu 29 Nov 1990 -by- Lindsay Harris [lindsayh]
* Time = 0
*
**************************************************************************/
static BOOL
LoadWinResData( pWRD )
WINRESDATA *pWRD;
{
DWORD lSize; /* Determine how big they are */
DWORD lSize2; /* 'Cos of silly ReadFile parameters */
/*
* Determine the length of the resource data in the file, then
* allocate storage and read it all in. Not that hard!
*/
if( (lSize = ResDataSum( pWRD )) == 0 )
{
/* Zero length is not a good sign! */
return FALSE;
}
if( !(pWRD->pResData = (void *)GlobalAlloc( GMEM_FIXED, lSize )) )
return FALSE;
/*
* Now read the data - ASSUME IT IS CONTIGUOUS!!!
*/
/* !!!LindsayH - as the resource data COULD be quite large, we should
* be careful here, and perhaps set a size limit, above which the
* the data is paged. For now, assume the data is small enough
* to handle in one chunk.
*/
if( SetFilePointer( pWRD->hFile, pWRD->lResOffset, NULL, FILE_BEGIN ) == -1)
return FALSE;
if( !ReadFile( pWRD->hFile, pWRD->pResData, lSize, &lSize2, NULL ) ||
lSize != lSize2 )
{
return FALSE;
}
return TRUE;
}
/************************** Function Header *******************************
* ResDataSum
* Determine the size and starting location of the resource data
* in the minidriver file.
*
* RETURNS:
* TRUE/FALSE, TRUE for success.
*
* HISTORY
* 14:52 on Thu 29 Nov 1990 -by- Lindsay Harris [lindsayh]
* Creation time
*
**************************************************************************/
static long
ResDataSum( pWRD )
WINRESDATA *pWRD;
{
/*
* The data consists of a RSRC_TYPEINFO structure, followed by
* an array of RSRC_NAMEINFO structures, which are then followed
* by a RSRC_TYPEINFO structure, again followed by an array of
* RSRC_NAMEINFO structures. This continues until an RSRC_TYPEINFO
* structure which has a 0 in the rt_id field.
*/
long lSize;
unsigned short usOffset; /* Find lowest offset of resources */
RSRC_TYPEINFO *pRSType;
RSRC_NAMEINFO *pRSName;
lSize = 0;
pRSType = (RSRC_TYPEINFO *)(pWRD->paResTab);
usOffset = (unsigned short)~0;
while( pRSType->rt_id )
{
int cNames;
/* Each TYPE contains a count of the number of NAMEs following */
cNames = pRSType->rt_nres;
++pRSType; /* Skip over that one */
for( pRSName = (RSRC_NAMEINFO *)pRSType; --cNames >= 0; ++pRSName )
{
lSize += pRSName->rn_length;
if( usOffset > pRSName->rn_offset )
usOffset = pRSName->rn_offset;
}
pRSType = (RSRC_TYPEINFO *)pRSName;
}
pWRD->lResOffset = (LONG)usOffset << pWRD->iShift;
pWRD->cbResData = lSize <<= pWRD->iShift;
return lSize;
}
/************************** Function Header *******************************
* WinResClose
* Free the resources associated with this module. This includes
* any memory allocated, and also the file handle to the driver.
*
* RETURNS:
* Nothing
*
* 13:36 on Fri 26 Apr 1991 -by- Lindsay Harris [lindsayh]
* Disengage NT resource mechanism if that has been used.
*
* 14:22 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
* Creation
*
*************************************************************************/
void
WinResClose( pWinResData )
WINRESDATA *pWinResData;
{
/*
* Free used resources. Which resources are used has been recorded
* in the fStatus field of the WINRESDATA structure passed in to us.
*/
if( pWinResData->fStatus & WRD_NT_DLL )
{
/* An NT DLL - so free it up! */
if( pWinResData->hLoadRes )
{
/* A resource is being used - free it */
UnlockResource( pWinResData->hLoadRes );
FreeResource( pWinResData->hLoadRes );
pWinResData->hLoadRes = 0; /* Mark it as free */
}
FreeLibrary( pWinResData->hMod );
}
if( pWinResData->fStatus & WRD_FOPEN )
{
/* File opened, so close it. */
CloseHandle( pWinResData->hFile );
}
if( pWinResData->pResTab )
{
/* Resource table is allocated - free it */
GlobalFree( pWinResData->pResTab );
pWinResData->pResTab = 0;
}
if( pWinResData->pResData )
{
/* Resource table is allocated - free it */
GlobalFree( pWinResData->pResData );
pWinResData->pResData = 0;
}
pWinResData->fStatus = WRD_NOTHING; /* Zero, actually */
return;
}
/*************************** Function Header *******************************
* GetExeResTab
* Reads the .exe resource table from the file, and installs the
* relevant data in the WINRESDATA structure passed in.
*
* RETURNS:
* FALSE on error, TRUE on success.
*
* HISTORY:
* 15:15 on Mon 11 May 1992 -by- Lindsay Harris [lindsayh]
* Changed to delete NEW_RSRC structure x on stack
*
* 14:17 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
* Must be the initial version.
*
**************************************************************************/
static BOOL
GetExeResTab( pWRD )
WINRESDATA *pWRD;
{
DWORD dwSilly; /* For new, detiorated ReadFile call */
NEW_EXE NewExe; /* New header - for ease of manipulation */
if( !(pWRD->cbResTab = GetExeHeader( pWRD, &NewExe )) )
return FALSE;
if( !(pWRD->pResTab = (void *)GlobalAlloc( GMEM_FIXED, pWRD->cbResTab )) )
return FALSE; /* Caller cleans up */
/*
* Read the resource table data. This is all that's required to
* learn all that is of interest to us about the resources.
*/
if( SetFilePointer( pWRD->hFile,
NewExe.ne_rsrctab + pWRD->lNewExe,
NULL, FILE_BEGIN ) == -1 )
{
return FALSE;
}
if( !ReadFile( pWRD->hFile, pWRD->pResTab, pWRD->cbResTab, &dwSilly,NULL) ||
(DWORD)pWRD->cbResTab != dwSilly )
{
return 0;
}
/* IMPORTANT: record the shift information for size & offsets */
pWRD->iShift = ((NEW_RSRC *)(pWRD->pResTab))->rs_align;
/*
* ALSO ADD 2 TO THE ADDRESS. THIS IS MESSY, BUT THE COMPILER
* HAS ALIGNED THE ELEMENTS OF NEW_RSRC TYPE, SO THAT TAKING THE
* ADDRESS OF NEW_RSRC.rs_typeinfo PRODUCES A RESULT 2 BIGGER THAN
* EXPECTED. THE COMPILER DOES THE RIGHT THING HERE, BUT THE DATA
* ON THE DISK IS NOT LAID OUT HOW THE COMPILER DOES IT IN MEMORY
* WHEN GENERATING CODE FOR A 32 BIT ENVIRONMENT. SINCE THE DISK
* LAYOUT IS PREDETERMINED, WE NEED TO ADJUST THE POINTER.
*/
pWRD->paResTab = (BYTE *)(pWRD->pResTab) +
sizeof( ((NEW_RSRC *)0)->rs_align );
return TRUE;
}
/************************ Function Header *********************************
* GetExeHeader
* Reads the new header associated with .exe files, and returns its
* size. A zero return indicates an error: either an explicit
* error (e.g. I/O error), or an absence of resources.
*
* RETURNS:
* Number of bytes in resourc table, else 0 on error.
*
* 14:13 on Wed 28 Nov 1990 -by- Lindsay Harris [lindsayh]
*
**************************************************************************/
static int
GetExeHeader( pWRD, pNewExe )
WINRESDATA *pWRD; /* The magic data we need */
NEW_EXE *pNewExe; /* Where new header is placed */
{
/*
* Read the old header to get the location of the new header.
* Also check the old header's magic value, for verification.
*/
DWORD dwSilly;
EXE_HDR ExeHdr; /* Old format, at beginning of file */
if( !ReadFile( pWRD->hFile, &ExeHdr, sizeof( ExeHdr ), &dwSilly, NULL ) ||
dwSilly != sizeof( ExeHdr ) )
{
return FALSE;
}
if( ExeHdr.e_magic != EMAGIC )
{
SetLastError( ERROR_BAD_FORMAT );
return 0;
}
/*
* The e_lfanew field in ExeHdr contains the file location of the
* new header, so we need to seek to that location.
*/
pWRD->lNewExe = ExeHdr.e_lfanew; /* Offsets are relative to here */
if( SetFilePointer( pWRD->hFile, ExeHdr.e_lfanew, NULL, FILE_BEGIN ) == -1 )
return 0;
if( !ReadFile( pWRD->hFile, pNewExe, sizeof( NEW_EXE ), &dwSilly, NULL ) ||
dwSilly != sizeof( NEW_EXE ) )
{
return 0;
}
if( pNewExe->ne_magic != NEMAGIC )
{
SetLastError( ERROR_BAD_FORMAT );
return 0;
}
/*
* The following test is applied by DOS, so I presume that it is
* legitimate. The assumption is that the resident name table
* FOLLOWS the resource table directly, and that if it points to
* the same location as the resource table, then there are no
* resources.
*/
if( pNewExe->ne_rsrctab == pNewExe->ne_restab )
SetLastError( ERROR_BAD_FORMAT );
return pNewExe->ne_restab - pNewExe->ne_rsrctab;
}