Patching a .NET assembly?

40 views
Skip to first unread message

Anton Shepelev

unread,
Sep 17, 2020, 6:22:11 PM9/17/20
to
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

unread,
Sep 17, 2020, 8:16:20 PM9/17/20
to
On 9/17/2020 6:22 PM, Anton Shepelev wrote:
> 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

unread,
Sep 17, 2020, 8:31:40 PM9/17/20
to
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

unread,
Sep 18, 2020, 6:14:42 AM9/18/20
to
I wrote:

> 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

unread,
Sep 18, 2020, 8:47:39 AM9/18/20
to
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

unread,
Sep 18, 2020, 10:56:05 AM9/18/20
to
Arne Vajhoj to Anton Shepelev:

> 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.
Reply all
Reply to author
Forward
0 new messages