Menu

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.

Show posts Menu

Topics - RawCode

#1
Help / Making custom overlay display step by step
August 09, 2021, 08:47:36 AM
1) Open the game;
2) Hover over existing overlay display, like "beauty";
Toggle beauty display
3) Search this string inside data folder
   
<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.

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:
BeautyDrawer
EnvironmentStatsDrawer

7) Method
DrawBeautyAroundMouse
is 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:

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:

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)

GameObject go = new GameObject("TOKEN");
go.AddComponent<XToken>();
UnityEngine.Object.DontDestroyOnLoad(go);
go.SetActive(true);


Payload:

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
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
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
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
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:

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


_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.


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
Not useful by it's own, still, VERY useful in you know when and how.

How to use? look at this sample method:

[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)
[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)

_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):


_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.


_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!
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 :

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:
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:

[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
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:


_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
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
[StaticConstructorOnStartup]

Then, create static constructor, similar to provided one
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
"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.
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:

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:
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")
[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

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
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.
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

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.

new basex ().showmewhatyougot ();
new donthave_allow_hook ().showmewhatyougot ();
new donthave_and_dont_allow_hook ().showmewhatyougot ();
new havemyown ().showmewhatyougot ();


result is
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
Well, new things in this topic (compared to my prev threads):

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

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:

__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".

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

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:

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



//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
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

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
August 11, 2016, 09:47:27 PM
subj
tl:dr section in very end


[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.


s_rpret caster = new s_rpret();
caster._o = targetObject;


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


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:


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:

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:

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:
smap_PrivateClass* mirror = (smap_PrivateClass*)caster._v;

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

local bitwise copy:
smap_PrivateClass mirror = *(smap_PrivateClass*)caster._v;

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

pc.print();



complete code:

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;

}
#16
Outdated / [A14] Rickroll mod!
July 17, 2016, 02:10:26 AM
This mod allows you to get rickrolled without visiting youtube!

https://www.sendspace.com/file/uhjr8i

https://www.youtube.com/watch?v=N3WT1c9Dq3U&feature=youtu.be

p.s.
Actually this is x64_Hook_Abs_From_To testing modification, just run mod and tell me, do it works on MAC\Linux thx.

Sources are included as post attachment.

[attachment deleted by admin - too old]
#17
Public:

Number of methods with 0 arguments is 27968
Number of methods with 1 arguments is 12425
Number of methods with 2 arguments is 2910
Number of methods with 3 arguments is 706
Number of methods with 4 arguments is 177
Number of methods with 5 arguments is 62
Number of methods with 6 arguments is 20
Number of methods with 7 arguments is 8
Number of methods with 8 arguments is 1
Number of methods with 9 arguments is 5
Number of methods with 10 arguments is 1
Number of methods with 11 arguments is 0
Number of methods with 12 arguments is 0
Number of methods with 13 arguments is 0
Number of methods with 14 arguments is 1


All:

Number of methods with 0 arguments is 45279
Number of methods with 1 arguments is 15272
Number of methods with 2 arguments is 3436
Number of methods with 3 arguments is 876
Number of methods with 4 arguments is 293
Number of methods with 5 arguments is 84
Number of methods with 6 arguments is 25
Number of methods with 7 arguments is 13
Number of methods with 8 arguments is 1
Number of methods with 9 arguments is 5
Number of methods with 10 arguments is 1
Number of methods with 11 arguments is 1
Number of methods with 12 arguments is 0
Number of methods with 13 arguments is 0
Number of methods with 14 arguments is 1


Static:

Number of methods with 0 arguments is 948
Number of methods with 1 arguments is 1759
Number of methods with 2 arguments is 708
Number of methods with 3 arguments is 305
Number of methods with 4 arguments is 113
Number of methods with 5 arguments is 56
Number of methods with 6 arguments is 22
Number of methods with 7 arguments is 9
Number of methods with 8 arguments is 1
Number of methods with 9 arguments is 5
Number of methods with 10 arguments is 1
Number of methods with 11 arguments is 1
Number of methods with 12 arguments is 0
Number of methods with 13 arguments is 0
Number of methods with 14 arguments is 1


Sources:
Assembly sx = typeof(AcceptanceReport).Assembly;

int argmax = 0;
MethodInfo maxed = null;
int iz = 0;

int[] breakdown = new int[32];


foreach (Type t in sx.GetTypes())
foreach (MethodInfo m in t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
{
breakdown [m.GetParameters ().Length]++;
if (m.GetParameters ().Length > argmax)
{
argmax = m.GetParameters ().Length;
maxed = m;
}
}

while (true)
{
Console.WriteLine ("Number of methods with " + iz + " arguments is " + breakdown[iz]);
iz++;
if (iz >= 20)
break;
}
#18
Help / Mono x86-64 ABS hooks
June 25, 2016, 08:43:57 AM
Unlike my first and second posts about subject, this code "LIKELY"(read as "must work but untested in *live* enviroment") to work on MAC\Linux without any modifications.

Also all provided functions perform absolute adress jump, ever on 32 bit platform.
No need of short\near offset calculation.

First function, abs jump via eax\rax, obviously will damage eax\rax:
(similar to native stuff implemented by windows API, damage of EAX\RAX follow calling convention actually)

static public unsafe byte[] x64_Hook_Abs_From_To(MethodInfo From, MethodInfo Dest)
{
//will damage 12 bytes of target function
//store and return byte array of original function

if (From == null)
throw new Exception ("From method is null");

if (Dest == null)
throw new Exception ("Dest method is null");

byte* FromPTR = (byte*)From.MethodHandle.GetFunctionPointer ().ToPointer ();
void* DestPTR = Dest.MethodHandle.GetFunctionPointer ().ToPointer ();
int sovp = 0; //Size Of Void Pointer

byte[] orgcode = new byte[12];

while(sovp < orgcode.Length)
{
orgcode [sovp] = FromPTR [sovp];
sovp++;
}

sovp = sizeof(void*);
FromPTR [0]     = (byte)(sovp==4 ? 0x90 : 0x48); //sign extension flag or NOP for x86
FromPTR [1] = 0xB8; //EAX\RAX selection
*(long*)(FromPTR+2) = (long)DestPTR; //magic related to avoid pointer match auto multiplication
FromPTR [sovp+2]    = 0xFF; //JUMPF
FromPTR [sovp+3]    = 0xE0; //R-M-BYTE section 4(E) direction EAX\RAX(0)

return orgcode;
}


No register version of function:

static public unsafe byte* x64_Hook_Abs_From_To_NR(MethodInfo From, MethodInfo Dest)
{
//will not damage any register
//will allocate 20 bytes of unmanaged memory
//will damage 12 bytes of source(from) function
//store and return pointer to native memory required to recovery
//setting return value via pointer operation will alter codeflow of hooked method

if (From == null)
throw new Exception ("From method is null");

if (Dest == null)
throw new Exception ("Dest method is null");

byte* FromPTR = (byte*)From.MethodHandle.GetFunctionPointer ().ToPointer ();
void* DestPTR = Dest.MethodHandle.GetFunctionPointer ().ToPointer ();

//32-64 detection
int sovp = sizeof(void*), tmp = sizeof(void*);

//fixed size, real size is 4+sovp*2 (8 and 20)
byte* store = (byte*)Marshal.AllocHGlobal (20).ToPointer();
*(long*)store = (long)DestPTR;

while(tmp < 20)
{
store [tmp] = FromPTR [tmp-sovp];
tmp++;
}

FromPTR [0] = (byte)(sovp==4 ? 0x90 : 0xFF);
FromPTR [1] = (byte)(sovp==4 ? 0xFF : 0x24);
FromPTR [2] = 0x25;
*(long*)(FromPTR+3) = (long)store;

return store;
}


No register version store data required to perform hook inside unmanaged memory, there is no way to use heap due to garbage collection.
Very minor modifications allows to use static fields instead of unmanaged memory (static fields never moved in memory).
You likely to see this version over unmanaged buffer (or native code managed) in my not yet finished project.

After such hook is installed, it can be altered by single set operation:

byte* datax = x64_Hook_Abs_From_To_NR (ma, mb);

TEST_A ();
TEST_B ();

*(long*)datax = (long)mc.MethodHandle.GetFunctionPointer ().ToPointer ();

TEST_A ();
TEST_B ();


Some individuals demanded "short" version of hook and ever removed padding from CCL implementation.

Well, short version of abs jmp for x32 (similar hack is possible on 64 by adding sign extension flag, sadly it will have same size as *long* version (4+8) due to rm and ex flags):

static public unsafe void x86ABSHookIndirect(MethodInfo ORG, MethodInfo NEW)
{
byte* dptr = (byte*)ORG.MethodHandle.GetFunctionPointer ().ToPointer ();
dptr [0] = 0x68;
*(int*)(dptr + 1) = (int)NEW.MethodHandle.GetFunctionPointer ().ToPointer ();
dptr[5] = 0xC3;
//6 bytes abs jmp
}


Provided methods have safety stripped and will fail hard if source method less then size of injection.
Inlined methods also cannot be altered.
Solution will be provided later.

p.s. there is no problems with overloads, just use your head or provided method(s):

static public int GetHashCodeSpecial(Type[] data)
{
int hash = 31;
foreach (Type o in data)
hash = (hash * 54059) ^ (o.GetHashCode () * 76963);
return hash;
}
static public int GetHashCodeSpecial(ParameterInfo[] data)
{
int hash = 31;
foreach (ParameterInfo o in data)
hash = (hash * 54059) ^ (o.ParameterType.GetHashCode () * 76963);
return hash;
}

static public MethodInfo GetMethodWithOverloads(Type t, string s, params Type[] argx)
{
if (t == null)
throw new Exception ("Type is null");
if (t == null)
throw new Exception ("Name is null");
if (argx == null || argx.Length == 0)
throw new Exception ("No arguments?");

MethodInfo[] store = t.GetMethods ((BindingFlags)60);
int argxh = GetHashCodeSpecial (argx);
foreach (MethodInfo m in store)
{
if (m.Name.Equals (s) && GetHashCodeSpecial (m.GetParameters ()) == argxh)
{
return m;
}
}
throw new Exception ("No suitable method is found");
}


happy hooking!
#19
Help / x86 Mono "safe" native data access
May 16, 2016, 07:14:17 AM
Not safe actually.
Content:

Platform independant (should be) native bindings that actually works with a13 public build;
Implementation sample;
Proof of work;

Structs:

//partial map for MonoJitInfo unmanaged structure
[StructLayout(LayoutKind.Explicit)] public unsafe struct u_MonoJitInfo
{
[FieldOffset(0) ] public int  *dmethod;
[FieldOffset(8) ] public int  *code_start;
[FieldOffset(16)] public int   code_size;
}

//partial map for MonoMethod unamanged structure
[StructLayout(LayoutKind.Explicit)] public unsafe struct u_MonoMethod
{
[FieldOffset(16) ] public int* name;
}


natives:

[DllImport("__Internal")]
static extern private unsafe int* mono_method_full_name(int* MonoMethod, bool signature = true);

[DllImport("__Internal")]
static extern private unsafe int* mono_jit_info_table_find(void* MonoDomain, void* ptr2function);

[DllImport("__Internal")]
static extern private unsafe void mono_print_method_from_ip(int* ptr2mfunction);

[DllImport("__Internal")]
static extern private unsafe void* mono_domain_get ();


Implementation (including mapping unmanaged memory to "managed" struct:

static public void MethodFastPrint(Type t, string s)
{
MethodInfo mi = t.GetMethod (s, (BindingFlags)60);
if (mi == null)
return;
void* fpraw = mi.MethodHandle.GetFunctionPointer().ToPointer();
void* jitinforaw = mono_jit_info_table_find (mono_domain_get (), fpraw);
u_MonoJitInfo jitinfo = *(u_MonoJitInfo*)jitinforaw;
int size = jitinfo.code_size;
int i = 0;

byte* walk = (byte*)fpraw;

Console.WriteLine ("IP BEGIN " + mi);
while (i < size)
{
Console.WriteLine ("{0:X2}", walk[i]);
i++;
}
Console.WriteLine ("IP END " + mi);
}


proof of work (you will need to replace console write with logger warning or similar:

[attachment deleted by admin - too old]
#20
subj:


[MethodImpl(MethodImplOptions.NoInlining)]
static public void ForgeObjectType
(
object Target,
Type Newtype
)
{
MethodInfo _CII = typeof(Activator).GetMethod ("CreateInstanceInternal", (BindingFlags)60);
object vtablesource = _CII.Invoke (null, new object[]{ Newtype });
UnionHack.Cast (Target)[0] = UnionHack.Cast (vtablesource)[0];
}


union hack definition:


[StructLayout(LayoutKind.Explicit)]
public unsafe struct UnionHack
{
[FieldOffset(0)] public object arg;
[FieldOffset(0)] public int*   ret;

static private UnionHack INSTANCE = new UnionHack ();

static public int* Cast(object o)
{
INSTANCE.arg = o;
return INSTANCE.ret;
}

private void illayer()
{
DynamicMethod dm = new DynamicMethod("void",typeof(int),new Type[]{typeof(object)});
ILGenerator ilg = dm.GetILGenerator ();
ilg.Emit (OpCodes.Ldarg_0);
ilg.Emit (OpCodes.Conv_I);
ilg.Emit (OpCodes.Ret);
}
}


1) unsafe cast, string to ArrayList anyone
2) full access to private fields with native performance levels
3) memcopy for objects
4) other funny applications