Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1030 lines
30 KiB

#include "stdinc.h"
static const char File[] = __FILE__;
#include "delayload_tool.h"
#include "fusionstring.h"
#include "setfilepointerex.c"
#include "getfilesizeex.c"
#include <assert.h>
#include "delayimp.h"
#include "imagehlp.h"
#define BITS_OF(x) (sizeof(x) * 8)
String_t GetErrorString(DWORD Error);
//
// delayimp.h doesn't work when tool bitness != image bitness
//
typedef ULONG32 PImgThunkData32;
typedef ULONG32 PCImgThunkData32;
typedef ULONG32 LPCSTR32;
typedef ULONG32 PHMODULE32;
typedef ULONG64 PImgThunkData64;
typedef ULONG64 PCImgThunkData64;
typedef ULONG64 LPCSTR64;
typedef ULONG64 PHMODULE64;
typedef struct ImgDelayDescrV1_32 {
DWORD grAttrs; // attributes
LPCSTR32 szName; // pointer to dll name
PHMODULE32 phmod; // address of module handle
PImgThunkData32 pIAT; // address of the IAT
PCImgThunkData32 pINT; // address of the INT
PCImgThunkData32 pBoundIAT; // address of the optional bound IAT
PCImgThunkData32 pUnloadIAT; // address of optional copy of original IAT
DWORD dwTimeStamp; // 0 if not bound,
// O.W. date/time stamp of DLL bound to (Old BIND)
} ImgDelayDescrV1_32, * PImgDelayDescrV1_32;
typedef struct ImgDelayDescrV1_64 {
DWORD grAttrs; // attributes
LPCSTR64 szName; // pointer to dll name
PHMODULE64 phmod; // address of module handle
PImgThunkData64 pIAT; // address of the IAT
PCImgThunkData64 pINT; // address of the INT
PCImgThunkData64 pBoundIAT; // address of the optional bound IAT
PCImgThunkData64 pUnloadIAT; // address of optional copy of original IAT
DWORD dwTimeStamp; // 0 if not bound,
// O.W. date/time stamp of DLL bound to (Old BIND)
} ImgDelayDescrV1_64, * PImgDelayDescrV1_64;
//
// get msvcrt.dll wildcard processing on the command line
//
extern "C" { int _dowildcard = 1; }
void Spinner()
{
static char s[] = "-\\|/";
static unsigned i;
fprintf(stderr, "%c\r", s[i++ % (sizeof(s) - 1)]);
}
void Throw(PCWSTR s)
{
if (::IsDebuggerPresent())
{
DbgPrint("Throw(%ls)\n", s);
DebugBreak();
}
throw (s);
}
void F::ThrowHresult(HRESULT hr)
{
if (::IsDebuggerPresent())
{
DbgPrint("ThrowHresult:0x%lx|%ld|%ls\n", hr, (hr & 0xffff), GetErrorString(hr).c_str());
DebugBreak();
}
throw (hr);
}
void ThrowLastWin32Error()
{
DWORD dw = GetLastError();
if (::IsDebuggerPresent())
{
DbgPrint("ThrowLastWin32Error:0x%lx|%ld|%ls\n", dw, dw, GetErrorString(dw).c_str());
DebugBreak();
}
throw (dw);
}
void
CollectDirectoryPathsNonRecursively(
const String_t& directory,
StringVector_t& paths
)
{
WIN32_FIND_DATAW wfd;
DFindFile FindFile;
HRESULT hr = 0;
String_t directory_slash_star = directory + L"\\*";
if (FAILED(hr = FindFile.HrCreate(directory_slash_star, &wfd)))
{
FindFirstFileError_t err;
err.m_hresult = hr;
err.m_dwLastError = GetLastError();
std::swap(err.m_strParameter, directory_slash_star);
throw err;
}
directory_slash_star.clear();
do
{
if (FusionpIsDotOrDotDot(wfd.cFileName))
{
continue;
}
if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
paths.insert(paths.end(), directory + L"\\" + wfd.cFileName);
}
} while (::FindNextFileW(FindFile, &wfd));
}
typedef BOOL (CALLBACK * PFN_COLLECTION_FILE_PATHS_RECURSIVELY_FILTER)(PVOID FilterContext, PCWSTR Directory, WIN32_FIND_DATAW * wfd);
void
CollectFilePathsRecursivelyHelper(
const String_t& directory,
StringVector_t& paths,
PFN_COLLECTION_FILE_PATHS_RECURSIVELY_FILTER Filter,
PVOID FilterContext,
WIN32_FIND_DATAW& wfd
)
{
DFindFile FindFile;
HRESULT hr = 0;
String_t directory_slash_star = directory + L"\\*";
if (FAILED(hr = FindFile.HrCreate(directory_slash_star, &wfd)))
{
FindFirstFileError_t err;
err.m_hresult = hr;
err.m_dwLastError = GetLastError();
std::swap(err.m_strParameter, directory_slash_star);
throw err;
}
directory_slash_star.clear();
do
{
if (FusionpIsDotOrDotDot(wfd.cFileName))
{
continue;
}
if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
if (Filter == NULL || (*Filter)(FilterContext, directory, &wfd))
{
CollectFilePathsRecursivelyHelper(directory + L"\\" + wfd.cFileName, paths, Filter, FilterContext, wfd);
}
}
else
{
if (Filter == NULL || (*Filter)(FilterContext, directory, &wfd))
{
paths.insert(paths.end(), directory + L"\\" + wfd.cFileName);
}
}
} while (::FindNextFileW(FindFile, &wfd));
}
void
CollectFilePathsRecursively(
const String_t& directory,
StringVector_t& paths,
PFN_COLLECTION_FILE_PATHS_RECURSIVELY_FILTER Filter,
PVOID FilterContext
)
{
WIN32_FIND_DATAW wfd;
CollectFilePathsRecursivelyHelper(directory, paths, Filter, FilterContext, wfd);
}
void DelayloadToolAssertFailed(const char* Expression, const char* File, unsigned long Line)
{
fprintf(stderr, "ASSERTION FAILURE: File %s, Line %lu, Expression %s\n", File, Line, Expression);
abort();
}
void DelayloadToolInternalErrorCheckFailed(const char* Expression, const char* File, unsigned long Line)
{
fprintf(stderr, "INTERNAL ERROR: File %s, Line %lu, Expression %s\n", File, Line, Expression);
abort();
}
String_t NumberToString(ULONG Number, PCWSTR Format)
{
// the size needed is really dependent on Format..
WCHAR NumberAsString[BITS_OF(Number) + 5];
_snwprintf(NumberAsString, NUMBER_OF(NumberAsString), Format, Number);
NumberAsString[NUMBER_OF(NumberAsString) - 1] = 0;
return NumberAsString;
}
String_t GetErrorString(DWORD Error)
{
PWSTR s = NULL;
String_t ErrorString = NumberToString(Error, L"%lu");
PWSTR FormatMessageAllocatedBuffer = NULL;
if (!FormatMessageW(
FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
Error,
0,
reinterpret_cast<PWSTR>(&FormatMessageAllocatedBuffer),
100,
NULL
)
|| FormatMessageAllocatedBuffer == NULL
)
{
goto Exit;
}
if (FormatMessageAllocatedBuffer[0] == 0)
{
goto Exit;
}
//
// Error messages often end with vertical whitespce, remove it.
//
s = FormatMessageAllocatedBuffer + StringLength(FormatMessageAllocatedBuffer) - 1;
while (s != FormatMessageAllocatedBuffer && (*s == '\n' || *s == '\r'))
*s-- = 0;
ErrorString = ErrorString + L" (" + FormatMessageAllocatedBuffer + L")";
Exit:
LocalFree(FormatMessageAllocatedBuffer);
return ErrorString;
}
String_t GetLastErrorString()
{
return GetErrorString(GetLastError());
}
String_t RemoveOptionChar(const String_t& s)
{
if (s.Length() != 0)
{
if (s[0] == '-')
return s.substr(1);
else if (s[0] == '/')
return s.substr(1);
else if (s[0] == ':') // hacky..
return s.substr(1);
else if (s[0] == '=') // hacky..
return s.substr(1);
}
return s;
}
void __cdecl Error(const wchar_t* s, ...)
{
printf("%s\n", s);
exit(EXIT_FAILURE);
}
String_t GetEnv(PCWSTR Name)
{
DWORD LengthIn = 64;
DWORD LengthOut = 0;
std::vector<WCHAR> Buffer;
while (true)
{
Buffer.resize(LengthIn);
Buffer[0] = 0;
LengthOut = GetEnvironmentVariableW(Name, &Buffer[0], LengthIn);
if (LengthOut < LengthIn)
{
break;
}
LengthIn = 1 + std::max(2 * LengthIn, LengthOut);
}
return &Buffer[0];
}
String_t FindLatestReleaseOnServer(const String_t& Server)
{
StringVector_t Releases;
String_t ServerRelease;
ServerRelease += L"\\\\";
ServerRelease += Server;
ServerRelease += L"\\release";
CollectDirectoryPathsNonRecursively(ServerRelease, Releases);
std::sort(Releases.begin(), Releases.end());
return Releases.back();
}
BOOL DelayloadTool_Filter(PVOID FilterContext, PCWSTR Directory, WIN32_FIND_DATAW * wfd)
{
const static UNICODE_STRING directoriesToIgnore[] =
{
#define X(x) RTL_CONSTANT_STRING(x)
X(L"pro"), X(L"srv"), X(L"ads"), X(L"dtc"), X(L"bla"), X(L"per"),
X(L"sbs"),
X(L"proinf"), X(L"srvinf"), X(L"adsinf"), X(L"dtcinf"), X(L"blainf"), X(L"perinf"),
X(L"procd1"), X(L"procd2"),
X(L"ifs_cd"), X(L"symbols"), X(L"ifs_flat"), X(L"build_logs"),
X(L"symbols.pri"), X(L"processor_cd"), X(L"processor_flat"),
X(L"asmscab"),
X(L"ddk_flat"),
X(L"scp_wpa"),
X(L"hu"),
X(L"ara"), X(L"br"), X(L"chs"), X(L"cht"), X(L"cs"), X(L"da"), X(L"el"), X(L"es"),
X(L"euq"), X(L"fi"), X(L"fr"), X(L"ger"), X(L"heb"), X(L"hun"), X(L"it"), X(L"jpn"),
X(L"kor"), X(L"nl"), X(L"no"), X(L"pl"), X(L"pt"), X(L"ru"), X(L"sky"), X(L"slv"),
X(L"sv"), X(L"tr"), X(L"usa"),
X(L"congeal_scripts"),
X(L"lanman"),
X(L"dos"), X(L"lanman.os2"), X(L"tcp32wfw"), X(L"update.wfw"), X(L"msclient"),
X(L"bootfloppy"),
X(L"opk"),
X(L"winpe"),
X(L"presign"),
X(L"prerebase"),
};
const static UNICODE_STRING extensionsToIgnore[] =
{
X(L"txt"), X(L"htm"), X(L"gif"), X(L"bmp"), X(L"pdb"),
X(L"inf"), X(L"sif"), X(L"pnf"), X(L"png"),
X(L"sys"), X(L"ttf"), X(L"vbs"), X(L"hlp"), X(L"ini"), X(L"cat"),
X(L"cab"), X(L"nls"), X(L"gpd"), X(L"chm"), X(L"cur"), X(L"jpg"),
X(L"cer"), X(L"ani"), X(L"fon"), X(L"css"), X(L"hash"),
X(L"lst"), X(L"icm"), X(L"msg"), X(L"386"),
X(L"ico"), X(L"dos"), X(L"asp"), X(L"sld"),
X(L"pif"), X(L"cnt"), X(L"mof"), X(L"man"), X(L"msm"),
X(L"cdf"), X(L"img"), X(L"doc"), X(L"dns"), X(L"cpx"), X(L"mib"), X(L"ppd")
X(L"map"), X(L"sym")
#undef X
};
CUnicodeString cFileName(wfd->cFileName);
SIZE_T i;
if ((wfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
Spinner();
//fprintf(stderr, "%wZ\n", &cFileName);
for (i = 0 ; i != RTL_NUMBER_OF(directoriesToIgnore) ; ++i)
{
if (FusionpEqualStringsI(&directoriesToIgnore[i], &cFileName))
return FALSE;
}
}
else
{
PCWSTR dot;
if (RTL_STRING_GET_LAST_CHAR(&cFileName) == L'_')
return FALSE;
if (RTL_STRING_GET_LAST_CHAR(&cFileName) == L'$')
return FALSE;
dot = wcsrchr(wfd->cFileName, '.');
if (dot != NULL && wcslen(dot + 1) == 3)
{
CUnicodeString dotString(dot + 1);
for (i = 0 ; i != RTL_NUMBER_OF(extensionsToIgnore) ; ++i)
{
if (FusionpEqualStringsI(&extensionsToIgnore[i], &dotString))
return FALSE;
}
}
}
_wcslwr(wfd->cFileName);
return TRUE;
}
void
SeekTo(
HANDLE FileHandle,
ULONG64 Offset
)
{
LARGE_INTEGER liOffset;
liOffset.QuadPart = Offset;
if (!FusionpSetFilePointerEx(FileHandle, liOffset, NULL, FILE_BEGIN))
{
DbgPrint("SeekTo:0x%I64x failing\n", Offset);
ThrowLastWin32Error();
}
}
void
SeekBackward(
HANDLE FileHandle,
LONG64 Offset
)
{
LARGE_INTEGER liOffset;
liOffset.QuadPart = -Offset;
if (!FusionpSetFilePointerEx(FileHandle, liOffset, NULL, FILE_CURRENT))
ThrowLastWin32Error();
}
ULONG64
GetCurrentSeekPointer(
HANDLE FileHandle
)
{
LARGE_INTEGER li;
LARGE_INTEGER li2;
li.QuadPart = 0;
li2.QuadPart = 0;
if (!FusionpSetFilePointerEx(FileHandle, li, &li2, FILE_CURRENT))
ThrowLastWin32Error();
return li2.QuadPart;
}
void
SeekForward(
HANDLE FileHandle,
ULONG64 Offset
)
{
LARGE_INTEGER liOffset;
liOffset.QuadPart = Offset;
if (!FusionpSetFilePointerEx(FileHandle, liOffset, NULL, FILE_CURRENT))
ThrowLastWin32Error();
}
PBYTE
FindRunOfZeros(
PBYTE pb,
PBYTE pbEnd,
SIZE_T elementSize
)
{
SIZE_T k = 0;
SIZE_T mod = ((pbEnd - pb) % elementSize);
assert(mod == 0);
if (mod != 0)
{
return pbEnd;
}
if (pb + elementSize >= pbEnd)
return pbEnd;
for ( ; pb != pbEnd ; pb += elementSize)
{
for (k = 0 ; k != elementSize ; ++k)
{
if (pb[k] != 0)
{
break;
}
}
if (k == elementSize)
{
break;
}
}
return pb;
}
void
ReadImportFunctionNames(
HANDLE File,
SIZE_T SizeOfPointer,
const std::vector<ULONG64>& IatRvas
std::vector<String_t>& IatRvas
)
{
}
void
ReadIatRvas(
HANDLE File,
SIZE_T SizeOfPointer,
std::vector<ULONG64>& Iat
)
//
// This leaves the seek pointer in an arbitrary location.
//
{
union
{
ULONG32 Iat32[64];
ULONG64 Iat64[32];
BYTE Bytes[64 * 4];
} u;
ULONG BytesRead;
ULONG Mod;
Iat.resize(0);
assert(SizeOfPointer == 4 || SizeOfPointer == 8);
while (true)
{
BytesRead = 0;
if (!ReadFile(File, &u, sizeof(u), &BytesRead, NULL))
ThrowLastWin32Error(/*"ReadFile"*/);
Mod = (BytesRead % SizeOfPointer);
if (Mod != 0)
{
SeekBackward(File, Mod);
BytesRead -= Mod;
}
if (BytesRead == 0)
{
Throw(L"end of file without nul terminal\n");
}
PBYTE pb = FindRunOfZeros(u.Bytes, u.Bytes + BytesRead, SizeOfPointer);
switch (SizeOfPointer)
{
case 4:
std::copy(u.Iat32, reinterpret_cast<ULONG32*>(pb), std::inserter(Iat.end()));
break;
case 8:
std::copy(u.Iat64, reinterpret_cast<ULONG64*>(pb), std::inserter(Iat.end()));
break;
default:
Throw("unknown sizeof pointer");
break;
}
if (pb != u.Bytes + BytesRead)
{
break;
}
}
}
String_t
ReadDllName(
HANDLE File
)
//
// This leaves the seek pointer in an arbitrary location.
//
{
String_t Result;
CHAR BufferA[65];
WCHAR BufferW[65];
DWORD BytesRead = 0;
BufferA[NUMBER_OF(BufferA) - 1] = 0;
BufferW[NUMBER_OF(BufferW) - 1] = 0;
while (true)
{
BytesRead = 0;
if (!ReadFile(File, &BufferA[0], (NUMBER_OF(BufferA) - 1) * sizeof(BufferA[0]), &BytesRead, NULL))
ThrowLastWin32Error(/*"ReadFile"*/);
if (BytesRead == 0)
{
Throw(L"end of file without nul terminal\n");
}
_strlwr(BufferA);
for (ULONG i = 0 ; i != BytesRead ; ++i)
{
if ((BufferW[i] = BufferA[i]) == 0)
{
Result += BufferW;
return Result;
}
}
Result += BufferW;
}
}
void
Read(
HANDLE FileHandle,
VOID * Buffer,
ULONG BytesToRead
)
{
DWORD BytesRead;
if (!ReadFile(FileHandle, Buffer, BytesToRead, &BytesRead, NULL))
ThrowLastWin32Error(/*"ReadFile"*/);
if (BytesToRead != BytesRead)
{
Throw(L"wrong number of bytes read");
}
}
void DelayloadTool_t::ProcessBuild(const BuildFlavor_t& b)
{
FilePaths_t FilePaths;
CollectFilePathsRecursively(*b.ActualRoot, FilePaths, DelayloadTool_Filter);
for (FilePaths_t::const_iterator i = FilePaths.begin() ; i != FilePaths.end() ; ++i)
{
ProcessFile(*b.ActualRoot, *i);
Spinner();
}
}
String_t
DelayloadTool_t::ReadOneDelayload(
HANDLE File
)
{
ImgDelayDescrV1_32 delay1_32 = { 0 };
ImgDelayDescrV1_64 delay1_64 = { 0 };
ImgDelayDescrV2 delay2 = { 0 };
LONG64 FileOffsetToDelayLoadedName = 0;
DWORD dwDelayFlags = 0;
Read(File, &dwDelayFlags, 4);
SeekBackward(File, 4);
bool rvaFlag = ((dwDelayFlags & dlattrRva) != 0);
if (rvaFlag)
{
Read(File, &delay2, sizeof(delay2));
}
else
{
if (m_OptionalHeader32 != NULL)
{
Read(File, &delay1_32, sizeof(delay1_32));
if (delay1_32.szName == 0)
{
delay2.rvaDLLName = 0;
}
else
{
delay2.rvaDLLName = static_cast<RVA>(delay1_32.szName - m_OptionalHeader32->ImageBase);
}
}
else if (m_OptionalHeader64 != NULL)
{
Read(File, &delay1_64, sizeof(delay1_64));
if (delay1_64.szName == 0)
{
delay2.rvaDLLName = 0;
}
else
{
delay2.rvaDLLName = static_cast<RVA>(delay1_64.szName - m_OptionalHeader64->ImageBase);
}
}
else
{
Throw(L"unknown image format");
}
}
if (delay2.rvaDLLName == 0)
{
FileOffsetToDelayLoadedName = 0;
}
else
{
PBYTE pb = reinterpret_cast<PBYTE>(ImageRvaToVa(GetNtHeaders(), GetMappedBase(), delay2.rvaDLLName, &m_HintSection));
FileOffsetToDelayLoadedName = (pb - &m_HeadersBuffer[0]);
}
if (FileOffsetToDelayLoadedName == 0)
{
return L"";
}
ULONG64 CurrentOffset = GetCurrentSeekPointer(File);
SeekTo(File, FileOffsetToDelayLoadedName);
String_t DllName = ReadDllName(File);
SeekTo(File, CurrentOffset);
return DllName;
}
void DelayloadTool_t::ProcessFile(const FilePath_t & RootPath, const FilePath_t & FilePath)
{
DFile File;
Image_t Image;
LARGE_INTEGER FileSize = { 0 };
PIMAGE_FILE_HEADER FileHeader = 0;
m_OptionalHeader32 = 0;
m_OptionalHeader64 = 0;
PIMAGE_SECTION_HEADER SectionHeaders = 0;
PIMAGE_DATA_DIRECTORY DelayloadDataDirectory = 0;
HRESULT hr = 0;
m_OffsetToPe = 0;
ULONG OffsetToFileHeader = 0;
ULONG OffsetToOptionalHeader = 0;
ULONG OffsetToSectionHeaders = 0;
ULONG SizeOfOptionalHeader = 0;
ULONG SizeofSectionHeaders = 0;
ULONG NumberOfSections = 0;
m_HintSection = 0;
String_t DllName;
struct
{
IMAGE_IMPORT_DESCRIPTOR RawDescriptor;
String_t DllName;
std::vector<ULONG64> Iat;
std::vector<String_t> FunctionNames;
} Import;
Image.m_FullPath = FilePath;
if (RootPath.GetLength() != 0)
{
assert(RootPath.GetLength() > Image.m_FullPath.GetLength());
Image.m_RelativePath = Image.m_FullPath.substr(1 + RootPath.GetLength());
}
else
{
Image.m_RelativePath = L"";
}
Image.m_LeafPath = Image.m_FullPath.substr(1 + Image.m_FullPath.find_last_of(L"\\/"));
//fprintf(stderr, "\n%ls", Image.m_RelativePath.c_str());
hr = File.HrCreate(FilePath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
if (FAILED(hr))
{
goto Error;
}
if (!FusionpGetFileSizeEx(File, &FileSize))
{
goto Error;
}
if (FileSize.QuadPart < 64)
{
goto NotAnImage;
}
m_HeadersBuffer.resize(64);
Read(File, &m_HeadersBuffer[0], 2);
if (memcmp(&m_HeadersBuffer[0], "MZ", 2) != 0)
goto NotAnImage;
SeekTo(File, 60);
Read(File, &m_HeadersBuffer[60], 4);
m_OffsetToPe = *reinterpret_cast<ULONG*>(&m_HeadersBuffer[60]);
OffsetToFileHeader = m_OffsetToPe + 4;
OffsetToOptionalHeader = OffsetToFileHeader + sizeof(IMAGE_FILE_HEADER);
if (m_OffsetToPe > MAXULONG - 4)
goto NotAnImage;
if (m_OffsetToPe + 4 > FileSize.QuadPart)
goto NotAnImage;
SeekTo(File, m_OffsetToPe);
m_HeadersBuffer.resize(m_OffsetToPe + 4 + sizeof(IMAGE_FILE_HEADER));
Read(File, &m_HeadersBuffer[m_OffsetToPe], 4);
if (memcmp(&m_HeadersBuffer[m_OffsetToPe], "PE\0\0", 4) != 0)
goto NotAnImage;
Read(File, &m_HeadersBuffer[OffsetToFileHeader], sizeof(IMAGE_FILE_HEADER));
FileHeader = reinterpret_cast<PIMAGE_FILE_HEADER>(&m_HeadersBuffer[OffsetToFileHeader]);
SizeOfOptionalHeader = FileHeader->SizeOfOptionalHeader;
NumberOfSections = FileHeader->NumberOfSections;
OffsetToSectionHeaders = OffsetToOptionalHeader + SizeOfOptionalHeader;
SizeofSectionHeaders = NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
m_HeadersBuffer.resize(OffsetToOptionalHeader + SizeOfOptionalHeader + SizeofSectionHeaders);
Read(File, &m_HeadersBuffer[OffsetToOptionalHeader], SizeOfOptionalHeader + SizeofSectionHeaders);
FileHeader = reinterpret_cast<PIMAGE_FILE_HEADER>(&m_HeadersBuffer[OffsetToFileHeader]);
m_OptionalHeader32 = reinterpret_cast<PIMAGE_OPTIONAL_HEADER32>(&m_HeadersBuffer[OffsetToOptionalHeader]);
m_OptionalHeader64 = reinterpret_cast<PIMAGE_OPTIONAL_HEADER64>(&m_HeadersBuffer[OffsetToOptionalHeader]);
SectionHeaders = reinterpret_cast<PIMAGE_SECTION_HEADER>(&m_HeadersBuffer[SizeofSectionHeaders]);
switch (m_OptionalHeader32->Magic)
{
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
m_OptionalHeader64 = NULL;
break;
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
m_OptionalHeader32 = NULL;
break;
case IMAGE_ROM_OPTIONAL_HDR_MAGIC:
goto IgnoreRomImages;
break;
default:
goto UnrecognizableImage;
}
if (GET_OPTIONAL_HEADER_FIELD(m_OptionalHeader32, m_OptionalHeader64, NumberOfRvaAndSizes)
< IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT)
{
goto NoDelayloads;
}
DelayloadDataDirectory = &GET_OPTIONAL_HEADER_FIELD(m_OptionalHeader32, m_OptionalHeader64, DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT]);
if (DelayloadDataDirectory->VirtualAddress == NULL)
{
goto NoDelayloads;
}
if (DelayloadDataDirectory->Size == NULL)
{
goto NoDelayloads;
}
fprintf(stderr, "\r%ls\n", Image.m_RelativePath.c_str());
PBYTE pb;
pb = reinterpret_cast<PBYTE>(ImageRvaToVa(GetNtHeaders(), GetMappedBase(), DelayloadDataDirectory->VirtualAddress, &m_HintSection));
LONG64 OffsetToDelayloads;
OffsetToDelayloads = pb - &m_HeadersBuffer[0];
SeekTo(File, OffsetToDelayloads);
DllName = ReadOneDelayload(File);
if (DllName == L"")
{
goto NoDelayloads;
}
if (GET_OPTIONAL_HEADER_FIELD(m_OptionalHeader32, m_OptionalHeader64, NumberOfRvaAndSizes)
< IMAGE_DIRECTORY_ENTRY_IMPORT)
{
goto NoImports;
}
ImportDataDirectory = &GET_OPTIONAL_HEADER_FIELD(m_OptionalHeader32, m_OptionalHeader64, DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]);
if (ImportDataDirectory->VirtualAddress == NULL)
{
goto NoImports;
}
if (ImportDataDirectory->Size == NULL)
{
goto NoImports;
}
pb = reinterpret_cast<PBYTE>(ImageRvaToVa(GetNtHeaders(), GetMappedBase(), ImportDataDirectory->VirtualAddress, &m_HintSection));
LONG64 OffsetToImport;
OffsetToImport = pb - &m_HeadersBuffer[0];
SeekTo(File, OffsetToImport);
Read(File, &Import.RawDescriptor, sizeof(Import.RawDescriptor));
OffsetToImport += sizeof(ImportDescriptor);
SeekTo(File, Import.RawDescriptor.Name);
Import.DllName = ReadDllName(File);
SeekTo(File, Import.RawDescriptor.OriginalFirstThunk);
ReadIatRvas(File, GetSizeOfPointer(), Import.Iat);
ReadImportFunctionNames(File, GetSizeOfPointer(), Import.Iat, Import.FunctionNames);
NoImports:
m_XmlWriter.startElement(L"file");
m_XmlWriter.startElement(L"type");
m_XmlWriter.characters(L"pe/coff image");
m_XmlWriter.endElement(L"type");
m_XmlWriter.startElement(L"full-path");
m_XmlWriter.characters(Image.m_FullPath);
m_XmlWriter.endElement(L"full-path");
if (Image.m_RelativePath != L"")
{
m_XmlWriter.startElement(L"relative-path");
m_XmlWriter.characters(Image.m_RelativePath);
m_XmlWriter.endElement(L"relative-path");
}
m_XmlWriter.startElement(L"leaf-path");
m_XmlWriter.characters(Image.m_LeafPath);
m_XmlWriter.endElement(L"leaf-path");
m_XmlWriter.startElement(L"delay-loads");
for ( ; DllName != L""; DllName = ReadOneDelayload(File) )
{
m_XmlWriter.startElement(L"delay-load");
m_XmlWriter.characters(DllName);
m_XmlWriter.endElement(L"delay-load");
}
m_XmlWriter.endElement(L"delay-loads");
m_XmlWriter.endElement(L"file");
return;
/*
BytesReadError;
Image.m_Error = L"bad number of bytes read";
return;
*/
Error:
Image.m_Error = GetLastErrorString();
fprintf(stderr, "%ls", Image.m_Error.c_str());
return;
UnrecognizableImage:
Image.m_Error = L" unrecognizable image";
fprintf(stderr, " unrecognizable image");
return;
IgnoreRomImages:
fprintf(stderr, " ignore rom image");
return;
NoDelayloads:
//fprintf(stderr, " no delayloads");
return;
NotAnImage:
//fprintf(stderr, " not an image");
return;
}
void DelayloadTool_t::Main(const StringVector_t& args)
{
typedef std::vector<FilePath_t> Files_t;
Files_t Files;
typedef std::vector<BuildFlavor_t> Builds_t;
Builds_t Builds;
String_t Nttree = GetEnv(L"_Nttree");
BuildFlavor_t localBuild = { L"", L"", L"", L"" };
localBuild.ActualRoot = &Nttree;
BuildFlavor_t buildFlavors[] =
{
{ L"x86fre", L"x86", L"fre", L"robsvbl11" },
{ L"x86chk", L"x86", L"chk", L"robsvbl2" },
{ L"ia64fre", L"ia64", L"fre", L"robsvbl3" },
{ L"ia64chk", L"ia64", L"chk", L"robsvbl4" },
//{ L"amd64fre", "amd64", L"fre", L"robsvbl5" },
//{ L"amd64chk", "amd64", L"chk", L"robsvbl6" },
};
std::vector<String_t> ActualRoots;
ActualRoots.reserve(NUMBER_OF(buildFlavors));
for (StringVector_t::const_iterator i = args.begin() ; i != args.end() ; ++i)
{
String_t arg = *i;
if (arg == L"checkall")
{
SIZE_T j;
for (j = 0 ; j != NUMBER_OF(buildFlavors); ++j)
{
if (buildFlavors[j].ActualRoot == NULL)
{
ActualRoots.insert(ActualRoots.end(), FindLatestReleaseOnServer(buildFlavors[j].ReleaseServer));
buildFlavors[j].ActualRoot = &ActualRoots.back();
Builds.insert(Builds.end(), buildFlavors[j]);
}
}
}
else if (arg == L"checklocal")
{
if (Nttree == L"")
{
Error(L"nttree not set\n");
}
Builds.insert(Builds.end(), localBuild);
}
else if (arg == L"dlllist")
{
//
// feedback loop optimization..
//
}
else
{
SIZE_T k;
for (k = 0 ; k != NUMBER_OF(buildFlavors) ; ++k)
{
if (arg == buildFlavors[k].Name)
{
if (buildFlavors[k].ActualRoot == NULL)
{
ActualRoots.insert(ActualRoots.end(), FindLatestReleaseOnServer(buildFlavors[k].ReleaseServer));
buildFlavors[k].ActualRoot = &ActualRoots.back();
Builds.insert(Builds.end(), buildFlavors[k]);
}
break;
}
}
if (k == NUMBER_OF(buildFlavors))
{
DWORD dw = GetFileAttributesW(arg);
if (dw != 0xFFFFFFFF && (dw & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
Files.insert(Files.end(), arg);
}
}
}
}
this->m_XmlWriter.encoding = L"ISO-8859-1";
this->m_XmlWriter.output = static_cast<IStream*>(&this->m_OutFileStream);
this->m_XmlWriter.indent = VARIANT_TRUE;
if (!m_OutFileStream.OpenForWrite(
L"c:\\delayload_out.xml",
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL
))
{
ThrowLastWin32Error();
}
this->m_XmlWriter.startDocument();
this->m_XmlWriter.startElement(L"files");
for (Builds_t::const_iterator m = Builds.begin() ; m != Builds.end() ; ++m)
{
ProcessBuild(*m);
}
for (Files_t::const_iterator n = Files.begin() ; n != Files.end() ; ++n)
{
ProcessFile(L"", *n);
}
this->m_XmlWriter.endElement(L"files");
this->m_XmlWriter.endDocument();
//Exit:
return;
}
extern "C"
{
void __cdecl mainCRTStartup(void);
void __cdecl wmainCRTStartup(void);
}
int __cdecl main(int argc, char** argv)
{
wmainCRTStartup();
return 0;
}
extern "C" int __cdecl wmain(int argc, wchar_t** argv)
{
CoInitialize(NULL);
FusionpInitializeHeap(GetModuleHandleW(NULL));
DelayloadTool_t tool;
StringVector_t args;
args.reserve(argc);
std::copy(argv + 1, argv + argc, std::back_inserter(args));
tool.Main(args);
return 0;
}