Ludeon Forums

Ludeon Forums

  • May 24, 2022, 06:36:37 PM
  • Welcome, Guest
Please login or register.

Login with username, password and session length
Advanced search  

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Topics - RawCode

Pages: [1] 2 3 4
1
Help / Making custom overlay display step by step
« on: August 09, 2021, 08:47:36 AM »
1) Open the game;
2) Hover over existing overlay display, like "beauty";
Code: [Select]
Toggle beauty display3) Search this string inside data folder
Code: [Select]
   
<KeyBindingDef ParentName="GameKeyBinding">
    <defName>ToggleBeautyDisplay</defName>
    <label>toggle beauty display</label>
    <defaultKeyCodeA>T</defaultKeyCodeA>
  </KeyBindingDef>
If you are using non English, you will find this string with extra step, all translations are part of data.

4) Not very useful, but this is exactly how modding is done, first you must understand how exactly game works in order to change anything.
Code: [Select]
public void DoPlaySettingsGlobalControls(WidgetRow row, bool worldView)

5) Feature is "hardcoded" and integral part of UI itself, it cannot be changed without code injection.

6) Pressing button flips "showBeauty" nothing more, actual work done elsewhere:
Code: [Select]
BeautyDrawer
Code: [Select]
EnvironmentStatsDrawer
7) Method
Code: [Select]
DrawBeautyAroundMouseis rather suspicious, dunno what can that method actually do, there are no comments in disassembly after all, probably we will never know!

8) Tracking how this method is called lead us to this cozy list:
Code: [Select]
unity GUI loop
OnGUI
UIRootOnGUI
MapInterfaceOnGUI_BeforeMainTabs
BeautyDrawerOnGUI

7) There are other mods with overlay and GUI features, i checked few and they use postfix to inject into GUI rendering, this is okay, but not needed, you can inject into Unity GUI loop directly.
GUI loop called ~60 times per second, you should never perform anything heavy inside GUI loop, you can and will slowdown entire game.

8) How exactly it works and why it works - google is your very best friend, this is part of Unity development and not related to modding or Rimworld, this is how Unity games are made.

9) Copy classes from vanilla, make some changes, tech demo ready:

Code injection part A:
Code: [Select]
public class XToken : MonoBehaviour
{
public void OnGUI()
{
CoverDrawer.DrawCoverAroundMouse();
}
}

Part B:
(can be called from any place you like, should be called only once obviously)
Code: [Select]
GameObject go = new GameObject("TOKEN");
go.AddComponent<XToken>();
UnityEngine.Object.DontDestroyOnLoad(go);
go.SetActive(true);

Payload:
Code: [Select]
public static class CoverDrawer
{
public static bool ShouldShow()
{
//if you think that this code is super bad, check assembly image of it first
while (true)
{
if (Find.CurrentMap == null)
break;
if (UI.MouseCell() == IntVec3.Invalid)
break;
if (Mouse.IsInputBlockedNow)
break;
return UI.MouseCell().InBounds(Find.CurrentMap);
}

return false;
}
public static void DrawCoverAroundMouse()
{
if (!ShouldShow())
return;


IntVec3 rt = UI.MouseCell();
if (!rt.IsValid)
return;

int z = 0;
for (int i = 0; i < 25; i++)
{
IntVec3 intVec = rt + GenRadial.RadialPattern[i];
if (intVec.InBounds(Find.CurrentMap))
{
List<Thing> list = Find.CurrentMap.thingGrid.ThingsListAt(intVec);
foreach (Thing t in list)
{
//this is not cover, thx i know
z += t.def.CostStuffCount;
}
GenMapUI.DrawThingLabel(GenMapUI.LabelDrawPosFor(intVec), Mathf.RoundToInt(z).ToStringCached(), Color.white);
z = 0;
}
}
}
}

2
Unfinished / (WIP) Twitch stream (IRC based) "organic" storyteller
« on: September 03, 2018, 07:47:16 AM »
What is "done":

IRC client and communication implemented by IrcDotNet with very minor modifications to buildin MarkovChainTextBot.
Unity socket permission stuff and integration will be tested soonish, but i know that it will work fine without major modifications, as i already run tests on mono dll grabbed from game.

IRC<>syncthread communication implemented by pair of ConcurrentQueue instances, one for input from channel and one for posting messages into channel.

Storyteller integration done via code injection and will work for any storyteller, ever custom ones, as long as they follow same "component" model as vanilla ones.
Code injection is p2p full replacement, will not be compatible with anything that want to inject into same methods.

Logic is simple, when storyteller is going to throw negative event, it's state is saved and execution is supressed for some time, not decided will it use ingame ticks like 24 ingame hours or IRL time.
Message is pushed for IRC component to be posted into stream chat.

Message is simple (and not localized) "Going to throw <eventname> what do you think?"
Users in chat have options "yes", "no" and "sarcasm" and vote simply by saying that in chat.

No any kind of special logic, each user have single vote, no options or configuration.
Default option is "yes" and without activity from users execution will work exactly like vanilla.

Then storyteller is resumed from suppression and based on votes adjust raid points on event.
It will not cancell event completely, just set 35 points and run it in case of "no", in case of "sacrasm" it will double raid points.
Cancelling event completely have side effects.

Sarcasm planned to provide other events instead (raid>siege>mechanoids), but i have no time to provide mod with such feature in reasonable time.

What is not done:
Ingame GUI components are not done and will not be shipped with intial versions of mod, login and password will be stored inside plaintext XML as thingdef of map component.
Steam, mod will not be posted to steam workshop ever.

Why this thread, well, i do not need any help with development, as basically i already have crude version of mod that works sometimes (and sometimes not).

It's about information exchange, as i personally never stream and signed twitch account less then 24 hours ago just to get IRC password token for testing IRC integration.

Originally i planned to use twitchlib, but most of features provided by library is no use and it demand login and password for twitch, asking such data as ingame popup just neh.


3
Bugs / [0.19.1987] Trying to build floors under flowerpots cause issue
« on: August 16, 2018, 09:16:04 AM »
Well, this is not bug, still

When you try to build floor under flower pot, jobdriver will order "cut plant" on that flower, after cut is complete, pawn will instantly switch to "sow plant" on same pot, repeated forever.

Caused by pawns with haul allowed and building not allowed.

Video is provided for more clarity.

https://youtu.be/cArLDtlXp1M

4
Unfinished / [WIP][A16] Realtime networking project
« on: April 06, 2017, 03:22:50 AM »
Features:

1) Basic async network stack
2) Basic server<>client infrastructure
3) Basic remote procedure calls (for demonstration purposes it uses http\web for now)
4) Basic async>>sync data processing

code:
https://github.com/RawCode/yaCIL/blob/master/_netLink.cs

demo mod as post attachment

How to use demo?

1) Run game with mod enabled, you will need to load map, it won't activate in pregame GUI
2) type localhost or 127.0.0.1 in your web browser, you will see simple form (screen 1)
3) type name of event, like "ShipChunkDrop", you can get list of event from devconsole or from "core" mod, any event will work fine.
4) event will trigger from 1 to 119 ticks from that moment
5) port and local bind are hardcoded to "localhost:80" for now, if you have 80th port bound game will fail with exception, there are no checks and recovery yet


[attachment deleted by admin due to age]

5
Tools / Gated code injection (yes it is not "destructive")*
« on: March 01, 2017, 10:20:04 AM »
All code can be found on git:
https://github.com/RawCode/yaCIL

*Non destructive code injection is not possible, you MUST change existing code to create entry point.
You can change call relative opcode inside specific methods to redirect flow, but this anyway destroys information about original call offsets.


1) Copy native function you need into RWX memory:
Code: [Select]

stored_ORIGINAL = new _FuncPtr32(typeof(Kagimono).GetMethod("ORIGINAL"));
stored_ORIGINAL.Rebase();
stored_ORIGINAL.Rebind();

After operation you have fully functional copy of provided function, you can invoke it with __CALL or _JMP methods provided with _FuncPtr32

2) Emit jmp into original method

Code: [Select]

_FuncPtr32 jmp = new _FuncPtr32(typeof(Kagimono).GetMethod("ORIGINAL"));
_FuncPtr32 gate = new _FuncPtr32(typeof(Kagimono).GetMethod("__GATE__ORIGINAL"));

jmp.Stream2Image();
jmp.Stream(__arglist((byte)0x68,(int)gate,(byte)0xC3));
jmp.Image2Raw();

It obviously destroys original method, but you already have copy.

Method "Stream" uses undocumented keyword __arglist.
You must specify type of each input, in other case, everything will be converted into integers and emit will fail hard due to zero opcodes appearing everywhere.
There is no way around, as developer have legitimate reasons to emit zero as integer and code can't read your mind (yet).

3) You still need managed method with proper signature, but you do not need to copy original method.

Code: [Select]

static _FuncPtr32 stored_ORIGINAL;
static public void __GATE__ORIGINAL(int _test_int)
{
_test_int+= 8;
stored_ORIGINAL.__HOST();
}

Gate code injection is about checking and altering arguments before they get into function.
Also you can yield to original method without any changes or cancel it's invocation completely and in case of methods with return - return some other value.

6
Tools / Magic of x86 assembly right inside your managed c# methods
« on: February 27, 2017, 06:54:19 AM »
Not useful by it's own, still, VERY useful in you know when and how.

How to use? look at this sample method:
Code: [Select]

[MethodImpl(MethodImplOptions.NoInlining)]
static public int RETURN_CALLER(int argx)
{
Console.WriteLine ("THIS IS RETURN CALLER PRE");
_ReJIT.__REPLACE
(
0x8B, 0x44, 0x24, 0x04, 0xD1, 0xE0, 0xC3
);
Console.WriteLine ("THIS IS RETURN CALLER POST");
return 0;
}

1)
Code: [Select]
[MethodImpl(MethodImplOptions.NoInlining)]Mandatory flag, in other case your singleline placeholder methods will get inlined and modifications will have no effect.
It will not inline your methods in current version anyway, just in case.

2) Output left for reference, you will see first message once, second message won't show up ever.

3)
Code: [Select]

_ReJIT.__REPLACE
(
0x8B, 0x44, 0x24, 0x04, 0xD1, 0xE0, 0xC3
);
this is actual payload, it accept sequence of bytes that will be emitted directly into executable memory.

That all, first execution will invoke anything that method contains prior to __ReJIT line, then will invoke rejitter and then rejitter will return to already modified method, skipping original stackframes.

code itself can be found here
https://github.com/RawCode/yaCIL/tree/master

Few spotlights (code useful on it's own):

Code: [Select]

_FuncPtr32 RETIMM = new _FuncPtr32(typeof(_ReJIT).GetMethod("__TOPCALLER"));

RETIMM.Array2Image
(
0x8B, 0x45, 0x04, //mov    eax,DWORD PTR [esp+0x0]
0xC3 //ret
);
RETIMM.Image2Raw();
topcaller returns method that called method that called topcaller
this method used to determinate, what method contains _ReJIT instruction, it essential for gated hooks.

Code: [Select]
_FuncPtr32 DROPSPECIAL = new _FuncPtr32(typeof(_ReJIT).GetMethod("__DROPSPECIAL"));

DROPSPECIAL.Array2Image
(
0x8B, 0x44, 0x24, 0x04,
0xC9,
0xC9,
0x50,
0xC3
);
DROPSPECIAL.Image2Raw();
dropspecial discards two stack frames, frame holding __REPLACE and frame holding method, that called __REPLACE and jump into new address, in current implementation, it jumps into freshly rejitted method.
this allows to reuse memory of original method, it it can hold entire sequence of bytes provided.

Not yet completed method _X68.Update__CALLR() that can be used to copy and rebase method from one memory location to other memory location, without any overhead.
It already works well and fail only in case of unregistered opcodes.

Not yet finalized method _Funcptr.__CALL() that already works but need some love and support of __arglist.
Anyway, you can create rejitted method for each signature you may need and invoke function pointers directly, without delegates or reflection.
Same code will be reused for more user friendly access to private fields of objects.

7
Outdated / [A16,CIB] Tastes like chicken!
« on: February 21, 2017, 04:55:10 AM »
Very very simple modification suggested few days ago.
It replaces ALL raw meat objects with raw chicken meat, including human.

Actually designed as fallback handler for modversion transfering, but can be used for fun.

It called "singleliner" for reason, i chip code from larger project, to keep individual uploads clean from unrelated code.

Payload is :

Code: [Select]
public static Thing __REJIT_MakeThing(ThingDef def, ThingDef stuff)
{
if (stuff != null && !stuff.IsStuff)
{
Log.Error(string.Concat(new object[]
{
"MakeThing error: Tried to make ",
def,
" from ",
stuff,
" which is not a stuff. Assigning default."
}));
stuff = GenStuff.DefaultStuffFor(def);
}
if (def.MadeFromStuff && stuff == null)
{
Log.Error("MakeThing error: " + def + " is madeFromStuff but stuff=null. Assigning default.");
stuff = GenStuff.DefaultStuffFor(def);
}
if (!def.MadeFromStuff && stuff != null)
{
Log.Error(string.Concat(new object[]
{
"MakeThing error: ",
def,
" is not madeFromStuff but stuff=",
stuff,
". Setting to null."
}));
stuff = null;
}


if (def.ingestible != null)
if (def.ingestible.foodType == FoodTypeFlags.Meat)
def = DefDatabase<ThingDef>.GetNamed ("Chicken_Meat",false);

Thing thing;

try
{
thing = (Thing)Activator.CreateInstance(def.thingClass);
}catch
{
Dictionary<Def,ModContentPack> test = new Dictionary<Def,ModContentPack> ();
foreach (ModContentPack tz in LoadedModManager.RunningMods)
{
foreach (Def gh in tz.AllDefs)
{
test [gh] = tz;
}
}

throw new Exception (def.defName + " have invalid thingclass owner is " + test[def].Name);
};

thing.def = def;
thing.SetStuffDirect(stuff);
thing.PostMake();
return thing;
}

[attachment deleted by admin due to age]

8
1) Very simple "custom implementation" of text writter:
Code: [Select]
public class ConsoleToUnityLogWritter : System.IO.TextWriter
{

public override System.Text.Encoding Encoding
{
get { return null;}
}

public override void Write (object value)
{
Log.Warning (value.ToString ());
}

public override void Write (string value)
{
Log.Warning (value);
}

public override void WriteLine ()
{
return;
}
}

2) Entry point that will trigger only in game and does nothing on external run:

Code: [Select]
[StaticConstructorOnStartup]
public unsafe class Kagimono
{
static Kagimono()
{
Verse.LongEventHandler.QueueLongEvent (gate_Main, "gate_Main_indirect_call", false, null);
}

static public void gate_Main()
{
Console.SetOut (new ConsoleToUnityLogWritter ());
Main (null);
}

3) Somewhat done, you will need stub method "Write" for each type of data you actually want to output.

9
Help / [Code Snippet (CS)] Not very safe _FunctionHandle class
« on: February 14, 2017, 06:04:00 AM »
Code: [Select]
using System;
using System.Runtime.InteropServices;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Reflection;
using System.Text;

namespace rcrml
{
unsafe public class _FunctionHandle
{
//sync with domain internals header line # 199

//void* equal to "native integer", it follows word size based on platform used automatically
public struct _MonoJitInfo
{
//should work on x64 due to variable size of void*
public RuntimeMethodHandle method; //should work properly because IntPtr host void* intenrnally
public void* next_jit_code_hash;
public IntPtr code_start; //same void* under wrappers
public uint  unwind_info;
public int    code_size;
public void* __rest_is_omitted;
//struct is longer actually, but rest of fields does not matter
}

//you may pass byte that belong to function, but is not first byte of function
//first byte will be used internally and can be accessed by ->code_start
//yes undescores violate naming convention, leave them be
private void* function_pointer;
private int malloc_size;
private byte[] function_image;    //managed pointer, managed type
private byte[][]    image_backup_stack;//managed pointer, managed type

//very unsafe
//raw (direct) pointer into VM memory structure that holds actual data
//modification to this data will cause VM wide effects
//both expected and unforseen
private _MonoJitInfo* function_jit_native; //pointer into native memory, unmanaged, unsafe

//semi constructors:

public _FunctionHandle(void* _pointer)
{
Initialize (_pointer);
}

public _FunctionHandle(MethodInfo _method_info)
{
Initialize ((void*)_method_info.MethodHandle.GetFunctionPointer ());
}

public _FunctionHandle(RuntimeMethodHandle _method_info_native)
{
Initialize ((void*)_method_info_native.GetFunctionPointer ());
}

//no platform word size checks here
public _FunctionHandle(long _unsafe_long)
{
Initialize ((void*)_unsafe_long);
}
public _FunctionHandle(int _unsafe_int)
{
Initialize ((void*)_unsafe_int);
}

private void Initialize(void* _pointer)
{
function_pointer = _pointer;
function_jit_native =
(_MonoJitInfo*)_Native.mono_jit_info_table_find (_Native.mono_domain_get (),function_pointer);

if (function_jit_native == null)
return;

malloc_size = Math.Max (function_jit_native->code_size, sizeof(void*) * 2);
}

public MethodBase GetReflectionHandle()
{
if (function_jit_native == null)
return null;
return MethodBase.GetMethodFromHandle (function_jit_native->method);
//real return is MonoMethod
}

//read and write methods are follow

private void PushImageBackup()
{
if (image_backup_stack == null)
image_backup_stack = new byte[8][];

Array.Copy (image_backup_stack, 0, image_backup_stack, 1, 7);
image_backup_stack [0] = function_image;
}

public byte[] Undo()
{
if (image_backup_stack == null)
return null;
if (image_backup_stack[0] == null)
return null;

byte[] shadow = function_image;

function_image = image_backup_stack [0];
Array.Copy (image_backup_stack, 1, image_backup_stack, 0, 7);
return shadow;
}

//read unmanaged memory into fresh byte[]
//always push value of function_image to backup stack
[MethodImpl(MethodImplOptions.NoInlining)]
public void SyncRaw2Image()
{
if (function_jit_native == null)
throw new Exception ("Pointer " + string.Format("{0:X4}",(long)function_pointer) + " does not belong to managed method");

byte[] newarray = new byte[malloc_size];
Marshal.Copy (function_jit_native->code_start, newarray, 0, malloc_size);

PushImageBackup ();
function_image = newarray;
}

//replace existing array with new one, params syntax sugar version, no safety
[MethodImpl(MethodImplOptions.NoInlining)]
public void SyncArray2Image(params byte[] _array)
{
//no safety here!
PushImageBackup ();
function_image = _array;
}

public byte[] GetFunctionImage()
{
byte[] shadow = new byte[function_image.Length];
Array.Copy (function_image, shadow, function_image.Length);
return shadow;
}

public byte[] GetFunctionImageRef()
{
return function_image;
}

//Emit data stored inside array into unmanaged RWX memory
//no safety checks, may ruin your game deeply
[MethodImpl(MethodImplOptions.NoInlining)]
public void SyncImage2Raw()
{
if (function_jit_native == null)
throw new Exception ("Pointer " + string.Format("{0:X4}",(long)function_pointer) + " does not belong to managed method");

if (function_image.Length > malloc_size)
throw new Exception ("Provided array cannot fit, check your code or use Rebase");

Marshal.Copy (function_image, 0, function_jit_native->code_start, function_image.Length);
}

public void WriteLine()
{
Console.WriteLine (ToString ());
}

[MethodImpl(MethodImplOptions.NoInlining)]
public override string ToString()
{
//this required to for one line printing of function data
if (function_image == null)
SyncRaw2Image ();
if (function_image == null)
return "Pointer " + string.Format("{0:X4}",(long)function_pointer) + " does not belong to managed method";
StringBuilder sb = new StringBuilder ();
MethodBase mb = GetReflectionHandle ();

long delta = (long)function_pointer - (long)function_jit_native->code_start;

sb.Append ("IP BEGIN " + mb + "+" + string.Format("{0:X4}",delta) +" ( "+String.Format("{0:X2}", (long)function_jit_native->code_start)+" )");

int az = -1;

foreach (byte i in function_image)
{
az++;
if (az % 4 == 0)
sb.Append ("\n" + String.Format("{0:X2}", i));
else
sb.Append (" " + String.Format("{0:X2}", i));
}
sb.Append ("\nIP END " + mb +" ( "+String.Format("{0:X2}", (int)function_jit_native->code_start)+" )");

return sb.ToString ();
}

}
}

Usage:

Code: [Select]
_FunctionHandle fh1 = new _FunctionHandle (typeof(Kagimono).GetMethod ("TEST_HOOK"));

fh1.SyncRaw2Image (); //read native memory into "image"
fh1.SyncArray2Image (0xC3); //replace "image" with solo RET sequence
TEST_HOOK (); //test invoke
fh1.SyncImage2Raw (); //apply modifications to native memory
TEST_HOOK (); //test invoke
byte[] redo = fh1.Undo (); //undo last modification - in our caseSyncArray2Image
//there is no "redo" stack.
//up to 8 modifications are tracked for each function handle
fh1.SyncImage2Raw (); //apply Undo to native memory
TEST_HOOK (); //test invoke
fh1.SyncArray2Image (redo); //redo changes to image
fh1.SyncImage2Raw (); //write image to native memory
TEST_HOOK (); //test invoke

10
Tools / Code injection development tutorial basics
« on: January 23, 2017, 03:08:23 AM »
This tutorial about "developing" code injection routines, not about using them.

1) You will need mono runtime source code, there are two options:
"staging" version provided by unity https://github.com/Unity-Technologies/mono?files=1
or mono-2 provided by mono itself https://github.com/mono/mono/tree/mono-2-0

Mono source code is "C" (without sharp) with lots and lots of pointers, you don't really need to know C to read sources, still, there are two major tricks:

Number of declarations have special versions with leading underscore, like _MonoMethod normally, such declarations do have actual code and never referenced from anywhere, expect place of declaration.

Watch for pointer sign (*), especially in case of structs.
If one struct reference other struct directly, it will be injected completely and can be typecasted both directions.
If one struct reference other struct by pointer, only 4-8 bytes reference is provided and structs cannot be typecasted directly.

Some structs allocated and passed from middle of declaration, VTABLE stuff is done by typecasting pointer to 3 different objects, many other objects created similar way.

2) You need notepad++ to navigate around source code.

3) Start from simple task, get native code of some "extern" method, like "GetFunctionPointer" nothing complicated.
There number of abstraction layer, you need to get self (without any 3rd party help) actual method that do return pointer you need.

4) You can't use number of native methods directly, due to issues with export table - some methods are not present in export table and registered only as ICALLS, some methods are removed from export table and not registered as ICALLS.
To make sure, is method available from game, use tools like DLL export viewer http://www.nirsoft.net/utils/dll_export_viewer.html

also you can test it directly, but this is time consuming task

5) About time consumption, it's viable to setup workspace and perform compilation of dll, that can run standalone and from game at same time without any modifications.

First of all, mark your main type with
Code: [Select]
[StaticConstructorOnStartup]
Then, create static constructor, similar to provided one
Code: [Select]
static Kagimono()
{
Action tx = new Action(delegate
{
Main(null);
});

Verse.LongEventHandler.QueueLongEvent (tx, "MixedMain", false, null);
}

Under normal conditions you are not allowed to invoke any platform methods, especially methods related to modification of executable memory from non main thread.
Such construction ensure, that your main will be invoked by game from main thread.

Manager do nothing outside from game, so you don't need any checks or similar constructions if you running project externally.

6) You can execute DLL if it have entry point
Code: [Select]
"C:\Program Files (x86)\Mono\bin\mono" --debug "D:\User\Desktop\MonoRuntimeTest\bin\Release\MonoRuntimeTest.dll"
Just make sure, that you have only mono-2 or reference proper version of mono, in other case, you may brew code, that will not work properly ingame.

7) Make sure that you are executing your code with mono runtime, MS runtime have completely different rules related to code injection.

8) After some time, you will need to work with x86-64 there is no way around, C# is jit based framework and all your methods are compiled on demand at moment of execution.

Reading assembler a lot more simple with services like
https://defuse.ca/online-x86-assembler.htm#disassembly

9) To extract opcodes from function pointer, you may brew something yourself, or use code provided below.
NOTE: it does not work in current version of game, without changing __Internal to mono.dll (for windows)
Multibind solution is WIP at this moment, check for updates soon.
Code: [Select]
using System.Runtime.CompilerServices;
using System.Reflection;
using System.Text;

namespace rcrml
{
unsafe public class _FunctionHandle
{
[DllImport("__Internal")]//replace to meta mono
extern static void* mono_domain_get ();

[DllImport("__Internal")]//replace to meta mono
static extern private unsafe _MonoJitInfo* mono_jit_info_table_find(void* _MonoDomainPtr, void* _FuncPtr);
public unsafe struct _MonoJitInfo
{
//should work on x64 due to variable size of void*
public RuntimeMethodHandle method; //should work properly because IntPtr host void* intenrnally
public void* next_jit_code_hash;
public IntPtr code_start; //same void* under wrappers
public uint  unwind_info;
public int   code_size;
public void* _rest_is_omitted;
//struct is longer actually, but rest of fields does not matter
}

//you may pass byte that belong to function, but is not first byte of function
//first byte will be used internally and can be accessed by ->code_start
public void* function_ptr;
public _MonoJitInfo* mono_jit_info_ptr;
public byte[] function_image;//this is managed pointer, be carefull

public _FunctionHandle(void* _FuncPtr)
{
mono_jit_info_ptr = mono_jit_info_table_find (mono_domain_get (),_FuncPtr);
function_ptr = _FuncPtr;//can be non equal to code start
}

[MethodImpl(MethodImplOptions.NoInlining)]
public MethodBase GetReflectionHandle()
{
return MethodBase.GetMethodFromHandle (mono_jit_info_ptr->method);
}//return same type actually - MonoMethod

[MethodImpl(MethodImplOptions.NoInlining)]
public void SyncRaw2Image()
{//do not change size inside  jit info struct, it will affect runtime
int sizefixup = Math.Max (mono_jit_info_ptr->code_size, sizeof(void*) * 2);
byte[] tmpret = new byte[sizefixup];
Marshal.Copy (mono_jit_info_ptr->code_start, tmpret, 0, sizefixup);
function_image = tmpret;
}

[MethodImpl(MethodImplOptions.NoInlining)]
public void SyncImage2Raw()
{
Marshal.Copy (function_image, 0, mono_jit_info_ptr->code_start, mono_jit_info_ptr->code_size);
}

[MethodImpl(MethodImplOptions.NoInlining)]
public void PrepareJmpABS64AX(void* _TargetFuncPtr)//absolute 64 AX register (EAX\RAX)
{
//function_image [0] = 0x90;

//function_image [1] = ((byte*)&offset)[0];
//function_image [2] = ((byte*)&offset)[1];
//function_image [3] = ((byte*)&offset)[2];
//function_image [4] = ((byte*)&offset)[3];

}

[MethodImpl(MethodImplOptions.NoInlining)]
public void PrepareJmpREL32I(void* _TargetFuncPtr)//relative 32 bit intermediate
{
int offset = (int)_TargetFuncPtr - (int)mono_jit_info_ptr->code_start;

function_image [0] = 0x90;

function_image [1] = ((byte*)&offset)[0];
function_image [2] = ((byte*)&offset)[1];
function_image [3] = ((byte*)&offset)[2];
function_image [4] = ((byte*)&offset)[3];

}

[MethodImpl(MethodImplOptions.NoInlining)]
public void PrepareJmpABS32PR(void* _TargetFuncPtr)//absolute 32 bit push return
{
//always fits, min size is sizeof(void*)*2 (8-16)
//does not works on inlined methods
//obviously will damage function, still, you can save image
//before setting jump to rollback if you need
function_image [0] = 0x68;

function_image [1] = ((byte*)&_TargetFuncPtr)[0];
function_image [2] = ((byte*)&_TargetFuncPtr)[1];
function_image [3] = ((byte*)&_TargetFuncPtr)[2];
function_image [4] = ((byte*)&_TargetFuncPtr)[3];

function_image [5] = 0xC3;
}

[MethodImpl(MethodImplOptions.NoInlining)]
public string PrintFromShallowCopy()
{
StringBuilder sb = new StringBuilder ();
MethodBase mb = GetReflectionHandle ();
sb.Append ("IP BEGIN " + mb +" ( "+String.Format("{0:X2}", (int)function_ptr)+" )");

foreach (byte i in function_image)
{
sb.Append ("\n" + String.Format("{0:X2}", i));
}
sb.Append ("\nIP END " + mb +" ( "+String.Format("{0:X2}", (int)function_ptr)+" )");

return sb.ToString ();
}

}
}

Typical output looks like:

Code: [Select]
IP BEGIN Void TEST_BASE_NONDYNAMIC() ( 2B5C488 )
55
8B
EC
83
EC
08
8B
05
E0
3F
51
00
83
EC
0C
50
E8
57
3E
FE
FF
83
C4
10
C9
C3
IP END Void TEST_BASE_NONDYNAMIC() ( 2B5C488 )

Where "Void TEST_BASE_NONDYNAMIC()" is full name of method extracted from pointer and "( 2B5C488 )" is pointer itself.
Byte per line is opcodes of passed method, size of functions is calculated automatically (managed methods only).

Usage is:
Code: [Select]
void* dx = typeof(Kagimono).GetMethod ("TEST_BASE_NONDYNAMIC").MethodHandle.GetFunctionPointer ().ToPointer ();

_FunctionHandle x = new _FunctionHandle (dx);
x.SyncRaw2Image ();
Console.WriteLine (x.PrintFromShallowCopy ());

Just copypaste output of PrintFromShallowCopy to defuse.ca and you will get a bit more usefull representation of data
SEE ATTACHMENT #1

11) As you can see, defuse.ca can be used to compile basic assembly and provide you C# compatible array, you can use it directly with method like (not part of library due to "reasons")
Code: [Select]
[MethodImpl(MethodImplOptions.NoInlining)]
public void LoadImageParams(params byte[] data)
{
function_image = data;
}

Lets compile "mov EAX,EBP;RET;"
SEE ATTACHMENT #2


Resulting array is "{ 0x89, 0xE8, 0xC3 }" just copypaste it into LoadImageParams

Code: [Select]
x.LoadImageParams( 0x89, 0xE8, 0xC3 );
Performing "SyncImage2Raw" will result in loading new code for method, running method will invoke your code.

13) Some methods are special, they are wrapped or "gated", you can notice such conditions ever without special skills - change method, get function image, change method again, add new call, or remove one of calls, get function image again, if image does not reflect your changes you are peeking at trampoline.

If multiple methods provide same function pointer, you are peeking at shared trampoline and actual method is passed as argument.
Noticing same pointer condition only possible at same run, different runs always result in different pointers, this is due to memory allocation.

[attachment deleted by admin due to age]

11
Help / Injecting hook for method that does not exists (lol?)
« on: January 04, 2017, 05:44:39 AM »
Sometimes people tell me, what my own code can and can't do, sometimes they are right, sometimes they are wrong, this is second case.

Yes, technically you can't inject new code into method, that have no references, but this does not mean, that you can't inject code into method one step above.

All and every virtual method is instance one, you can't (legally) have method both static and virtual, reason behind this is virtual dispatch table, that stored inside all and every object, value types don't have vtable, but this does not belong to this thread.

Unlike "static" methods, virtual ones are never (by normal code) called directly, you can call virtual method directly by natives and reflection, but normal code never does this.
Instead, object and vtable index are passed into dispatch table function, that select proper method to be called for passed object and jump into that method.

What this means?
We always have object reference and can perform secondary dispatch inside our managed code.
Yes some objects does not have virtual method we want, instead, we will hook base method, copy paste entire code and inject additional branch with custom code for that specific object type.
Sounds simple, well, you already can copypaste methods from game into your "detours" it's about copy pasting two methods into single body and add branch condition to select proper one.

Little setup code, we have one base type that have one method we don't want.
Additional type that have virtual method override.
Type that does not have override and should use hook.
And type that does not have override and should use hook.
Code: [Select]
public class basex
{
virtual public void showmewhatyougot()
{
Console.WriteLine ("this is base method");
}
}

public class havemyown : basex
{
virtual public void showmewhatyougot()
{
Console.WriteLine ("i have my own implementation of method");
}
}

//out task to hook method only for this class
//base class and donthave_and_dont_allow_hook should call original method
public class donthave_allow_hook : basex
{
virtual public void showmewhatyougot1()
{
Console.WriteLine ("this will not call");
}
}

public class donthave_and_dont_allow_hook : basex
{
virtual public void showmewhatyougot1()
{
Console.WriteLine ("this will not call");
}
}

replacement method is

Code: [Select]
static public void MAGIC(basex thisx)
{
if (thisx is donthave_and_dont_allow_hook)
{
//code of base method is copypasted here
Console.WriteLine ("this is base method from hook");
return;
}
if (thisx.GetType() == typeof(basex))
{
//code from base method is copypasted here second time
//for reason described below
Console.WriteLine ("this is base method from hook");
return;
}
//replacement code
Console.WriteLine ("hooked method that does not exists WOA!");
}

Only thing is actually complicated, is filter for base class, issue is simple, every child class will pass "is basex" condition and basex class also will pass this condition, if you want to filter base class, you must perform exact type check, instanceof or "assignablefrom" will fail.

Code: [Select]
new basex ().showmewhatyougot ();
new donthave_allow_hook ().showmewhatyougot ();
new donthave_and_dont_allow_hook ().showmewhatyougot ();
new havemyown ().showmewhatyougot ();

result is
Code: [Select]
this is base method from hook
hooked method that does not exists WOA!
this is base method from hook
i have my own implementation of method

Similar tricks are possible by:
Injecting SAME code everywhere and calling MethodBase.GetCurrentMethod (), when method is passed by "jmp" instruction, it does not have it's own stackframe and will be detected by stackwalker as original method.

Injecting code, including inline cases and getting one stackframe above, to get information about, what method called us, acting based on that, invoking custom code of full copy of original.

12
Help / Assembler for everyone: __jmp31 function implementation for mono\C#
« on: December 18, 2016, 09:17:48 AM »
Well, new things in this topic (compared to my prev threads):

1) Allocation of RWX memory;
2) Calling into RWX memory without much magic;

Code: [Select]
using System;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

namespace rc.kagimono.cmu
{
unsafe public class CodeManipulationUtils
{
//this method will allocate new codemanager
//you now allowed to access global codemanager with mono.dll shipped with game*
//*it's possible to access it anyway, but there are no reasons to do it
[DllImport("__Internal")]
static extern private unsafe void* mono_code_manager_new();

//this method will allocate memory with RWX permissions
//since you have exclusive access to that memory, no reasons to follow commit procedure
[DllImport("__Internal")]
static extern private unsafe void* mono_code_manager_reserve(void* MonoCodeManager, int size);

//you already seen this struct, do not cache results anywhere and do not store it
[StructLayout(LayoutKind.Explicit,Size=32)]
public unsafe struct reinterpret_cast_struct_32
{
[FieldOffset(0)] public object target;
[FieldOffset(0)] public void* pointer;
}

static void* u_MonoCodeManager;
static void* u_RWXM;
static CodeManipulationUtils()
{
u_MonoCodeManager = mono_code_manager_new ();
u_RWXM = mono_code_manager_reserve (u_MonoCodeManager, 512);
Console.WriteLine ("RWX allocation " + (int)u_RWXM);
}


//ease of use bits, it's possible to allocate delegate object by other means
delegate int __jmp_delegate();

//method to allocate delegate, never actually called
[MethodImpl(MethodImplOptions.NoInlining)]
static public int __jmp_dummy_method()
{
throw new Exception ("Jump failure");
return 0;
}

//this method explained in forum post, line by line
[MethodImpl(MethodImplOptions.NoInlining)]
static public int __jmp31(void* _dest)
{
__jmp_delegate callsite = __jmp_dummy_method;
reinterpret_cast_struct_32 rcs = new reinterpret_cast_struct_32 ();
rcs.target = callsite;
((int*)rcs.pointer) [3] = (int)_dest;
return callsite ();
}

//load bytearray into RWX memory and call into it
[MethodImpl(MethodImplOptions.NoInlining)]
static public int __asm32(params byte[] x8632)
{
Marshal.Copy (x8632, 0, new IntPtr (u_RWXM), x8632.Length);
return __jmp32 (u_RWXM);
}
}
}

Simple things explained in comments, complex stuff is __jmp32, explanation line by line:

Code: [Select]
__jmp_delegate callsite = __jmp_dummy_method;cause runtime to create and initialize multicast delegate that extends __jmp_delegate inner (hidden) type, this is syntax sugar, real code is not "single line".

Code: [Select]
reinterpret_cast_struct_32 rcs = new reinterpret_cast_struct_32 ();
rcs.target = callsite;
((int*)rcs.pointer) [3] = (int)_dest;
allocate memory to host reinterpret_cast_struct_32 instance (32 bytes of memory)
store reference to our delegate object into first word of allocated memory
read that memory as int* to overcome type safety rules of c#
then replace 4th word of delegate object with provided pointer

Code: [Select]
return callsite ();invoke our delegate

this method allows to call any pointer as function, but perform no safety checks of any kind, calling invalid pointer will crash runtime without any warning.

Usage:
Code: [Select]
//print "some value" extracted via ASM code
Console.WriteLine (CodeManipulationUtils.__asm32 (0xB8, 0xD2, 0x04, 0x00, 0x00, 0xC3));

Code: [Select]

//call "wtf1" method
CodeManipulationUtils.__jmp31 (typeof(Kagimono).GetMethod ("wtf1").MethodHandle.GetFunctionPointer ().ToPointer ());

__jmp31 called this way because this is not "jmp" and "true" jump is not possible without changing how jitter works

13
Well, issue cannot be ignored anymore, major modding tool remain mystery for community two years later.

Reasons, well, reasons are simple, people do not like thing they do not understand, can't use properly things they do not understand and unable to contribute and improve things they do not understand.

I will try to change situation.
Sadly, trying to keep my own rule "no spoonfeeding" and "refer proper documentation please" resulted in, well, bad things.

Please ask your questions related to code injection, i will do my best do explain usage and internals.

Few "mini articles" are already panned and will be posted in upcoming days.

14
subjtldr
Code: [Select]
static RWL ()
{
SetHookFromToABS64(
typeof(Pawn_StoryTracker).GetMethod("WorkTagIsDisabled"),
typeof(RWL).GetMethod("hook_WorkTagIsDisabled"));

SetHookFromToABS64(typeof(Pawn_StoryTracker).GetProperty("CombinedDisabledWorkTags",
(BindingFlags)0x3F3C).GetGetMethod(),
typeof(RWL).GetMethod("hook_CombinedDisabledWorkTags"));
}

hooks are

Code: [Select]
static public WorkTags hook_CombinedDisabledWorkTags(object ignored_this)
{
//Log.Warning ("Echo:hook_get_CombinedDisabledWorkTags");
return WorkTags.None;
}

static public bool hook_WorkTagIsDisabled(object ignored_this,object ignored_tag)
{
return false;
}

answer to
https://ludeon.com/forums/index.php?topic=24130.0

[attachment deleted by admin - too old]

15
Mods / Non reflection based access to private fields
« on: August 11, 2016, 09:47:27 PM »
subj
tl:dr section in very end

Code: [Select]

[StructLayout(LayoutKind.Explicit,Size=8)]
public unsafe struct s_rpret
{
[FieldOffset(0)] public object _o;
[FieldOffset(0)] public void*  _v;
}

no reason to store in static fields, this struct always allocated from stack, accessing static field will take more time.
void* can be safely replaced by any other pointer, they all have same size anyway.
If you think that IntPtr is better - open source code of that class and you will be surprised.

Code: [Select]
s_rpret caster = new s_rpret();
caster._o = targetObject;

Alternative is ugly __makeref() left for reference, result is same.

Code: [Select]

TypedReference rawref = __makeref(object);
int** actualref = (int**)&rawref;
Console.WriteLine(*actualref[1]); //result is pointer to object

Now lets talk about reading and writing objects.

All classes have struct layout auto and all structs have layout sequential, this can and will cause issues if ignored.
Classes have vtable and syncblock both have size of native int (32\64) (long on 64 bit)

Layout auto allows runtime to "move" fields around in order to reach most effective allocation, result is deterministic, two sets of fields with layout auto will be stored in same manner, always.
Looks like mono embedded with game does not perform any optimizations, still, you must take this in account.

If you extend class and add new fields, runtime will add them separately in increment manner, optimizations done at block level, so extension will never alter field order of base class.

Lets begin, out "victim" class:

Code: [Select]

public class PrivateClass
{
private int NoAccessA = 99998;
private int NoAccessB = 88888;
private int NoAccessC = 77777;

public void print()
{
Console.WriteLine(NoAccessA);
Console.WriteLine(NoAccessB);
Console.WriteLine(NoAccessC);
}
}

Write "same" field struct:

Code: [Select]
public unsafe struct smap_PrivateClass
{
public void* vtable;
public void* syncblock;
public int NoAccessA;
public int NoAccessB;
public int NoAccessC;
}
don't forget about special fields, struct do not have them by default.

final code will looks like:
Code: [Select]

PrivateClass pc = new PrivateClass();
s_rpret caster = new s_rpret();
caster._o = pc;
((smap_PrivateClass*)caster._v)->NoAccessA = 1;
((smap_PrivateClass*)caster._v)->NoAccessB = 1;
((smap_PrivateClass*)caster._v)->NoAccessC = 1;
pc.print();
fields are set without usage of reflection, same code can be used for reading.

Special note related to storing smap_PrivateClass in variables:

expected result:
Code: [Select]
smap_PrivateClass* mirror = (smap_PrivateClass*)caster._v;

mirror->NoAccessA = 1;
mirror->NoAccessB = 1;
mirror->NoAccessC = 1;
local bitwise copy:
Code: [Select]
smap_PrivateClass mirror = *(smap_PrivateClass*)caster._v;

mirror.NoAccessA = 1;
mirror.NoAccessB = 1;
mirror.NoAccessC = 1;

pc.print();


complete code:
Code: [Select]
public class PrivateClass
{
private int NoAccessA = 99998;
private int NoAccessB = 88888;
private int NoAccessC = 77777;

public void print()
{
Console.WriteLine(NoAccessA);
Console.WriteLine(NoAccessB);
Console.WriteLine(NoAccessC);
}
}

public unsafe struct smap_PrivateClass
{
public void* vtable;
public void* syncblock;
public int NoAccessA;
public int NoAccessB;
public int NoAccessC;
}


[StructLayout(LayoutKind.Explicit,Size=8)]
public unsafe struct s_rpret
{
[FieldOffset(0)] public object _o;
[FieldOffset(0)] public void*  _v;
}

//TypedReference ttz = __makeref(pc);
//int** ggv = (int**)&ttz;
//Console.WriteLine(*ggv[1]);

static void ext()
{
PrivateClass pc = new PrivateClass();
s_rpret caster = new s_rpret();
caster._o = pc;

smap_PrivateClass* mirror = (smap_PrivateClass*)caster._v;

mirror->NoAccessA = 1;
mirror->NoAccessB = 1;
mirror->NoAccessC = 1;

pc.print();

//((smap_PrivateClass*)caster._v)->NoAccessA = 1;
//((smap_PrivateClass*)caster._v)->NoAccessB = 1;
//((smap_PrivateClass*)caster._v)->NoAccessC = 1;

}

Pages: [1] 2 3 4