// ACHooks.cpp : Implementation of CDecalApp and DLL registration. #include "stdafx.h" #include "ACHooks.h" #include #include /* Heyus 23 March 2003 */ #include ".\achooks.h" /* I believe in VC6, the limit of unnamed variables (_bstr_t("foo")) has been reached, which caused the following error: F:\Decal\source\Decal\ACHooks.cpp(467) : fatal error C1001: INTERNAL COMPILER ERROR (compiler file 'E:\8168\vc98\p2\src\P2\main.c', line 494) Please choose the Technical Support command on the Visual C++ Help menu, or open the Technical Support help file for more information This macro allows us to use a single variable, while keeping more or less the same syntax. A variable of type _bstr_t named _Unnamed must be declared in any procedure this is used. Note - This only works with inline strings -> L"Foo" */ #define BSTRT(x) (_Unnamed = L##x, _Unnamed) ///////////////////////////////////////////////////////////////////////////// cACHooks* cACHooks::s_pACHooks = NULL; long g_lObjectDestroyedProc = 0; long g_lSelectItemHijackProc = 0; long g_lIdentifyHijackProc = 0; long g_lToolTextProc = 0; long g_lToolText2Proc = 0; void (__fastcall *pfnOldChatMessage)(int _ecx, int _edx, char *, DWORD ) = NULL; void (*pfnOldChatText)() = NULL; void (*pfnUseItem)( DWORD, DWORD ) = NULL; void (*pfnMoveItemEx)( DWORD, DWORD, DWORD ) = NULL; void ( __fastcall *pfnInternalStringDestructor)( qString * ) = NULL; long (*pfnSendMessageToID)( qString *, long ) = NULL; long (*pfnSendMessageToName)( qString *, qString * ) = NULL; long (*pfnSendMessageByMask)( long, qString * ) = NULL; long (*pfnLocalChatText)( qString * ) = NULL; long (*pfnLocalChatEmote)( qString * ) = NULL; qString* ( __fastcall *pfnInternalStringConstructor)( qString *, long, char * ) = NULL; bool g_bTimestamp; char *g_szTimestampFormat; DWORD g_lTimestampColor; char g_charBufferPreviousCall; extern void __fastcall OnChatMessage( int _ecx, int _edx, char* pText, long dwColor ); extern void CatchToolText(); extern void CatchToolTextAppend(); extern void OnChatText(); extern void IdentifyShortcircuit(); extern void SelectItemHook(); extern void ObjectDestroyedHook(); extern DWORD HookCall (DWORD dwCallAddress, DWORD dwReplacement); cACHooks::cACHooks() { g_bTimestamp = false; s_pACHooks = this; m_bDecalRef = false; m_bIdQueueRef = false; m_bMismatch = true; m_bPrevSelect = false; m_bCurrentSelect = false; m_bMouse = false; m_bCastSpell = false; m_bMoveItem = false; m_bSelectItem = false; m_bUseItem = false; m_bAllYourBase = false; m_bSetCombatState = false; m_bCombatStateOffset = false; m_bChatState = false; m_bRequestID = false; m_bStackCount = false; m_bTestFormula = false; m_bVendorID = false; m_bBusyState = false; m_bPointerState = false; m_bMoveItemEx = false; m_bFaceHeading = false; m_bChatMessageAddy = false; m_bSendMessageToID = false; m_bSendMessageToName = false; m_bSendMessageToMask = false; m_bLocalChatText = false; m_bLocalChatEmote = false; m_bSetAutorun = false; m_bGetVital = false; m_bGetAttribute = false; m_bGetSkill = false; m_bLogout = false; m_bSecureTrade_Add = false; m_bSecureTrade_Add_Off1 = false; m_bSecureTrade_Add_Off2 = false; m_bGetSkillInfo = false; m_bGetAttributeInfo = false; m_bGetVitalInfo = false; m_bSelectItemHook = false; m_bUstAddItem_Useable = false; m_bRequestShortcircuit = false; m_bToolTextHook = false; m_bToolText2Hook = false; m_bIdleLoc = false; m_Hooks = 0; memset(m_HooksEx, 0, sizeof(m_HooksEx)); m_HookCount = 0; USES_CONVERSION; _bstr_t _Unnamed; char szPath[ MAX_PATH ]; DWORD dwCount = MAX_PATH; g_charBufferPreviousCall = '\n'; DWORD dwTimestamp = 0; char szTimestampFormat[ MAX_PATH ]; DWORD lTimestampFormatLength = MAX_PATH; RegKey key; if( key.Open( HKEY_LOCAL_MACHINE, "SOFTWARE\\Decal", KEY_READ ) == ERROR_SUCCESS ) { if( key.QueryDWORDValue( _T("Timestamp"), dwTimestamp ) != ERROR_SUCCESS ) dwTimestamp = 0; if( key.QueryStringValue( _T("TimestampFormat"), szTimestampFormat, &lTimestampFormatLength ) != ERROR_SUCCESS ) /* Heyus 21 March 2003 */ memset( szTimestampFormat, 0, sizeof(szTimestampFormat) ), strncpy( szTimestampFormat, "[%H:%M]", sizeof( szTimestampFormat ) ); if( key.QueryDWORDValue( _T("TimestampColor"), g_lTimestampColor ) != ERROR_SUCCESS ) g_lTimestampColor = 12; // Grey key.Close(); } int iStrLen = strlen( szTimestampFormat ) + 2; g_szTimestampFormat = new char[ iStrLen ]; memset( g_szTimestampFormat, 0, iStrLen ); _snprintf( g_szTimestampFormat, iStrLen, "%s ", szTimestampFormat ); // 0xFFFFFFFF = same color as chat text, for those that want time stamps but don't // want to infringe upon their 300 max chat window items if( g_lTimestampColor < 0 || g_lTimestampColor > 22 && g_lTimestampColor != 0xFFFFFFFF ) g_lTimestampColor = 12; // Grey g_bTimestamp = dwTimestamp ? true : false ; TCHAR szFilename[ MAX_PATH ]; ::GetModuleFileName( NULL, szFilename, MAX_PATH ); LPTSTR strProcessName = ::_tcsrchr( szFilename, _T( '\\' ) ); strProcessName[ 7 ] = _T( '\0' ); if( ::_tcsicmp( strProcessName + 1, _T( "client" ) ) != 0 ) return; key.Open( HKEY_LOCAL_MACHINE, "SOFTWARE\\Decal\\Agent", KEY_READ ); key.QueryStringValue( _T("AgentPath"), szPath, &dwCount ); strncat( szPath, "\\memlocs.xml", MAX_PATH ); MSXML::IXMLDOMDocumentPtr pMemLocDoc; pMemLocDoc.CreateInstance( __uuidof( MSXML::DOMDocument ) ); pMemLocDoc->async = false; VARIANT_BOOL bSuccess = pMemLocDoc->load( szPath ); if( ! bSuccess ) { std::string szXML; DecryptXML( szPath, szXML ); if( szXML != "" ) bSuccess = pMemLocDoc->loadXML( _bstr_t( szXML.c_str() ) ); } if( bSuccess ) { MSXML::IXMLDOMElementPtr pNode = pMemLocDoc->selectSingleNode( BSTRT( "locations" ) ); long lVerMajor = 0, lVerMinor = 0, lVerRelease = 0; _variant_t vVersion = pNode->getAttribute( BSTRT( "version" ) ); char *szTemp, *szVersion = OLE2A( vVersion.bstrVal ); // I'm tired and sscanf is crashing - this works even if it's lame lVerMajor = atol( szVersion ); szTemp = strstr( szVersion, "." ) + 1; lVerMinor = atol( szTemp ); szTemp = strstr( szTemp, "." ) + 1; lVerRelease = atol( szTemp ); RegKey rk; if( rk.Open( HKEY_LOCAL_MACHINE, _T( "Software\\Microsoft\\Microsoft Games\\Asheron's Call\\1.00" ) ) == ERROR_SUCCESS ) { TCHAR szClientPath[ MAX_PATH ]; DWORD dwPathLength = MAX_PATH; if( rk.QueryStringValue ( _T( "path" ), szClientPath, &dwPathLength ) == ERROR_SUCCESS ) { ::_tcscpy( szClientPath + ( dwPathLength - 1 ), _T( "\\client.exe" ) ); DWORD dwDummy, dwVerSize = ::GetFileVersionInfoSize( const_cast< LPTSTR > ( szClientPath ), &dwDummy ); if( dwVerSize != 0 ) { BYTE *pbVersionInfo = reinterpret_cast< BYTE * >( ::_alloca( dwVerSize ) ); ::GetFileVersionInfo( const_cast< LPTSTR > ( szClientPath ), 0, dwVerSize, pbVersionInfo ); VS_FIXEDFILEINFO *vffi; UINT nLength = sizeof( VS_FIXEDFILEINFO ); if( ::VerQueryValue( pbVersionInfo, _T( "\\" ), reinterpret_cast< LPVOID * >( &vffi ), &nLength ) ) { if( (static_cast< long >( HIWORD( vffi->dwFileVersionMS ) ) == lVerMajor) && (static_cast< long >( LOWORD( vffi->dwFileVersionMS ) ) == lVerMinor) && (static_cast< long >( HIWORD( vffi->dwFileVersionLS ) ) == lVerRelease) ) { m_bMismatch = false; } } } } } MSXML::IXMLDOMNodeListPtr pNodes = pMemLocDoc->selectNodes( BSTRT( "/locations/memloc" ) ); for( pNode = pNodes->nextNode(); pNode.GetInterfacePtr() != NULL; pNode = pNodes->nextNode() ) { _variant_t vName = pNode->getAttribute( _T( "name" ) ), vValue = pNode->getAttribute( _T( "value" ) ); sMemoryLocation loc; loc.Name = OLE2A( vName.bstrVal ); loc.Location = wcstoul( vValue.bstrVal, 0, 16 ); m_mLocationList[ loc.Name ] = loc; } } long Val; if( QueryMemLoc( BSTRT( "PrevItem1" ), &Val ) == S_OK ) m_lPrevSelect[0] = Val; if( QueryMemLoc( BSTRT( "PrevItem2" ), &Val ) == S_OK ) { m_lPrevSelect[1] = Val; m_bPrevSelect = true; m_Hooks |= ePrevSelect ; } if( QueryMemLoc( BSTRT( "CurrentItem1" ), &Val ) == S_OK ) m_lCurrentSelect[0] = Val; if( QueryMemLoc( BSTRT( "CurrentItem2" ), &Val ) == S_OK ) { m_lCurrentSelect[1] = Val; m_bCurrentSelect = true; m_Hooks |= eCurrentSelect ; } if( QueryMemLoc( BSTRT( "ChatMessage" ), &Val ) == S_OK ) pfnOldChatMessage = reinterpret_cast< void (__fastcall*)( int, int, char *, DWORD ) >( Val ); if( QueryMemLoc( BSTRT( "ChatMessageAddy" ), &Val ) == S_OK ) { m_lChatMessageAddy = Val; m_bChatMessageAddy = true; } if( QueryMemLoc( BSTRT( "ChatText" ), &Val ) == S_OK ) pfnOldChatText = reinterpret_cast< void (*)() >( Val ); if( QueryMemLoc( BSTRT( "Mouse1X" ), &Val ) == S_OK ) m_lMouse[0] = Val; if( QueryMemLoc( BSTRT( "Mouse2X" ), &Val ) == S_OK ) m_lMouse[1] = Val; if( QueryMemLoc( BSTRT( "Mouse3X" ), &Val ) == S_OK ) m_lMouse[2] = Val; if( QueryMemLoc( BSTRT( "Mouse4X" ), &Val ) == S_OK ) { m_bMouse = true; m_lMouse[3] = Val; m_Hooks |= eMouse ; } if( QueryMemLoc( BSTRT( "CastSpell" ), &Val ) == S_OK ) { m_bCastSpell = true; m_Hooks |= eCastSpell ; m_lCastSpell = Val; } if( QueryMemLoc( BSTRT( "MoveItem" ), &Val ) == S_OK ) { m_bMoveItem = true; m_Hooks |= eMoveItem ; m_lMoveItem = Val; } if( QueryMemLoc( BSTRT( "SelectItem" ), &Val ) == S_OK ) { m_bSelectItem = true; m_Hooks |= eSelectItem ; m_lSelectItem = Val; } if( QueryMemLoc( BSTRT( "UseItem" ), &Val ) == S_OK ) { m_bUseItem = true; m_Hooks |= eUseItem ; SetHookEx( eUseItemRaw ); SetHookEx( eUseFociSpell ); m_lUseItem = Val; pfnUseItem = reinterpret_cast< void (*)( DWORD, DWORD ) >( Val ); } if( QueryMemLoc( BSTRT( "AllYourBase" ), &Val ) == S_OK ) { // The memloc formerly known as CombatState m_bAllYourBase = true; m_Hooks |= eCombatState ; m_lAllYourBase = Val; } if( QueryMemLoc( BSTRT( "SetCombatState" ), &Val ) == S_OK ) { m_bSetCombatState = true; m_Hooks |= eSetCombatState ; m_lSetCombatState = Val; } if( QueryMemLoc( BSTRT( "CombatStateOffset" ), &Val ) == S_OK ) { m_bCombatStateOffset = true; m_Hooks |= eCombatState ; m_lCombatStateOffset = Val; } if( QueryMemLoc( BSTRT( "ChatState" ), &Val ) == S_OK ) { m_bChatState = true; m_Hooks |= eChatState ; m_lChatState = Val; } if( QueryMemLoc( BSTRT( "GetFellowStats" ), &Val ) == S_OK ) { m_bRequestID = true; m_lRequestID = Val; m_Hooks |= eGetFellowStats; SetHookEx( eRequestID ); } if( QueryMemLoc( BSTRT( "RequestID" ), &Val ) == S_OK ) { m_bRequestID = true; m_lRequestID = Val; m_Hooks |= eGetFellowStats; SetHookEx( eRequestID ); } if( QueryMemLoc( BSTRT( "NumStackItemsSelected" ), &Val ) == S_OK ) { m_bStackCount = true; m_Hooks |= eStackCount ; m_lStackCount = Val; } if( QueryMemLoc( BSTRT( "TestFormula" ), &Val ) == S_OK ) m_lTestFormula = Val; if( QueryMemLoc( BSTRT( "TestFormulavtp" ), &Val ) == S_OK ) { m_bTestFormula = true; m_Hooks |= eTestFormula ; m_lTestFormulaVTable = Val; } if( QueryMemLoc( BSTRT( "VendorID" ), &Val ) == S_OK ) { m_bVendorID = true; m_Hooks |= eVendorID ; m_lVendorID = Val; } if( QueryMemLoc( BSTRT( "ItemBusyState" ), &Val ) == S_OK ) { m_bBusyState = true; m_Hooks |= eBusyState ; m_lBusyState = Val; } if( QueryMemLoc( BSTRT( "ItemBusyGUID" ), &Val ) == S_OK ) { m_bBusyStateID = true; m_Hooks |= eBusyStateID ; m_lBusyStateID = Val; } if( QueryMemLoc( BSTRT( "PointerState" ), &Val ) == S_OK ) { m_bPointerState = true; m_Hooks |= ePointerState ; m_lPointerState = Val; } if( QueryMemLoc( BSTRT( "MoveItemEx" ), &Val ) == S_OK ) { m_bMoveItemEx = true; m_Hooks |= eMoveItemEx ; m_lMoveItemEx = Val; pfnMoveItemEx = reinterpret_cast< void (*)(DWORD, DWORD, DWORD) >( Val ); } if( QueryMemLoc( BSTRT( "3DAreaWidth" ), &Val ) == S_OK ) { m_bArea3DWidth = true; m_Hooks |= eArea3DWidth ; m_lpArea3DWidth = reinterpret_cast< long * >( Val ); } if( QueryMemLoc( BSTRT( "3DAreaHeight" ), &Val ) == S_OK ) { m_bArea3DHeight = true; m_Hooks |= eArea3DHeight ; m_lpArea3DHeight = reinterpret_cast< long * >( Val ); } if( QueryMemLoc( BSTRT( "ObjectFromGUID" ), &Val ) == S_OK ) { m_lObjectFromGuid = Val; SetHookEx( eObjectFromGUID ); if( QueryMemLoc( BSTRT( "ObjectFromGUIDClass" ), &Val ) == S_OK ) { m_lObjectFromGuidClass = Val; SetHookEx( eObjectFromGUIDClass ); m_bObjectFromGuid = true; } } m_lMovementThingyParent = m_lMovementThingyOffset = m_lFaceHeading = 0; if( QueryMemLoc( BSTRT( "MovementThingyParent" ), &Val ) == S_OK) { m_lMovementThingyParent = Val; } if( QueryMemLoc( BSTRT( "MovementThingyOffset" ), &Val ) == S_OK) { m_lMovementThingyOffset = Val; } if( QueryMemLoc( BSTRT( "FaceHeading" ), &Val ) == S_OK) { m_lFaceHeading = Val; } if( QueryMemLoc( BSTRT( "SetAutorun" ), &Val ) == S_OK) { m_lSetAutorun = Val; } if (m_lMovementThingyParent && m_lMovementThingyOffset && m_lFaceHeading) { m_bFaceHeading = true; m_Hooks |= eFaceHeading; } if (m_lMovementThingyParent && m_lMovementThingyOffset && m_lSetAutorun) { m_bSetAutorun = true; m_Hooks |= eSetAutorun; } /* // While the address of ObjectDestroyed is interesting, it isn't actually needed. // We can't assume that the calls we're hooking call to this address, as they // might have already been hooked! if( QueryMemLoc( BSTRT( "ObjectDestroyed"), &Val ) == S_OK ) { } */ long lCall1 = 0, lCall2 = 0; if( QueryMemLoc( BSTRT( "ObjectDestroyed_Call1"), &Val ) == S_OK ) { lCall1 = Val; } if( QueryMemLoc( BSTRT( "ObjectDestroyed_Call2"), &Val ) == S_OK ) { lCall2 = Val; } if (lCall1 && lCall2) { DWORD dwFunc1 = HookCall (lCall1, (DWORD) ObjectDestroyedHook); DWORD dwFunc2 = HookCall (lCall2, (DWORD) ObjectDestroyedHook); _ASSERTE (dwFunc1 && (dwFunc1 == dwFunc2)); if (dwFunc1 && (dwFunc1 != dwFunc2)) { // Doh, okay put them back, something's wrong. HookCall (lCall1, dwFunc1); HookCall (lCall2, dwFunc2); } else { m_Hooks |= eObjectDestroyed; g_lObjectDestroyedProc = dwFunc1; } } if( QueryMemLoc( BSTRT( "InternalStringConstructor" ), &Val ) == S_OK) { m_bInternalStringConstructor = true; m_lInternalStringConstructor = Val; pfnInternalStringConstructor = reinterpret_cast< qString *(__fastcall*)(qString *, long, char *) >( Val ); } if( QueryMemLoc( BSTRT( "InternalStringDestructor" ), &Val ) == S_OK) { m_bInternalStringDestructor = true; m_lInternalStringDestructor = Val; pfnInternalStringDestructor = reinterpret_cast< void(__fastcall *)(qString *) >( Val ); } if( QueryMemLoc( BSTRT( "SendMessageToID" ), &Val ) == S_OK) { m_bSendMessageToID = true; m_lSendMessageToID = Val; pfnSendMessageToID = reinterpret_cast< long(*)(qString *, long) >( Val ); } if( QueryMemLoc( BSTRT( "SendMessageToName" ), &Val ) == S_OK) { m_bSendMessageToName = true; m_lSendMessageToName = Val; pfnSendMessageToName = reinterpret_cast< long(*)(qString *, qString *) >( Val ); } if( QueryMemLoc( BSTRT( "SendMessageToMask" ), &Val ) == S_OK) { m_bSendMessageToMask = true; m_lSendMessageToMask = Val; pfnSendMessageByMask = reinterpret_cast< long(*)( long, qString * ) >( Val ); } if( QueryMemLoc( BSTRT( "LocalChatText" ), &Val ) == S_OK) { m_bLocalChatText = true; m_lLocalChatText = Val; pfnLocalChatText = reinterpret_cast< long(*)(qString *) >( Val ); } if( QueryMemLoc( BSTRT( "LocalChatEmote" ), &Val ) == S_OK) { m_bLocalChatEmote = true; m_lLocalChatEmote = Val; pfnLocalChatEmote = reinterpret_cast< long(*)(qString *) >( Val ); } if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToID ) m_Hooks |= eSendTell; if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToName ) m_Hooks |= eSendTellEx; if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bLocalChatText ) m_Hooks |= eLocalChatText; if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bLocalChatEmote ) m_Hooks |= eLocalChatEmote; if( m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToMask ) SetHookEx( eSendMessageByMask ); if( QueryMemLoc( BSTRT( "VitalBase" ), &Val ) == S_OK ) { m_lVitalBase = Val; } if( QueryMemLoc( BSTRT( "GetVital" ), &Val ) == S_OK ) { m_lGetVital = Val; m_bGetVital = true; } if( QueryMemLoc( BSTRT( "GetAttribute" ), &Val ) == S_OK ) { m_lGetAttribute = Val; m_bGetAttribute = true; } if( QueryMemLoc( BSTRT( "GetSkill" ), &Val ) == S_OK ) { m_lGetSkill = Val; m_bGetSkill = true; } if( m_lVitalBase ) { if( m_bGetVital ) m_Hooks |= eGetVital; if( m_bGetAttribute ) m_Hooks |= eGetAttribute; if( m_bGetSkill ) m_Hooks |= eGetSkill; } if( QueryMemLoc( BSTRT( "Logout" ), &Val ) == S_OK ) { m_lLogout = Val; m_bLogout = true; SetHookEx(eLogout); } if (QueryMemLoc(BSTRT( "SecureTrade_Add" ), &Val) == S_OK) { m_lSecureTrade_Add = Val; m_bSecureTrade_Add = true; } if (QueryMemLoc(BSTRT( "SecureTrade_Add_Off1" ), &Val) == S_OK) { m_lSecureTrade_Add_Off1 = Val; m_bSecureTrade_Add_Off1 = true; } if (QueryMemLoc(BSTRT( "SecureTrade_Add_Off2" ), &Val) == S_OK) { m_lSecureTrade_Add_Off2 = Val; m_bSecureTrade_Add_Off2 = true; } if (m_bSecureTrade_Add && m_bSecureTrade_Add_Off1 && m_bSecureTrade_Add_Off2 && m_bAllYourBase) { SetHookEx(eSecureTrade_Add); } if (QueryMemLoc(BSTRT( "GetSkillInfo" ), &Val) == S_OK) { m_lGetSkillInfo = Val; m_bGetSkillInfo = true; } if (QueryMemLoc(BSTRT( "GetVitalInfo" ), &Val) == S_OK) { m_lGetVitalInfo = Val; m_bGetVitalInfo = true; } if (QueryMemLoc(BSTRT( "GetAttributeInfo" ), &Val) == S_OK) { m_lGetAttributeInfo = Val; m_bGetAttributeInfo = true; } /* I don't believe the vTable is used for any of these, however, if it becomes necessary the functionality is here to a) detect the problem (crash at 0xFF......), and fix it without requiring a complete update to Decal */ if (QueryMemLoc(BSTRT( "GetSkillInfo_vT" ), &Val) == S_OK) { m_lGetSkillInfo_vT = Val; } else { m_lGetSkillInfo_vT = 0xFF111111; } if (QueryMemLoc(BSTRT( "GetVitalInfo_vT" ), &Val) == S_OK) { m_lGetVitalInfo_vT = Val; } else { m_lGetVitalInfo_vT = 0xFF222222; } if (QueryMemLoc(BSTRT( "GetAttributeInfo_vT" ), &Val) == S_OK) { m_lGetAttributeInfo_vT = Val; } else { m_lGetAttributeInfo_vT = 0xFF333333; } if (m_lVitalBase) { if (m_bGetSkillInfo) { SetHookEx(eSkillInfo); } if (m_bGetVitalInfo) { SetHookEx(eVitalInfo); } if (m_bGetAttributeInfo) { SetHookEx(eAttributeInfo); } } if (QueryMemLoc(BSTRT( "ToolTextHJ" ), &Val) == S_OK) { m_lToolTextHJ = Val; g_lToolTextProc = HookCall( m_lToolTextHJ, (DWORD)CatchToolText ); SetHookEx( eToolText ); m_bToolTextHook = true; } if (QueryMemLoc(BSTRT( "ToolText2HJ" ), &Val) == S_OK) { m_lToolText2HJ = Val; g_lToolText2Proc = HookCall( m_lToolText2HJ, (DWORD)CatchToolTextAppend ); SetHookEx( eToolText2 ); m_bToolText2Hook = true; } DWORD dwOldProtect; if( QueryMemLoc( BSTRT( "OnChatText" ), &Val ) == S_OK ) { VirtualProtect( reinterpret_cast< void * >( Val ), 4, PAGE_EXECUTE_READWRITE, &dwOldProtect ); *reinterpret_cast< long * >( Val ) = ( reinterpret_cast< long >( OnChatText ) - ( Val + 0x4 ) ); } if( QueryMemLoc( BSTRT( "OnChatMessage" ), &Val ) == S_OK ) { VirtualProtect( reinterpret_cast< void * >( Val ), 4, PAGE_EXECUTE_READWRITE, &dwOldProtect ); *reinterpret_cast< long * >( Val ) = ( reinterpret_cast< long >( OnChatMessage ) - ( Val + 0x4 ) ); } m_Hooks |= eHooksAvailEx; if( QueryMemLoc( BSTRT( "SelectItemHook" ), &Val ) == S_OK ) { m_lSelectItemHook = Val; m_bSelectItemHook = true; g_lSelectItemHijackProc = HookCall( m_lSelectItemHook, (DWORD) SelectItemHook ); SetHookEx( eOnSelectItemEvent ); } bool m_bUstAddItem = false; bool m_bUstAddItem_Off1 = false; bool m_bUstAddItem_Off2 = false; if (QueryMemLoc(BSTRT( "UstAddItem" ), &Val) == S_OK) { m_lUstAddItem = Val; m_bUstAddItem = true; } if (QueryMemLoc(BSTRT( "UstAddItem_Off1" ), &Val) == S_OK) { m_lUstAddItem_Off1 = Val; m_bUstAddItem_Off1 = true; } if (QueryMemLoc(BSTRT( "UstAddItem_Off2" ), &Val) == S_OK) { m_lUstAddItem_Off2 = Val; m_bUstAddItem_Off2 = true; } if (m_bUstAddItem && m_bUstAddItem_Off1 && m_bUstAddItem_Off2 && m_bChatMessageAddy) { SetHookEx(eUstAddItem); m_bUstAddItem_Useable = true; } m_lRequestShortcircuit1 = 0; m_lRequestShortcircuit2 = 0; m_lRequestShortcircuit3 = 0; if( QueryMemLoc( BSTRT( "RequestShortcircuit1" ), &Val ) == S_OK ) m_lRequestShortcircuit1 = Val; if( QueryMemLoc( BSTRT( "RequestShortcircuit2" ), &Val ) == S_OK ) m_lRequestShortcircuit2 = Val; if( QueryMemLoc( BSTRT( "RequestShortcircuit3" ), &Val ) == S_OK ) m_lRequestShortcircuit3 = Val; if( m_lRequestShortcircuit1 && m_lRequestShortcircuit2 && m_lRequestShortcircuit3 ) { DWORD dwHook1 = HookCall( m_lRequestShortcircuit1, (DWORD) IdentifyShortcircuit ); DWORD dwHook2 = HookCall( m_lRequestShortcircuit2, (DWORD) IdentifyShortcircuit ); DWORD dwHook3 = HookCall( m_lRequestShortcircuit3, (DWORD) IdentifyShortcircuit ); if( dwHook1 && dwHook2 && dwHook3 && (dwHook1 == dwHook2) && (dwHook2 == dwHook3) ) { m_bRequestShortcircuit = true; g_lIdentifyHijackProc = dwHook1; } else { // Something's wrong. HookCall( m_lRequestShortcircuit1, dwHook1 ); HookCall( m_lRequestShortcircuit2, dwHook2 ); HookCall( m_lRequestShortcircuit3, dwHook3 ); } } if( QueryMemLoc( BSTRT( "IdleTime" ), &Val ) == S_OK ) { m_lIdleLoc = Val; m_bIdleLoc = true; SetHookEx( eSetIdleTime ); } if( QueryMemLoc( BSTRT( "SlashDay" ), &Val ) == S_OK ) { m_lSlashDay = Val; m_bSlashDay = true; SetHookEx( eSetDay ); } } cACHooks::~cACHooks() { _bstr_t _Unnamed; delete [] g_szTimestampFormat; long Val, lCall1 = 0, lCall2 = 0; if( QueryMemLoc( BSTRT( "ObjectDestroyed_Call1"), &Val ) == S_OK ) { lCall1 = Val; } if( QueryMemLoc( BSTRT( "ObjectDestroyed_Call2"), &Val ) == S_OK ) { lCall2 = Val; } if (lCall1 && lCall2) { HookCall( lCall1, g_lObjectDestroyedProc ); HookCall( lCall2, g_lObjectDestroyedProc ); } if( m_bRequestShortcircuit ) { HookCall( m_lRequestShortcircuit1, g_lIdentifyHijackProc ); HookCall( m_lRequestShortcircuit2, g_lIdentifyHijackProc ); HookCall( m_lRequestShortcircuit3, g_lIdentifyHijackProc ); } if( m_bToolTextHook ) { HookCall( m_lToolTextHJ, g_lToolTextProc ); } if( m_bToolText2Hook ) { HookCall( m_lToolText2HJ, g_lToolText2Proc ); } s_pACHooks = NULL; g_lObjectDestroyedProc = 0; if( m_bDecalRef ) m_pDecal.Release(); if( m_bIdQueueRef ) m_pIdQueue.Release(); } void cACHooks::DecryptXML( const char *szPath, std::string &szXML ) { if( szPath == NULL ) { szXML = ""; return; } FILE *f = fopen( szPath, "rb" ); if( f == NULL ) { szXML = ""; return; } szXML.clear(); unsigned char szBuffer[1025]; try { CCryptProv crypt; if( crypt.Initialize( PROV_RSA_FULL, "Decal_Memlocs", MS_DEF_PROV ) == NTE_BAD_KEYSET ) crypt.Initialize( PROV_RSA_FULL, "Decal_Memlocs", MS_DEF_PROV, CRYPT_NEWKEYSET ); CCryptMD5Hash hash; hash.Initialize( crypt ); hash.AddString( DECAL_KEY ); CCryptDerivedKey key; key.Initialize( crypt, hash ); DWORD dwDecLen = 0; while( ! feof(f) ) { memset( szBuffer, 0, sizeof( szBuffer ) ); dwDecLen = fread( szBuffer, 1, 1024, f ); key.Decrypt( feof(f), (BYTE *) szBuffer, &dwDecLen ); szXML += (char *)szBuffer; } key.Destroy(); hash.Destroy(); crypt.Release(); } catch( ... ) { // crap... szXML = ""; } fclose( f ); } STDMETHODIMP cACHooks::SetDecal( IUnknown *pDecal ) { if( m_bDecalRef ) { m_pDecal.Release(); m_bDecalRef = false; } if( pDecal->QueryInterface( __uuidof( IDecal ), reinterpret_cast< void ** >( &m_pDecal ) ) == S_OK ) m_bDecalRef = true; return S_OK; } STDMETHODIMP cACHooks::QueryMemLoc(BSTR bstrName, long *pVal) { USES_CONVERSION; if( m_bMismatch ) { *pVal = NULL; return S_FALSE; } std::string queryName = OLE2A( bstrName ); LocMap::iterator i = m_mLocationList.find( queryName ); if( i != m_mLocationList.end() ) { *pVal = i->second.Location; return S_OK; } return S_FALSE; } STDMETHODIMP cACHooks::get_CurrentSelection( long *pVal ) { if( !m_bCurrentSelect ) return S_FALSE; *pVal = *( reinterpret_cast< long * >( m_lCurrentSelect[0] ) ); return S_OK; } STDMETHODIMP cACHooks::put_CurrentSelection(long newVal) { if( !m_bCurrentSelect ) return S_FALSE; *( reinterpret_cast< long * >( m_lCurrentSelect[0] ) ) = newVal; *( reinterpret_cast< long * >( m_lCurrentSelect[1] ) ) = newVal; return S_OK; } STDMETHODIMP cACHooks::get_PreviousSelection(long *pVal) { if( !m_bPrevSelect ) return S_FALSE; *pVal = *( reinterpret_cast< long * >( m_lPrevSelect[0] ) ); return S_OK; } STDMETHODIMP cACHooks::put_PreviousSelection(long newVal) { if( !m_bPrevSelect ) return S_FALSE; *( reinterpret_cast< long * >( m_lPrevSelect[0] ) ) = newVal; *( reinterpret_cast< long * >( m_lPrevSelect[1] ) ) = newVal; return S_OK; } /* Heyus - 23 March 2003 */ // Should be the method by which all functions write text to the chat window // Writes raw text (does not append \n). chatMessageArg1 and 2 are the first two // arguments you normally pass to pfnOldChatMessage. THIS SHOULD NOT BE CALLED BY // PLUGINS/FILTERS UNLESS ABSOLUTELY NECESSARY. // Will implement IKitchenSink later void InternalRawWriteToChat( char* pText, long lColor, int chatMessageArg1, int chatMessageArg2 ) { if( pText == NULL ) return; if( g_bTimestamp ) { bool bDoTimeStamp = (g_charBufferPreviousCall == '\n') ? true : false; int iStrLen = strlen( pText ); char *szTimeStamp = new char[ iStrLen + 2 ]; memset( szTimeStamp, 0, iStrLen + 2 ); // Copy into a larger buffer to accomodate a possible \n // If i were more awake, I'd see if this could just be replaced with // g_charBufferPreviousCall = pText[strlen(pText)] int iOffset = 0; char *szTemp = pText; while( *szTemp != 0 ) { szTimeStamp[ iOffset++ ] = *szTemp; g_charBufferPreviousCall = *szTemp; szTemp++; } // Format a time stamp char szFormattedTimestamp[ MAX_PATH ]; memset( szFormattedTimestamp, 0, MAX_PATH ); time_t stTmpTime; time( &stTmpTime ); tm *tmTime = localtime( &stTmpTime ); long lFormattedStampLength = (long) strftime( szFormattedTimestamp, MAX_PATH, g_szTimestampFormat, tmTime ); while( *szTimeStamp != NULL && *szTimeStamp == '\n' ) { pfnOldChatMessage( chatMessageArg1, chatMessageArg2, "\n", lColor ); g_charBufferPreviousCall = '\n'; *szTimeStamp++; } char* szToken = strtok( szTimeStamp, _T( "\n" ) ); char* toWrite; if( g_lTimestampColor != 0xFFFFFFFF ) lFormattedStampLength = 0; while( szToken != NULL ) { int len = strlen( szToken ) + lFormattedStampLength + 3; toWrite = new char[ len ]; memset( toWrite, 0, len ); if( bDoTimeStamp ) { if( g_lTimestampColor == 0xFFFFFFFF ) toWrite = strcat( toWrite, szFormattedTimestamp ); else pfnOldChatMessage( chatMessageArg1, chatMessageArg2, szFormattedTimestamp, g_lTimestampColor ); } toWrite = strcat( toWrite, szToken ); char* nextToken = strtok( NULL, "\n" ); if( nextToken != NULL || pText[strlen(pText)-1] == '\n' ) toWrite = strcat( toWrite, "\n" ); pfnOldChatMessage( chatMessageArg1, chatMessageArg2, toWrite, lColor ); szToken = nextToken; delete[] toWrite; } delete[] szTimeStamp; } else pfnOldChatMessage( chatMessageArg1, chatMessageArg2, pText, lColor ); return; } STDMETHODIMP cACHooks::ChatOut(BSTR szText, long lColor) { if( pfnOldChatMessage == NULL ) return S_FALSE; DWORD *Addy = reinterpret_cast< DWORD * > ( m_lChatMessageAddy ); if( *Addy == NULL ) return S_FALSE; USES_CONVERSION; char *strText = OLE2A( szText ); if( strText == NULL ) return S_FALSE; int iStrLen = strlen( strText ); int iOffset = 0; char* szTemp = new char[iStrLen + 2]; memset( szTemp, 0, iStrLen+2 ); strncpy( szTemp, strText, iStrLen + 2 ); strncat( szTemp, "\n", iStrLen + 2 ); InternalRawWriteToChat( szTemp, lColor, *Addy, 0 ); return S_OK; } /* Heyus - 23 Mar 2003 - Fixed to point to the new universal function */ STDMETHODIMP cACHooks::RawChatOut(BSTR szText, long lColor) { if( pfnOldChatMessage == NULL ) return S_FALSE; DWORD *Addy = reinterpret_cast< DWORD * > ( m_lChatMessageAddy ); if( *Addy == NULL ) return S_FALSE; USES_CONVERSION; char *strText = OLE2A( szText ); InternalRawWriteToChat( strText, lColor, *Addy, 0 ); return S_OK; } STDMETHODIMP cACHooks::SetCursorPosition(long lX, long lY) { if( !m_bMouse ) return S_FALSE; for( int i = 0; i < 4; i++ ) { *(reinterpret_cast< long * >( m_lMouse[i] ) ) = lX; *(reinterpret_cast< long * >( m_lMouse[i] + 4 ) ) = lY; } SetCursorPos( lX, lY ); for( i = 0; i < 4; i++ ) { *(reinterpret_cast< long * >( m_lMouse[i] ) ) = lX; *(reinterpret_cast< long * >( m_lMouse[i] + 4 ) ) = lY; } return S_OK; } STDMETHODIMP cACHooks::CastSpell(long lSpellID, long lObjectID) { if( !m_bCastSpell ) return S_FALSE; long lCombatState = 4; if( get_CombatState( &lCombatState ) == S_OK ) { if( lCombatState != 4 ) //Must be in MAGIC MODE return S_FALSE; } long lCurrentSelect; get_CurrentSelection( &lCurrentSelect ); put_CurrentSelection( lObjectID ); typedef void(*CastPtr)( long ); CastPtr pCast = reinterpret_cast< CastPtr >( m_lCastSpell ); pCast( lSpellID ); put_CurrentSelection( lCurrentSelect ); return S_OK; } STDMETHODIMP cACHooks::MoveItem(long lObjectID, long lPackID, long lSlot, VARIANT_BOOL bStack) { if( !m_bMoveItem ) return S_FALSE; long lStack = 0; if( bStack == VARIANT_TRUE ) lStack = 1; typedef void(*MovePtr)( long, long, long, long ); MovePtr pMove = reinterpret_cast< MovePtr >( m_lMoveItem ); pMove( lObjectID, lPackID, lSlot, lStack ); return S_OK; } STDMETHODIMP cACHooks::SelectItem(long lObjectID) { if( !m_bSelectItem ) return S_FALSE; typedef void(*SelectPtr)( long ); SelectPtr pSelect = reinterpret_cast< SelectPtr >( m_lSelectItem ); pSelect( lObjectID ); return S_OK; } STDMETHODIMP cACHooks::UseItem(long lObjectID, long lUseState) { if( !m_bUseItem ) return S_FALSE; __asm { push 0x0 push lUseState push lObjectID call pfnUseItem add esp, 0x0C } return S_OK; } STDMETHODIMP cACHooks::UseItemRaw(long lObjectID, long lUseState, long lUseMethod) { if( !m_bUseItem ) return S_FALSE; __asm { push lUseMethod push lUseState push lObjectID call pfnUseItem add esp, 0x0C } return S_OK; } STDMETHODIMP cACHooks::UseFociSpell(long UseThis, long OnThis) { if( !m_bUseItem ) return S_FALSE; long lCurrentSelected; get_CurrentSelection( &lCurrentSelected ); put_CurrentSelection( OnThis ); __asm { push 0x1 push 0x1 push UseThis call pfnUseItem add esp, 0x0C } put_CurrentSelection( lCurrentSelected ); return S_OK; } STDMETHODIMP cACHooks::get_CombatState(long *pVal) { if( !m_bAllYourBase ) return S_FALSE; if( !m_bCombatStateOffset ) return S_FALSE; *pVal = *(reinterpret_cast< long * >( (*reinterpret_cast< char ** >( m_lAllYourBase )) + m_lCombatStateOffset )); return S_OK; } STDMETHODIMP cACHooks::SetCombatState(long pVal) { if( !m_bSetCombatState ) return S_FALSE; if( (pVal < 1) || (pVal > 4) ) return E_INVALIDARG; typedef void(__fastcall *SetCombatStatePtr)( long, long, long, long ); SetCombatStatePtr pSetCState = reinterpret_cast< SetCombatStatePtr >( m_lSetCombatState ); pSetCState( *( reinterpret_cast< long * >( m_lAllYourBase ) ), 0, pVal, 1 ); return S_OK; } STDMETHODIMP cACHooks::get_ChatState(VARIANT_BOOL *pVal) { if( !m_bChatState ) return S_FALSE; long *pChatState = reinterpret_cast< long * >( m_lChatState ); if( m_bDecalRef ) { CComPtr< IPSite > pSite; if( m_pDecal->get_Object( _bstr_t( "services\\DecalPlugins.InjectService\\site" ), __uuidof( IPSite ), reinterpret_cast< void ** >( &pSite ) ) == S_OK ) { if( pSite->get_Focus( pVal ) != S_OK ) *pVal = *pChatState ? VARIANT_TRUE : VARIANT_FALSE; else *pVal = (*pChatState || (*pVal == VARIANT_TRUE) ) ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } else *pVal = *pChatState ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } *pVal = *pChatState ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } STDMETHODIMP cACHooks::UseItemEx(long UseThis, long OnThis) { if( !m_bUseItem ) return S_FALSE; long lCurrentSelected; get_CurrentSelection( &lCurrentSelected ); put_CurrentSelection( OnThis ); UseItem( UseThis, 1 ); put_CurrentSelection( lCurrentSelected ); return S_OK; } STDMETHODIMP cACHooks::GetFellowStats(long lCharID) { return IDQueueAdd( lCharID ); } STDMETHODIMP cACHooks::get_SelectedStackCount(long lStackCount, long *pVal) { if( !m_bStackCount ) return S_FALSE; *pVal = *( reinterpret_cast< long * >( m_lStackCount ) ); return S_OK; } STDMETHODIMP cACHooks::put_SelectedStackCount(long lStackCount, long newVal) { if( !m_bStackCount ) return S_FALSE; *( reinterpret_cast< long * >( m_lStackCount ) ) = newVal; return S_OK; } STDMETHODIMP cACHooks::get_VendorID(long *pVal) { if( !m_bVendorID ) return S_FALSE; *pVal = *( reinterpret_cast< long * >( m_lVendorID ) ); return S_OK; } STDMETHODIMP cACHooks::get_BusyState(long *pVal) { if( !m_bBusyState ) return S_FALSE; *pVal = *( reinterpret_cast< long * >( m_lBusyState ) ); return S_OK; } STDMETHODIMP cACHooks::get_BusyStateID(long *pVal) { if( !m_bBusyStateID ) return S_FALSE; *pVal = *( reinterpret_cast< long * >( m_lBusyStateID ) ); return S_OK; } STDMETHODIMP cACHooks::get_PointerState(long *pVal) { if( !m_bPointerState ) return S_FALSE; *pVal = *( reinterpret_cast< long * >( m_lPointerState ) ); return S_OK; } STDMETHODIMP cACHooks::MoveItemEx(long lObjectID, long lDestinationID) { if( !m_bMoveItemEx ) return S_FALSE; __asm { push 0x0 push lDestinationID push lObjectID call pfnMoveItemEx add esp, 0x0C } return S_OK; } long* cACHooks::GetCs(long offs) { if (!m_bAllYourBase) { return NULL ; } // follow multiple indirection from m_lCombatState to the long *rv = reinterpret_cast< long * >( m_lAllYourBase ); if (*rv) rv = reinterpret_cast< long * >( *rv + 0xE4 ); if (*rv) rv = reinterpret_cast< long * >( *rv + 0x160 ); if (*rv) rv = reinterpret_cast< long * >( *rv + offs); return rv ; } STDMETHODIMP cACHooks::get_Heading(double *pVal) { HRESULT rv = S_OK ; if (!m_bAllYourBase) { *pVal = 0.0 ; return S_FALSE ; } long* pX = GetCs(0x6C) ; long* pY = GetCs(0x70) ; float fHeadingX(0) ; float fHeadingY(0) ; if (pX) { fHeadingX = *(reinterpret_cast< float * >(pX)) ; } else { rv = S_FALSE ; } if (pY) { fHeadingY = *(reinterpret_cast< float * >(pY)) ; } else { rv = S_FALSE ; } long lCardinal = 0; if( (fHeadingX > 0) && (fHeadingY > 0) ) lCardinal = 90; if( (fHeadingX < 0) && (fHeadingY < 0) ) lCardinal = 270; if( (fHeadingX < 0) && (fHeadingY > 0) ) lCardinal = 270; if( (fHeadingX > 0) && (fHeadingY < 0) ) lCardinal = 450; *pVal = fabs( atan( fHeadingY / fHeadingX ) * 180 / 3.14159265358979323846 - 450 + lCardinal ); return rv; } STDMETHODIMP cACHooks::get_Landblock(long *pVal) { HRESULT rv = S_OK ; *pVal = 0 ; if (!m_bAllYourBase) { return S_FALSE ; } long *cs = GetCs(0x4C) ; if (cs) { *pVal = *cs ; } else { *pVal = rv ; } return rv; } STDMETHODIMP cACHooks::get_LocationX(double *pVal) { HRESULT rv = S_OK ; if (!m_bAllYourBase) { *pVal = 0 ; return S_FALSE ; } long* cs = GetCs(0x50) ; float val(0) ; if (cs) { val = *(reinterpret_cast< float * >(cs)); } else { rv = S_FALSE ; } *pVal = double(val) ; return rv; } STDMETHODIMP cACHooks::get_LocationY(double *pVal) { HRESULT rv = S_OK ; if (!m_bAllYourBase) { *pVal = 0 ; return S_FALSE ; } long* cs = GetCs(0x54) ; float val(0) ; if (cs) { val = *(reinterpret_cast< float * >(cs)); } else { rv = S_FALSE ; } *pVal = double(val) ; return rv; } STDMETHODIMP cACHooks::get_LocationZ(double *pVal) { HRESULT rv = S_OK ; if (!m_bAllYourBase) { *pVal = 0 ; return S_FALSE ; } long* cs = GetCs(0x58) ; float val(0) ; if (cs) { val = *(reinterpret_cast< float * >(cs)); } else { rv = S_FALSE ; } *pVal = double(val) ; return rv ; } STDMETHODIMP cACHooks::get_HooksAvail(long *pVal) { *pVal = m_Hooks ; return S_OK ; } STDMETHODIMP cACHooks::DropItem(long lObjectID) { if( !m_bMoveItemEx ) return S_FALSE; __asm { push 0x1 push 0x0 push lObjectID call pfnMoveItemEx add esp, 0x0C } return S_OK; } // Turn to a particular heading, discovered by Madar on 8/25/2002 STDMETHODIMP cACHooks::FaceHeading (float fHeading, VARIANT_BOOL bUnknown, VARIANT_BOOL *pRetval) { if (!m_bFaceHeading) { *pRetval = VARIANT_FALSE; return S_FALSE; } DWORD dwTemp = m_lFaceHeading; DWORD ** pTemp = (DWORD **) m_lMovementThingyParent; DWORD dwMovementThingy = pTemp[0][m_lMovementThingyOffset]; long lResult = 0; DWORD dwSecondArg = (bUnknown == VARIANT_TRUE) ? 1 : 0; __asm { mov ecx,dwMovementThingy push dwSecondArg push fHeading call dwTemp mov lResult, eax } *pRetval = lResult ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } // Set auto-run, discovered by Madar on 9/16/2002 STDMETHODIMP cACHooks::SetAutorun (VARIANT_BOOL bOnOff) { if (!m_bSetAutorun) { return S_FALSE; } DWORD dwTemp = m_lSetAutorun; DWORD ** pTemp = (DWORD **) m_lMovementThingyParent; DWORD dwMovementThingy = pTemp[0][m_lMovementThingyOffset]; long lFirstArg = (bOnOff == VARIANT_TRUE) ? 1 : 0; long lUnknown = 1; __asm { mov ecx,dwMovementThingy push lUnknown push lFirstArg call dwTemp } return S_OK; } STDMETHODIMP cACHooks::ItemIsKnown(long lGUID, VARIANT_BOOL* pRetval) { if (!m_bObjectFromGuid) { *pRetval = VARIANT_FALSE; return S_FALSE; } DWORD dwTemp = m_lObjectFromGuid ; DWORD dwClass = *((DWORD*) m_lObjectFromGuidClass); long lResult = 0; __asm { mov ecx,dwClass push lGUID call dwTemp mov lResult, eax } *pRetval = lResult ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } STDMETHODIMP cACHooks::get_Area3DWidth(long *pVal) { if( !m_bArea3DWidth ) return S_FALSE; *pVal = *m_lpArea3DWidth; return S_OK; } STDMETHODIMP cACHooks::get_Area3DHeight(long *pVal) { if( !m_bArea3DHeight ) return S_FALSE; *pVal = *m_lpArea3DHeight; return S_OK; } STDMETHODIMP cACHooks::SendTell( long lPlayerID, BSTR Message ) { if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToID) ) return S_FALSE; USES_CONVERSION; char *szText = OLE2A( Message ); long retval; qString Msg; pfnInternalStringConstructor( &Msg, 0, szText ); retval = pfnSendMessageToID( &Msg, lPlayerID ); pfnInternalStringDestructor( &Msg ); return S_OK; } STDMETHODIMP cACHooks::SendTellEx( BSTR Name, BSTR Message ) { if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToName) ) return S_FALSE; USES_CONVERSION; char *szName = OLE2A( Name ); char *szText = OLE2A( Message ); long retval; qString qSName; qString qSMsg; pfnInternalStringConstructor( &qSMsg, 0, szText ); pfnInternalStringConstructor( &qSName, 0, szName ); retval = pfnSendMessageToName( &qSMsg, &qSName ); pfnInternalStringDestructor( &qSMsg ); pfnInternalStringDestructor( &qSName ); return S_OK; } STDMETHODIMP cACHooks::LocalChatText(BSTR Text) { if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bLocalChatText) ) return S_FALSE; USES_CONVERSION; char *szText = OLE2A( Text ); qString qSText; pfnInternalStringConstructor( &qSText, 0, szText ); pfnLocalChatText( &qSText ); pfnInternalStringDestructor( &qSText ); return S_OK; } STDMETHODIMP cACHooks::LocalChatEmote(BSTR EmoteText) { if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bLocalChatEmote) ) return S_FALSE; USES_CONVERSION; char *szText = OLE2A( EmoteText ); qString qSText; pfnInternalStringConstructor( &qSText, 0, szText ); pfnLocalChatEmote( &qSText ); pfnInternalStringDestructor( &qSText ); return S_OK; } STDMETHODIMP cACHooks::get_Vital(long Vital, long* pVal) { if( !(m_bGetVital && m_lVitalBase) ) return S_FALSE; if( (Vital < 1) || (Vital > 9) ) return E_INVALIDARG; long lBaseOrBuffed = (Vital > 6) ? 1 : 0; if( lBaseOrBuffed ) { if( Vital == 7 ) // health Vital = 2; else if( Vital == 8 ) // stamina Vital = 4; else if( Vital == 9 ) // mana Vital = 6; } long ( __fastcall *Internal_GetStat )( qPointerList *, long, long, long *, long ) = reinterpret_cast< long ( __fastcall * )( qPointerList *, long, long, long *, long ) >( m_lGetVital ); qPointerList *p = reinterpret_cast< qPointerList * >( m_lVitalBase ); p = p->dd[0]; Internal_GetStat( p, 0, Vital, pVal, lBaseOrBuffed ); return S_OK; } STDMETHODIMP cACHooks::get_Attribute(long Attribute, long* pVal) { if( !(m_bGetAttribute && m_lVitalBase) ) return S_FALSE; if( (Attribute < 1) || (Attribute > 12) ) return E_INVALIDARG; long lBaseOrBuffed = (Attribute > 6) ? 1 : 0; if( lBaseOrBuffed ) Attribute -= 6; qPointerList *p = reinterpret_cast< qPointerList * >( m_lVitalBase ); p = p->dd[0]; long ( __fastcall *Internal_GetAttribute )( qPointerList *, long, long, long *, long ) = reinterpret_cast< long ( __fastcall * )( qPointerList *, long, long, long *, long ) >( m_lGetAttribute ); Internal_GetAttribute( p, 0, Attribute, pVal, lBaseOrBuffed ); return S_OK; } STDMETHODIMP cACHooks::get_Skill(long Skill, long* pVal) { if( !(m_bGetSkill && m_lVitalBase) ) return S_FALSE; // error on out of range, the unused range for added skills, and other skill ids that Turbine skips if((Skill < 1) || (Skill > 89) || ((Skill > 39) && (Skill < 50)) || (Skill == 8 ) || (Skill == 58) || (Skill == 17) || (Skill == 67) || (Skill == 25) || (Skill == 75) || (Skill == 26) || (Skill == 76)) return E_INVALIDARG; long lBaseOrBuffed = (Skill > 50) ? 1 : 0; if( lBaseOrBuffed ) Skill -= 50; qPointerList *p = reinterpret_cast< qPointerList * >( m_lVitalBase ); p = p->dd[0]; long ( __fastcall *Internal_GetSkill )( qPointerList *, long, long, long *, long ) = reinterpret_cast< long ( __fastcall * )( qPointerList *, long, long, long *, long ) >( m_lGetSkill ); Internal_GetSkill( p, 0, Skill, pVal, lBaseOrBuffed ); return S_OK; } STDMETHODIMP cACHooks::get_HooksAvailEx(eAvailableHooksEx HookID, VARIANT_BOOL *pVal) { unsigned int ID; unsigned int Index, Offset; // Default to not being valid *pVal = VARIANT_FALSE; // Convert the enum to an integer so we can do maths on it ID = static_cast< unsigned int >( HookID ); // Ensure the value is within range if( ID > m_HookCount ) { return S_OK; } // Extract the index and bit offset Index = ID >> 5; // 32 -> 5 bits Offset = ID & 0x1F; // 1F -> 5 bits worth of 1s if( m_HooksEx[Index] & (1 << Offset) ) { *pVal = VARIANT_TRUE; } return S_OK; } STDMETHODIMP cACHooks::Logout() { if( m_bLogout ) { long ( __cdecl *Internal_Logout )( long ); Internal_Logout = reinterpret_cast< long ( __cdecl * )( long ) >( m_lLogout ); Internal_Logout(0); return S_OK; } return S_FALSE; } STDMETHODIMP cACHooks::ToolText(BSTR Text, VARIANT_BOOL bError) { /* Moputu - 09012003: Added to allow plugins to display text in the upper left hand corner as either white text w/o sound or as yellow text with the busy/error sound. Either CombatState or ObjectBase can be used as the starting memloc as both always seems to have the same value and the function is called using one or the other in the client.exe. You can only find the function address after the player is logged in. */ if( !m_bAllYourBase ) //the combat state memloc is necessary return S_FALSE; USES_CONVERSION; char *szText = OLE2A( Text ); //pointer to the text being passed DWORD cstate = *((long *)m_lAllYourBase); long lErr; if (bError) lErr = 1; // display text as yellow w/sound else lErr = 0; // display text as white w/o sound __asm { mov ecx, cstate push lErr push szText mov edx, dword ptr [ecx] call dword ptr [edx+114h] add esp, 8 } return S_OK; } STDMETHODIMP cACHooks::ToolTextAppend(BSTR Text, VARIANT_BOOL bError) { if( !m_bAllYourBase ) //the combat state memloc is necessary return S_FALSE; USES_CONVERSION; char *szText = OLE2A( Text ); //pointer to the text being passed DWORD cstate = *((long *)m_lAllYourBase); long lErr; if (bError) lErr = 1; // display text as yellow w/sound else lErr = 0; // display text as white w/o sound __asm { mov ecx, cstate push lErr push szText mov edx, dword ptr [ecx] call dword ptr [edx+118h] } return S_OK; } STDMETHODIMP cACHooks::SecureTrade_Add(long ItemID, VARIANT_BOOL *pVal) { void ( __fastcall *Internal_SecureTrade_Add )( struct qPointerList *, int, long ); struct qPointerList *p; VARIANT_BOOL ItemExists; if (pVal) /* Should probably return an error code. Tough. */ { *pVal = VARIANT_FALSE; } else return E_FAIL; if ( m_bSecureTrade_Add && m_bSecureTrade_Add_Off1 && m_bSecureTrade_Add_Off2 && m_bAllYourBase ) { if( ItemIsKnown(ItemID, &ItemExists) != S_OK ) return E_FAIL; if (ItemExists == VARIANT_FALSE) { return S_FALSE; } p = (qPointerList *)m_lAllYourBase; if (!p) { return S_FALSE; } p = p->dd[0]; if (!p) { return S_FALSE; } p = p->dd[m_lSecureTrade_Add_Off1 >> 2]; if (!p) { return S_FALSE; } p = p->dd[m_lSecureTrade_Add_Off2 >> 2]; if (!p) { return S_FALSE; } Internal_SecureTrade_Add = reinterpret_cast< void ( __fastcall *)( struct qPointerList *, int, long ) >( m_lSecureTrade_Add ); Internal_SecureTrade_Add(p, 0, ItemID); if (pVal) { *pVal = VARIANT_TRUE; } return S_OK; } return S_FALSE; } HRESULT cACHooks::GetSkillInfo(eSkill SkillID, struct qSkill *Skill) { int ( __fastcall *Internal_GetSkillInfo )( void *, int, int, struct qSkill * ); if (!m_bGetSkillInfo) { return E_FAIL; } if (SkillID > 50) { SkillID = (eSkill)(SkillID - 50); } if ((SkillID < 1) || (SkillID > 50)) { return E_INVALIDARG; } Skill->vTable = m_lGetSkillInfo_vT; Internal_GetSkillInfo = reinterpret_cast< int (__fastcall*)(void *, int, int, struct qSkill *) >(m_lGetSkillInfo); if (Internal_GetSkillInfo(*(void **)m_lVitalBase, 0, SkillID, Skill)) { return S_OK; } return E_FAIL; } HRESULT cACHooks::GetAttributeInfo(eAttribute AttributeID, struct qAttribute *Attribute) { int (__fastcall *Internal_GetAttributeInfo)(void *, int, int, struct qAttribute *); if (!m_bGetAttributeInfo) { return E_FAIL; } if (AttributeID > 6) { AttributeID = (eAttribute)(AttributeID - 6); } if ((AttributeID < 1) || (AttributeID > 6)) { return E_INVALIDARG; } Attribute->vTable = m_lGetAttributeInfo_vT; Internal_GetAttributeInfo = reinterpret_cast< int (__fastcall*)(void *, int, int, struct qAttribute *) >(m_lGetAttributeInfo); if (Internal_GetAttributeInfo(*(void **)m_lVitalBase, 0, AttributeID, Attribute)) { return S_OK; } return E_FAIL; } HRESULT cACHooks::GetVitalInfo(eVital VitalID, struct qVital *Vital) { int (__fastcall *Internal_GetVitalInfo)(void *, int, int, struct qVital *); if (!m_bGetVitalInfo) { return E_FAIL; } switch (VitalID) { case eCurrentHealth: case eMaximumHealth: case eBaseHealth: VitalID = eCurrentHealth; break; case eCurrentStamina: case eMaximumStamina: case eBaseStamina: VitalID = eCurrentStamina; break; case eCurrentMana: case eMaximumMana: case eBaseMana: VitalID = eCurrentMana; break; default: return E_INVALIDARG; } Vital->vTable = m_lGetVitalInfo_vT; Internal_GetVitalInfo = reinterpret_cast< int (__fastcall*)(void *, int, int, struct qVital *) >(m_lGetVitalInfo); if (Internal_GetVitalInfo(*(void **)m_lVitalBase, 0, VitalID, Vital)) { return S_OK; } return E_FAIL; } STDMETHODIMP cACHooks::get_SkillTrainLevel( eSkill SkillID, eTrainLevel *pVal ) { struct qSkill Skill; HRESULT hr; hr = GetSkillInfo(SkillID, &Skill); if (FAILED(hr)) { return hr; } *pVal = Skill.Trained; return S_OK; } STDMETHODIMP cACHooks::get_SkillTotalXP( eSkill SkillID, int *pVal ) { struct qSkill Skill; HRESULT hr; hr = GetSkillInfo(SkillID, &Skill); if (FAILED(hr)) { return hr; } *pVal = Skill.TotalXP; return S_OK; } STDMETHODIMP cACHooks::get_SkillFreePoints( eSkill SkillID, int *pVal ) { struct qSkill Skill; HRESULT hr; hr = GetSkillInfo(SkillID, &Skill); if (FAILED(hr)) { return hr; } *pVal = Skill.FreePoints; return S_OK; } STDMETHODIMP cACHooks::get_SkillClicks( eSkill SkillID, int *pVal ) { struct qSkill Skill; HRESULT hr; hr = GetSkillInfo(SkillID, &Skill); if (FAILED(hr)) { return hr; } *pVal = Skill.Clicks; return S_OK; } STDMETHODIMP cACHooks::get_AttributeClicks( eAttribute AttributeID, int *pVal ) { struct qAttribute Attribute; HRESULT hr; hr = GetAttributeInfo(AttributeID, &Attribute); if (FAILED(hr)) { return hr; } *pVal = Attribute.Clicks; return S_OK; } STDMETHODIMP cACHooks::get_AttributeTotalXP( eAttribute AttributeID, int *pVal ) { struct qAttribute Attribute; HRESULT hr; hr = GetAttributeInfo(AttributeID, &Attribute); if (FAILED(hr)) { return hr; } *pVal = Attribute.TotalXP; return S_OK; } STDMETHODIMP cACHooks::get_AttributeStart( eAttribute AttributeID, int *pVal ) { struct qAttribute Attribute; HRESULT hr; hr = GetAttributeInfo(AttributeID, &Attribute); if (FAILED(hr)) { return hr; } *pVal = Attribute.Start; return S_OK; } STDMETHODIMP cACHooks::get_VitalClicks( eVital VitalID, int *pVal ) { struct qVital Vital; HRESULT hr; hr = GetVitalInfo(VitalID, &Vital); if (FAILED(hr)) { return hr; } *pVal = Vital.Clicks; return S_OK; } STDMETHODIMP cACHooks::get_VitalTotalXP( eVital VitalID, int *pVal ) { struct qVital Vital; HRESULT hr; hr = GetVitalInfo(VitalID, &Vital); if (FAILED(hr)) { return hr; } *pVal = Vital.TotalXP; return S_OK; } void cACHooks::SetHookEx( eAvailableHooksEx HookID ) { unsigned int ID; unsigned int Index, Offset; ID = static_cast< unsigned int >( HookID ); Index = ID >> 5; Offset = ID & 0x1F; _ASSERTE( Index < (sizeof(m_HooksEx) / sizeof(m_HooksEx[0])) ); m_HooksEx[Index] |= (1 << Offset); if( ID > m_HookCount ) m_HookCount = ID; return; } STDMETHODIMP cACHooks::SetIdleTime( double dIdleTimeout ) { if( !m_bIdleLoc ) return S_FALSE; DWORD dwOldProtect = 0; DWORD dwNewProtect = PAGE_READWRITE; VirtualProtect( reinterpret_cast< void * >( m_lIdleLoc ), 8 /* sizeof double */, dwNewProtect, &dwOldProtect ); *( reinterpret_cast< double * >( m_lIdleLoc ) ) = dIdleTimeout; VirtualProtect( reinterpret_cast< void * >( m_lIdleLoc ), 8 /* sizeof double */, dwOldProtect, &dwNewProtect ); return S_OK; } void cACHooks::InternalObjectDestroyed (DWORD dwGuid) { Fire_ObjectDestroyed( dwGuid ); } void cACHooks::InternalSelectItem( DWORD dwID ) { Fire_OnSelectItem( dwID ); } void cACHooks::InternalShortcircuit( DWORD dwID ) { if( m_bIdQueueRef ) m_pIdQueue->ShortcircuitID( dwID ); } void OnObjectDestroyed (DWORD dwGuid) { if( cACHooks::s_pACHooks ) cACHooks::s_pACHooks->InternalObjectDestroyed( dwGuid ); } void OnSelectItem( DWORD dwID ) { if( cACHooks::s_pACHooks ) cACHooks::s_pACHooks->InternalSelectItem( dwID ); } void Shortcircuit( DWORD dwID ) { if( cACHooks::s_pACHooks ) cACHooks::s_pACHooks->InternalShortcircuit( dwID ); } void __declspec(naked) SelectItemHook() { _asm { push eax call OnSelectItem add esp,4 jmp g_lSelectItemHijackProc } } void __declspec(naked) ObjectDestroyedHook() { _asm { mov eax,[esp+8] push eax push ecx push eax call OnObjectDestroyed add esp,4 pop ecx pop eax mov [esp+8],eax jmp g_lObjectDestroyedProc } } void __declspec(naked) IdentifyShortcircuit() { __asm { mov eax,[esp+4] push eax push ecx push eax call Shortcircuit add esp, 4 pop ecx pop eax mov [esp+4], eax jmp g_lIdentifyHijackProc } } // Returns the function which previously was being called, after replacing it with the new call. DWORD HookCall (DWORD dwCallAddress, DWORD dwReplacement) { DWORD* pTemp = (DWORD *) (dwCallAddress + 1); HANDLE hProcess = OpenProcess ( PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, GetCurrentProcessId () ); DWORD dwOriginal = 0; if (hProcess) { dwOriginal = (*pTemp) + dwCallAddress + 5; DWORD dwTemp = dwReplacement - (dwCallAddress + 5); if (WriteProcessMemory ( hProcess, pTemp, &dwTemp, sizeof (DWORD), NULL )) { } else { dwOriginal = 0; } CloseHandle (hProcess); } return dwOriginal; } bool cACHooks::InternalChatMessage( char *szText, long lColor ) { return Fire_OnChatBoxMessage( _bstr_t( szText ), lColor ) == VARIANT_TRUE ? true : false; } bool cACHooks::InternalChatText( char *szText ) { return Fire_OnCommandLineText( _bstr_t( szText ) ) == VARIANT_TRUE ? true : false; } bool DispatchChatMessage( char *pText, long pdwColor ) { if( cACHooks::s_pACHooks ) return cACHooks::s_pACHooks->InternalChatMessage( pText, pdwColor ); return false; } bool DispatchChatText( char *pText ) { if( cACHooks::s_pACHooks ) return cACHooks::s_pACHooks->InternalChatText( pText ); return false; } /* Heyus - 23 Mar 2003 - Fixed to point to the new universal function */ void __fastcall OnChatMessage( int _ecx, int _edx, char* pText, long lColor ) { if( !DispatchChatMessage( pText, lColor ) ) InternalRawWriteToChat( pText, lColor, _ecx, _edx ); return; } void __declspec(naked) OnChatText() { __asm { push ebp mov ebp, esp sub esp, 0xC call pfnOldChatText mov [ebp-4], ecx mov [ebp-8], eax push eax call DispatchChatText mov edx, eax mov ecx, [ebp-4] mov eax, [ebp-8] test dl, dl jz dont_eat_chat_text mov byte ptr [eax], 0 dont_eat_chat_text: mov esp, ebp pop ebp ret } } void cACHooks::InternalToolText( char *szText, VARIANT_BOOL bError ) { USES_CONVERSION; Fire_OnToolText( T2BSTR( szText ), bError ); } void OnToolText( char *szText, long lError ) { VARIANT_BOOL bError = lError; if( cACHooks::s_pACHooks ) cACHooks::s_pACHooks->InternalToolText( szText, bError ); } void __declspec(naked) CatchToolText() { __asm { push ecx push edx push edi push eax call OnToolText pop eax pop edi pop edx pop ecx jmp g_lToolTextProc } } void cACHooks::InternalToolTextAppend( char *szText, VARIANT_BOOL bError ) { USES_CONVERSION; Fire_OnToolTextAppend( T2BSTR( szText ), bError ); } void OnToolTextAppend( char *szText, long lError ) { VARIANT_BOOL bError = lError; if( cACHooks::s_pACHooks ) cACHooks::s_pACHooks->InternalToolTextAppend( szText, bError ); } void __declspec(naked) CatchToolTextAppend() { __asm { push ecx push edx push edi push eax call OnToolTextAppend pop eax pop edi pop edx pop ecx jmp g_lToolText2Proc } } STDMETHODIMP cACHooks::RequestID(long lObjectID) { if( !m_bRequestID ) return S_FALSE; if( m_bIdQueueRef ) return m_pIdQueue->AddToQueue( lObjectID ); typedef void(*RequestPtr)( long ); RequestPtr pRequest = reinterpret_cast< RequestPtr >( m_lRequestID ); pRequest( lObjectID ); return S_OK; } STDMETHODIMP cACHooks::IDQueueAdd(long lObjectID) { if( !m_bIdQueueRef ) return RequestID( lObjectID ); return m_pIdQueue->AddToQueue( lObjectID ); } STDMETHODIMP cACHooks::SetIDFilter(IKitchenSink* pIDFilter) { if( !m_bIdQueueRef ) { m_bIdQueueRef = true; m_pIdQueue = pIDFilter; SetHookEx( eIDQueueAdd ); } return S_OK; } STDMETHODIMP cACHooks::UstAddItem(long lObjectID) { VARIANT_BOOL ItemExists; if ( !m_bUstAddItem_Useable ) return S_FALSE; if( ItemIsKnown( lObjectID, &ItemExists ) != S_OK ) return E_FAIL; if( ItemExists == VARIANT_FALSE ) return S_FALSE; //Calculate the THIS pointer //DWORD thisPtr = *((long *)(*((long *)(*((long *)0x77A618) + 0x324)) + 0xE0)); //DWORD tmp; //DWORD func = 0x005556C0; DWORD thisPtr = *((long *)(*((long *)(*((long *)m_lChatMessageAddy) + m_lUstAddItem_Off1)) + m_lUstAddItem_Off2)); DWORD tmp; DWORD func = (DWORD)m_lUstAddItem; __asm { mov tmp, ecx mov ecx, thisPtr push lObjectID call func mov ecx, tmp } return S_OK; } STDMETHODIMP cACHooks::SendMessageByMask( long lMask, BSTR szMessage ) { if( !(m_bInternalStringConstructor && m_bInternalStringDestructor && m_bSendMessageToMask) ) return S_FALSE; USES_CONVERSION; char *szText = OLE2A( szMessage ); long retval; qString Msg; pfnInternalStringConstructor( &Msg, 0, szText ); retval = pfnSendMessageByMask( lMask, &Msg ); pfnInternalStringDestructor( &Msg ); return S_OK; } STDMETHODIMP cACHooks::SetDay( VARIANT_BOOL bDay ) { if( !m_bSlashDay ) return S_FALSE; *reinterpret_cast< long * >( m_lSlashDay ) = bDay == VARIANT_TRUE ? 1 : 0; return S_OK; }