vrijdag 13 juni 2008

Reflector + Reflexil: Verander de code van een assembly (!)

".Net Reflector" zullen de meeste .Net'ers wel kennen (.Net assemblies details bekijken, analyseren, decompilen, etc):
http://www.aisto.com/roeder/dotnet/Download.aspx?File=Reflector
Voor dit mooie programma zijn ook allerlei "add ins" beschikbaar:
http://www.codeplex.com/reflectoraddins

1 ervan is "Reflexil":
http://sebastien.lebreton.free.fr/reflexil/
Hiermee kan een assembly ook bewerkt worden! Bestaande code kan aangepast worden, of geheel vervangen worden door nieuwe code. Ik heb het zelf even getest met een Delphi.Net programma, en het werkt super.

Het is gebasseerd op Mono.Cecil, wat onderdeel is van het open source "Mono" project:
http://www.mono-project.com/Cecil

Een aantal voorbeelden hoe je een assembly kunt aanpassen:
http://www.codeproject.com/KB/msil/reflexil.aspx
http://blog.cumps.be/reverse-engineering-with-reflector-and-reflexil/

Wat wel even belangrijk is als je het zelf probeert: als je iets aangepast hebt, moet je in de tree van Reflector de assembly zelf selecteren. Dan pas kun je de wijzigingen opslaan :-).

Nu kan het een en ander natuurlijk moeilijker gemaakt worden dmv "obfuscation". Hiermee worden de originele namen vervangen door "abc", code structuur iets aangepast (geen mooie "if then else" constructies, etc):
http://blog.cumps.be/obfuscation-making-reverse-engineering-harder/

Ook kun je "Code Signing" gebruiken om het nog moeilijker te maken, maar het is en blijft vrij eenvoudig mogelijk om een assembly aan te passen:
http://blog.cumps.be/code-signing-as-reverse-engineering-protection/

Veel succes ermee! :-)

vrijdag 6 juni 2008

Snelheid + Schaalbaarheid .Net & Delphi

Als Delphi programmeur was ik nog een beetje sceptisch over .Net, vooral mbt de snelheid. Hiervoor heb ik in Delphi een klein programmaatje gemaakt, wat in 2 for loops wat strings heen en weer kopieert. Dit heb ik gemaakt in een thread, zodat ik ook makkelijk met meerdere threads kon testen. Dit programmaatje heb ik met Delphi 2006 zowel native als met Delphi.Net gecompileerd.

Test resultaten: Win32 vs .Net
Resultaten op een Intel Core2 Duo (dual core dus), MS .Net 2.0:
Delphi.Win32:
1 thread = 3s
2 threads = 6s + 6s

Delphi.Net:
1 thread = 2s
2 threads = 4s + 4s

.Net is dus sneller dan native! Bovendien schalen ze allebei niet goed, want beide keren bleef de CPU steken op zo'n 50% (dus geen goed gebruik van dual core).

Test resultaten: TopMM
Standaard gebruikt Delphi 200X de FastMM memory manager. Ik had al eens eerder een andere gezien, die wel goed zou moeten schalen: TopMM (http://topsoftwaresite.nl/Downloads/TopMemoryManager22.zip).

Resultaten:
Delphi.Win32, TopMM:
1 thread = 6s
2 threads = 6s + 6s

Tja, nu schaalt hij heel mooi (beide cores op 100%) maar de performance is wel slechter...

FastMM fix
Benieuwd waarom TopMM wel goed schaalt en FastMM niet, zat ik in de code te duiken. FastMM gebruikt een lock voor de memory pool, terwijl TopMM per thread een aparte pool heeft (geen locks dus nodig). Als eerste heb ik de lock eruit gehaald: nu kwam de snelheid ook op 2s! Maar goed, voor meerdere threads is die lock wel nodig. Toen heb ik even snel een hack gemaakt voor FastMM door oa een "threadvar" te gebruiken, zodat elke thread zijn eigen pool krijgt. Nu hebben beide threads 2s en 100% CPU, oftewel: Delphi.Win32 is even snel als .Net, maar bovenal: het schaalt beter!

Multi cores: nadeel voor .Net
Het grote nadeel nu aan .Net is dat je dit niet makkelijk zelf kunt fixen, wat in Delphi.Win32 wel makkelijk kan. Vooral met het oog op steeds meer cores per CPU is dit een slecht punt voor MS .Net.

MS CLR shared code
Benieuw hoe in .Net oa de string allocatie is, kwam ik via het volgende artikel:
http://selvasamuel.wordpress.com/2008/03/14/boxingunboxing-in-net/
op het idee om in de CLR code van Microsoft te duiken. Via het "Shared source" initiatief van MS kan iedereen een gedeelte van oa de CLR downloaden (maar niet aanpassen etc!):

Shared Source Common Language Infrastructure 2.0 Release
http://www.microsoft.com/downloads/details.aspx?FamilyId=8C09FD61-3F26-4555-AE17-3121B4F51D4D&displaylang=en

Als eerste heb ik in de ".Net Reflector" (http://www.aisto.com/roeder/dotnet/Download.aspx?File=Reflector)
de code opgezocht van mijn thread. Aan de hand hiervan naar de functie gesprongen (door te klikken in de code) voor het kopiëren van strings: System.String.Copy. Deze maakt oa gebruik van "FastAllocateString":
Deze functie was als volgt gedeclareerd (in C#):
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string FastAllocateString(int length);

"InterCall" betekent dat het in de .Net CLR zelf geïmplementeerd is. Aan de hand van de shared code van MS van de CLR heb ik gezocht op "FastAllocateString". Deze functie wordt weer doorgelinkt van "ECall::FastAllocateString" naar "JIT_TrialAlloc::GenAllocString(flags)".
Hierin wordt net als FastMM een lock gebruikt. Helaas is deze lock niet makkelijk aan te fixen, oa omdat de Shared Source CLR niet compleet is.