Pitanje:
Kako mogu dodati funkcionalnost postojećem binarnom izvršnom programu?
asheeshr
2013-03-23 18:55:13 UTC
view on stackexchange narkive permalink

Želim dodati neke funkcionalnosti postojećoj binarnoj datoteci. Binarna datoteka kreirana je pomoću gcc .

  • Trebam li prvo dekompilirati binarni sustav, iako dovoljno razumijem funkcioniranje programa?
  • Kako da dodam potreban kod?
  • Trebam li neke alate da bih to mogao učiniti?
za koju platformu, npr. windows, linux?
Koja je funkcionalnost koju želite dodati? jer ovisno o tome postoje različiti pristupi. Na primjer, za automatizaciju GUI-ja koristite drugu tehniku ​​koja primjerice mijenja mehanizam baze podataka.
http://stackoverflow.com/questions/4309771/disassembling-modifying-and-then-reassembling-a-linux-executable
Osam odgovori:
#1
+38
Ed McMan
2013-03-23 20:47:41 UTC
view on stackexchange narkive permalink

Postoji nekoliko širokih načina na koje biste to mogli učiniti.

  1. Dinamička instrumentacija

    Alati poput PIN, Valgrind ili DynamoRIO omogućuju vam dinamičko mijenjanje ponašanja programa. Na primjer, možete dodavati pozive novim funkcijama na određenim adresama, presretati pozive iz biblioteke i mijenjati ih, i još mnogo toga.

    Loša strana je što dinamički instrumenti često imaju velike troškove.

  2. Statička instrumentacija

    Također možete pokušati statički izmijeniti program kako biste dodali željeno ponašanje. Jedan je izazov taj što često trebate zajebavati format izvršne datoteke. Neki alati, kao što je elfsh iz projekta ERESI, postoje za to, ali smatram da su programski i da ih je teško koristiti.

    Još jedna strategija za statički instrumentacija je za "ponovno sastavljanje". To možete učiniti dekompiliranjem programa, modificiranjem izvornog koda i ponovnim kompiliranjem. U teoriji, također biste mogli koristiti alat poput BAP za podizanje programa na IL, njegovo modificiranje i ponovno sastavljanje pomoću LLVM-a. Međutim, trenutna verzija vjerojatno nije dovoljno zrela za ovo.

  3. Dinamičko učitavanje

    Možete koristiti LD_PRELOAD za poništavanje funkcija koji će biti dinamički povezani. Ovo je lijepa opcija kada želite promijeniti ponašanje funkcije knjižnice. Prirodno, ne radi na statički povezanim binarnim datotekama niti na statičkim funkcijama.

  4. Binarno zakrpanje

    Često možete napraviti jednostavne promjene u binarnom sustavu pomoću hex-urednik. Na primjer, ako postoji poziv funkcije ili grana koji biste željeli preskočiti, često ga možete zamijeniti uputama nop . Ako trebate dodati veliku količinu novog koda, vjerojatno ćete trebati upotrijebiti nešto poput elfsh iz projekta ERESI da biste lakše promijenili veličinu binarnog datoteke.

#2
+17
Gilles 'SO- stop being evil'
2013-03-23 19:53:18 UTC
view on stackexchange narkive permalink

Vrlo često možete promijeniti ponašanje programa pažljivim priključivanjem na njega. Hoćete li na ovaj način dodati željenu funkcionalnost, ovisi o načinu izrade programa. Pomaže ako program dolazi u obliku jedne glavne izvršne datoteke i nekoliko knjižnica.

Možete se spojiti na bilo koji poziv koji program uputi zajedničkim knjižnicama tako da prvo povežete vlastitu knjižnicu s LD_PRELOAD . Napišite biblioteku koja definira funkciju foo i postavite varijablu okoline LD_PRELOAD na stazu do vaše kompajlirane ( .so ) knjižnice kada započnete program: tada će program pozvati vašu foo umjesto one koju namjerava. Izvornu funkciju foo možete pozvati iz zamjene dobivanjem pokazivača na nju s dlsym().

Evo nekoliko primjera i vodiča:

Neki primjeri programa koji koriste LD_PRELOAD:

Ograničenje LD_PRELOAD je da možete presretati samo pozive funkcija koji su razriješeni tijekom izvođenja (dinamičko povezivanje ). Ako želite presresti interni poziv, morat ćete pribjeći tehnikama veće težine (izmjena izvršne datoteke na disku ili u memoriji pomoću ptrace ).

#3
+7
Michael Anderson
2013-03-23 22:06:39 UTC
view on stackexchange narkive permalink

Želim dodati neke funkcionalnosti postojećoj binarnoj datoteci.

Dakle, općenito se ova četiri veća pitanja odnose na izmjenu izvršne datoteke:

Postavljeno prvo osnovno pitanje: Je li Program oprezan kod izmjena koda (samoprovjera, trikovi protiv otklanjanja pogrešaka, zaštita od kopiranja, ...)?

Ako je tako:

  1. Je li uopće moguće ukloniti / zaobići ove zaštite (npr. raspakiravanje, ako je spakirano) lako
  2. Je li vrijedno vremena da to učinimo?
  3. ol>

    Drugo je pitanje:
    Možete li saznati koji je kompajler / jezik upotrijebljen za izradu izvršne datoteke?

    Više detalja je bolje, ali većina osnovne konstrukcije ( if i druge kontrolne strukture) trebale bi se na sličan način preslikavati na razne kompajlere.

    To je povezano s prethodnim pitanjem o RE-Stackexchange.

    Treće pitanje je:
    Kako se implementira korisničko sučelje (CLI, Win32-Window Controls, Custom, ...)?

    Ako je ovo poznato:
    Možete li shvatiti mapiranje uobičajenih HLL-konstrukcija (izbornici, padajući izbornici, potvrdni okviri, ...) u vezi s korištenim kompajlerom / jezikom koji želite izmijeniti?

    Četvrto i najveće pitanje je:
    Kako možete stvoriti željenu funkcionalnost u programu?

    U osnovi to može zahtijevati prilično obrnuto inženjering, kako biste saznali kako se najbolje uključiti u program, a da ga ne uznemirujete.

    Središnja točka: Kako možete koristiti postojeće interne API-je da biste postigli svoj cilj, a da pritom ne razbijete stvari (poput CRTL + Z, verzija, obnavljanje značajke)?

  • postojeće strukture podataka (i kako su povezane?)
  • postojeće funkcije (parametri, format parametra, ...)
    • što radi?
    • Što još može učiniti?
    • Što DOISTA radi?
    • ...
  • postojeći procesi (= Kako se program interno odvija, postupno za implementaciju sličnih značajki)
    • Koje se funkcije pozivaju, kojim redoslijedom?
    • Koje se strukture podataka koriste?
  • Gdje je meso značajke / programa (podaci, npr. glavno slikarsko područje i kako se to interno odnosi?)
  • Što je sa pripazite (ako se tiče željene značajke):
    • Dnevnik
    • Značajke oporavka
    • Izrada verzija
  • Kako se rukuje metapodacima (npr. Brzina zatvarača, f-Zaustavljanja, ...), što je povezano sa željenom značajkom.

Primjeri projekata: b>

  • Ugradnja nove vrste alata za slikanje u grafički program (bez dodatka-API-ja).
  • Proširenje API-ja dodatka programa.
  • Ugradnja API-ja dodatka u program bez njega.
  • Dodavanje novog formata spremanja / izvoza za datoteke (ako ne postoji način pretvorbe izlaznog formata u željeni format ili ako u izvoženim f nedostaju ključne informacije iles).
  • Dodavanje novog uvoznog formata (ako ne postoji način za pretvorbu ulaznog formata u uvozni ili ako neki podaci nisu ispravno uvezeni).
  • Proširenje Mspainta alatom za pretraživanje i zamjenu u boji (unutar odabira ili na cijeloj slici)
  • Dodavanje proxy podrške / osnovne proxy autentifikacije u program.
  • Dodavanje ( novi) Naredbeni redak prebacuje se na program koji izlaže nove / postojeće značajke.
  • Dodavanje API-ja za udaljene procedure-pozive za eksterno upravljanje operacijama programa.
  • Dodavanje podrške za skriptiranje za automatizaciju često ponavljanih operacija (ako za početak nema dodatka / API-ja za skriptiranje) ili podržavanje skupne obrade.

Što se tiče zamotanih dekompilatora &: Neću govoriti o umotanom kodu na drugim jezicima koji je pakiran s VM-om / tumačem (Py2Exe, Java 2 Exe, ...) ili koristi instalirani (JVM, C #). Za neke od tih slučajeva postoje prilično dobri Decompileri. Nakon uspješne dekompilacije, to se u velikoj mjeri svodi na poraz nad zamućenjem koda (ako postoji).

Što se tiče C / C ++ - Dekompajlera:
Ne mogu govoriti o C / C ++ - Dekompajleri, iako bi se to svodilo na HLL-premapiranje (za stvari koje Decompiler nije dobio) i Deobfuskaciju koda (ako je sastavljen bez simbola), pod uvjetom da u izvršnoj datoteci nema daljnje zaštite.

Preporuka u vezi s HLL-mapiranjem:
U osnovi se velik dio ovog pitanja odnosi na "HLL mapiranje" (mapiranje jezika na visokoj razini (u strojnom kodu)) i izmjenu ove konstrukcije u odgovarajućem strojnom kodu.

Pronašao sam izvrsni početni tečaj za preuzimanje koji koristi "IDA Free" u ovoj temi ovdje (binary-auditing.com).

#4
+7
Ange
2013-03-26 12:49:26 UTC
view on stackexchange narkive permalink

(Pomalo zastarjelo, ali kako to prethodno nije spomenuto u ovoj niti)

Davno sam mjesecima proširivao softver samo s binarnim datotekama.

  • Koristio sam IDA za analizu i SoftICE za ispravljanje pogrešaka uživo. Dekompilacija nije potrebna ako možete razumjeti cilj na razini opcode / bytecode-a.
  • Tada sam, jer je to bio binarni x86 PE, koristio Tasm i Iczelion-ov Code Snippet Creator : To više nije poznati alat, ali dopuštao je transparentnu upotrebu Tasma i ponovno ubrizgavanje koda, s PE transformacijama itd ...

    Dodao je kôd na EntryPoint, pa sam ručno napravio svoje zakrpe , a zatim je skočio na izvorni EntryPoint.

Sad pomalo old-school - vjerojatno bih ubrizgao DLL ovih dana - ali zasigurno je uspio.

I barem vam daje potpunu kontrolu putem ASM-a, a istovremeno održava mogućnost održavanja putem automatiziranog krpanja.

#5
+6
Andrew
2013-03-23 19:30:43 UTC
view on stackexchange narkive permalink

Ne morate dekompilirati binarnu datoteku. Ako razumijete koje promjene želite napraviti, a te se promjene mogu izvršiti samo modificiranjem binarne datoteke ili njezinih ovisnosti, tada te izmjene možete napraviti samo na disku ili u memoriji.

Imate nekoliko izbora kako izvršiti samu izmjenu.

Možete koristiti LD_PRELOAD da povezivač učita zajednički objekt prije izvođenja binarnog programa. Tada uopće ne trebate mijenjati binarni zapis na disku. To je nešto što valgrind radi, učitava se kao zajednički objekt, ali tada započinje dinamička binarna instrumentacija.

Možete koristiti valgrind. Valgrind bi vam omogućio da dinamički prepišete program i proizvoljno modificirate njegovo ponašanje. Valgrind je dinamički binarni instrumentni program koji omogućuje svojim alatima da uređuju program dok se izvršava. Ako samo želite promijeniti ponašanje programa, ovo bi moglo uspjeti, ali valgrind također dolazi do globalnog usporavanja i ako ste željeli zakrpati i preraspodijeliti program, to vjerojatno nije idealno.

Možete koristiti i alate poput elfsh / eresi za umetanje novog koda u program. Ti bi alati trebali voditi računa o injekciji vašeg koda u odnosu na stvari poput zaglavlja ELF programa. Postoji koncept "ELF infector" koji biste mogli potražiti, gdje vaš ubrizgani kôd postaje nova ulazna točka programa, nešto poduzme, a zatim skoči na staru ulaznu točku programa.

#6
+6
0xC0000022L
2013-04-07 03:19:50 UTC
view on stackexchange narkive permalink

Radeći to u sustavu Windows

Iako je ovo pitanje usredotočeno na Linux, gdje bih osobno išao laganom metodom LD_PRELOAD kako je navedeno u drugim odgovorima, Windows poznaje sličan mehanizam koji zapravo je zlostavljana u novijoj prošlosti (također vidi dolje alternativne pristupe). Upotrijebio sam tu metodu za "probijanje" jednog dongle sustava.

Unesite ...

DLL napade (aka preloading, aka otmica) napadi

Ime ima dana je metodi prilično nedavno kada se ispostavilo da bi postavljanje DLL-ova na udaljene dijeljene datoteke, a zatim navigacija do dijeljenja, recimo medija playera, rezultiralo time da media player učitava udaljeni DLL umjesto lokalne verzije. Ovo je prema dizajnu. Ako ga sada promijenite, razbiti bi stotine, ako ne i tisuće aplikacija.

Microsoft se ovim riješio na određene načine, iako je jedino pravo rješenje pravilna implementacija na strani aplikacije. Ali tada, mnogi programeri nisu ni shvatili NT sigurnost iako se moramo nositi s njom otkad je Windows 2000 postao prvi potrošački OS zasnovan na NT platformi.

Kakve to veze ima s vašim opisani cilj?

Dodavanje funkcionalnosti ne znači nužno da zakrpite izvršnu datoteku na disku. To možete učiniti i u memoriji.

Kako to iskoristiti?

Kad god aplikacija koristi DLL, a redoslijed učitavanja možete odrediti s Dependency Walker ili ispod programa za ispravljanje pogrešaka, možete odabrati jedan od DLL-ova koje on uvozi i zamijeniti ga (na njegovom trenutnom mjestu) ili smjestiti drugi DLL u stazu koja prethodi postojećoj DLL-u u redoslijedu učitavanja.

alternativna metoda je promjena imena uvezenih DLL-ova. U rijetkim slučajevima (na primjer, dobro poznati DLL-ovi) ovo je jedina održiva metoda za učitavanje alternativnog DLL-a, koja u nekim posebnim slučajevima i dalje može zakazati.

Ograničenja

Ako korišteni DLL postoji na prvom mjestu u redoslijedu pretraživanja DLL-a, morat ćete doslovno zamijeniti datoteku na disku, osim ako uvoz ne preimenujete kako je gore gore spomenuto.

Implementacije

Ručni pristup može se koristiti za DLL-ove sa samo nekoliko izvezenih simbola. Najlakše bi bilo stvoriti datoteku definicije modula iz DLL-a, a iz nje stvoriti DLL samo s prosljeđivačima funkcija. Na taj bi se način postavljeni DLL već učitao i jednostavno prošao kroz pozive.

Međutim, ovaj pristup neće uspjeti s izvezenim varijablama (za razliku od funkcija).

Evo jednostavnog Python skripta zasnovana na pefile koju sam napisao za još jedan odgovor na StackOverflow:

  import osimport sysimport redef glavni (pename): iz pefile uvoza PE ispis "Raščlanjivanje% s"% pename pe = PE (pename) modname = os.path.basename (pename) libname = re.sub (r "(? i) ^. *? ( [^ \\ /] +) \. (?: dll | exe | sys | ocx) $ ", r" \ 1.lib ", modname) defname = libname.replace (" .lib "," .def ") ispis "Pisanje datoteke definicije modula% s za% s"% (defname, modname) f = open (defname, "w") # želite je baciti, ovdje nema sofisticiranog rukovanja pogreškama f.write ("BIBLIOTEKA% s \ n \ n "% modname) f.write (" EXPORTS \ n ") numexp = 0 za exp u pe.DIRECTORY_ENTRY_EXPORT.symbols: if exp.name: numexp + = 1 f.write (" \ t% s \ n "% exp .name) print "Napisao% s s% d izvozom "% (defname, numexp) print" \ n \ nUpotrijebite ovo za stvaranje lib izvoza: \ n \ tlib / def:% s / out:% s "% (defname, libname) ako je __name__ == '__main__': if len (sys.argv)! = 2: sys.stderr.write ("POGREŠKA: \ n \ tSintaksa: fakelib <dllfile> \ n") sys.exit (1) sys.exit (main (sys.argv) [1]))  

Možete ga prilagoditi tako da stvara prosljeđivače funkcija umjesto jednostavne definicije modula s izvoženim imenima.

Dakle, ovo način na koji možete prebaciti svoj kôd u ciljanu aplikaciju i otići odatle.

Alternativni pristupi

Instrumentacija i priključivanje već su spomenuti. Zaobilazni putovi često je spominjani primjer povezivanja nezgodnog EULA-a u većinu praktičnih svrha. Pogledajte postojeće odgovore za ovu vrstu pristupa.

Također možete koristiti vrijednost registra AppInit_DLL za rano ubrizgavanje DLL-a. Ili možete napisati mali pokretač s petljom za otklanjanje pogrešaka i koristiti mogućnosti izvršenja slikovne datoteke da bi vaša meta prvo pokrenula svoj program za otklanjanje pogrešaka. Alat za ispravljanje pogrešaka također može utjecati na učitavanje DLL-a ili jednostavno presresti - prikladno - pozive na granici između izvršne i DLL datoteke.

Zanimljivosti: ovo ( Opcije izvršavanja slikovne datoteke ) je način na koji Process Explorer zamjenjuje Upravitelja zadataka kad odaberete opciju unutar Process Explorera.


Primijetit ćete kako ove pristupe možete razvrstati u kategorije Ed McMan koji je već spomenut u svom odgovoru. Međutim, to ću prepustiti čitatelju kao vježbu :)

#7
+3
jyz
2013-03-23 20:36:48 UTC
view on stackexchange narkive permalink

To sam učinio s Notepad.exe u sustavu Windows. Želio sam dodati jednu stavku u gornjem izborniku da bih otvorio calc.exe samo iz zabave (znam da je vaše pitanje označeno kao Linux i gcc kompajler, ali ideja je vjerojatno ista).

Stoga sam koristio Alat Resource Hacker za dodavanje Calc izbornika i otvaranje notepad.exe na Imunost Debuggeru u potrazi za nekim prostorom u kodu gdje bih mogao staviti svoj WinExec shellcode. U početku nisam mijenjao izvršnu datoteku, morao sam gledati program u memoriji kako bih pronašao prostor u koji bih mogao zalijepiti upute za montažu bez rušenja bloka.

Jednom kad sam pronašao dovoljno prostora (promjena izvornog koda eliminirajući neke nepotrebne upute za montažu ili čak optimizirajući ih) Otvorio sam notepad.exe u XVI Hex Editor-u i tražio opkodove koji su radili na Imunitetu. Mislim, program za ispravljanje pogrešaka vodio je neke opcode-ove, zar ne? Samo sam potražio slijed opkodova kako bih bio siguran da se nalazim na pravom dijelu softvera koji sam želio promijeniti i ukrcao ga svojim ljuskovnim kodom (sada ovo nije kod sklopa, već "sastavljeni" sklop - strojni kod)

Opet: Znam da je vaše pitanje označeno Linux i gcc kompajler, ali možda bi netko mogao istaknuti neke alate u Linuxu kako bi postigao isto što i ja na Windowsu. Ideja je vjerojatno ista.

#8
+1
Peter Teoh
2014-11-15 13:38:19 UTC
view on stackexchange narkive permalink

"ptrace ()" neobavezno je spomenuo Giles. Ali mislim da je samo po sebi zaslužio čitav odjeljak. "ptrace ()" je API sistemskog poziva koji pruža OS (Linux i svi UNIX imaju ga, kao i Windows) za vršenje kontrole otklanjanja pogrešaka nad drugim procesom. Kada ste koristili PTRACE_ATTACH (kao dio ptrace ()) za spajanje na drugi proces, jezgra će u potpunosti zaustaviti CPU koji izvodi taj proces, što vam omogućuje da napravite promjene u BILO KOJEM dijelu procesa: CPU, bilo koji registri, bilo koji dio toga obraditi memoriju itd. Tako funkcionira dinamičko inline povezivanje. (ptrace () priložiti, izmijeniti binarnu memoriju, a zatim ptrace () nevezati). Koliko znam, sve dinamičke modifikacije drugog procesa moraju koristiti ptrace () - jer je to jedini mehanizam koji jezgra osigurava integritet putem sistemskog poziva u ovom trenutku.

Ali nedavno sličan API poput pojavljuje se utrace (), pa je i teoretski moguće inline povezivanje:

http://landley.net/kdocs/ols/2007/ols2007v1-pages-215-224.pdf

Za priključivanje jezgre postoji mnogo metoda: syscall, interrupt i inline hooking. Ovo je za spajanje prekida:

http://mammon.github.io/Text/linux_hooker.txt



Ova pitanja su automatski prevedena s engleskog jezika.Izvorni sadržaj dostupan je na stackexchange-u, što zahvaljujemo na cc by-sa 3.0 licenci pod kojom se distribuira.
Loading...