1429 lines
36 KiB
C++
1429 lines
36 KiB
C++
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
apidll.cpp
|
|
|
|
Abstract:
|
|
|
|
This file implements the non-architecture specific
|
|
code for the api monitor trojan/support dll.
|
|
|
|
Author:
|
|
|
|
Wesley Witt (wesw) 28-June-1995
|
|
|
|
Environment:
|
|
|
|
User Mode
|
|
|
|
--*/
|
|
#include "apidllp.h"
|
|
#include <tchar.h>
|
|
#pragma hdrstop
|
|
|
|
typedef struct _BUF_INFO {
|
|
LPSTR BufferHead;
|
|
LPSTR Buffer;
|
|
} BUF_INFO, *PBUF_INFO;
|
|
|
|
|
|
PVOID MemPtr;
|
|
PDLL_INFO DllList;
|
|
HANDLE hLogFile;
|
|
PGETCURRENTTHREADID pGetCurrentThreadId;
|
|
PUCHAR ThunksBase;
|
|
PUCHAR Thunks;
|
|
BOOL RunningOnNT;
|
|
BOOL StaticLink;
|
|
ULONG_PTR LoadLibraryA_Addr;
|
|
ULONG_PTR LoadLibraryW_Addr;
|
|
ULONG_PTR FreeLibrary_Addr;
|
|
ULONG_PTR GetProcAddress_Addr;
|
|
HANDLE ApiTraceMutex;
|
|
HANDLE ApiMemMutex;
|
|
PTRACE_BUFFER TraceBuffer;
|
|
DWORD ThreadCnt;
|
|
|
|
DLL_INFO WndProcDllInfo;
|
|
BOOL printNow = 0;
|
|
extern "C" {
|
|
LPDWORD ApiCounter;
|
|
LPDWORD ApiTraceEnabled;
|
|
LPDWORD ApiTimingEnabled;
|
|
LPDWORD FastCounterAvail;
|
|
LPDWORD ApiOffset;
|
|
LPDWORD ApiStrings;
|
|
LPDWORD ApiCount;
|
|
LPDWORD WndProcEnabled;
|
|
LPDWORD WndProcCount;
|
|
LPDWORD WndProcOffset;
|
|
DWORD TlsReEnter;
|
|
DWORD TlsStack;
|
|
DWORD ThunkOverhead;
|
|
DWORD ThunkCallOverhead;
|
|
PTLSGETVALUE pTlsGetValue;
|
|
PTLSSETVALUE pTlsSetValue;
|
|
PGETLASTERROR pGetLastError;
|
|
PSETLASTERROR pSetLastError;
|
|
PVIRTUALALLOC pVirtualAlloc;
|
|
PQUERYPERFORMANCECOUNTER pQueryPerformanceCounter;
|
|
}
|
|
|
|
extern API_MASTER_TABLE ApiTables[];
|
|
BOOL ReDirectIat(VOID);
|
|
BOOL ProcessDllLoad(VOID);
|
|
PUCHAR CreateApiThunk(ULONG_PTR,PUCHAR,PDLL_INFO,PAPI_INFO);
|
|
BOOL ProcessApiTable(PDLL_INFO DllInfo);
|
|
VOID CreateWndProcApi(LPCSTR lpszClassName, WNDPROC *pWndProc);
|
|
VOID CalibrateThunk();
|
|
VOID Calib1Func(VOID);
|
|
VOID Calib2Func(VOID);
|
|
VOID (*Calib1Thunk)();
|
|
VOID (*Calib2Thunk)();
|
|
|
|
extern "C" void
|
|
__cdecl
|
|
dprintf(
|
|
char *format,
|
|
...
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Prints a debug string to the API monitor.
|
|
|
|
Arguments:
|
|
|
|
format - printf() format string
|
|
... - Variable data
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
char buf[1024];
|
|
va_list arg_ptr;
|
|
va_start(arg_ptr, format);
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 1 );
|
|
_vsnprintf(buf, sizeof(buf), format, arg_ptr);
|
|
OutputDebugString( buf );
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 0 );
|
|
return;
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
DWORD
|
|
ApiDllEntry(
|
|
HINSTANCE hInstance,
|
|
DWORD Reason,
|
|
LPVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DLL initialization function.
|
|
|
|
Arguments:
|
|
|
|
hInstance - Instance handle
|
|
Reason - Reason for the entrypoint being called
|
|
Context - Context record
|
|
|
|
Return Value:
|
|
|
|
TRUE - Initialization succeeded
|
|
FALSE - Initialization failed
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Reason == DLL_PROCESS_ATTACH) {
|
|
return ProcessDllLoad();
|
|
}
|
|
|
|
if (Reason == DLL_THREAD_ATTACH) {
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 1 );
|
|
PTHREAD_STACK Stack = (PTHREAD_STACK) pVirtualAlloc( NULL, sizeof(THREAD_STACK), MEM_COMMIT, PAGE_READWRITE );
|
|
|
|
if (!Stack) {
|
|
return FALSE;
|
|
}
|
|
|
|
Stack->ThreadNum = ++ThreadCnt;
|
|
|
|
// Start at 2nd entry so that there is always a parent frame
|
|
Stack->Pointer = (DWORD_PTR)&Stack->Body[FRAME_SIZE];
|
|
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 0 );
|
|
pTlsSetValue( TlsStack, Stack );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (Reason == DLL_THREAD_DETACH) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (Reason == DLL_PROCESS_DETACH) {
|
|
return TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
} //extern "C"
|
|
|
|
PDLL_INFO
|
|
AddDllToList(
|
|
ULONG DllAddr,
|
|
LPSTR DllName,
|
|
ULONG DllSize
|
|
)
|
|
{
|
|
//
|
|
// look for the dll entry in the list
|
|
//
|
|
for (ULONG i=0; i<MAX_DLLS; i++) {
|
|
if (DllList[i].BaseAddress == DllAddr) {
|
|
return &DllList[i];
|
|
}
|
|
}
|
|
|
|
//
|
|
// this check should be unnecessary
|
|
// the debugger side (apimon.exe) takes
|
|
// care of adding the dlls to the list when
|
|
// it gets a module load from the debug
|
|
// subsystem. this code is here only so
|
|
// a test program that is not a debugger
|
|
// will work properly.
|
|
//
|
|
for (i=0; i<MAX_DLLS; i++) {
|
|
if (DllList[i].BaseAddress == 0) {
|
|
DllList[i].BaseAddress = DllAddr;
|
|
strcpy( DllList[i].Name, DllName );
|
|
DllList[i].Size = DllSize;
|
|
return &DllList[i];
|
|
}
|
|
}
|
|
|
|
//
|
|
// we could not find a dll in the list that matched
|
|
// and we could not add it because the list is
|
|
// is full. we're hosed.
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
BOOL
|
|
ProcessDllLoad(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets up the API thunks for the process that this dll
|
|
is loaded into.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
TRUE - Success
|
|
FALSE - Failure
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
ULONG cnt;
|
|
HANDLE hMap;
|
|
|
|
//
|
|
// see if we are running on NT
|
|
// this is necessary because APIMON implements some
|
|
// features that are NOT available on WIN95
|
|
//
|
|
OSVERSIONINFO OsVersionInfo;
|
|
OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
|
|
GetVersionEx( &OsVersionInfo );
|
|
RunningOnNT = OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT;
|
|
|
|
TlsReEnter = TlsAlloc();
|
|
if (TlsReEnter == TLS_OUT_OF_INDEXES) {
|
|
return FALSE;
|
|
}
|
|
TlsStack = TlsAlloc();
|
|
if (TlsStack == TLS_OUT_OF_INDEXES) {
|
|
return FALSE;
|
|
}
|
|
|
|
HMODULE hMod = GetModuleHandle( KERNEL32 );
|
|
if (!hMod) {
|
|
return FALSE;
|
|
}
|
|
pGetCurrentThreadId = (PGETCURRENTTHREADID) GetProcAddress( hMod, "GetCurrentThreadId" );
|
|
if (!pGetCurrentThreadId) {
|
|
return FALSE;
|
|
}
|
|
pGetLastError = (PGETLASTERROR) GetProcAddress( hMod, "GetLastError" );
|
|
if (!pGetLastError) {
|
|
return FALSE;
|
|
}
|
|
pSetLastError = (PSETLASTERROR) GetProcAddress( hMod, "SetLastError" );
|
|
if (!pSetLastError) {
|
|
return FALSE;
|
|
}
|
|
pQueryPerformanceCounter = (PQUERYPERFORMANCECOUNTER) GetProcAddress( hMod, "QueryPerformanceCounter" );
|
|
if (!pQueryPerformanceCounter) {
|
|
return FALSE;
|
|
}
|
|
pTlsGetValue = (PTLSGETVALUE) GetProcAddress( hMod, "TlsGetValue" );
|
|
if (!pTlsGetValue) {
|
|
return FALSE;
|
|
}
|
|
pTlsSetValue = (PTLSSETVALUE) GetProcAddress( hMod, "TlsSetValue" );
|
|
if (!pTlsSetValue) {
|
|
return FALSE;
|
|
}
|
|
pVirtualAlloc = (PVIRTUALALLOC) GetProcAddress( hMod, "VirtualAlloc" );
|
|
if (!pVirtualAlloc) {
|
|
return FALSE;
|
|
}
|
|
|
|
Thunks = (PUCHAR)VirtualAlloc( NULL, THUNK_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
|
if (!Thunks) {
|
|
return FALSE;
|
|
}
|
|
ThunksBase = Thunks;
|
|
|
|
PTHREAD_STACK Stack = (PTHREAD_STACK) pVirtualAlloc( NULL, sizeof(THREAD_STACK), MEM_COMMIT, PAGE_READWRITE );
|
|
if (!Stack) {
|
|
return FALSE;
|
|
}
|
|
|
|
Stack->ThreadNum = ++ThreadCnt;
|
|
|
|
// Start at 2nd entry so that there is always a parent frame
|
|
Stack->Pointer = (DWORD_PTR)&Stack->Body[FRAME_SIZE];
|
|
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 0 );
|
|
pTlsSetValue( TlsStack, Stack );
|
|
|
|
hMap = OpenFileMapping(
|
|
FILE_MAP_WRITE,
|
|
FALSE,
|
|
"ApiWatch"
|
|
);
|
|
if (!hMap) {
|
|
return FALSE;
|
|
}
|
|
|
|
MemPtr = (PUCHAR)MapViewOfFile(
|
|
hMap,
|
|
FILE_MAP_WRITE,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
if (!MemPtr) {
|
|
return FALSE;
|
|
}
|
|
|
|
ApiCounter = (LPDWORD) MemPtr + 0;
|
|
ApiTraceEnabled = (LPDWORD) MemPtr + 1;
|
|
ApiTimingEnabled = (LPDWORD) MemPtr + 2;
|
|
FastCounterAvail = (LPDWORD) MemPtr + 3;
|
|
ApiOffset = (LPDWORD) MemPtr + 4;
|
|
ApiStrings = (LPDWORD) MemPtr + 5;
|
|
ApiCount = (LPDWORD) MemPtr + 6;
|
|
WndProcEnabled = (LPDWORD) MemPtr + 7;
|
|
WndProcCount = (LPDWORD) MemPtr + 8;
|
|
WndProcOffset = (LPDWORD) MemPtr + 9;
|
|
DllList = (PDLL_INFO) ((LPDWORD)MemPtr + 10);
|
|
|
|
//
|
|
// open the shared memory region for the api trace buffer
|
|
//
|
|
hMap = OpenFileMapping(
|
|
FILE_MAP_WRITE,
|
|
FALSE,
|
|
"ApiTrace"
|
|
);
|
|
if (!hMap) {
|
|
return FALSE;
|
|
}
|
|
|
|
TraceBuffer = (PTRACE_BUFFER)MapViewOfFile(
|
|
hMap,
|
|
FILE_MAP_WRITE,
|
|
0,
|
|
0,
|
|
0
|
|
);
|
|
if (!TraceBuffer) {
|
|
return FALSE;
|
|
}
|
|
|
|
ApiTraceMutex = OpenMutex( SYNCHRONIZE, FALSE, "ApiTraceMutex" );
|
|
if (!ApiTraceMutex) {
|
|
return FALSE;
|
|
}
|
|
|
|
ApiMemMutex = OpenMutex( SYNCHRONIZE, FALSE, "ApiMemMutex" );
|
|
if (!ApiMemMutex) {
|
|
return FALSE;
|
|
}
|
|
|
|
// Initialize dummy window proc Dll
|
|
// (Only need the fields accesed by thunk and thunk creation)
|
|
strcpy(WndProcDllInfo.Name, WNDPROCDLL);
|
|
WndProcDllInfo.Enabled = TRUE;
|
|
|
|
CalibrateThunk();
|
|
|
|
ReDirectIat();
|
|
|
|
// Disable close handle exceptions
|
|
if (RunningOnNT) {
|
|
NtCurrentPeb()->NtGlobalFlag &= ~FLG_ENABLE_CLOSE_EXCEPTIONS;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PUCHAR
|
|
ProcessThunk(
|
|
ULONG_PTR ThunkAddr,
|
|
ULONG_PTR IatAddr,
|
|
PUCHAR Text
|
|
)
|
|
{
|
|
PDLL_INFO DllInfo;
|
|
for (ULONG k=0; k<MAX_DLLS; k++) {
|
|
DllInfo = &DllList[k];
|
|
if (ThunkAddr >= DllInfo->BaseAddress &&
|
|
ThunkAddr < DllInfo->BaseAddress+DllInfo->Size) {
|
|
break;
|
|
}
|
|
}
|
|
if (k == MAX_DLLS) {
|
|
return Text;
|
|
}
|
|
|
|
PIMAGE_DOS_HEADER dh = (PIMAGE_DOS_HEADER)DllInfo->BaseAddress;
|
|
PIMAGE_NT_HEADERS nh = (PIMAGE_NT_HEADERS)(dh->e_lfanew + DllInfo->BaseAddress);
|
|
PIMAGE_SECTION_HEADER SectionHdrs = IMAGE_FIRST_SECTION( nh );
|
|
BOOL IsCode = FALSE;
|
|
for (ULONG l=0; l<nh->FileHeader.NumberOfSections; l++) {
|
|
if (ThunkAddr-DllInfo->BaseAddress >= SectionHdrs[l].VirtualAddress &&
|
|
ThunkAddr-DllInfo->BaseAddress < SectionHdrs[l].VirtualAddress+SectionHdrs[l].SizeOfRawData) {
|
|
if (SectionHdrs[l].Characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
|
IsCode = TRUE;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (!IsCode) {
|
|
return Text;
|
|
}
|
|
PAPI_INFO ApiInfo = (PAPI_INFO)(DllInfo->ApiOffset + (ULONG_PTR)DllList);
|
|
for (l=0; l<DllInfo->ApiCount; l++) {
|
|
if (ApiInfo[l].Address == ThunkAddr) {
|
|
return CreateApiThunk( IatAddr, Text, DllInfo, &ApiInfo[l] );
|
|
}
|
|
}
|
|
|
|
return Text;
|
|
}
|
|
|
|
PUCHAR
|
|
ProcessUnBoundImage(
|
|
PDLL_INFO DllInfo,
|
|
PUCHAR Text
|
|
)
|
|
{
|
|
PIMAGE_DOS_HEADER dh = (PIMAGE_DOS_HEADER)DllInfo->BaseAddress;
|
|
if (dh->e_magic != IMAGE_DOS_SIGNATURE) {
|
|
return Text;
|
|
}
|
|
PIMAGE_NT_HEADERS nh = (PIMAGE_NT_HEADERS)(dh->e_lfanew + DllInfo->BaseAddress);
|
|
|
|
PIMAGE_SECTION_HEADER SectionHdrs = IMAGE_FIRST_SECTION( nh );
|
|
ULONG Address = nh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
|
ULONG i;
|
|
for (i=0; i<nh->FileHeader.NumberOfSections; i++) {
|
|
if (Address >= SectionHdrs[i].VirtualAddress &&
|
|
Address < SectionHdrs[i].VirtualAddress+SectionHdrs[i].SizeOfRawData) {
|
|
break;
|
|
}
|
|
}
|
|
if (i == nh->FileHeader.NumberOfSections) {
|
|
return Text;
|
|
}
|
|
|
|
ULONG_PTR SeekPos = DllInfo->BaseAddress +
|
|
nh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
|
|
|
|
ULONG PageProt;
|
|
ULONG ThunkProt;
|
|
ULONG_PTR ImportStart = SeekPos;
|
|
PUCHAR TextStart = Text;
|
|
|
|
VirtualProtect(
|
|
(PVOID)ImportStart,
|
|
nh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size,
|
|
PAGE_READWRITE,
|
|
&PageProt
|
|
);
|
|
|
|
while( TRUE ) {
|
|
PIMAGE_IMPORT_DESCRIPTOR desc = (PIMAGE_IMPORT_DESCRIPTOR)SeekPos;
|
|
|
|
SeekPos += sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
|
|
|
if ((desc->Characteristics == 0) && (desc->Name == 0) && (desc->FirstThunk == 0)) {
|
|
//
|
|
// End of import descriptors
|
|
//
|
|
break;
|
|
}
|
|
ULONG_PTR *ThunkAddr = (ULONG_PTR *)((ULONG)desc->FirstThunk + DllInfo->BaseAddress);
|
|
while( *ThunkAddr ) {
|
|
|
|
#ifdef _X86_
|
|
if (RunningOnNT) {
|
|
Text = ProcessThunk(*ThunkAddr, (ULONG_PTR)ThunkAddr, Text );
|
|
} else {
|
|
Text = ProcessThunk(*(PULONG)(*ThunkAddr + 1), (ULONG)ThunkAddr, Text );
|
|
}
|
|
#else
|
|
Text = ProcessThunk(*ThunkAddr, (ULONG_PTR)ThunkAddr, Text );
|
|
#endif
|
|
ThunkAddr += 1;
|
|
}
|
|
}
|
|
|
|
VirtualProtect(
|
|
(PVOID)ImportStart,
|
|
nh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size,
|
|
PageProt,
|
|
&PageProt
|
|
);
|
|
|
|
FlushInstructionCache(
|
|
GetCurrentProcess(),
|
|
(PVOID)DllInfo->BaseAddress,
|
|
DllInfo->Size
|
|
);
|
|
|
|
FlushInstructionCache(
|
|
GetCurrentProcess(),
|
|
(PVOID)TextStart,
|
|
(DWORD)(Text-TextStart)
|
|
);
|
|
|
|
return Text;
|
|
}
|
|
|
|
PUCHAR
|
|
ProcessBoundImage(
|
|
PDLL_INFO DllInfo,
|
|
PUCHAR Text,
|
|
PULONG IatBase,
|
|
ULONG IatCnt
|
|
)
|
|
{
|
|
ULONG j;
|
|
ULONG PageProt;
|
|
ULONG ThunkProt;
|
|
PUCHAR TextStart = Text;
|
|
|
|
VirtualProtect(
|
|
IatBase,
|
|
IatCnt*4,
|
|
PAGE_READWRITE,
|
|
&PageProt
|
|
);
|
|
|
|
//
|
|
// process the iat entries
|
|
//
|
|
for (j=0; j<IatCnt; j++) {
|
|
if (IatBase[j]) {
|
|
#ifdef _X86_
|
|
if (RunningOnNT) {
|
|
Text = ProcessThunk( IatBase[j], (ULONG_PTR)&IatBase[j], Text );
|
|
} else {
|
|
Text = ProcessThunk(*(PULONG)(IatBase[j] + 1), (ULONG)&IatBase[j], Text );
|
|
}
|
|
#else
|
|
Text = ProcessThunk( IatBase[j], (ULONG_PTR)&IatBase[j], Text );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
VirtualProtect(
|
|
IatBase,
|
|
IatCnt*4,
|
|
PageProt,
|
|
&PageProt
|
|
);
|
|
|
|
FlushInstructionCache(
|
|
GetCurrentProcess(),
|
|
(PVOID)DllInfo->BaseAddress,
|
|
DllInfo->Size
|
|
);
|
|
|
|
FlushInstructionCache(
|
|
GetCurrentProcess(),
|
|
(PVOID)TextStart,
|
|
(DWORD)(Text-TextStart)
|
|
);
|
|
|
|
|
|
return Text;
|
|
}
|
|
|
|
BOOL
|
|
ReDirectIat(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG i;
|
|
PUCHAR Text = Thunks;
|
|
|
|
for (i=0; i<MAX_DLLS; i++) {
|
|
PDLL_INFO DllInfo = &DllList[i];
|
|
if (!DllInfo->BaseAddress) {
|
|
break;
|
|
}
|
|
if ((DllInfo->Snapped) || (DllInfo->Unloaded)) {
|
|
continue;
|
|
}
|
|
PIMAGE_DOS_HEADER dh = (PIMAGE_DOS_HEADER)DllInfo->BaseAddress;
|
|
PULONG IatBase = NULL;
|
|
ULONG IatCnt = 0;
|
|
if (dh->e_magic == IMAGE_DOS_SIGNATURE) {
|
|
PIMAGE_NT_HEADERS nh = (PIMAGE_NT_HEADERS)(dh->e_lfanew + DllInfo->BaseAddress);
|
|
if (nh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) {
|
|
IatBase = (PULONG)(DllInfo->BaseAddress +
|
|
nh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress);
|
|
IatCnt = nh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size / 4;
|
|
}
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
if (!IatBase) {
|
|
Text = ProcessUnBoundImage( DllInfo, Text );
|
|
} else {
|
|
Text = ProcessBoundImage( DllInfo, Text, IatBase, IatCnt );
|
|
}
|
|
DllInfo->Snapped = TRUE;
|
|
|
|
ProcessApiTable( DllInfo );
|
|
}
|
|
|
|
Thunks = Text;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
VOID
|
|
HandleDynamicDllLoadA(
|
|
ULONG_PTR DllAddress,
|
|
LPSTR DllName
|
|
)
|
|
{
|
|
if ( (!DllAddress) || (_stricmp(DllName,TROJANDLL)==0) ) {
|
|
return;
|
|
}
|
|
|
|
ReDirectIat();
|
|
}
|
|
|
|
VOID
|
|
HandleDynamicDllLoadW(
|
|
ULONG_PTR DllAddress,
|
|
LPWSTR DllName
|
|
)
|
|
{
|
|
CHAR AsciiBuf[512];
|
|
ZeroMemory( AsciiBuf, sizeof(AsciiBuf) );
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
DllName,
|
|
wcslen(DllName),
|
|
AsciiBuf,
|
|
sizeof(AsciiBuf),
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (!strlen(AsciiBuf)) {
|
|
return;
|
|
}
|
|
HandleDynamicDllLoadA( DllAddress, AsciiBuf );
|
|
}
|
|
|
|
|
|
VOID
|
|
HandleRegisterClassA(
|
|
WNDCLASSA *pWndClass
|
|
)
|
|
{
|
|
if (!*WndProcEnabled)
|
|
return;
|
|
|
|
// Don't deal with call procedure handles or special addresses
|
|
#ifdef _WIN64
|
|
if (HIWORD((((DWORD_PTR)pWndClass->lpfnWndProc) >> 32)) == 0xFFFF)
|
|
#else
|
|
if (HIWORD(pWndClass->lpfnWndProc) == 0xFFFF)
|
|
#endif
|
|
return;
|
|
|
|
if ((ULONG_PTR)(pWndClass->lpfnWndProc) & 0x80000000) {
|
|
return;
|
|
}
|
|
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 1 );
|
|
|
|
if ((ULONG_PTR)pWndClass->lpszClassName < 0x10000) {
|
|
CreateWndProcApi("<Atom>", &pWndClass->lpfnWndProc);
|
|
} else {
|
|
CreateWndProcApi( pWndClass->lpszClassName, &pWndClass->lpfnWndProc );
|
|
}
|
|
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 0 );
|
|
|
|
}
|
|
|
|
|
|
VOID HandleRegisterClassW(
|
|
WNDCLASSW *pWndClass
|
|
)
|
|
{
|
|
CHAR AsciiBuf[128];
|
|
|
|
if (!*WndProcEnabled)
|
|
return;
|
|
|
|
// Don't deal with call procedure handles or special addresses
|
|
#ifdef _WIN64
|
|
if ((HIWORD((((DWORD_PTR)pWndClass->lpfnWndProc) >> 32)) == 0xFFFF) ||
|
|
#else
|
|
if (( HIWORD(pWndClass->lpfnWndProc) == 0xFFFF) ||
|
|
#endif
|
|
((ULONG_PTR)(pWndClass->lpfnWndProc) & 0x80000000) ) {
|
|
return;
|
|
}
|
|
|
|
if ((ULONG_PTR)pWndClass->lpszClassName < 0x10000) {
|
|
CreateWndProcApi( "<Atom>", &pWndClass->lpfnWndProc );
|
|
return;
|
|
}
|
|
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 1 );
|
|
|
|
ZeroMemory( AsciiBuf, sizeof(AsciiBuf) );
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
pWndClass->lpszClassName,
|
|
wcslen(pWndClass->lpszClassName),
|
|
AsciiBuf,
|
|
sizeof(AsciiBuf),
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 0 );
|
|
|
|
if (!strlen(AsciiBuf)) {
|
|
return;
|
|
}
|
|
|
|
CreateWndProcApi( AsciiBuf, &pWndClass->lpfnWndProc );
|
|
}
|
|
|
|
LONG_PTR
|
|
HandleSetWindowLong(
|
|
HWND hWindow,
|
|
LONG lOffset,
|
|
LPARAM lValue
|
|
)
|
|
{
|
|
if (!*WndProcEnabled || (lOffset != GWLP_WNDPROC))
|
|
return lValue;
|
|
|
|
// Don't handle special addresses
|
|
#ifdef _WIN64
|
|
if ((HIWORD((lValue >> 32)) == 0xFFFF) ||
|
|
#else
|
|
if ( (HIWORD(lValue) == 0xFFFF) ||
|
|
#endif
|
|
((ULONG_PTR)lValue & 0x80000000) ) {
|
|
return lValue;
|
|
}
|
|
|
|
CreateWndProcApi( "Subclass", (WNDPROC*)&lValue );
|
|
|
|
return lValue;
|
|
}
|
|
|
|
|
|
VOID
|
|
HandleDynamicDllFree(
|
|
ULONG_PTR DllAddress
|
|
)
|
|
{
|
|
for (ULONG i=0; i<MAX_DLLS; i++) {
|
|
if (DllList[i].BaseAddress == DllAddress) {
|
|
DllList[i].Unloaded = TRUE;
|
|
// DllList[i].Enabled = FALSE; Leave enable in case it's reloaded
|
|
DllList[i].Snapped = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ULONG_PTR
|
|
HandleGetProcAddress(
|
|
ULONG_PTR ProcAddress
|
|
)
|
|
{
|
|
if (ProcAddress == NULL)
|
|
return NULL;
|
|
|
|
Thunks = ProcessThunk(ProcAddress, (ULONG_PTR)&ProcAddress, Thunks);
|
|
|
|
return ProcAddress;
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
|
|
VOID
|
|
CreateWndProcApi(
|
|
LPCSTR lpszClassName,
|
|
WNDPROC *pWndProc
|
|
)
|
|
{
|
|
PAPI_INFO ApiInfo;
|
|
DWORD i;
|
|
PUCHAR NewThunks;
|
|
CHAR debugBuf[256];
|
|
|
|
// Don't re-thunk one of our own thunks
|
|
if (ThunksBase <= (PUCHAR)*pWndProc && (PUCHAR)*pWndProc < Thunks)
|
|
return;
|
|
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 1 );
|
|
|
|
// Get exclusive access to API memory
|
|
WaitForSingleObject( ApiMemMutex, INFINITE );
|
|
|
|
|
|
// Check for existing thunk for this window proc
|
|
ApiInfo = (PAPI_INFO)(*WndProcOffset + (ULONG_PTR)DllList);
|
|
for (i=0; i<*WndProcCount; i++,ApiInfo++) {
|
|
if (ApiInfo->Address == (ULONG_PTR)*pWndProc) {
|
|
*pWndProc = (WNDPROC)ApiInfo->ThunkAddress;
|
|
ReleaseMutex(ApiMemMutex);
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 0 );
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Allocate an API Info slot
|
|
if (*ApiCount < MAX_APIS) {
|
|
*WndProcOffset -= sizeof(API_INFO);
|
|
*WndProcCount += 1;
|
|
*ApiCount += 1;
|
|
ApiInfo = (PAPI_INFO)(*WndProcOffset + (ULONG_PTR)DllList);
|
|
ApiInfo->Name = *ApiStrings;
|
|
strcpy( (LPSTR)((LPSTR)MemPtr + *ApiStrings), lpszClassName );
|
|
*ApiStrings += (strlen(lpszClassName) + 1);
|
|
}
|
|
else {
|
|
ApiInfo = NULL;
|
|
}
|
|
|
|
|
|
if (ApiInfo != NULL) {
|
|
|
|
ApiInfo->Count = 0;
|
|
ApiInfo->NestCount = 0;
|
|
ApiInfo->Time = 0;
|
|
ApiInfo->CalleeTime = 0;
|
|
ApiInfo->ThunkAddress = 0;
|
|
ApiInfo->Address = (ULONG_PTR)*pWndProc;
|
|
ApiInfo->DllOffset = 0;
|
|
ApiInfo->HardFault = 0;
|
|
ApiInfo->SoftFault = 0;
|
|
ApiInfo->CodeFault = 0;
|
|
ApiInfo->DataFault = 0;
|
|
|
|
NewThunks = CreateMachApiThunk( (PULONG_PTR)pWndProc, Thunks, &WndProcDllInfo, ApiInfo );
|
|
FlushInstructionCache( GetCurrentProcess(), (PVOID)Thunks, (DWORD)(NewThunks - Thunks));
|
|
Thunks = NewThunks;
|
|
}
|
|
|
|
ReleaseMutex( ApiMemMutex );
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 0 );
|
|
|
|
}
|
|
|
|
BOOL
|
|
ProcessApiTable(
|
|
PDLL_INFO DllInfo
|
|
)
|
|
{
|
|
ULONG i,j;
|
|
PAPI_MASTER_TABLE ApiMaster = NULL;
|
|
|
|
i = 0;
|
|
while( ApiTables[i].Name ) {
|
|
if (_stricmp( ApiTables[i].Name, DllInfo->Name ) == 0) {
|
|
ApiMaster = &ApiTables[i];
|
|
break;
|
|
}
|
|
i += 1;
|
|
}
|
|
if (!ApiMaster) {
|
|
return FALSE;
|
|
}
|
|
if (ApiMaster->Processed) {
|
|
return TRUE;
|
|
}
|
|
|
|
i = 0;
|
|
PAPI_TABLE ApiTable = ApiMaster->ApiTable;
|
|
PAPI_INFO ApiInfo = (PAPI_INFO)(DllInfo->ApiOffset + (ULONG_PTR)DllList);
|
|
while( ApiTable[i].Name ) {
|
|
for (j=0; j<DllInfo->ApiCount; j++) {
|
|
if (strcmp( ApiTable[i].Name, (LPSTR)MemPtr+ApiInfo[j].Name ) == 0) {
|
|
ApiInfo[j].ApiTable = &ApiTable[i];
|
|
ApiInfo[j].ApiTableIndex = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
ApiMaster->Processed = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PUCHAR
|
|
CreateApiThunk(
|
|
ULONG_PTR IatAddr,
|
|
PUCHAR Text,
|
|
PDLL_INFO DllInfo,
|
|
PAPI_INFO ApiInfo
|
|
)
|
|
{
|
|
CHAR debugBuf[256];
|
|
#if DBG
|
|
_stprintf(debugBuf, "CreateApiThunk: %s:%s\n",DllInfo->Name, (LPSTR)MemPtr + ApiInfo->Name);
|
|
OutputDebugString(debugBuf);
|
|
#endif
|
|
|
|
LPSTR Name = (LPSTR)MemPtr+ApiInfo->Name;
|
|
if ((strcmp(Name,"FlushInstructionCache")==0) ||
|
|
(strcmp(Name,"NtFlushInstructionCache")==0) ||
|
|
(strcmp(Name,"ZwFlushInstructionCache")==0) ||
|
|
(strcmp(Name,"VirtualProtect")==0) ||
|
|
(strcmp(Name,"VirtualProtectEx")==0) ||
|
|
(strcmp(Name,"NtProtectVirtualMemory")==0) ||
|
|
(strcmp(Name,"ZwProtectVirtualMemory")==0) ||
|
|
(strcmp(Name,"QueryPerformanceCounter")==0) ||
|
|
(strcmp(Name,"NtQueryPerformanceCounter")==0) ||
|
|
(strcmp(Name,"ZwQueryPerformanceCounter")==0) ||
|
|
(strcmp(Name,"NtCallbackReturn")==0) ||
|
|
(strcmp(Name,"ZwCallbackReturn")==0) ||
|
|
(strcmp(Name,"_chkstk")==0) ||
|
|
(strcmp(Name,"_alloca_probe")==0) ||
|
|
(strcmp(Name,"GetLastError")==0) ||
|
|
(strcmp(Name,"SetLastError")==0) ||
|
|
(strcmp(Name,"_setjmp")==0) ||
|
|
(strcmp(Name,"_setjmp3")==0) ||
|
|
(strcmp(Name,"longjmp")==0) ||
|
|
(strcmp(Name,"_longjmpex")==0) ||
|
|
(strcmp(Name,"TlsGetValue")==0) ||
|
|
(strcmp(Name,"TlsSetValue")==0) ||
|
|
(strncmp(Name,"_Ots",4)==0)) {
|
|
return Text;
|
|
}
|
|
|
|
|
|
PUCHAR stat = CreateMachApiThunk( (PULONG_PTR)IatAddr, Text, DllInfo, ApiInfo );
|
|
|
|
return stat;
|
|
}
|
|
|
|
LPSTR
|
|
UnDname(
|
|
LPSTR sym,
|
|
LPSTR undecsym,
|
|
DWORD bufsize
|
|
)
|
|
{
|
|
if (*sym != '?') {
|
|
return sym;
|
|
}
|
|
|
|
if (UnDecorateSymbolName( sym,
|
|
undecsym,
|
|
bufsize,
|
|
UNDNAME_COMPLETE |
|
|
UNDNAME_NO_LEADING_UNDERSCORES |
|
|
UNDNAME_NO_MS_KEYWORDS |
|
|
UNDNAME_NO_FUNCTION_RETURNS |
|
|
UNDNAME_NO_ALLOCATION_MODEL |
|
|
UNDNAME_NO_ALLOCATION_LANGUAGE |
|
|
UNDNAME_NO_MS_THISTYPE |
|
|
UNDNAME_NO_CV_THISTYPE |
|
|
UNDNAME_NO_THISTYPE |
|
|
UNDNAME_NO_ACCESS_SPECIFIERS |
|
|
UNDNAME_NO_THROW_SIGNATURES |
|
|
UNDNAME_NO_MEMBER_TYPE |
|
|
UNDNAME_NO_RETURN_UDT_MODEL |
|
|
UNDNAME_NO_ARGUMENTS |
|
|
UNDNAME_NO_SPECIAL_SYMS |
|
|
UNDNAME_NAME_ONLY )) {
|
|
|
|
return undecsym;
|
|
}
|
|
|
|
return sym;
|
|
}
|
|
|
|
extern "C" ULONG
|
|
GetApiInfo(
|
|
PAPI_INFO *ApiInfo,
|
|
PDLL_INFO *DllInfo,
|
|
PULONG ApiFlag,
|
|
ULONG Address
|
|
)
|
|
{
|
|
ULONG i;
|
|
ULONG rval;
|
|
LONG High;
|
|
LONG Low;
|
|
LONG Middle;
|
|
PAPI_INFO ai;
|
|
|
|
|
|
*ApiInfo = NULL;
|
|
*DllInfo = NULL;
|
|
*ApiFlag = APITYPE_NORMAL;
|
|
|
|
|
|
#if defined(_M_IX86)
|
|
|
|
//
|
|
// the call instruction use to call penter
|
|
// is 5 bytes long
|
|
//
|
|
Address -= 5;
|
|
rval = 1;
|
|
|
|
#elif defined(_M_MRX000)
|
|
|
|
//
|
|
// search for the beginning of the prologue
|
|
//
|
|
PULONG Instr = (PULONG) (Address - 4);
|
|
i = 0;
|
|
rval = 0;
|
|
while( i < 16 ) {
|
|
//
|
|
// the opcode for the addiu instruction is 9
|
|
//
|
|
if ((*Instr >> 16) == 0xafbf) {
|
|
//
|
|
// find the return address
|
|
//
|
|
rval = *Instr & 0xffff;
|
|
break;
|
|
}
|
|
Instr -= 1;
|
|
i += 1;
|
|
}
|
|
if (i == 16 || rval == 0) {
|
|
return 0;
|
|
}
|
|
|
|
#elif defined(_M_ALPHA)
|
|
|
|
rval = 1;
|
|
|
|
#elif defined(_M_PPC)
|
|
|
|
//
|
|
// On PPC, the penter call sequence looks like this:
|
|
//
|
|
// mflr r0
|
|
// stwu sp,-0x40(sp)
|
|
// bl ..penter
|
|
//
|
|
// So the function entry point is the return address - 12.
|
|
//
|
|
// (We really should do a function table lookup here, so
|
|
// we're not dependent on the sequence...)
|
|
//
|
|
|
|
Address -= 12;
|
|
rval = 1;
|
|
|
|
#else
|
|
#error( "unknown target machine" );
|
|
#endif
|
|
|
|
for (i=0; i<MAX_DLLS; i++) {
|
|
if (Address >= DllList[i].BaseAddress &&
|
|
Address < DllList[i].BaseAddress + DllList[i].Size) {
|
|
*DllInfo = &DllList[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!*DllInfo) {
|
|
return 0;
|
|
}
|
|
|
|
ai = (PAPI_INFO)((*DllInfo)->ApiOffset + (ULONG_PTR)DllList);
|
|
|
|
Low = 0;
|
|
High = (*DllInfo)->ApiCount - 1;
|
|
|
|
while (High >= Low) {
|
|
Middle = (Low + High) >> 1;
|
|
if (Address < ai[Middle].Address) {
|
|
|
|
High = Middle - 1;
|
|
|
|
} else if (Address > ai[Middle].Address) {
|
|
|
|
Low = Middle + 1;
|
|
|
|
} else {
|
|
|
|
*ApiInfo = &ai[Middle];
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
if (!*ApiInfo) {
|
|
return 0;
|
|
}
|
|
|
|
if (Address == LoadLibraryA_Addr) {
|
|
*ApiFlag = APITYPE_LOADLIBRARYA;
|
|
} else if (Address == LoadLibraryW_Addr) {
|
|
*ApiFlag = APITYPE_LOADLIBRARYW;
|
|
} else if (Address == FreeLibrary_Addr) {
|
|
*ApiFlag = APITYPE_FREELIBRARY;
|
|
} else if (Address == GetProcAddress_Addr) {
|
|
*ApiFlag = APITYPE_GETPROCADDRESS;
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
|
|
extern "C" VOID
|
|
ApiTrace(
|
|
PAPI_INFO ApiInfo,
|
|
ULONG_PTR Arg[MAX_TRACE_ARGS],
|
|
ULONG ReturnValue,
|
|
ULONG Caller,
|
|
DWORDLONG EnterTime,
|
|
DWORDLONG Duration,
|
|
ULONG LastError
|
|
)
|
|
{
|
|
PTRACE_ENTRY TraceEntry;
|
|
ULONG TraceEntryLen;
|
|
PTHREAD_STACK ThreadStack;
|
|
LPSTR TraceString;
|
|
LPSTR TraceLimit;
|
|
CHAR debugBuf[128];
|
|
ULONG_PTR len;
|
|
DWORD *dwPtr;
|
|
ULONG i;
|
|
ULONG ArgCount;
|
|
|
|
__try {
|
|
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 1 );
|
|
WaitForSingleObject( ApiTraceMutex, INFINITE );
|
|
|
|
// if trace buffer has room for another entry
|
|
if ( TraceBuffer->Offset + sizeof(TRACE_ENTRY) < TraceBuffer->Size ) {
|
|
|
|
TraceEntry = (PTRACE_ENTRY)((PCHAR)TraceBuffer->Entry + TraceBuffer->Offset);
|
|
TraceEntry->Address = ApiInfo->Address;
|
|
TraceEntry->ReturnValue = ReturnValue;
|
|
TraceEntry->Caller = Caller;
|
|
TraceEntry->LastError = LastError;
|
|
TraceEntry->ApiTableIndex = ApiInfo->ApiTableIndex;
|
|
TraceEntry->EnterTime = EnterTime;
|
|
TraceEntry->Duration = Duration;
|
|
|
|
ArgCount = (ApiInfo->ApiTable && ApiInfo->ApiTable->ArgCount) ?
|
|
ApiInfo->ApiTable->ArgCount : DFLT_TRACE_ARGS;
|
|
|
|
for (i=0; i<ArgCount; i++)
|
|
TraceEntry->Args[i] = Arg[i];
|
|
|
|
ThreadStack = (PTHREAD_STACK)pTlsGetValue(TlsStack);
|
|
TraceEntry->ThreadNum = ThreadStack->ThreadNum;
|
|
TraceEntry->Level = (DWORD)((ThreadStack->Pointer - (DWORD_PTR)ThreadStack->Body))
|
|
/ FRAME_SIZE - 1;
|
|
|
|
TraceEntryLen = sizeof(TRACE_ENTRY);
|
|
|
|
if (ApiInfo->ApiTable && ApiInfo->ApiTable->ArgCount) {
|
|
|
|
PAPI_TABLE ApiTable = ApiInfo->ApiTable;
|
|
|
|
TraceString = (LPSTR)TraceEntry + sizeof(TRACE_ENTRY);
|
|
TraceLimit = (LPSTR)TraceBuffer->Entry + TraceBuffer->Size;
|
|
|
|
for (ULONG i=0; i<ApiTable->ArgCount; i++) {
|
|
|
|
switch( LOWORD(ApiTable->ArgType[i]) ) {
|
|
case T_DWORD:
|
|
break;
|
|
|
|
case T_DWORDPTR:
|
|
if (TraceEntry->Args[i]) {
|
|
TraceEntry->Args[i] = *(DWORD*)(TraceEntry->Args[i] + HIWORD(ApiTable->ArgType[i]));
|
|
}
|
|
break;
|
|
|
|
case T_DLONGPTR:
|
|
// Warning - this type wipes out the following arg to save a DWORDLONG
|
|
if (TraceEntry->Args[i]) {
|
|
dwPtr = (DWORD*) (TraceEntry->Args[i] + HIWORD(ApiTable->ArgType[i]));
|
|
TraceEntry->Args[i] = dwPtr[0];
|
|
TraceEntry->Args[i+1] = dwPtr[1];
|
|
}
|
|
break;
|
|
|
|
|
|
case T_LPSTRC:
|
|
case T_LPSTR:
|
|
//
|
|
// go read the string
|
|
//
|
|
{
|
|
if (HIWORD(TraceEntry->Args[i]) == 0)
|
|
len = 0;
|
|
else if (ApiTable->ArgType[i] == T_LPSTRC)
|
|
len = TraceEntry->Args[i+1];
|
|
else {
|
|
TraceEntry->Args[i] += HIWORD(ApiTable->ArgType[i]);
|
|
len = strlen( (LPSTR) TraceEntry->Args[i] );
|
|
}
|
|
|
|
if ( TraceString + len >= TraceLimit )
|
|
len = 0;
|
|
|
|
if (len)
|
|
memcpy(TraceString, (LPSTR)TraceEntry->Args[i], len);
|
|
|
|
TraceString[len] = 0;
|
|
|
|
TraceString += Align(sizeof(WCHAR), (len + 1));
|
|
}
|
|
break;
|
|
|
|
case T_LPWSTRC:
|
|
case T_LPWSTR:
|
|
//
|
|
// go read the string
|
|
//
|
|
{
|
|
if (HIWORD(TraceEntry->Args[i]) == 0)
|
|
len = 0;
|
|
else if (ApiTable->ArgType[i] == T_LPSTRC)
|
|
len = TraceEntry->Args[i+1];
|
|
else {
|
|
TraceEntry->Args[i] += HIWORD(ApiTable->ArgType[i]);
|
|
len = (wcslen( (LPWSTR) TraceEntry->Args[i] ));
|
|
}
|
|
|
|
if ( TraceString + len * sizeof(WCHAR) >= TraceLimit )
|
|
len = 0;
|
|
|
|
if (len)
|
|
memcpy( (LPWSTR)TraceString, (LPWSTR) TraceEntry->Args[i], len * sizeof(WCHAR) );
|
|
|
|
((LPWSTR)TraceString)[len] = 0;
|
|
|
|
TraceString += (len + 1) * sizeof(WCHAR);
|
|
}
|
|
break;
|
|
|
|
case T_UNISTR:
|
|
case T_OBJNAME:
|
|
//
|
|
// go read the string
|
|
//
|
|
{
|
|
PUNICODE_STRING pustr;
|
|
ULONG len;
|
|
|
|
if (ApiTable->ArgType[i] == T_OBJNAME)
|
|
pustr = ((POBJECT_ATTRIBUTES)TraceEntry->Args[i])->ObjectName;
|
|
else
|
|
pustr = (PUNICODE_STRING)TraceEntry->Args[i];
|
|
|
|
len = pustr->Length + sizeof(WCHAR);
|
|
if (pustr != NULL && TraceString + len < TraceLimit) {
|
|
wcsncpy( (LPWSTR)TraceString, pustr->Buffer, pustr->Length/sizeof(WCHAR));
|
|
((LPWSTR)TraceString)[pustr->Length/sizeof(WCHAR)] = 0;
|
|
}
|
|
else {
|
|
len = sizeof(WCHAR);
|
|
((LPWSTR)TraceString)[0] = 0;
|
|
}
|
|
|
|
TraceString += len;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
// align overall entry length to DWORDLONG
|
|
TraceEntryLen = (DWORD)(Align(sizeof(DWORDLONG), TraceString - (LPSTR)TraceEntry));
|
|
}
|
|
TraceBuffer->Count += 1;
|
|
TraceEntry->SizeOfStruct = TraceEntryLen;
|
|
TraceBuffer->Offset += TraceEntryLen;
|
|
}
|
|
|
|
} __except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
|
|
;
|
|
}
|
|
|
|
ReleaseMutex( ApiTraceMutex );
|
|
pTlsSetValue( TlsReEnter, (LPVOID) 0 );
|
|
}
|
|
|
|
VOID
|
|
CalibrateThunk(
|
|
VOID
|
|
)
|
|
{
|
|
int i;
|
|
DLL_INFO CalibDllInfo;
|
|
API_INFO Calib1ApiInfo,Calib2ApiInfo;
|
|
PUCHAR NewThunks;
|
|
ULONGLONG MinTime;
|
|
CHAR debugbuf[128];
|
|
|
|
// Setup calibration Dll
|
|
strcpy(CalibDllInfo.Name, "Calib");
|
|
CalibDllInfo.Enabled = TRUE;
|
|
|
|
// Setup calibration Api
|
|
Calib1ApiInfo.Count = 0;
|
|
Calib1ApiInfo.NestCount = 0;
|
|
Calib1ApiInfo.Time = 0;
|
|
Calib1ApiInfo.CalleeTime = 0;
|
|
Calib1ApiInfo.ThunkAddress = 0;
|
|
Calib1ApiInfo.TraceEnabled = 0;
|
|
Calib1ApiInfo.Address = (ULONG_PTR)Calib1Func;
|
|
|
|
Calib2ApiInfo.Count = 0;
|
|
Calib2ApiInfo.NestCount = 0;
|
|
Calib2ApiInfo.Time = 0;
|
|
Calib2ApiInfo.CalleeTime = 0;
|
|
Calib2ApiInfo.ThunkAddress = 0;
|
|
Calib2ApiInfo.TraceEnabled = 0;
|
|
Calib2ApiInfo.Address = (ULONG_PTR)Calib2Func;
|
|
|
|
// Create thunks
|
|
NewThunks = CreateMachApiThunk( (PULONG_PTR)&Calib1Thunk, Thunks, &CalibDllInfo, &Calib1ApiInfo );
|
|
NewThunks = CreateMachApiThunk( (PULONG_PTR)&Calib2Thunk, NewThunks, &CalibDllInfo, &Calib2ApiInfo );
|
|
FlushInstructionCache( GetCurrentProcess(), (PVOID)Thunks, (DWORD)(NewThunks - Thunks));
|
|
Thunks = NewThunks;
|
|
|
|
ThunkOverhead = 0;
|
|
ThunkCallOverhead = 0;
|
|
|
|
// Call the calibration function via the thunk
|
|
MinTime = 1000000;
|
|
for (i=0; i<1000; i++) {
|
|
|
|
Calib1ApiInfo.Time = 0;
|
|
|
|
(*Calib1Thunk)();
|
|
|
|
if (Calib1ApiInfo.Time < MinTime)
|
|
MinTime = Calib1ApiInfo.Time;
|
|
}
|
|
|
|
// Take min time as the overhead
|
|
ThunkOverhead = (DWORD)MinTime;
|
|
|
|
MinTime = 1000000;
|
|
for (i=0; i<1000; i++) {
|
|
|
|
Calib2ApiInfo.Time = 0;
|
|
|
|
(*Calib2Thunk)();
|
|
|
|
if (Calib2ApiInfo.Time < MinTime)
|
|
MinTime = Calib1ApiInfo.Time;
|
|
}
|
|
|
|
ThunkCallOverhead = (DWORD)MinTime;
|
|
}
|
|
|
|
// Null function for measuring overhead
|
|
VOID
|
|
Calib1Func(
|
|
VOID
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Calling function for measuring overhead
|
|
VOID
|
|
Calib2Func(
|
|
VOID
|
|
)
|
|
{
|
|
(*Calib1Thunk)();
|
|
}
|