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.

205 lines
7.5 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
/*
This tool validates ability to set probe if base relocation is present in probed bytes.
Such probe is not allowed in relocated image where fixups are not yet resolved.
The test application first loads a DLL at preferred base address and then its copy
which is certainly relocated by system loader, so rebase condition is guaranteed.
The tool limits validation of Pin functionality only to case where fixups are not yet resolved.
To detect unresolved fixups the tool checks reference to known address.
*/
#include <stdio.h>
#include <string>
#include "pin.H"
namespace WIND
{
#include <windows.h>
}
using std::string;
/*
* Return preferred image base taken from field OptionalHeader.ImageBase
* in NT optional header of loaded image.
* NOTE: OS may set value in the field to actual base address of the loaded image.
* Pin reasonably assumes that it may only happen AFTER the OS loader relocated the image
* and applied base relocations.
* @param[in] moduleBase Actual base address of loaded image.
*/
ADDRINT GetModulePreferredBase(ADDRINT moduleBase)
{
if (moduleBase == 0)
{
return 0;
}
WIND::PIMAGE_DOS_HEADER pDos = reinterpret_cast<WIND::PIMAGE_DOS_HEADER>(moduleBase);
// Returns FALSE when not DOS MZ header
if (pDos->e_magic != IMAGE_DOS_SIGNATURE)
{
return 0;
}
const WIND::PIMAGE_NT_HEADERS pHeaders = reinterpret_cast<WIND::PIMAGE_NT_HEADERS>
(reinterpret_cast<WIND::ULONG_PTR>(pDos) + pDos->e_lfanew);
// check that this is PE/COFF image
if (pHeaders->Signature != IMAGE_NT_SIGNATURE)
{
return 0;
}
return pHeaders->OptionalHeader.ImageBase;
}
/*
* Return TRUE if baseName matches tail of imageName. Comparison is case-insensitive.
* @param[in] imageName image file name in either form with extension
* @param[in] baseName image base name with extension (e.g. kernel32.dll)
*/
static BOOL CmpBaseImageName(const string & imageName, const string & baseName)
{
if (imageName.size() >= baseName.size())
{
return _stricmp(imageName.c_str() + imageName.size() - baseName.size(), baseName.c_str()) == 0;
}
return FALSE;
}
static VOID on_module_loading(IMG img, VOID *data)
{
// Image rebase detection.
// Only mismatch between actual and preferred base address is considered as detectable rebase.
BOOL rebase_detected = ( IMG_LowAddress(img) != GetModulePreferredBase(IMG_LowAddress(img)) );
RTN routine = RTN_FindByName(img, "baserel_in_probe");
if (!RTN_Valid(routine))
{
routine = RTN_FindByName(img, "_baserel_in_probe");
}
// This same function is exported by the main executable and by 2 loaded DLLs.
// Main executable is built with base address 0, so it will be relocated.
// DLLs are exact copies, differ only by file name.
// The first DLL is loaded at its preferred base address 0x10000000 and the second is relocated.
if (RTN_Valid(routine))
{
// Fixup is located at offset 3 from function entry point.
// Value of the fixup is address of the function entry point.
ADDRINT * fixup_addr = reinterpret_cast<ADDRINT *>(RTN_Address(routine) + 3);
if (rebase_detected)
{
// This is apparent image relocation event.
// In general we expect Pin to reject probe with base relocation,
// since Pin considers worst scenario (fixups were not yet resolved).
// Check that probe is not allowed due to unresolved fixup.
if (!RTN_IsSafeForProbedInsertion(routine) && !RTN_IsSafeForProbedReplacement(routine))
{
printf("fixup is handled properly, probe refused\n");
}
else if (*fixup_addr == RTN_Address(routine))
{
// If Pin indeed allowed probe (for images loaded before Pin attach, excluding main exe),
// ensure that fixups have been already applied.
printf("fixup is handled properly, probe enabled as fixups are considered applied\n");
}
else
{
printf("ERROR: probe was enabled while fixups were not yet applied in relocated image\n");
}
}
else
{
if (RTN_IsSafeForProbedInsertion(routine) && RTN_IsSafeForProbedReplacement(routine))
{
if (*fixup_addr != RTN_Address(routine))
{
// Unexpected situaltion. OS reports fixups were applied while actually it is not yet done.
printf("ERROR: Image fared relocated. Probe was enabled while fixups were not yet applied\n");
}
else
{
printf("fixup is handled properly, probe enabled\n");
}
}
else
{
printf("ERROR: probe was unexpectedly refused for non-relocated image or image with applied fixups\n");
}
}
fflush(stdout);
}
if (CmpBaseImageName(IMG_Name(img), "kernel32.dll"))
{
routine = RTN_FindByName(img, "DuplicateHandle");
if (!RTN_Valid(routine))
{
routine = RTN_FindByName(img, "_DuplicateHandle@28");
}
if (RTN_Valid(routine))
{
// DuplicateHandle in kernel32.dll contains base relocation in first 5 bytes of code.
// Anyway Pin should allow probe regardless of kernel32.dll relocation.
// kernel32.dll is always loaded in memory prior to Pin attach and thus it is assumed
// base relocation were already applied by OS prior to invocation of this callback.
// Check that probe is allowed.
if (RTN_IsSafeForProbedInsertion(routine) && RTN_IsSafeForProbedReplacement(routine))
{
printf("fixup is handled properly, probe enabled\n");
}
// This extra check is done to demonstrate that Pin may reject this probe due to
// other reasons (like wrong assumptions in Pin's naive static code discovery algorithm
// regarding branch targets in probed bytes).
// NOTE: Due to lack of internal info we do not consider this reject as test failure.
else if (!RTN_IsSafeForProbedInsertion(routine) && !RTN_IsSafeForProbedReplacement(routine))
{
if (rebase_detected)
{
printf("fixup is handled properly, probe LIKELY refused due to reason not related to image relocation\n");
}
else
{
printf("fixup is handled properly, probe refused due to reason not related to image relocation\n");
}
}
else
{
printf("ERROR: probe of DuplicateHandle is handled improperly\n");
}
fflush(stdout);
}
}
// The tool is expected to print the message 4 times.
}
int main(int argc, char** argv)
{
PIN_InitSymbols();
if (!PIN_Init(argc, argv))
{
IMG_AddInstrumentFunction(on_module_loading, 0);
PIN_StartProgramProbed();
}
exit(1);
}