Writing ELF headers in Radare?











up vote
5
down vote

favorite
2












Reading Keith Makan's, "Introduction to the ELF Format : The ELF Header", he modifies e_entry,




The e_entry field lists the offset in the file where the program should start executing.Normally it points to your _start method (of course if you compiled it with the usual stuff). You can point the e_entry anywhere you like, as an example I'm going to show that you can call a function that would other wise be impossible under normal execution.




Also documented in man 5 elf, I'm wondering if Radare has any functionality to rewrite ELF-specific headers or if writing the bits manually is the current way to do this? For example, I know it'll show the entry point with ie.










share|improve this question




















  • 1




    You absolutely want to do this with radare2? If not, have a look at the bfd project (used by binutils).
    – 0xC0000022L
    Nov 19 at 22:15






  • 2




    @0xC0000022L I'm not sure there is a way to do this, generally speaking I assume that Radare can't do something, and then I ask and I find out it can (a huge value of this site). I assume it can only parse ELF. If it can only parse ELF, I think a workaround is a great contribution because I'm pretty spankin new to RE, and I'm sure others are testing the waters just like me. If Radare grows the ability later, I will just come back and mark the newer answer as chosen.
    – Evan Carroll
    Nov 19 at 22:18

















up vote
5
down vote

favorite
2












Reading Keith Makan's, "Introduction to the ELF Format : The ELF Header", he modifies e_entry,




The e_entry field lists the offset in the file where the program should start executing.Normally it points to your _start method (of course if you compiled it with the usual stuff). You can point the e_entry anywhere you like, as an example I'm going to show that you can call a function that would other wise be impossible under normal execution.




Also documented in man 5 elf, I'm wondering if Radare has any functionality to rewrite ELF-specific headers or if writing the bits manually is the current way to do this? For example, I know it'll show the entry point with ie.










share|improve this question




















  • 1




    You absolutely want to do this with radare2? If not, have a look at the bfd project (used by binutils).
    – 0xC0000022L
    Nov 19 at 22:15






  • 2




    @0xC0000022L I'm not sure there is a way to do this, generally speaking I assume that Radare can't do something, and then I ask and I find out it can (a huge value of this site). I assume it can only parse ELF. If it can only parse ELF, I think a workaround is a great contribution because I'm pretty spankin new to RE, and I'm sure others are testing the waters just like me. If Radare grows the ability later, I will just come back and mark the newer answer as chosen.
    – Evan Carroll
    Nov 19 at 22:18















up vote
5
down vote

favorite
2









up vote
5
down vote

favorite
2






2





Reading Keith Makan's, "Introduction to the ELF Format : The ELF Header", he modifies e_entry,




The e_entry field lists the offset in the file where the program should start executing.Normally it points to your _start method (of course if you compiled it with the usual stuff). You can point the e_entry anywhere you like, as an example I'm going to show that you can call a function that would other wise be impossible under normal execution.




Also documented in man 5 elf, I'm wondering if Radare has any functionality to rewrite ELF-specific headers or if writing the bits manually is the current way to do this? For example, I know it'll show the entry point with ie.










share|improve this question















Reading Keith Makan's, "Introduction to the ELF Format : The ELF Header", he modifies e_entry,




The e_entry field lists the offset in the file where the program should start executing.Normally it points to your _start method (of course if you compiled it with the usual stuff). You can point the e_entry anywhere you like, as an example I'm going to show that you can call a function that would other wise be impossible under normal execution.




Also documented in man 5 elf, I'm wondering if Radare has any functionality to rewrite ELF-specific headers or if writing the bits manually is the current way to do this? For example, I know it'll show the entry point with ie.







radare2 elf






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 19 at 22:14









0xC0000022L

7,76942963




7,76942963










asked Nov 19 at 22:06









Evan Carroll

71716




71716








  • 1




    You absolutely want to do this with radare2? If not, have a look at the bfd project (used by binutils).
    – 0xC0000022L
    Nov 19 at 22:15






  • 2




    @0xC0000022L I'm not sure there is a way to do this, generally speaking I assume that Radare can't do something, and then I ask and I find out it can (a huge value of this site). I assume it can only parse ELF. If it can only parse ELF, I think a workaround is a great contribution because I'm pretty spankin new to RE, and I'm sure others are testing the waters just like me. If Radare grows the ability later, I will just come back and mark the newer answer as chosen.
    – Evan Carroll
    Nov 19 at 22:18
















  • 1




    You absolutely want to do this with radare2? If not, have a look at the bfd project (used by binutils).
    – 0xC0000022L
    Nov 19 at 22:15






  • 2




    @0xC0000022L I'm not sure there is a way to do this, generally speaking I assume that Radare can't do something, and then I ask and I find out it can (a huge value of this site). I assume it can only parse ELF. If it can only parse ELF, I think a workaround is a great contribution because I'm pretty spankin new to RE, and I'm sure others are testing the waters just like me. If Radare grows the ability later, I will just come back and mark the newer answer as chosen.
    – Evan Carroll
    Nov 19 at 22:18










1




1




You absolutely want to do this with radare2? If not, have a look at the bfd project (used by binutils).
– 0xC0000022L
Nov 19 at 22:15




You absolutely want to do this with radare2? If not, have a look at the bfd project (used by binutils).
– 0xC0000022L
Nov 19 at 22:15




2




2




@0xC0000022L I'm not sure there is a way to do this, generally speaking I assume that Radare can't do something, and then I ask and I find out it can (a huge value of this site). I assume it can only parse ELF. If it can only parse ELF, I think a workaround is a great contribution because I'm pretty spankin new to RE, and I'm sure others are testing the waters just like me. If Radare grows the ability later, I will just come back and mark the newer answer as chosen.
– Evan Carroll
Nov 19 at 22:18






@0xC0000022L I'm not sure there is a way to do this, generally speaking I assume that Radare can't do something, and then I ask and I find out it can (a huge value of this site). I assume it can only parse ELF. If it can only parse ELF, I think a workaround is a great contribution because I'm pretty spankin new to RE, and I'm sure others are testing the waters just like me. If Radare grows the ability later, I will just come back and mark the newer answer as chosen.
– Evan Carroll
Nov 19 at 22:18












2 Answers
2






active

oldest

votes

















up vote
12
down vote



accepted










Yes, obviously you can. radare2 has built-in features to handle binary headers. This including reading, parsing and modifying the headers of the binary. And this is not different for elf or pe files, it will work great with both.



TL;DR



$ ./example.elf
[*] you ran this binary!

$ r2 -w -nn example.elf
[0x00000000]> .pf.elf_header.entry=0x0000063a
[0x00000000]> q

$ ./example.elf
[*] wow how did you manage to call this?




Creating our test file



As described in the article you linked in your question, it is easy to create a binary with a function that should never be executed under regular circumstances. Here's the exact code that was used in the linked article:



$ cat example.c

#include <stdio.h>


void never_call (void) {
printf ("[*] wow how did you manage to call this?n");
return;
}

int main (int argc, char **argv) {
printf ("[*] you ran this binary!n");
return 0;
}


As you can see, the function never_call would, well... never be called. The program would execute the entrypoint which would execute the main function and will return.



Now let's compile it using the command line used in the article, and execute the program:



$ gcc -Wall -o example.elf example.c
$ ./example.elf
[*] you ran this binary!


As we said, only main() was executed. Now let's open the binary in radare2 to see the magic happens.





radare2 time!



Finding the address of the function



As you requested, we want to modify the entry point of the binary by modifying the pointed address in the elf header to be our never_call function. So first, we need to find the address of never_call in the binary.



$ r2 example.elf
[0x00000530]> f~never_call
0x0000063a 19 sym.never_call


We can see that the function never_call is at address 0x0000063a. As you probably know by now, the f command is used to list the flags that was marked by radare2, this including symbols as functions names. Then, we used ~ which is r2's internal grep and grepped for the relevant function.



Parsing the ELF Header



First, we need to seek to address 0 using s 0 and then and only then we can parse the header with a new command pf. The command pf is used to print formatted data such as structures, enums, and types. Let's load the format definition for elf64 using pfo elf64 and use the pf. command to list the format definitions:



[0x00002400]> s 0        # Seek to pos 0 in the binary

[0x00000000]> pfo elf64 # Load a Format Definition File for elf

[0x00000000]> pf.
pf.elf_header [16]z[2]E[2]Exqqqxwwwwww ident (elf_type)type (elf_machine)machine version entry phoff shoff flags ehsize phentsize phnum shentsize shnum shstrndx

pf.elf_phdr [4]E[4]Eqqqqqq (elf_p_type)type (elf_p_flags)flags offset vaddr paddr filesz memsz align

pf.elf_shdr x[4]E[8]Eqqqxxqq name (elf_s_type)type (elf_s_flags_64)flags addr offset size link info addralign entsize


One of the loaded definitions is the elf_header which holds the structure for the elf64 header. We can print the header like this:



[0x00000000]> pf.elf_header
ident : 0x00000000 = .ELF...
type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
version : 0x00000014 = 0x00000001
entry : 0x00000018 = (qword)0x0000000000000530
phoff : 0x00000020 = (qword)0x0000000000000040
shoff : 0x00000028 = (qword)0x0000000000001948
flags : 0x00000030 = 0x00000000
ehsize : 0x00000034 = 0x0040
phentsize : 0x00000036 = 0x0038
phnum : 0x00000038 = 0x0009
shentsize : 0x0000003a = 0x0040
shnum : 0x0000003c = 0x001d
shstrndx : 0x0000003e = 0x001c


As you can see, radare2 printed the elf64 header in a readable format so now we can see that entry, at 0x18, points to 0x530 which is our original entrypoint function. We can verify it by using ie, a radare2 command to print the entrypooint:



[0x00000000]> ie
[Entrypoints]
vaddr=0x00000530 paddr=0x00000530 baddr=0x00000000 laddr=0x00000000 haddr=0x00000018 hvaddr=0x00000018 type=program


Indeed, you can see that the entry point is 0x530 and the haddr, which is the header address, is 0x18.



Modifying the entry point



In order to modify this entry, we would need to open the file in writing mode. We can simply execute oo+ from our current session in order to re-open the file in write mode, or use the -w argument to radare2.



Then, we can simply use the pf command to write to the parsed structure the address of never_call function.



[0x00000000]> oo+
[0x00000000]> pf.elf_header.entry=0x0000063a
wv8 0x0000063a @ 0x00000018


This printed us a radare2 command to execute which will modify this address in the header. We can either execute it ourselves or use the . command to "interpret the output of the command as r2 commands".



So instead of executing wv8 ..., we will simply do:



[0x00000000]> .pf.elf_header.entry=0x0000063a


And now entry should be overridden with 0x63a which is our never_call function.



[0x00000000]> pf.elf_header
ident : 0x00000000 = .ELF...
type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
version : 0x00000014 = 0x00000001
entry : 0x00000018 = (qword)0x000000000000063a
phoff : 0x00000020 = (qword)0x0000000000000040
shoff : 0x00000028 = (qword)0x0000000000001948
flags : 0x00000030 = 0x00000000
ehsize : 0x00000034 = 0x0040
phentsize : 0x00000036 = 0x0038
phnum : 0x00000038 = 0x0009
shentsize : 0x0000003a = 0x0040
shnum : 0x0000003c = 0x001d
shstrndx : 0x0000003e = 0x001c

[0x00000000]> pf.elf_header.entry
entry : 0x00000018 = (qword)0x000000000000063a


Executing



Great! We can now exit radare and execute the program.



$ ./example.elf
[*] wow how did you manage to call this?




Last words



This long answer explained every step in the way but can really be narrowed to a simple command .pf.elf_header.entry=0x0000063a which sets the entry in the elf header to be the desired address. In the TL;DR version I demonstrated the use of -w to open the binary in write-mode and the use of -nn to load the binary structure (pfo elf64, etc...). So simply, opening radare2 like this r2 -w -nn example.elf and executing .pf.elf_header.entry=<address> would solve your problem.



Don't be afraid to ask how to do things in radare2. Although it is quite a scary framework, it is really powerful and with proper knowledge, can do much more things than seems like at first.



Read more




  • radare.today | Parsing a fileformat with radare2

  • r2book | Types






share|improve this answer



















  • 1




    Wow, this is really cool. From the UI standpoint, it would be nice if the .pf.elf_header.entry=0x0000063a didn't write to $$ but to @ 0. Got it right the second time though.
    – Evan Carroll
    Nov 20 at 9:46












  • I just used this to answer another question on the site, thanks again for answering all my questions on re.se. I'll keep them coming. =) reverseengineering.stackexchange.com/a/19936/22669
    – Evan Carroll
    Nov 20 at 22:58


















up vote
2
down vote













I don't think this feature is supported according to the source code.
Edit: I was wrong, sorry about that.



However, if you really need a library/tool to do that, I recommend LIEF.






share|improve this answer










New contributor




wisk is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.


















    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "489"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    noCode: true, onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2freverseengineering.stackexchange.com%2fquestions%2f19921%2fwriting-elf-headers-in-radare%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    12
    down vote



    accepted










    Yes, obviously you can. radare2 has built-in features to handle binary headers. This including reading, parsing and modifying the headers of the binary. And this is not different for elf or pe files, it will work great with both.



    TL;DR



    $ ./example.elf
    [*] you ran this binary!

    $ r2 -w -nn example.elf
    [0x00000000]> .pf.elf_header.entry=0x0000063a
    [0x00000000]> q

    $ ./example.elf
    [*] wow how did you manage to call this?




    Creating our test file



    As described in the article you linked in your question, it is easy to create a binary with a function that should never be executed under regular circumstances. Here's the exact code that was used in the linked article:



    $ cat example.c

    #include <stdio.h>


    void never_call (void) {
    printf ("[*] wow how did you manage to call this?n");
    return;
    }

    int main (int argc, char **argv) {
    printf ("[*] you ran this binary!n");
    return 0;
    }


    As you can see, the function never_call would, well... never be called. The program would execute the entrypoint which would execute the main function and will return.



    Now let's compile it using the command line used in the article, and execute the program:



    $ gcc -Wall -o example.elf example.c
    $ ./example.elf
    [*] you ran this binary!


    As we said, only main() was executed. Now let's open the binary in radare2 to see the magic happens.





    radare2 time!



    Finding the address of the function



    As you requested, we want to modify the entry point of the binary by modifying the pointed address in the elf header to be our never_call function. So first, we need to find the address of never_call in the binary.



    $ r2 example.elf
    [0x00000530]> f~never_call
    0x0000063a 19 sym.never_call


    We can see that the function never_call is at address 0x0000063a. As you probably know by now, the f command is used to list the flags that was marked by radare2, this including symbols as functions names. Then, we used ~ which is r2's internal grep and grepped for the relevant function.



    Parsing the ELF Header



    First, we need to seek to address 0 using s 0 and then and only then we can parse the header with a new command pf. The command pf is used to print formatted data such as structures, enums, and types. Let's load the format definition for elf64 using pfo elf64 and use the pf. command to list the format definitions:



    [0x00002400]> s 0        # Seek to pos 0 in the binary

    [0x00000000]> pfo elf64 # Load a Format Definition File for elf

    [0x00000000]> pf.
    pf.elf_header [16]z[2]E[2]Exqqqxwwwwww ident (elf_type)type (elf_machine)machine version entry phoff shoff flags ehsize phentsize phnum shentsize shnum shstrndx

    pf.elf_phdr [4]E[4]Eqqqqqq (elf_p_type)type (elf_p_flags)flags offset vaddr paddr filesz memsz align

    pf.elf_shdr x[4]E[8]Eqqqxxqq name (elf_s_type)type (elf_s_flags_64)flags addr offset size link info addralign entsize


    One of the loaded definitions is the elf_header which holds the structure for the elf64 header. We can print the header like this:



    [0x00000000]> pf.elf_header
    ident : 0x00000000 = .ELF...
    type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
    machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
    version : 0x00000014 = 0x00000001
    entry : 0x00000018 = (qword)0x0000000000000530
    phoff : 0x00000020 = (qword)0x0000000000000040
    shoff : 0x00000028 = (qword)0x0000000000001948
    flags : 0x00000030 = 0x00000000
    ehsize : 0x00000034 = 0x0040
    phentsize : 0x00000036 = 0x0038
    phnum : 0x00000038 = 0x0009
    shentsize : 0x0000003a = 0x0040
    shnum : 0x0000003c = 0x001d
    shstrndx : 0x0000003e = 0x001c


    As you can see, radare2 printed the elf64 header in a readable format so now we can see that entry, at 0x18, points to 0x530 which is our original entrypoint function. We can verify it by using ie, a radare2 command to print the entrypooint:



    [0x00000000]> ie
    [Entrypoints]
    vaddr=0x00000530 paddr=0x00000530 baddr=0x00000000 laddr=0x00000000 haddr=0x00000018 hvaddr=0x00000018 type=program


    Indeed, you can see that the entry point is 0x530 and the haddr, which is the header address, is 0x18.



    Modifying the entry point



    In order to modify this entry, we would need to open the file in writing mode. We can simply execute oo+ from our current session in order to re-open the file in write mode, or use the -w argument to radare2.



    Then, we can simply use the pf command to write to the parsed structure the address of never_call function.



    [0x00000000]> oo+
    [0x00000000]> pf.elf_header.entry=0x0000063a
    wv8 0x0000063a @ 0x00000018


    This printed us a radare2 command to execute which will modify this address in the header. We can either execute it ourselves or use the . command to "interpret the output of the command as r2 commands".



    So instead of executing wv8 ..., we will simply do:



    [0x00000000]> .pf.elf_header.entry=0x0000063a


    And now entry should be overridden with 0x63a which is our never_call function.



    [0x00000000]> pf.elf_header
    ident : 0x00000000 = .ELF...
    type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
    machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
    version : 0x00000014 = 0x00000001
    entry : 0x00000018 = (qword)0x000000000000063a
    phoff : 0x00000020 = (qword)0x0000000000000040
    shoff : 0x00000028 = (qword)0x0000000000001948
    flags : 0x00000030 = 0x00000000
    ehsize : 0x00000034 = 0x0040
    phentsize : 0x00000036 = 0x0038
    phnum : 0x00000038 = 0x0009
    shentsize : 0x0000003a = 0x0040
    shnum : 0x0000003c = 0x001d
    shstrndx : 0x0000003e = 0x001c

    [0x00000000]> pf.elf_header.entry
    entry : 0x00000018 = (qword)0x000000000000063a


    Executing



    Great! We can now exit radare and execute the program.



    $ ./example.elf
    [*] wow how did you manage to call this?




    Last words



    This long answer explained every step in the way but can really be narrowed to a simple command .pf.elf_header.entry=0x0000063a which sets the entry in the elf header to be the desired address. In the TL;DR version I demonstrated the use of -w to open the binary in write-mode and the use of -nn to load the binary structure (pfo elf64, etc...). So simply, opening radare2 like this r2 -w -nn example.elf and executing .pf.elf_header.entry=<address> would solve your problem.



    Don't be afraid to ask how to do things in radare2. Although it is quite a scary framework, it is really powerful and with proper knowledge, can do much more things than seems like at first.



    Read more




    • radare.today | Parsing a fileformat with radare2

    • r2book | Types






    share|improve this answer



















    • 1




      Wow, this is really cool. From the UI standpoint, it would be nice if the .pf.elf_header.entry=0x0000063a didn't write to $$ but to @ 0. Got it right the second time though.
      – Evan Carroll
      Nov 20 at 9:46












    • I just used this to answer another question on the site, thanks again for answering all my questions on re.se. I'll keep them coming. =) reverseengineering.stackexchange.com/a/19936/22669
      – Evan Carroll
      Nov 20 at 22:58















    up vote
    12
    down vote



    accepted










    Yes, obviously you can. radare2 has built-in features to handle binary headers. This including reading, parsing and modifying the headers of the binary. And this is not different for elf or pe files, it will work great with both.



    TL;DR



    $ ./example.elf
    [*] you ran this binary!

    $ r2 -w -nn example.elf
    [0x00000000]> .pf.elf_header.entry=0x0000063a
    [0x00000000]> q

    $ ./example.elf
    [*] wow how did you manage to call this?




    Creating our test file



    As described in the article you linked in your question, it is easy to create a binary with a function that should never be executed under regular circumstances. Here's the exact code that was used in the linked article:



    $ cat example.c

    #include <stdio.h>


    void never_call (void) {
    printf ("[*] wow how did you manage to call this?n");
    return;
    }

    int main (int argc, char **argv) {
    printf ("[*] you ran this binary!n");
    return 0;
    }


    As you can see, the function never_call would, well... never be called. The program would execute the entrypoint which would execute the main function and will return.



    Now let's compile it using the command line used in the article, and execute the program:



    $ gcc -Wall -o example.elf example.c
    $ ./example.elf
    [*] you ran this binary!


    As we said, only main() was executed. Now let's open the binary in radare2 to see the magic happens.





    radare2 time!



    Finding the address of the function



    As you requested, we want to modify the entry point of the binary by modifying the pointed address in the elf header to be our never_call function. So first, we need to find the address of never_call in the binary.



    $ r2 example.elf
    [0x00000530]> f~never_call
    0x0000063a 19 sym.never_call


    We can see that the function never_call is at address 0x0000063a. As you probably know by now, the f command is used to list the flags that was marked by radare2, this including symbols as functions names. Then, we used ~ which is r2's internal grep and grepped for the relevant function.



    Parsing the ELF Header



    First, we need to seek to address 0 using s 0 and then and only then we can parse the header with a new command pf. The command pf is used to print formatted data such as structures, enums, and types. Let's load the format definition for elf64 using pfo elf64 and use the pf. command to list the format definitions:



    [0x00002400]> s 0        # Seek to pos 0 in the binary

    [0x00000000]> pfo elf64 # Load a Format Definition File for elf

    [0x00000000]> pf.
    pf.elf_header [16]z[2]E[2]Exqqqxwwwwww ident (elf_type)type (elf_machine)machine version entry phoff shoff flags ehsize phentsize phnum shentsize shnum shstrndx

    pf.elf_phdr [4]E[4]Eqqqqqq (elf_p_type)type (elf_p_flags)flags offset vaddr paddr filesz memsz align

    pf.elf_shdr x[4]E[8]Eqqqxxqq name (elf_s_type)type (elf_s_flags_64)flags addr offset size link info addralign entsize


    One of the loaded definitions is the elf_header which holds the structure for the elf64 header. We can print the header like this:



    [0x00000000]> pf.elf_header
    ident : 0x00000000 = .ELF...
    type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
    machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
    version : 0x00000014 = 0x00000001
    entry : 0x00000018 = (qword)0x0000000000000530
    phoff : 0x00000020 = (qword)0x0000000000000040
    shoff : 0x00000028 = (qword)0x0000000000001948
    flags : 0x00000030 = 0x00000000
    ehsize : 0x00000034 = 0x0040
    phentsize : 0x00000036 = 0x0038
    phnum : 0x00000038 = 0x0009
    shentsize : 0x0000003a = 0x0040
    shnum : 0x0000003c = 0x001d
    shstrndx : 0x0000003e = 0x001c


    As you can see, radare2 printed the elf64 header in a readable format so now we can see that entry, at 0x18, points to 0x530 which is our original entrypoint function. We can verify it by using ie, a radare2 command to print the entrypooint:



    [0x00000000]> ie
    [Entrypoints]
    vaddr=0x00000530 paddr=0x00000530 baddr=0x00000000 laddr=0x00000000 haddr=0x00000018 hvaddr=0x00000018 type=program


    Indeed, you can see that the entry point is 0x530 and the haddr, which is the header address, is 0x18.



    Modifying the entry point



    In order to modify this entry, we would need to open the file in writing mode. We can simply execute oo+ from our current session in order to re-open the file in write mode, or use the -w argument to radare2.



    Then, we can simply use the pf command to write to the parsed structure the address of never_call function.



    [0x00000000]> oo+
    [0x00000000]> pf.elf_header.entry=0x0000063a
    wv8 0x0000063a @ 0x00000018


    This printed us a radare2 command to execute which will modify this address in the header. We can either execute it ourselves or use the . command to "interpret the output of the command as r2 commands".



    So instead of executing wv8 ..., we will simply do:



    [0x00000000]> .pf.elf_header.entry=0x0000063a


    And now entry should be overridden with 0x63a which is our never_call function.



    [0x00000000]> pf.elf_header
    ident : 0x00000000 = .ELF...
    type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
    machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
    version : 0x00000014 = 0x00000001
    entry : 0x00000018 = (qword)0x000000000000063a
    phoff : 0x00000020 = (qword)0x0000000000000040
    shoff : 0x00000028 = (qword)0x0000000000001948
    flags : 0x00000030 = 0x00000000
    ehsize : 0x00000034 = 0x0040
    phentsize : 0x00000036 = 0x0038
    phnum : 0x00000038 = 0x0009
    shentsize : 0x0000003a = 0x0040
    shnum : 0x0000003c = 0x001d
    shstrndx : 0x0000003e = 0x001c

    [0x00000000]> pf.elf_header.entry
    entry : 0x00000018 = (qword)0x000000000000063a


    Executing



    Great! We can now exit radare and execute the program.



    $ ./example.elf
    [*] wow how did you manage to call this?




    Last words



    This long answer explained every step in the way but can really be narrowed to a simple command .pf.elf_header.entry=0x0000063a which sets the entry in the elf header to be the desired address. In the TL;DR version I demonstrated the use of -w to open the binary in write-mode and the use of -nn to load the binary structure (pfo elf64, etc...). So simply, opening radare2 like this r2 -w -nn example.elf and executing .pf.elf_header.entry=<address> would solve your problem.



    Don't be afraid to ask how to do things in radare2. Although it is quite a scary framework, it is really powerful and with proper knowledge, can do much more things than seems like at first.



    Read more




    • radare.today | Parsing a fileformat with radare2

    • r2book | Types






    share|improve this answer



















    • 1




      Wow, this is really cool. From the UI standpoint, it would be nice if the .pf.elf_header.entry=0x0000063a didn't write to $$ but to @ 0. Got it right the second time though.
      – Evan Carroll
      Nov 20 at 9:46












    • I just used this to answer another question on the site, thanks again for answering all my questions on re.se. I'll keep them coming. =) reverseengineering.stackexchange.com/a/19936/22669
      – Evan Carroll
      Nov 20 at 22:58













    up vote
    12
    down vote



    accepted







    up vote
    12
    down vote



    accepted






    Yes, obviously you can. radare2 has built-in features to handle binary headers. This including reading, parsing and modifying the headers of the binary. And this is not different for elf or pe files, it will work great with both.



    TL;DR



    $ ./example.elf
    [*] you ran this binary!

    $ r2 -w -nn example.elf
    [0x00000000]> .pf.elf_header.entry=0x0000063a
    [0x00000000]> q

    $ ./example.elf
    [*] wow how did you manage to call this?




    Creating our test file



    As described in the article you linked in your question, it is easy to create a binary with a function that should never be executed under regular circumstances. Here's the exact code that was used in the linked article:



    $ cat example.c

    #include <stdio.h>


    void never_call (void) {
    printf ("[*] wow how did you manage to call this?n");
    return;
    }

    int main (int argc, char **argv) {
    printf ("[*] you ran this binary!n");
    return 0;
    }


    As you can see, the function never_call would, well... never be called. The program would execute the entrypoint which would execute the main function and will return.



    Now let's compile it using the command line used in the article, and execute the program:



    $ gcc -Wall -o example.elf example.c
    $ ./example.elf
    [*] you ran this binary!


    As we said, only main() was executed. Now let's open the binary in radare2 to see the magic happens.





    radare2 time!



    Finding the address of the function



    As you requested, we want to modify the entry point of the binary by modifying the pointed address in the elf header to be our never_call function. So first, we need to find the address of never_call in the binary.



    $ r2 example.elf
    [0x00000530]> f~never_call
    0x0000063a 19 sym.never_call


    We can see that the function never_call is at address 0x0000063a. As you probably know by now, the f command is used to list the flags that was marked by radare2, this including symbols as functions names. Then, we used ~ which is r2's internal grep and grepped for the relevant function.



    Parsing the ELF Header



    First, we need to seek to address 0 using s 0 and then and only then we can parse the header with a new command pf. The command pf is used to print formatted data such as structures, enums, and types. Let's load the format definition for elf64 using pfo elf64 and use the pf. command to list the format definitions:



    [0x00002400]> s 0        # Seek to pos 0 in the binary

    [0x00000000]> pfo elf64 # Load a Format Definition File for elf

    [0x00000000]> pf.
    pf.elf_header [16]z[2]E[2]Exqqqxwwwwww ident (elf_type)type (elf_machine)machine version entry phoff shoff flags ehsize phentsize phnum shentsize shnum shstrndx

    pf.elf_phdr [4]E[4]Eqqqqqq (elf_p_type)type (elf_p_flags)flags offset vaddr paddr filesz memsz align

    pf.elf_shdr x[4]E[8]Eqqqxxqq name (elf_s_type)type (elf_s_flags_64)flags addr offset size link info addralign entsize


    One of the loaded definitions is the elf_header which holds the structure for the elf64 header. We can print the header like this:



    [0x00000000]> pf.elf_header
    ident : 0x00000000 = .ELF...
    type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
    machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
    version : 0x00000014 = 0x00000001
    entry : 0x00000018 = (qword)0x0000000000000530
    phoff : 0x00000020 = (qword)0x0000000000000040
    shoff : 0x00000028 = (qword)0x0000000000001948
    flags : 0x00000030 = 0x00000000
    ehsize : 0x00000034 = 0x0040
    phentsize : 0x00000036 = 0x0038
    phnum : 0x00000038 = 0x0009
    shentsize : 0x0000003a = 0x0040
    shnum : 0x0000003c = 0x001d
    shstrndx : 0x0000003e = 0x001c


    As you can see, radare2 printed the elf64 header in a readable format so now we can see that entry, at 0x18, points to 0x530 which is our original entrypoint function. We can verify it by using ie, a radare2 command to print the entrypooint:



    [0x00000000]> ie
    [Entrypoints]
    vaddr=0x00000530 paddr=0x00000530 baddr=0x00000000 laddr=0x00000000 haddr=0x00000018 hvaddr=0x00000018 type=program


    Indeed, you can see that the entry point is 0x530 and the haddr, which is the header address, is 0x18.



    Modifying the entry point



    In order to modify this entry, we would need to open the file in writing mode. We can simply execute oo+ from our current session in order to re-open the file in write mode, or use the -w argument to radare2.



    Then, we can simply use the pf command to write to the parsed structure the address of never_call function.



    [0x00000000]> oo+
    [0x00000000]> pf.elf_header.entry=0x0000063a
    wv8 0x0000063a @ 0x00000018


    This printed us a radare2 command to execute which will modify this address in the header. We can either execute it ourselves or use the . command to "interpret the output of the command as r2 commands".



    So instead of executing wv8 ..., we will simply do:



    [0x00000000]> .pf.elf_header.entry=0x0000063a


    And now entry should be overridden with 0x63a which is our never_call function.



    [0x00000000]> pf.elf_header
    ident : 0x00000000 = .ELF...
    type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
    machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
    version : 0x00000014 = 0x00000001
    entry : 0x00000018 = (qword)0x000000000000063a
    phoff : 0x00000020 = (qword)0x0000000000000040
    shoff : 0x00000028 = (qword)0x0000000000001948
    flags : 0x00000030 = 0x00000000
    ehsize : 0x00000034 = 0x0040
    phentsize : 0x00000036 = 0x0038
    phnum : 0x00000038 = 0x0009
    shentsize : 0x0000003a = 0x0040
    shnum : 0x0000003c = 0x001d
    shstrndx : 0x0000003e = 0x001c

    [0x00000000]> pf.elf_header.entry
    entry : 0x00000018 = (qword)0x000000000000063a


    Executing



    Great! We can now exit radare and execute the program.



    $ ./example.elf
    [*] wow how did you manage to call this?




    Last words



    This long answer explained every step in the way but can really be narrowed to a simple command .pf.elf_header.entry=0x0000063a which sets the entry in the elf header to be the desired address. In the TL;DR version I demonstrated the use of -w to open the binary in write-mode and the use of -nn to load the binary structure (pfo elf64, etc...). So simply, opening radare2 like this r2 -w -nn example.elf and executing .pf.elf_header.entry=<address> would solve your problem.



    Don't be afraid to ask how to do things in radare2. Although it is quite a scary framework, it is really powerful and with proper knowledge, can do much more things than seems like at first.



    Read more




    • radare.today | Parsing a fileformat with radare2

    • r2book | Types






    share|improve this answer














    Yes, obviously you can. radare2 has built-in features to handle binary headers. This including reading, parsing and modifying the headers of the binary. And this is not different for elf or pe files, it will work great with both.



    TL;DR



    $ ./example.elf
    [*] you ran this binary!

    $ r2 -w -nn example.elf
    [0x00000000]> .pf.elf_header.entry=0x0000063a
    [0x00000000]> q

    $ ./example.elf
    [*] wow how did you manage to call this?




    Creating our test file



    As described in the article you linked in your question, it is easy to create a binary with a function that should never be executed under regular circumstances. Here's the exact code that was used in the linked article:



    $ cat example.c

    #include <stdio.h>


    void never_call (void) {
    printf ("[*] wow how did you manage to call this?n");
    return;
    }

    int main (int argc, char **argv) {
    printf ("[*] you ran this binary!n");
    return 0;
    }


    As you can see, the function never_call would, well... never be called. The program would execute the entrypoint which would execute the main function and will return.



    Now let's compile it using the command line used in the article, and execute the program:



    $ gcc -Wall -o example.elf example.c
    $ ./example.elf
    [*] you ran this binary!


    As we said, only main() was executed. Now let's open the binary in radare2 to see the magic happens.





    radare2 time!



    Finding the address of the function



    As you requested, we want to modify the entry point of the binary by modifying the pointed address in the elf header to be our never_call function. So first, we need to find the address of never_call in the binary.



    $ r2 example.elf
    [0x00000530]> f~never_call
    0x0000063a 19 sym.never_call


    We can see that the function never_call is at address 0x0000063a. As you probably know by now, the f command is used to list the flags that was marked by radare2, this including symbols as functions names. Then, we used ~ which is r2's internal grep and grepped for the relevant function.



    Parsing the ELF Header



    First, we need to seek to address 0 using s 0 and then and only then we can parse the header with a new command pf. The command pf is used to print formatted data such as structures, enums, and types. Let's load the format definition for elf64 using pfo elf64 and use the pf. command to list the format definitions:



    [0x00002400]> s 0        # Seek to pos 0 in the binary

    [0x00000000]> pfo elf64 # Load a Format Definition File for elf

    [0x00000000]> pf.
    pf.elf_header [16]z[2]E[2]Exqqqxwwwwww ident (elf_type)type (elf_machine)machine version entry phoff shoff flags ehsize phentsize phnum shentsize shnum shstrndx

    pf.elf_phdr [4]E[4]Eqqqqqq (elf_p_type)type (elf_p_flags)flags offset vaddr paddr filesz memsz align

    pf.elf_shdr x[4]E[8]Eqqqxxqq name (elf_s_type)type (elf_s_flags_64)flags addr offset size link info addralign entsize


    One of the loaded definitions is the elf_header which holds the structure for the elf64 header. We can print the header like this:



    [0x00000000]> pf.elf_header
    ident : 0x00000000 = .ELF...
    type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
    machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
    version : 0x00000014 = 0x00000001
    entry : 0x00000018 = (qword)0x0000000000000530
    phoff : 0x00000020 = (qword)0x0000000000000040
    shoff : 0x00000028 = (qword)0x0000000000001948
    flags : 0x00000030 = 0x00000000
    ehsize : 0x00000034 = 0x0040
    phentsize : 0x00000036 = 0x0038
    phnum : 0x00000038 = 0x0009
    shentsize : 0x0000003a = 0x0040
    shnum : 0x0000003c = 0x001d
    shstrndx : 0x0000003e = 0x001c


    As you can see, radare2 printed the elf64 header in a readable format so now we can see that entry, at 0x18, points to 0x530 which is our original entrypoint function. We can verify it by using ie, a radare2 command to print the entrypooint:



    [0x00000000]> ie
    [Entrypoints]
    vaddr=0x00000530 paddr=0x00000530 baddr=0x00000000 laddr=0x00000000 haddr=0x00000018 hvaddr=0x00000018 type=program


    Indeed, you can see that the entry point is 0x530 and the haddr, which is the header address, is 0x18.



    Modifying the entry point



    In order to modify this entry, we would need to open the file in writing mode. We can simply execute oo+ from our current session in order to re-open the file in write mode, or use the -w argument to radare2.



    Then, we can simply use the pf command to write to the parsed structure the address of never_call function.



    [0x00000000]> oo+
    [0x00000000]> pf.elf_header.entry=0x0000063a
    wv8 0x0000063a @ 0x00000018


    This printed us a radare2 command to execute which will modify this address in the header. We can either execute it ourselves or use the . command to "interpret the output of the command as r2 commands".



    So instead of executing wv8 ..., we will simply do:



    [0x00000000]> .pf.elf_header.entry=0x0000063a


    And now entry should be overridden with 0x63a which is our never_call function.



    [0x00000000]> pf.elf_header
    ident : 0x00000000 = .ELF...
    type : 0x00000010 = type (enum elf_type) = 0x3 ; ET_DYN
    machine : 0x00000012 = machine (enum elf_machine) = 0x3e ; EM_AMD64
    version : 0x00000014 = 0x00000001
    entry : 0x00000018 = (qword)0x000000000000063a
    phoff : 0x00000020 = (qword)0x0000000000000040
    shoff : 0x00000028 = (qword)0x0000000000001948
    flags : 0x00000030 = 0x00000000
    ehsize : 0x00000034 = 0x0040
    phentsize : 0x00000036 = 0x0038
    phnum : 0x00000038 = 0x0009
    shentsize : 0x0000003a = 0x0040
    shnum : 0x0000003c = 0x001d
    shstrndx : 0x0000003e = 0x001c

    [0x00000000]> pf.elf_header.entry
    entry : 0x00000018 = (qword)0x000000000000063a


    Executing



    Great! We can now exit radare and execute the program.



    $ ./example.elf
    [*] wow how did you manage to call this?




    Last words



    This long answer explained every step in the way but can really be narrowed to a simple command .pf.elf_header.entry=0x0000063a which sets the entry in the elf header to be the desired address. In the TL;DR version I demonstrated the use of -w to open the binary in write-mode and the use of -nn to load the binary structure (pfo elf64, etc...). So simply, opening radare2 like this r2 -w -nn example.elf and executing .pf.elf_header.entry=<address> would solve your problem.



    Don't be afraid to ask how to do things in radare2. Although it is quite a scary framework, it is really powerful and with proper knowledge, can do much more things than seems like at first.



    Read more




    • radare.today | Parsing a fileformat with radare2

    • r2book | Types







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 21 at 6:34









    Evan Carroll

    71716




    71716










    answered Nov 20 at 7:36









    Megabeets

    6,2681835




    6,2681835








    • 1




      Wow, this is really cool. From the UI standpoint, it would be nice if the .pf.elf_header.entry=0x0000063a didn't write to $$ but to @ 0. Got it right the second time though.
      – Evan Carroll
      Nov 20 at 9:46












    • I just used this to answer another question on the site, thanks again for answering all my questions on re.se. I'll keep them coming. =) reverseengineering.stackexchange.com/a/19936/22669
      – Evan Carroll
      Nov 20 at 22:58














    • 1




      Wow, this is really cool. From the UI standpoint, it would be nice if the .pf.elf_header.entry=0x0000063a didn't write to $$ but to @ 0. Got it right the second time though.
      – Evan Carroll
      Nov 20 at 9:46












    • I just used this to answer another question on the site, thanks again for answering all my questions on re.se. I'll keep them coming. =) reverseengineering.stackexchange.com/a/19936/22669
      – Evan Carroll
      Nov 20 at 22:58








    1




    1




    Wow, this is really cool. From the UI standpoint, it would be nice if the .pf.elf_header.entry=0x0000063a didn't write to $$ but to @ 0. Got it right the second time though.
    – Evan Carroll
    Nov 20 at 9:46






    Wow, this is really cool. From the UI standpoint, it would be nice if the .pf.elf_header.entry=0x0000063a didn't write to $$ but to @ 0. Got it right the second time though.
    – Evan Carroll
    Nov 20 at 9:46














    I just used this to answer another question on the site, thanks again for answering all my questions on re.se. I'll keep them coming. =) reverseengineering.stackexchange.com/a/19936/22669
    – Evan Carroll
    Nov 20 at 22:58




    I just used this to answer another question on the site, thanks again for answering all my questions on re.se. I'll keep them coming. =) reverseengineering.stackexchange.com/a/19936/22669
    – Evan Carroll
    Nov 20 at 22:58










    up vote
    2
    down vote













    I don't think this feature is supported according to the source code.
    Edit: I was wrong, sorry about that.



    However, if you really need a library/tool to do that, I recommend LIEF.






    share|improve this answer










    New contributor




    wisk is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






















      up vote
      2
      down vote













      I don't think this feature is supported according to the source code.
      Edit: I was wrong, sorry about that.



      However, if you really need a library/tool to do that, I recommend LIEF.






      share|improve this answer










      New contributor




      wisk is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.




















        up vote
        2
        down vote










        up vote
        2
        down vote









        I don't think this feature is supported according to the source code.
        Edit: I was wrong, sorry about that.



        However, if you really need a library/tool to do that, I recommend LIEF.






        share|improve this answer










        New contributor




        wisk is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        I don't think this feature is supported according to the source code.
        Edit: I was wrong, sorry about that.



        However, if you really need a library/tool to do that, I recommend LIEF.







        share|improve this answer










        New contributor




        wisk is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        share|improve this answer



        share|improve this answer








        edited Nov 20 at 19:43





















        New contributor




        wisk is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.









        answered Nov 19 at 23:36









        wisk

        493




        493




        New contributor




        wisk is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.





        New contributor





        wisk is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






        wisk is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
        Check out our Code of Conduct.






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2freverseengineering.stackexchange.com%2fquestions%2f19921%2fwriting-elf-headers-in-radare%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            AnyDesk - Fatal Program Failure

            How to calibrate 16:9 built-in touch-screen to a 4:3 resolution?

            QoS: MAC-Priority for clients behind a repeater