Har du någonsin känt en önskan att plocka isär en mekanism för att ta reda på hur den fungerar? Vem har inte det? Denna önskan är den ledande kraften i reverse engineering. Denna färdighet är användbar för att analysera produktsäkerhet, ta reda på syftet med en misstänkt .exe-fil utan att köra den, återskapa förlorad dokumentation, utveckla en ny lösning baserad på äldre programvara etc.

I den här artikeln diskuterar vi kunskapsbasen som behövs för att utföra reverse engineering, grundprinciper för reverse engineering av en Windows-programvara, disassemblers och verktyg. Vi ger också ett steg-för-steg-exempel på reverse engineering av en applikation.

Författat av

Sergii Bratus,

utvecklingssamordnare,

nätverkssäkerhetsteamet

och

Anton Kukoba,

Säkerhetsforskningsledare

Innehåll

Vad är mjukvaruomvändning?

Vad behöver vi för reverse engineering?

Teoretisk kunskap. Process för omvänd programvaruutveckling

Användbara verktyg för omvänd programvaruutveckling av Windows-programvara

Disassemblers

Windows Sysinternals

Verktyg för nätverksövervakning

Debuggers

Real-exempel på omvänd programvara i verkligheten

Hur man omvänd konstruerar en drivrutin

Slutsats

Vad är omvänd programvara?

Reverse engineering är processen för att avslöja principerna bakom en maskin- eller programvara, till exempel dess arkitektur och interna struktur. Frågan som driver reverse engineering är Hur fungerar det?

Oppenbarligen blir hela processen mycket enklare om du har dokumentation. Men det händer ofta att det inte finns någon dokumentation och du måste hitta ett annat sätt att lära dig hur en programvara fungerar.

När kan du behöva göra reverse engineering av en programvara och hur kan det hjälpa dig att göra det?

Det finns många användningsområden för reverse engineering inom datavetenskap, bland annat:

  • Utforskning av nätverkskommunikationsprotokoll
  • Finnande av algoritmer som används i skadlig kod, t.ex. datorvirus, trojaner, utpressningstrojaner osv.
  • Utforska det filformat som används för att lagra någon typ av information, till exempel e-postdatabaser och diskbilder
  • Kontrollera den egna programvarans förmåga att motstå omvänd ingenjörskonst
  • Förbättra programvarans kompatibilitet med plattformar och programvara från tredje part
  • Använda odokumenterade plattformsfunktioner

Legaliteten av omvänd ingenjörskonst beror på syftet och hur programvaran kommer att användas. Alla de syften som nämns ovan är helt legitima, förutsatt att du har fått en kopia av programvaran på laglig väg. Men om du till exempel har för avsikt att reverse engineera en viss funktion i ett stängt program och sedan implementera den i ett annat program kommer du förmodligen att få problem.

Rörande den juridiska dokumentationen är reverse engineering ofta förbjuden i licensavtal för slutanvändare (EULAs). Men den amerikanska Digital Millennium Copyright Act anger att det är lagligt att återge en programvara om det görs för att förbättra kompatibiliteten med andra produkter.

De juridiska kraven varierar från land till land, så ta dig tid att undersöka dem innan du börjar.

Nu ska vi se hur man återger en programvara.

Vad behöver vi för reverse engineering?

För att börja reverse engineering av mjukvara behöver du:

  1. kunskap inom det område där du vill tillämpa reverse engineering
  2. verktyg som gör det möjligt för dig att tillämpa din kunskap medan du försöker demontera mjukvara.

Låtsas vi betrakta ett generiskt exempel som inte är kopplat till mjukvara. Låt oss säga att du har en klocka och vill ta reda på om den är mekanisk, kvarts eller automatisk.

Att ha kunskap inom området innebär att du bör veta att det finns tre typer av klockor. Dessutom bör du veta att om det finns ett batteri så finns det inuti klockan och du kan se det om du öppnar den. Du bör också ha grundläggande kunskaper om en klockas inre struktur, hur batteriet ser ut och vilka verktyg du behöver för att öppna en klocklåda. Att ha verktygen för att tillämpa dina kunskaper innebär att du måste ha en skruvmejsel eller ett annat särskilt verktyg som ger dig möjlighet att öppna klockan.

Såsom reverse engineering av en klocka kräver särskilda färdigheter och verktyg, kräver reverse engineering av mjukvara sina egna fältspecifika kunskaper och verktyg.

Teoretisk kunskap. Software Reverse Engineering Process

För olika uppgifter inom software reverse engineering behöver du olika typer av kunskap. Naturligtvis finns det gemensamma kunskaper som hjälper dig i de flesta reverse engineering-uppdrag: kunskap om vanliga applikationsstrukturer, programmeringsspråk, kompilatorer och så vidare. Men utan särskilda teoretiska kunskaper kan du inte lösa specifika reverse engineering-uppdrag.

Om du…

Du behöver kunskaper om…

genomföra alla nätverkstillämpningar

principer för kommunikation mellan processer, nätverksstruktur, anslutningar, nätverkspaket osv.

omvända kryptografiska algoritmer

kryptografi och de mest populära algoritmerna som används inom området

forskningsfil. strukturer

grundläggande filkoncept och hur olika system eller komponenter arbetar med filer

Speciella tekniker kan spara mycket tid vid reversering av speciella typer av programvara. När det gäller filinteraktioner kan det hjälpa dig att göra ett test som skriver unika typvärden till en fil samtidigt som du loggar offsets och datastorlek till den faktiska lagringsfilen, vilket kan hjälpa dig att hitta vanliga mönster i offsets. Detta kommer att ge dig en antydan om de interna strukturerna i dessa filer.

När programvaruutvecklare påbörjar en reverse engineering-process använder de i allmänhet en disassembler för att hitta algoritmer och programlogik på plats. Det finns många olika format för körbara filer, kompilatorer (som ger olika utdata) och operativsystem. Denna mångfald av tekniker utesluter användningen av en enda teknik för att återskapa alla typer av programvara.

För att förstå den dekompilerade koden behöver du en viss kunskap om assemblerspråket, konventioner för anrop av funktioner, stackstruktur, begreppet stackramar etc.

Kunskap om assemblerutgången för olika kodprover kan hjälpa dig att avslöja den ursprungliga funktionaliteten. Låt oss betrakta några exempel för Windows x86-plattformen.

Säg att vi har följande kod:

int count = 0;for (int i = 0; i < 10; ++i){count++;}std::cout << count;

Om vi kompilerar den här koden till en körbar fil får vi se detta i disassembler:

004113DE loc_4113DE:004113DE mov eax, 004113E1 add eax, 1004113E4 mov , eax004113E7 loc_4113E7:004113E7 cmp , 0Ah004113EB jge short loc_4113F8004113ED mov eax, 004113F0 add eax, 1004113F3 mov , eax004113F6 jmp short loc_4113DE004113F8 loc_4113F8:004113F8 mov ecx, ds:004113FE push eax00411400 call ds:<<(int)00411404 xor eax, eax00411406 retn 

Som vi kan se har den vanliga cykeln förvandlats till assemblerkod med jämförelser och hopp. Lägg märke till att assemblerkoden inte använder den vanliga assemblerloopen med räknaren i ecx-registret. Dessutom hänvisas lokala variabler här till som och följaktligen.

Låt oss se vad som händer om vi kompilerar den här koden med hjälp av release build:

00401000 main proc near00401000 mov ecx, ds:00401006 push 0Ah00401008 call ds:<<(int)0040100E xor eax, eax00401010 retn00401010 main endp

Det här kodstycket ser inte alls ut som det föregående. Detta beror på hur koden optimerades. Tekniskt sett togs slingan bort, eftersom den inte gör något värdefullt annat än att öka count-variabeln till 10. Så optimeraren bestämde sig för att bara behålla slutvärdet av count-variabeln och placera värdet direkt som ett argument för count-utgångsoperatorn.

De kompilatorer som vi använder nuförtiden är mycket bra på att optimera kod. Det är därför som det vid reverse engineering är bättre att förstå idén bakom koden (principerna för koden) än att försöka få fram själva originalkoden. Om du förstår idén bakom koden kan du bara skriva en egen prototyp som passar den ursprungliga uppgiften.

Det kommer att vara mycket användbart att veta vilken assemblerkod du får om du kompilerar olika operatörer, strukturer och andra språkkonstruktioner. Att förstå resulterande assemblerkod är ett bra sätt att starta C++ reverse engineering-processen, men vi kommer inte att gå in på tekniska detaljer om det här.

Användbara verktyg för reverse engineering av Windows-programvara

Vi har redan beskrivit flera reverse engineering-verktyg, inklusive ProcessMonitor och ProcessExplorer, i vår forskning om applikationsarkitektur. Dessa verktyg är helt oumbärliga för reverse engineering.

I det här avsnittet går vi igenom de mest populära disassemblerna och ytterligare några verktyg som vi använder för våra reverse engineering-projekt.

Du kan få mer information och användningsexempel i vår artikel om de bästa verktygen för reverse engineering av mjukvara.

Disassembler

En disassembler är ett program som översätter en körbar fil till assembleringsspråk. Det mest populära är IDA Pro

IDA Pro

IDA Pro

IDA Pro är ett bekvämt och kraftfullt verktyg för disassemblering. Det har ett stort antal instrument som gör att du snabbt kan plocka isär en programvara. Det kan visa funktionskallsträdet, analysera import och export av den körbara filen och visa information om dem. Den kan till och med visa koden i C. Dessutom har den stöd för flera CPU-arkitekturer, så det är möjligt att använda IDA Pro för att reverse engineera kod för ARM, AVR, M68k och många andra arkitekturer.

Radare

Radare

Disassembleraren Radare är ett alternativ till IDA. Den har i princip alla IDA-funktioner utan att vara lika robust och stabil. Men den är gratis och har öppen källkod. Radare i sig är ett konsolverktyg, men det har en Cutter-frontend, vilket gör det till ett verkligt alternativ till IDA.

Windows Sysinternals

Windows Sysinternals verktyg används i allmänhet för hantering, diagnostik, felsökning och övervakning av Microsoft Windows-miljön. Men de är också lämpliga för reverse engineering av Windows-programvara.

TCPView är en nätverkssniffer som visar all information om TCP/UDP-paket från alla processer. Det här verktyget är användbart för att vända nätverksprotokoll.

PortMon är en fysisk systemportövervakare. Den övervakar seriella och parallella portar och all trafik som går genom dem.

WinObj visar alla globala objekt i systemet i en hierarkisk struktur. Det här verktyget kan vara användbart när man reverserar ett program som arbetar med synkroniseringsprimitiver som mutexes och semaforer och även när man reverserar drivrutiner i kärnläge.

Nätverksövervakningsverktyg

Wireshark

Wireshark

Wireshark är en av de kraftfullaste nätverkssniffers. Den gör det inte bara möjligt att fånga nätverkstrafik utan innehåller också parsers för olika nätverksprotokoll, från riktigt låg nivå som Ethernet, TCP och IP till tillämpningsspecifika protokoll som WebSockets och XMPP.

Fiddler

Fiddler

Fiddler är en webbproxy som registrerar trafiken från webbläsare och gör det möjligt att analysera HTTP/HTTPS-förfrågningar. Till skillnad från Wireshark visar den HTTP-sessioner i stället för separata nätverkspaket. Med Fiddler kan du också analysera komprimerade data som skickas via HTTP och analysera JSON- och XML-data när du övervakar SOAP-, REST- och AJAX-begäranden.

API Monitor

API Monitor

API Monitor är ett användbart verktyg för att upptäcka vilka API:er som anropas av ett program och vilket beteende programmet förväntar sig av dessa API:er. Verktyget har en kraftfull databas och låter dig se anrop till ett stort antal API-funktioner av inte bara kernel32 och ntdll utan även COM, managed environment och andra. Dessutom erbjuder API Monitor praktiska filtreringsmekanismer.

Debugger

En debugger är ovärderlig för alla utvecklare för att se vad ett program gör just nu. Du får samma nytta av felsökning när du backar program som du får av felsökning av liveprogram.

De mest populära felsökarna är OllyDbg, WinDbg och Windbg Preview.

OllyDbg

OllyDBG

OllyDbg (och dess efterföljare x64dbg) är förmodligen den bästa felsökaren när det gäller omvänd programvara. Den utvecklades specifikt för behoven av omvänd granskning och har alla de verktyg som behövs för detta ändamål:

  • En inbyggd disassembler med möjlighet att analysera och identifiera viktiga datastrukturer
  • En funktion för import- och exportanalys
  • En inbyggd motor för sammansättning och patching

Förmågan att parsa API-funktioner och deras parametrar gör det enkelt att omvända interaktioner med ett system. Stackvyn ger mycket information om anropsstapeln. En viktigare fördel är att du kan använda OllyDbg med felsökningsskyddade program, när vanliga felsökare helt enkelt inte kan göra något.

WinDbg

Windbg

Trots det enkla gränssnittet har WinDbg kraftfulla verktyg för felsökning. Det har en inbyggd disassembler, olika kommandon som gör att du kan få reda på nästan allt om den process/det system du felsöker och möjligheten att göra felsökning i kernel-läge, vilket förmodligen är den mest värdefulla funktionen. Det är en stor fördel för att vända drivrutiner, särskilt drivrutiner i kernel-mode.

Windbg Preview

Windbg Preview

Windbg Preview är en ny version av Windbg som utvecklats av Microsoft. Den distribueras endast via Windows Store. Den har alla funktioner från den klassiska Windbg tillsammans med ett nytt användargränssnitt och flera nya funktioner. En av dessa nya funktioner är Time Travel Debugging, som gör att du kan spela in en viss period av programutförandet och sedan spela upp det så många gånger som du behöver. På så sätt kan du exekvera de intressanta delarna av koden stegvis, utan att vara rädd för att köra någon kod av misstag och förlora kontexten eller alla data.

Läs också:
9 bästa verktygen för reverse engineering 2018

Exempel på reell reverse engineering av mjukvara

Nu ska vi se ett exempel på hur man reverse engineering av en mjukvara. Låt oss föreställa oss att du har en misstänkt körbar fil. Du måste ta reda på vad det här programmet gör och om det är säkert för användarna.

Med tanke på scenariot är det en bra idé att inte köra den här körbara filen på din arbetsdator utan istället använda en virtuell maskin. Låt oss starta programmet i vår virtuella maskin.

Processen skapar en tjänst

Som vi kan se skapar filen en Windows-tjänst som heter TestDriver. Den har typen kernel, så vi vet att det är en drivrutin. Men varifrån tar den drivrutinsfilen för att kunna köras? Vi kan använda ProcessMonitor från Sysinternals Suite för att ta reda på det. När vi öppnar ProcessMonitor kan vi ställa in filter för att visa oss endast filaktiviteten från den process vi är intresserade av. Dess aktivitetslogg ser ut så här:

FileMon information

Drivrutinsfilen skapas av den process som vi vänder, och denna process lägger filen i användarens temp-katalog. Det finns ingen anledning att leta efter filen i temp-mappen eftersom vi ser att processen raderar den direkt efter användning. Så vad gör processen med den här filen? Om den packar upp filen kan vi försöka hitta den i processens resurssektion, eftersom detta är en vanlig plats att lagra sådana data på. Låt oss titta där. Vi använder ett annat verktyg – Resource Hacker – för att undersöka resurserna. Låt oss köra det:

Undersök resurser med Resource Hacker

Bingo! Som vi kan se av innehållet i den funna resursen är detta förmodligen den körbara filen för Windows, eftersom den börjar med en MZ-signatur och har strängen ”Det här programmet kan inte köras i DOS-läge”. Låt oss kontrollera om det är vår drivrutinsfil. För det ändamålet extraherar vi resursen med Resource Hacker och öppnar den i disassembler.

Disassembler-skärm

Som vi vet är DriverEntry ingångspunkten för drivrutiner i kernel-läge i Windows-system. Vi kan fortsätta vår forskning, eftersom det ser ut som om vi har hittat rätt drivrutin.

Hur man reverse engineer en drivrutin

För att börja reverse engineering av drivrutinen undersöker vi funktioner som anropas från DriverEntry en efter en. Om vi går till sub_14005 hittar vi inget intressant, så vi fortsätter med sub_110F0 och hittar den här koden:

Kodstycke 1

Kodstycke 2

Kodstycke 3

Kodstycke 4

En del rader är utelämnade här för enkelhetens skull.

I den första listningen skapas en unicode-sträng som pekar på sökvägen C:\hello.txt. Därefter fylls strukturen OBJECT_ATTRIBUTES med vanliga värden; vi vet att denna struktur ofta behövs när man anropar funktioner som ZwCreateFile.

I den andra listningen ser vi att ZwCreateFile verkligen anropas, vilket gör att vi är ganska säkra på att drivrutinen skapar filen – och vi vet var filen finns efter att den har skapats.

I den tredje och fjärde listningen kan vi se att drivrutinen tar unicode-strängen och skriver den till bufferten (detta sker i funktionen sub_11150), och att bufferten kommer att skrivas till filen med hjälp av funktionen ZwWriteFile. I slutet stänger drivrutinen filen med hjälp av ZwClose API:et.

Låt oss sammanfatta. Vi fick reda på att det ursprungliga programmet extraherar drivrutinsfilen från sina resurser, lägger den i den aktuella användarens temp-mapp, skapar Windows-tjänsten för den här drivrutinen och kör den. Därefter stoppar programmet och raderar tjänsten och den ursprungliga drivrutinsfilen från temp-katalogen. Av detta beteende och av analysen av demonteringen framgår det att drivrutinen inte gör något annat än att skapa en fil på C-enheten med namnet hello.txt och skriva strängen ”Hello from driver”.

Nu måste vi kontrollera om vi har rätt. Låt oss köra programmet och kontrollera C-enheten:

Programskärm

Vackert! Vi har bakåtkompilerat det här enkla programmet och nu vet vi att det är säkert att använda.

Vi kunde ha uppnått det här resultatet på många olika sätt – genom att använda felsökning eller API Mon, skriva tester osv. Du kan hitta dina egna sätt att reverse engineer programvara som fungerar för dig.

Slutsats

Windows software reverse engineering kräver en gedigen utbildningsbakgrund och programmeringserfarenhet. För att kunna utföra reverse engineering måste du kombinera färdigheter i demontering, nätverksövervakning, felsökning, API-integration, flera programspråk, kompilatorer osv. Du måste också vara mycket försiktig när du reverserar programvara för att inte bryta mot upphovsrättslagar eller skada ditt system.

På Apriorit har vi ett erfaret team av reverse engineers. Om du vill använda dina kunskaper om reverse engineering i ditt projekt, är du välkommen att kontakta oss!

Lämna ett svar

Din e-postadress kommer inte publiceras.