|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Sep 2006
Città: Bologna/Milano
Messaggi: 525
|
[c/c++]aggiungere codice eseguibile dentro ad un altro eseguibile in modo permanente
aggiungere codice eseguibile dentro ad un altro eseguibile in modo permanente è possibile???
vorrei nel mio computer aggiungere dentro al programma explorer.exe (quello di windows...) dei comandi per svolgere alcune operazioni di rutin che nn voglio sempre fare a mano o con un programma che si carica per i fatti suoi... si puo fare??? grazie ciao |
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2780
|
Non puoi usare un semplice file batch?
|
|
|
|
|
|
#3 | |
|
Senior Member
Iscritto dal: Sep 2006
Città: Bologna/Milano
Messaggi: 525
|
Quote:
1) dovrei far avviare qualcos'altro ad ogni avvio 2) non eseguirebbe comandi che devono eseguirsi magari al verificarsi di determinate situazioni che avvengono dopo l'avvio 3 last but not least) se lo usassi come migliorerei le mie scarse capacità di programmatore??? grazie comunque per l'idea anche se nn era ciò che cercavo |
|
|
|
|
|
|
#4 | ||||
|
Senior Member
Iscritto dal: Nov 2005
Città: TO
Messaggi: 5206
|
Quote:
Ma perché molto probabilmente quello che vuoi fare si può realizzare sviluppando semplicemente un normale eseguibile. Quote:
Quote:
Quote:
__________________
Andrea, SCJP 5 (91%) - SCWCD 5 (94%) |
||||
|
|
|
|
|
#5 | |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
vorrà dire che dovrò mandarti le arance con dentro le limette ![]() infettare un eseguibile per Windows è un'operazione dalla difficoltà molto variabile. il contenuto di un eseguibile è diviso in sezioni, e in genere una sezione di nome ".text" è dedicata esclusivamente al codice. le sezioni non possono avere dimensioni qualsiasi, ma devono avere dimensioni multiple di un certo valore di allineamento scritto negli headers del file. a causa di ciò spesso e volentieri serve del padding, cioè il compilatore una volta che ha finito di scrivere il codice deve concludere la sezione con un po' di zeri che la riempiono finché non raggiunge le dimensioni di allineamento. ora: se tu vuoi scrivere del codice nell'eseguibile chiaramente per prima cosa devi vedere se la sezione ".text" contiene abbastanza padding. se lo contiene (e spesso è così) bene, sennò...? ti tocca ingrandire una sezione, cosa a dir poco complessa... questo era il primo passo, ora veniamo al secondo: una volta che hai scritto il codice devi anche fare in modo che esso venga eseguito. questo per fortuna è un'operazione semplice che funziona sempre: gli headers del file contengono tra le altre cose anche l'RVA (Relative Virtual Address, indirizzo virtuale relativo al base address di caricamento del file, praticamente l'indirizzo) dell'entry point, cioè del punto (che dovrebbe trovarsi sempre nella sezione ".text") a cui inizia l'esecuzione del programma. ciò che devi fare è cambiare quel valore con l'RVA del tuo codice "clandestino", il quale codice clandestino alla fine dovrà contenere un JMP che salti all'entry point originale. questo è quanto, se vuoi entro in dettagli. |
|
|
|
|
|
|
#6 | ||
|
Senior Member
Iscritto dal: Sep 2006
Città: Bologna/Milano
Messaggi: 525
|
Quote:
e cmq se in futuro mi regaleranno delle arance saprò che nn le devo accettare Quote:
grazie mille |
||
|
|
|
|
|
#7 | |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
http://www.microsoft.com/whdc/system...re/PECOFF.mspx poi vai anche qua e mettitelo tra i preferiti, è un articolo bellissimo di Matt Pietrek che aiuta la comprensione di tutta una serie di cose che sarebbero propedeutiche allo studio delle specifiche ufficiali del formato PE, e che stanno sparse qua e là per tutta MSDN e sono quindi difficili da trovare: http://msdn.microsoft.com/msdnmag/is...E/default.aspx è segnato a 3 come livello di difficoltà ma non è vero, io lo trovo chiarissimo. e casomai se vuoi leggerti anche la seconda parte ecco qua: http://msdn.microsoft.com/msdnmag/is...2/default.aspx detto questo, io ti consiglio di leggerti prima l'articolo tenendoti accanto le specifiche ufficiali da consultare, e poi di leggerti la mia spiegazione che segue. nell'header winnt.h sono dichiarate tutte le struct e le macro necessarie alla lettura di un file PE, e poiché winnt.h è incluso da windows.h come includi windows.h hai automaticamente tutto il necessario. si assume inoltre che tu lavori in Win32, cioè Windows a 32 bit (a 64 bit alcune cose cambiano). primo passo: headers del file. apri il file, spostati all'offset 0x3C e leggi un DWORD; poi spostati all'offset espresso da quel DWORD (attenzione: offset assoluto, non relativo! devi andarci, non devi avanzare) e leggi una struct IMAGE_NT_HEADERS. tra le varie cose ci troverai un campo NumberOfSections che ti dice il numero di sezioni in cui è diviso il contenuto vero e proprio del file. ciascuna sezione è descritta da un proprio header, e tutti gli headers delle sezioni si trovano esattamente dopo gli headers principali che hai letto nella struttura IMAGE_NT_HEADERS. quindi alloca un array di NumberOfSections strutture IMAGE_SECTION_HEADER (vado a memoria, spero che si chiamasse così la struct) e prendine il contenuto direttamente dal file. secondo passo: trovare la sezione di codice. analizza gli header delle sezioni uno per uno: la sezione di codice è quella il cui header ha attivato il flag IMAGE_SCN_CNT_CODE nel campo Characteristics (non ti fidare del nome ".text", è una convenzione che non tutti i compilatori rispettano: quello della Borland la chiama "CODE"). in teoria potresti addirittura trovare più d'una sezione contenente codice, nel qual caso a parer mio devi congegnare l'algoritmo in modo da scrivere il codice clandestino in quella con padding sufficiente. una volta individuato un section header che descrive una sezione di codice, i seguenti campi dell'header ti possono essere utili:
terzo passo: calcolare la dimensione minima di padding il padding inizia semplicemente quando da un certo punto in poi trovi solo zeri; ma non è detto che uno dei primi di quegli zeri sia già padding, potrebbe anche essere la parte finale della codifica dell'ultima istruzione, e se la sovrascrivi sono guai. che io ricordi non c'è campo nel section header che ti dica la dimensione del padding, perciò devi analizzare il contenuto della sezione partendo dalla fine e andando a ritroso, finché non trovi un byte diverso da zero; poi però devi ri-avanzare di qualche byte per essere sicuro di non sovrascrivere "zeri utili". di quanti byte avanzare? per sicurezza è meglio avanzare di N con N = dimensione massima di un'istruzione assembly x86 il resto te lo dico dopo che è pronta la cena |
|
|
|
|
|
|
#8 | |
|
Senior Member
Iscritto dal: Sep 2006
Città: Bologna/Milano
Messaggi: 525
|
Quote:
buon appetito grazie davvero!! aspetto il resto |
|
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Jan 2002
Città: Napoli
Messaggi: 1727
|
Io quando mi occupavo di ste cose avevo fatto un po' di modifiche a un po' di roba.
Il primo passo è disassemblare l'eseguibile, tramite ad esempio wdasm32. Quindi cerchi al suo interno riferimenti a stringhe o a chiamate ad API di windows. Ad esempio se nel programma in fase di chiusura appare la stringa "sei sicuro di voler uscire?" tu cerchi nelle string reference questo messaggio, e pratica puoi andare nella sezione di codice assembler dove questa stringa viene "usata", magari abbinata a una chiamata all'API MessageBox o qualcosa del genere... Quindi ti guardi attorno, magari poche istruzioni più su, trovi una reference a una call, in pratica puoi andare a scoprire nel codice disassemblato da dove questa funzioncina viene chiamata, e boom.. magari finisci in una sezione di codice dalla quale la funzione che poi mostra la messagebox viene chiamata. Vabbè in sostanza devi trovare un punto buono dove "iniettare" il tuo codice. A quel tutto è abbastanza semplice, cerchi un'area "zero padded" dell'eseguibile, di solito stanno verso la fine. Nel punto dove vuoi iniettare il codice sostituisci un'istruzione con una JUMP che ti manda nella zona zero-padded, lì ci scrivi quello che ti pare e infine scrivi l'istruzione che avevi tolto prima e fai un JUMP per tornare nella zona originale. Comunque se cerchi su google "code injection" "reverse engineering" o altra roba del genere dovresti trovare un mucchio di tutorial. Visto che facevo ste cose nello scorso millennio, non sono più molto documentato sulla faccenda
__________________
Se buttassimo in un cestino tutto ciò che in Italia non funziona cosa rimarrebbe? Il cestino. |
|
|
|
|
|
#10 | |
|
Senior Member
Iscritto dal: Apr 2003
Città: Genova
Messaggi: 4739
|
Quote:
__________________
Jappilas is a character created by a friend for his own comic - I feel honored he allowed me to bear his name Saber's true name belongs to myth - a Heroic Soul out of legends, fighting in our time to fullfill her only wish Let her image remind of her story, and of the emotions that flew from my heart when i assisted to her Fate
|
|
|
|
|
|
|
#11 |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
@mamo139, la seconda parte viene domani (e probabilmente di sera) ché oggi non ho avuto tempo. hai tutto il tempo di fare gli esperimenti e di leggerti l'articolo di Pietrek
|
|
|
|
|
|
#12 | |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
quarto passo: scrittura del codice una volta che hai trovato l'area di padding ci scrivi il codice e via. tipicamente potrà essere una chiamata a LoadLibraryA che carica una tua DLL. inoltre come abbiamo detto alla fine deve esserci un JMP relativo che ritorno all'RVA dell'entry point originario. tale RVA è scritto nel campo AddressOfEntryPoint dell'header principale del file, e chiaramente dovrai anche modificare quel campo mettendoci l'RVA del codice clandestino (il byte a cui sei sicuro che inizia il padding), in modo che l'esecuzione del programma inizi dal tuo codice. quinto passo, opzionale: espansione di una sezione, e qui siamo sull'orlo della ricompilazione se per caso decidessi di rendere l'installer del tuo malware ( ) a prova di casi sfigati di totale assenza di padding, avrai la necessità di scrivere il codice necessario ad esandere una sezione. espandere una sezione non è un problema finché lo spazio che c'è dopo è gap (spazio vuoto tra sezioni), o finché la sezione in questione è l'ultima del file; il problema è quando ci stanno altre sezioni dopo. in quel caso le sezioni successive vanno spostate in avanti, e vanno rilocate, altrimenti di sicuro il programma non funzionerà più.anzitutto devi calcolare il delta per lo spostamento, cioè di quanto le sezioni successive vanno spostate in avanti; e devi calcolarlo in modo che (come stabilito dalle specifiche) l'inizio di ciascuna rimanga un multiplo del valore di allineamento specificato dal membro FileAlignment dell'header principale (credo che solitamente corrisponda a 0x1000, la dimensione di una pagina). dopo aver fisicamente riscritto le sezioni più avanti nel file devi aggiornare nei rispettivi section header i campi PointerToRawData e VirtualAddress aggiungendo semplicemente il delta di spostamento. infine devi rilocare le sezioni: consultando la normale fixup table dell'eseguibile esegui un normale algoritmo di rilocazione che applica i fixup solo quando questi vadano a cadere dentro una delle sezioni spostate, e li applica addizionando il delta di spostamento. |
|
|
|
|
|
|
#13 | |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
non si tratta banalmente di addizionare il delta per ritrovare il punto in cui applicare il fixup, devi proprio correggere il valore di offset di tutte le entries interessate; e potrebbe essere un bel c***o di problema in quanto le entries non esprimono il punto di applicazione del fixup con un RVA da 32 bit, ma per risparmiare spazio lo esprimono con un offset da 12 bit calcolato rispetto ad un certo RVA di base. per l'esattezza, la fixup table è divisa in più fixup blocks, ciascuno dei quali contiene un RVA di base (a 32 bit) ed N fixup entries da 16 bit, di cui 12 sono l'offset. il problema è evidente: avendo a disposizione solo 12 bit per gli offset, spostando una sezione e semplicemente addizionando il delta all'offset potresti mandarlo in overflow. ciò che puoi fare nel caso in cui tutte le entries di quel fixup block cadano nella stessa sezione è addizionare il delta direttamente all'RVA di base del blocco anziché ai singoli offset. altrimenti non lo so, potrebbe anche non esserci soluzione al problema (perlomeno non soluzione che valga la pena, perché al limite c'è sempre la ricompilazione totale è chiaro ma le sorprese non sono finite, aspetta che ti spiego come va scritto il codice clandestino Ultima modifica di 71104 : 20-11-2006 alle 09:13. |
|
|
|
|
|
|
#14 |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
appendice: generazione del codice clandestino
ricordiamoci che il nostro scopo è chiamare LoadLibraryA passandogli l'indirizzo di una stringa situata nel codice stesso, e subito dopo fare un JMP all'entry point originale. possiamo strutturare il codice come segue:
cominciamo dal PUSH, già abbiamo un problema: con una rapida consultatina al manuale Intel vediamo che la versione che dovremmo usare è PUSH imm32, opcode 0x68 seguito da 4 bytes di valore immediato. calcolare il valore immediato è banale, basta sommare l'RVA della stringa al base address dell'eseguibile; il problema è che avremmo (in teoria) bisogno di un fixup in quel punto... possibili soluzioni? 1) ce ne freghiamo - tanto è un eseguibile, verrà sicuramente caricato al suo base address predefinito, a meno che il programmatore sadico non l'abbia definito come 0x7C800000 (il base address di kernel32.dll) o come >= 0x80000000 (base address in kernel space). 2) pur di essere sicuri di non doverci rilocare spostiamo tutto l'eseguibile al base address standard, 0x00400000 e a dire il vero non è neanche una soluzione tanto difficile: basta rilocare tutto il file utilizzando (0x00400000 - il suo base address) come delta col PUSH siamo quindi (più o meno ) a posto: iniziamo a scrivere 0x68 e lasciamo 4 byte vuoti perché l'RVA della stringa ancora non lo sappiamo.ora passiamo al CALL: stavolta, al contrario del caso precedente, se vogliamo usare un valore immediato nella chiamata non abbiamo a disposizione una versione absolute dell'istruzione, ma solo relative; peccato che adesso invece ci serviva proprio la absolute (eccheppalle abbiamo due casi: 1) l'eseguibile importa LoadLibraryA da kernel32.dll 2) l'eseguibile non importa LoadLibraryA nel primo caso siamo fortunati: dobbiamo usare CALL r/m32 specificando l'indirizzo della entry relativa a LoadLibraryA nella Import Address Table. non entro in dettagli perché dal manuale non ho capito la codifica di quella versione di CALL ^__^'' nel secondo caso invece, considerando che nello spazio di indirizzamento di qualsiasi processo il base address di kernel32.dll non cambia mai (e quindi neanche l'indirizzo di LoadLibraryA), utilizzeremo CALL rel32: scriviamo 0xE8 e subito dopo un delta così calcolato: (indirizzo di LoadLibraryA ottenuto da una GetProcAddress chiamata in qualsiasi processo) - (VA a cui stiamo scrivendo il CALL) - (dimensione del CALL, cioè 5) e la cosa bella è che qui non ci serve il fixup andiamo avanti: il JMP. caso analogo: ciò che dobbiamo usare è JMP rel32, opcode 0xE9 seguito dai 4 bytes di delta così calcolati: (valore originale del membro AddressOfEntryPoint dell'header principale) - (VA del JMP) - (dimensione del JMP, cioè 5) dopodiché scriviamo la stringa e a questo punto, conoscendo anche l'RVA della stringa stessa, possiamo ultimare il PUSH iniziale. occhio però: ai 4 bytes immediati del PUSH non dobbiamo scrivere l'RVA, ma il VA (l'RVA sommato al base address predefinito, sperando che sia sempre anche quello effettivo |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 09:40.












in quel caso le sezioni successive vanno spostate in avanti, e vanno rilocate, altrimenti di sicuro il programma non funzionerà più.








