Can you hack this out?

I recently had to take a really deep look into how to cheat the CLR, that brought about some interesting discoveries, including the fact that it is, surprisingly, possible to do so.

Let us say that you have this code in some 3rd party assembly that you cannot modify:

internal interface IRunner
{
void Execute();
}

public sealed class AssemblyRunner : IRunner
{
void IRunner.Execute()
{
Console.WriteLine("executing");
}
}

public class CompositeRunner<T> where T : new()
{
public void Execute()
{
if(!typeof(IRunner).IsAssignableFrom(typeof(T)))
throw new InvalidOperationException("invalid type");
var runner = (IRunner)new T();
Console.WriteLine("starting");
runner.Execute();
Console.WriteLine("done");
}
}

Can you get the CompositeRunner to output:

    • starting
    • before executing
    • executing
    • after executing
    • done

The real problem was a bit harder, but this is a good start.

Print | posted on Thursday, November 19, 2009 12:00 PM

Feedback


Gravatar

# re: Can you hack this out? 11/19/2009 12:24 PM eti

Hi,

I think that
if(typeof(IRunner).IsAssignableFrom(typeof(T)))
should be
if( ! typeof(IRunner).IsAssignableFrom(typeof(T)))


Gravatar

# re: Can you hack this out? 11/19/2009 12:25 PM Pierre Murasso

Using Aspect Oriented Programming?

For instance you can write Aspects that get injected into this assembly during PostCompilation, although this is not CLR hacking.


Gravatar

# re: Can you hack this out? 11/19/2009 12:32 PM Ayende Rahien

Eti,
Yes, it should, fixed, thanks :-)

Pierre,
You can't modify the original assembly in any way.


Gravatar

# re: Can you hack this out? 11/19/2009 12:33 PM Glenn F. Henriksen

I have no idea on how you did it. You, Sir, are a machine!

Is this something that could be used for mocking unmockable classes? (Sealed, non-virtual, etc)


Gravatar

# re: Can you hack this out? 11/19/2009 12:38 PM eti

Hi again,

Well i'm sure you are thinking about something else but this code outputs the expected values:

class Test : IRunner {
public void Execute() {
Console.WriteLine("before executing");
Console.WriteLine("executing");
Console.WriteLine("after executing");
}
}

CompositeRunner c = new CompositeRunner();
c.Execute();

You probably are asking about CompositeRunner.


Gravatar

# re: Can you hack this out? 11/19/2009 12:38 PM configurator

Use reflection to find the interface that AssemblyRunner implements, and implement it yourself in your own emitted class?


Gravatar

# re: Can you hack this out? 11/19/2009 12:39 PM Van

public class MyRunner : IRunner
{
private readonly AssemblyRunner _inner = new AssemblyRunner();

public void Execute()
{
Console.WriteLine("before executing");
_inner.Execute();
Console.WriteLine("after executing");
}
}

new CompositeRunner().Execute();


Gravatar

# re: Can you hack this out? 11/19/2009 12:42 PM ralf

How about that?
private class MyRunner : IRunner
{
private readonly IRunner inner = new AssemblyRunner();


public void Execute()
{
Console.WriteLine("before executing");
this.inner.Execute();
Console.WriteLine("after executing");
}
}


[TestMethod]
public void TestMethodName()
{
var runner = new CompositeRunner();
runner.Execute();
}


Gravatar

# re: Can you hack this out? 11/19/2009 12:44 PM Van

Sorry, did not notice IRunner is internal.


Gravatar

# re: Can you hack this out? 11/19/2009 12:45 PM Igal Tabachnik

You could probably 'TypeMock' it, and use Profiler API to hook the method...?


Gravatar

# re: Can you hack this out? 11/19/2009 12:48 PM David Hanson

Ralf wont your call to inner.Execute() be in accessible as its private?

Well this could be done quite easily with dynamic dispatch in .net 4.0. Something tells me we cant use that however. :-)


Gravatar

# re: Can you hack this out? 11/19/2009 12:59 PM Ayende Rahien

Eti,
IRunner is an _internal_ interface in another assembly, you cannot inherit from it.


Gravatar

# re: Can you hack this out? 11/19/2009 12:59 PM Ayende Rahien

Configurator,
Try it :-)
I can tell you it... isn't easy


Gravatar

# re: Can you hack this out? 11/19/2009 1:00 PM Ayende Rahien

Van & Ralf,
IRunner is an internal interface in another assembly, your code won't compile


Gravatar

# re: Can you hack this out? 11/19/2009 1:01 PM Ayende Rahien

Igal,
Show me working code to make this work.
The profiling API are... possible, but they are a bigger cheat than I would consider.


Gravatar

# re: Can you hack this out? 11/19/2009 1:02 PM Ayende Rahien

David,
Try solving this using 4.0, it would be interesting to see where it trips you


Gravatar

# re: Can you hack this out? 11/19/2009 1:22 PM Chris Smith

Ignore the rules specified. Use Mono.Cecil. Rewrite the assembly.


Gravatar

# re: Can you hack this out? 11/19/2009 1:24 PM Stefan Wenig

OK, time for a hint. Did you find a way to implement an internal interface using reflection.emit? To derive from a sealed class? Make the CLR think your type implemented an interface while it did not ... quite? Something else altogether?


Gravatar

# re: Can you hack this out? 11/19/2009 1:28 PM configurator

Ah, yes, I see the problem.
Type 'Implementation' from assembly 'NewAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is attempting to implement an inaccessible interface.


Gravatar

# re: Can you hack this out? 11/19/2009 1:34 PM Hristo Deshev

The solution is to use the Remoting RealProxy class and "implement" the interface with some magic.

blogs.msdn.com/.../...linq-to-sql-datacontext.aspx


Gravatar

# re: Can you hack this out? 11/19/2009 1:37 PM Stefan Wenig

... just when I was going to say: if the solution involves in-proc remoting, then I don't want to know it ;-) bah!


Gravatar

# re: Can you hack this out? 11/19/2009 1:41 PM configurator

The problem with using C# 4's dynamic is that you can't cast it to the interface (I think)


Gravatar

# re: Can you hack this out? 11/19/2009 1:42 PM Ayende Rahien

Chris,
You can't, assume this is a framework assembly

Stefan,
I will give you a hint, remoting...

Hristo,
That is a good first step, but it won't solve this particular problem.
I am not asking you to replace a live instance, I am asking you to change the way it works when I create a _new_ instance.


Gravatar

# re: Can you hack this out? 11/19/2009 1:48 PM Dave Hanson

Is transparent proxy near the mark? :-)


Gravatar

# re: Can you hack this out? 11/19/2009 1:59 PM Ayende Rahien

Dave,
Yes & no.
Try to get a working sample, you'll see what I mean.


Gravatar

# re: Can you hack this out? 11/19/2009 2:50 PM Krzysztof Kozmic

I haven't tried solving this puzzle yet, but it seems more complicated than I thought.

Closed generic type complicates things significantly...


Gravatar

# re: Can you hack this out? 11/19/2009 2:55 PM Ayende Rahien

Krzysztof,
That is more or less the point :-)


Gravatar

# re: Can you hack this out? 11/19/2009 3:11 PM liviu

Ayende, Are you looking for a hack or do you really have one, because
the code you posted does not compile:

public sealed class AssemblyRunner : IRunner
{
private void IRunner.Execute()
{
Console.WriteLine("executing");
}
}

Compile Error 1 The modifier 'private' is not valid for this item


Gravatar

# re: Can you hack this out? 11/19/2009 3:30 PM liviu

The core of the problem is the line:

if(!typeof(IRunner).IsAssignableFrom(typeof(T)))

the call to IsAssignableFrom

Looking into Type.IsAssignableFrom code, it maybe a path to implement a TypeBuilder ...


Gravatar

# re: Can you hack this out? 11/19/2009 3:38 PM Ayende Rahien

liviu,
I have a hack, and thanks for catching that issue, fixed that.
And a type builder wouldn't quite work here.


Gravatar

# re: Can you hack this out? 11/19/2009 4:46 PM Dave Hanson

So I was thinking something similar to this approach.

stackoverflow.com/.../is-there-a-way-to-call-a-...


Gravatar

# re: Can you hack this out? 11/19/2009 5:06 PM Ayende Rahien

Dave,
You can't modify the assembly, and try it with proxies, see where it gets you


Gravatar

# re: Can you hack this out? 11/19/2009 5:16 PM Alkampfer

Is something related to ContextBoundObject?

Alk.


Gravatar

# re: Can you hack this out? 11/19/2009 5:26 PM Pixel

Why not:

public class MyCompositeRunner : CompositeRunner
{

public new void Execute()
{
// bla bla
}

}

?


Gravatar

# re: Can you hack this out? 11/19/2009 5:31 PM Ayende Rahien

Alkampfer,
That _is_ related, in some way, yes


Gravatar

# re: Can you hack this out? 11/19/2009 5:32 PM Ayende Rahien

Pixel,
That won't work, when you pass CompositeRunner to something that will call its Execute method, your method won't get called.


Gravatar

# re: Can you hack this out? 11/19/2009 5:34 PM Marc-André Bertrand

public class WrapperRunner : IRunner where T : IRunner, new()
{
public void Execute()
{
Console.WriteLine("Before running");
var runner = new T();
runner.Execute();
Console.WriteLine("After running");
}
}


var composite = new CompositeRunner>();

its a bit weird but should work



composite.Execute();


Gravatar

# re: Can you hack this out? 11/19/2009 5:36 PM Ayende Rahien

Marc,
IRunner is internal, you can't inherit it.


Gravatar

# re: Can you hack this out? 11/19/2009 5:40 PM Marc-André Bertrand

You should escape the brackets. It prevents us from posting code with generics and it could allow cross-site scripting.


Gravatar

# re: Can you hack this out? 11/19/2009 6:13 PM Al

The solution must use ContextBoundObjects, message sinks, and transparent proxies. Although, it's been a while since I've dug into those internals, I think you just need to find a way to get the CompositeRunner participating in the sink chain?

I can't picture the code, but it doesn't *feel* impossible. I don't have time to experiment right now, but it's a nice puzzle. Looking forward to your solution.


Gravatar

# re: Can you hack this out? 11/19/2009 6:17 PM Alkampfer

Actually I have no time to try a solution, but the right direction can be trying to load the sealed object in another AppDomain, since communication between AppDomains always happens with a proxy. When you create object in another Appdomain all communication happens with a remoting proxy.

The only problem is that the creation of the sealed object happens inside the CompositeRunner, that directly called

var runner = (IRunner)new T();

You probably found a way to make this code creates T object in another appDomain?

Alk.


Gravatar

# re: Can you hack this out? 11/19/2009 6:45 PM fred

I should not call the execute method directly, but have to wrap it in a proxy, or put the method in a delegate and pass the delegate into a execute method, in the execute method to add your decoration before and after running the delegate


Gravatar

# re: Can you hack this out? 11/19/2009 7:09 PM Kyle Szklenski

It seems like there should be a way of doing this by deriving from Type. I'm just not sure offhand how to implement it in such a way that it would do that. Reflecting on IsAssignableFrom doesn't really seem to help as much as I'd hoped it would (or I'm too dense to see the right way to work it based on that).


Gravatar

# re: Can you hack this out? 11/19/2009 9:18 PM Bunter

No, I can't hack this out. Enlighten us, Ayende.


Gravatar

# re: Can you hack this out? 11/20/2009 2:39 AM Paulo Köch

Something around latent typing? Can't recall I f I'll need to reference the internal interface, though.

Maybe getting down to pointer/memory level?

If all else fails, remoting, as Ayende said. I remember seeing some ORM using that technique.


Gravatar

# re: Can you hack this out? 11/20/2009 4:12 AM Ayende Rahien

Al,
Try it :-)

Alkampfer,
No second app domain is required.
And yes, there is a trick here.

Fred,
Show me the code

Kyle,
You are in the right direction, now take it to the illogical conclusion.

Paulo,
Latent typing? I can't see a solution to that here, but maybe you can educate me.
I thought about doing pointers here, but it is not needed.
Remoting would work,but _how_?


Gravatar

# re: Can you hack this out? 11/20/2009 4:13 AM Ayende Rahien

Al,
You are close, but not quite.


Gravatar

# re: Can you hack this out? 11/20/2009 9:18 AM Dennis

I saw an article the other day about hooking into the JIT and hijacking the jump table. But I cannot find the reference again :(


Gravatar

# re: Can you hack this out? 11/20/2009 9:30 AM Dennis

http://netasm.codeplex.com/
Atleast similar


Gravatar

# re: Can you hack this out? 11/20/2009 10:39 AM SeeR

I remember your tweets about AppDomain.AssemblyResolve and hacking LINQ2SQL IProvider.
The best was "how to override System.RuntimeType at runtime using Reflection.Emit "

I guess this is it :-)


Gravatar

# re: Can you hack this out? 11/20/2009 12:05 PM SeeR

Hmm. I'm guessing that now, you know also the way to mock static methoda with Rhino Mocks :-)


Gravatar

# re: Can you hack this out? 11/20/2009 1:08 PM Alkampfer

If you do not use another appDomain, probably a possibility is to inherit from Type, override the ISAssignableFrom(Type) method and return true, this fools the Runner and makes the following test pass

if(!typeof(IRunner).IsAssignableFrom(typeof(T)))
throw new InvalidOperationException("invalid type");

then maybe it is possible with reflection.emit, to create a new class, and use your custom Type as type, so when the runner call typeof(T) it gets your MyType that return true when it ask for IsAssignableFrom, and it gets fooled.

But actually you still have another problem, because the IRunner is internal interface, and even with reflection Emit you cannot create a class that implements it, so you can make this class inherits from ContextBoundObject and use the standard IMessage AOP technique to intercept calls and redirect to a real AsseemblyRunner object, and now you can inject code before and after the call :)

I wish to have some time to check this path and verify where it leads :)

Alk.


Gravatar

# re: Can you hack this out? 11/20/2009 5:32 PM Whut

I haven't done any remoting or COM, so I'm just fooling around.

I'm trying to use proxy of Type class and using it as generic argument to CompositeRunner, but I can't just cast transparent proxy to Type;)


Gravatar

# re: Can you hack this out? 11/20/2009 5:43 PM Alex Simkin

@Whut Transparent proxy is an object not a type. If you want its type, use GetType(), but I do not see what it gives you.


Gravatar

# re: Can you hack this out? 11/21/2009 3:42 AM Martinho Fernandes

So, you're not gonna tell us?


Gravatar

# Possible Use? 11/21/2009 8:27 AM anon

No clue how :)
But, can this somehow be used to provide a undo/redo facility that is transparent to the objects? Somehow catching the get/set of a property and also enhancing any property in a object with Undo() and Redo() methods?


Gravatar

# Some link of help? 11/21/2009 8:32 AM anon

Found 2 links about something like this. Sorry for polluting your comments section :)

stackoverflow.com/.../how-do-i-intercept-a-meth...

www.developerfusion.com/.../3/


Gravatar

# And this 11/21/2009 8:34 AM anon

msdn.microsoft.com/en-us/magazine/cc164165.aspx
Again, sorry for pollution, but I can't edit the comment previous.


Gravatar

# re: Can you hack this out? 11/21/2009 9:21 AM Mags

Care to post the solution?


Gravatar

# re: Can you hack this out? 11/21/2009 9:35 AM Vadi

I think, the story comes from here ..
gyrate.wordpress.com/.../context-bound-object-p...


Gravatar

# re: Can you hack this out? 11/21/2009 9:57 AM Gian Maria

I spent this morning 30 minutes thinking to a solution, it is really a thought question :).
Ayende, it is somewhat related to creating a dynamic class with reflection.Emit and changing manually the TypeToken, setting with reflection the m_tdType field of the TypeBuilder? when the compositeRunner checks if T implements IRunner uses typeof(T) that in MSIL generates a call to GetTypeFromHandle using the TypeToken of T...

Alk


Gravatar

# re: Can you hack this out? 11/21/2009 2:54 PM Whut

Using remoting, message sinks and some reflection hacks I'm able to run those lines:

var runner = (IRunner)new T();
runner.Execute();

Still I can't crack this

if(!typeof(IRunner).IsAssignableFrom(typeof(T)))

But I will find it;)


Gravatar

# re: Can you hack this out? 11/22/2009 3:44 PM olcay şeker

@ayende
will you unveil the answer???


Gravatar

# re: Can you hack this out? 11/23/2009 12:15 AM Alex Simkin

@olcay şeker

Apparently we didn't ask kindly enough.


Gravatar

# re: Can you hack this out? 11/23/2009 12:27 AM Anthony Dewhirst

Please Don't give the answer, maybe some hints so we can try to figure it out. (I might be the only fool asking for this though)


Gravatar

# re: Can you hack this out? 11/23/2009 1:14 AM liviu

I think the solution can be found by using resharper on L2S Profiler :--))


Gravatar

# re: Can you hack this out? 11/23/2009 1:53 AM David

I agree with Anthony, can we have some more hints, at work we are having fun in our lunch break on this one ;)

@ Whut, how does you code look right now?


I think to get round the IsAssignableFrom, you have to Inherit off the Type Class, override this function to return true and then use the System.Reflection.Emit to force the code to use your Type class. thing is I have yet to figure out how to do that

@ Ayende, the class type you pass into the CompositeRunner does not inherit of IRunner? its just a class that has an execute function, and you make it always return true on the IsAssignableFrom?


Gravatar

# re: Can you hack this out? 11/23/2009 3:39 AM Alex Simkin

@liviu
"resharper on L2S Profiler :--))"

Did that, understand how he solved the task at hand, still cannot solve this one.


Gravatar

# re: Can you hack this out? 11/23/2009 8:56 AM Anthony Dewhirst

David:
if you do override IsAssignableFrom you still have to get past the cast on the next line.

Ayende:
Do you need to some how push the IRunner interface that you get using reflection into the RuntimeTypeCache for the new object or am I heading in the wrong direction?


Gravatar

# re: Can you hack this out? 11/23/2009 9:45 AM Van

Anthony Dewhirst:
I think the cast can be handled with explicit operator.

I still cannot figure out how to trick the typeof(T) to return the Type that I wanted.


Gravatar

# re: Can you hack this out? 11/23/2009 1:05 PM hpower11

Ayende:
You said "The real problem was a bit harder" And by far no one has manage to solve the "easier one"

Can you please enlighten us with at list some hints. Also I am very curious about the real challenge you had.


Gravatar

# re: Can you hack this out? 11/23/2009 1:28 PM liviu

I said resharper, i ment reflector...
I think the challange is related either to EF or to L2S profiling...


Gravatar

# re: Can you hack this out? 11/24/2009 10:05 AM Arielr

Change the System.Console.WriteLine() function in mscorlib, and do with it what you want.
www.blackhat.com/.../...agedCodeRootkits-PAPER.pdf


Gravatar

# re: Can you hack this out? 11/24/2009 1:26 PM Ayende Rahien

Arielr,
That is pretty much cheating.


Gravatar

# re: Can you hack this out? 11/25/2009 10:15 PM dexon

Maybe something like this:

var irunner = typeof(AssemblyRunner).GetInterface("IRunner");
....
TypeBuilder myType = myModule.DefineType("MyRunner",
TypeAttributes.Public | TypeAttributes.Class, null, new Type[]{ irunner });
MethodBuilder exMethod =
myType.DefineMethod("Execute", MethodAttributes.Public, typeof(void), new Type[]{});
ILGenerator ilgen = exMethod.GetILGenerator();
ilgen.EmitWriteLine("before executing");
// call to AssemblyRunner.Execute
ilgen.EmitWriteLine("after executing");

Type finished = myType.CreateType();

Type[] typeArgs = {finished};
Type constructed = typeof(CompositeRunner<>).MakeGenericType(typeArgs);
MethodInfo mi = constructed.GetMethod("Execute");

mi.Invoke(Activator.CreateInstance(constructed, null, null), null);

It's allready passing through
typeof(IRunner).IsAssignableFrom(typeof(T))
but failing on
var runner = (IRunner)new T();


Gravatar

# re: Can you hack this out? 11/26/2009 9:06 PM Arielr

Oren,

Yeah, I know.
Fun, ain't it? :)


Gravatar

# re: Can you hack this out? 11/27/2009 9:39 AM Mark Whitfeld

Hmmm.... If this is possible, then I'm hoping that there are some pretty ground breaking improvements to Rhino Mocks in the near future :)

Comments have been closed on this topic.