/*++ 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 #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; iThreadNum = ++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= 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; lFileHeader.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; lApiCount; 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; iFileHeader.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; jBaseAddress, DllInfo->Size ); FlushInstructionCache( GetCurrentProcess(), (PVOID)TextStart, (DWORD)(Text-TextStart) ); return Text; } BOOL ReDirectIat( VOID ) { ULONG i; PUCHAR Text = Thunks; for (i=0; iBaseAddress) { 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("", &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( "", &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; iAddress == (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; jApiCount; 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= 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; iArgs[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; iArgCount; 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)(); }