 |
Cheat Engine The Official Site of Cheat Engine
|
View previous topic :: View next topic |
Author |
Message |
jgoemat Master Cheater
Reputation: 23
Joined: 25 Sep 2011 Posts: 264
|
Posted: Tue Jan 26, 2021 11:21 pm Post subject: DnSpy integration would be amazing... |
|
|
I've just started using ILSpy and dnSpy and they're pretty cool. Editing C# methods with dnSpy and saving an updated 'Assembly-CSharp.dll' works so well, but then any update or reinstall means the changes have to be done all over again. I thought about something that could call the MonoDataCollector and have it load an assembly with updated or new types, or JIT some IL code for a new method. Is there any way to do that? Are there other ways? Trying different things I created a separate solution, referenced the game classes, and tried to create a new method, but the code referenced private and protected fields and a nested enum, so I had to copy the whole class. If I could load that assembly and in ASM, hook the game method, and just jump to the code for my method if the cheat is enabled, would that work? It would be nice to have a method in MonoDataCollector to load a managed assembly. It wouldn't be too hard then to do that.
What about compiling IL in MonoDataCollector? I'm fairly new to this, but check out this method (handling dropping one item from a stack):
Code: |
.method family hidebysig virtual
instance void HandleDropOne () cil managed
{
// Method begins at RVA 0x21d530
// Code size 157 (0x9d)
.maxstack 3
.locals init (
[0] class ItemStack,
[1] int32,
[2] class ItemStack
)
// ItemStack currentStack = base.xui.dragAndDrop.CurrentStack;
IL_0000: ldarg.0
IL_0001: call instance class XUi XUiController::get_xui()
IL_0006: callvirt instance class XUiC_DragAndDropWindow XUi::get_dragAndDrop()
IL_000b: callvirt instance class ItemStack XUiC_DragAndDropWindow::get_CurrentStack()
IL_0010: stloc.0
// if (currentStack.IsEmpty())
IL_0011: ldloc.0
IL_0012: callvirt instance bool ItemStack::IsEmpty()
IL_0017: brtrue IL_009c
// int num = 1;
IL_001c: ldc.i4.1
IL_001d: stloc.1
...
|
My thoughts were something like this...
1. Use dnSpy to create a new method on the class that is a 'cheat' version of the existing, or just a method I can call in ASM to do some cheat
2. Grab the IL for my new method
3. Put the IL into my cheat table and call the MonoDataCollector to JIT the IL into the game
I don't know if that's even possible. The actual bytes from the IL have the method signatures as values created at compile time I think, like IL_0001 is 5 bytes, the opcode and an identifier for the method that could change between versions, so just grabbing bytes wouldn't work.
I wrote some code for work a long time ago to parse binary data with xml definitions for the data types. It generated IL code based on the definitions for the data types and was about 10x as fast as doing it manually. It used It looks like mono has the same functionality with DynamicMethod and System.Reflection to generate code at runtime (though those would have to be loaded into the game as well). It seems like that can be made to access private variables on classes...
I don't have enough time to really dig into it and don't want to waste time going down the wrong path. Maybe there's an easier way? dnSpy is open source, it shouldn't be too difficult to create 'patch' files that could be applied to the game assembly using the command line so it would be easy to update newer versions with new or modified methods. I wouldn't want to use much of the game's code though. It seems like the cleanest way would be to just create new methods and do hooking using cheat engine to call the new version based on activation of a cheat.
Sorry for the rambling, I just didn't want to put too much work into something if there was already a way to do some of this stuff. Just being able to write my own assembly and load it using MonoDataCollector would be cool.
|
|
Back to top |
|
 |
Dark Byte Site Admin
Reputation: 470
Joined: 09 May 2003 Posts: 25796 Location: The netherlands
|
Posted: Wed Jan 27, 2021 11:46 am Post subject: |
|
|
perhaps someday
it depends on how mono deals with an unexpected pointerswap for native code back to IL
tip: Look into mono_loadAssemblyFromFile and https://github.com/pardeike/Harmony
edit:
I guess I could always use a c# dll that I control with CE, make it build a method and then compile the original method, and replace it with a jmp to the new method delegate
edit2: You're going to like what i'm adding to CE
e.g kindergarten 2:
Code: |
LaunchMonoDataCollector()
if dotnetdetours==nil then
dotnetdetours={}
else
local di=dotnetdetours['Interactable.Interact']
if di and di.processid==getOpenedProcessID() then
--already detoured. Undo first
local r,err=autoAssemble(di.disablescript, di.disableinfo)
if not r then
error(err)
else
dotnetdetours['Interactable.Interact']=nil
end
end
end
local detourinfo={}
local csharpscript=[[
using System.Runtime.CompilerServices; //for NoInlining
//feel free to add more
public class patchedInteractable : Interactable
{
public void newInteract()
{
//you have access to public fields. Use reflection if you wish to access private fields
oldInteract();
if (this.player)
{
this.player.Explode();
}
return;
}
[MethodImpl(MethodImplOptions.NoInlining)]
public void oldInteract()
{
//don't bother putting code in here. It will get replaced (just some stuff to make sure there's space)
return ;
}
}
]]
local references, sysfile=dotnetpatch_getAllReferences() --you're free to build your own list
local csfile,msg=compileCS(csharpscript, references, sysfile)
if csfile==nil then
if msg==nil then msg=' (?Unknown error?)' end
messageDialog('Compilation error:'..msg, mtError) --show compile error in a dialog instead of a lua error only
error(msg)
end
--still here, c# dll created, now inject and hook
local result, disableinfo, disablescript=InjectDotNetDetour(csfile, "Interactable::Interact","patchedInteractable::newInteract","patchedInteractable::oldInteract")
if result then
detourinfo.disableinfo=di
detourinfo.disablescript=disablescript
detourinfo.processid=getOpenedProcessID()
dotnetdetours['Interactable.Interact']=detourinfo
else
if disableinfo==nil then disableinfo='no reason' end
error('InjectDotNetDetour failed : '..disableinfo) --prevents checking
end
|
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
Back to top |
|
 |
MMM-304 Expert Cheater
Reputation: 0
Joined: 17 Aug 2020 Posts: 170 Location: Milkey Way
|
Posted: Mon Oct 04, 2021 11:38 am Post subject: |
|
|
Q1: how do i eject the code and free memory in disable section when using InjectDotNetDetour to inject the CSCompiled code?
Q2: sorry i do not understand? how do I get access to private fields of parent class from inherited class?
|
|
Back to top |
|
 |
Dark Byte Site Admin
Reputation: 470
Joined: 09 May 2003 Posts: 25796 Location: The netherlands
|
Posted: Mon Oct 04, 2021 1:17 pm Post subject: |
|
|
1: replace it with a version that does nothing. It just calls the old function and nothing else
2: use the reflection library.
'this' is the class to inspect
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
Back to top |
|
 |
MMM-304 Expert Cheater
Reputation: 0
Joined: 17 Aug 2020 Posts: 170 Location: Milkey Way
|
Posted: Tue Oct 05, 2021 1:34 am Post subject: |
|
|
1. what I meant by ejecting is removing the images too when the script is disabled. I am using autoAssemble in disable section. It does restore the code but it does not dealloc the compiled CS code (free memory) as expected, neither does it remove the assembly image from the list:
every time I (re)enable the same script, it creates a new image but does not destroy the old one.
2. I tried it:
but it gives an error:
Also it using netstandard as sys in CompileCS does not work so i left it nil. dotnetpatch_getAllReferences could not find mscorlib even though it is in game's directory.
Another question how do I create my own reference that can have both netstandard and mscorlib?
|
|
Back to top |
|
 |
Dark Byte Site Admin
Reputation: 470
Joined: 09 May 2003 Posts: 25796 Location: The netherlands
|
Posted: Tue Oct 05, 2021 2:24 am Post subject: |
|
|
1: Check https://docs.microsoft.com/en-us/dotnet/standard/assembly/load-unload
Basically, it's not that easy as you'll have to unload the whole appdomain, and with multiple threads that can be quite a hassle
Best is to compile once, or use unique/randomized patch classnames
or I guess I could adjust InjectDotNetDetour to get the patched module just from the assembly it just injected instead of relying on the default symbol handler
2:
with reflection I mean something like:
Code: |
using System.Reflection;
...
Type thistype = this.GetType();
FieldInfo f = thistype.GetField("stats", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (f != null)
{
NeedsStat[] stats= (NeedsStat[])f.GetValue(this);
//and now you can access stats. If you need to access private fields of stats, do something similar
}
|
dotnetpatch_getAllReferences returns 2 results. the references list and the main sys file
i'm not sure a cs-library can have both netstandard and mscordlib. I think it has to be either one of them
but you can of course add custom references to the references list
_________________
Do not ask me about online cheats. I don't know any and wont help finding them.
Like my help? Join me on Patreon so i can keep helping |
|
Back to top |
|
 |
MMM-304 Expert Cheater
Reputation: 0
Joined: 17 Aug 2020 Posts: 170 Location: Milkey Way
|
Posted: Wed Oct 06, 2021 12:02 am Post subject: |
|
|
ah thanks, I will try it next time I open the game.
|
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum You cannot attach files in this forum You can download files in this forum
|
|