windows-nt/Source/XPSP1/NT/sdktools/profiler/profiler.c
2020-09-26 16:20:57 +08:00

521 lines
12 KiB
C

#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <tlhelp32.h>
#include "profiler.h"
#include "inject.h"
#include "view.h"
#include "except.h"
#include "thread.h"
#include "dump.h"
#include "shimdb.h"
#include "shim2.h"
#include "hooks.h"
#include "memory.h"
#include "filter.h"
#include "clevel.h"
#include "cap.h"
extern CHAR g_fnFinalizeInjection[MAX_PATH];
extern HINSTANCE g_hProfileDLL;
extern FIXUPRETURN g_fnFixupReturn[1];
extern DWORD g_dwCallArray[2];
extern CAPFILTER g_execFilter;
int
WINAPI
WinMain(
HINSTANCE hInst,
HINSTANCE hInstPrev,
LPSTR lpszCmd,
int swShow)
{
HANDLE hFile = 0;
BOOL bResult = FALSE;
STARTUPINFO sInfo;
PCHAR pszToken;
PCHAR pszEnd;
PROCESS_INFORMATION pInfo;
DWORD dwEntry = 0;
OSVERSIONINFO verInfo;
BOOL bIsWin9X = FALSE;
HANDLE hDevice = INVALID_HANDLE_VALUE;
//
// Get the OS information
//
ZeroMemory(&verInfo, sizeof(OSVERSIONINFO));
verInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
bResult = GetVersionExA(&verInfo);
if (FALSE == bResult) {
return -1;
}
if (VER_PLATFORM_WIN32_NT == verInfo.dwPlatformId) {
bIsWin9X = FALSE;
}
else if (VER_PLATFORM_WIN32_WINDOWS == verInfo.dwPlatformId) {
bIsWin9X = TRUE;
}
//
// Initialize my working heap
//
bResult = InitializeHeap();
if (FALSE == bResult) {
return -1;
}
//
// Parse the command line
//
pszToken = strstr(lpszCmd, "\"");
if (pszToken) {
pszToken++;
pszEnd = strstr(pszToken, "\"");
*pszEnd = '\0';
}
if (0 == pszToken) {
pszToken = strstr(lpszCmd, " ");
if (0 == pszToken) {
pszToken = strstr(lpszCmd, "\t");
if (0 == pszToken) {
pszToken = lpszCmd;
}
}
}
//
// Initialize our process information struct
//
ZeroMemory(&sInfo, sizeof(STARTUPINFO));
ZeroMemory(&pInfo, sizeof(PROCESS_INFORMATION));
sInfo.cb = sizeof(STARTUPINFO);
dwEntry = GetExeEntryPoint(pszToken);
if (0 == dwEntry) {
return -1;
}
//
// Get our exe ready for DLL injection
//
bResult = CreateProcessA(0,
pszToken,
0,
0,
FALSE,
CREATE_SUSPENDED,
0,
0, //should make this a setable param sooner rather than later
&sInfo,
&pInfo);
if (FALSE == bResult) {
return -1;
}
//
// If we're 9x - bring in the VxD
//
if (TRUE == bIsWin9X) {
hDevice = AttachToEXVectorVXD();
if (INVALID_HANDLE_VALUE == hDevice) {
return -1;
}
}
//
// Inject our dll into the target
//
hFile = InjectDLL(dwEntry,
pInfo.hProcess,
NAME_OF_DLL_TO_INJECT);
if (0 == hFile) {
return -1;
}
//
// Turn the process loose
//
bResult = ResumeThread(pInfo.hThread);
if (FALSE == bResult) {
return -1;
}
//
// Wait for target termination
//
WaitForSingleObject(pInfo.hThread,
INFINITE);
//
// If we're 9x - close our handle to the vxd (this will unload the vxd from memory)
//
if (TRUE == bIsWin9X) {
if (INVALID_HANDLE_VALUE != hDevice) {
DetachFromEXVectorVXD(hDevice);
}
}
return 0;
}
DWORD
GetExeEntryPoint(LPSTR pszExePath)
{
PIMAGE_NT_HEADERS pHeaders;
BOOL bResult;
PCHAR pEXEBits = 0;
DWORD dwEntry = 0;
DWORD dwNumberBytesRead;
HANDLE hFile = INVALID_HANDLE_VALUE;
pEXEBits = (PCHAR)AllocMem(4096 * 1); //allocate a page for reading the PE entry point
if (0 == pEXEBits) {
return dwEntry;
}
hFile = CreateFileA(pszExePath,
GENERIC_READ,
FILE_SHARE_READ,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == hFile) {
goto handleerror;
}
bResult = ReadFile(hFile,
pEXEBits,
4096, //read one page
&dwNumberBytesRead,
0);
if (FALSE == bResult) {
goto handleerror;
}
//
// Dig out the PE information
//
pHeaders = ImageNtHeader2((PVOID)pEXEBits);
if (0 == pHeaders) {
goto handleerror;
}
dwEntry = pHeaders->OptionalHeader.ImageBase + pHeaders->OptionalHeader.AddressOfEntryPoint;
handleerror:
if (pEXEBits) {
FreeMem(pEXEBits);
}
if (INVALID_HANDLE_VALUE != hFile) {
CloseHandle(hFile);
}
return dwEntry;
}
PIMAGE_NT_HEADERS
ImageNtHeader2 (PVOID Base)
{
PIMAGE_NT_HEADERS NtHeaders = NULL;
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) {
NtHeaders = NULL;
}
}
}
return NtHeaders;
}
BOOL
WINAPI
DllMain (
HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved)
{
PIMAGE_NT_HEADERS pHeaders;
PVOID pBase = 0;
DWORD dwEntryPoint;
BOOL bResult = FALSE;
//
// Return true for everything coming through here
//
if (DLL_PROCESS_ATTACH == fdwReason) {
//
// Initialize my working heap
//
bResult = InitializeHeap();
if (FALSE == bResult) {
return FALSE;
}
//
// Initialize the asm for the fixup return
//
//
// Get the entry point from the headers
//
pBase = (PVOID)GetModuleHandle(0);
if (0 == pBase) {
return FALSE;
}
//
// Dig out the PE information
//
pHeaders = ImageNtHeader2(pBase);
if (0 == pHeaders) {
return FALSE;
}
dwEntryPoint = pHeaders->OptionalHeader.ImageBase + pHeaders->OptionalHeader.AddressOfEntryPoint;
//
// Initialize stub asm for cleanup
//
g_fnFinalizeInjection[0] = 0x90; // int 3
g_fnFinalizeInjection[1] = 0xff; // call dword ptr [xxxxxxxx] - RestoreImageFromInjection
g_fnFinalizeInjection[2] = 0x15;
*(DWORD *)(&(g_fnFinalizeInjection[3])) = (DWORD)g_fnFinalizeInjection + 50;
g_fnFinalizeInjection[7] = 0x83;
g_fnFinalizeInjection[8] = 0xc4;
g_fnFinalizeInjection[9] = 0x04;
g_fnFinalizeInjection[10] = 0x61;
g_fnFinalizeInjection[11] = 0xa1;
*(DWORD *)(&(g_fnFinalizeInjection[12])) = (DWORD)g_fnFinalizeInjection + 54;
g_fnFinalizeInjection[16] = 0xff;
g_fnFinalizeInjection[17] = 0xe0;
*(DWORD *)(&(g_fnFinalizeInjection[50])) = (DWORD)RestoreImageFromInjection;
*(DWORD *)(&(g_fnFinalizeInjection[54])) = dwEntryPoint;
//
// Initialize the call return code
//
g_dwCallArray[0] = (DWORD)PopCaller;
g_dwCallArray[1] = (DWORD)g_fnFixupReturn;
g_fnFixupReturn->PUSHAD = 0x60; //pushad (60)
g_fnFixupReturn->PUSHFD = 0x9c; //pushfd (9c)
g_fnFixupReturn->PUSHDWORDESPPLUS24[0] = 0xff; //push dword ptr [esp+24] (ff 74 24 24)
g_fnFixupReturn->PUSHDWORDESPPLUS24[1] = 0x74;
g_fnFixupReturn->PUSHDWORDESPPLUS24[2] = 0x24;
g_fnFixupReturn->PUSHDWORDESPPLUS24[3] = 0x24;
g_fnFixupReturn->CALLROUTINE[0] = 0xff; //call [address] (ff15 dword address)
g_fnFixupReturn->CALLROUTINE[1] = 0x15;
*(DWORD *)(&(g_fnFixupReturn->CALLROUTINE[2])) = (DWORD)&(g_dwCallArray[0]);
g_fnFixupReturn->MOVESPPLUS24EAX[0] = 0x89; //mov [esp+0x24],eax (89 44 24 24)
g_fnFixupReturn->MOVESPPLUS24EAX[1] = 0x44;
g_fnFixupReturn->MOVESPPLUS24EAX[2] = 0x24;
g_fnFixupReturn->MOVESPPLUS24EAX[3] = 0x24;
g_fnFixupReturn->POPFD = 0x9d; //popfd (9d)
g_fnFixupReturn->POPAD = 0x61; //popad (61)
g_fnFixupReturn->RET = 0xc3; //ret (c3)
//
// Store the DLL base address
//
g_hProfileDLL = hinstDLL;
}
return TRUE;
}
BOOL
InitializeProfiler(VOID)
{
BOOL bResult = TRUE;
PIMAGE_NT_HEADERS pHeaders;
PVOID pBase = 0;
DWORD dwEntryPoint;
PVIEWCHAIN pvTemp;
//
// Get the entry point from the headers
//
pBase = (PVOID)GetModuleHandle(0);
if (0 == pBase) {
return FALSE;
}
//
// Dig out the PE information
//
pHeaders = ImageNtHeader2(pBase);
if (0 == pHeaders) {
return FALSE;
}
dwEntryPoint = pHeaders->OptionalHeader.ImageBase + pHeaders->OptionalHeader.AddressOfEntryPoint;
//
// Tag the entry point so it'll start profiling with the initial view
//
bResult = InitializeViewData();
if (FALSE == bResult) {
//
// Something unexpected happened
//
ExitProcess(-1);
}
//
// Initialize execution filter data
//
ZeroMemory(&g_execFilter, sizeof(CAPFILTER));
//
// Initialize thread context data
//
InitializeThreadData();
//
// Get the debug logging setup
//
bResult = InitializeDumpData();
if (FALSE == bResult) {
//
// Something unexpected happened
//
ExitProcess(-1);
}
//
// Initialize the module filtering
//
bResult = InitializeFilterList();
if (FALSE == bResult) {
//
// Something unexpected happened
//
ExitProcess(-1);
}
//
// Set up exception trap mechanism
//
bResult = HookUnchainableExceptionFilter();
if (FALSE == bResult) {
//
// Something unexpected happened while chaining exception filter
//
ExitProcess(-1);
}
//
// Fixup the module list now that everything is restored
//
//
InitializeBaseHooks(g_hProfileDLL);
//
// Write out import table base info
//
bResult = WriteImportDLLTableInfo();
if (FALSE == bResult) {
ExitProcess(-1);
}
//
// Add our entrypoint to the view monitor
//
pvTemp = AddViewToMonitor(dwEntryPoint,
ThreadStart);
if (0 == pvTemp) {
ExitProcess(-1);
}
//
// We're done
//
return TRUE;
}
BOOL
WriteImportDLLTableInfo(VOID)
{
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
MODULEENTRY32 ModuleEntry32;
BOOL bResult;
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,
0);
if (INVALID_HANDLE_VALUE == hSnapshot) {
return FALSE;
}
//
// Walk the DLL imports
//
ModuleEntry32.dwSize = sizeof(ModuleEntry32);
bResult = Module32First(hSnapshot,
&ModuleEntry32);
if (FALSE == bResult) {
return bResult;
}
while(bResult) {
//
// Dump the module information to disk
//
if ((DWORD)(ModuleEntry32.modBaseAddr) != (DWORD)g_hProfileDLL) {
bResult = WriteDllInfo(ModuleEntry32.szModule,
(DWORD)(ModuleEntry32.modBaseAddr),
(DWORD)(ModuleEntry32.modBaseSize));
if (FALSE == bResult) {
CloseHandle(hSnapshot);
return FALSE;
}
}
bResult = Module32Next(hSnapshot,
&ModuleEntry32);
}
if (INVALID_HANDLE_VALUE != hSnapshot) {
CloseHandle(hSnapshot);
}
return TRUE;
}
HANDLE
AttachToEXVectorVXD(VOID)
{
HANDLE hFile;
hFile = CreateFileA(NAME_OF_EXCEPTION_VXD,
0,
0,
0,
0,
FILE_FLAG_DELETE_ON_CLOSE,
0);
return hFile;
}
VOID
DetachFromEXVectorVXD(HANDLE hDevice)
{
CloseHandle(hDevice);
}