dinsdag 23 september 2008

Dll Import Table van executable aanpassen

In mijn vorige blogpost over de TC hack, had ik beloofd uit te leggen hoe je de hack (dll) vast in kunt bouwen, zodat het elke keer direct bij het starten van het programma actief wordt.

Dit is onder andere mogelijke door de "DLL Import Table" van de executable aan te passen. Deze table bevat namelijk de statisch gelinkte dlls en hun procedures (dus niet wat het programma zelf runtime dynamisch kan laden!). Deze tabel wordt door Windows in gelezen en alle dll's worden automatisch geladen. Door nu deze tabel aan te passen, kun je dus je eigen dll laden!

Na wat zoek en prutswerk kwam ik de volgende (werkende) tool tegen:
"Explorer Suite" (http://www.ntcore.com/exsuite.php ).
Een van de onderdelen van deze suite is de "CFF Explorer". Dit is een resource explorer, waarmee allerlei "resources" van een exe/dll bekeken en aangepast kan worden (icons, resourcestrings, etc). Een van de dingen die aangepast kan worden is de Import Table.

Hiermee heb ik met succes de "TCMain.exe" (exe van TC) aangepast, zodat het altijd mijn extra dll laadt. Bij het laden van de dll wordt direct de hook toegepast (zie vorige post).
Een simpel stappenplan:

  1. Bestand laden (TCMain.exe in dit geval)
  2. "Import Adder" selecteren
  3. Add knop en dll selecteren (TCHook.dll in dit geval)
  4. Een willekeurige functie van de dll selecteren (deze wordt toch niet aangeroepen, maar je hebt nu eenmaal 1 nodig)
    Vervolgens op "Import by Name" knop drukken
  5. Import table opnieuw bouwen
  6. En de aangepaste exe opslaan

Dat was alles!

maandag 1 september 2008

Team Coherence hack -> 10x sneller!

Op mijn huidige detacheringsplek gebruiken ze "Team Coherence" (http://www.teamcoherence.com) voor versie beheer en bug/issue tracking. Ze gebruiken dit pakket heel strict: bijvoorbeeld elke check-in moet een tracker melding hebben, een tracker heeft aantal stadia (waaronder controle door de aanvrager of indiener), versie labels, promotion levels, etc.

Op zich zijn ze tevreden over dit pakket. Het pakket heeft wel een poos een dip gehad, waarbij het niet meer onderhouden werd door de makers, maar nu wordt weer af en toe een update uitgebracht. Het grootste probleem echter wat ze hadden, was dat het pakket steeds trager werd: opstarten duurde maar liefst anderhalve minuut! Ook wisselen van views etc duurde dik een minuut.

Toen ik even niets te doen had (wachten op specs etc), heb ik even gekeken met Proces Explorer naar wat de oorzaak kon zijn. Nu blijkt dat hij veel geheugen acties doet (van 10Mb oplopend naar 65Mb en dan weer 36Mb), en veel kernel/system (rood) tijd gebruikt. Zie onder (er is trouwens getest op een HT systeem, vandaar niet meer dan 50% CPU):


1 thead (main thread) is druk bezig. Zie onder:



Als we nu de stack trace opvragen (en dit een paar keer doen), dan blijkt dat hij steeds bezig is met "GlobalRealloc".
Zie onder:


Ik weet dat het een Delphi 5 programma is, en Delphi gebruikt maar op 1 plek Global memory: TMemorystream.SetSize. Waarschijnlijk wordt steeds een paar bytes geschreven (stream.Write(s) oid), zodat het geheugenblok steeds met paar bytes vergroot moet worden. Nu doet Windows dit niet efficiënt: zelfs als na het huidige blok genoeg ruimte is, hij kopieert altijd naar een nieuw blok geheugen. En dit kost tijd, vooral als het heel vaak gebeurt. Vandaar de "rode" systeem CPU tijd.

Nu heb ik al wat ervaring met hacken gekregen met mijn profiler (http://code.google.com/p/asmprofiler) en detouring, dus ik heb ik een kleine dll geschreven die de GlobalRealloc overruled, en 1Mb extra reserveert. Als de nieuwe ruimte nog past in het oude, dan doet het niets, anders vraagt het door middel van de originele GlobalRealloc nieuw geheugen aan (met weer 1Mb extra):

function HookedGlobalReAlloc(hMem: HGLOBAL; dwBytes: SIZE_T; uFlags: UINT): HGLOBAL; stdcall;
begin
if GlobalSize(hMem) < id="pcex4"> Result := trampoline_GlobalReAlloc(hMem, dwBytes + (1000*1024), uFlags) //reserve 1Mb extra mem
else
Result := hMem; //do not realloc if needed size fits in current size, GlobalRealloc ALWAYS does a resize, even when it is not needed!
end;

Door middel van dll injection heb ik dit in Team Coherence geladen (zowel server als client), en nu duurt het opstarten maar 10 seconden! Dus 10x sneller!

P.S. ik heb dit ook aan de makers gestuurd, nog geen reactie tot nu toe...
P.S.2 de volgende keer zal ik demonstreren hoe ik de executable aangepast heb, zodat altijd mijn extra dll geladen wordt (dll injection dus niet meer nodig elke keer).