Discussion:
Patching a .NET assembly?
(too old to reply)
Anton Shepelev
2020-09-17 22:22:02 UTC
Permalink
Hello, all

I have an ADO.NET provider that performs some very slow and
redundant query processing. I can improve its performance in
my case by a factor of seven if I make it avoid the
stripping of comments form SQL code. At source level, it
means commenting a single invocation, but the assembly is
huge and compicated, and not easily decompiled. Is there a
way to "patch" the hacker way, wihout decompilation and re-
compilation, and replace the StripComments() comments with a
dummy implementation that does nothing and save huge amounts
of CPU time?

Funny that it should be the bottleneck in my data-migration
program, but I believe the profiler.
--
() ascii ribbon campaign -- against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
Arne Vajhøj
2020-09-18 00:16:07 UTC
Permalink
Post by Anton Shepelev
I have an ADO.NET provider that performs some very slow and
redundant query processing. I can improve its performance in
my case by a factor of seven if I make it avoid the
stripping of comments form SQL code. At source level, it
means commenting a single invocation, but the assembly is
huge and compicated, and not easily decompiled. Is there a
way to "patch" the hacker way, wihout decompilation and re-
compilation, and replace the StripComments() comments with a
dummy implementation that does nothing and save huge amounts
of CPU time?
Funny that it should be the bottleneck in my data-migration
program, but I believe the profiler.
Decompile, edit and recompile may be the best supported
option.

If you want to hack it, then you use an AOP static weaver. If
you can find one that is. You should be able to take out the
call with a pointcut to that call and an around advice that
do not make the call.

Arne
Arne Vajhøj
2020-09-18 00:31:27 UTC
Permalink
Post by Arne Vajhøj
Post by Anton Shepelev
I have an ADO.NET provider that performs some very slow and
redundant query processing. I can improve its performance in
my case by a factor of seven if I make it avoid the
stripping of comments form SQL code. At source level, it
means commenting a single invocation, but the assembly is
huge and compicated, and not easily decompiled. Is there a
way to "patch" the hacker way, wihout decompilation and re-
compilation, and replace the StripComments() comments with a
dummy implementation that does nothing and save huge amounts
of CPU time?
Funny that it should be the bottleneck in my data-migration
program, but I believe the profiler.
Decompile, edit and recompile may be the best supported
option.
If you want to hack it, then you use an AOP static weaver. If
you can find one that is. You should be able to take out the
call with a pointcut to that call and an around advice that
do not make the call.
I have a toy AOP static weaver: YAAOPF.

It does not support around advice, but before
advice can force the call to be skipped, which
is just as good.

It apparently does not work for private methods
(I guess I could fix that).

Demo:

C:\Work\dnaop>type SomeLib.cs
using System;

namespace SomeLib
{
public class SomeClass
{
public void X()
{
Console.WriteLine("X");
}
public void M1()
{
Console.WriteLine("M1");
}
public void M2()
{
Console.WriteLine("M2 before");
X();
Console.WriteLine("M2 after");
}
public void M3()
{
Console.WriteLine("M3");
}
}
}


C:\Work\dnaop>csc /t:library SomeLib.cs
Microsoft (R) Visual C# Compiler version 3.5.0-beta4-20153-05 (20b9af91)
Copyright (C) Microsoft Corporation. All rights reserved.


C:\Work\dnaop>type Program.cs
using System;

using SomeLib;

namespace MyApp
{
public class Program
{
public static void Main(string[] args)
{
SomeClass o = new SomeClass();
o.M1();
o.M2();
o.M3();
}
}
}


C:\Work\dnaop>csc /r:SomeLib.dll Program.cs
Microsoft (R) Visual C# Compiler version 3.5.0-beta4-20153-05 (20b9af91)
Copyright (C) Microsoft Corporation. All rights reserved.


C:\Work\dnaop>Program
M1
M2 before
X
M2 after
M3

C:\Work\dnaop>type Patch.cs
using System;

using Vajhoej.StaticWeaver;

namespace Hack
{
[Aspect]
public class Patch
{
[Pointcut(Signature="* SomeLib.SomeClass::X(*)")]
public static void MethodToPatch() { }
[BeforeCallAdvice(Pointcut="MethodToPatch")]
public static void SkipX(MethodJoinpoint mjp)
{
Console.WriteLine("Let us skip the call to X");
mjp.SkipCall = true;
}
}
}

C:\Work\dnaop>csc /r:StaticWeaver.dll /t:library Patch.cs
Microsoft (R) Visual C# Compiler version 3.5.0-beta4-20153-05 (20b9af91)
Copyright (C) Microsoft Corporation. All rights reserved.


C:\Work\dnaop>call yaaopf1 SomeLib.dll Patch.dll Glue.dll

C:\Work\dnaop>Program
M1
M2 before
Let us skip the call to X
M2 after
M3


Arne
Anton Shepelev
2020-09-18 10:14:33 UTC
Permalink
Post by Anton Shepelev
I have an ADO.NET provider that performs some very slow
and redundant query processing. I can improve its
performance in my case by a factor of seven if I make it
avoid the stripping of comments form SQL code. At source
level, it means commenting a single invocation, but the
assembly is huge and compicated, and not easily
decompiled. Is there a way to "patch" the hacker way,
wihout decompilation and re- compilation, and replace the
StripComments() comments with a dummy implementation that
does nothing and save huge amounts of CPU time?
Decompilation with ILSpy proved very difficult. Failing to
compile the project generated by ILSpy, I used the NetDasm
disassembly-patcher (the fist that I found):

https://www.codeproject.com/Articles/19016/NetDasm-A-tool-to-disassemble-and-patch-NET-assemb

to replace the first instruction in the comment-removal
function with `ret'. It seems to have helped, but not
knowing IL, I am not sure I have not broken anything. If the
parameters are passed on the stack, ought I not to pop them
at least? I think I will find that out by looking at the IL
of an empty function with the same prototype...

Nevertheless, the modified driver works as expected, but I
have failed to strong-sign it. It tried to re-sign it by
`sn.exe -R', but it complained that the public key did not
match the signature. Signing an assembly from scratch using
the linter `al' requires a code module (.netmodule) file,
which I do not have. I am stuck.
--
() ascii ribbon campaign - against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
Arne Vajhøj
2020-09-18 12:47:22 UTC
Permalink
Post by Anton Shepelev
Post by Anton Shepelev
I have an ADO.NET provider that performs some very slow
and redundant query processing. I can improve its
performance in my case by a factor of seven if I make it
avoid the stripping of comments form SQL code. At source
level, it means commenting a single invocation, but the
assembly is huge and compicated, and not easily
decompiled. Is there a way to "patch" the hacker way,
wihout decompilation and re- compilation, and replace the
StripComments() comments with a dummy implementation that
does nothing and save huge amounts of CPU time?
Decompilation with ILSpy proved very difficult. Failing to
compile the project generated by ILSpy, I used the NetDasm
https://www.codeproject.com/Articles/19016/NetDasm-A-tool-to-disassemble-and-patch-NET-assemb
to replace the first instruction in the comment-removal
function with `ret'. It seems to have helped, but not
knowing IL, I am not sure I have not broken anything. If the
parameters are passed on the stack, ought I not to pop them
at least? I think I will find that out by looking at the IL
of an empty function with the same prototype...
Nevertheless, the modified driver works as expected, but I
have failed to strong-sign it. It tried to re-sign it by
`sn.exe -R', but it complained that the public key did not
match the signature. Signing an assembly from scratch using
the linter `al' requires a code module (.netmodule) file,
which I do not have. I am stuck.
You should be able to sign it with your own signature. You
may need to change the key file ref in the code.

You can obviously not sign it with the original signature.

Arne
Anton Shepelev
2020-09-18 14:55:55 UTC
Permalink
Post by Arne Vajhøj
You should be able to sign it with your own signature. You
may need to change the key file ref in the code.
I have done the following:

1. Remove the existing signature with snremove.exe:
http://www.nirsoft.net/dot_net_tools/strong_name_remove.html
snremove.exe -r AdoNetProvider.dll

2. Generate a new key with the standard tool sn.exe:
sn.exe -k key

But I do not understand how to sign an existing .NET
assembly. The official documentation:

How to: Sign an assembly with a strong name:
https://tinyurl.com/y62ck2ty

does not seem to list a method of signing an existing
assembly. I have tried disassembling and assembling with
the key:

ildasm.exe AdoNetProvider.dll /out:res.il
ilasm.exe res.il /dll /key:key /out:AdoNetProviderFixed.dll

but the assembler fails with several errors:

Duplicate field declaration: '?'

The assembly does not survive the round trip to IL and back.
--
() ascii ribbon campaign - against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
Continue reading on narkive:
Loading...