[ News ] [ Paper Feed ] [ Issues ] [ Authors ] [ Archives ] [ Contact ]


..[ Phrack Magazine ]..
.:: Embedded ELF Debugging ::.

Issues: [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ 14 ] [ 15 ] [ 16 ] [ 17 ] [ 18 ] [ 19 ] [ 20 ] [ 21 ] [ 22 ] [ 23 ] [ 24 ] [ 25 ] [ 26 ] [ 27 ] [ 28 ] [ 29 ] [ 30 ] [ 31 ] [ 32 ] [ 33 ] [ 34 ] [ 35 ] [ 36 ] [ 37 ] [ 38 ] [ 39 ] [ 40 ] [ 41 ] [ 42 ] [ 43 ] [ 44 ] [ 45 ] [ 46 ] [ 47 ] [ 48 ] [ 49 ] [ 50 ] [ 51 ] [ 52 ] [ 53 ] [ 54 ] [ 55 ] [ 56 ] [ 57 ] [ 58 ] [ 59 ] [ 60 ] [ 61 ] [ 62 ] [ 63 ] [ 64 ] [ 65 ] [ 66 ] [ 67 ] [ 68 ] [ 69 ] [ 70 ]
Current issue : #63 | Release date : 2005-01-08 | Editor : Phrack Staff
IntroductionPhrack Staff
LoopbackPhrack Staff
LinenoisePhrack Staff
Phrack Prophile on TiagoPhrack Staff
OSX heap exploitation techniquesNemo
Hacking Windows CE (pocketpcs & others)San
Games with kernel Memory...FreeBSD Stylejkong
Raising The Bar For Windows Rootkit Detectionsherri sparks & jamie butler
Embedded ELF DebuggingELFsh crew
Hacking Grub for Fun & Profitcoolq
Advanced antiforensics : SELFripe & pluf
Process Dump and Binary Reconstructionilo
Next-Gen. Runtime Binary Encryptionzvrba
Shifting the Stack Pointerandrewg
NT Shellcode Prevention Demystifiedpiotr
PowerPC Cracking on OSX with GDBcurious
Hacking with Embedded Systemscawan
Process Hiding & The Linux Schedulerubra
Breaking Through a Firewallkotkrye
Phrack World NewsPhrack Staff
Title : Embedded ELF Debugging
Author : ELFsh crew
                             ==Phrack Inc.==

              Volume 0x0b, Issue 0x3f, Phile #0x09 of 0x14

|=------=[ Embedded ELF Debugging : the middle head of Cerberus ]=------=|
|=----------------------------------------------------------------------=|
|=------------=[ The ELF shell crew <elfsh@devhell.org> ]=--------------=|
|=----------------------------------------------------------------------=|


I. Hardened software debugging introduction
     a. Previous work & limits
     b. Beyond PaX and ptrace()		
     c.	Interface improvements
II. The embedded debugging playground
     a. In-process injection
     b. Alternate ondisk and memory ELF scripting (feat. linkmap)
     c. Real debugging : dumping, backtrace, breakpoints
     d. A note on dynamic analyzers generation 
III. Better multiarchitecture ELF redirections
     a. CFLOW: PaX-safe static functions redirection		
     b. ALTPLT technique revised				
     c. ALTGOT technique : the RISC complement			
     d. EXTPLT technique : unknown function postlinking
     e. IA32, SPARC32/64, ALPHA64, MIPS32 compliant algorithms		 
V. Constrained Debugging
     a. ET_REL relocation in memory				
     b. ET_REL injection for Hardened Gentoo (ET_DYN + pie + ssp)
     c. Extending static executables				
     d. Architecture independant algorithms
VI. Past and present
VII. Greetings  
VIII. References



-------[ I. Hardened software debugging introduction
	 
	 
	      In the past, binary manipulation work has focussed on virii
	 writing, software cracking, backdoors deployment, or creation of 
	 tiny or obfuscated executables. Besides the tools from the GNU 
	 project such as the GNU binutils that includes the GNU debugger [1] 
	 (which focus more on portability than functionalities), no major 
	 binary manipulation framework does exist. For almost ten years, 
	 the ELF format has been a success and most UNIX Operating Systems 
	 and distributions rely on it. 

	 However, the existing tools do not take advantage of the format 
	 and most of the reverse engineering or debugging softwares are 
	 either very architecture specific, or simply do not care about 
	 binary internals for extracting and redirecting information.

	 Since our first published work on the ELF shell, we improved so
	 much the new framework that it is now time to publish a second
	 deep article focussing on advances in static and runtime	
	 ELF techniques. We will explain in great details the 8 new
	 binary manipulation functionalities that intersect with the 
	 existing reverse engineering methodology. Those techniques allow 
	 for a new type of approach on debugging and extending closed 
	 source software in hardened environments.

	 We worked on many architectures (x86, alpha, sparc, mips) and 
	 focussed on constrained environments where binaries are linked 
	 for including security protections (such as hardened gentoo 
	 binaries) in PaX [2] protected machines. It means that our 
	 debugger can stay safe if it is injected inside a (local or) 
	 remote process.


----[ A. Previous work & limits


	 In the first part of the Cerberus articles serie, we introduced 
	 a new residency technique called ET_REL injection. It consisted 
	 in compiling C code into relocatable (.o) files and injecting
	 them into existing closed source binary programs. This technique 
	 was proposed for INTEL and SPARC architectures on the ELF32 
	 format. 

	 We improved this technique so that both 32 and 64 bits binaries 
	 are supported so we added alpha64 and sparc64 support. We also 
	 worked on the MIPS r5000 architecture and now provide a nearly 
	 complete environment for it as well. We now also allow for ET_REL
	 injection into ET_DYN objects (shared libraries) so that our 
	 technique is compatible with fully randomized environments such 
	 as provided by Hardened Gentoo with the PaX protection enabled
	 on the Linux Operating System. We also worked on other OS such as
	 BSD based ones, Solaris, and HP-UX and the code was compiled and
	 tested regulary on those as well.

	 A major innovation of our binary manipulation based debugging 
	 framework is the absence of ptrace. We do not use kernel residency 
	 like in [8] so that even unprivilegied users can use this and it 
	 is not Operating System dependent.

	 Existing debuggers use to rely on the ptrace system call so that 
	 the debugger process can attach the debuggee program and enable 
	 various internal processes manipulations such as dumping memory, 
	 putting breakpoints, backtracing, and so on. We propose the same 
	 features without using the system call.
	 
	 The reasons why we do not use ptrace are multiple and simple. 
	 First of all, a lot of hardened or embedded systems do not 
	 implement it, or just disable it. That's the case for grsecurity 
	 based systems, production systems, or phone systems whoose 
	 Operating System is ELF based but without a ptrace interface. 

	 The second major reason for not using ptrace is the performance 
	 penalties of such a debugging system. We do not suffer from 
	 performance penalties since the debugger resides in the same 
	 process. We provide a full userland technique that does not have 
	 to access the kernel memory, thus it is useful in all stages of 
	 a penetration testing when debugging sensitive software on 
	 hardened environment is needed and no system update is possible. 

	 We allow for plain C code injection inside new binary files (in 
	 the static perspective) and processes (in the runtime mode) using 
	 a unified software. When requested, we only use ELF techniques that
	 reduce forensics evidences on the disk and only works in memory.


----[ B. Beyond PaX and ptrace


	 Another key point in our framework are the greatly improved 
	 redirection techniques. We can redirect almost all control flow, 
	 wether or not the function code is placed inside the binary 
	 itself (CFLOW technique) or in a library on which the binary 
	 depends (Our previous work presented new hijacking techniques 
	 such that ALTPLT). 

	 We improved this techniques and passed through many rewrites 
	 and now allow a complete architecture independant implementation. 
	 We completed ALTPLT by a new technique called ALTGOT so that 
	 hijacking a function and calling back the original copy from the 
	 hooking function is possible on Alpha and Mips RISC machines as 
	 well. 

	 We also created a new technique called EXTPLT which allow for 
	 unknown function (for which no dynamic linking information is 
	 available at all in the ELF file) using a new postlinking 
	 algorithm compatible with ET_EXEC and ET_DYN objets.


----[ C. Interface improvements


	 Our Embedded ELF debugger implementation is a prototype. 
	 Understand that it is really usable but we are still in the 
	 development process. All the code presented here is known to 
	 work. However we are not omniscient and you might encounter a 
	 problem. In that case, drop us an email so that we can figure 
	 out how to create a patch. 

	 The only assumption that we made is the ability to read the 
	 debuggee program. In all case, you can also debug in memory 
	 the unreadable binaries on disk by loading the debugger using
	 the LD_PRELOAD variable.  Nevertheless, e2dbg is enhanced
	 when binary files are readable. Because the debugger run in the 
	 same address space, you can still read memory [3] [4] and 
	 restore the binary program even though we do not implement it 
	 yet.
	 
	 The central communication language in the Embedded ELF Debugger 
	 (e2dbg) framework is the ELFsh scripting language. We augmented 
	 it with loop and conditional control flow, transparent support 
	 for lazy typed variables (like perl). The source command (for 
	 executing a script inside the current session) and user-defined 
	 macros (scriptdir command) are also supported.
	 
	 We also developed a peer2peer stack so called Distributed 
	 Update Management Protocol - DUMP - that allow for linking 
	 multiple debugger instances using the network, but this 
	 capability is not covered by the article. For completeness, we
	 now support multiusers (parallel or shared) sessions and 
	 environment swapping using the workspace command.

	 We will go through the use of such interface in the first part 
	 of the paper. In the second part, we give technical details 
	 about the implementation of such features on multiple 
	 architectures. The last part is dedicated to the most recent 
	 and advanced techniques we developed in the last weeks for
	 constrained debugging in protected binaries. The last algorithms
	 of the paper are architecture independant and constitute the
	 core of the relocation engine in ELFsh.
	 


-------[ II. The embedded debugging playground
     


---[ A. In-process injection


     
	We have different techniques for injecting the debugger
	inside the debuggee process. Thus it will share the address
	space and the debugger will be able to read its own data 
	and code for getting (and changing) information in the 
	debuggee process.

	Because the ELF shell is composed of 40000 lines of code, 
	we did not want to recode everything for allowing process
	modification. We used some trick that allow us to select
	wether the modifications are done in memory or on disk. The
	trick consists in 10 lines of code. Considering the PROFILE
	macros not beeing mandatory, here is the exact stuff :


 (libelfsh/section.c)


 ========= BEGIN DUMP 0 =========

 void                    *elfsh_get_raw(elfshsect_t *sect)
 {
   ELFSH_PROFILE_IN(__FILE__, __FUNCTION__, __LINE__);

   /* sect->parent->base is always NULL for ET_EXEC */
   if (elfsh_is_debug_mode())
     {
       sect->pdata = (void *) sect->parent->base + sect->shdr->sh_addr;
      ELFSH_PROFILE_ROUT(__FILE__, __FUNCTION__, __LINE__, (sect->pdata));
     }
   if (sect)
     ELFSH_PROFILE_ROUT(__FILE__, __FUNCTION__, __LINE__, (sect->data));

   ELFSH_PROFILE_ERR(__FILE__, __FUNCTION__, __LINE__, 
					"Invalid parameter", NULL);
 }

 ========= END DUMP 0 =========


	What is the technique about ? It is quite simple : if the debugger
	internal flag is set to static mode (on-disk modification), then we
	return the pointer on the ELFsh internal data cache for the section 
	data we want to access. 

	However if we are in dynamic mode (process modification), then we 
	just return the address of that section. The debugger runs in the 
	same process and thus will think that the returned address is a 
	readable (or writable) buffer. We can reuse all the ELF shell
	API by just taking care of using the elfsh_get_raw() function when
	accessing the ->data pointer. The process/ondisk selection is then
	transparent for all the debugger/elfsh code.

	The idea of injecting code directly inside the process is not
	new and we studied it for some years now. Embedded code injection
	is also used in the Windows cracking community [12] for bypassing 
	most of the protections against tracing and debugging, but nowhere
	else we have seen an implementation of a full debugger, capable
	of such advanced features like ET_REL injection or function
	redirection on multiple architectures, both on disk and in memory, 
	with a single code.



---[ B. Alternate ondisk and memory ELF scripting (feat. linkmap)



	We have 2 approaches for inserting the debugger inside the debuggee
	program. When using a DT_NEEDED entry and redirecting the main 
	debuggee function onto the main entry point of the ET_DYN debugger,
	we also inject various sections so that we can perform core 
	techniques such as EXTPLT. That will be described in details in 
	the next part. 

	The second approach is about using LD_PRELOAD on the debuggee 
	program and putting breakpoints (either by 0xCC opcode on x86 or 
        the equivalent opcode on another architecture, or by function 
        redirection which is available on many architectures and for many
        kind of functions in the framework).

	Since binary modification is needed anyway, we are using the 
	DT_NEEDED technique for adding the library dependance, and all 
	other sections injections or redirection described in this article,
	before starting the real debugging.

	The LD_PRELOAD technique is particulary more useful when you 
        cannot read the binary you want to debug. It is left to the user
        the choice of debugger injection technique, depending on the needs
        of the moment.

	Let's see how to use the embedded debugger and its 'mode' command
	that does the memory/disk selection. Then we print the Global 
	Offset Table (.got). First the memory GOT is displayed, then we 
	get back in static mode and the ondisk GOT is printed :


 ========= BEGIN DUMP 1 =========

 (e2dbg-0.65) list

 .::. Working files .::.
 [001] Sun Jul 31 19:23:33 2005  D ID: 9 /lib/libncurses.so.5
 [002] Sun Jul 31 19:23:33 2005  D ID: 8 /lib/libdl.so.2
 [003] Sun Jul 31 19:23:33 2005  D ID: 7 /lib/libtermcap.so.2
 [004] Sun Jul 31 19:23:33 2005  D ID: 6 /lib/libreadline.so.5
 [005] Sun Jul 31 19:23:33 2005  D ID: 5 /lib/libelfsh.so
 [006] Sun Jul 31 19:23:33 2005  D ID: 4 /lib/ld-linux.so.2
 [007] Sun Jul 31 19:23:33 2005  D ID: 3 ./ibc.so.6    # e2dbg.so renamed
 [008] Sun Jul 31 19:23:33 2005  D ID: 2 /lib/tls/libc.so.6
 [009] Sun Jul 31 19:23:33 2005 *D ID: 1 ./a.out_e2dbg # debuggee

 .::. ELFsh modules .::.
 [*] No loaded module

 (e2dbg-0.65) mode

 [*] e2dbg is in DYNAMIC MODE

 (e2dbg-0.65) got

 [Global Offset Table .::. GOT : .got ]
 [Object ./a.out_e2dbg]

 0x080498E4: [0] 0x00000000       <?>

 [Global Offset Table .::. GOT : .got.plt ]
 [Object ./a.out_e2dbg]

 0x080498E8: [0] 0x0804981C       <_DYNAMIC@a.out_e2dbg>
 0x080498EC: [1] 0x00000000       <?>
 0x080498F0: [2] 0x00000000       <?>
 0x080498F4: [3] 0x0804839E       <fflush@a.out_e2dbg>
 0x080498F8: [4] 0x080483AE       <puts@a.out_e2dbg>
 0x080498FC: [5] 0x080483BE       <malloc@a.out_e2dbg>
 0x08049900: [6] 0x080483CE       <strlen@a.out_e2dbg>
 0x08049904: [7] 0x080483DE       <__libc_start_main@a.out_e2dbg>
 0x08049908: [8] 0x080483EE       <printf@a.out_e2dbg>
 0x0804990C: [9] 0x080483FE       <free@a.out_e2dbg>
 0x08049910: [10] 0x0804840E      <read@a.out_e2dbg>

 [Global Offset Table .::. GOT : .elfsh.altgot ]
 [Object ./a.out_e2dbg]

 0x08049928: [0] 0x0804981C      <_DYNAMIC@a.out_e2dbg>
 0x0804992C: [1] 0xB7F4A4E8      <_r_debug@ld-linux.so.2 + 24>
 0x08049930: [2] 0xB7F3EEC0      <_dl_rtld_di_serinfo@ld-linux.so.2 + 477>
 0x08049934: [3] 0x0804839E      <fflush@a.out_e2dbg>
 0x08049938: [4] 0x080483AE      <puts@a.out_e2dbg>
 0x0804993C: [5] 0xB7E515F0      <__libc_malloc@libc.so.6>
 0x08049940: [6] 0x080483CE      <strlen@a.out_e2dbg>
 0x08049944: [7] 0xB7E01E50      <__libc_start_main@libc.so.6>
 0x08049948: [8] 0x080483EE      <printf@a.out_e2dbg>
 0x0804994C: [9] 0x080483FE      <free@a.out_e2dbg>
 0x08049950: [10] 0x0804840E     <read@a.out_e2dbg>
 0x08049954: [11] 0xB7DAFFF6     <e2dbg_run@ibc.so.6>

 (e2dbg-0.65) mode static

 [*] e2dbg is now in STATIC mode

 (e2dbg-0.65) # Here we switched in ondisk perspective
 (e2dbg-0.65) got

 [Global Offset Table .::. GOT : .got ]
 [Object ./a.out_e2dbg]

 0x080498E4: [0] 0x00000000       <?>

 [Global Offset Table .::. GOT : .got.plt ]
 [Object ./a.out_e2dbg]

 0x080498E8: [0] 0x0804981C       <_DYNAMIC>
 0x080498EC: [1] 0x00000000       <?>
 0x080498F0: [2] 0x00000000       <?>
 0x080498F4: [3] 0x0804839E       <fflush>
 0x080498F8: [4] 0x080483AE       <puts>
 0x080498FC: [5] 0x080483BE       <malloc>
 0x08049900: [6] 0x080483CE       <strlen>
 0x08049904: [7] 0x080483DE       <__libc_start_main>
 0x08049908: [8] 0x080483EE       <printf>
 0x0804990C: [9] 0x080483FE       <free>
 0x08049910: [10] 0x0804840E      <read>

 [Global Offset Table .::. GOT : .elfsh.altgot ]
 [Object ./a.out_e2dbg]

 0x08049928: [0] 0x0804981C       <_DYNAMIC>
 0x0804992C: [1] 0x00000000       <?>
 0x08049930: [2] 0x00000000       <?>
 0x08049934: [3] 0x0804839E       <fflush>
 0x08049938: [4] 0x080483AE       <puts>
 0x0804993C: [5] 0x080483BE       <malloc>
 0x08049940: [6] 0x080483CE       <strlen>
 0x08049944: [7] 0x080483DE       <__libc_start_main>
 0x08049948: [8] 0x080483EE       <printf>
 0x0804994C: [9] 0x080483FE       <free>
 0x08049950: [10] 0x0804840E      <read>
 0x08049954: [11] 0x0804614A      <e2dbg_run + 6>

 =========  END DUMP 1 =========


	   There are many things to notice in this dump. First you can 
	   verify that it actually does what it is supposed to by 
	   looking the first GOT entries which are reserved for the 
	   linkmap and the rtld dl-resolve function. Those entries are 
	   filled at runtime, so the static GOT version contains NULL 
	   pointers for them. However the GOT which stands in memory has
	   them filled. 

	   Also, the new version of the GNU linker does insert multiple
	   GOT sections inside ELF binaries. The .got section handles
	   the pointer for external variables, while .got.plt handles 
	   the external function pointers. In earlier versions of LD, 
	   those 2 sections were merged. We support both conventions.

	   Finally, you can see in last the .elfsh.altgot section.
	   That is part of the ALTGOT technique and it will be 
	   explained as a standalone algorithm in the next parts
	   of this paper. The ALTGOT technique allow for a size
	   extension of the Global Offset Table. It allows different
	   things depending on the architecture. On x86, ALTGOT is
	   only used when EXTPLT is used, so that we can add extra 
	   function to the host file. On MIPS and ALPHA, ALTGOT
	   allows to redirect an extern (PLT) function without losing
	   the real function address. We will develop both of these
	   techniques in the next parts.



---[ C. Real debugging : dumping, backtrace, breakpoints


          When performing debugging using a debugger embedded in the 
	  debuggee process, we do not need ptrace so we cannot 
	  modify so easily the process address space. That's why 
	  we have to do small static changes : we add the debugger
	  as a DT_NEEDED dependancy. The debugger will also overload some 
	  signal handlers (SIGTRAP, SIGINT, SIGSEGV ..) so that it 
	  can takes control on those events. 

	  We can redirect functions as well using either the CFLOW or 
	  ALTPLT technique using on-disk modification, so that we takes 
	  control at the desired moment. Obviously we can also set 
	  breakpoints in runtime but that need to mprotect the code zone 
	  if it was not writable for the moment. We have idea about how
	  to get rid of mprotect but this was not implemented in that
	  version (0.65). Indeed, many uses of the mprotect system call
	  are incompatible with one of the PaX option). Fortunately
	  we assume for now that we have read access to the debuggee
	  program, which means that we can copy the file and disable
	  that option.

	  This is how the DT_NEEDED dependence is added :


 ========= BEGIN DUMP 2 =========

 elfsh@WTH $ cat inject_e2dbg.esh
 #!../../vm/elfsh
 load a.out
 set 1.dynamic[08].val 0x2
 set 1.dynamic[08].tag DT_NEEDED
 redir main e2dbg_run
 save a.out_e2dbg

 =========  END DUMP 2 =========


	   Let's see the modified binary .dynamic section, where the
	   extra DT_NEEDED entries were added using the DT_DEBUG
	   technique that we published 2 years ago [0] :


 ========= BEGIN DUMP 3 =========

 elfsh@WTH $ ../../vm/elfsh -f ./a.out -d DT_NEEDED

 [*] Object ./a.out has been loaded (O_RDONLY)

 [SHT_DYNAMIC]
 [Object ./a.out]

 [00] Name of needed library => libc.so.6 {DT_NEEDED}

 [*] Object ./a.out unloaded

 elfsh@WTH $ ../../vm/elfsh -f ./a.out_e2dbg -d DT_NEEDED

 [*] Object ./a.out_e2dbg has been loaded (O_RDONLY)

 [SHT_DYNAMIC]
 [Object ./a.out_e2dbg]

 [00] Name of needed library => libc.so.6 {DT_NEEDED}
 [08] Name of needed library => ibc.so.6 {DT_NEEDED}

 [*] Object ./a.out_e2dbg unloaded

 =========  END DUMP 3 =========


     Let's see how we redirected the main function to the hook_main 
     function. You can notice the overwritten bytes between the 2 jmp 
     of the hook_main function. This technique is also available MIPS 
     architecture, but this dump is from the IA32 implementation :


 ========= BEGIN DUMP 4 =========

 elfsh@WTH $ ../../vm/elfsh -f ./a.out_e2dbg -D main%40

 [*] Object ./a.out_e2dbg has been loaded (O_RDONLY)

 08045134 [foff: 308] hook_main + 0  jmp   <e2dbg_run>
 08045139 [foff: 313] hook_main + 5  push  %ebp
 0804513A [foff: 314] hook_main + 6  mov   %esp,%ebp
 0804513C [foff: 316] hook_main + 8  push  %esi
 0804513D [foff: 317] hook_main + 9  push  %ebx
 0804513E [foff: 318] hook_main + 10 jmp   <main + 5>

 08045139 [foff: 313] old_main + 0   push  %ebp
 0804513A [foff: 314] old_main + 1   mov   %esp,%ebp
 0804513C [foff: 316] old_main + 3   push  %esi
 0804513D [foff: 317] old_main + 4   push  %ebx
 0804513E [foff: 318] old_main + 5   jmp   <main + 5>

 08048530 [foff: 13616] main + 0     jmp   <hook_main> 
 08048535 [foff: 13621] main + 5     sub   $2010,%esp
 0804853B [foff: 13627] main + 11    mov   8(%ebp),%ebx
 0804853E [foff: 13630] main + 14    mov   C(%ebp),%esi
 08048541 [foff: 13633] main + 17    and   $FFFFFFF0,%esp
 08048544 [foff: 13636] main + 20    sub   $10,%esp
 08048547 [foff: 13639] main + 23    mov   %ebx,4(%esp,1)
 0804854B [foff: 13643] main + 27    mov   $<_IO_stdin_used + 43>,(%esp,1)
 08048552 [foff: 13650] main + 34    call  <printf>
 08048557 [foff: 13655] main + 39    mov   (%esi),%eax

 [*] No binary pattern was specified

 [*] Object ./a.out_e2dbg unloaded

 =========  END DUMP 4 =========

	   
	   Let's now execute the debuggee program, in which the 
	   debugger was injected.


 ========= BEGIN DUMP 5 =========

 elfsh@WTH $ ./a.out_e2dbg


         The Embedded ELF Debugger 0.65 (32 bits built) .::.

         .::. This software is under the General Public License V.2
         .::. Please visit http://www.gnu.org 

 [*] Sun Jul 31 17:56:52 2005 - New object ./a.out_e2dbg loaded
 [*] Sun Jul 31 17:56:52 2005 - New object /lib/tls/libc.so.6 loaded
 [*] Sun Jul 31 17:56:53 2005 - New object ./ibc.so.6 loaded
 [*] Sun Jul 31 17:56:53 2005 - New object /lib/ld-linux.so.2 loaded
 [*] Sun Jul 31 17:56:53 2005 - New object /lib/libelfsh.so loaded
 [*] Sun Jul 31 17:56:53 2005 - New object /lib/libreadline.so.5 loaded
 [*] Sun Jul 31 17:56:53 2005 - New object /lib/libtermcap.so.2 loaded
 [*] Sun Jul 31 17:56:53 2005 - New object /lib/libdl.so.2 loaded
 [*] Sun Jul 31 17:56:53 2005 - New object /lib/libncurses.so.5 loaded

 (e2dbg-0.65) b puts

 [*] Breakpoint added at <puts@a.out_e2dbg> (0x080483A8)

 (e2dbg-0.65) continue

         [..: Embedded ELF Debugger returns to the grave :...]

 [e2dbg_run] returning to 0x08045139
 [host] main argc 1
 [host] argv[0] is : ./a.out_e2dbg

 First_printf test

         The Embedded ELF Debugger 0.65 (32 bits built) .::.

         .::. This software is under the General Public License V.2
         .::. Please visit http://www.gnu.org 

 [*] Sun Jul 31 17:57:03 2005 - New object /lib/tls/libc.so.6 loaded

 (e2dbg-0.65) bt

 .:: Backtrace ::.
 [00] 0xB7DC1EC5 <vm_bt@ibc.so.6 + 208>
 [01] 0xB7DC207F <cmd_bt@ibc.so.6 + 152>
 [02] 0xB7DBC88C <vm_execmd@ibc.so.6 + 174>
 [03] 0xB7DAB4DE <vm_loop@ibc.so.6 + 578>
 [04] 0xB7DAB943 <vm_run@ibc.so.6 + 271>
 [05] 0xB7DA5FF0 <e2dbg_entry@ibc.so.6 + 110>
 [06] 0xB7DA68D6 <e2dbg_genericbp_ia32@ibc.so.6 + 183>
 [07] 0xFFFFE440 <_r_debug@ld-linux.so.2 + 1208737648>	# sigtrap retaddr
 [08] 0xB7DF7F3B <__libc_start_main@libc.so.6 + 235>	
 [09] 0x08048441 <_start@a.out_e2dbg + 33>

 (e2dbg-0.65) b

 .:: Breakpoints ::.

 [00] 0x080483A8 <puts@a.out_e2dbg>

 (e2dbg-0.65) delete 0x080483A8

 [*] Breakpoint at 080483A8 <puts@a.out_e2dbg> removed

 (e2dbg-0.65) b

 .:: Breakpoints ::.

 [*] No breakpoints

 (e2dbg-0.65) b printf

 [*] Breakpoint added at <printf@a.out_e2dbg> (0x080483E8)

 (e2dbg-0.65) dumpregs

 .:: Registers ::.

         [EAX] 00000000 (0000000000) <unknown>
         [EBX] 08203F48 (0136331080) <.elfsh.relplt@a.out_e2dbg + 1811272>
         [ECX] 00000000 (0000000000) <unknown>
         [EDX] B7F0C7C0 (3086010304) <__guard@libc.so.6 + 1656>
         [ESI] BFE3B7C4 (3219371972) <_r_debug@ld-linux.so.2 + 133149428>
         [EDI] BFE3B750 (3219371856) <_r_debug@ld-linux.so.2 + 133149312>
         [ESP] BFE3970C (3219363596) <_r_debug@ld-linux.so.2 + 133141052>
         [EBP] BFE3B738 (3219371832) <_r_debug@ld-linux.so.2 + 133149288>
         [EIP] 080483A9 (0134513577) <puts@a.out_e2dbg>

 (e2dbg-0.65) stack 20

 .:: Stack ::.
 0xBFE37200 0x00000000 <(null)>
 0xBFE37204 0xB7DC2091 <vm_dumpstack@ibc.so.6>
 0xBFE37208 0xB7DDF5F0 <_GLOBAL_OFFSET_TABLE_@ibc.so.6>
 0xBFE3720C 0xBFE3723C <_r_debug@ld-linux.so.2 + 133131628>
 0xBFE37210 0xB7DC22E7 <cmd_stack@ibc.so.6 + 298>
 0xBFE37214 0x00000014 <_r_debug@ld-linux.so.2 + 1208744772>
 0xBFE37218 0xB7DDDD90 <__FUNCTION__.5@ibc.so.6 + 49>
 0xBFE3721C 0xBFE37230 <_r_debug@ld-linux.so.2 + 133131616>
 0xBFE37220 0xB7DB9DF9 <vm_implicit@ibc.so.6 + 304>
 0xBFE37224 0xB7DE1A7C <world@ibc.so.6 + 92>
 0xBFE37228 0xB7DA8176 <do_resolve@ibc.so.6>
 0xBFE3722C 0x080530B8 <.elfsh.relplt@a.out_e2dbg + 38072>
 0xBFE37230 0x00000014 <_r_debug@ld-linux.so.2 + 1208744772>
 0xBFE37234 0x08264FF6 <.elfsh.relplt@a.out_e2dbg + 2208758>
 0xBFE37238 0xB7DDF5F0 <_GLOBAL_OFFSET_TABLE_@ibc.so.6>
 0xBFE3723C 0xBFE3726C <_r_debug@ld-linux.so.2 + 133131676>
 0xBFE37240 0xB7DBC88C <vm_execmd@ibc.so.6 + 174>
 0xBFE37244 0x0804F208 <.elfsh.relplt@a.out_e2dbg + 22024>
 0xBFE37248 0x00000000 <(null)>
 0xBFE3724C 0x00000000 <(null)>

 (e2dbg-0.65) continue

         [..: Embedded ELF Debugger returns to the grave :...]

 First_puts

         The Embedded ELF Debugger 0.65 (32 bits built) .::.

         .::. This software is under the General Public License V.2
         .::. Please visit http://www.gnu.org 

 [*] Sun Jul 31 18:00:47 2005 - /lib/tls/libc.so.6 loaded
 [*] Sun Jul 31 18:00:47 2005 - /usr/lib/gconv/ISO8859-1.so loaded

 (e2dbg-0.65) dumpregs

 .:: Registers ::.

         [EAX] 0000000B (0000000011) <_r_debug@ld-linux.so.2 + 1208744763>
         [EBX] 08203F48 (0136331080) <.elfsh.relplt@a.out_e2dbg + 1811272>
         [ECX] 0000000B (0000000011) <_r_debug@ld-linux.so.2 + 1208744763>
         [EDX] B7F0C7C0 (3086010304) <__guard@libc.so.6 + 1656>
         [ESI] BFE3B7C4 (3219371972) <_r_debug@ld-linux.so.2 + 133149428>
         [EDI] BFE3B750 (3219371856) <_r_debug@ld-linux.so.2 + 133149312>
         [ESP] BFE3970C (3219363596) <_r_debug@ld-linux.so.2 + 133141052>
         [EBP] BFE3B738 (3219371832) <_r_debug@ld-linux.so.2 + 133149288>
         [EIP] 080483E9 (0134513641) <printf@a.out_e2dbg>

 (e2dbg-0.65) linkmap

 .::. Linkmap entries .::.
 [01] addr : 0x00000000 dyn : 0x0804981C -
 [02] addr : 0x00000000 dyn : 0xFFFFE590 -
 [03] addr : 0xB7DE3000 dyn : 0xB7F0AD3C - /lib/tls/libc.so.6
 [04] addr : 0xB7D95000 dyn : 0xB7DDF01C - ./ibc.so.6
 [05] addr : 0xB7F29000 dyn : 0xB7F3FF14 - /lib/ld-linux.so.2
 [06] addr : 0xB7D62000 dyn : 0xB7D93018 - /lib/libelfsh.so
 [07] addr : 0xB7D35000 dyn : 0xB7D5D46C - /lib/libreadline.so.5
 [08] addr : 0xB7D31000 dyn : 0xB7D34BB4 - /lib/libtermcap.so.2
 [09] addr : 0xB7D2D000 dyn : 0xB7D2FEEC - /lib/libdl.so.2
 [10] addr : 0xB7CEB000 dyn : 0xB7D2A1C0 - /lib/libncurses.so.5
 [11] addr : 0xB6D84000 dyn : 0xB6D85F28 - /usr/lib/gconv/ISO8859-1.so

 (e2dbg-0.65) exit

 [*] Unloading object 1 (/usr/lib/gconv/ISO8859-1.so)
 [*] Unloading object 2 (/lib/tls/libc.so.6)
 [*] Unloading object 3 (/lib/tls/libc.so.6)
 [*] Unloading object 4 (/lib/libncurses.so.5)
 [*] Unloading object 5 (/lib/libdl.so.2)
 [*] Unloading object 6 (/lib/libtermcap.so.2)
 [*] Unloading object 7 (/lib/libreadline.so.5)
 [*] Unloading object 8 (/home/elfsh/WTH/elfsh/libelfsh/libelfsh.so)
 [*] Unloading object 9 (/lib/ld-linux.so.2)
 [*] Unloading object 10 (./ibc.so.6)
 [*] Unloading object 11 (/lib/tls/libc.so.6)
 [*] Unloading object 12 (./a.out_e2dbg) *

         .:: Bye -:: The Embedded ELF Debugger 0.65

 =========  END DUMP 5 =========


	   As you see, the use of the debugger is quite similar to other
	   debuggers. The difference is about the implementation technique
	   which allows for hardened and embedded systems debugging where
	   ptrace is not present or disabled.

	   We were told [9] that the sigaction system call enables the 
	   possibility of doing step by step execution without using
	   ptrace. We did not have time to implement it but we will 
	   provide a step-capable debugger in the very near future. Since 
	   that call is not filtered by grsecurity and seems to be quite 
	   portable on Linux, BSD, Solaris and HP-UX, it is definitely 
	   worth testing it.


---[ D. Dynamic analyzers generation 


           Obviously, tools like ltrace [7] can be now done in elfsh
	   scripts for multiple architectures since all the redirection 
	   stuff is available.     

	   We also think that the framework can be used in dynamic 
	   software instrumentation. Since we support multiple 
	   architectures, we let the door open to other development 
	   team to develop such modules or extension inside the ELF 
	   shell framework.

	   We did not have time to include an example script for now that 
	   can do this, but we will soon. The kind of interresting stuff
	   that could be done and improved using the framework would
	   take its inspiration in projects like fenris [6]. That could
	   be done for multiple architectures as soon as the instruction
	   format type is integrated in the script engine, using the code
	   abstraction of libasm (which is now included as sources in
	   elfsh).

	   We do not deal with encryption for now, but some promising API 
	   [5] could be implemented as well for multiple architectures 
	   very easily.



-------[ III. Better multiarchitecture ELF redirections


	 In the first issue of the Cerberus ELF interface [0], we 
	 presented a redirection technique that we called ALTPLT. This 
	 technique is not enough since it allows only for PLT 
	 redirection on existing function of the binary program so
	 the software extension usable functions set is limited.

	 Morever, we noticed a bug in the previously released 
	 implementation of the ALTPLT technique : On the SPARC
	 architecture, when calling the original function, the 
	 redirection was removed and the program continued to work as if
	 no hook was installed. This bug came from the fact that Solaris
	 does not use the r_offset field for computing its relocation 
	 but get the file offset by multiplying the PLT entry size by the 
	 pushed relocation offset on the stack at the moment of dynamic 
	 resolution. 

	 We found a solution for this problem. That solution consisted in
	 adding some architecture specific fixes at the beginning of the 
	 ALTPLT section. However, such a fix is too much architecture
	 dependant and we started to think about an alternative technique
	 for implementing ALTPLT. As we had implemented the DT_DEBUG 
	 technique by modifying some entries in the .dynamic sections, we
	 discovered that many other entries are erasable and allow for
	 a very strong and architecture independant technique for 
	 redirecting access to various sections. More precisely, when 
	 patching the DT_PLTREL entry, we are able to provide our own 
	 pointer. DT_PLTREL is an architecture dependant entry and the  
	 documentation about it is quite weak, not to say inexistant. 

	 It actually points on the section of the executable beeing   
	 runtime relocated (e.g. GOT on x86 or mips, PLT on sparc and 
	 alpha). By changing this entry we are able to provide our own 
	 PLT or GOT, which leads to possibly extending it.

	 Let's first have look at the CFLOW technique and then comes
	 back on the PLT related redirections using the DT_PLTREL
	 modification.



---[ A. CFLOW: PaX-safe static functions redirection		


	 CFLOW is a simple but efficient technique for function 
	 redirection that are located in the host file and not
	 having a PLT entry.                          
	 
	 Let's see the host file that we use for this test: 
	 


 ========= BEGIN DUMP 6 =========

 elfsh@WTH $ cat host.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>

 int     legit_func(char *str)
 {
   printf("legit func (%s) !\n", str);
   return (0);
 }

 int	main()
 {
   char  *str;
   char  buff[BUFSIZ];

   read(0, buff, BUFSIZ-1);

   str = malloc(10);
   if (str == NULL)
     goto err;
   strcpy(str, "test");
   printf("First_printf %s\n", str);
   fflush(stdout);
   puts("First_puts");
   printf("Second_printf %s\n", str);

   free(str);

   puts("Second_puts");

   fflush(stdout);
   legit_func("test");
   return (0);
  err:
   printf("Malloc problem\n");
   return (-1);
 }

 =========  END DUMP 6 =========


	   We will here redirect the function legit_func, which is located
	   inside host.c by the hook_func function located in the 
	   relocatable object.

	   Let's look at the relocatable file that we are going to inject
	   in the above binary.


 ========= BEGIN DUMP 7 =========

 elfsh@WTH $ cat rel.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>

 int     glvar_testreloc = 42;
 int     glvar_testreloc_bss;
 char    glvar_testreloc_bss2;
 short   glvar_testreloc_bss3;

 int     hook_func(char *str)
 {
    printf("HOOK FUNC %s !\n", str);
    return (old_legit_func(str));
 }

 int     puts_troj(char *str)
 {
   int   local = 1;
   char  *str2;

   str2 = malloc(10);
   *str2 = 'Z';
   *(str2 + 1) = 0x00;

   glvar_testreloc_bss  = 43;
   glvar_testreloc_bss2 = 44;
   glvar_testreloc_bss3 = 45;

   printf("Trojan injected ET_REL takes control now "
          "[%s:%s:%u:%u:%hhu:%hu:%u] \n",
         str2, str,
         glvar_testreloc,
         glvar_testreloc_bss,
         glvar_testreloc_bss2,
         glvar_testreloc_bss3,
         local);

   free(str2);

   putchar('e');
   putchar('x');
   putchar('t');
   putchar('c');
   putchar('a');
   putchar('l');
   putchar('l');
   putchar('!');
   putchar('\n'); 

   old_puts(str); 

   write(1, "calling write\n", 14);
   fflush(stdout);
   return (0);
 }

 int     func2()
 {
   return (42);
 }

 =========  END DUMP 7 =========

	  
	  As you can see, the relocatable object use of unknown functions
     like write and putchar. Those functions do not have a symbol, plt 
     entry, got entry, or even relocatable entry in the host file.
	   
     We can call it however using the EXTPLT technique that will be 
     described as a standalone technique in the next part of this paper. 
     For now we focuss on the CFLOW technique that allow for redirection 
     of the legit_func on the hook_func. This function does not have a 
     PLT entry and we cannot use simple PLT infection for this. 

     We developped a technique that is PaX safe for ondisk redirection of 
     this kind of function. It consists of putting the good old jmp
     instruction at the beginning of the legit_func and redirect the flow
     on our own code. ELFsh will take care of executing the overwritten
     bytes somewhere else and gives back control to the redirected
     function, just after the jmp hook, so that no runtime restoration is
     needed and it stays PaX safe on disk.

     When these techniques are used in the debugger directly in memory
     and not on disk, they all break the mprotect protection of PaX, 
     which means that this flag must be disabled if you want to redirect
     the flow directly into memory. We use use the mprotect syscall on
     small code zone for beeing able to changes some specific instructions
     for redirection. However, we think that this technique is mostly
     interresting for debugging and not for other things, so it is not
     our priority to improve this for now.
	   
     Let's see the small ELFsh script for this example :


 ========= BEGIN DUMP 8 =========

 elfsh@WTH $ file a.out
 a.out: ELF 32-bit LSB executable, Intel 80386, dynamically linked, \
 not stripped
 elfsh@WTH $ cat relinject.esh
 #!../../../vm/elfsh

 load a.out
 load rel.o

 reladd 1 2

 redir puts puts_troj
 redir legit_func hook_func

 save fake_aout

 quit

 =========  END  EXAMPLE 8 =========


    The output of the ORIGINAL binary is as follow:


 ========= BEGIN DUMP 9 =========

 elfsh@WTH $ ./a.out

 First_printf test
 First_puts
 Second_printf test
 Second_puts
 LEGIT FUNC
 legit func (test) !

 ========= END DUMP 9 ===========


     Now let's inject the stuff:

	   
 ========= BEGIN DUMP 10 ========

 elfsh@WTH $ ./relinject.esh


         The ELF shell 0.65 (32 bits built) .::.

         .::. This software is under the General Public License V.2
         .::. Please visit http://www.gnu.org 

 ~load a.out

 [*] Sun Jul 31 15:30:14 2005 - New object a.out loaded

 ~load rel.o

 [*] Sun Jul 31 15:30:14 2005 - New object rel.o loaded

 ~reladd 1 2
 Section Mirrored Successfully !

 [*] ET_REL rel.o injected succesfully in ET_EXEC a.out

 ~redir puts puts_troj

 [*] Function puts redirected to addr 0x08047164 <puts_troj>

 ~redir legit_func hook_func

 [*] Function legit_func redirected to addr 0x08047134 <hook_func>

 ~save fake_aout

 [*] Object fake_aout saved successfully

 ~quit

 [*] Unloading object 1 (rel.o)
 [*] Unloading object 2 (a.out) *
         .:: Bye -:: The ELF shell 0.65

 ========= END DUMP 10 =========


	   Let's now execute the modified binary.

	   
 ========= BEGIN DUMP 11 =========

 elfsh@WTH $ ./fake_aout

 First_printf test
 Trojan injected ET_REL takes control now [Z:First_puts:42:43:44:45:1]
 extcall!
 First_puts
 calling write
 Second_printf test
 Trojan injected ET_REL takes control now [Z:Second_puts:42:43:44:45:1]
 extcall!
 Second_puts
 calling write
 HOOK FUNC test !
 Trojan injected ET_REL takes control now [Z:LEGIT FUNC:42:43:44:45:1]
 extcall!
 calling write
 legit func (test) !
 elfsh@WTH $

 =========  END DUMP 11 =========


	   Fine. Clearly legit_func has been redirected on the hook 
	   function, and hook_func takes care of calling back the
	   legit_func using the old symbol technique described in
	   the first issue of the Cerberus articles serie.

	   Let's see the original legit_func code which is redirected
	   using the CFLOW technique on the x86 architecture :
	   

 ========= BEGIN DUMP 12 =========

 080484C0 legit_func + 0        push   %ebp                             
 080484C1 legit_func + 1        mov    %esp,%ebp                        
 080484C3 legit_func + 3        sub    $8,%esp                          
 080484C6 legit_func + 6        mov    $<_IO_stdin_used + 4>,(%esp,1)   
 080484CD legit_func + 13       call   <.plt + 32>                      
 080484D2 legit_func + 18       mov    $<_IO_stdin_used + 15>,(%esp,1)  

 ========= END DUMP 12 =========


	   Now the modified code:


 ========= BEGIN DUMP 13 =========

 080484C0 legit_func + 0        jmp    <hook_legit_func>               
 080484C5 legit_func + 5        nop                                    
 080484C6 legit_func + 6        mov    $<_IO_stdin_used + 4>,(%esp,1)  
 080484CD legit_func + 13       call   <puts>                          
 080484D2 legit_func + 18       mov    $<_IO_stdin_used + 15>,(%esp,1) 
 080484D9 legit_func + 25       mov    8(%ebp),%eax                    
 080484DC legit_func + 28       mov    %eax,4(%esp,1)                  
 080484E0 legit_func + 32       call   <printf>                        
 080484E5 legit_func + 37       leave                                  
 080484E6 legit_func + 38       xor    %eax,%eax                       

 ========= END DUMP 13 =========

 
	We create a new section .elfsh.hooks whoose data is an array 
	of hook code stubs like this one:


 ========= BEGIN DUMP 14 =========

 08042134 hook_legit_func + 0   jmp    <hook_func>                     
 08042139 old_legit_func  + 0   push   %ebp                            
 0804213A old_legit_func  + 1   mov    %esp,%ebp                       
 0804213C old_legit_func  + 3   sub    $8,%esp                         
 0804213F old_legit_func  + 6   jmp    <legit_func + 6>                

 ========= END DUMP 14 =========


	 Because we want to be able to recall the original function
	 (legit_func), we add the erased bytes of it, just after the
	 first jmp. Then we call back the legit_func at the good offset
	 (so that we do not recurse inside the hook because the function
	 was hijacked), as you can see starting at the old_legit_func 
	 symbol of example 14.

	 This old symbols technique is coherent with the ALTPLT technique
	 that we published in the first article. We can as well use
	 the old_funcname() call inside the injected C code for 
	 calling back the good hijacked function, and we do that without
	 a single byte restoration at runtime. That is why the CFLOW
	 technique is PaX compatible.

	 For the MIPS architecture, the CFLOW technique is quite similar, 
	 we can see the result of it as well (DUMP 15 is the original
	 binary and DUMP 16 the modified one):


 ======== BEGIN DUMP 15 =========

 400400 <func>:        lui     gp,0xfc1
 400404 <func+4>:      addiu   gp,gp,-21696
 400408 <func+8>:      addu    gp,gp,t9
 40040c <func+12>:     addiu   sp,sp,-40
 400410 <func+16>:     sw      ra,36(sp)
 [...]

 ======== END DUMP 15 =========

	  
	  The modified func code is now :

	 
 ======== BEGIN DUMP 16 =========

 <func>
 400400:       addi    t9,t9,104	 # Register T9 as target function
 400404:       j       0x400468 <func2>	 # Direct JMP on hook function 
 400408:       nop			 # Delay slot 
 40040c:       addiu   sp,sp,-40	 # The original func code 
 400410:       sw      ra,36(sp)
 400414:       sw      s8,32(sp)
 400418:       move    s8,sp
 40041c:       sw      gp,16(sp)
 400420:       sw      a0,40(s8)

 ======== END DUMP 16 =========


	  The func2 function can be anything we want, provided that it has
	  the same number and type of parameters. When the func2 function
	  wants to call the original function (func), then it jumps on 
	  the old_func symbol that points inside the .elfsh.hooks section
	  entry for this CFLOW hook. That is how looks like such a hooks
	  entry on the MIPS architecture :


 ======== BEGIN DUMP 17 ========= 
 
 <old_func>
 3ff0f4         addi    t9,t9,4876
 3ff0f8         lui     gp,0xfc1
 3ff0fc         addiu   gp,gp,-21696
 3ff100         addu    gp,gp,t9
 3ff104         j       0x400408 <func + 8>
 3ff108         nop
 3ff10c         nop

 ======== END DUMP 17 ===========


	  As you can see, the three instructions that got erased for
	  installing the CFLOW hook at the beginning of func() are
	  now located in the hook entry for func(), pointed by
	  the old_func symbol. The T9 register is also reset so that
	  we can come back to a safe situation before jumping back
	  on func + 8.



---[ B. ALTPLT technique revised


     ALTPLT technique v1 was presented in the Cerberus ELF Interface [0]
     paper. As already stated, it was not satisfying because it was
     removing the hook on SPARC at the first original function call. 

     Since on SPARC the first 4 PLT entries are reserved, there is
     room for 12 instructions that would fix anything needed (actually
     the first PLT entry) at the moment when ALTPLT+0 takes control.
     
     ALTPLTv2 is working indeed in 12 instructions but it needed to	
     reencode the first ALTPLT section entry with the code from PLT+0 
     (which is relocated in runtime on SPARC before the main takes 
     control, which explains why we cannot patch this on the disk 
     statically).

     By this behavior, it breaks PaX, and the implementation is
     very architecture dependant since its SPARC assembly. For those
     who want to see it, we let the code of this in the ELFsh source 
     tree in libelfsh/sparc32.c .

     For the ALPHA64 architecture, it gives pretty much the same in its
     respective instructions set, and this time the implementation is
     located in libelfsh/alpha64.c .

     As you can see in the code (that we will not reproduce here for
     clarity of the article), ALTPLTv2 is a real pain and we needed to 
     get rid of all this assembly code that was requesting too much 
     efforts for potential future ports of this technique to other 
     architectures.

     Then we found the .dynamic DT_PLTREL trick and we tried to see what
     happened when changing this .dynamic entry inside the host binary.
     Changing the DT_PLTREL entry is very attractive since this is
     completely architecture independant so it works everywhere.

     Let's see how look like the section header table and the .dynamic 
     section used in the really simple ALTPLTv3 technique. We use the 
     .elfsh.altplt section as a mirror of the original .plt as explained 
     in our first paper. The other .elfsh.* sections has been explained 
     already or will be just after the log.

     The output (modified) binary looks like :


 =============== BEGIN DUMP 18 ================

 [SECTION HEADER TABLE .::. SHT is not stripped]
 [Object fake_aout]

 [000] 0x00000000 -------                 foff:00000000 sz:0000000 link:00
 [001] 0x08042134 a-x---- .elfsh.hooks    foff:00000308 sz:0000016 link:00
 [002] 0x08043134 a-x---- .elfsh.extplt   foff:00004404 sz:0000048 link:00
 [003] 0x08044134 a-x---- .elfsh.altplt   foff:00008500 sz:0004096 link:00
 [004] 0x08045134 a--ms-- rel.o.rodata.str1.32 foff:12596 sz:4096  link:00
 [005] 0x08046134 a--ms-- rel.o.rodata.str1.1  foff:16692 sz:4096  link:00
 [006] 0x08047134 a-x---- rel.o.text      foff:00020788 sz:0004096 link:00
 [007] 0x08048134 a------ .interp         foff:00024884 sz:0000019 link:00
 [008] 0x08048148 a------ .note.ABI-tag   foff:00024904 sz:0000032 link:00
 [009] 0x08048168 a------ .hash           foff:00024936 sz:0000064 link:10
 [010] 0x080481A8 a------ .dynsym         foff:00025000 sz:0000176 link:11
 [011] 0x08048258 a------ .dynstr         foff:00025176 sz:0000112 link:00
 [012] 0x080482C8 a------ .gnu.version    foff:00025288 sz:0000022 link:10
 [013] 0x080482E0 a------ .gnu.version_r  foff:00025312 sz:0000032 link:11
 [014] 0x08048300 a------ .rel.dyn        foff:00025344 sz:0000016 link:10
 [015] 0x08048310 a------ .rel.plt        foff:00025360 sz:0000056 link:10
 [016] 0x08048348 a-x---- .init           foff:00025416 sz:0000023 link:00
 [017] 0x08048360 a-x---- .plt            foff:00025440 sz:0000128 link:00
 [018] 0x08048400 a-x---- .text           foff:00025600 sz:0000736 link:00
 [019] 0x080486E0 a-x---- .fini           foff:00026336 sz:0000027 link:00
 [020] 0x080486FC a------ .rodata         foff:00026364 sz:0000116 link:00
 [021] 0x08048770 a------ .eh_frame       foff:00026480 sz:0000004 link:00
 [022] 0x08049774 aw----- .ctors          foff:00026484 sz:0000008 link:00
 [023] 0x0804977C aw----- .dtors          foff:00026492 sz:0000008 link:00
 [024] 0x08049784 aw----- .jcr            foff:00026500 sz:0000004 link:00
 [025] 0x08049788 aw----- .dynamic        foff:00026504 sz:0000200 link:11
 [026] 0x08049850 aw----- .got            foff:00026704 sz:0000004 link:00
 [027] 0x08049854 aw----- .got.plt        foff:00026708 sz:0000040 link:00
 [028] 0x0804987C aw----- .data           foff:00026748 sz:0000012 link:00
 [029] 0x08049888 aw----- .bss            foff:00026760 sz:0000008 link:00
 [030] 0x08049890 aw----- rel.o.bss       foff:00026768 sz:0004096 link:00
 [031] 0x0804A890 aw----- rel.o.data      foff:00030864 sz:0000004 link:00
 [032] 0x0804A894 aw----- .elfsh.altgot   foff:00030868 sz:0000048 link:00
 [033] 0x0804A8E4 aw----- .elfsh.dynsym   foff:00030948 sz:0000208 link:34
 [034] 0x0804AA44 aw----- .elfsh.dynstr   foff:00031300 sz:0000127 link:33
 [035] 0x0804AB24 aw----- .elfsh.reldyn   foff:00031524 sz:0000016 link:00
 [036] 0x0804AB34 aw----- .elfsh.relplt   foff:00031540 sz:0000072 link:00
 [037] 0x00000000 ------- .comment        foff:00031652 sz:0000665 link:00
 [038] 0x00000000 ------- .debug_aranges  foff:00032324 sz:0000120 link:00
 [039] 0x00000000 ------- .debug_pubnames foff:00032444 sz:0000042 link:00
 [040] 0x00000000 ------- .debug_info     foff:00032486 sz:0006871 link:00
 [041] 0x00000000 ------- .debug_abbrev   foff:00039357 sz:0000511 link:00
 [042] 0x00000000 ------- .debug_line     foff:00039868 sz:0000961 link:00
 [043] 0x00000000 ------- .debug_frame    foff:00040832 sz:0000072 link:00
 [044] 0x00000000 ---ms-- .debug_str      foff:00040904 sz:0008067 link:00
 [045] 0x00000000 ------- .debug_macinfo  foff:00048971 sz:0029295 link:00
 [046] 0x00000000 ------- .shstrtab       foff:00078266 sz:0000507 link:00
 [047] 0x00000000 ------- .symtab         foff:00080736 sz:0002368 link:48
 [048] 0x00000000 ------- .strtab         foff:00083104 sz:0001785 link:47

 [SHT_DYNAMIC]
 [Object ./testsuite/etrel_inject/etrel_original/fake_aout]

 [00] Name of needed library            =>           libc.so.6 {DT_NEEDED}
 [01] Address of init function          =>          0x08048348 {DT_INIT}
 [02] Address of fini function          =>          0x080486E0 {DT_FINI}
 [03] Address of symbol hash table      =>          0x08048168 {DT_HASH}
 [04] Address of dynamic string table   =>          0x0804AA44 {DT_STRTAB}
 [05] Address of dynamic symbol table   =>          0x0804A8E4 {DT_SYMTAB}
 [06] Size of string table              =>      00000127 bytes {DT_STRSZ}
 [07] Size of symbol table entry        =>      00000016 bytes {DT_SYMENT}
 [08] Debugging entry (unknown)         =>          0x00000000 {DT_DEBUG}
 [09] Processor defined value           =>          0x0804A894 {DT_PLTGOT}
 [10] Size in bytes for .rel.plt        =>      000072 bytes {DT_PLTRELSZ}
 [11] Type of reloc in PLT              =>            00000017 {DT_PLTREL}
 [12] Address of .rel.plt               =>          0x0804AB34 {DT_JMPREL}
 [13] Address of .rel.got section       =>          0x0804AB24 {DT_REL}
 [14] Total size of .rel section        =>      00000016 bytes {DT_RELSZ}
 [15] Size of a REL entry               =>      00000008 bytes {DT_RELENT}
 [16] SUN needed version table          =>          0x80482E0 {DT_VERNEED}
 [17] SUN needed version number         =>             001 {DT_VERNEEDNUM}
 [18] GNU version VERSYM                =>          0x080482C8 {DT_VERSYM}

 =============== END DUMP 18 ================
     

	As you can see, various sections has been copied and extended,	
	and their entries in .dynamic changed. That holds for .got 
	(DT_PLTGOT), .rel.plt (DT_JMPREL), .dynsym (DT_SYMTAB), and
	.dynstr (DT_STRTAB). Changing those entries allow for the 
	new ALTPLT technique without any line of assembly.

	Of course the ALTPLT technique version 3 does not need any
	non-mandatory information like debug sections. It may sound
	obvious but some peoples really asked this question.



---[ C. ALTGOT technique : the RISC complement			


	       On the MIPS architecture, calls to PLT entries are 
       done differently. Indeed, instead of a direct call instruction on 
       the entry, an indirect jump is used for using the GOT entry linked
       to the desired function. If such entry is filled, then the 
       function is called directly. By default, the GOT entries contains 
       the pointer on the PLT entries. During the execution eventually, 
       the dynamic linker is called for relocating the GOT section (MIPS, 
       x86) or the PLT section (on SPARC or ALPHA).

       Here is the MIPS assembly log that prove this on some dumb 
       helloworld program using printf :

       00400790 <main>:
       400790:  3c1c0fc0   lui     gp,0xfc0	  # Set GP to GOT base
       400794:  279c78c0   addiu   gp,gp,30912    # address + 0x7ff0
       400798:  0399e021   addu    gp,gp,t9	  # using t9 (= main)
       40079c:  27bdffe0   addiu   sp,sp,-32	  
       4007a0:  afbf001c   sw      ra,28(sp)
       4007a4:  afbe0018   sw      s8,24(sp)
       4007a8:  03a0f021   move    s8,sp
       4007ac:  afbc0010   sw      gp,16(sp)
       4007b0:  8f828018   lw      v0,-32744(gp)
       4007b4:  00000000   nop
       4007b8:  24440a50   addiu   a0,v0,2640
       4007bc:  2405002a   li      a1,42
       4007c0:  8f828018   lw      v0,-32744(gp)
       4007c4:  00000000   nop
       4007c8:  24460a74   addiu   a2,v0,2676
       4007cc:  8f99803c   lw      t9,-32708(gp)  # Load printf GOT entry
       4007d0:  00000000   nop			   
       4007d4:  0320f809   jalr    t9		  # and jump on it
       4007d8:  00000000   nop
       4007dc:  8fdc0010   lw      gp,16(s8)
       4007e0:  00001021   move    v0,zero
       4007e4:  03c0e821   move    sp,s8
       4007e8:  8fbf001c   lw      ra,28(sp)
       4007ec:  8fbe0018   lw      s8,24(sp)
       4007f0:  27bd0020   addiu   sp,sp,32
       4007f4:  03e00008   jr      ra		  # return from the func
       4007f8:  00000000   nop
       4007fc:  00000000   nop

       We note that the global pointer register %gp is always set
       on the GOT section base address on MIPS, more or less some
       fixed signed offset, in our case 0x7ff0 (0x8000 on ALPHA).

       In order to call a function whoose address is unknown, the GOT
       entries are filled and then the indirect jump instruction  
       on MIPS does not use the PLT entry anymore. What do we learn
       from this ? Simply that we cannot rely on a classical PLT 
       hijacking because the PLT entry code wont be called if the GOT 
       entry is already filled, which means that we will hijack the 
       function only the first time.

       Because of this, we will hijack functions using GOT patching
       on MIPS. However it does not resolve the problem of recalling
       the original function. In order to allow such recall, we will
       just insert the old_ symbols on the real PLT entry, so that
       we can still access the dynamic linking mechanism code stub
       even if the GOT has been modified.

       Let's see the detailed results of the ALTGOT technique on the 
       ALPHA and MIPS architecture. It was done without a single
       line of assembly code which makes it very portable :


 ========= BEGIN DUMP 19 =========

 elfsh@alpha$ cat host.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>

 int main()
 {
   char  *str;

   str = malloc(10);
   if (str == NULL)
     goto err;
   strcpy(str, "test");
   printf("First_printf %s\n", str);
   fflush(stdout);
   puts("First_puts");
   printf("Second_printf %u\n", 42);
   puts("Second_puts");
   fflush(stdout);
   return (0);
  err:
   printf("Malloc problem %u\n", 42);
   return (-1);
 }

 elfsh@alpha$ gcc host.c -o a.out
 elfsh@alpha$ file ./a.out
 a.out: ELF 64-bit LSB executable, Alpha (unofficial), for NetBSD 2.0G,
       dynamically linked, not stripped

 ========= END DUMP 19 =========


	   The original binary executes:


 ========= BEGIN DUMP 20 =========

 elfsh@alpha$ ./a.out
 First_printf test
 First_puts
 Second_printf 42
 Second_puts

 ========= END DUMP 20 ==========


	   Let's look again the relocatable object we are injecting:


 ========= BEGIN DUMP 21 =========

 elfsh@alpha$ cat rel.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>

 int     glvar_testreloc = 42;

 int     glvar_testreloc_bss;
 char    glvar_testreloc_bss2;
 short   glvar_testreloc_bss3;


 int     puts_troj(char *str)
 {
   int   local = 1;
   char  *str2;

   str2 = malloc(10);
   *str2 = 'Z';
   *(str2 + 1) = 0x00;

   glvar_testreloc_bss  = 43;
   glvar_testreloc_bss2 = 44;
   glvar_testreloc_bss3 = 45;

   printf("Trojan injected ET_REL takes control now "
         "[%s:%s:%u:%u:%hhu:%hu:%u] \n",
         str2, str,
         glvar_testreloc,
         glvar_testreloc_bss,
         glvar_testreloc_bss2,
         glvar_testreloc_bss3,
         local);

   old_puts(str);
   fflush(stdout);
   return (0);
 }

 int     func2()
 {
   return (42);
 }

 ========= END DUMP 21 =========


	   As you can see, the relocatable object rel.c uses old_ symbols
	   which means that it relies on the ALTPLT technique. However
	   we do not perform EXTPLT technique on ALPHA and MIPS yet so
	   we are not able to call unknown function from the binary on 
	   those architectures for now. Our rel.c is a copy from the one 
	   in example 7 without the calls to the unknown functions
	   write and putchar of example 7.

	   Now we inject the stuff:


 ========= BEGIN DUMP 22 =========

 elfsh@alpha$ ./relinject.esh > relinject.out
 elfsh@alpha$ ./fake_aout
 First_printf test
 Trojan injected ET_REL takes control now [Z:First_puts:42:43:44:45:1]
 First_puts
 Second_printf 42
 Trojan injected ET_REL takes control now [Z:Second_puts:42:43:44:45:1]
 Second_puts

 ========= END DUMP 22 ==========


	The section list on ALPHA is then as follow. A particular
	look at the injected sections is recommended :	


 ========= BEGIN DUMP 23 =========

 elfsh@alpha$ elfsh -f fake_aout -s -p

 [*] Object fake_aout has been loaded (O_RDONLY)

 [SECTION HEADER TABLE .::. SHT is not stripped]
 [Object fake_aout]

 [000] 0x000000000 -------                     foff:00000 sz:00000
 [001] 0x120000190 a------ .interp             foff:00400 sz:00023
 [002] 0x1200001A8 a------ .note.netbsd.ident  foff:00424 sz:00024
 [003] 0x1200001C0 a------ .hash               foff:00448 sz:00544
 [004] 0x1200003E0 a------ .dynsym             foff:00992 sz:00552
 [005] 0x120000608 a------ .dynstr             foff:01544 sz:00251
 [006] 0x120000708 a------ .rela.dyn           foff:01800 sz:00096
 [007] 0x120000768 a------ .rela.plt           foff:01896 sz:00168
 [008] 0x120000820 a-x---- .init               foff:02080 sz:00128
 [009] 0x1200008A0 a-x---- .text               foff:02208 sz:01312
 [010] 0x120000DC0 a-x---- .fini               foff:03520 sz:00104
 [011] 0x120000E28 a------ .rodata             foff:03624 sz:00162
 [012] 0x120010ED0 aw----- .data               foff:03792 sz:00000
 [013] 0x120010ED0 a------ .eh_frame           foff:03792 sz:00004
 [014] 0x120010ED8 aw----- .dynamic            foff:03800 sz:00352
 [015] 0x120011038 aw----- .ctors              foff:04152 sz:00016
 [016] 0x120011048 aw----- .dtors              foff:04168 sz:00016
 [017] 0x120011058 aw----- .jcr                foff:04184 sz:00008
 [018] 0x120011060 awx---- .plt                foff:04192 sz:00116
 [019] 0x1200110D8 aw----- .got                foff:04312 sz:00240
 [020] 0x1200111C8 aw----- .sdata              foff:04552 sz:00024
 [021] 0x1200111E0 aw----- .sbss               foff:04576 sz:00024
 [022] 0x1200111F8 aw----- .bss                foff:04600 sz:00056
 [023] 0x120011230 a-x---- rel.o.text          foff:04656 sz:00320
 [024] 0x120011370 aw----- rel.o.sdata         foff:04976 sz:00008
 [025] 0x120011378 a--ms-- rel.o.rodata.str1.1 foff:04984 sz:00072
 [026] 0x1200113C0 a-x---- .alt.plt.prolog     foff:05056 sz:00048
 [027] 0x1200113F0 a-x---- .alt.plt            foff:05104 sz:00120
 [028] 0x120011468 a------ .alt.got            foff:05224 sz:00072
 [029] 0x1200114B0 aw----- rel.o.got           foff:05296 sz:00080
 [030] 0x000000000 ------- .comment            foff:05376 sz:00240
 [031] 0x000000000 ------- .debug_aranges      foff:05616 sz:00048
 [032] 0x000000000 ------- .debug_pubnames     foff:05664 sz:00027
 [033] 0x000000000 ------- .debug_info         foff:05691 sz:02994
 [034] 0x000000000 ------- .debug_abbrev       foff:08685 sz:00337
 [035] 0x000000000 ------- .debug_line         foff:09022 sz:00373
 [036] 0x000000000 ------- .debug_frame        foff:09400 sz:00048
 [037] 0x000000000 ---ms-- .debug_str          foff:09448 sz:01940
 [038] 0x000000000 ------- .debug_macinfo      foff:11388 sz:12937
 [039] 0x000000000 ------- .ident              foff:24325 sz:00054
 [040] 0x000000000 ------- .shstrtab           foff:24379 sz:00393
 [041] 0x000000000 ------- .symtab             foff:27527 sz:02400
 [042] 0x000000000 ------- .strtab             foff:29927 sz:00948

 [Program header table .::. PHT]
 [Object fake_aout]

 [00] 0x120000040 -> 0x120000190 r-x  => Program header table
 [01] 0x120000190 -> 0x1200001A7 r--  => Program interpreter
 [02] 0x120000000 -> 0x120000ECA r-x  => Loadable segment
 [03] 0x120010ED0 -> 0x120011510 rwx  => Loadable segment
 [04] 0x120010ED8 -> 0x120011038 rw-  => Dynamic linking info
 [05] 0x1200001A8 -> 0x1200001C0 r--  => Auxiliary information

 [Program header table .::. SHT correlation]
 [Object fake_aout]

 [*] SHT is not stripped

 [00] PT_PHDR
 [01] PT_INTERP         .interp
 [02] PT_LOAD           .interp .note.netbsd.ident .hash .dynsym .dynstr
                        .rela.dyn .rela.plt .init .text .fini .rodata
 [03] PT_LOAD           .data .eh_frame .dynamic .ctors .dtors .jcr .plt
                        .got .sdata .sbss .bss rel.o.text rel.o.sdata
                        rel.o.rodata.str1.1 .alt.plt.prolog .alt.plt
                        .alt.got rel.o.got
 [04] PT_DYNAMIC        .dynamic
 [05] PT_NOTE           .note.netbsd.ident

 [*] Object fake_aout unloaded

 ========= END DUMP 23 =========


	  Segments are extended the good way. We see this because of
	  the correlation between SHT and PHT : all bounds are correct.
	  the end. The .alt.plt.prolog section is there for implementing
	  the ALTPLTv2 on ALPHA. This could will patch in runtime the
	  first ALTPLT entry bytes with the first PLT entry bytes on
	  the first time that ALTPLT first entry is called (when calling
	  some original function from a hook function for the first time).
	  
	  When we discovered how to do the ALTPLTv3 (without a line
	  of assembly), then .alt.plt.prolog just became a padding
	  section so that GOT and ALTGOT were well aligned on some
	  size that was necessary for setting up ALTPLT because of
	  the ALPHA instruction encoding of indirect control flow
	  jumps.


---[ D. EXTPLT technique : unknown function postlinking


	  This technique is one of the major one of the new ELFsh
	  version. It works on ET_EXEC and ET_DYN files, including   
	  when the injection is done directly in memory. EXTPLT	     
	  consists in adding a new section (.elfsh.extplt) so that   
	  we can add entries for new functions. 

	  When coupled to .rel.plt, .got, .dynsym, and .dynstr mirroring 
	  extensions, it allows for placing relocation entries that match 
	  the needs of the new ALTPLT/ALTGOT couple. Let's look at the 
	  additional relocation information using the elfsh -r command.
 
	  First, let see the original binary relocation table:

 
 ========= BEGIN DUMP 24 =========

 [*] Object ./a.out has been loaded (O_RDONLY) 

 [RELOCATION TABLES]
 [Object ./a.out]

 {Section .rel.dyn} 
 [000] R_386_GLOB_DAT  0x08049850 sym[010] : __gmon_start__   
 [001] R_386_COPY      0x08049888 sym[004] : stdout           

 {Section .rel.plt} 
 [000] R_386_JMP_SLOT  0x08049860 sym[001] : fflush           
 [001] R_386_JMP_SLOT  0x08049864 sym[002] : puts             
 [002] R_386_JMP_SLOT  0x08049868 sym[003] : malloc           
 [003] R_386_JMP_SLOT  0x0804986C sym[005] : __libc_start_main
 [004] R_386_JMP_SLOT  0x08049870 sym[006] : printf           
 [005] R_386_JMP_SLOT  0x08049874 sym[007] : free             
 [006] R_386_JMP_SLOT  0x08049878 sym[009] : read             

 [*] Object ./testsuite/etrel_inject/etrel_original/a.out unloaded 
	  
 ========= END DUMP 24 =========


	    Let's now see the modified binary relocation tables:


 ========= BEGIN DUMP 25 =========
	  
 [*] Object fake_aout has been loaded (O_RDONLY) 

 [RELOCATION TABLES]
 [Object ./fake_aout]

 {Section .rel.dyn} 
 [000] R_386_GLOB_DAT  0x08049850 sym[010] : __gmon_start__   
 [001] R_386_COPY      0x08049888 sym[004] : stdout           

 {Section .rel.plt} 
 [000] R_386_JMP_SLOT  0x0804A8A0 sym[001] : fflush           
 [001] R_386_JMP_SLOT  0x0804A8A4 sym[002] : puts             
 [002] R_386_JMP_SLOT  0x0804A8A8 sym[003] : malloc           
 [003] R_386_JMP_SLOT  0x0804A8AC sym[005] : __libc_start_main
 [004] R_386_JMP_SLOT  0x0804A8B0 sym[006] : printf           
 [005] R_386_JMP_SLOT  0x0804A8B4 sym[007] : free             
 [006] R_386_JMP_SLOT  0x0804A8B8 sym[009] : read             

 {Section .elfsh.reldyn} 
 [000] R_386_GLOB_DAT  0x08049850 sym[010] : __gmon_start__   
 [001] R_386_COPY      0x08049888 sym[004] : stdout           

 {Section .elfsh.relplt} 
 [000] R_386_JMP_SLOT  0x0804A8A0 sym[001] : fflush           
 [001] R_386_JMP_SLOT  0x0804A8A4 sym[002] : puts             
 [002] R_386_JMP_SLOT  0x0804A8A8 sym[003] : malloc           
 [003] R_386_JMP_SLOT  0x0804A8AC sym[005] : __libc_start_main
 [004] R_386_JMP_SLOT  0x0804A8B0 sym[006] : printf           
 [005] R_386_JMP_SLOT  0x0804A8B4 sym[007] : free             
 [006] R_386_JMP_SLOT  0x0804A8B8 sym[009] : read             
 [007] R_386_JMP_SLOT  0x0804A8BC sym[011] : _IO_putc         
 [008] R_386_JMP_SLOT  0x0804A8C0 sym[012] : write            

 [*] Object fake_aout unloaded 

 =========  END DUMP 25 =========     


	    As you see, _IO_putc (internal name for putchar) and write 
	    functions has been used in the injected object. We had to 
	    insert them inside the host binary so that the output binary 
	    can work.
	    
	    The .elfsh.relplt section is copied from the .rel.plt
	    section but with a doubled size so that we have room
	    for additional entries. Even if we extend only one of the
	    relocation table, both tables needs to be copied, because
	    on ET_DYN files, the rtld will assume that both tables
	    are adjacent in memory, so we cannot just copy .rel.plt
	    but also need to keep .rel.dyn (aka .rel.got) near the
	    .rel.plt copy. That is why you can see with .elfsh.reldyn
	    and .elfsh.relplt .

	    When extra symbols are needed, more sections are moved
	    after the BSS, including .dynsym and .dynstr.


---[ E. IA32, SPARC32/64, ALPHA64, MIPS32 compliant algorithms		 


	  Let's now give all algorithms details about the techniques we
	  introduced by the practice in the previous paragraphs. We
	  cover here all pseudos algorithms for ELF redirections. More
	  constrained debugging detailed algorithms are given at the end 
	  of the next part.

	  Because of ALTPLT and ALTGOT techniques are so complementary, 
	  we implemented them inside only one algorithm that we give
	  now. There is no conditions on the SPARC architecture since
	  it is the default architecture case in the listing.

	  The main ALTPLTv3 / ALTGOT algorithm (libelfsh/altplt.c) can be
	  found in elfsh_build_plt() and elfsh_relink_plt(), is as 
	  follow. 

	  It could probably be cleaned if all the code go in architecture 
	  dependant handlers but that would duplicate some code, so we 
	  keep it like this :

	  Multiarchitecture ALTPLT / ALTGOT algorithm
	 +-------------------------------------------+

	  0/ IF [ ARCH is MIPS AND PLT is not found AND File is dynamic ]
	     [
		- Get .text section base address
		- Find MIPS opcodes fingerprint for embedded PLT 
		  located inside .text
		- Fixup SHT to include PLT section header
	     ]

	  1/ SWITCH on ELF architecture
	  [
             MIPS:
		* Insert mapped .elfsh.gotprolog section
		* Insert mapped .elfsh.padgot section
	     ALPHA:
	        * Insert mapped .elfsh.pltprolog section
	     DEFAULT:
	        * Insert mapped .elfsh.altplt section (copy of .plt)
	  ]

	  2/ IF [ ARCH is (MIPS or ALPHA or IA32) ]
	  [
		* Insert .elfsh.altgot section (copy of .got)
	  ]

	  3/ FOREACH (ALT)PLT ENTRY:
	  [
		IF [ FIRST PLT entry ]
		[
		   IF [ARCH is MIPS ]
		   [
			* Insert pairs of ld/st instructions in 
			  .elfsh.gotprolog for copying extern variables 
			  addresses fixed in GOT by the RTLD inside 
			  ALTGOT section. See MIPS altplt handler
			  in libelfsh/mips32.c
		   ]
		   ELSE IF [ ARCH is IA32 ]
		   [
			* Reencode the first PLT entry using GOT - ALTGOT
			  address difference (so we relocate into ALTGOT
			  instead of GOT)
		   ]
		]
		
		IF [ ARCH is MIPS ]
		   * Inject OLD symbol on current PLT entry
		ELSE
		   * Inject OLD symbol on current ALTPLT entry

		IF [ ARCH is ALPHA ]
		   * Shift relocation entry pointing at current location
		
		IF [ ARCH is IA32 ]
		   * Reencode PLT and ALTPLT current entry
	  ]   

	  4/ SWITCH on ELF architecture
	  [
	       MIPS:
	       IA32:
		 * Change DT_PLTGOT entry from GOT to ALTGOT address
		 * Shift GOT related relocation
	       SPARC:
	         * Change DT_PLTGOT entry from PLT to ALTPLT address
		 * Shift PLT related relocations
	  ]

	  

	  On MIPS, there is no relocation tables inside ET_EXEC binaries.
	  If we want to shift the relocations that make reference to GOT 
	  inside the MIPS code, we need to fingerprint such code patterns
	  so that we fix them using the ALTGOT - GOT difference. They are
	  easily found since the needed patches are always on the same 
	  binary instructions pattern :

	  3c1c0000        lui     gp,0x0
	  279c0000        addiu   gp,gp,0
	  
	  The zero fields in those instructions should be patched at
	  linking time when they match HI16 and LO16 MIPS relocations. 
	  However this information is not available in a table for 
	  ET_EXEC files, so we had to find them back in the binary code. 
	  It way easier to do this on RISC architectures since all 
	  instructions are the same length so false positives are very 
	  unlikely to happen. Once we found all those patterns, we fix 
	  them using the ALTGOT-GOT difference in the relocatable fields.
	  Of course, we wont change ALL references to GOT inside the 
	  code, because that would result in just moving the GOT without
	  performing any hijack. We just fix those references in the 
	  first 0x100 bytes of .text, and in .init, .fini, that means 
	  only the references at the reserved GOT entries (filled with 
	  dl-resolve virtual address and linkmap address). That way, we 
	  make the original code use the ALTGOT section when accessing 
	  reserved entries (since they have been runtime relocated in 
	  ALTGOT and not GOT) and the original GOT entries when accessing
	  the function entries (so that we can hijack functions using 
	  GOT modification).


	  EXTPLT algorithm
	 +----------------+
	  
	  The EXTPLT algorithm fits well in the previous algorithm. We 
	  just needed to add 2 steps in the previous listing : 

	  	  
	  Step 2 BIS : Insert the EXTPLT (copy of PLT) section on 
		       supported architectures.

	  Step 5     : Mirror (and extend) dynamic linking sections on 
		       supported architectures. Let's give more details
		       about this algorithm implemented in 
		       libelfsh/extplt.c.

	  * Mirror .rel.got (.rel.dyn) and .rel.plt sections after BSS, 
	  with a double sized mirror sections. Those 2 sections needs to
	  stay adjacent in memory so that EXTPLT works on ET_DYN objects 
	  as well.

	  * Update DT_REL and DT_JMPREL entries in .dynamic

	  * Mirror .dynsym and .dynstr sections with a double size
	  
	  * Update DT_SYMTAB and DT_STRTAB entries in .dynamic

	  Once those operations are done, we have room in all the various
	  dynamic linking oriented sections and we can add on-demand 
	  dynamic symbols, symbols names, and relocation entry necessary 
	  for adding extra PLT entries in the EXTPLT section.

	  Then, each time we encounter a unknown symbol in the process of 
	  relocating a ET_REL object inside a ET_EXEC or ET_DYN object, 
	  we can use the REQUESTPLT algorithm, as implemented in 
	  elfsh_request_pltent() function in the libelfsh/extplt.c file :

	  * Check room in EXTPLT, RELPLT, DYNSYM, DYNSTR, and 
	  ALTGOT sections.

	  * Initialize ALTGOT entry to EXTPLT allocated new entry.

	  * Encode EXTPLT entry for using the ALTGOT entry.

	  * Insert relocation entry inside .elfsh.relplt for ALTGOT 
	  new entry.

	  * Add relocation entry size to DT_PLTRELSZ entry value in 
	  .dynamic section.

	  * Insert missing symbol in .elfsh.dynsym, with name inserted in 
	  .elfsh.dynstr section.

	  * Add symbol name length to DT_STRSZ entry value in .dynamic 
	  section.

	  This algorithm is called from the main ET_REL injection and 
	  relocation algorithm each time the ET_REL object use an unknown
	  function whoose symbol is not present in the host file. The 
	  new ET_REL injection algorithm is given at the end of the 
	  constrained debugging part of the article.	  


	  CFLOW algorithm
	 +----------------+

	 This technique is implemented using an architecture dependant 
	 backend but the global algorithm stays the same for all 
	 architectures :

	 - Create .elfsh.hooks sections (only 1 time)
	 - Find number of bytes aligned on instruction size :
		* Using libasm on IA32
		* Manually on RISC machines
	 - Insert HOOK entry on demand (see CFLOW dump for format)
	 - Insert JMP to hook entry in hijacked function prolog
	 - Align JUMP hook on instruction size with NOP in hijacked prolog
	 - Insert hook_funcname and old_funcname symbols in hook entry for
	   beeing able to call back the original function.


	 The technique is PaX safe since it does not need any runtime 
	 bytes restoration step. We can hook the address of our choice 
	 using the CFLOW technique, however executing the original bytes 
	 in the hook entry instead of their original place will not work 
	 when placing hooks on relative branching instructions. Indeed, 
	 relatives branching will be resolved to a wrong virtual address 
	 if we execute their opcodes at the wrong place (inside 
	 .elfsh.hooks instead of their original place) inside the 
	 process. Remember this when placing CFLOW hooks : it is not 
	 intended to hook relative branch instructions.



-------[ V. Constrained Debugging


	 In nowadays environment, hardened binaries are usually
	 of type ET_DYN. We had to support this kind of injection
	 since it allows for library files modification as much
	 powerful as the the executable files modification. Moreover
	 some distribution comes with a default binary set compiled
	 in ET_DYN, such as hardened gentoo.

	 Another improvement that we wanted to be done is the ET_REL
	 relocation in memory. The algorithm for it is the same than
	 the ondisk injection, but this time the disk is not changed
	 so it reduces forensics evidences like in [12]. It is believed 
	 that this kind of injection can be used in exploits and direct
	 process backdooring without touching the hard disk. Evil eh ?

	 We are aware of another implementation of the ET_REL injection	
	 into memory [10]. Ours supports a wider range of architecture and
	 couples with the EXTPLT technique directly in memory, which
	 was not previously implemented to our knowledge.

	 A last technique that we wanted to develop was about extending
	 and debugging static executables. We developed this new technique
	 that we called EXTSTATIC algorithm. It allows for static
	 injections by taking parts of libc.a when functions or code is
	 missing. The same ET_REL injection algorithm is used except
	 that more than one relocatable file taken from libc.a is 
	 injected at a time using a recursive dependency algorithm.


---[ A. ET_REL relocation in memory				


	 Because we want to be able to provide a handler for breakpoints
	 as they are specified, we allow for direct mapping of an ET_REL
	 object into memory. We use extra mmap zone for this, always
	 taking care that it does not break PaX : we do not map any zone
	 beeing both executable and writable.

	 In e2dbg, breakpoints can be implemented in 2 ways. Either an
	 architecture specific opcode (like 0xCC on IA32) is used on the
	 desired redirected access, or the CFLOW/ALTPLT primitives can be
	 used in runtime. In the second case, the mprotect system
	 call must be used to be able to modify code at runtime. However
	 we may be able to get rid of mprotect soon for runtime injections
	 as the CFLOW techniques improves for beeing both static and
	 runtime PaX safe.

	 Let's look at some simple binary that does just use printf and
	 and puts to understand more those concepts:


 ========= BEGIN DUMP 26 =========

 elfsh@WTH $ ./a.out
 [host] main argc 1
 [host] argv[0] is : ./a.out

 First_printf test
 First_puts
 Second_printf test
 Second_puts
 LEGIT FUNC
 legit func (test) !
 ========= END DUMP 26 =========


	   We use a small elfsh script as e2dbg so that it creates
	   another file with the debugger injected inside it, using
	   regular elfsh techniques. Let's look at it :



 ========= BEGIN DUMP 27 =========	  
 elfsh@WTH $ cat inject_e2dbg.esh
 #!../../vm/elfsh
 load a.out
 set 1.dynamic[08].val 0x2			# entry for DT_DEBUG
 set 1.dynamic[08].tag DT_NEEDED
 redir main e2dbg_run
 save a.out_e2dbg
 ========= END DUMP 27 =========


	   We then execute the modified binary.


 ========= BEGIN DUMP 28 =========

 elfsh@WTH $ ./aout_e2dbg


         The Embedded ELF Debugger 0.65 (32 bits built) .::.

         .::. This software is under the General Public License V.2
         .::. Please visit http://www.gnu.org

 [*] Sun Jul 31 16:24:00 2005 - New object ./a.out_e2dbg loaded
 [*] Sun Jul 31 16:24:00 2005 - New object /lib/tls/libc.so.6 loaded
 [*] Sun Jul 31 16:24:00 2005 - New object ./ibc.so.6 loaded
 [*] Sun Jul 31 16:24:00 2005 - New object /lib/ld-linux.so.2 loaded
 [*] Sun Jul 31 16:24:00 2005 - New object /lib/libelfsh.so loaded
 [*] Sun Jul 31 16:24:00 2005 - New object /lib/libreadline.so.5 loaded
 [*] Sun Jul 31 16:24:00 2005 - New object /lib/libtermcap.so.2 loaded
 [*] Sun Jul 31 16:24:00 2005 - New object /lib/libdl.so.2 loaded
 [*] Sun Jul 31 16:24:00 2005 - New object /lib/libncurses.so.5 loaded

 (e2dbg-0.65) quit

         [..: Embedded ELF Debugger returns to the grave :...]

 [e2dbg_run] returning to 0x08045139
 [host] main argc 1
 [host] argv[0] is : ./a.out_e2dbg

 First_printf test
 First_puts
 Second_printf test
 Second_puts
 LEGIT FUNC
 legit func (test) !

 elfsh@WTH $

========= END DUMP 28 =========


	   Okay, that was easy. What if we want to do something more
	   interresting like ET_REL object injection into memory. We
	   will make use of the profile command so that we can see
	   the autoprofiling feature of e2dbg. This command is always
	   useful to learn more about the internals of the debugger, 
	   and for internal debugging problems that may occur while
	   developping it.

	   Our cheap function calls pattern matching makes the output 
	   more understandable than a raw print of profiling information
	   and took only a few hours to implement using the 
	   ELFSH_PROFILE_{OUT,ERR,ROUT} macros in libelfsh-internals.h
	   and libelfsh/error.c 

	   We will also print the linkmap list. The linkmap first fields
	   are OS independant. There are a lot of other internal fields
	   that we do not display here but a lot of information could
	   be grabbed from there as well.

	   See the stuff in action :
	   

 ========= BEGIN DUMP 29 =========

 elfsh@WTH $ ./a.out_e2dbg

         The Embedded ELF Debugger 0.65 (32 bits built) .::.

         .::. This software is under the General Public License V.2
         .::. Please visit http://www.gnu.org 

 [*] Sun Jul 31 16:12:48 2005 - New object ./a.out_e2dbg loaded
 [*] Sun Jul 31 16:12:48 2005 - New object /lib/tls/libc.so.6 loaded
 [*] Sun Jul 31 16:12:48 2005 - New object ./ibc.so.6 loaded
 [*] Sun Jul 31 16:12:48 2005 - New object /lib/ld-linux.so.2 loaded
 [*] Sun Jul 31 16:12:48 2005 - New object /lib/libelfsh.so loaded
 [*] Sun Jul 31 16:12:48 2005 - New object /lib/libreadline.so.5 loaded
 [*] Sun Jul 31 16:12:48 2005 - New object /lib/libtermcap.so.2 loaded
 [*] Sun Jul 31 16:12:48 2005 - New object /lib/libdl.so.2 loaded
 [*] Sun Jul 31 16:12:48 2005 - New object /lib/libncurses.so.5 loaded

 (e2dbg-0.65) linkmap 

 .::. Linkmap entries .::.
 [01] addr : 0x00000000 dyn : 0x080497D4 -
 [02] addr : 0x00000000 dyn : 0xFFFFE590 -
 [03] addr : 0xB7E73000 dyn : 0xB7F9AD3C - /lib/tls/libc.so.6
 [04] addr : 0xB7E26000 dyn : 0xB7E6F01C - ./ibc.so.6
 [05] addr : 0xB7FB9000 dyn : 0xB7FCFF14 - /lib/ld-linux.so.2
 [06] addr : 0xB7DF3000 dyn : 0xB7E24018 - /lib/libelfsh.so
 [07] addr : 0xB7DC6000 dyn : 0xB7DEE46C - /lib/libreadline.so.5
 [08] addr : 0xB7DC2000 dyn : 0xB7DC5BB4 - /lib/libtermcap.so.2
 [09] addr : 0xB7DBE000 dyn : 0xB7DC0EEC - /lib/libdl.so.2
 [10] addr : 0xB7D7C000 dyn : 0xB7DBB1C0 - /lib/libncurses.so.5

 (e2dbg-0.65) list

 .::. Working files .::.
 [001] Sun Jul 31 16:24:00 2005  D ID: 9 /lib/libncurses.so.5
 [002] Sun Jul 31 16:24:00 2005  D ID: 8 /lib/libdl.so.2
 [003] Sun Jul 31 16:24:00 2005  D ID: 7 /lib/libtermcap.so.2
 [004] Sun Jul 31 16:24:00 2005  D ID: 6 /lib/libreadline.so.5
 [005] Sun Jul 31 16:24:00 2005  D ID: 5 /lib/libelfsh.so
 [006] Sun Jul 31 16:24:00 2005  D ID: 4 /lib/ld-linux.so.2
 [007] Sun Jul 31 16:24:00 2005  D ID: 3 ./ibc.so.6
 [008] Sun Jul 31 16:24:00 2005  D ID: 2 /lib/tls/libc.so.6
 [009] Sun Jul 31 16:24:00 2005 *D ID: 1 ./a.out_e2dbg

 .::. ELFsh modules .::.
 [*] No loaded module

 (e2dbg-0.65) source ./etrelmem.esh

 ~load myputs.o

 [*] Sun Jul 31 16:13:32 2005 - New object myputs.o loaded

 [!!] Loaded file is not the linkmap, switching to STATIC mode

 ~switch 1

 [*] Switched on object 1 (./a.out_e2dbg)

 ~mode dynamic

 [*] e2dbg is now in DYNAMIC mode

 ~reladd 1 10

 [*] ET_REL myputs.o injected succesfully in ET_EXEC ./a.out_e2dbg

 ~profile
         .:: Profiling enable

 + <vm_print_actual@loop.c:38>
 ~redir puts myputs
 + <vm_implicit@implicit.c:91>
 + <cmd_hijack@fcthijack.c:19>
 + <elfsh_get_metasym_by_name@sym_common.c:283>
 + <elfsh_get_dynsymbol_by_name@dynsym.c:255>
 + <elfsh_get_dynsymtab@dynsym.c:87>
 + <elfsh_get_raw@section.c:691>
 [P] --[ <elfsh_get_raw@section.c:691>
 [P] --- Last 1 function(s) recalled 1 time(s) ---
 + <elfsh_get_dynsymbol_name@dynsym.c:17>
 [W]     <elfsh_get_dynsymbol_by_name@dynsym.c:274>      Symbol not found
 [P] --[ <elfsh_get_raw@section.c:691>
 [P] --[ <elfsh_get_dynsymbol_name@dynsym.c:17>
 [P] --- Last 2 function(s) recalled 12 time(s) ---
 + <elfsh_get_symbol_by_name@symbol.c:236>
 + <elfsh_get_symtab@symbol.c:110>
 + <elfsh_get_symbol_name@symbol.c:20>
 [P] --[ <elfsh_get_symbol_name@symbol.c:20>
 [P] --- Last 1 function(s) recalled 114 time(s) ---
 + <elfsh_hijack_function_by_name@hijack.c:25>
 + <elfsh_setup_hooks@hooks.c:199>
 + <elfsh_get_pagesize@hooks.c:783>
 + <elfsh_get_archtype@hooks.c:624>
 + <elfsh_get_arch@elf.c:179>
 + <elfsh_copy_plt@altplt.c:525>
 + <elfsh_static_file@elf.c:491>
 + <elfsh_get_segment_by_type@pht.c:215>
 + <elfsh_get_pht@pht.c:364>
 + <elfsh_get_segment_type@pht.c:174>
 [P] --[ <elfsh_get_segment_type@pht.c:174>
 [P] --- Last 1 function(s) recalled 4 time(s) ---
 + <elfsh_get_arch@elf.c:179>
 [P] --[ <elfsh_get_arch@elf.c:179>
 [P] --- Last 1 function(s) recalled 1 time(s) ---
 + <elfsh_relink_plt@altplt.c:121>
 + <elfsh_get_archtype@hooks.c:624>
 [P] --[ <elfsh_get_arch@elf.c:179>
 [P] --[ <elfsh_relink_plt@altplt.c:121>
 [P] --[ <elfsh_get_archtype@hooks.c:624>
 [P] --- Last 3 function(s) recalled 1 time(s) ---
 + <elfsh_get_elftype@hooks.c:662>
 + <elfsh_get_objtype@elf.c:204>
 + <elfsh_get_ostype@hooks.c:709>
 + <elfsh_get_real_ostype@hooks.c:679>
 + <elfsh_get_interp@interp.c:41>
 + <elfsh_get_raw@section.c:691>
 [P] --[ <elfsh_get_raw@section.c:691>
 [P] --- Last 1 function(s) recalled 1 time(s) ---
 + <elfsh_get_section_by_name@section.c:168>
 + <elfsh_get_section_name@sht.c:474>
 [P] --[ <elfsh_get_section_name@sht.c:474>
 [P] --- Last 1 function(s) recalled 1 time(s) ---
 + <elfsh_get_symbol_by_name@symbol.c:236>
 + <elfsh_get_symtab@symbol.c:110>
 + <elfsh_get_symbol_name@symbol.c:20>
 [W]     <elfsh_get_symbol_by_name@symbol.c:253>         Symbol not found
 [P] --[ <elfsh_get_symbol_name@symbol.c:20>
 [P] --- Last 1 function(s) recalled 114 time(s) ---
 + <elfsh_is_pltentry@plt.c:73>
 [W]     <elfsh_is_pltentry@plt.c:77>               Invalid NULL parameter
 + <elfsh_get_dynsymbol_by_name@dynsym.c:255>
 + <elfsh_get_dynsymtab@dynsym.c:87>
 + <elfsh_get_raw@section.c:691>
 [P] --[ <elfsh_get_raw@section.c:691>
 [P] --- Last 1 function(s) recalled 1 time(s) ---
 + <elfsh_get_dynsymbol_name@dynsym.c:17>
 [P] --[ <elfsh_is_pltentry@plt.c:73>
 [P] --[ <elfsh_get_dynsymbol_by_name@dynsym.c:255>
 [P] --[ <elfsh_get_dynsymtab@dynsym.c:87>
 [P] --[ <elfsh_get_raw@section.c:691>
 [P] --[ <elfsh_get_dynsymbol_name@dynsym.c:17>
 [P] --- Last 5 function(s) recalled 1 time(s) ---
 + <elfsh_get_plt@plt.c:16>
 + <elfsh_is_plt@plt.c:49>
 + <elfsh_get_section_name@sht.c:474>
 + <elfsh_is_altplt@plt.c:62>
 [P] --[ <elfsh_is_plt@plt.c:49>
 [P] --[ <elfsh_get_section_name@sht.c:474>
 [P] --[ <elfsh_is_altplt@plt.c:62>
 [P] --- Last 3 function(s) recalled 3 time(s) ---
 + <elfsh_get_anonymous_section@section.c:334>
 + <elfsh_get_raw@section.c:691>
 [P] --[ <elfsh_is_plt@plt.c:49>
 [P] --[ <elfsh_get_section_name@sht.c:474>
 [P] --[ <elfsh_is_altplt@plt.c:62>
 [P] --[ <elfsh_get_anonymous_section@section.c:334>
 [P] --[ <elfsh_get_raw@section.c:691>
 [P] --- Last 5 function(s) recalled 44 time(s) ---
 + <elfsh_get_arch@elf.c:179>
 [P] --[ <elfsh_get_arch@elf.c:179>
 [P] --- Last 1 function(s) recalled 1 time(s) ---
 + <elfsh_hijack_plt_ia32@ia32.c:258>
 + <elfsh_get_foffset_from_vaddr@raw.c:85>
 + <elfsh_get_pltentsz@plt.c:94>
 [P] --[ <elfsh_get_arch@elf.c:179>
 [P] --[ <elfsh_hijack_plt_ia32@ia32.c:258>
 [P] --[ <elfsh_get_foffset_from_vaddr@raw.c:85>
 [P] --[ <elfsh_get_pltentsz@plt.c:94>
 [P] --- Last 4 function(s) recalled 1 time(s) ---
 + <elfsh_munprotect@runtime.c:97>
 + <elfsh_get_parent_section@section.c:380>
 + <elfsh_get_parent_segment@pht.c:304>
 + <elfsh_segment_is_readable@pht.c:14>
 + <elfsh_segment_is_writable@pht.c:21>
 + <elfsh_segment_is_executable@pht.c:28>
 + <elfsh_raw_write@raw.c:22>
 + <elfsh_get_parent_section_by_foffset@section.c:416>
 + <elfsh_get_sht@sht.c:159>
 + <elfsh_get_section_type@sht.c:887>
 + <elfsh_get_anonymous_section@section.c:334>
 + <elfsh_get_raw@section.c:691>
 + <elfsh_raw_write@raw.c:22>
 + <elfsh_get_parent_section_by_foffset@section.c:416>
 + <elfsh_get_sht@sht.c:159>
 + <elfsh_get_section_type@sht.c:887>
 + <elfsh_get_anonymous_section@section.c:334>
 + <elfsh_get_raw@section.c:691>
 + <elfsh_get_pltentsz@plt.c:94>
 + <elfsh_get_arch@elf.c:179>
 + <elfsh_mprotect@runtime.c:135>

 [*] Function puts redirected to addr 0xB7FB6000 <myputs>

 + <vm_print_actual@loop.c:38>
 ~profile
 + <vm_implicit@implicit.c:91>
         .:: Profiling disable


 [*] ./etrelmem.esh sourcing -OK-

 (e2dbg-0.65) continue


         [..: Embedded ELF Debugger returns to the grave :...]

 [e2dbg_run] returning to 0x08045139
 [host] main argc 1
 [host] argv[0] is : ./a.out_e2dbg

 First_printf test
 Hijacked puts !!! arg = First_puts
 First_puts
 Second_printf test
 Hijacked puts !!! arg = Second_puts
 Second_puts
 Hijacked puts !!! arg = LEGIT FUNC
 LEGIT FUNC
 legit func (test) !
 elfsh@WTH $

 ========= END DUMP 29 =========


	  Really cool. We hijacked 2 functions (puts and legit_func) using
	  the 2 different (ALTPLT and CFLOW) techniques. For this, we
	  did not have to inject an additional ET_REL file inside the
	  ET_EXEC host, but we directly injected the hook module inside
	  memory using mmap.

	  We could have printed the SHT and PHT as well just after the
	  ET_REL injection into memory. We keep track of all mapping
	  when we inject such relocatable objects, so that we can 
	  eventually unmap them in the future or remap them later :


 ========= BEGIN DUMP 30 =========
	  
 (e2dbg-0.65) s

 [SECTION HEADER TABLE .::. SHT is not stripped]
 [Object ./a.out_e2dbg]

 [000] 0x00000000 -------                           foff:00000 size:00308
 [001] 0x08045134 a-x---- .elfsh.hooks              foff:00308 size:00015
 [002] 0x08046134 a-x---- .elfsh.extplt             foff:04404 size:00032
 [003] 0x08047134 a-x---- .elfsh.altplt             foff:08500 size:04096
 [004] 0x08048134 a------ .interp                   foff:12596 size:00019
 [005] 0x08048148 a------ .note.ABI-tag             foff:12616 size:00032
 [006] 0x08048168 a------ .hash                     foff:12648 size:00064
 [007] 0x080481A8 a------ .dynsym                   foff:12712 size:00176
 [008] 0x08048258 a------ .dynstr                   foff:12888 size:00112
 [009] 0x080482C8 a------ .gnu.version              foff:13000 size:00022
 [010] 0x080482E0 a------ .gnu.version_r            foff:13024 size:00032
 [011] 0x08048300 a------ .rel.dyn                  foff:13056 size:00016
 [012] 0x08048310 a------ .rel.plt                  foff:13072 size:00056
 [013] 0x08048348 a-x---- .init                     foff:13128 size:00023
 [014] 0x08048360 a-x---- .plt                      foff:13152 size:00128
 [015] 0x08048400 a-x---- .text                     foff:13312 size:00800
 [016] 0x08048720 a-x---- .fini                     foff:14112 size:00027
 [017] 0x0804873C a------ .rodata                   foff:14140 size:00185
 [018] 0x080487F8 a------ .eh_frame                 foff:14328 size:00004
 [019] 0x080497FC aw----- .ctors                    foff:14332 size:00008
 [020] 0x08049804 aw----- .dtors                    foff:14340 size:00008
 [021] 0x0804980C aw----- .jcr                      foff:14348 size:00004
 [022] 0x08049810 aw----- .dynamic                  foff:14352 size:00200
 [023] 0x080498D8 aw----- .got                      foff:14552 size:00004
 [024] 0x080498DC aw----- .got.plt                  foff:14556 size:00040
 [025] 0x08049904 aw----- .data                     foff:14596 size:00012
 [026] 0x08049910 aw----- .bss                      foff:14608 size:00008
 [027] 0x08049918 aw----- .elfsh.altgot             foff:14616 size:00044
 [028] 0x08049968 aw----- .elfsh.dynsym             foff:14696 size:00192
 [029] 0x08049AC8 aw----- .elfsh.dynstr             foff:15048 size:00122
 [030] 0x08049BA8 aw----- .elfsh.reldyn             foff:15272 size:00016
 [031] 0x08049BB8 aw----- .elfsh.relplt             foff:15288 size:00064
 [032] 0x00000000 ------- .comment                  foff:15400 size:00665
 [033] 0x00000000 ------- .debug_aranges            foff:16072 size:00120
 [034] 0x00000000 ------- .debug_pubnames           foff:16192 size:00042
 [035] 0x00000000 ------- .debug_info               foff:16234 size:06904
 [036] 0x00000000 ------- .debug_abbrev             foff:23138 size:00503
 [037] 0x00000000 ------- .debug_line               foff:23641 size:00967
 [038] 0x00000000 ------- .debug_frame              foff:24608 size:00076
 [039] 0x00000000 ---ms-- .debug_str                foff:24684 size:08075
 [040] 0x00000000 ------- .debug_macinfo            foff:32759 size:29295
 [041] 0x00000000 ------- .shstrtab                 foff:62054 size:00496
 [042] 0x00000000 ------- .symtab                   foff:64473 size:02256
 [043] 0x00000000 ------- .strtab                   foff:66729 size:01665
 [044] 0x40019000 aw----- myputs.o.bss              foff:68394 size:04096
 [045] 0x00000000 ------- .elfsh.rpht               foff:72493 size:04096
 [046] 0x4001A000 a-x---- myputs.o.text             foff:76589 size:04096
 [047] 0x4001B000 a--ms-- myputs.o.rodata.str1.1    foff:80685 size:04096

 (e2dbg-0.65) p

 [Program Header Table .::. PHT]
 [Object ./a.out_e2dbg]

 [00] 0x08045034 -> 0x08045134 r-x memsz(00256) filesz(00256)
 [01] 0x08048134 -> 0x08048147 r-- memsz(00019) filesz(00019)
 [02] 0x08045000 -> 0x080487FC r-x memsz(14332) filesz(14332)
 [03] 0x080497FC -> 0x08049C30 rw- memsz(01076) filesz(01068)
 [04] 0x08049810 -> 0x080498D8 rw- memsz(00200) filesz(00200)
 [05] 0x08048148 -> 0x08048168 r-- memsz(00032) filesz(00032)
 [06] 0x00000000 -> 0x00000000 rw- memsz(00000) filesz(00000)
 [07] 0x00000000 -> 0x00000000 --- memsz(00000) filesz(00000)

 [SHT correlation]
 [Object ./a.out_e2dbg]

 [*] SHT is not stripped 
 
 [00] PT_PHDR    
 [01] PT_INTERP         .interp 
 [02] PT_LOAD           .elfsh.hooks .elfsh.extplt .elfsh.altplt .interp 
			.note.ABI-tag .hash .dynsym .dynstr .gnu.version 
			.gnu.version_r .rel.dyn .rel.plt .init .plt 
			.text .fini .rodata .eh_frame 
 [03] PT_LOAD           .ctors .dtors .jcr .dynamic .got .got.plt .data 
			.bss .elfsh.altgot .elfsh.dynsym .elfsh.dynstr 
			.elfsh.reldyn .elfsh.relplt 
 [04] PT_DYNAMIC        .dynamic 
 [05] PT_NOTE           .note.ABI-tag 
 [06] PT_GNU_STACK 
 [07] PT_PAX_FLAGS 

 [Runtime Program Header Table .::. RPHT]
 [Object ./a.out_e2dbg]

 [00] 0x40019000 -> 0x4001A000 rw- memsz(4096) filesz(4096)
 [01] 0x4001A000 -> 0x4001B000 r-x memsz(4096) filesz(4096)
 [02] 0x4001B000 -> 0x4001C000 r-x memsz(4096) filesz(4096)

 [SHT correlation]
 [Object ./a.out_e2dbg]

 [*] SHT is not stripped 
 
 [00] PT_LOAD           myputs.o.bss 
 [01] PT_LOAD           myputs.o.text 
 [02] PT_LOAD           myputs.o.rodata.str1.1 

 (e2dbg-0.65) 


 ========= BEGIN DUMP 30 =========



	   Our algorithm is not really optimized since it allocates 
	   a new PT_LOAD by section. Here, we created a new table RPHT 
	   (Runtime PHT) which handle the list of all runtime injected
	   pages. This table has no legal existance in the ELF file, 
	   but that avoid to extend the real PHT with additional
	   runtime memory areas. The technique does not break PaX
	   since all zones are allocated using the strict necessary
	   rights. However, if you want to redirect existing functions
	   on the newly injected functions from myputs.o, then you
	   will have to change some code in runtime, and then it
	   becomes necessary to disable mprotect option to avoid
	   breaking PaX. 



---[ B. ET_REL relocation into ET_DYN				



	  We ported the ET_REL injection and the EXTPLT technique to 
	  ET_DYN files. The biggest difference is that ET_DYN files have 
	  a relative address space ondisk. Of course, stripped binaries 
	  have no effect on our algorithms and we dont need any	      
	  non-mandatory information such as debug sections or anything
	  (it may be obvious but some peoples really asked this).

	  Let's see what happens on this ET_DYN host file:


 ========= BEGIN DUMP 31 =========

 elfsh@WTH $ file main
 main: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), 
 stripped

 elfsh@WTH $ ./main
 0x800008c8 main(argc=0xbfa238d0, argv=0xbfa2387c, envp=0xbfa23878, 
	         auxv=0xbfa23874) __guard=0xb7ef4148
 ssp-all (Stack) Triggering an overflow by copying [20] of data into [10]
 of space
 main: stack smashing attack in function main()
 Aborted

 elfsh@WTH $ ./main AAAAA
 0x800008c8 main(argc=0xbf898e40, argv=0xbf898dec, envp=0xbf898de8, 
	         auxv=0xbf898de4) __guard=0xb7f6a148
 ssp-all (Stack) Copying [5] of data into [10] of space

 elfsh@WTH $ ./main AAAAAAAAAAAAAAAAAAAAAAAAAAA
 0x800008c8 main(argc=0xbfd3c8e0, argv=0xbfd3c88c, envp=0xbfd3c888, 
                 auxv=0xbfd3c884) __guard=0xb7f0b148
 ssp-all (Stack) Copying [27] of data into [10] of space
 main: stack smashing attack in function main()
 Aborted

 ========= END DUMP 31 =========


	   For the sake of fun, we decided to study in priority  the
	   hardened gentoo binaries [11] . Those comes with PIE (Position
	   Independant Executable) and SSP (Stack Smashing Protection)
	   built in. It does not change a line of our algorithm. Here
	   are some tests done on a stack smashing protected binary
	   with an overflow in the first parameter, triggering the
	   stack smashing handler. We will redirect that handler
	   to show that it is a normal function that use classical
	   PLT mechanisms.

	   This is the code that we are going to inject :
	   

 ========= BEGIN DUMP 32 =========

 elfsh@WTH $ cat simple.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>

 int     fake_main(int argc, char **argv)
 {
   old_printf("I am the main function, I have %d argc and my "
  	      "argv is %08X yupeelala \n",
              argc, argv); 

   write(1, "fake_main is calling write ! \n", 30);

   old_main(argc, argv);

   return (0);
 }

 char*   fake_strcpy(char *dst, char *src)
 {
   printf("The fucker wants to copy %s at address %08X \n", src, dst);
   return ((char *) old_strcpy(dst, src));
 }

 void    fake_stack_smash_handler(char func[], int damaged)
 {
   static int i = 0;
   printf("calling printf from stack smashing handler %u\n", i++);
   if (i>3)
     old___stack_smash_handler(func, damaged);
   else
     printf("Same player play again [damaged = %08X] \n", damaged);
   printf("A second (%d) printf from the handler \n", 2);
 }

 int fake_libc_start_main(void *one, void *two, void *three, void *four, 
                          void *five, void *six, void *seven)
 {
   static int i = 0;

   old_printf("fake_libc_start_main \n");
   printf("start_main has been run %u \n", i++);
   return (old___libc_start_main(one, two, three, four, 
			         five, six, seven));
 }

 ========= END DUMP 32 =========

	   
	   The elfsh script that allow for the modification is :


 ========= BEGIN DUMP 33 =========

 elfsh@WTH $ cat relinject.esh
 #!../../../vm/elfsh

 load main
 load simple.o

 reladd 1 2

 redir main fake_main
 redir __stack_smash_handler fake_stack_smash_handler
 redir __libc_start_main fake_libc_start_main
 redir strcpy fake_strcpy

 save fake_main

 quit

 ========= END DUMP 33 =========


	   Now let's see this in action !


 ========= BEGIN DUMP 34 =========
 elfsh@WTH $ ./relinject.esh


         The ELF shell 0.65 (32 bits built) .::.

         .::. This software is under the General Public License V.2
         .::. Please visit http://www.gnu.org

 ~load main

 [*] Sun Jul 31 17:24:20 2005 - New object main loaded

 ~load simple.o

 [*] Sun Jul 31 17:24:20 2005 - New object simple.o loaded

 ~reladd 1 2

 [*] ET_REL simple.o injected succesfully in ET_DYN main

 ~redir main fake_main

 [*] Function main redirected to addr 0x00005154 <fake_main>

 ~redir __stack_smash_handler fake_stack_smash_handler

 [*] Function __stack_smash_handler redirected to addr 
     0x00005203 <fake_stack_smash_handler>

 ~redir __libc_start_main fake_libc_start_main

 [*] Function __libc_start_main redirected to addr 
     0x00005281 <fake_libc_start_main>

 ~redir strcpy fake_strcpy

 [*] Function strcpy redirected to addr 0x000051BD <fake_strcpy>

 ~save fake_main

 [*] Object fake_main saved successfully

 ~quit

 [*] Unloading object 1 (simple.o)
 [*] Unloading object 2 (main) *
         .:: Bye -:: The ELF shell 0.65
 
 ========= END DUMP 34 =========


	   What about the result ?


 ========= BEGIN DUMP 35 =========

 elfsh@WTH $ ./fake_main
 fake_libc_start_main
 start_main has been run 0
 I am the main function, I have 1 argc and my argv is BF9A6F54 yupeelala
 fake_main is calling write !
 0x800068c8 main(argc=0xbf9a6e80, argv=0xbf9a6e2c, envp=0xbf9a6e28, 
 	        auxv=0xbf9a6e24) __guard=0xb7f78148
 ssp-all (Stack) Triggering an overflow by copying [20] of data into [10]
 of space
 The fucker wants to copy 01234567890123456789 at address BF9A6E50
 calling printf from stack smashing handler 0
 Same player play again [damaged = 39383736]
 A second (2) printf from the handler

 elfsh@WTH $ ./fake_main AAAA
 fake_libc_start_main
 start_main has been run 0
 I am the main function, I have 2 argc and my argv is BF83A164 yupeelala
 fake_main is calling write !
 0x800068c8 main(argc=0xbf83a090, argv=0xbf83a03c, envp=0xbf83a038, 
	        auxv=0xbf83a034) __guard=0xb7f09148
 ssp-all (Stack) Copying [4] of data into [10] of space
 The fucker wants to copy AAAA at address BF83A060

 elfsh@WTH $ ./fake_main AAAAAAAAAAAAAAA
 fake_libc_start_main
 start_main has been run 0
 I am the main function, I have 2 argc and my argv is BF8C7F24 yupeelala
 fake_main is calling write !
 0x800068c8 main(argc=0xbf8c7e50, argv=0xbf8c7dfc, envp=0xbf8c7df8, 
                 auxv=0xbf8c7df4) __guard=0xb7f97148
 ssp-all (Stack) Copying [15] of data into [10] of space
 The fucker wants to copy AAAAAAAAAAAAAAA at address BF8C7E20

 ========= END DUMP 35 =========


	No problem there : strcpy, main, libc_start_main and
	__stack_smash_handler are redirected on our own routines
	as the output shows. We also call write that was not available
	in the original binary, which show that EXTPLT also works on
	ET_DYN objects, the cool stuff beeing that it worked without
	any modification.

	In the current release (0.65rc1) there is a limitation on ET_DYN
	however. We have to avoid non-initialized variables because 
	that would add some entries in relocation tables. This is not
	a problem to add some since we also copy .rel.got (rel.dyn) in
	EXTPLT on ET_DYN, but it is not implemented for now.



---[ C. Extending static executables



        Now we would like to be able to debug static binary the same way 
	we do for dynamic ones. Since we cannot inject e2dbg using 
	DT_NEEDED dependances on static binaries, the idea is to inject 
	e2dbg as ET_REL into ET_EXEC since it is possible on static 
	binaries. E2dbg as many more dependancies than a simple host.c 
	program. The extended idea is to inject the missing part of 
	static libraries when it is necessary.

	We have to resolve dependancies on-the-fly while ET_REL injection
        is performed. For that we will use a simple recursive algorithm
	on the existing relocation code : when a symbol is not found
	at relocation time, either it is a old_* symbol so it is delayed
	in a second stage relocation time (Indeed, old symbols appears
	at redirection time, which is done after the injection of the 
	ET_REL file so we miss that symbol at first stage), or the 
	function symbol is definitely unknown and we need to add 
	information so that the rtld can resolve it as well.

        To be able to find the suitable ET_REL to inject, ELFsh load all
        the ET_REL from static library (.a) then the resolution is done
        using this pool of binaries. The workspace feature of elfsh is
	quite useful for this, when sessions are performed on more than
	a thousand of ET_EXEC ELF files at a time (after extracting
	modules from libc.a and others static librairies, for instance).

        Circular dependancies are solved by using second stage relocation
        when the required symbol is in a file that is being injected after
	the current file. The same second stage relocation mechanism
	is used when we need to relocate ET_REL objects that use OLD
	symbols. Since OLD symbols are injected at redirection time and
	ET_REL files should be injected before (so that we can use
	functions from the ET_REL object as hook functions), we do not
	have OLD symbols at relocation time. The second stage relocation
	is then triggered at save time (for on disk modifications) or
	recursively solved when injecting multiple ET_REL with circular
	relocation dependances.

        A problem is remaining, as for now we had one PT_LOAD by injected
        section, we quickly reach more than 500 PT_LOAD. This seems to be
        a bit too much for a regular ELF static file. We need to improve
	the PT_LOAD allocation mechanism so that we can inject bigger
	extension to such host binaries.

        This technique provide the same features as EXTPLT but for static
        binaries : we can inject what we want (regardless of what the host
        binary contains).

        So here is a smaller working example:


 ========= BEGIN DUMP 36 =========

 elfsh@WTH $ cat host.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>

 int     legit_func(char *str)
 {
   puts("legit func !");
   return (0);
 }

 int main()
 {
   char  *str;
   char  buff[BUFSIZ];
   read(0, buff, BUFSIZ-1);

   puts("First_puts");

   puts("Second_puts");

   fflush(stdout);

   legit_func("test");

   return (0);
 }

 elfsh@WTH $ file a.out
 a.out: ELF 32-bit LSB executable, Intel 80386, statically linked, 
 not stripped

 elfsh@WTH $ ./a.out

 First_puts
 Second_puts
 legit func !

 ========= END DUMP 36 =========

	   
	   The injected file source code is as follow :


 ========= BEGIN DUMP 37 =========

 elfsh@WTH $ cat rel2.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 #include <netdb.h>


 int     glvar_testreloc = 42;
 int     glvar_testreloc_bss;
 char    glvar_testreloc_bss2;
 short   glvar_testreloc_bss3;


 int     hook_func(char *str)
 {
   int sd;

   printf("hook func %s !\n", str);

   return (old_legit_func(str));
 }


 int     puts_troj(char *str)
 {
   int   local = 1;
   char  *str2;
   int   fd;
   char  name[16];
   void  *a;

   str2 = malloc(10);
   *str2 = 'Z';
   *(str2 + 1) = 0x00;

   glvar_testreloc_bss  = 43;
   glvar_testreloc_bss2 = 44;
   glvar_testreloc_bss3 = 45;

   memset(name, 0, 16);

   printf("Trojan injected ET_REL takes control now "
          "[%s:%s:%u:%u:%hhu:%hu:%u] \n",
          str2, str,
          glvar_testreloc,
          glvar_testreloc_bss,
          glvar_testreloc_bss2,
          glvar_testreloc_bss3,
          local);

  free(str2);

  gethostname(name, 15);
  printf("hostname : %s\n", name);

  printf("printf called from puts_troj [%s] \n", str);

  fd = open("/etc/services", 0, O_RDONLY);

  if (fd)
    {
     if ((a = mmap(0, 100, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *) -1)
        {
          perror("mmap");
          close(fd);
          printf("mmap failed : fd: %d\n", fd);
          return (-1);
        }
      printf("-=-=-=-=-=- BEGIN /etc/services %d -=-=-=-=-=\n", fd);
      printf("host : %.60s\n", (char *) a);
      printf("-=-=-=-=-=- END   /etc/services %d -=-=-=-=-=\n", fd);
      printf("mmap succeed fd : %d\n", fd);
      close(fd);
    }


   old_puts(str);
   fflush(stdout);
   return (0);
 }

 ========= END DUMP 37 =========
	   

	   The load_lib.esh script, generated using a small bash
	   script, looks like this :


 ========= BEGIN DUMP 38 =========

 elfsh@WTH $ head -n 10 load_lib.esh
 #!../../../vm/elfsh
 load libc/init-first.o
 load libc/libc-start.o
 load libc/sysdep.o
 load libc/version.o
 load libc/check_fds.o
 load libc/libc-tls.o
 load libc/elf-init.o
 load libc/dso_handle.o
 load libc/errno.o
 
 ========= END DUMP 38 =========


           Here is the injection ELFsh script:


 ========= BEGIN DUMP 39 =========

 elfsh@WTH $ cat relinject.esh
 #!../../../vm/elfsh

 exec gcc -g3 -static host.c
 exec gcc -g3 -static rel2.c -c

 load a.out
 load rel2.o

 source ./load_lib.esh

 reladd 1 2

 redir puts puts_troj
 redir legit_func hook_func

 save fake_aout

 quit

 ========= END DUMP 39 =========


           Stripped output of the injection :


 ========= BEGIN DUMP 40 =========
 elfsh@WTH $ ./relinject.esh

         The ELF shell 0.65 (32 bits built) .::.

         .::. This software is under the General Public License V.2
         .::. Please visit http://www.gnu.org

 ~exec gcc -g3 -static host.c

 [*] Command executed successfully

 ~exec gcc -g3 -static rel2.c -c

 [*] Command executed successfully

 ~load a.out
 [*] Sun Jul 31 16:37:32 2005 - New object a.out loaded

 ~load rel2.o
 [*] Sun Jul 31 16:37:32 2005 - New object rel2.o loaded

 ~source ./load_lib.esh
 ~load libc/init-first.o
 [*] Sun Jul 31 16:37:33 2005 - New object libc/init-first.o loaded

 ~load libc/libc-start.o
 [*] Sun Jul 31 16:37:33 2005 - New object libc/libc-start.o loaded

 ~load libc/sysdep.o
 [*] Sun Jul 31 16:37:33 2005 - New object libc/sysdep.o loaded

 ~load libc/version.o
 [*] Sun Jul 31 16:37:33 2005 - New object libc/version.o loaded

 [[... 1414 files later ...]]

 [*] ./load_lib.esh sourcing -OK-

 ~reladd 1 2

 [*] ET_REL rel2.o injected succesfully in ET_EXEC a.out

 ~redir puts puts_troj

 [*] Function puts redirected to addr 0x080B7026 <puts_troj>

 ~redir legit_func hook_func

 [*] Function legit_func redirected to addr 0x080B7000 <hook_func>

 ~save fake_aout

 [*] Object fake_aout saved successfully

 ~quit

 [*] Unloading object 1 (libpthreadnonshared/pthread_atfork.oS)
 [*] Unloading object 2 (libpthread/ptcleanup.o)
 [*] Unloading object 3 (libpthread/pthread_atfork.o)
 [*] Unloading object 4 (libpthread/old_pthread_atfork.o)

 [[... 1416 files later ...]]

         .:: Bye -:: The ELF shell 0.65

 ========= END DUMP 40 =========


           Does it works ?


 ========= BEGIN DUMP 41 =========

 elfsh@WTH $ ./fake_aout

 Trojan injected ET_REL takes control now [Z:First_puts:42:43:44:45:1]
 hostname : WTH
 printf called from puts_troj [First_puts]
 -=-=-=-=-=- BEGIN /etc/services 3 -=-=-=-=-=
 host : # /etc/services
 #
 # Network services, Internet style
 #
 # Not
 -=-=-=-=-=- END   /etc/services 3 -=-=-=-=-=
 mmap succeed fd : 3
 First_puts
 Trojan injected ET_REL takes control now [Z:Second_puts:42:43:44:45:1]
 hostname : WTH
 printf called from puts_troj [Second_puts]
 -=-=-=-=-=- BEGIN /etc/services 3 -=-=-=-=-=
 host : # /etc/services
 #
 # Network services, Internet style
 #
 # Not
 -=-=-=-=-=- END   /etc/services 3 -=-=-=-=-=
 mmap succeed fd : 3
 Second_puts
 hook func test !
 Trojan injected ET_REL takes control now [Z:legit func !:42:43:44:45:1]
 hostname : WTH
 printf called from puts_troj [legit func !]
 -=-=-=-=-=- BEGIN /etc/services 3 -=-=-=-=-=
 host : # /etc/services
 #
 # Network services, Internet style
 #
 # Not
 -=-=-=-=-=- END   /etc/services 3 -=-=-=-=-=
 mmap succeed fd : 3
 legit func !
 ========= END DUMP 41 ========= 


           Yes, It's working. Now have a look at the fake_aout static
	   file :



 ========= BEGIN DUMP 42 =========

 elfsh@WTH $ ../../../vm/elfsh  -f ./fake_aout -s

 [*] Object ./fake_aout has been loaded (O_RDONLY)

 [SECTION HEADER TABLE .::. SHT is not stripped]
 [Object ./fake_aout]

 [000] 0x00000000 -------                             foff:000000 sz:00000
 [001] 0x080480D4 a------ .note.ABI-tag               foff:069844 sz:00032
 [002] 0x08048100 a-x---- .init                       foff:069888 sz:00023
 [003] 0x08048120 a-x---- .text                       foff:69920 sz:347364
 [004] 0x0809CE10 a-x---- __libc_freeres_fn           foff:417296 sz:02222
 [005] 0x0809D6C0 a-x---- .fini                       foff:419520 sz:00029
 [006] 0x0809D6E0 a------ .rodata                     foff:419552 sz:88238
 [007] 0x080B2F90 a------ __libc_atexit               foff:507792 sz:00004
 [008] 0x080B2F94 a------ __libc_subfreeres           foff:507796 sz:00036
 [009] 0x080B2FB8 a------ .eh_frame                   foff:507832 sz:03556
 [010] 0x080B4000 aw----- .ctors                      foff:512000 sz:00012
 [011] 0x080B400C aw----- .dtors                      foff:512012 sz:00012
 [012] 0x080B4018 aw----- .jcr                        foff:512024 sz:00004
 [013] 0x080B401C aw----- .data.rel.ro                foff:512028 sz:00044
 [014] 0x080B4048 aw----- .got                        foff:512072 sz:00004
 [015] 0x080B404C aw----- .got.plt                    foff:512076 sz:00012
 [016] 0x080B4060 aw----- .data                       foff:512096 sz:03284
 [017] 0x080B4D40 aw----- .bss                        foff:515380 sz:04736
 [018] 0x080B5FC0 aw----- __libc_freeres_ptrs         foff:520116 sz:00024
 [019] 0x080B6000 aw----- rel2.o.bss                  foff:520192 sz:04096
 [020] 0x080B7000 a-x---- rel2.o.text                 foff:524288 sz:04096
 [021] 0x080B8000 aw----- rel2.o.data                 foff:528384 sz:00004
 [022] 0x080B9000 a------ rel2.o.rodata               foff:532480 sz:04096
 [023] 0x080BA000 a-x---- .elfsh.hooks                foff:536576 sz:00032
 [024] 0x080BB000 aw----- libc/printf.o.bss           foff:540672 sz:04096
 [025] 0x080BC000 a-x---- libc/printf.o.text          foff:544768 sz:04096
 [026] 0x080BD000 aw----- libc/gethostname.o.bss      foff:548864 sz:04096
 [027] 0x080BE000 a-x---- libc/gethostname.o.text     foff:552960 sz:04096
 [028] 0x080BF000 aw----- libc/perror.o.bss           foff:557056 sz:04096
 [029] 0x080C0000 a-x---- libc/perror.o.text          foff:561152 sz:04096
 [030] 0x080C1000 a--ms-- libc/perror.o.rodata.str1.1 foff:565248 sz:04096
 [031] 0x080C2000 a--ms-- libc/perror.o.rodata.str4.4 foff:569344 sz:04096
 [032] 0x080C3000 aw----- libc/dup.o.bss              foff:573440 sz:04096
 [033] 0x080C4000 a-x---- libc/dup.o.text             foff:577536 sz:04096
 [034] 0x080C5000 aw----- libc/iofdopen.o.bss         foff:581632 sz:04096
 [035] 0x00000000 ------- .comment                    foff:585680 sz:20400
 [036] 0x080C6000 a-x---- libc/iofdopen.o.text        foff:585728 sz:04096
 [037] 0x00000000 ------- .debug_aranges              foff:606084 sz:00136
 [038] 0x00000000 ------- .debug_pubnames             foff:606220 sz:00042
 [039] 0x00000000 ------- .debug_info                 foff:606262 sz:01600
 [040] 0x00000000 ------- .debug_abbrev               foff:607862 sz:00298
 [041] 0x00000000 ------- .debug_line                 foff:608160 sz:00965
 [042] 0x00000000 ------- .debug_frame                foff:609128 sz:00068
 [043] 0x00000000 ------- .debug_str                  foff:609196 sz:00022
 [044] 0x00000000 ------- .debug_macinfo              foff:609218 sz:28414
 [045] 0x00000000 ------- .shstrtab                   foff:637632 sz:00632
 [046] 0x00000000 ------- .symtab                     foff:640187 sz:30192
 [047] 0x00000000 ------- .strtab                     foff:670379 sz:25442

 [*] Object ./fake_aout unloaded

 elfsh@WTH $ ../../../vm/elfsh  -f ./fake_aout -p

 [*] Object ./fake_aout has been loaded (O_RDONLY)

 [Program Header Table .::. PHT]
 [Object ./fake_aout]

 [00] 0x8037000 -> 0x80B3D9C r-x memsz(511388) foff(000000) =>Loadable seg
 [01] 0x80B4000 -> 0x80B7258 rw- memsz(012888) foff(512000) =>Loadable seg
 [02] 0x80480D4 -> 0x80480F4 r-- memsz(000032) foff(069844) =>Aux. info.
 [03] 0x0000000 -> 0x0000000 rw- memsz(000000) foff(000000) =>Stackflags
 [04] 0x0000000 -> 0x0000000 --- memsz(000000) foff(000000) =>New PaXflags
 [05] 0x80B6000 -> 0x80B7000 rwx memsz(004096) foff(520192) =>Loadable seg
 [06] 0x80B7000 -> 0x80B8000 rwx memsz(004096) foff(524288) =>Loadable seg
 [07] 0x80B8000 -> 0x80B8004 rwx memsz(000004) foff(528384) =>Loadable seg
 [08] 0x80B9000 -> 0x80BA000 rwx memsz(004096) foff(532480) =>Loadable seg
 [09] 0x80BA000 -> 0x80BB000 rwx memsz(004096) foff(536576) =>Loadable seg
 [10] 0x80BB000 -> 0x80BC000 rwx memsz(004096) foff(540672) =>Loadable seg
 [11] 0x80BC000 -> 0x80BD000 rwx memsz(004096) foff(544768) =>Loadable seg
 [12] 0x80BD000 -> 0x80BE000 rwx memsz(004096) foff(548864) =>Loadable seg
 [13] 0x80BE000 -> 0x80BF000 rwx memsz(004096) foff(552960) =>Loadable seg
 [14] 0x80BF000 -> 0x80C0000 rwx memsz(004096) foff(557056) =>Loadable seg
 [15] 0x80C0000 -> 0x80C1000 rwx memsz(004096) foff(561152) =>Loadable seg
 [16] 0x80C1000 -> 0x80C2000 rwx memsz(004096) foff(565248) =>Loadable seg
 [17] 0x80C2000 -> 0x80C3000 rwx memsz(004096) foff(569344) =>Loadable seg
 [18] 0x80C3000 -> 0x80C4000 rwx memsz(004096) foff(573440) =>Loadable seg
 [19] 0x80C4000 -> 0x80C5000 rwx memsz(004096) foff(577536) =>Loadable seg
 [20] 0x80C5000 -> 0x80C6000 rwx memsz(004096) foff(581632) =>Loadable seg
 [21] 0x80C6000 -> 0x80C7000 rwx memsz(004096) foff(585728) =>Loadable seg

 [SHT correlation]
 [Object ./fake_aout]

 [*] SHT is not stripped

 [00] PT_LOAD            .note.ABI-tag .init .text __libc_freeres_fn .fini
                         .rodata __libc_atexit __libc_subfreeres .eh_frame
 [01] PT_LOAD           .ctors .dtors .jcr .data.rel.ro .got .got.plt 
			.data
                        .bss __libc_freeres_ptrs
 [02] PT_NOTE           .note.ABI-tag
 [03] PT_GNU_STACK
 [04] PT_PAX_FLAGS
 [05] PT_LOAD           rel2.o.bss
 [06] PT_LOAD           rel2.o.text
 [07] PT_LOAD           rel2.o.data
 [08] PT_LOAD           rel2.o.rodata
 [09] PT_LOAD           .elfsh.hooks
 [10] PT_LOAD           libc/printf.o.bss
 [11] PT_LOAD           libc/printf.o.text
 [12] PT_LOAD           libc/gethostname.o.bss
 [13] PT_LOAD           libc/gethostname.o.text
 [14] PT_LOAD           libc/perror.o.bss
 [15] PT_LOAD           libc/perror.o.text
 [16] PT_LOAD           libc/perror.o.rodata.str1.1
 [17] PT_LOAD           libc/perror.o.rodata.str4.4
 [18] PT_LOAD           libc/dup.o.bss
 [19] PT_LOAD           libc/dup.o.text
 [20] PT_LOAD           libc/iofdopen.o.bss |.comment
 [21] PT_LOAD           libc/iofdopen.o.text
 [*] Object ./fake_aout unloaded

 ========= END DUMP 42 =========


         We can notice the ET_REL really injected : printf.o@libc,
         dup.o@libc, gethostname.o@libc, perror.o@libc and
         iofdopen.o@libc.

         Each injected file create several PT_LOAD segments. For this
	 example it is okay, but for injecting E2dbg that is really too 
	 much.

         This technique will be improved as soon as possible by reusing
         PT_LOAD entry when this is possible.



----[ D. Architecture independant algorithms



      In this part, we give all the architecture independent algorithms
      that were developed for the new residency techniques in memory, 
      ET_DYN libraries, or static executables.

      The new generic ET_REL injection algorithm is not that different 
      from the one presented in the first Cerberus Interface article [0], 
      that is why we only give it again in its short form. However, the 
      new algorithm has improved in modularity and portability. We will 
      detail some parts of the algorithm that were not explained in 
      previous articles. The implementation mainly takes place in 
      elfsh_inject_etrel() in the relinject.c file :

      
      New generic relocation algorithm
     +--------------------------------+

      1/ Inject ET_REL BSS after the HOST BSS in a dedicated section (new)

      2/ FOREACH section in ET_REL object
       [
	  IF [ Section is allocatable and Section is not BSS ]
	  [
		- Inject section in Host file or memory
	  ]
       ]
       
      3/ Fuze ET_REL and host file symbol tables

      4/ Relocate the ET_REL object (STAGE 1)

      5/ At save time, relocate the ET_REL object 
         (STAGE 2 for old symbols relocations)


      We only had one relocation stage in the past. We had to use another
      one since not all requested symbols are available (like old symbols
      gained from CFLOW redirections that may happen after the ET_REL 
      injection). For ondisk modifications, the second stage relocation 
      is done at save time.

      Some steps in this algorithm are quite straightforward, such as 
      step 1 and step 3. They have been explained in the first Cerberus 
      article [0], however the BSS algorithm has changed for compatibility
      with ET_DYN files and multiple ET_REL injections. Now the BSS is 
      injected just as other sections, instead of adding a complex BSS 
      zones algorithm for always keeping one bss in the program.

      
       ET_DYN / ET_EXEC section injection algorithm
      +--------------------------------------------+


      Injection algorithm for DATA sections does not change between ET_EXEC
      and ET_DYN files. However, code sections injection slighly changed 
      for supporting both binaries and libraries host files. Here is the 
      new algorithm for this operation :

      * Find executable PT_LOAD
      * Fix injected section size for page size congruence

      IF [ Hostfile is ET_EXEC ]
      [	 
	* Set injected section vaddr to lowest mapped section vaddr
	* Substract new section size to new section virtual address
      ]
      ELSE IF [ Hostfile is ET_DYN ]
      [
	* Set injected section vaddr to lowest mapped section vaddr
      ]
      
      * Extend code segment size by newly injected section size

      IF [ Hostfile is ET_EXEC ]
      [
        * Substract injected section vaddr to executable PT_LOAD vaddr
      ] 

      FOREACH [ Entry in PHT ]
      [
	 IF [ Segment is PT_PHDR and Hostfile is ET_EXEC ]
	 [
	   * Substract injected section size to segment p_vaddr / p_paddr
	 ]
	 ELSE IF [ Segment stands after extended PT_LOAD ]
	 [
	   * Add injected section size to segment p_offset
	   IF [ Hostfile is ET_DYN ]
	   [
		* Add injected section size to segment p_vaddr and p_paddr
	   ]
	 ]
      ]

      IF [ Hostfile is ET_DYN ]
      [
	FOREACH [ Relocation entry in every relocation table ]
	[
	     IF [ Relocation offset points after injected section ]
	     [
	        * Shift relocation offset from injected section size
	     ]
	]

	* Shift symbols from injected section size when pointing after it
	* Shift dynamic syms from injected section size (same condition)
	* Shift dynamic entries D_PTR's from injected section size
	* Shift GOT entries from injected section size
	* If existing, Shift ALTGOT entries from injected section size
	* Shift DTORS and CTORS the same way
	* Shift the entry point in ELF header the same way
      ]

      * Inject new SECTION symbol on injected code


       Static ET_EXEC section injection algorithm
      +------------------------------------------+


      This algorithm is used to insert sections inside static binaries. It
      can be found in libelfsh/inject.c in elfsh_insert_static_section() :

      * Pad the injected section size to stay congruent to page size
      * Create a new PT_LOAD program header whoose bounds match the 
        new section bounds.
      * Insert new section using classical algorithm
      * Insert new program header in PHT


       Runtime section injection algorithm in memory
      +---------------------------------------------+
      
      
      This algorithm can be found in libelfsh/inject.c in the function
      elfsh_insert_runtime_section() :

      * Create a new PT_LOAD program header 
      * Insert SHT entry for new runtime section 
        (so we keep a static map up-to-date)
      * Insert new section using the classical algorithm
      * Insert new PT_LOAD in Runtime PHT table (RPHT) with same bounds


      Runtime PHT is a new table that we introduced so that we can 
      separate segments regulary mapped by the dynamic linker (original
      PHT segments) from runtime injected segments. This may lead to an 
      easier algorithm for binary reconstruction from its memory image 
      in the future.            

      We will detail now the core (high level) relocation algorithm as 
      implemented in elfsh_relocate_object() and 
      elfsh_relocate_etrel_section() functions in libelfsh/relinject.c . 
      This code is common for all types of host files and for all 
      relocation stages. It is used at STEP 4 of the general algorithm:

      
      Core portable relocation algorithm
     +----------------------------------+

      This algorithm has never been explained in any paper. Here it is :


      FOREACH Injected ET_REL sections inside the host file
      [
	FOREACH relocation entry in ET_REL file
	[
	   * Find needed symbol in ET_REL for this relocation
	   IF [ Symbol is COMMON or NOTYPE ]
	   [	   
		   * Find the corresponding symbol in Host file.
		   IF [ Symbol is NOT FOUND ]
		   [
		      IF [ symbol is OLD and RELOCSTAGE == 1 ]
		      [
			 * Delay relocation for it
		      ]
		      ELSE
		      [
		        IF [ ET_REL symbol type is NOTYPE ]
			[
			    * Request a new PLT entry and use its address
			     for performing relocation (EXTPLT algorithm)
			]
			ELSE IF [ Host file is STATIC ]
			[
			    * Perform EXTSTATIC technique (next algorithm)
			]
			ELSE
			[
			    * Algorithm failed, return ERROR
			]
		      ]
		   ]
		   ELSE
		   [
		      * Use host file's symbol value
		   ]
	   ]
	   ELSE
	   [
		* Use injected section base address as symbol value
	   ]
	   - Relocate entry (switch/case architecture dependant handler)
	]
      ]
      

      EXTSTATIC relocation extension algorithm
     +----------------------------------------+

      In case the host file is a static file, we can try to get the 
      unknown symbol from relocatables files from static libraries that 
      are available on disk. An example of use of this EXTSTATIC technique
      is located in the testsuite/etrel_inject/ directory.

      Here is the EXTSTATIC algorithm that comes at the specified place
      in the  previous algorithm for providing the same functionality as
      EXTPLT but for static binaries :

      
      FOREACH loaded ET_REL objects in ELFSH
      [
	 IF [ Symbol is found anywhere in current analyzed ET_REL ]
	 [
	     IF [ Found symbol is strongest than current result ]
	     [
	        * Update best symbol result and associated ET_REL file	
	     ]
	     ELSE
	     [
	        * Discard current iteration result
	     ]
	 ]
      ]
      * Inject the ET_REL dependency inside Host file
      * Use newly injected symbol in hostfile as relocation symbol in core
        relocation algorithm.


       Strongest symbol algorithm
      +--------------------------+

      When we have to choose between multiple symbols that have the same
      name in different objects (either during static or runtime 
      injection), we use this simple algorithm to determine which one 
      to use :


      IF [ Current chosen symbol has STT_NOTYPE ]
      [
         * Symbol becomes temporary choice
      ]
      ELSE IF [ Candidate symbol has STT_NOTYPE ]
      [
         * Symbol becomes temporary choice
      ]
      ELSE IF [ Candidate symbol binding > Chosen symbol binding ]
      [
	 * Candidate symbol becomes Chosen symbol
      ]



-------[ VI. Past and present


	 In the past we have shown that ET_REL injection into 
	 non-relocatable ET_EXEC object is possible. This paper presented 
	 multiple extensions and ports to this residency technique 
	 (ET_DYN and static executables target). Coupled to the EXTPLT 
	 technique that allow for a complete post-linking of the host 
	 file, we can add function definitions and use unknown functions 
	 in the software extension. All those static injection 
	 techniques worse when all PaX options are enabled on the 
	 modified binary. Of course, the position independant and stack 
	 smashing protection features of hardened Gentoo does not protect
	 anything when it comes to binary manipulation, either performed
	 on disk or at runtime.

	 We have also shown that it is possible to debug without using 
	 the ptrace system call, which open the door for new reverse 
	 engineering and embedded debugging methodology that bypass known 
	 anti-debugging techniques. The embedded debugger is not 
	 completely PaX proof and it is still necessary to disable the 
	 mprotect flag. Even if it does not sound like a real problem, 
	 we are still investigating on how to put breakpoints (e.g. 
	 redirections) without disabling it.

	 Our core techniques are portable to many architectures (x86, 
	 alpha, mips, sparc) on both 32bits and 64bits files. However 
	 our proof of concept debugger was done for x86 only. We believe 
	 that our techniques are portable enough to be able to provide
	 the debugger for other architectures without much troubles.

	 Share and enjoy the framework, contributions are welcome.


-------[ VII. Greetings  


	 We thank all the peoples at the WhatTheHack party 2005 in 
	 Netherlands. We add much fun with you guys and again we will 
	 come in the future. 

	 Special thanks go to andrewg for teaching us the sigaction 
	 technique, dvorak for his interest in the optimization on the
	 the ALTPLT technique version 2 for the SPARC architecture,
	 sk for libasm, and solar for providing us the ET_DYN pie/ssp
	 testsuite.

	 Respects go to Devhell Labs, the PaX team, Phrackstaff, GOBBLES,
	 MMHS, ADM, and Synnergy Networks. Final shoutouts to s/ash from 
	 RTC for driving us to WTH and the Coconut Crew for everything 
	 and the rest, you know who you are.


-------[ VIII. References


 [0] The Cerberus ELF Interface				mayhem
     http://www.phrack.org/show.php?p=61&a=8

 [1] The GNU debugger					GNU project
     http://www.gnu.org/software/gdb/

 [2] PaX / grsecurity					The PaX team
     http://pax.grsecurity.net/

 [3] binary reconstruction from a core image		Silvio Cesare
     http://vx.netlux.org/lib/vsc03.html

 [4] Antiforensic evolution: Self			Ripe & Pluf
     http://www.phrack.org/show.php?p=63&a=11

 [5] Next-Gen. Runtime binary encryption		Zeljko Vbra
     http://www.phrack.org/show.php?p=63&a=13

 [6] Fenris						Michal Zalewski
     http://lcamtuf.coredump.cx/fenris/

 [7] Ltrace						Ltrace team
     http://freshmeat.net/projects/ltrace/

 [8] The dude (replacement to ptrace)			Mammon
     http://www.eccentrix.com/members/mammon/Text/d\
     ude_paper.txt

 [9] Binary protection schemes				Andrewg	
     http://www.codebreakers-journal.com/viewar\
     ticle.php?id=51&layout=abstract

 [10] ET_REL injection in memory			JP
      http://www.whatever.org.ar/~cuco/MERCANO.TXT
      
 [11] Hardened Gentoo project				Hardened team
      http://www.gentoo.org/proj/en/hardened/

 [12] Unpacking by Code Injection			Eduardo Labir
      http://www.codebreakers-journal.com/viewart\
      icle.php?id=36&layout=abstract
      
[ News ] [ Paper Feed ] [ Issues ] [ Authors ] [ Archives ] [ Contact ]
© Copyleft 1985-2021, Phrack Magazine.