I'm not a complete retard here, but how in the world would anyone find a method to consistently find memory values that are used in game?
There are a few tools that I would like to make but I can't find a way to find any of the memory values.
I'm not a complete retard here, but how in the world would anyone find a method to consistently find memory values that are used in game?
There are a few tools that I would like to make but I can't find a way to find any of the memory values.
From my understanding, Unity3D makes this very difficult. I haven't looked into it much but my findings where the offsets are never static and quite hard to keep track of.
I'm sort of new with cheat engine, but i've been able to find everything i've needed in the past. With this game though, I can't find even the health values of either champion..I just end up filtering down to 0 results...
Any tips?
And here I sit with my own cheat programming side business and still can't do anything with Hearthstone... Dammit Blizzard
Posted this a little while back: http://www.ownedcore.com/forums/mmo/...ml#post2893422 (Idea for a hearthstone memory reader program)
You can find the names of the cards in your hand, on the board and in the graveyard in memory. Also wasn't able to find health etc.
Had a quick look at Hearstone Yesterday, so i decided to share which entrypoints i saw:
1. Unity use .NET Bytecode as Language for most of the Gamelogic. Its located in the Assembly-Csharp.dll and can be decompiled to yield pretty accurate highlevel Code.
Intressting starting points would be
Or the FunctionCode:static SslSocket() { SslSocket.BattleNetCertificateThumbprint = "673D9D1072B625CAD95CB47BF0F0F512233E39FD"; SslSocket.s_log = new LogThreadHelper("SslSocket"); SslSocket.s_rootCertificate = new X509Certificate2(Encoding.get_ASCII().GetBytes("-----BEGIN CERTIFICATE-----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-----END CERTIFICATE-----")); }
Both located in the SSLSocket Class.Code:private static bool OnValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
One approach would be replacing some of this stuff which woud enable us to perfom a Mitm Attack, giving us the ability to alter the Packetflow through a Proxy.
(Mono.Cecil)
Another approach would be getting Unity to load our own Code.
Sorry i know its dirty, but it was just a proof of concept, this show how we use Mono.Cecil to snsert some instructions into the Assembly-Csharp.dllCode:public class hook { static string assemblypath = @"D:\hstest\hstest\ass\Assembly-CSharp.dll"; static string injectpath = @"D:\hstest\hstest\ass\loaderdll.dll"; static string assemblypathfinal = @"D:\hstest\hstest\ass\finalAssembly-CSharp.dll"; static string saveas = @"D:\hstest\ass\mod-csharp.dll"; public static void injection() { var typeName = "Hub"; var methodName = "Start"; var assembly = AssemblyDefinition.ReadAssembly(assemblypath); var injassembly = AssemblyDefinition.ReadAssembly(injectpath); var typedefinj = injassembly.MainModule.Types.Single(t=> t.Name == "loader"); var injmethDefinition = typedefinj.Methods.Single(t => t.Name == "init"); var typeDefinition = assembly.MainModule.Types.Single(t => t.Name == typeName); var methDefinition = typeDefinition.Methods.Single(t => t.Name == methodName); var setMethodWriter = methDefinition.Body.GetILProcessor(); var firstExistingInstruction = setMethodWriter.Body.Instructions[0]; setMethodWriter.InsertBefore(firstExistingInstruction, setMethodWriter.Create(OpCodes.Call, assembly.MainModule.Import(injmethDefinition.Resolve()))); assembly.Write(@"D:\test.dll"); }
We load our loaderdll.dll we load the Assembly-Csharp.dll, then we fetch proper Functionreferences for Hub.Start (Just had a quick look, its called in the main menu after starting the game), fetch a reference from loaderdll.dll in the class loader with the function name init. In the next step we insert a Call to our dll Function and write all to D:\test.dll.
If you replace the vanilla Assembly-Csharp.dll with our newly created, we can see in the Outputlog:
This is unity properly loading our DLL and calling the Initfunction. This should be a nice starting Point i guess.Code:Platform assembly: D:\heartstone\client\Hearthstone\Hearthstone_Data\Managed\loaderdll.dll (this message is harmless)
Edit:
Found the time to play around a bit more
As someone asked how to fetch values
Dont mind the dirty code , but it should make the basic idea behind it obvious.Code:GameState mg = GameState.Get(); if (mg != null) { Console.WriteLine("Its Turn: " + mg.GetTurn().ToString()); Player test = mg.GetLocalPlayer(); Console.WriteLine("My Name is :" + test.GetName() + Environment.NewLine); Console.WriteLine("I have " + test.GetNumAvailableResources().ToString() + " Mana" + Environment.NewLine); Console.WriteLine("my minions num: " + test.GetNumFriendlyMinionsInPlay() + "his minion num: " + test.GetNumEnemyMinionsInPlay() + Environment.NewLine); Console.WriteLine("is this my turn ? " + mg.IsLocalPlayerTurn().ToString() + Environment.NewLine); if (mg.IsLocalPlayerTurn()) { List<Card> mycards = test.GetHandZone().GetCards(); foreach (Card x in mycards) { Console.WriteLine(Environment.NewLine + x.ToString() + Environment.NewLine); Console.WriteLine(x.GetEntity().GetCost() + Environment.NewLine); Console.WriteLine(x.GetEntity().GetCardTextInHand() + Environment.NewLine); } } }
Last edited by Maddin1803; 12-14-2013 at 09:38 PM.
I will take a look into Hearthstone, also.
Maddin1803, thanks for sharing some hope.
Didnt had much time lately as iam a bit crowded in work, so i will just share a bunch of stuff, hopefully someone with more time can get something out of it
The main problem atm is, understanding their code Its not hard and reeealy good seperated but its a good amount :P
Iam able to Play creaturecards, end turns, Accept the End of the Game and so on. It was easier then i thought at first.
My Basic Setup is:
Patch Assembly.dll to load my loader.dll
The loader.dll then loads every dll he founds in a specific directory, giving me the ability to seperate code better.
I didnt wanted to mess around with the original functions, but as we need to hijack the input stuff, i decided to not alter the original, but rewrite a bunch of functions that were needed.
This code is able to play a Creaturecard, i just dont react to spellcards as i didnt worked on the targeting yet.Code:using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace hsplugintest { public class myhelperclass { public ZoneHand m_myHandZone; public ZonePlay m_myPlayZone; public ZoneWeapon m_myWeaponZone; public bool playcard(Card cardtoplay) { try { populatezones(); InputManager im = InputManager.Get(); Entity entity = cardtoplay.GetEntity(); GameState.Get().GetGameEntity().NotifyOfCardDropped(entity); bool targeting = false; Zone destinationZone = null; if (entity != null && entity.GetZone() == TAG_ZONE.HAND) { bool isMinion = entity.IsMinion(); bool isWeapon = entity.IsWeapon(); if (isMinion || isWeapon) { if (isWeapon) { destinationZone = (Zone)m_myWeaponZone; } else if (isMinion) { destinationZone = (Zone)m_myPlayZone; } else { return false; //error } GameState gameState = GameState.Get(); int num = 0; if (isMinion) { num = getzoneslot() + 1; //hum needs testing related to function this.PlayZoneSlotMousedOver } else if (isWeapon) { num = 1; } gameState.SetSelectedOptionPosition(num); if (im.DoNetworkResponse(entity)) { int zonePosition = entity.GetZonePosition(); ZoneMgr.Get().AddLocalZoneChange(cardtoplay, destinationZone, num); if (isMinion && gameState.EntityHasTargets(entity)) { targeting = true; //battlecry stuff todo //should be only ui related } } else { gameState.SetSelectedOptionPosition(Network.NoPosition); } } else if (entity.IsSpell()) { //todo return false; } m_myHandZone.UpdateLayout(-1, true); m_myPlayZone.SortWithSpotForHeldCard(-1); } if (targeting) { if ((bool)((UnityEngine.Object)EnemyActionHandler.Get())) EnemyActionHandler.Get().NotifyOpponentOfTargetModeBegin(cardtoplay); } else if (GameState.Get().GetResponseMode() != GameState.ResponseMode.SUB_OPTION) { EnemyActionHandler.Get().NotifyOpponentOfCardDropped(); } return true; } catch (Exception ex) { Console.WriteLine(ex.StackTrace.ToString()); return false; } } public void populatezones() { try { List<Zone> allzones = (ZoneMgr.Get().GetZones()); foreach (Zone z in allzones) { Zone current = z; if (current.m_Side == Player.Side.FRIENDLY) { if (current is ZoneHand) { m_myHandZone = (ZoneHand)current; } else if (current is ZonePlay) { m_myPlayZone = (ZonePlay)current; } else if (current is ZoneWeapon) { m_myWeaponZone = (ZoneWeapon)current; } } } } catch { } } private void ForceManaUpdate(Entity entity) { Player localPlayer = GameState.Get().GetLocalPlayer(); int num1 = entity.GetRealTimeCost() - localPlayer.GetRealTimeTempMana(); if (localPlayer.GetRealTimeTempMana() > 0) { int num2 = Clamp(entity.GetRealTimeCost(), 0, localPlayer.GetRealTimeTempMana()); localPlayer.NotifyOfUsedTempMana(num2); ManaCrystalMgr.Get().DestroyTempManaCrystals(num2); } if (num1 > 0) { localPlayer.NotifyOfSpentMana(num1); ManaCrystalMgr.Get().UpdateSpentMana(num1); } localPlayer.UpdateManaCounter(); } public int getzoneslot() //next free slot on our zone { int count = this.m_myPlayZone.GetCards().Count; return count; } public static int Clamp(int value, int min, int max) //needed as the standart math framework of c# dont now clamp :O { return (value < min) ? min : (value > max) ? max : value; } } }
How to end a Round
Example how to play a turn:Code:InputManager im = InputManager.Get(); im.DoEndTurnButton(); Thread.Sleep(5000);
Looking for an EndgameScreenCode:if (mg.IsLocalPlayerTurn()) //Check if this is our turn { List<Card> mycards = test.GetHandZone().GetCards(); //Get a List of all Cards in our hand foreach (Card x in mycards) //for each card { Console.WriteLine(Environment.NewLine + x.ToString() + Environment.NewLine); //Cardname Console.WriteLine(x.GetEntity().GetCost() + Environment.NewLine); //Mana Cost Console.WriteLine(x.GetEntity().GetCardTextInHand() + Environment.NewLine); //CardText if (x.GetEntity().GetCost() <= test.GetNumAvailableResources()) //If the card costs less mana then we have { if (x.GetEntity().GetCardType() == TAG_CARDTYPE.MINION) //& the card is a creature { mhc.playcard(x); //helperclass, play the card Thread.Sleep(1000); //little wait so we dont try to play the same card over and over again, unsure if needed } } } InputManager im = InputManager.Get(); //get an instance of the Inputmanager im.DoEndTurnButton(); //Simluate a Press to the End Turn Button Thread.Sleep(5000); }
Code:EndGameScreen es = EndGameScreen.Get(); if (es != null) { Thread.Sleep(10000); //needed as some Animationspeed stuff breaks otherwise, didnt looked deeper, its a working solution for the moment SceneMgr.Get().SetNextMode(SceneMgr.Mode.PRACTICE); //switch to the Play Pratice Game Menu }
Starting a game is a bit more complicated, we need to fetch the DeckID of tha AI through the collectionmanager, our deckid through the collectionmanager and then use some more Functions in the PraticePickerTrayDisplay if i remember right to iussue a gamestart, but i dont remember exactly.
Be aware some of this code is unstable, can throw errors and so on, its mainly for getting a feeling how all this little things work together, but its at least allready able to play cards cicumventing the Code that was added to stop gaining experience from automated loosing.
Absolutely brilliant!
Welp, I'm still a noob at this kind of shit I guess.
What version of .net and Cecil are you using for this? Im trying to replicate this myself and dealing with issues with it writing out the modified assembly. Did you have to load up any other assemblies or have them in the GAC?
You need to inculde references in your project for the unity.dlls and the assembly-csharp
Thanks! ive actually got my library loading now, but when simply trying to write to a file, im getting errors
Platform assembly: C:\Program Files (x86)\Hearthstone\Hearthstone_Data\Managed\HSLoader.dll (this message is harmless)
InvalidProgramException: Invalid IL code in Hub:Start (): IL_0000: call 0x0a0006f6
is what im seeing in the log file and
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace HSLoader
{
public class loader
{
public void init()
{
File.WriteAllText(@"C:\tesths.txt", "test");
}
}
}
is all of the code in my loader, any idea whats up?
Inspect the IL Code, check if its proper, additional look if the monoframework supports your commands
But aside of that, create a new thread, otherwise the Function never returns and heartstone can never execute his own code -> freezed process.
Edit:
Oh .. try it with a static void
Last edited by Maddin1803; 01-03-2014 at 02:02 PM.