620 lines
19 KiB
C++
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
|