Copy Link
Add to Bookmark
Report

Come inserire una nuova sezione e una nuova funzione in un PE

DrWatson's profile picture
Published in 
guide hacker
 · 3 Jun 2018

--------------------------------------------------------------------------------------------------------
LE INFORMAZIONI CHE TROVATE ALL'INTERNO DI QUESTO FILE SONO PER PURO SCOPO DIDATTICO.
L'AUTORE NON INCORAGGIA CHI VOLESSE UTILIZZARLE PER SCOPI ILLEGALI.
--------------------------------------------------------------------------------------------------------


Quello che viene presentato in questo tute è uno studio su come intercettare le funzioni che interrogano il sistema sulla data (GetSystemTime e GetLocalTime) in modo da reindirizzare tali chiamate verso una routine dummy che restituisce sempre la stessa data ed ora.
Dato che molti programmi shareware hanno un periodo di scadenza e dopo un certo tempo diventano inutilizzabili, se fosse restituita sempre la stessa data il programma non raggiunggerebbe mai la scadenza. In realtà bisogna dire che questo sistema non è sempre applicabile. Ad esempio in un programma tipo agenda o calendario se restituissimo sempre la stessa data e ora questi diventerebbero inutilizzabili.

Ma quello che è interessante, a mio avviso, è la sostituzione di una funzione con un altra fatta da noi e l'aggiunta di una nuova sezione di codice. Questa tecnica potrebbe essere utilizzata in tante altre occasioni, le funzioni GetSystemTime e GetLocalTime sono state prese solo come spunto per un esempio pratico.


I passi fondametali che seguiremo sono:


1) Aggiunta di una nuova sezione al file eseguibile PE e aggiornamento dell'header: il piu delle volte alla fine della sezione .text c'e' abbastanza spazio per aggiungere qualche linea di codice asm ma non sempre è sufficente per i nostri scopi. Anche nel programma che ho preso come target la routine sarebbe comodamente entrata alla fine della sezione .text, ma è stata comunque aggiunta una nuova sezione.

2) scrittura della dummy routine nella nuova sezione appena creata.

3) dirottamanto delle funzioni GetsystemTime e GetLocaltime verso la nostra routine.


Il programma che ho scelto come target è lo stesso per il quale avevamo fatto un keygen: Programmers IDE.
Se il programma risulta registrato potrete agevolmente cancellare la registrazione con il Regedit.

Per prima cosa dobbiamo incrementare le dimensioni dell'eseguibile aggiungendo alcuni bytes in coda al file. Con HIEW in modalità HEX spostiamoci alla fine del file, andando in edit mode sara possibile aggiungere dei bytes, nell'esempio io ho aggiunto 128 bytes digitando tutti zeri.

A questo punto bisogna fare è una modifica all'header del file PE per aggiungere una nuova sezione: con HIEW apriamo il file project.exe e settiamo la modalità HEX, dopo la signature per il dos sarà possibile notare i caratteri "PE" che indicano l'inizio dell'header PE (SIGNATURE BYTES), se ci spostiamo di 7 bytes saremo dentro la sezione "# OBJECTS" per aggiungere una nuova sezione bastera incrementare questo valore di 1.

 
+-------------------------------------------------------+
¦ SIGNATURE BYTES ¦ CPU TYPE ¦ # OBJECTS ¦ < ------
+---------------------------+---------------------------¦
¦ TIME/DATE STAMP ¦ RESERVED ¦
+---------------------------+---------------------------¦
¦ RESERVED ¦ NT HDR SIZE¦ FLAGS ¦
+---------------------------+---------------------------¦
¦ RESERVED ¦LMAJOR¦LMINOR¦ RESERVED ¦
+---------------------------+---------------------------¦
¦ RESERVED ¦ RESERVED ¦
+---------------------------+---------------------------¦
¦ ENTRYPOINT RVA ¦ RESERVED ¦
+---------------------------+---------------------------¦
¦ RESERVED ¦ IMAGE BASE ¦
+---------------------------+---------------------------¦
¦ OBJECT ALIGN ¦ FILE ALIGN ¦
+---------------------------+---------------------------¦
¦ OS MAJOR ¦ OS MINOR ¦USER MAJOR ¦USER MINOR ¦
+-------------+-------------+---------------------------¦
¦ SUBSYS MAJOR¦ SUBSYS MINOR¦ RESERVED ¦
+---------------------------+---------------------------¦
¦ IMAGE SIZE ¦ HEADER SIZE ¦
+---------------------------+---------------------------¦
¦ FILE CHECKSUM ¦ SUBSYSTEM ¦ DLL FLAGS ¦
+---------------------------+---------------------------¦
¦ STACK RESERVE SIZE ¦ STACK COMMIT SIZE ¦
+---------------------------+---------------------------¦
¦ HEAP RESERVE SIZE ¦ HEAP COMMIT SIZE ¦
+---------------------------+---------------------------¦
¦ RESERVED ¦ # INTERESTING RVA/SIZES ¦
+---------------------------+---------------------------¦
¦ EXPORT TABLE RVA ¦ TOTAL EXPORT DATA SIZE ¦
+---------------------------+---------------------------¦
¦ IMPORT TABLE RVA ¦ TOTAL IMPORT DATA SIZE ¦
+---------------------------+---------------------------¦
¦ RESOURCE TABLE RVA ¦ TOTAL RESOURCE DATA SIZE ¦
+---------------------------+---------------------------¦
¦ EXCEPTION TABLE RVA ¦ TOTAL EXCEPTION DATA SIZE¦
+---------------------------+---------------------------¦
¦ SECURITY TABLE RVA ¦ TOTAL SECURITY DATA SIZE ¦
+---------------------------+---------------------------¦
¦ FIXUP TABLE RVA ¦ TOTAL FIXUP DATA SIZE ¦
+---------------------------+---------------------------¦
¦ DEBUG TABLE RVA ¦ TOTAL DEBUG DIRECTORIES ¦
+---------------------------+---------------------------¦
¦ IMAGE DESCRIPTION RVA ¦ TOTAL DESCRIPTION SIZE ¦
+---------------------------+---------------------------¦
¦ MACHINE SPECIFIC RVA ¦ MACHINE SPECIFIC SIZE ¦
+---------------------------+---------------------------¦
¦ THREAD LOCAL STORAGE RVA ¦ TOTAL TLS SIZE ¦
+-------------------------------------------------------+


Il prossimo passo è quello di aggiungere una nuova entry nella "object table" per assegnare alla nuova sezione un nome, una VistualSize, un RVA, una PhisycalSize un Offset, e i flags: la "object table" è situata immediatamente dopo l'header pe infatti spostandoci con hiew sotto l'header si potranno notare i nomi delle varie sezioni : .text, .rdata, .data, ecc.

 
+-------------------------------------------------------+
¦ OBJECT NAME ¦
+-------------------------------------------------------¦
¦ VIRTUAL SIZE ¦ RVA ¦
+---------------------------+---------------------------¦
¦ PHYSICAL SIZE ¦ PHYSICAL OFFSET ¦
+---------------------------+---------------------------¦
¦ RESERVED ¦ RESERVED ¦
+---------------------------+---------------------------¦
¦ RESERVED ¦ OBJECT FLAGS ¦
+-------------------------------------------------------+


Come è possibile notare dalla tabella ogni entry è composta di 40 byes bisognerà quindi spostarsi di di 40 bytes dall'ultima sezione, nel nostro caso .reloc, e iniziare ad assegnare le proprieta alla nostra nuova sezione:

OBJECT NAME: il nome che ho scelto di assegnare è ".pippo", un classico! :))


VIRTUAL SIZE: indica al loader quanta memoria deve essere allocata per il caricamento dell'object, per non sbagliarmi io ho messo il numero dei bytes aggiunti all'eseguibile : 80h.


RVA : rappresenta l'ndirizzo a cui è relocato l'object relativamente alla Image Base. se in modalita HEX con HIEW premiamo F8 compariranno varie informazioni sul PE-header tra queste ci sara anche "Image Base 00400000", premendo ora F6 comparirà la tabella delle sezioni:

 
+-Number Name VirtSize RVA PhysSize Offset Flag---+
¦ 1 .text 00021754 00001000 00021800 00000400 60000020 ¦
¦ 2 .rdata 00000988 00023000 00000A00 00021C00 40000040 ¦
¦ 3 .data 00016920 00024000 00007C00 00022600 C0000040 ¦
¦ 4 .idata 0000165E 0003B000 00001800 0002A200 C0000040 ¦
¦ 5 .rsrc 0000D1FC 0003D000 0000D200 0002BA00 40000040 ¦
¦ 6 .reloc 000029C8 0004B000 00002A00 00038C00 42000040 ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
+-------------------------------------------------------------+


sulla colonna degli RVA ci sono tutti gli indirizzi virtuali relativi alla Image Base. Se sommiamo l'RVA dell'ultima sezione (.reloc) con la sua Phisical Size otteniamo l'ultima posizione occupata dalla sezione: 4b000+2a00 = 4da00. Da questo valore possiamo ricavare un RVA per la nostra nuova sezione che dovrà essere > 4da00, nel mio esempio ho scelto il valore 4e000.


PHYSICAL OFFSET: non sarebbe altro che l'indirizzo assoluto dall'inizio del file. spostiamoci con HIEW sull'ultimo byte della sezione .reloc (0044d9ff) premiamo ALT-F1 e otteremo l'indirizzamento globale. l'offset della nuova sezione si trova all'indirizzo 003b600.


OBJECT FLAGS: questa nuova sezione dovra avere le caratteristiche: __Code object, __Executable object, __Readable object. Le stesse della sezione .text : 60000020h.


Questa è una schermata di hiew con le modifiche apportate alla object table:

 
00000240: 2E 72 65 6C-6F 63 00 00-C8 29 00 00-00 B0 04 00 .reloc +) _
00000250: 00 2A 00 00-00 8C 03 00-00 00 00 00-00 00 00 00 * î
00000260: 00 00 00 00-40 00 00 42-2E 70 69 70-70 6F 00 00 @ B.pippo
00000270: 80 00 00 00-00 E0 04 00-80 00 00 00-00 B6 03 00 + _ + ¦
00000280: 00 00 00 00-00 00 00 00-00 00 00 00-20 00 00 60 `


A questo punto la nuova sezione dovrebbe essere presente, se chiudiamo e riapriamo il file con hiew la object table dovrebbe apparire così:

 
+-Number Name VirtSize RVA PhysSize Offset Flag---+
¦ 1 .text 00021754 00001000 00021800 00000400 60000020 ¦
¦ 2 .rdata 00000988 00023000 00000A00 00021C00 40000040 ¦
¦ 3 .data 00016920 00024000 00007C00 00022600 C0000040 ¦
¦ 4 .idata 0000165E 0003B000 00001800 0002A200 C0000040 ¦
¦ 5 .rsrc 0000D1FC 0003D000 0000D200 0002BA00 40000040 ¦
¦ 6 .reloc 000029C8 0004B000 00002A00 00038C00 42000040 ¦
¦ 7 .pippo 00000080 0004E000 00000080 0003B600 60000020 ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
¦ ¦
+-------------------------------------------------------------+


Un'ultima cosa da fare è quella di modificare nell'header il valore della Image Size sommandogli il valore della VirtualSize della nuova sezione altrimenti sotto NT il programma non girerebbe:
04e000 + 80 = 04e080.

La prima parte del lavoro è completata, adesso bisogna implementare la funzione che andrà a sostituire GetSystemTime e GetLocalTime nella nuova sezione appena creata: Il parametro che viene passato alle funzioni è un puntatore ad una struttura di tipo SYSTEMTIME:

 
typedef struct _SYSTEMTIME { // st
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME;


non bisogna far altro che scrivere qualche riga di asm per riempire i campi della struttura con dei valori falsi:

 
.0044E000: 55 push ebp
.0044E001: 8BEC mov ebp,esp
.0044E003: 57 push edi
.0044E004: 8B7D08 mov edi,[ebp][00008] ; puntatore alla struttura
.0044E007: 66C74700CC07 mov w,[edi][00000],007CC ; wYear = 1996
.0044E00D: 66C747060100 mov w,[edi][00006],00001 ; wDay = 01
.0044E013: 66C747020100 mov w,[edi][00002],00001 ; wMonth= 01
.0044E019: 66C747080200 mov w,[edi][00008],00002 ; wHour = 02
.0044E01F: 66C7470A0300 mov w,[edi][0000A],00003 ; wMinute=03
.0044E025: 66C7470C0400 mov w,[edi][0000C],00004 ; wSecond=04
.0044E02B: 31C0 xor eax,eax
.0044E02D: 40 inc eax
.0044E02E: 5D pop ebp
.0044E02F: 5F pop edi
.0044E030: C20400 retn 00004


Ora non rimane altro che andare a cercare le call alle funzioni in oggetto e sostituirle con delle call alla nuova funzione. Nel programma che ho preso in esame c'erano due sole call:

 
.004188CC: FF15C4B54300 call GetLocalTime ;KERNEL32.dll
.004188D2: 8D4C2404 lea ecx,[esp][00004]
.004188D6: 51 push ecx
.004188D7: FF1504B64300 call GetSystemTime ;KERNEL32.dll
.004188DD: 668B0D7A2C4300 mov cx,[000432C7A]


Bisognera calcolare l'offset a cui punta la call rispetto alla istruzione successiva, quindi nel caso della prima call 44E000 - 4188D1 = 03572F e per la seconda 44E000 - 4188DC = 035724 :

 
.004188CC: E82F570300 call .00044E000
.004188D1: 90 nop
.004188D2: 8D4C2404 lea ecx,[esp][00004]
.004188D6: 51 push ecx
.004188D7: E824570300 call .00044E000
.004188DC: 90 nop


Il programma adesso dovrebbe essere sempre in trial, infatti la versione originale dopo 30 giorni da una messagebox di avvertimento che il periodo di prova è scaduto e la splash screen che si presenta all'avvio dura parecchio tempo, con la versione modificata sarete sempre dentro i 30 giorni della trial :))

 
Bibliografia : "PORTABLE EXECUTABLE FORMAT" Micheal J. O'Leary (sulla rete)
"The PE file format" B. Luevelsmeyer (sulla rete)
"il tute di killexx sui crypter" Killexx (Ringzer0)


Ringraziamenti:

a Killexx che è sempre disponibile a dare spiegazioni :)
Insano che ci sopporta.
Malattia anche se è un po che non lo sento :(
A tutti gli altri membri di RingZer0, anche se purtroppo non ho mai occasione di parlare con loro :(

Pusillus.

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT