Table of Contents for
Learning Linux Binary Analysis

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Learning Linux Binary Analysis by Ryan elfmaster O'Neill Published by Packt Publishing, 2016
  1. Cover
  2. Table of Contents
  3. Learning Linux Binary Analysis
  4. Learning Linux Binary Analysis
  5. Credits
  6. About the Author
  7. Acknowledgments
  8. About the Reviewers
  9. www.PacktPub.com
  10. Preface
  11. What you need for this book
  12. Who this book is for
  13. Conventions
  14. Reader feedback
  15. Customer support
  16. 1. The Linux Environment and Its Tools
  17. Useful devices and files
  18. Linker-related environment points
  19. Summary
  20. 2. The ELF Binary Format
  21. ELF program headers
  22. ELF section headers
  23. ELF symbols
  24. ELF relocations
  25. ELF dynamic linking
  26. Coding an ELF Parser
  27. Summary
  28. 3. Linux Process Tracing
  29. ptrace requests
  30. The process register state and flags
  31. A simple ptrace-based debugger
  32. A simple ptrace debugger with process attach capabilities
  33. Advanced function-tracing software
  34. ptrace and forensic analysis
  35. Process image reconstruction – from the memory to the executable
  36. Code injection with ptrace
  37. Simple examples aren't always so trivial
  38. Demonstrating the code_inject tool
  39. A ptrace anti-debugging trick
  40. Summary
  41. 4. ELF Virus Technology �� Linux/Unix Viruses
  42. ELF virus engineering challenges
  43. ELF virus parasite infection methods
  44. The PT_NOTE to PT_LOAD conversion infection method
  45. Infecting control flow
  46. Process memory viruses and rootkits – remote code injection techniques
  47. ELF anti-debugging and packing techniques
  48. ELF virus detection and disinfection
  49. Summary
  50. 5. Linux Binary Protection
  51. Stub mechanics and the userland exec
  52. Other jobs performed by protector stubs
  53. Existing ELF binary protectors
  54. Downloading Maya-protected binaries
  55. Anti-debugging for binary protection
  56. Resistance to emulation
  57. Obfuscation methods
  58. Protecting control flow integrity
  59. Other resources
  60. Summary
  61. 6. ELF Binary Forensics in Linux
  62. Detecting other forms of control flow hijacking
  63. Identifying parasite code characteristics
  64. Checking the dynamic segment for DLL injection traces
  65. Identifying reverse text padding infections
  66. Identifying text segment padding infections
  67. Identifying protected binaries
  68. IDA Pro
  69. Summary
  70. 7. Process Memory Forensics
  71. Process memory infection
  72. Detecting the ET_DYN injection
  73. Linux ELF core files
  74. Summary
  75. 8. ECFS – Extended Core File Snapshot Technology
  76. The ECFS philosophy
  77. Getting started with ECFS
  78. libecfs – a library for parsing ECFS files
  79. readecfs
  80. Examining an infected process using ECFS
  81. The ECFS reference guide
  82. Process necromancy with ECFS
  83. Learning more about ECFS
  84. Summary
  85. 9. Linux /proc/kcore Analysis
  86. stock vmlinux has no symbols
  87. /proc/kcore and GDB exploration
  88. Direct sys_call_table modifications
  89. Kprobe rootkits
  90. Debug register rootkits – DRR
  91. VFS layer rootkits
  92. Other kernel infection techniques
  93. vmlinux and .altinstructions patching
  94. Using taskverse to see hidden processes
  95. Infected LKMs – kernel drivers
  96. Notes on /dev/kmem and /dev/mem
  97. /dev/mem
  98. K-ecfs – kernel ECFS
  99. Kernel hacking goodies
  100. Summary
  101. Index

Identifying parasite code characteristics

We just reviewed some common methods for hijacking execution flow. If you can identify where the execution flow points, you can typically identify some or all of the parasite code. In the section Detecting PLT/GOT hooks, we determined the location of the parasite code for the hijacked puts() function by simply locating the PLT/GOT entry that had been modified and seeing where that address pointed to, which, in that case, was to an appended page containing parasite code.

Parasite code can be qualified as code that is unnaturally inserted into the binary; in other words, it wasn't linked in by the actual ELF object linker. With that said, there are several characteristics that can sometimes be attributed to injected code, depending on the techniques used.

Position independent code (PIC) is often used for parasites so that it can be injected into any point of a binary or memory and still execute properly regardless of its position in memory. PIC parasites are easier to inject into an executable because the code can be inserted into the binary without having to consider handling relocations. In some cases, such as with my Linux padding Virus http://www.bitlackeys.org/projects/lpv.c, the parasite is compiled as an executable with the gcc-nostdlib flag. It is not compiled as position independent, but it has no libc linking, and special care is taken within the parasite code itself to dynamically resolve memory addresses with instruction-pointer relative computations.

In many cases, the parasite code is written purely in assembly language and is therefore in a sense more identifiable as being a potential parasite since it will look different from what the compiler produces. One of the giveaways with parasite code written in assembly is the way in which syscalls are handled. In C code, typically syscalls are called through libc functions that will invoke the actual syscall. Therefore, syscalls look just like regular dynamically linked functions. In handwritten assembly code, syscalls are usually invoked directly using either the Intel sysenter or syscall instructions, and sometimes even int 0x80 (which is now considered legacy). If syscall instructions are present, we may consider it a red flag.

Another red flag, especially when analyzing a remote process that may be infected, is to see int3 instructions that can serve many purposes such as passing control back to a tracing process that is performing the infection or, even more disturbing, the ability to trigger some type of anti-debugging mechanism within malware or a binary protector.

The following 32-bit code memory maps a shared library into a process and then passes control back to the tracer with an int3. Notice that int 0x80 is being used to invoke the syscalls. This shellcode is actually quite old; I wrote it in 2008. Typically, nowadays we want to use either the sysenter or syscall instruction to invoke a system call in Linux, but the int 0x80 will still work; it is just slower and therefore considered deprecated:

_start:
        jmp B
A:

        # fd = open("libtest.so.1.0", O_RDONLY);

        xorl %ecx, %ecx
        movb $5, %al
        popl %ebx
        xorl %ecx, %ecx
        int $0x80

        subl $24, %esp

        # mmap(0, 8192, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED, fd, 0);

        xorl %edx, %edx
        movl %edx, (%esp)
        movl $8192,4(%esp)
        movl $7, 8(%esp)
        movl $2, 12(%esp)
        movl %eax,16(%esp)
        movl %edx, 20(%esp)
        movl $90, %eax
        movl %esp, %ebx
        int $0x80

        int3
B:
        call A
        .string "/lib/libtest.so.1.0"

If you were to see this code inside an executable on disk or in memory, you should quickly come to the conclusion that it does not look like compiled code. One dead giveaway is the call/pop technique that is used to dynamically retrieve the address of /lib/libtest.so.1.0. The string is stored right after the call A instruction and therefore its address is pushed onto the stack, and then you can see that it gets popped into ebx, which is not conventional compiler code.

Note

This particular snippet was taken from a runtime virus I wrote in 2009. We will specifically get into the analysis of process memory in the next chapter.

For runtime analysis, the infection vectors are many, and we will cover more about parasite identification in memory when we get into Chapter 7, Process Memory Forensics.