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?
- Vad behöver vi för reverse engineering?
- Teoretisk kunskap. Software Reverse Engineering Process
- Användbara verktyg för reverse engineering av Windows-programvara
- Disassembler
- Windows Sysinternals
- Nätverksövervakningsverktyg
- Debugger
- Exempel på reell reverse engineering av mjukvara
- Hur man reverse engineer 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:
- kunskap inom det område där du vill tillämpa reverse engineering
- 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:
Om vi kompilerar den här koden till en körbar fil får vi se detta i disassembler:
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:
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!