Avictus
02-26-2007, 12:25 PM
This might be a very "newb-ish" question, but I seen an application a few days ago, and I've been going crazy trying to figure out how it works.
The application is a program which, somehow, communicates with the Vanguard: Saga of Heroes game client. It's able to retrieve information such as item details in your inventory, the player's location, etc. The program is not an official app, so they don't have any API access or anything like that. The only thing I have to go on is a quote from one of the developers:
This can become very technical but I’ll avoid that going into any inner details. The software basically interfaces with Vanguard via the dynamic link libraries provided by the game. While these DLL’s do not provide a proper interface one can use it if you reverse engineer the client. All reverse engineering done was for pure interoperability purposes. The game exposes a lot of functionality that can be used for this type of application and many other types of applications. The application then uses these DLL functions to query for game state information. It was really important that the software didn’t have a negative impact on performance. So far none of our users have complained about performance being affected negatively and as far as we can tell there’s no real measurable performance difference.
Currently the client fetches information about all the items you have in your inventory, all quests you have active, quest sources and quest targets, everything you see, loot information, when you click item links and character profile information. This may be extended in the future to include spell, skill information and more.
All this information is the sent to a central server for processing.
From what I have read, you cannot have access to another process' DLL data space, since Windows creates a private data space for each process that loads a DLL. So, how would this program be able to call functions in the DLLs and have them return data from the Vanguard client process?
I was thinking that maybe they used some sort of code injection, but they don't have a DLL distributed with their app, it's just a lone executable. Most code injection techniques I've read about involve loading a DLL into another process.
Also, here is the program's console output from the last time I ran it:
Console::logToFile - Logging to file C:\Documents and Settings\Thomas\Desktop\vgdb.txt
Platform::getProcAddress - Loaded LoadLibraryW
Platform::getProcAddress - Loaded CreateThread
Platform::getProcAddress - Loaded Sleep
Platform::getProcAddress - Loaded GetTickCount
Platform::getProcAddress - Loaded VirtualProtect
Platform::getProcAddress - Loaded VirtualQuery
Platform::getProcAddress - Loaded _aullrem
Platform::getProcAddress - Loaded _allshl
Platform::getProcAddress - Loaded _aullshr
Platform::getProcAddress - Loaded _allmul
Platform::getProcAddress - Loaded _allshr
Platform::getProcAddress - Loaded MessageBoxW
Platform::getProcAddress - Loaded getaddrinfo
Platform::getProcAddress - Loaded freeaddrinfo
Platform::getProcAddress - Loaded socket
Platform::getProcAddress - Loaded closesocket
Platform::getProcAddress - Loaded recv
Platform::getProcAddress - Loaded send
Platform::getProcAddress - Loaded connect
Platform::getProcAddress - Loaded select
Platform::getProcAddress - Loaded WSAGetLastError
Platform::getProcAddress - Loaded ioctlsocket
entryPoint - Curse VG extension, version 0.9.7 launching
Platform::verifyDll - Core.dll hash: 687d9250c356335941e4e714f008ae6b5f9ee548
Platform::verifyDll - VGCommon.dll hash: 0cc37ee53ac26464e1edbc9175fd19ebb6ca340d
Platform::verifyDll - VGClient.dll hash: 45165f4465471f8742db1c9d8cb68a3a3c4e715a
Platform::verifyDll - SGOUnrealAbstractionLayer.dll hash: 4b83c12018e3ac56211a1eb40f0c4b222aba8b99
Platform::verifyDll - SGOFoundation.dll hash: 88541f86db2b05d17718cd2a7c259a2dadf79488
Platform::verifyDll - SGOEngineCore.dll hash: 8b61b39b341b9ebdb4a0c305264d1ec2d4381ae7
init - Seeding random number generator
Engine::init
ASGOUnrealPawn::init
SGOVector::init
AAnimPawn::init
APawn::init
AActor::init
UObject::init
Platform::getProcAddress - Loaded ?GetEntityId@APawn@@QAE_KXZ
Platform::getProcAddress - Loaded ?GetIsInCombat@APawn@@QAEHXZ
VgPlanet::init
ULevel::init
Platform::getProcAddress - Loaded ?GetPlanet@VgPlanet@@SAPAV1@XZ
Platform::getProcAddress - Loaded ?GetChunkByLocation@VgPlanet@@QAEPAVULevel@@AAVFVe ctor@@H@Z
Platform::getProcAddress - Loaded ?GetChunkCoordX@VgPlanet@@SAHK@Z
Platform::getProcAddress - Loaded ?GetChunkCoordY@VgPlanet@@SAHK@Z
Platform::getProcAddress - Loaded ?GetChunkIDFromLevel@VgPlanet@@UAEKPAVULevel@@@Z
Platform::getProcAddress - Loaded ?GetCurrentChunkID@VgPlanet@@QAEKXZ
Platform::getProcAddress - Loaded ?GetChunkTranslation@VgPlanet@@QAEXKKAAVFVector@@@ Z
Platform::getProcAddress - Loaded ?GetCanFly@ASGOUnrealPawn@@QBEEXZ
Platform::getProcAddress - Loaded ?GetCanSwim@ASGOUnrealPawn@@QBEEXZ
Platform::getProcAddress - Loaded ?GetCanWallCrawl@ASGOUnrealPawn@@QBEEXZ
Platform::getProcAddress - Loaded ?GetGameplayClass@ASGOUnrealPawn@@QAEHXZ
Platform::getProcAddress - Loaded ?GetIsDead@ASGOUnrealPawn@@QAE_NXZ
Platform::getProcAddress - Loaded ?GetPointsValue@ASGOUnrealPawn@@QAEHXZ
Platform::getProcAddress - Loaded ?GetRaceId@ASGOUnrealPawn@@QAEHXZ
Platform::getProcAddress - Loaded ?GetLocation@ASGOUnrealPawn@@QAE?AVSGOVector@@XZ
Platform::getProcAddress - Loaded ?s_instance@Engine@SGOEngineCore@@0PAV12@A
Platform::getProcAddress - Loaded ?GetClientPCPawn@Engine@SGOEngineCore@@QAEPAVASGOU nrealPawn@@XZ
Platform::getProcAddress - Loaded ?GetPawnByEntityId@Engine@SGOEngineCore@@QAEPAVASG OUnrealPawn@@_K_N@Z
Platform::getProcAddress - Loaded ?GetChunkCoords@Engine@SGOEngineCore@@QBEXAAH0@Z
Platform::getProcAddress - Loaded ?GetChunkDisplayNameFromXY@Engine@SGOEngineCore@@Q AEPBGHH@Z
VGClientLoot::init
Platform::getProcAddress - Loaded ?g_pLoot@VGClient@@3PAVVGClientLoot@@A
Platform::getProcAddress - Loaded ?IsLooting@VGClientLoot@@QAE_NXZ
Platform::getProcAddress - Loaded ?GetCorpseBeingLootedId@VGClientLoot@@QAE_KXZ
Platform::getProcAddress - Loaded ?GetItemAt@VGClientLoot@@QAEPAVVGClientItem@@H@Z
Platform::getProcAddress - Loaded ?GetItemCount@VGClientLoot@@QAEHXZ
Platform::getProcAddress - Loaded ?GetIndexByItem@VGClientLoot@@AAEHPAVVGClientItem@ @@Z
Platform::getProcAddress - Loaded ?AddItemGV@VGClientLoot@@AAEXPAVVGClientItem@@_N@Z
Platform::getProcAddress - Loaded ?TryLootBegin@VGClientLoot@@QAEX_K_N@Z
Platform::getProcAddress - Loaded ?ClearCorpseItems@VGClientLoot@@AAEXXZ
VGClientInventory::init
Platform::getProcAddress - Loaded ?g_pInventory@VGClient@@3PAVVGClientInventory@@A
Platform::getProcAddress - Loaded ?GetSpaceUsed@VGClientInventory@@QAEMXZ
Platform::getProcAddress - Loaded ?FillItemMods@VGClientInventory@@SAHPAEHPAVVGClien tItem@@@Z
Platform::getProcAddress - Loaded ?GetItemByEquippedSlot@VGClientInventory@@QAEPAVVG ClientItem@@H@Z
VGClientPCStatistics::init
Platform::getProcAddress - Loaded ?g_pStats@VGClient@@3PAVVGClientPCStatistics@@A
Platform::getProcAddress - Loaded ?GetNumStats@VGClientPCStatistics@@QAEHW4VGClientS tatSphereType@@@Z
Platform::getProcAddress - Loaded ?GetStat@VGClientPCStatistics@@QAEPAUVGClientPCSta t@@HW4VGClientStatSphereType@@@Z
Platform::getProcAddress - Loaded ?DisplayAllStats@VGClientPCStatistics@@QAEXXZ
VGClientQuestManager::init
Platform::getProcAddress - Loaded ?g_pQuestManager@VGClient@@3PAVVGClientQuestManage r@@A
VGClientDialogResponses::init
Platform::getProcAddress - Loaded ?g_pDialogResponses@VGClient@@3PAVVGClientDialogRe sponses@@A
Platform::getProcAddress - Loaded ?GetTalkingNPC@VGClientDialogResponses@@QAE_KXZ
Platform::getProcAddress - Loaded ?appSeconds@@YANXZ
Platform::getProcAddress - Loaded ?HandleExamineInfo@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleDoubleClick@InputEventHandler@VGClient@@AAE _NXZ
Platform::getProcAddress - Loaded ?HandleLootEnd@VGClientLoot@@AAEXXZ
Platform::getProcAddress - Loaded ?HandleLootItemInfo@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleLootCoinInfo@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleLootBegin@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleLootText@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleSingleItemInfo@VGClientQuestManager@@AAEXPB EH@Z
Platform::getProcAddress - Loaded ?HandleViewItemLink@VGClientUIEntitySelf@@AAEXPBEH @Z
Platform::getProcAddress - Loaded ?AddAlertEmitterToPawn@VGClientLootAlerts@@AAEH_K@ Z
Platform::getProcAddress - Loaded ?tick@Engine@SGOEngineCore@@QAEXXZ
Platform::getProcAddress - Loaded ?ConnectToWorldServer@Engine@SGOEngineCore@@QAE_NP BG00@Z
The loaded functions, via getProcAddress, are located in the DLLs that are verified near the top of the log.
My question in a nutshell is basically this: How is someone able to load a DLL, call a function such as VGClientInventory::GetSpaceUsed(), and have it actually return the inventory space used in a VGClientInventory class instance in the VGClient.exe from an outside process?
If it helps any, from what I can tell, the DLLs create global pointers to instances of the different classes. For example, g_pInventory is a pointer to a VGClientInventory object. Does this being global in the DLL mean that the same instance is visible to all processes that load the DLL?
I really appreciate any information you guys (and girls?) can give me. Maybe if someone could just give me a push in the right direction, that would be extremely helpful. Again, thank you in advance for any help.
The application is a program which, somehow, communicates with the Vanguard: Saga of Heroes game client. It's able to retrieve information such as item details in your inventory, the player's location, etc. The program is not an official app, so they don't have any API access or anything like that. The only thing I have to go on is a quote from one of the developers:
This can become very technical but I’ll avoid that going into any inner details. The software basically interfaces with Vanguard via the dynamic link libraries provided by the game. While these DLL’s do not provide a proper interface one can use it if you reverse engineer the client. All reverse engineering done was for pure interoperability purposes. The game exposes a lot of functionality that can be used for this type of application and many other types of applications. The application then uses these DLL functions to query for game state information. It was really important that the software didn’t have a negative impact on performance. So far none of our users have complained about performance being affected negatively and as far as we can tell there’s no real measurable performance difference.
Currently the client fetches information about all the items you have in your inventory, all quests you have active, quest sources and quest targets, everything you see, loot information, when you click item links and character profile information. This may be extended in the future to include spell, skill information and more.
All this information is the sent to a central server for processing.
From what I have read, you cannot have access to another process' DLL data space, since Windows creates a private data space for each process that loads a DLL. So, how would this program be able to call functions in the DLLs and have them return data from the Vanguard client process?
I was thinking that maybe they used some sort of code injection, but they don't have a DLL distributed with their app, it's just a lone executable. Most code injection techniques I've read about involve loading a DLL into another process.
Also, here is the program's console output from the last time I ran it:
Console::logToFile - Logging to file C:\Documents and Settings\Thomas\Desktop\vgdb.txt
Platform::getProcAddress - Loaded LoadLibraryW
Platform::getProcAddress - Loaded CreateThread
Platform::getProcAddress - Loaded Sleep
Platform::getProcAddress - Loaded GetTickCount
Platform::getProcAddress - Loaded VirtualProtect
Platform::getProcAddress - Loaded VirtualQuery
Platform::getProcAddress - Loaded _aullrem
Platform::getProcAddress - Loaded _allshl
Platform::getProcAddress - Loaded _aullshr
Platform::getProcAddress - Loaded _allmul
Platform::getProcAddress - Loaded _allshr
Platform::getProcAddress - Loaded MessageBoxW
Platform::getProcAddress - Loaded getaddrinfo
Platform::getProcAddress - Loaded freeaddrinfo
Platform::getProcAddress - Loaded socket
Platform::getProcAddress - Loaded closesocket
Platform::getProcAddress - Loaded recv
Platform::getProcAddress - Loaded send
Platform::getProcAddress - Loaded connect
Platform::getProcAddress - Loaded select
Platform::getProcAddress - Loaded WSAGetLastError
Platform::getProcAddress - Loaded ioctlsocket
entryPoint - Curse VG extension, version 0.9.7 launching
Platform::verifyDll - Core.dll hash: 687d9250c356335941e4e714f008ae6b5f9ee548
Platform::verifyDll - VGCommon.dll hash: 0cc37ee53ac26464e1edbc9175fd19ebb6ca340d
Platform::verifyDll - VGClient.dll hash: 45165f4465471f8742db1c9d8cb68a3a3c4e715a
Platform::verifyDll - SGOUnrealAbstractionLayer.dll hash: 4b83c12018e3ac56211a1eb40f0c4b222aba8b99
Platform::verifyDll - SGOFoundation.dll hash: 88541f86db2b05d17718cd2a7c259a2dadf79488
Platform::verifyDll - SGOEngineCore.dll hash: 8b61b39b341b9ebdb4a0c305264d1ec2d4381ae7
init - Seeding random number generator
Engine::init
ASGOUnrealPawn::init
SGOVector::init
AAnimPawn::init
APawn::init
AActor::init
UObject::init
Platform::getProcAddress - Loaded ?GetEntityId@APawn@@QAE_KXZ
Platform::getProcAddress - Loaded ?GetIsInCombat@APawn@@QAEHXZ
VgPlanet::init
ULevel::init
Platform::getProcAddress - Loaded ?GetPlanet@VgPlanet@@SAPAV1@XZ
Platform::getProcAddress - Loaded ?GetChunkByLocation@VgPlanet@@QAEPAVULevel@@AAVFVe ctor@@H@Z
Platform::getProcAddress - Loaded ?GetChunkCoordX@VgPlanet@@SAHK@Z
Platform::getProcAddress - Loaded ?GetChunkCoordY@VgPlanet@@SAHK@Z
Platform::getProcAddress - Loaded ?GetChunkIDFromLevel@VgPlanet@@UAEKPAVULevel@@@Z
Platform::getProcAddress - Loaded ?GetCurrentChunkID@VgPlanet@@QAEKXZ
Platform::getProcAddress - Loaded ?GetChunkTranslation@VgPlanet@@QAEXKKAAVFVector@@@ Z
Platform::getProcAddress - Loaded ?GetCanFly@ASGOUnrealPawn@@QBEEXZ
Platform::getProcAddress - Loaded ?GetCanSwim@ASGOUnrealPawn@@QBEEXZ
Platform::getProcAddress - Loaded ?GetCanWallCrawl@ASGOUnrealPawn@@QBEEXZ
Platform::getProcAddress - Loaded ?GetGameplayClass@ASGOUnrealPawn@@QAEHXZ
Platform::getProcAddress - Loaded ?GetIsDead@ASGOUnrealPawn@@QAE_NXZ
Platform::getProcAddress - Loaded ?GetPointsValue@ASGOUnrealPawn@@QAEHXZ
Platform::getProcAddress - Loaded ?GetRaceId@ASGOUnrealPawn@@QAEHXZ
Platform::getProcAddress - Loaded ?GetLocation@ASGOUnrealPawn@@QAE?AVSGOVector@@XZ
Platform::getProcAddress - Loaded ?s_instance@Engine@SGOEngineCore@@0PAV12@A
Platform::getProcAddress - Loaded ?GetClientPCPawn@Engine@SGOEngineCore@@QAEPAVASGOU nrealPawn@@XZ
Platform::getProcAddress - Loaded ?GetPawnByEntityId@Engine@SGOEngineCore@@QAEPAVASG OUnrealPawn@@_K_N@Z
Platform::getProcAddress - Loaded ?GetChunkCoords@Engine@SGOEngineCore@@QBEXAAH0@Z
Platform::getProcAddress - Loaded ?GetChunkDisplayNameFromXY@Engine@SGOEngineCore@@Q AEPBGHH@Z
VGClientLoot::init
Platform::getProcAddress - Loaded ?g_pLoot@VGClient@@3PAVVGClientLoot@@A
Platform::getProcAddress - Loaded ?IsLooting@VGClientLoot@@QAE_NXZ
Platform::getProcAddress - Loaded ?GetCorpseBeingLootedId@VGClientLoot@@QAE_KXZ
Platform::getProcAddress - Loaded ?GetItemAt@VGClientLoot@@QAEPAVVGClientItem@@H@Z
Platform::getProcAddress - Loaded ?GetItemCount@VGClientLoot@@QAEHXZ
Platform::getProcAddress - Loaded ?GetIndexByItem@VGClientLoot@@AAEHPAVVGClientItem@ @@Z
Platform::getProcAddress - Loaded ?AddItemGV@VGClientLoot@@AAEXPAVVGClientItem@@_N@Z
Platform::getProcAddress - Loaded ?TryLootBegin@VGClientLoot@@QAEX_K_N@Z
Platform::getProcAddress - Loaded ?ClearCorpseItems@VGClientLoot@@AAEXXZ
VGClientInventory::init
Platform::getProcAddress - Loaded ?g_pInventory@VGClient@@3PAVVGClientInventory@@A
Platform::getProcAddress - Loaded ?GetSpaceUsed@VGClientInventory@@QAEMXZ
Platform::getProcAddress - Loaded ?FillItemMods@VGClientInventory@@SAHPAEHPAVVGClien tItem@@@Z
Platform::getProcAddress - Loaded ?GetItemByEquippedSlot@VGClientInventory@@QAEPAVVG ClientItem@@H@Z
VGClientPCStatistics::init
Platform::getProcAddress - Loaded ?g_pStats@VGClient@@3PAVVGClientPCStatistics@@A
Platform::getProcAddress - Loaded ?GetNumStats@VGClientPCStatistics@@QAEHW4VGClientS tatSphereType@@@Z
Platform::getProcAddress - Loaded ?GetStat@VGClientPCStatistics@@QAEPAUVGClientPCSta t@@HW4VGClientStatSphereType@@@Z
Platform::getProcAddress - Loaded ?DisplayAllStats@VGClientPCStatistics@@QAEXXZ
VGClientQuestManager::init
Platform::getProcAddress - Loaded ?g_pQuestManager@VGClient@@3PAVVGClientQuestManage r@@A
VGClientDialogResponses::init
Platform::getProcAddress - Loaded ?g_pDialogResponses@VGClient@@3PAVVGClientDialogRe sponses@@A
Platform::getProcAddress - Loaded ?GetTalkingNPC@VGClientDialogResponses@@QAE_KXZ
Platform::getProcAddress - Loaded ?appSeconds@@YANXZ
Platform::getProcAddress - Loaded ?HandleExamineInfo@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleDoubleClick@InputEventHandler@VGClient@@AAE _NXZ
Platform::getProcAddress - Loaded ?HandleLootEnd@VGClientLoot@@AAEXXZ
Platform::getProcAddress - Loaded ?HandleLootItemInfo@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleLootCoinInfo@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleLootBegin@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleLootText@VGClientLoot@@AAEXPBEH@Z
Platform::getProcAddress - Loaded ?HandleSingleItemInfo@VGClientQuestManager@@AAEXPB EH@Z
Platform::getProcAddress - Loaded ?HandleViewItemLink@VGClientUIEntitySelf@@AAEXPBEH @Z
Platform::getProcAddress - Loaded ?AddAlertEmitterToPawn@VGClientLootAlerts@@AAEH_K@ Z
Platform::getProcAddress - Loaded ?tick@Engine@SGOEngineCore@@QAEXXZ
Platform::getProcAddress - Loaded ?ConnectToWorldServer@Engine@SGOEngineCore@@QAE_NP BG00@Z
The loaded functions, via getProcAddress, are located in the DLLs that are verified near the top of the log.
My question in a nutshell is basically this: How is someone able to load a DLL, call a function such as VGClientInventory::GetSpaceUsed(), and have it actually return the inventory space used in a VGClientInventory class instance in the VGClient.exe from an outside process?
If it helps any, from what I can tell, the DLLs create global pointers to instances of the different classes. For example, g_pInventory is a pointer to a VGClientInventory object. Does this being global in the DLL mean that the same instance is visible to all processes that load the DLL?
I really appreciate any information you guys (and girls?) can give me. Maybe if someone could just give me a push in the right direction, that would be extremely helpful. Again, thank you in advance for any help.