Windows-Server-2003/sdktools/perfmtr/poolfind.cpp

620 lines
19 KiB
C++

/*++
Copyright (c) 2002 Microsoft Corporation
Module Name:
poolfind.cpp
Abstract:
This module contains the code to find the tags in a driver binary
Author:
Andrew Edwards (andred) Oct-2001
Revision History:
Swetha Narayanaswamy (swethan) 19-Mar-2002
--*/
#if !defined (_WIN64)
#pragma warning(disable: 4514)
#include "windows.h"
#include "msdis.h"
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <delayimp.h>
#define TAGSIZE 5
#define DRIVERDIR "\\drivers\\"
#define DRIVERFILEEXT "*.sys"
#define MAXPATH 1024
int __cdecl main(int argc, char** argv);
void ParseImageFile(PTCHAR szImage);
CHAR localTagFile[MAXPATH] = "localtag.txt";
int cSystemDirectory = 0;
//Used to form list of tags used by the same driver
typedef struct _TAGLIST{
TCHAR Tag[TAGSIZE];
struct _TAGLIST *next;
} TAGLIST, *PTAGLIST;
BOOL
GetTagFromCall (
const BYTE *pbCall, // pointer to call instruction
PTCHAR ptchTag, //out param: pointer to tag
DIS *pDis,
int tagLocation) //location of tag in the parameter list
/*++
Routine Description:
This function disassembles the memory allocation function call.
It finds the third push and determines the tag and
places it in the ptchTag return parameter
Return Value:
FALSE: If unable to find tag
TRUE: Otherwise
--*/
{
// try to backup 3 pushes:
// FF /6 + modrm etc
// 50-5F
// 6A <8imm>
// 68 <32imm>
int cbMax = 200;
const BYTE *pb = pbCall;
const BYTE *pTag = NULL;
if ((ptchTag == NULL) || (pbCall == NULL) || (pDis == NULL)) return FALSE;
_tcscpy(ptchTag,"");
while (cbMax--)
{
pb--;
if (pb[0] == 0x68)
{
// disassemble forward
const BYTE *pbInst = pb;
size_t cb = 1;
int cPush = 0;
while (cb && pbInst < pbCall)
{
cb = pDis->CbDisassemble( (DWORD)pbInst,
pbInst, pbCall - pbInst);
if ( (pbInst[0] == 0xFF) &&
((pbInst[1] & 0x38) == 0x30))
{
// this looks like a push <r/m>
cPush++;
}
else if ((pbInst[0] & 0xF0) == 0x50)
{
// this looks like a push <reg>
cPush++;
}
else if (pbInst[0] == 0x6A)
{
// this looks like a push <byte>
cPush++;
}
else if (pbInst[0] == 0x68)
{
// this looks like a push <dword>
cPush++;
}
pbInst += cb;
}
if (cPush == tagLocation && pbInst == pbCall)
{
_sntprintf(ptchTag,5,"%c%c%c%c",
pb[1],pb[2],pb[3],( 0x7f &pb[4]));
return TRUE;
}
}
}
return FALSE;
}
BOOL
FindTags(
const BYTE *pb,
DWORD addr,
PTAGLIST tagList, // out param: List of tags to append the new tags to
DIS *pDis,
int tagLocation) // tag location
/*++
Routine Description:
This function reads the bytes in the instruction and looks for
indirect/direct calls. The tag is appended to the tagList parameter
Return Value:
FALSE: If there is an exception or lack of memory
TRUE: Otherwise
--*/
{
TCHAR tag[TAGSIZE];
BOOL done = FALSE;
PTAGLIST tempTagNode=NULL, prevTagNode=NULL, newTagNode=NULL;
if ((pb==NULL) || (tagList == NULL) || (pDis == NULL)) return FALSE;
// Get the raw bytes and size of the image
try
{
for(;;)
{
done = FALSE;
if (pb[0] == 0xFF && pb[1] == 0x15)
{
// Indirect call
pb += 2;
if (*(DWORD *)pb == (DWORD)addr)
{
// Found a call
if ((GetTagFromCall(pb-2,tag,pDis, tagLocation)) == FALSE)
{
pb++;
continue;
}
tempTagNode = prevTagNode = tagList;
while (tempTagNode != NULL)
{
if ((_tcscmp(tempTagNode->Tag,"")) == 0)
{
// Insert here
_tcsncpy(tempTagNode->Tag, tag, TAGSIZE);
done = TRUE;
break;
}
else if (!(memcmp(tempTagNode->Tag,tag,TAGSIZE)))
{
//Tag already exists in list
done = TRUE;
break;
}
prevTagNode = tempTagNode;
tempTagNode = tempTagNode->next;
}
if (!done )
{
newTagNode = (PTAGLIST)malloc(sizeof(TAGLIST));
if (!newTagNode)
{
printf("Poolmon: Insufficient memory: %d\n", GetLastError());
return FALSE;
}
//There is at least one node allocated so prevTagNode
//will never be NULL
prevTagNode->next = newTagNode;
// Insert here
_tcsncpy(newTagNode->Tag, tag, TAGSIZE);
newTagNode->next = NULL;
}
}
}
pb++;
}
}
catch (...)
{
return FALSE;
}
return TRUE;
}
unsigned RvaToPtr(unsigned rva, IMAGE_NT_HEADERS *pNtHeader)
{
int iSect = 0;
for (PIMAGE_SECTION_HEADER pSect = IMAGE_FIRST_SECTION(pNtHeader); iSect < pNtHeader->FileHeader.NumberOfSections; pSect++, iSect++)
{
if (rva >= pSect->VirtualAddress &&
rva < pSect->VirtualAddress + pSect->SizeOfRawData)
{
rva -= pSect->VirtualAddress;
rva += pSect->PointerToRawData;
return rva;
}
}
//error case
return 0;
}
void
ParseImageFile(
PTCHAR szImage, PTAGLIST tagList) // Image file name
/*++
Routine Description:
This function opens the binary driver image file, reads it and looks for
a memory allocation call
Return Value:
None
--*/
{
DIS *pDis = NULL;
if ((tagList == NULL) || (szImage == NULL) ) return;
// read szImage into memory
FILE *pf = NULL;
pf = _tfopen(szImage, "rb");
if (!pf) return;
if ((fseek(pf, 0, SEEK_END )) != 0) goto exitParseImageFile;
size_t cbMax = 0;
cbMax = ftell(pf);
if (cbMax == -1) goto exitParseImageFile;
if ((fseek(pf, 0, SEEK_SET )) != 0) goto exitParseImageFile;
BYTE *pbImage = NULL;
pbImage = new BYTE[cbMax];
if (!pbImage) goto exitParseImageFile;
if ((fread( pbImage, cbMax, 1, pf )) <= 0) goto exitParseImageFile;
// find the import table
IMAGE_DOS_HEADER *phdr = (IMAGE_DOS_HEADER *)pbImage;
if (phdr->e_magic != IMAGE_DOS_SIGNATURE)
{
_tprintf("Poolmon: Bad image file %s\n", szImage);
goto exitParseImageFile;
}
if (cbMax < offsetof(IMAGE_DOS_HEADER, e_lfanew) +
sizeof(phdr->e_lfanew) ||phdr->e_lfanew == 0)
{
_tprintf("Poolmon: Bad image file %s\n", szImage);
goto exitParseImageFile;
}
IMAGE_NT_HEADERS *pNtHeader =
(IMAGE_NT_HEADERS *) (pbImage + phdr->e_lfanew);
if (pNtHeader == NULL) goto exitParseImageFile;
if (pNtHeader->Signature != IMAGE_NT_SIGNATURE ||
pNtHeader->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
{
_tprintf("Poolmon: Bad image file %s\n", szImage);
goto exitParseImageFile;
}
// Find import tables
IMAGE_DATA_DIRECTORY *pImports =
(IMAGE_DATA_DIRECTORY *)&pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (pImports == NULL) goto exitParseImageFile;
unsigned rva = pImports->VirtualAddress;
// need to adjust from rva to pointer accounting for section alignment
rva = RvaToPtr(rva, pNtHeader);
if (0 == rva) {
goto exitParseImageFile;
}
IMAGE_IMPORT_DESCRIPTOR *pImportDescr =
(IMAGE_IMPORT_DESCRIPTOR *) (pbImage+rva);
if (NULL == pImportDescr)
{
goto exitParseImageFile;
}
//msdis130.dll depends on msvcr70.dll and msvcp70.dll
//Try a loadlibrary on these 2 libraries, and then proceed to delayload msdis130.dll
#pragma prefast(suppress:321, "user guide:Programmers developing on the .NET server can ignore this warning by filtering it out.")
if ((!LoadLibrary("MSVCR70.DLL")) || (!LoadLibrary("MSVCP70.DLL")))
{
printf("Unable to load msvcr70.dll/msvcp70.dll, cannot create local tag file\n");
if (pf) fclose(pf);
if (pbImage) delete[](pbImage);
exit(-1);
}
try {
pDis = DIS::PdisNew( DIS::distX86 );
}
catch (...) {
printf("Poolmon: Unable to load msdis130.dll, cannot create local tag file\n");
if (pf) fclose(pf);
if (pbImage) delete[](pbImage);
exit(-1);
}
if (pDis == NULL)
{
goto exitParseImageFile;
}
// Find the import for ExAllocatePoolWithTag
for (;pImportDescr->Name &&pImportDescr->FirstThunk;pImportDescr++)
{
if (0 == (rva = RvaToPtr(pImportDescr->FirstThunk, pNtHeader))) {
goto exitParseImageFile;
}
IMAGE_THUNK_DATA32 *pIAT = (IMAGE_THUNK_DATA32 *) (pbImage + rva);
if (pIAT == NULL) goto exitParseImageFile;
IMAGE_THUNK_DATA32 *addrIAT =
(IMAGE_THUNK_DATA32 *) (pNtHeader->OptionalHeader.ImageBase + pImportDescr->FirstThunk);
if (addrIAT == NULL) goto exitParseImageFile;
if (0 == (rva = RvaToPtr(pImportDescr->Characteristics, pNtHeader))) {
goto exitParseImageFile;
}
IMAGE_THUNK_DATA32 *pINT= (IMAGE_THUNK_DATA32 *) (pbImage + rva);
if (pINT == NULL) goto exitParseImageFile;
for (;pIAT->u1.Ordinal;)
{
if (IMAGE_SNAP_BY_ORDINAL32(pINT->u1.Ordinal))
{
// by ordinal?
}
else
{
if (0 == (rva = RvaToPtr((int)pINT->u1.AddressOfData, pNtHeader))) {
goto exitParseImageFile;
}
IMAGE_IMPORT_BY_NAME* pIIN = (IMAGE_IMPORT_BY_NAME*) (pbImage + rva);
if (NULL == pIIN) goto exitParseImageFile;
char *name = (char*)pIIN->Name;
if (0 == strcmp( name, "ExAllocatePoolWithTag" ))
{
FindTags(pbImage, (DWORD)addrIAT,tagList, pDis,3);
}
else if (0 == strcmp( name, "ExAllocatePoolWithQuotaTag" ))
{
FindTags(pbImage, (DWORD)addrIAT,tagList,pDis,3);
}
else if (0 == strcmp( name, "ExAllocatePoolWithTagPriority" ))
{
FindTags(pbImage, (DWORD)addrIAT,tagList,pDis,3);
}
//wrapper functions
else if(0 == strcmp(name, "NdisAllocateMemoryWithTag"))
{
FindTags(pbImage, (DWORD)addrIAT,tagList,pDis,3);
}
else if(0 == strcmp(name,"VideoPortAllocatePool"))
{
FindTags(pbImage, (DWORD)addrIAT,tagList,pDis,4);
}
}
addrIAT++;
pIAT++;
pINT++;
}
}
exitParseImageFile:
if (pf) fclose(pf);
if (pbImage) delete[](pbImage);
}
extern "C" BOOL MakeLocalTagFile()
/*++
Routine Description:
This function finds files one by one in the system drivers directory and call ParseImageFile on the image
Return Value:
None
--*/
{
WIN32_FIND_DATA FileData;
HANDLE hSearch=0;
BOOL fFinished = FALSE;
TCHAR sysdir[1024];
PTCHAR filename=NULL;
TCHAR imageName[MAXPATH] = "";
PTAGLIST tagList = NULL;
BOOL ret = TRUE;
FILE *fpLocalTagFile = NULL;
cSystemDirectory = GetSystemDirectory(sysdir, 0);
if(!cSystemDirectory)
{
printf("Poolmon: Unable to get system directory: %d\n", GetLastError());
ret = FALSE;
goto freeall;
}
filename = (PTCHAR)malloc(cSystemDirectory +
(_tcslen(DRIVERDIR) + _tcslen(DRIVERFILEEXT) + 1) * sizeof(TCHAR));
if(!filename)
{
ret = FALSE;
goto freeall;
}
GetSystemDirectory(filename, cSystemDirectory + 1);
_tcscat(filename, DRIVERDIR);
_tcscat(filename, DRIVERFILEEXT);
// Search for .sys files
hSearch = FindFirstFile(filename, &FileData);
if (hSearch == INVALID_HANDLE_VALUE)
{
printf("Poolmon: No .sys files found\n");
ret = FALSE;
goto freeall;
}
_tcsncpy(imageName, filename,MAXPATH);
imageName[MAXPATH-1] = '\0';
tagList = (PTAGLIST)malloc(sizeof(TAGLIST));
if (!tagList)
{
ret = FALSE;
goto freeall;
}
_tcscpy(tagList->Tag,"");
tagList->next = NULL;
int cImagePath = cSystemDirectory+ _tcslen(DRIVERDIR) -1;
while (!fFinished)
{
// Do all the initializations for the next round
// Remove the previous name
imageName[cImagePath] = '\0';
// Initialize existing tagList
PTAGLIST tempTagNode = tagList;
while (tempTagNode != NULL)
{
_tcscpy(tempTagNode->Tag,"");
tempTagNode = tempTagNode->next;
}
try
{
_tcsncat(imageName, FileData.cFileName,MAXPATH-cImagePath);
ParseImageFile(imageName,tagList);
//Remove .sys from szImage
imageName[_tcslen(imageName) - 4] = '\0';
}
catch(...)
{
_tprintf("Poolmon: Could not read tags from %s\n", imageName);
}
if (!fpLocalTagFile)
{
printf("Poolmon: Creating %s in current directory......\n", localTagFile);
fpLocalTagFile = fopen(localTagFile, "w");
if (!fpLocalTagFile)
{
ret = FALSE;
goto freeall;
}
}
tempTagNode = tagList;
while (tempTagNode != NULL)
{
if ((_tcscmp(tempTagNode->Tag,"")))
{
_ftprintf(fpLocalTagFile, "%s - %s\n",
tempTagNode->Tag,imageName + cSystemDirectory + _tcslen(DRIVERDIR) -1);
tempTagNode = tempTagNode->next;
}
else break;
}
if (!FindNextFile(hSearch, &FileData))
{
if (GetLastError() == ERROR_NO_MORE_FILES)
{
fFinished = TRUE;
}
else
{
printf("Poolmon: Cannot find next .sys file\n");
}
}
}
freeall:
// Close the search handle.
if (hSearch)
{
if (!FindClose(hSearch)) {
printf("Poolmon: Unable to close search handle: %d\n", GetLastError());
}
}
if (filename) free(filename);
if (fpLocalTagFile) fclose(fpLocalTagFile);
//Free tagList memory
PTAGLIST tempTagNode = tagList,prevTagNode = tagList;
while (tempTagNode != NULL)
{
tempTagNode = tempTagNode->next;
free(prevTagNode);
prevTagNode = tempTagNode;
}
return ret;
}
FARPROC
WINAPI
PoolmonDLoadErrorHandler (
UINT unReason,
PDelayLoadInfo pDelayInfo
)
{
printf("Poolmon: Unable to load required dlls, cannot create local tag file\n");
exit(-1);
}
PfnDliHook __pfnDliFailureHook2 = PoolmonDLoadErrorHandler;
#endif