2264 lines
58 KiB
C
2264 lines
58 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
modimage.c
|
|
|
|
Abstract:
|
|
|
|
Implements a set of routines for examining EXE modules
|
|
|
|
Author:
|
|
|
|
Calin Negreanu (calinn) 27-Nov-1997
|
|
|
|
Revision History:
|
|
|
|
calinn 08-Mar-2000 Moved over from Win9xUpg project.
|
|
|
|
--*/
|
|
|
|
//
|
|
// Includes
|
|
//
|
|
|
|
#include "pch.h"
|
|
|
|
//
|
|
// Debug constants
|
|
//
|
|
|
|
#define DBG_MODIMAGE "ModImage"
|
|
|
|
//
|
|
// Strings
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Constants
|
|
//
|
|
|
|
#define SEG_CODE_MASK 0x0001
|
|
#define SEG_CODE 0x0000
|
|
#define SEG_PRELOAD_MASK 0x0040
|
|
#define SEG_PRELOAD 0x0040
|
|
#define SEG_RELOC_MASK 0x0100
|
|
#define SEG_RELOC 0x0100
|
|
|
|
#define RELOC_IMPORTED_ORDINAL 0x01
|
|
#define RELOC_IMPORTED_NAME 0x02
|
|
#define RELOC_ADDR_TYPE 0x03
|
|
|
|
#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
|
|
#define IMAGE_NE_SIGNATURE 0x454E // NE
|
|
#define IMAGE_PE_SIGNATURE 0x00004550l // PE00
|
|
|
|
//
|
|
// Macros
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Types
|
|
//
|
|
|
|
#pragma pack(push,1)
|
|
|
|
typedef struct _DOS_HEADER { // DOS .EXE header
|
|
WORD e_magic; // Magic number
|
|
WORD e_cblp; // Bytes on last page of file
|
|
WORD e_cp; // Pages in file
|
|
WORD e_crlc; // Relocations
|
|
WORD e_cparhdr; // Size of header in paragraphs
|
|
WORD e_minalloc; // Minimum extra paragraphs needed
|
|
WORD e_maxalloc; // Maximum extra paragraphs needed
|
|
WORD e_ss; // Initial (relative) SS value
|
|
WORD e_sp; // Initial SP value
|
|
WORD e_csum; // Checksum
|
|
WORD e_ip; // Initial IP value
|
|
WORD e_cs; // Initial (relative) CS value
|
|
WORD e_lfarlc; // File address of relocation table
|
|
WORD e_ovno; // Overlay number
|
|
WORD e_res[4]; // Reserved words
|
|
WORD e_oemid; // OEM identifier (for e_oeminfo)
|
|
WORD e_oeminfo; // OEM information; e_oemid specific
|
|
WORD e_res2[10]; // Reserved words
|
|
LONG e_lfanew; // File address of new exe header
|
|
} DOS_HEADER, *PDOS_HEADER;
|
|
|
|
typedef struct _NE_HEADER {
|
|
WORD Magic;
|
|
BYTE MajorLinkerVersion;
|
|
BYTE MinorLinkerVersion;
|
|
WORD EntryTableOff;
|
|
WORD EntryTableLen;
|
|
ULONG Reserved;
|
|
WORD Flags;
|
|
WORD NumberOfDataSeg;
|
|
WORD SizeOfHeap;
|
|
WORD SizeOfStack;
|
|
ULONG CS_IP;
|
|
ULONG SS_SP;
|
|
WORD NumEntriesSegTable;
|
|
WORD NumEntriesModuleTable;
|
|
WORD NonResNameTableSize;
|
|
WORD SegTableOffset;
|
|
WORD ResTableOffset;
|
|
WORD ResNameTableOffset;
|
|
WORD ModuleTableOffset;
|
|
WORD ImportedTableOffset;
|
|
ULONG NonResNameTableOffset;
|
|
WORD NumberOfMovableEntryPoints;
|
|
WORD ShiftCount;
|
|
WORD NumberOfResourceSegments;
|
|
BYTE TargetOS;
|
|
BYTE AdditionalInfo;
|
|
WORD FastLoadOffset;
|
|
WORD FastLoadSize;
|
|
WORD Reserved1;
|
|
WORD WinVersionExpected;
|
|
} NE_HEADER, *PNE_HEADER;
|
|
|
|
typedef struct {
|
|
WORD Signature; // 00h
|
|
BYTE LinkerVersion; // 02h
|
|
BYTE LinkerRevision; // 03h
|
|
WORD OffsetToEntryTable; // 04h
|
|
WORD LengthOfEntryTable; // 06h
|
|
DWORD Reserved; // 08h
|
|
WORD Flags; // 0ch
|
|
WORD AutoDataSegment; // 0eh
|
|
WORD LocalHeapSize; // 10h
|
|
WORD StackSize; // 12h
|
|
DWORD EntryAddress; // 14h
|
|
DWORD StackAddress; // 18h
|
|
WORD SegmentTableEntries; // 1ch
|
|
WORD ModuleReferenceTableEntries; // 1eh
|
|
WORD NonResidentTableSize; // 20h
|
|
WORD OffsetToSegmentTable; // 22h
|
|
WORD OffsetToResourceTable; // 24h
|
|
WORD OffsetToResidentNameTable; // 26h
|
|
WORD OffsetToModuleReferenceTable; // 28h
|
|
WORD OffsetToImportedNameTable; // 2ah
|
|
WORD OffsetToNonResidentNameTable; // 2ch
|
|
WORD Unused; // 2eh
|
|
WORD MovableEntryPoints; // 30h
|
|
WORD LogicalSectorShiftCount; // 32h
|
|
WORD ResourceSegments; // 34h
|
|
BYTE TargetOS; // 36h
|
|
BYTE AdditionalFlags; // 37h
|
|
WORD FastLoadOffset; // 38h
|
|
WORD SectorsInFastLoad; // 3ah
|
|
WORD Reserved2; // 3ch
|
|
WORD WindowsVersion; // 3eh
|
|
} NE_INFO_BLOCK, *PNE_INFO_BLOCK;
|
|
|
|
typedef struct _NE_SEGMENT_ENTRY {
|
|
WORD SegmentOffset;
|
|
WORD SegmentLen;
|
|
WORD SegmentFlags;
|
|
WORD SegMinAlloc;
|
|
} NE_SEGMENT_ENTRY, *PNE_SEGMENT_ENTRY;
|
|
|
|
typedef struct _NE_RELOC_ITEM {
|
|
BYTE AddressType;
|
|
BYTE RelocType;
|
|
WORD RelocOffset;
|
|
WORD ModuleOffset;
|
|
WORD FunctionOffset;
|
|
} NE_RELOC_ITEM, *PNE_RELOC_ITEM;
|
|
|
|
typedef struct {
|
|
WORD Offset;
|
|
WORD Length;
|
|
WORD Flags;
|
|
WORD Id;
|
|
WORD Handle;
|
|
WORD Usage;
|
|
} NE_RES_NAMEINFO, *PNE_RES_NAMEINFO;
|
|
|
|
typedef struct {
|
|
WORD TypeId;
|
|
WORD ResourceCount;
|
|
DWORD Reserved;
|
|
NE_RES_NAMEINFO NameInfo[];
|
|
} NE_RES_TYPEINFO, *PNE_RES_TYPEINFO;
|
|
|
|
#pragma pack(pop)
|
|
|
|
typedef struct {
|
|
WORD AlignShift;
|
|
GROWLIST TypeInfoArray;
|
|
GROWLIST ResourceNames;
|
|
} NE_RESOURCES, *PNE_RESOURCES;
|
|
|
|
typedef struct {
|
|
PLOADED_IMAGE Image;
|
|
PIMAGE_IMPORT_DESCRIPTOR ImageDescriptor;
|
|
DWORD ImportFunctionAddr;
|
|
PIMAGE_THUNK_DATA ImageData;
|
|
PIMAGE_IMPORT_BY_NAME ImageName;
|
|
} MD_IMPORT_ENUM32_HANDLE, *PMD_IMPORT_ENUM32_HANDLE;
|
|
|
|
typedef struct {
|
|
PBYTE Image;
|
|
PDOS_HEADER DosHeader;
|
|
PNE_HEADER NeHeader;
|
|
PNE_SEGMENT_ENTRY SegmentEntry;
|
|
WORD CurrSegEntry;
|
|
PWORD CurrNrReloc;
|
|
PNE_RELOC_ITEM RelocItem;
|
|
WORD CurrRelocItem;
|
|
} MD_IMPORT_ENUM16_HANDLE, *PMD_IMPORT_ENUM16_HANDLE;
|
|
|
|
typedef struct {
|
|
HANDLE File;
|
|
DWORD HeaderOffset;
|
|
NE_INFO_BLOCK Header;
|
|
NE_RESOURCES Resources;
|
|
BOOL ResourcesLoaded;
|
|
PMHANDLE ResourcePool;
|
|
} NE_HANDLE, *PNE_HANDLE;
|
|
|
|
typedef BOOL (CALLBACK* ENUMRESTYPEPROCEXA)(HMODULE hModule, PCSTR lpType, LONG_PTR lParam, PNE_RES_TYPEINFO TypeInfo);
|
|
|
|
typedef BOOL (CALLBACK* ENUMRESTYPEPROCEXW)(HMODULE hModule, PCWSTR lpType, LONG_PTR lParam, PNE_RES_TYPEINFO TypeInfo);
|
|
|
|
typedef BOOL (CALLBACK* ENUMRESNAMEPROCEXA)(HMODULE hModule, PCSTR lpType,
|
|
PSTR lpName, LONG_PTR lParam, PNE_RES_TYPEINFO TypeInfo, PNE_RES_NAMEINFO NameInfo);
|
|
|
|
typedef BOOL (CALLBACK* ENUMRESNAMEPROCEXW)(HMODULE hModule, PCWSTR lpType,
|
|
PWSTR lpName, LONG_PTR lParam, PNE_RES_TYPEINFO TypeInfo, PNE_RES_NAMEINFO NameInfo);
|
|
|
|
typedef struct {
|
|
PCSTR TypeToFind;
|
|
PNE_RES_TYPEINFO OutboundTypeInfo;
|
|
BOOL Found;
|
|
} TYPESEARCHDATAA, *PTYPESEARCHDATAA;
|
|
|
|
typedef struct {
|
|
PCSTR NameToFind;
|
|
PNE_RES_TYPEINFO OutboundTypeInfo;
|
|
PNE_RES_NAMEINFO OutboundNameInfo;
|
|
BOOL Found;
|
|
} NAMESEARCHDATAA, *PNAMESEARCHDATAA;
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion list
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Private function prototypes
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Macro expansion definition
|
|
//
|
|
|
|
// None
|
|
|
|
//
|
|
// Code
|
|
//
|
|
|
|
BOOL
|
|
MdLoadModuleDataA (
|
|
IN PCSTR ModuleName,
|
|
OUT PMD_MODULE_IMAGE ModuleImage
|
|
)
|
|
{
|
|
HANDLE fileHandle;
|
|
DWORD bytesRead;
|
|
DOS_HEADER dh;
|
|
DWORD sign;
|
|
PWORD signNE = (PWORD)&sign;
|
|
BOOL result = FALSE;
|
|
|
|
ZeroMemory (ModuleImage, sizeof (MD_MODULE_IMAGE));
|
|
|
|
fileHandle = CreateFileA (ModuleName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
ModuleImage->ModuleType = MODULETYPE_UNKNOWN;
|
|
return FALSE;
|
|
}
|
|
__try {
|
|
__try {
|
|
if ((!ReadFile (fileHandle, &dh, sizeof (DOS_HEADER), &bytesRead, NULL)) ||
|
|
(bytesRead != sizeof (DOS_HEADER))
|
|
) {
|
|
__leave;
|
|
}
|
|
result = TRUE;
|
|
if (dh.e_magic != IMAGE_DOS_SIGNATURE) {
|
|
ModuleImage->ModuleType = MODULETYPE_UNKNOWN;
|
|
__leave;
|
|
}
|
|
ModuleImage->ModuleType = MODULETYPE_DOS;
|
|
|
|
if (SetFilePointer (fileHandle, dh.e_lfanew, NULL, FILE_BEGIN) != (DWORD)dh.e_lfanew) {
|
|
__leave;
|
|
}
|
|
if ((!ReadFile (fileHandle, &sign, sizeof (DWORD), &bytesRead, NULL)) ||
|
|
(bytesRead != sizeof (DWORD))
|
|
) {
|
|
__leave;
|
|
}
|
|
CloseHandle (fileHandle);
|
|
fileHandle = INVALID_HANDLE_VALUE;
|
|
|
|
if (sign == IMAGE_PE_SIGNATURE) {
|
|
ModuleImage->ModuleType = MODULETYPE_WIN32;
|
|
result = MapAndLoad ((PSTR)ModuleName, NULL, &ModuleImage->ModuleData.W32Data.Image, FALSE, TRUE);
|
|
}
|
|
if (*signNE == IMAGE_NE_SIGNATURE) {
|
|
ModuleImage->ModuleType = MODULETYPE_WIN16;
|
|
ModuleImage->ModuleData.W16Data.Image = MapFileIntoMemoryA (
|
|
ModuleName,
|
|
&ModuleImage->ModuleData.W16Data.FileHandle,
|
|
&ModuleImage->ModuleData.W16Data.MapHandle
|
|
);
|
|
result = (ModuleImage->ModuleData.W16Data.Image != NULL);
|
|
}
|
|
}
|
|
__finally {
|
|
if (fileHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (fileHandle);
|
|
}
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
CloseHandle (fileHandle);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
MdLoadModuleDataW (
|
|
IN PCWSTR ModuleName,
|
|
OUT PMD_MODULE_IMAGE ModuleImage
|
|
)
|
|
{
|
|
PCSTR moduleNameA;
|
|
HANDLE fileHandle;
|
|
DWORD bytesRead;
|
|
DOS_HEADER dh;
|
|
DWORD sign;
|
|
PWORD signNE = (PWORD)&sign;
|
|
BOOL result = FALSE;
|
|
|
|
ZeroMemory (ModuleImage, sizeof (MD_MODULE_IMAGE));
|
|
|
|
fileHandle = CreateFileW (ModuleName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
ModuleImage->ModuleType = MODULETYPE_UNKNOWN;
|
|
return FALSE;
|
|
}
|
|
__try {
|
|
__try {
|
|
if ((!ReadFile (fileHandle, &dh, sizeof (DOS_HEADER), &bytesRead, NULL)) ||
|
|
(bytesRead != sizeof (DOS_HEADER))
|
|
) {
|
|
__leave;
|
|
}
|
|
result = TRUE;
|
|
if (dh.e_magic != IMAGE_DOS_SIGNATURE) {
|
|
ModuleImage->ModuleType = MODULETYPE_UNKNOWN;
|
|
__leave;
|
|
}
|
|
ModuleImage->ModuleType = MODULETYPE_DOS;
|
|
|
|
if (SetFilePointer (fileHandle, dh.e_lfanew, NULL, FILE_BEGIN) != (DWORD)dh.e_lfanew) {
|
|
__leave;
|
|
}
|
|
if ((!ReadFile (fileHandle, &sign, sizeof (DWORD), &bytesRead, NULL)) ||
|
|
(bytesRead != sizeof (DWORD))
|
|
) {
|
|
__leave;
|
|
}
|
|
CloseHandle (fileHandle);
|
|
fileHandle = INVALID_HANDLE_VALUE;
|
|
|
|
if (sign == IMAGE_PE_SIGNATURE) {
|
|
ModuleImage->ModuleType = MODULETYPE_WIN32;
|
|
moduleNameA = ConvertWtoA (ModuleName);
|
|
if (moduleNameA) {
|
|
result = MapAndLoad ((PSTR) moduleNameA, NULL, &ModuleImage->ModuleData.W32Data.Image, FALSE, TRUE);
|
|
FreeConvertedStr (moduleNameA);
|
|
}
|
|
}
|
|
if (*signNE == IMAGE_NE_SIGNATURE) {
|
|
ModuleImage->ModuleType = MODULETYPE_WIN16;
|
|
ModuleImage->ModuleData.W16Data.Image = MapFileIntoMemoryW (
|
|
ModuleName,
|
|
&ModuleImage->ModuleData.W16Data.FileHandle,
|
|
&ModuleImage->ModuleData.W16Data.MapHandle
|
|
);
|
|
result = (ModuleImage->ModuleData.W16Data.Image != NULL);
|
|
}
|
|
}
|
|
__finally {
|
|
if (fileHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (fileHandle);
|
|
}
|
|
}
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER) {
|
|
CloseHandle (fileHandle);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
MdUnloadModuleDataA (
|
|
IN OUT PMD_MODULE_IMAGE ModuleImage
|
|
)
|
|
{
|
|
switch (ModuleImage->ModuleType) {
|
|
case MODULETYPE_WIN32:
|
|
UnMapAndLoad (&ModuleImage->ModuleData.W32Data.Image);
|
|
break;
|
|
case MODULETYPE_WIN16:
|
|
UnmapFile (
|
|
(PVOID) ModuleImage->ModuleData.W16Data.Image,
|
|
ModuleImage->ModuleData.W16Data.FileHandle,
|
|
ModuleImage->ModuleData.W16Data.MapHandle
|
|
);
|
|
break;
|
|
default:;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
MdUnloadModuleDataW (
|
|
IN OUT PMD_MODULE_IMAGE ModuleImage
|
|
)
|
|
{
|
|
switch (ModuleImage->ModuleType) {
|
|
case MODULETYPE_WIN32:
|
|
UnMapAndLoad (&ModuleImage->ModuleData.W32Data.Image);
|
|
break;
|
|
case MODULETYPE_WIN16:
|
|
UnmapFile (
|
|
(PVOID) ModuleImage->ModuleData.W16Data.Image,
|
|
ModuleImage->ModuleData.W16Data.FileHandle,
|
|
ModuleImage->ModuleData.W16Data.MapHandle
|
|
);
|
|
break;
|
|
default:;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
MdEnumNextImport16A (
|
|
IN OUT PMD_IMPORT_ENUM16A ImportsEnum
|
|
)
|
|
{
|
|
PBYTE currSegmentOffset,importPtr;
|
|
PWORD moduleNameOffset;
|
|
BOOL itemFound;
|
|
PMD_IMPORT_ENUM16_HANDLE handle;
|
|
|
|
handle = (PMD_IMPORT_ENUM16_HANDLE) ImportsEnum->Handle;
|
|
|
|
handle->RelocItem ++;
|
|
handle->CurrRelocItem ++;
|
|
|
|
itemFound = FALSE;
|
|
|
|
while ((handle->CurrSegEntry <= handle->NeHeader->NumEntriesSegTable) && (!itemFound)) {
|
|
|
|
if (((handle->SegmentEntry->SegmentFlags & SEG_CODE_MASK ) == SEG_CODE ) &&
|
|
((handle->SegmentEntry->SegmentFlags & SEG_RELOC_MASK ) == SEG_RELOC ) &&
|
|
((handle->SegmentEntry->SegmentFlags & SEG_PRELOAD_MASK) == SEG_PRELOAD)
|
|
) {
|
|
__try {
|
|
|
|
while ((handle->CurrRelocItem <= *(handle->CurrNrReloc)) && (!itemFound)) {
|
|
|
|
if (((handle->RelocItem->AddressType == 0) ||
|
|
(handle->RelocItem->AddressType == 2) ||
|
|
(handle->RelocItem->AddressType == 3) ||
|
|
(handle->RelocItem->AddressType == 5) ||
|
|
(handle->RelocItem->AddressType == 11) ||
|
|
(handle->RelocItem->AddressType == 13)
|
|
) &&
|
|
((handle->RelocItem->RelocType == RELOC_IMPORTED_ORDINAL) ||
|
|
(handle->RelocItem->RelocType == RELOC_IMPORTED_NAME )
|
|
)
|
|
) {
|
|
itemFound = TRUE;
|
|
moduleNameOffset = (PWORD) (handle->Image +
|
|
handle->DosHeader->e_lfanew +
|
|
handle->NeHeader->ModuleTableOffset +
|
|
(handle->RelocItem->ModuleOffset - 1) * sizeof (WORD));
|
|
importPtr = handle->Image +
|
|
handle->DosHeader->e_lfanew +
|
|
handle->NeHeader->ImportedTableOffset +
|
|
*moduleNameOffset;
|
|
strncpy (ImportsEnum->ImportModule, importPtr + 1, (BYTE)importPtr[0]);
|
|
ImportsEnum->ImportModule[(BYTE)importPtr[0]] = 0;
|
|
|
|
if (handle->RelocItem->RelocType == RELOC_IMPORTED_ORDINAL) {
|
|
ImportsEnum->ImportFunction[0] = 0;
|
|
ImportsEnum->ImportFunctionOrd = handle->RelocItem->FunctionOffset;
|
|
}
|
|
else {
|
|
importPtr = handle->Image +
|
|
handle->DosHeader->e_lfanew +
|
|
handle->NeHeader->ImportedTableOffset +
|
|
handle->RelocItem->FunctionOffset;
|
|
strncpy (ImportsEnum->ImportFunction, importPtr + 1, (BYTE)importPtr[0]);
|
|
ImportsEnum->ImportFunction[(BYTE)importPtr[0]] = 0;
|
|
ImportsEnum->ImportFunctionOrd = 0;
|
|
}
|
|
}
|
|
|
|
if (!itemFound) {
|
|
handle->RelocItem ++;
|
|
handle->CurrRelocItem ++;
|
|
}
|
|
}
|
|
}
|
|
__except (1) {
|
|
itemFound = FALSE;
|
|
}
|
|
}
|
|
if (!itemFound) {
|
|
handle->SegmentEntry ++;
|
|
handle->CurrSegEntry ++;
|
|
|
|
currSegmentOffset = handle->Image +
|
|
(handle->SegmentEntry->SegmentOffset << handle->NeHeader->ShiftCount);
|
|
if (handle->SegmentEntry->SegmentLen == 0) {
|
|
currSegmentOffset += 65535;
|
|
}
|
|
else {
|
|
currSegmentOffset += handle->SegmentEntry->SegmentLen;
|
|
}
|
|
handle->CurrNrReloc = (PWORD) currSegmentOffset;
|
|
currSegmentOffset += sizeof(WORD);
|
|
|
|
handle->RelocItem = (PNE_RELOC_ITEM) currSegmentOffset;
|
|
|
|
handle->CurrRelocItem = 1;
|
|
}
|
|
}
|
|
return itemFound;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MdEnumFirstImport16A (
|
|
IN PBYTE ModuleImage,
|
|
IN OUT PMD_IMPORT_ENUM16A ImportsEnum
|
|
)
|
|
{
|
|
PMD_IMPORT_ENUM16_HANDLE handle;
|
|
PBYTE currSegmentOffset;
|
|
|
|
ZeroMemory (ImportsEnum, sizeof (MD_IMPORT_ENUM16A));
|
|
|
|
ImportsEnum->Handle = MemAlloc (g_hHeap, 0, sizeof (MD_IMPORT_ENUM16_HANDLE));
|
|
|
|
handle = (PMD_IMPORT_ENUM16_HANDLE) ImportsEnum->Handle;
|
|
|
|
handle->Image = ModuleImage;
|
|
|
|
handle->DosHeader = (PDOS_HEADER) (handle->Image);
|
|
handle->NeHeader = (PNE_HEADER) (handle->Image + handle->DosHeader->e_lfanew);
|
|
|
|
handle->SegmentEntry = (PNE_SEGMENT_ENTRY) (handle->Image +
|
|
handle->DosHeader->e_lfanew +
|
|
handle->NeHeader->SegTableOffset
|
|
);
|
|
handle->CurrSegEntry = 1;
|
|
|
|
currSegmentOffset = handle->Image +
|
|
(handle->SegmentEntry->SegmentOffset << handle->NeHeader->ShiftCount);
|
|
if (handle->SegmentEntry->SegmentLen == 0) {
|
|
currSegmentOffset += 65535;
|
|
}
|
|
else {
|
|
currSegmentOffset += handle->SegmentEntry->SegmentLen;
|
|
}
|
|
handle->CurrNrReloc = (PWORD) currSegmentOffset;
|
|
currSegmentOffset += sizeof(WORD);
|
|
|
|
handle->RelocItem = (PNE_RELOC_ITEM) currSegmentOffset;
|
|
|
|
handle->CurrRelocItem = 1;
|
|
|
|
handle->RelocItem --;
|
|
handle->CurrRelocItem --;
|
|
|
|
return MdEnumNextImport16A (ImportsEnum);
|
|
}
|
|
|
|
BOOL
|
|
MdAbortImport16EnumA (
|
|
IN PMD_IMPORT_ENUM16A ImportsEnum
|
|
)
|
|
{
|
|
if (ImportsEnum->Handle) {
|
|
MemFree (g_hHeap, 0, ImportsEnum->Handle);
|
|
ImportsEnum->Handle = NULL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
MdEnumNextImportFunction32A (
|
|
IN OUT PMD_IMPORT_ENUM32A ImportsEnum
|
|
)
|
|
{
|
|
PMD_IMPORT_ENUM32_HANDLE handle;
|
|
|
|
handle = (PMD_IMPORT_ENUM32_HANDLE) ImportsEnum->Handle;
|
|
|
|
if (handle->ImportFunctionAddr == 0) {
|
|
return FALSE;
|
|
}
|
|
handle->ImageData = (PIMAGE_THUNK_DATA)
|
|
ImageRvaToVa (
|
|
handle->Image->FileHeader,
|
|
handle->Image->MappedAddress,
|
|
handle->ImportFunctionAddr,
|
|
NULL
|
|
);
|
|
|
|
if (handle->ImageData->u1.AddressOfData) {
|
|
handle->ImageName = (PIMAGE_IMPORT_BY_NAME)
|
|
ImageRvaToVa (
|
|
handle->Image->FileHeader,
|
|
handle->Image->MappedAddress,
|
|
(DWORD)handle->ImageData->u1.AddressOfData,
|
|
NULL
|
|
);
|
|
|
|
if (handle->ImageName) { //import by name
|
|
|
|
ImportsEnum->ImportFunction = handle->ImageName->Name;
|
|
ImportsEnum->ImportFunctionOrd = 0;
|
|
}
|
|
else { //import by number
|
|
|
|
ImportsEnum->ImportFunction = NULL;
|
|
ImportsEnum->ImportFunctionOrd = (ULONG) handle->ImageData->u1.Ordinal & (~0x80000000);
|
|
}
|
|
handle->ImportFunctionAddr += 4;
|
|
return TRUE;
|
|
}
|
|
else {
|
|
handle->ImportFunctionAddr = 0;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
MdEnumFirstImportFunction32A (
|
|
IN OUT PMD_IMPORT_ENUM32A ImportsEnum
|
|
)
|
|
{
|
|
PMD_IMPORT_ENUM32_HANDLE handle;
|
|
|
|
handle = (PMD_IMPORT_ENUM32_HANDLE) ImportsEnum->Handle;
|
|
|
|
if ((handle->ImageDescriptor == NULL) ||
|
|
(ImportsEnum->ImportModule == NULL)
|
|
) {
|
|
return FALSE;
|
|
}
|
|
handle->ImportFunctionAddr = handle->ImageDescriptor->OriginalFirstThunk;
|
|
|
|
return MdEnumNextImportFunction32A (ImportsEnum);
|
|
}
|
|
|
|
BOOL
|
|
MdEnumNextImportModule32A (
|
|
IN OUT PMD_IMPORT_ENUM32A ImportsEnum
|
|
)
|
|
{
|
|
PMD_IMPORT_ENUM32_HANDLE handle;
|
|
|
|
handle = (PMD_IMPORT_ENUM32_HANDLE) ImportsEnum->Handle;
|
|
|
|
if (handle->ImageDescriptor == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
handle->ImageDescriptor ++;
|
|
|
|
if (handle->ImageDescriptor->Name == 0) {
|
|
return FALSE;
|
|
}
|
|
ImportsEnum->ImportModule = (PCSTR)
|
|
ImageRvaToVa (
|
|
handle->Image->FileHeader,
|
|
handle->Image->MappedAddress,
|
|
handle->ImageDescriptor->Name,
|
|
NULL
|
|
);
|
|
return (ImportsEnum->ImportModule != NULL);
|
|
}
|
|
|
|
BOOL
|
|
MdEnumFirstImportModule32A (
|
|
IN PLOADED_IMAGE ModuleImage,
|
|
IN OUT PMD_IMPORT_ENUM32A ImportsEnum
|
|
)
|
|
{
|
|
PMD_IMPORT_ENUM32_HANDLE handle;
|
|
ULONG imageSize;
|
|
|
|
ZeroMemory (ImportsEnum, sizeof (MD_IMPORT_ENUM32A));
|
|
|
|
ImportsEnum->Handle = MemAlloc (g_hHeap, 0, sizeof (MD_IMPORT_ENUM32_HANDLE));
|
|
|
|
handle = (PMD_IMPORT_ENUM32_HANDLE) ImportsEnum->Handle;
|
|
|
|
handle->Image = ModuleImage;
|
|
|
|
handle->ImageDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)
|
|
ImageDirectoryEntryToData (
|
|
ModuleImage->MappedAddress,
|
|
FALSE,
|
|
IMAGE_DIRECTORY_ENTRY_IMPORT,
|
|
&imageSize
|
|
);
|
|
if (!handle->ImageDescriptor) {
|
|
DEBUGMSGA((DBG_WARNING, DBG_MODIMAGE":Cannot load import directory for %s", ModuleImage->ModuleName));
|
|
return FALSE;
|
|
}
|
|
if (handle->ImageDescriptor->Name == 0) {
|
|
return FALSE;
|
|
}
|
|
ImportsEnum->ImportModule = (PCSTR)
|
|
ImageRvaToVa (
|
|
handle->Image->FileHeader,
|
|
handle->Image->MappedAddress,
|
|
handle->ImageDescriptor->Name,
|
|
NULL
|
|
);
|
|
return (ImportsEnum->ImportModule != NULL);
|
|
}
|
|
|
|
BOOL
|
|
MdAbortImport32EnumA (
|
|
IN PMD_IMPORT_ENUM32A ImportsEnum
|
|
)
|
|
{
|
|
if (ImportsEnum->Handle) {
|
|
MemFree (g_hHeap, 0, ImportsEnum->Handle);
|
|
ImportsEnum->Handle = NULL;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD
|
|
MdGetModuleTypeA (
|
|
IN PCSTR ModuleName
|
|
)
|
|
{
|
|
MD_MODULE_IMAGE moduleImage;
|
|
DWORD result = MODULETYPE_UNKNOWN;
|
|
|
|
__try {
|
|
if (!MdLoadModuleDataA (ModuleName, &moduleImage)) {
|
|
DEBUGMSGA((DBG_WARNING, DBG_MODIMAGE":Cannot load image for %s. Error:%ld", ModuleName, GetLastError()));
|
|
__leave;
|
|
}
|
|
result = moduleImage.ModuleType;
|
|
}
|
|
__finally {
|
|
MdUnloadModuleDataA (&moduleImage);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
MdGetModuleTypeW (
|
|
IN PCWSTR ModuleName
|
|
)
|
|
{
|
|
MD_MODULE_IMAGE moduleImage;
|
|
DWORD result = MODULETYPE_UNKNOWN;
|
|
|
|
__try {
|
|
if (!MdLoadModuleDataW (ModuleName, &moduleImage)) {
|
|
DEBUGMSGW((DBG_WARNING, DBG_MODIMAGE":Cannot load image for %s. Error:%ld", ModuleName, GetLastError()));
|
|
__leave;
|
|
}
|
|
result = moduleImage.ModuleType;
|
|
}
|
|
__finally {
|
|
MdUnloadModuleDataW (&moduleImage);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PCSTR
|
|
MdGet16ModuleDescriptionA (
|
|
IN PCSTR ModuleName
|
|
)
|
|
{
|
|
MD_MODULE_IMAGE moduleImage;
|
|
PSTR result = NULL;
|
|
|
|
PDOS_HEADER dosHeader;
|
|
PNE_HEADER neHeader;
|
|
PBYTE size;
|
|
|
|
__try {
|
|
if (!MdLoadModuleDataA (ModuleName, &moduleImage)) {
|
|
DEBUGMSGA((DBG_WARNING, DBG_MODIMAGE":Cannot load image for %s. Error:%ld", ModuleName, GetLastError()));
|
|
__leave;
|
|
}
|
|
if (moduleImage.ModuleType != MODULETYPE_WIN16) {
|
|
__leave;
|
|
}
|
|
__try {
|
|
dosHeader = (PDOS_HEADER) (moduleImage.ModuleData.W16Data.Image);
|
|
neHeader = (PNE_HEADER) (moduleImage.ModuleData.W16Data.Image + dosHeader->e_lfanew);
|
|
size = (PBYTE) (moduleImage.ModuleData.W16Data.Image + neHeader->NonResNameTableOffset);
|
|
if (*size == 0) {
|
|
__leave;
|
|
}
|
|
result = AllocPathStringA (*size + 1);
|
|
strncpy (result, moduleImage.ModuleData.W16Data.Image + neHeader->NonResNameTableOffset + 1, *size);
|
|
result [*size] = 0;
|
|
}
|
|
__except (1) {
|
|
DEBUGMSGA((DBG_WARNING, DBG_MODIMAGE":Access violation while examining %s.", ModuleName));
|
|
if (result != NULL) {
|
|
FreePathStringA (result);
|
|
result = NULL;
|
|
}
|
|
__leave;
|
|
}
|
|
}
|
|
__finally {
|
|
MdUnloadModuleDataA (&moduleImage);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PCWSTR
|
|
MdGet16ModuleDescriptionW (
|
|
IN PCWSTR ModuleName
|
|
)
|
|
{
|
|
MD_MODULE_IMAGE moduleImage;
|
|
PSTR resultA = NULL;
|
|
PCWSTR tempResult = NULL;
|
|
PCWSTR result = NULL;
|
|
|
|
PDOS_HEADER dosHeader;
|
|
PNE_HEADER neHeader;
|
|
PBYTE size;
|
|
|
|
__try {
|
|
if (!MdLoadModuleDataW (ModuleName, &moduleImage)) {
|
|
DEBUGMSGW((DBG_WARNING, DBG_MODIMAGE":Cannot load image for %s. Error:%ld", ModuleName, GetLastError()));
|
|
__leave;
|
|
}
|
|
if (moduleImage.ModuleType != MODULETYPE_WIN16) {
|
|
__leave;
|
|
}
|
|
__try {
|
|
dosHeader = (PDOS_HEADER) (moduleImage.ModuleData.W16Data.Image);
|
|
neHeader = (PNE_HEADER) (moduleImage.ModuleData.W16Data.Image + dosHeader->e_lfanew);
|
|
size = (PBYTE) (moduleImage.ModuleData.W16Data.Image + neHeader->NonResNameTableOffset);
|
|
if (*size == 0) {
|
|
__leave;
|
|
}
|
|
resultA = AllocPathStringA (*size + 1);
|
|
if (resultA) {
|
|
strncpy (resultA, moduleImage.ModuleData.W16Data.Image + neHeader->NonResNameTableOffset + 1, *size);
|
|
resultA [*size] = 0;
|
|
tempResult = ConvertAtoW (resultA);
|
|
if (tempResult) {
|
|
result = DuplicatePathStringW (tempResult, 0);
|
|
FreeConvertedStr (tempResult);
|
|
tempResult = NULL;
|
|
}
|
|
FreePathStringA (resultA);
|
|
resultA = NULL;
|
|
}
|
|
}
|
|
__except (1) {
|
|
DEBUGMSGA((DBG_WARNING, DBG_MODIMAGE":Access violation while examining %s.", ModuleName));
|
|
if (result != NULL) {
|
|
FreePathStringW (result);
|
|
result = NULL;
|
|
}
|
|
if (tempResult != NULL) {
|
|
FreeConvertedStr (tempResult);
|
|
tempResult = NULL;
|
|
}
|
|
if (resultA != NULL) {
|
|
FreePathStringA (resultA);
|
|
resultA = NULL;
|
|
}
|
|
__leave;
|
|
}
|
|
}
|
|
__finally {
|
|
MdUnloadModuleDataW (&moduleImage);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
PIMAGE_NT_HEADERS
|
|
pGetImageNtHeader (
|
|
IN PVOID Base
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function returns the address of the NT Header.
|
|
|
|
Arguments:
|
|
|
|
Base - Supplies the base of the image.
|
|
|
|
Return Value:
|
|
|
|
Returns the address of the NT Header.
|
|
|
|
--*/
|
|
|
|
{
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
|
|
if (Base != NULL && Base != (PVOID)-1) {
|
|
if (((PIMAGE_DOS_HEADER)Base)->e_magic == IMAGE_DOS_SIGNATURE) {
|
|
NtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew);
|
|
if (NtHeaders->Signature == IMAGE_NT_SIGNATURE) {
|
|
return NtHeaders;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ULONG
|
|
MdGetPECheckSumA (
|
|
IN PCSTR ModuleName
|
|
)
|
|
{
|
|
MD_MODULE_IMAGE moduleImage;
|
|
ULONG result = 0;
|
|
PIMAGE_NT_HEADERS NtHeaders;
|
|
|
|
__try {
|
|
if (!MdLoadModuleDataA (ModuleName, &moduleImage)) {
|
|
DEBUGMSGA((DBG_WARNING, DBG_MODIMAGE":Cannot load image for %s. Error:%ld", ModuleName, GetLastError()));
|
|
__leave;
|
|
}
|
|
if (moduleImage.ModuleType != MODULETYPE_WIN32) {
|
|
__leave;
|
|
}
|
|
__try {
|
|
NtHeaders = pGetImageNtHeader(moduleImage.ModuleData.W32Data.Image.MappedAddress);
|
|
if (NtHeaders) {
|
|
if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
|
result = ((PIMAGE_NT_HEADERS32)NtHeaders)->OptionalHeader.CheckSum;
|
|
} else
|
|
if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
|
|
result = ((PIMAGE_NT_HEADERS64)NtHeaders)->OptionalHeader.CheckSum;
|
|
}
|
|
}
|
|
}
|
|
__except (1) {
|
|
DEBUGMSGA((DBG_WARNING, DBG_MODIMAGE":Access violation while examining %s.", ModuleName));
|
|
result = 0;
|
|
__leave;
|
|
}
|
|
}
|
|
__finally {
|
|
MdUnloadModuleDataA (&moduleImage);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
MdGetCheckSumA (
|
|
IN PCSTR ModuleName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetCheckSum will compute the check sum for 4096 bytes starting at offset 512. The offset and the size of
|
|
the chunk are modified if the file size is too small.
|
|
|
|
Arguments:
|
|
|
|
ModuleName - Specifies the file to compute the check sum for.
|
|
|
|
Return value:
|
|
|
|
The computed checksum
|
|
|
|
--*/
|
|
{
|
|
INT i,size = 4096;
|
|
DWORD startAddr = 512;
|
|
HANDLE fileHandle = INVALID_HANDLE_VALUE;
|
|
PCHAR buffer = NULL;
|
|
DWORD checkSum = 0;
|
|
DWORD dontCare;
|
|
WIN32_FIND_DATAA findData;
|
|
|
|
if (!DoesFileExistExA (ModuleName, &findData)) {
|
|
return checkSum;
|
|
}
|
|
|
|
if (findData.nFileSizeLow < (ULONG)size) {
|
|
//
|
|
// File size is less than 4096. We set the start address to 0 and set the size for the checksum
|
|
// to the actual file size.
|
|
//
|
|
startAddr = 0;
|
|
size = findData.nFileSizeLow;
|
|
}
|
|
else
|
|
if (startAddr + size > findData.nFileSizeLow) {
|
|
//
|
|
// File size is too small. We set the start address so that size of checksum can be 4096 bytes
|
|
//
|
|
startAddr = findData.nFileSizeLow - size;
|
|
}
|
|
if (size <= 3) {
|
|
//
|
|
// we need at least 3 bytes to be able to do something here.
|
|
//
|
|
return 0;
|
|
}
|
|
__try {
|
|
buffer = HeapAlloc (g_hHeap, 0, size);
|
|
if (buffer == NULL) {
|
|
__leave;
|
|
}
|
|
fileHandle = CreateFileA (ModuleName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
__leave;
|
|
}
|
|
|
|
if (SetFilePointer (fileHandle, startAddr, NULL, FILE_BEGIN) != startAddr) {
|
|
__leave;
|
|
}
|
|
|
|
if (!ReadFile (fileHandle, buffer, size, &dontCare, NULL)) {
|
|
__leave;
|
|
}
|
|
for (i = 0; i<(size - 3); i+=4) {
|
|
checkSum += *((PDWORD) (buffer + i));
|
|
checkSum = _rotr (checkSum ,1);
|
|
}
|
|
}
|
|
__finally {
|
|
if (fileHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (fileHandle);
|
|
}
|
|
if (buffer != NULL) {
|
|
HeapFree (g_hHeap, 0, buffer);
|
|
}
|
|
}
|
|
return checkSum;
|
|
}
|
|
|
|
DWORD
|
|
MdGetCheckSumW (
|
|
IN PCWSTR ModuleName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetCheckSum will compute the check sum for 4096 bytes starting at offset 512. The offset and the size of
|
|
the chunk are modified if the file size is too small.
|
|
|
|
Arguments:
|
|
|
|
ModuleName - Specifies the file to compute the check sum for.
|
|
|
|
Return value:
|
|
|
|
The computed checksum
|
|
|
|
--*/
|
|
{
|
|
INT i,size = 4096;
|
|
DWORD startAddr = 512;
|
|
HANDLE fileHandle = INVALID_HANDLE_VALUE;
|
|
PCHAR buffer = NULL;
|
|
DWORD checkSum = 0;
|
|
DWORD dontCare;
|
|
WIN32_FIND_DATAW findData;
|
|
|
|
if (!DoesFileExistExW (ModuleName, &findData)) {
|
|
return checkSum;
|
|
}
|
|
|
|
if (findData.nFileSizeLow < (ULONG)size) {
|
|
//
|
|
// File size is less than 4096. We set the start address to 0 and set the size for the checksum
|
|
// to the actual file size.
|
|
//
|
|
startAddr = 0;
|
|
size = findData.nFileSizeLow;
|
|
}
|
|
else
|
|
if (startAddr + size > findData.nFileSizeLow) {
|
|
//
|
|
// File size is too small. We set the start address so that size of checksum can be 4096 bytes
|
|
//
|
|
startAddr = findData.nFileSizeLow - size;
|
|
}
|
|
if (size <= 3) {
|
|
//
|
|
// we need at least 3 bytes to be able to do something here.
|
|
//
|
|
return 0;
|
|
}
|
|
__try {
|
|
buffer = HeapAlloc (g_hHeap, 0, size);
|
|
if (buffer == NULL) {
|
|
__leave;
|
|
}
|
|
fileHandle = CreateFileW (ModuleName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
__leave;
|
|
}
|
|
|
|
if (SetFilePointer (fileHandle, startAddr, NULL, FILE_BEGIN) != startAddr) {
|
|
__leave;
|
|
}
|
|
|
|
if (!ReadFile (fileHandle, buffer, size, &dontCare, NULL)) {
|
|
__leave;
|
|
}
|
|
for (i = 0; i<(size - 3); i+=4) {
|
|
checkSum += *((PDWORD) (buffer + i));
|
|
checkSum = _rotr (checkSum ,1);
|
|
}
|
|
}
|
|
__finally {
|
|
if (fileHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (fileHandle);
|
|
}
|
|
if (buffer != NULL) {
|
|
HeapFree (g_hHeap, 0, buffer);
|
|
}
|
|
}
|
|
return checkSum;
|
|
}
|
|
|
|
VOID
|
|
DestroyAnsiResourceId (
|
|
IN PCSTR AnsiId
|
|
)
|
|
{
|
|
if (HIWORD (AnsiId)) {
|
|
FreeConvertedStr (AnsiId);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DestroyUnicodeResourceId (
|
|
IN PCWSTR UnicodeId
|
|
)
|
|
{
|
|
if (HIWORD (UnicodeId)) {
|
|
FreeConvertedStr (UnicodeId);
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
NeLoadHeader (
|
|
IN HANDLE File,
|
|
OUT PNE_INFO_BLOCK Header
|
|
)
|
|
{
|
|
DOS_HEADER dh;
|
|
LONG rc = ERROR_BAD_FORMAT;
|
|
BOOL b = FALSE;
|
|
|
|
__try {
|
|
SetFilePointer (File, 0, NULL, FILE_BEGIN);
|
|
if (!BfReadFile (File, (PBYTE)(&dh), sizeof (DOS_HEADER))) {
|
|
__leave;
|
|
}
|
|
|
|
if (dh.e_magic != ('M' + 'Z' * 256)) {
|
|
__leave;
|
|
}
|
|
|
|
SetFilePointer (File, dh.e_lfanew, NULL, FILE_BEGIN);
|
|
if (!BfReadFile (File, (PBYTE)Header, sizeof (NE_INFO_BLOCK))) {
|
|
__leave;
|
|
}
|
|
|
|
if (Header->Signature != ('N' + 'E' * 256) &&
|
|
Header->Signature != ('L' + 'E' * 256)
|
|
) {
|
|
if (Header->Signature == ('P' + 'E' * 256)) {
|
|
rc = ERROR_BAD_EXE_FORMAT;
|
|
} else {
|
|
rc = ERROR_INVALID_EXE_SIGNATURE;
|
|
}
|
|
|
|
DEBUGMSG ((DBG_NAUSEA, "Header signature is %c%c", Header->Signature & 0xff, Header->Signature >> 8));
|
|
__leave;
|
|
}
|
|
|
|
SetFilePointer (File, (DWORD) dh.e_lfanew, NULL, FILE_BEGIN);
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
if (!b) {
|
|
SetLastError (rc);
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
DWORD
|
|
pComputeSizeOfTypeInfo (
|
|
IN PNE_RES_TYPEINFO TypeInfo
|
|
)
|
|
{
|
|
return sizeof (NE_RES_TYPEINFO) + TypeInfo->ResourceCount * sizeof (NE_RES_NAMEINFO);
|
|
}
|
|
|
|
PNE_RES_TYPEINFO
|
|
pReadNextTypeInfoStruct (
|
|
IN HANDLE File,
|
|
IN PMHANDLE Pool
|
|
)
|
|
{
|
|
WORD Type;
|
|
WORD ResCount;
|
|
NE_RES_TYPEINFO TypeInfo;
|
|
PNE_RES_TYPEINFO ReturnInfo = NULL;
|
|
DWORD Size;
|
|
|
|
if (!BfReadFile (File, (PBYTE)(&Type), sizeof (WORD))) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!Type) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!BfReadFile (File, (PBYTE)(&ResCount), sizeof (WORD))) {
|
|
return NULL;
|
|
}
|
|
|
|
TypeInfo.TypeId = Type;
|
|
TypeInfo.ResourceCount = ResCount;
|
|
|
|
if (!BfReadFile (File, (PBYTE)(&TypeInfo.Reserved), sizeof (DWORD))) {
|
|
return NULL;
|
|
}
|
|
|
|
Size = sizeof (NE_RES_NAMEINFO) * ResCount;
|
|
|
|
ReturnInfo = (PNE_RES_TYPEINFO) PmGetMemory (Pool, Size + sizeof (TypeInfo));
|
|
if (!ReturnInfo) {
|
|
return NULL;
|
|
}
|
|
|
|
CopyMemory (ReturnInfo, &TypeInfo, sizeof (TypeInfo));
|
|
|
|
if (!BfReadFile (File, (PBYTE) ReturnInfo + sizeof (TypeInfo), Size)) {
|
|
return NULL;
|
|
}
|
|
|
|
return ReturnInfo;
|
|
}
|
|
|
|
BOOL
|
|
pReadTypeInfoArray (
|
|
IN HANDLE File,
|
|
IN OUT PGROWLIST TypeInfoList
|
|
)
|
|
{
|
|
PNE_RES_TYPEINFO TypeInfo;
|
|
DWORD Size;
|
|
PMHANDLE TempPool;
|
|
BOOL b = FALSE;
|
|
|
|
TempPool = PmCreatePool();
|
|
if (!TempPool) {
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
|
|
TypeInfo = pReadNextTypeInfoStruct (File, TempPool);
|
|
while (TypeInfo) {
|
|
Size = pComputeSizeOfTypeInfo (TypeInfo);
|
|
if (!GlAppend (TypeInfoList, (PBYTE) TypeInfo, Size)) {
|
|
__leave;
|
|
}
|
|
|
|
TypeInfo = pReadNextTypeInfoStruct (File, TempPool);
|
|
}
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
|
|
PmDestroyPool (TempPool);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
pReadStringArrayA (
|
|
IN HANDLE File,
|
|
IN OUT PGROWLIST GrowList
|
|
)
|
|
{
|
|
BYTE Size;
|
|
CHAR Name[256];
|
|
|
|
if (!BfReadFile (File, (PBYTE)(&Size), sizeof (BYTE))) {
|
|
return FALSE;
|
|
}
|
|
|
|
while (Size) {
|
|
|
|
if (!BfReadFile (File, Name, (DWORD) Size)) {
|
|
return FALSE;
|
|
}
|
|
|
|
Name[Size] = 0;
|
|
|
|
GlAppendStringA (GrowList, Name);
|
|
|
|
if (!BfReadFile (File, (PBYTE)(&Size), sizeof (BYTE))) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
NeLoadResources (
|
|
IN HANDLE File,
|
|
OUT PNE_RESOURCES Resources
|
|
)
|
|
{
|
|
NE_INFO_BLOCK Header;
|
|
|
|
ZeroMemory (Resources, sizeof (NE_RESOURCES));
|
|
|
|
if (!NeLoadHeader (File, &Header)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Read in NE_RESOURCES struct
|
|
//
|
|
|
|
SetFilePointer (File, (DWORD) Header.OffsetToResourceTable, NULL, FILE_CURRENT);
|
|
|
|
if (!BfReadFile (File, (PBYTE)(&Resources->AlignShift), sizeof (WORD))) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Array of NE_RES_TYPEINFO structs
|
|
if (!pReadTypeInfoArray (File, &Resources->TypeInfoArray)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Resource names
|
|
if (!pReadStringArrayA (File, &Resources->ResourceNames)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
NeFreeResources (
|
|
PNE_RESOURCES Resources
|
|
)
|
|
{
|
|
GlFree (&Resources->TypeInfoArray);
|
|
GlFree (&Resources->ResourceNames);
|
|
|
|
ZeroMemory (Resources, sizeof (NE_RESOURCES));
|
|
}
|
|
|
|
HANDLE
|
|
NeOpenFileA (
|
|
PCSTR FileName
|
|
)
|
|
{
|
|
PNE_HANDLE NeHandle;
|
|
BOOL b = FALSE;
|
|
|
|
NeHandle = (PNE_HANDLE) MemAlloc (g_hHeap, HEAP_ZERO_MEMORY, sizeof (NE_HANDLE));
|
|
|
|
__try {
|
|
|
|
NeHandle->ResourcePool = PmCreatePool();
|
|
if (!NeHandle->ResourcePool) {
|
|
__leave;
|
|
}
|
|
|
|
NeHandle->File = CreateFileA (
|
|
FileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if (NeHandle->File == INVALID_HANDLE_VALUE) {
|
|
__leave;
|
|
}
|
|
|
|
if (!NeLoadHeader (NeHandle->File, &NeHandle->Header)) {
|
|
__leave;
|
|
}
|
|
|
|
NeHandle->HeaderOffset = SetFilePointer (NeHandle->File, 0, NULL, FILE_CURRENT);
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
if (!b) {
|
|
PushError();
|
|
|
|
if (NeHandle->ResourcePool) {
|
|
PmDestroyPool (NeHandle->ResourcePool);
|
|
}
|
|
|
|
if (NeHandle->File != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (NeHandle->File);
|
|
}
|
|
|
|
MemFree (g_hHeap, 0, NeHandle);
|
|
NeHandle = NULL;
|
|
|
|
PopError();
|
|
}
|
|
}
|
|
|
|
return (HANDLE) NeHandle;
|
|
}
|
|
|
|
HANDLE
|
|
NeOpenFileW (
|
|
PCWSTR FileName
|
|
)
|
|
{
|
|
PNE_HANDLE NeHandle;
|
|
BOOL b = FALSE;
|
|
|
|
NeHandle = (PNE_HANDLE) MemAlloc (g_hHeap, HEAP_ZERO_MEMORY, sizeof (NE_HANDLE));
|
|
|
|
__try {
|
|
|
|
NeHandle->ResourcePool = PmCreatePool();
|
|
if (!NeHandle->ResourcePool) {
|
|
__leave;
|
|
}
|
|
|
|
NeHandle->File = CreateFileW (
|
|
FileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if (NeHandle->File == INVALID_HANDLE_VALUE) {
|
|
__leave;
|
|
}
|
|
|
|
if (!NeLoadHeader (NeHandle->File, &NeHandle->Header)) {
|
|
__leave;
|
|
}
|
|
|
|
NeHandle->HeaderOffset = SetFilePointer (NeHandle->File, 0, NULL, FILE_CURRENT);
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
if (!b) {
|
|
PushError();
|
|
|
|
if (NeHandle->ResourcePool) {
|
|
PmDestroyPool (NeHandle->ResourcePool);
|
|
}
|
|
|
|
if (NeHandle->File != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (NeHandle->File);
|
|
}
|
|
|
|
MemFree (g_hHeap, 0, NeHandle);
|
|
NeHandle = NULL;
|
|
|
|
PopError();
|
|
}
|
|
}
|
|
|
|
return (HANDLE) NeHandle;
|
|
}
|
|
|
|
VOID
|
|
NeCloseFile (
|
|
HANDLE Handle
|
|
)
|
|
{
|
|
PNE_HANDLE NeHandle;
|
|
|
|
NeHandle = (PNE_HANDLE) Handle;
|
|
if (!NeHandle) {
|
|
return;
|
|
}
|
|
|
|
if (NeHandle->File != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (NeHandle->File);
|
|
}
|
|
|
|
if (NeHandle->ResourcesLoaded) {
|
|
NeFreeResources (&NeHandle->Resources);
|
|
}
|
|
|
|
PmDestroyPool (NeHandle->ResourcePool);
|
|
|
|
MemFree (g_hHeap, 0, NeHandle);
|
|
}
|
|
|
|
PCSTR
|
|
pConvertUnicodeResourceId (
|
|
IN PCWSTR ResId
|
|
)
|
|
{
|
|
if (HIWORD (ResId)) {
|
|
return ConvertWtoA (ResId);
|
|
}
|
|
|
|
return (PCSTR) ResId;
|
|
}
|
|
|
|
PCSTR
|
|
pDecodeIdReferenceInString (
|
|
IN PCSTR ResName
|
|
)
|
|
{
|
|
if (HIWORD (ResName) && ResName[0] == '#') {
|
|
return (PCSTR) (ULONG_PTR) atoi (&ResName[1]);
|
|
}
|
|
|
|
return ResName;
|
|
}
|
|
|
|
BOOL
|
|
pNeLoadResourcesFromHandle (
|
|
IN PNE_HANDLE NeHandle
|
|
)
|
|
{
|
|
if (NeHandle->ResourcesLoaded) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (!NeLoadResources (NeHandle->File, &NeHandle->Resources)) {
|
|
return FALSE;
|
|
}
|
|
|
|
NeHandle->ResourcesLoaded = TRUE;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
pLoadNeResourceName (
|
|
OUT PSTR ResName,
|
|
IN HANDLE File,
|
|
IN DWORD StringOffset
|
|
)
|
|
{
|
|
BYTE ResNameSize;
|
|
|
|
SetFilePointer (File, StringOffset, NULL, FILE_BEGIN);
|
|
if (!BfReadFile (File, (PBYTE)(&ResNameSize), 1)) {
|
|
return FALSE;
|
|
}
|
|
|
|
ResName[ResNameSize] = 0;
|
|
|
|
return BfReadFile (File, ResName, ResNameSize);
|
|
}
|
|
|
|
BOOL
|
|
pNeEnumResourceTypesEx (
|
|
IN HANDLE Handle,
|
|
IN ENUMRESTYPEPROCEXA EnumFunc,
|
|
IN LONG_PTR lParam,
|
|
IN BOOL ExFunctionality,
|
|
IN BOOL UnicodeProc
|
|
)
|
|
{
|
|
PNE_HANDLE NeHandle;
|
|
PNE_RES_TYPEINFO TypeInfo;
|
|
INT Count;
|
|
INT i;
|
|
DWORD StringOffset;
|
|
CHAR ResName[256];
|
|
ENUMRESTYPEPROCA EnumFunc2 = (ENUMRESTYPEPROCA) EnumFunc;
|
|
ENUMRESTYPEPROCEXW EnumFuncW = (ENUMRESTYPEPROCEXW) EnumFunc;
|
|
ENUMRESTYPEPROCW EnumFunc2W = (ENUMRESTYPEPROCW) EnumFunc;
|
|
PWSTR UnicodeResName = NULL;
|
|
|
|
//
|
|
// Make sure resources are loaded
|
|
//
|
|
|
|
NeHandle = (PNE_HANDLE) Handle;
|
|
if (!NeHandle || !EnumFunc) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pNeLoadResourcesFromHandle (NeHandle)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Enumerate all resource types
|
|
//
|
|
|
|
Count = GlGetSize (&NeHandle->Resources.TypeInfoArray);
|
|
for (i = 0 ; i < Count ; i++) {
|
|
TypeInfo = (PNE_RES_TYPEINFO) GlGetItem (&NeHandle->Resources.TypeInfoArray, i);
|
|
|
|
if (TypeInfo->TypeId & 0x8000) {
|
|
if (ExFunctionality) {
|
|
if (UnicodeProc) {
|
|
if (!EnumFuncW (Handle, (PWSTR) (ULONG_PTR) (TypeInfo->TypeId & 0x7fff), lParam, TypeInfo)) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (!EnumFunc (Handle, (PSTR) (ULONG_PTR) (TypeInfo->TypeId & 0x7fff), lParam, TypeInfo)) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (UnicodeProc) {
|
|
if (!EnumFunc2W (Handle, (PWSTR) (ULONG_PTR) (TypeInfo->TypeId & 0x7fff), lParam)) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (!EnumFunc2 (Handle, (PSTR) (ULONG_PTR) (TypeInfo->TypeId & 0x7fff), lParam)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// TypeInfo->TypeId gives an offset to the resource string name,
|
|
// relative to the start of the resource table
|
|
//
|
|
|
|
StringOffset = NeHandle->HeaderOffset + NeHandle->Header.OffsetToResourceTable + TypeInfo->TypeId;
|
|
pLoadNeResourceName (ResName, NeHandle->File, StringOffset);
|
|
|
|
if (UnicodeProc) {
|
|
UnicodeResName = (PWSTR) ConvertAtoW (ResName);
|
|
}
|
|
|
|
if (ExFunctionality) {
|
|
if (UnicodeProc) {
|
|
if (!EnumFuncW (Handle, UnicodeResName, lParam, TypeInfo)) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (!EnumFunc (Handle, ResName, lParam, TypeInfo)) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (UnicodeProc) {
|
|
if (!EnumFunc2W (Handle, UnicodeResName, lParam)) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (!EnumFunc2 (Handle, ResName, lParam)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
NeEnumResourceTypesA (
|
|
IN HANDLE Handle,
|
|
IN ENUMRESTYPEPROCA EnumFunc,
|
|
IN LONG_PTR lParam
|
|
)
|
|
{
|
|
return pNeEnumResourceTypesEx (
|
|
Handle,
|
|
(ENUMRESTYPEPROCEXA) EnumFunc,
|
|
lParam,
|
|
FALSE, // no ex functionality
|
|
FALSE // ANSI enum proc
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
NeEnumResourceTypesW (
|
|
IN HANDLE Handle,
|
|
IN ENUMRESTYPEPROCW EnumFunc,
|
|
IN LONG_PTR lParam
|
|
)
|
|
{
|
|
return pNeEnumResourceTypesEx (
|
|
Handle,
|
|
(ENUMRESTYPEPROCEXA) EnumFunc,
|
|
lParam,
|
|
FALSE, // no ex functionality
|
|
TRUE // UNICODE enum proc
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
pEnumTypeForNameSearchProcA (
|
|
IN HANDLE Handle,
|
|
IN PCSTR Type,
|
|
IN LONG_PTR lParam,
|
|
IN PNE_RES_TYPEINFO TypeInfo
|
|
)
|
|
{
|
|
PTYPESEARCHDATAA Data;
|
|
|
|
Data = (PTYPESEARCHDATAA) lParam;
|
|
|
|
//
|
|
// Compare type
|
|
//
|
|
|
|
if (HIWORD (Data->TypeToFind) == 0) {
|
|
if (Type != Data->TypeToFind) {
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
if (HIWORD (Type) == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (!StringIMatchA (Type, Data->TypeToFind)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Type found
|
|
//
|
|
|
|
Data->OutboundTypeInfo = TypeInfo;
|
|
Data->Found = TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
pNeEnumResourceNamesEx (
|
|
IN HANDLE Handle,
|
|
IN PCSTR Type,
|
|
IN ENUMRESNAMEPROCEXA EnumFunc,
|
|
IN LONG_PTR lParam,
|
|
IN BOOL ExFunctionality,
|
|
IN BOOL UnicodeProc
|
|
)
|
|
{
|
|
PNE_HANDLE NeHandle;
|
|
PNE_RES_TYPEINFO TypeInfo;
|
|
PNE_RES_NAMEINFO NameInfo;
|
|
TYPESEARCHDATAA Data;
|
|
WORD w;
|
|
DWORD StringOffset;
|
|
CHAR ResName[256];
|
|
ENUMRESNAMEPROCA EnumFunc2 = (ENUMRESNAMEPROCA) EnumFunc;
|
|
ENUMRESNAMEPROCEXW EnumFuncW = (ENUMRESNAMEPROCEXW) EnumFunc;
|
|
ENUMRESNAMEPROCW EnumFunc2W = (ENUMRESNAMEPROCW) EnumFunc;
|
|
PCWSTR UnicodeType = NULL;
|
|
PCWSTR UnicodeResName = NULL;
|
|
|
|
Type = pDecodeIdReferenceInString (Type);
|
|
|
|
//
|
|
// Make sure resources are loaded
|
|
//
|
|
|
|
NeHandle = (PNE_HANDLE) Handle;
|
|
if (!NeHandle || !EnumFunc) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!pNeLoadResourcesFromHandle (NeHandle)) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Locate type
|
|
//
|
|
|
|
ZeroMemory (&Data, sizeof (Data));
|
|
|
|
Data.TypeToFind = Type;
|
|
|
|
if (!pNeEnumResourceTypesEx (
|
|
Handle,
|
|
pEnumTypeForNameSearchProcA,
|
|
(ULONG_PTR) &Data,
|
|
TRUE, // ex functionality
|
|
FALSE // ANSI enum proc
|
|
)) {
|
|
SetLastError (ERROR_RESOURCE_TYPE_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!Data.Found) {
|
|
SetLastError (ERROR_RESOURCE_TYPE_NOT_FOUND);
|
|
return FALSE;
|
|
}
|
|
|
|
TypeInfo = Data.OutboundTypeInfo;
|
|
|
|
if (UnicodeProc) {
|
|
if (HIWORD (Type)) {
|
|
UnicodeType = ConvertAtoW (Type);
|
|
} else {
|
|
UnicodeType = (PCWSTR) Type;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enumerate the resource names
|
|
//
|
|
|
|
NameInfo = TypeInfo->NameInfo;
|
|
|
|
for (w = 0 ; w < TypeInfo->ResourceCount ; w++) {
|
|
|
|
if (NameInfo->Id & 0x8000) {
|
|
if (ExFunctionality) {
|
|
if (UnicodeProc) {
|
|
if (!EnumFuncW (
|
|
Handle,
|
|
UnicodeType,
|
|
(PWSTR) (ULONG_PTR) (NameInfo->Id & 0x7fff),
|
|
lParam,
|
|
TypeInfo,
|
|
NameInfo
|
|
)) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (!EnumFunc (
|
|
Handle,
|
|
Type,
|
|
(PSTR) (ULONG_PTR) (NameInfo->Id & 0x7fff),
|
|
lParam,
|
|
TypeInfo,
|
|
NameInfo
|
|
)) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (UnicodeProc) {
|
|
if (!EnumFunc2W (
|
|
Handle,
|
|
UnicodeType,
|
|
(PWSTR) (ULONG_PTR) (NameInfo->Id & 0x7fff),
|
|
lParam
|
|
)) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (!EnumFunc2 (
|
|
Handle,
|
|
Type,
|
|
(PSTR) (ULONG_PTR) (NameInfo->Id & 0x7fff),
|
|
lParam
|
|
)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// TypeInfo->TypeId gives an offset to the resource string name,
|
|
// relative to the start of the resource table
|
|
//
|
|
|
|
StringOffset = NeHandle->HeaderOffset + NeHandle->Header.OffsetToResourceTable + NameInfo->Id;
|
|
pLoadNeResourceName (ResName, NeHandle->File, StringOffset);
|
|
|
|
if (UnicodeProc) {
|
|
UnicodeResName = ConvertAtoW (ResName);
|
|
}
|
|
|
|
if (ExFunctionality) {
|
|
if (UnicodeProc) {
|
|
if (!EnumFuncW (Handle, UnicodeType, (PWSTR) UnicodeResName, lParam, TypeInfo, NameInfo)) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (!EnumFunc (Handle, Type, ResName, lParam, TypeInfo, NameInfo)) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (UnicodeProc) {
|
|
if (!EnumFunc2W (Handle, UnicodeType, (PWSTR) UnicodeResName, lParam)) {
|
|
break;
|
|
}
|
|
} else {
|
|
if (!EnumFunc2 (Handle, Type, ResName, lParam)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (UnicodeProc) {
|
|
FreeConvertedStr (UnicodeResName);
|
|
}
|
|
}
|
|
|
|
NameInfo++;
|
|
}
|
|
|
|
if (UnicodeProc) {
|
|
DestroyUnicodeResourceId (UnicodeType);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
NeEnumResourceNamesA (
|
|
IN HANDLE Handle,
|
|
IN PCSTR Type,
|
|
IN ENUMRESNAMEPROCA EnumFunc,
|
|
IN LONG_PTR lParam
|
|
)
|
|
{
|
|
return pNeEnumResourceNamesEx (
|
|
Handle,
|
|
Type,
|
|
(ENUMRESNAMEPROCEXA) EnumFunc,
|
|
lParam,
|
|
FALSE, // no ex functionality
|
|
FALSE // ANSI enum proc
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
NeEnumResourceNamesW (
|
|
IN HANDLE Handle,
|
|
IN PCWSTR Type,
|
|
IN ENUMRESNAMEPROCW EnumFunc,
|
|
IN LONG_PTR lParam
|
|
)
|
|
{
|
|
BOOL b;
|
|
PCSTR AnsiType;
|
|
|
|
AnsiType = pConvertUnicodeResourceId (Type);
|
|
|
|
b = pNeEnumResourceNamesEx (
|
|
Handle,
|
|
AnsiType,
|
|
(ENUMRESNAMEPROCEXA) EnumFunc,
|
|
lParam,
|
|
FALSE, // no ex functionality
|
|
TRUE // UNICODE enum proc
|
|
);
|
|
|
|
PushError();
|
|
DestroyAnsiResourceId (AnsiType);
|
|
PopError();
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
pEnumTypeForResSearchProcA (
|
|
IN HANDLE Handle,
|
|
IN PCSTR Type,
|
|
IN PCSTR Name,
|
|
IN LPARAM lParam,
|
|
IN PNE_RES_TYPEINFO TypeInfo,
|
|
IN PNE_RES_NAMEINFO NameInfo
|
|
)
|
|
{
|
|
PNAMESEARCHDATAA Data;
|
|
|
|
Data = (PNAMESEARCHDATAA) lParam;
|
|
|
|
//
|
|
// Compare name
|
|
//
|
|
|
|
if (HIWORD (Data->NameToFind) == 0) {
|
|
if (Name != Data->NameToFind) {
|
|
return TRUE;
|
|
}
|
|
} else {
|
|
if (HIWORD (Name) == 0) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (!StringIMatchA (Name, Data->NameToFind)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Name found
|
|
//
|
|
|
|
Data->OutboundTypeInfo = TypeInfo;
|
|
Data->OutboundNameInfo = NameInfo;
|
|
Data->Found = TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
PBYTE
|
|
NeFindResourceExA (
|
|
IN HANDLE Handle,
|
|
IN PCSTR Type,
|
|
IN PCSTR Name
|
|
)
|
|
{
|
|
PNE_HANDLE NeHandle;
|
|
NAMESEARCHDATAA Data;
|
|
DWORD Offset;
|
|
DWORD Length;
|
|
PNE_RES_NAMEINFO NameInfo;
|
|
PBYTE ReturnData;
|
|
|
|
Type = pDecodeIdReferenceInString (Type);
|
|
Name = pDecodeIdReferenceInString (Name);
|
|
|
|
ZeroMemory (&Data, sizeof (Data));
|
|
|
|
//
|
|
// Make sure resources are loaded
|
|
//
|
|
|
|
NeHandle = (PNE_HANDLE) Handle;
|
|
if (!NeHandle || !Type || !Name) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
if (!pNeLoadResourcesFromHandle (NeHandle)) {
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Find resource
|
|
//
|
|
|
|
Data.NameToFind = Name;
|
|
|
|
if (!pNeEnumResourceNamesEx (
|
|
Handle,
|
|
Type,
|
|
pEnumTypeForResSearchProcA,
|
|
(LONG_PTR) &Data,
|
|
TRUE,
|
|
FALSE
|
|
)) {
|
|
SetLastError (ERROR_RESOURCE_NAME_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
if (!Data.Found) {
|
|
SetLastError (ERROR_RESOURCE_NAME_NOT_FOUND);
|
|
return NULL;
|
|
}
|
|
|
|
NameInfo = Data.OutboundNameInfo;
|
|
|
|
Offset = (DWORD) NameInfo->Offset << (DWORD) NeHandle->Resources.AlignShift;
|
|
Length = (DWORD) NameInfo->Length << (DWORD) NeHandle->Resources.AlignShift;
|
|
|
|
ReturnData = PmGetMemory (NeHandle->ResourcePool, Length);
|
|
if (!ReturnData) {
|
|
return NULL;
|
|
}
|
|
|
|
SetFilePointer (NeHandle->File, Offset, NULL, FILE_BEGIN);
|
|
|
|
if (!BfReadFile (NeHandle->File, ReturnData, Length)) {
|
|
PushError();
|
|
MemFree (g_hHeap, 0, ReturnData);
|
|
PopError();
|
|
return NULL;
|
|
}
|
|
|
|
return ReturnData;
|
|
}
|
|
|
|
PBYTE
|
|
NeFindResourceExW (
|
|
IN HANDLE Handle,
|
|
IN PCWSTR Type,
|
|
IN PCWSTR Name
|
|
)
|
|
{
|
|
PCSTR AnsiType;
|
|
PCSTR AnsiName;
|
|
PBYTE Resource;
|
|
|
|
AnsiType = pConvertUnicodeResourceId (Type);
|
|
AnsiName = pConvertUnicodeResourceId (Name);
|
|
|
|
Resource = NeFindResourceExA (
|
|
Handle,
|
|
AnsiType,
|
|
AnsiName
|
|
);
|
|
|
|
PushError();
|
|
|
|
DestroyAnsiResourceId (AnsiType);
|
|
DestroyAnsiResourceId (AnsiName);
|
|
|
|
PopError();
|
|
|
|
return Resource;
|
|
}
|
|
|
|
DWORD
|
|
NeSizeofResourceA (
|
|
IN HANDLE Handle,
|
|
IN PCSTR Type,
|
|
IN PCSTR Name
|
|
)
|
|
{
|
|
PNE_HANDLE NeHandle;
|
|
NAMESEARCHDATAA Data;
|
|
DWORD result = 0;
|
|
|
|
SetLastError (ERROR_SUCCESS);
|
|
|
|
Type = pDecodeIdReferenceInString (Type);
|
|
Name = pDecodeIdReferenceInString (Name);
|
|
|
|
ZeroMemory (&Data, sizeof (Data));
|
|
|
|
//
|
|
// Make sure resources are loaded
|
|
//
|
|
|
|
NeHandle = (PNE_HANDLE) Handle;
|
|
if (!NeHandle || !Type || !Name) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (!pNeLoadResourcesFromHandle (NeHandle)) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Find resource
|
|
//
|
|
|
|
Data.NameToFind = Name;
|
|
|
|
if (!pNeEnumResourceNamesEx (
|
|
Handle,
|
|
Type,
|
|
pEnumTypeForResSearchProcA,
|
|
(LONG_PTR) &Data,
|
|
TRUE,
|
|
FALSE
|
|
)) {
|
|
SetLastError (ERROR_RESOURCE_NAME_NOT_FOUND);
|
|
return 0;
|
|
}
|
|
|
|
if (!Data.Found) {
|
|
SetLastError (ERROR_RESOURCE_NAME_NOT_FOUND);
|
|
return 0;
|
|
}
|
|
|
|
result = Data.OutboundNameInfo->Length;
|
|
result = result<<4;
|
|
return result;
|
|
}
|
|
|
|
DWORD
|
|
NeSizeofResourceW (
|
|
IN HANDLE Handle,
|
|
IN PCWSTR Type,
|
|
IN PCWSTR Name
|
|
)
|
|
{
|
|
PCSTR AnsiType;
|
|
PCSTR AnsiName;
|
|
DWORD Size;
|
|
|
|
AnsiType = pConvertUnicodeResourceId (Type);
|
|
AnsiName = pConvertUnicodeResourceId (Name);
|
|
|
|
Size = NeSizeofResourceA (Handle, AnsiType, AnsiName);
|
|
|
|
PushError();
|
|
|
|
DestroyAnsiResourceId (AnsiType);
|
|
DestroyAnsiResourceId (AnsiName);
|
|
|
|
PopError();
|
|
|
|
return Size;
|
|
}
|