@@ -434,10 +434,11 @@ def lkm_get_init(self, ql):
434434 for nsym , symbol in enumerate (section .iter_symbols ()):
435435 if symbol .name == 'init_module' :
436436 addr = symbol .entry .st_value + elffile .get_section (symbol ['st_shndx' ])['sh_offset' ]
437- logging .info ("init_module = 0x%x" % addr )
437+ logging .info ("[+] init_module = 0x%x" % addr )
438438 return addr
439439
440440 # not found. FIXME: report error on invalid module??
441+ logging .warning ("[!] invalid module? symbol init_module not found" )
441442 return - 1
442443
443444 def lkm_dynlinker (self , ql , mem_start ):
@@ -458,7 +459,8 @@ def get_symbol(elffile, name):
458459 rev_reloc_symbols = {}
459460
460461 # dump_mem("XX Original code at 15a1 = ", ql.mem.read(0x15a1, 8))
461- for section in elffile .iter_sections ():
462+ _sections = list (elffile .iter_sections ())
463+ for section in _sections :
462464 # only care about reloc section
463465 if not isinstance (section , RelocationSection ):
464466 continue
@@ -467,9 +469,15 @@ def get_symbol(elffile, name):
467469 if section .name == ".rela.gnu.linkonce.this_module" :
468470 continue
469471
472+ dest_sec_idx = section .header .get ('sh_info' , None )
473+ if dest_sec_idx is not None and dest_sec_idx < len (_sections ):
474+ dest_sec = _sections [dest_sec_idx ]
475+ if dest_sec .header ['sh_flags' ] & 2 == 0 :
476+ # The target section is not loaded into memory, so just continue
477+ continue
478+
470479 # The symbol table section pointed to in sh_link
471480 symtable = elffile .get_section (section ['sh_link' ])
472-
473481 for rel in section .iter_relocations ():
474482 if rel ['r_info_sym' ] == 0 :
475483 continue
@@ -564,15 +572,33 @@ def get_symbol(elffile, name):
564572 val = rev_reloc_symbols [symbol_name ] + val - loc
565573 ql .mem .write (loc , ql .pack32 (val & 0xFFFFFFFF ))
566574
567- elif describe_reloc_type (rel ['r_info_type' ], elffile ) == 'R_386_32' :
575+ elif describe_reloc_type (rel ['r_info_type' ], elffile ) in ( 'R_386_32' , 'R_MIPS_32' ) :
568576 val = ql .unpack (ql .mem .read (loc , 4 ))
569577 val = rev_reloc_symbols [symbol_name ] + val
570578 ql .mem .write (loc , ql .pack32 (val & 0xFFFFFFFF ))
571579
580+ elif describe_reloc_type (rel ['r_info_type' ], elffile ) == 'R_MIPS_HI16' :
581+ # actual relocation is done in R_MIPS_LO16
582+ prev_mips_hi16_loc = loc
583+
584+ elif describe_reloc_type (rel ['r_info_type' ], elffile ) == 'R_MIPS_LO16' :
585+ val = ql .unpack16 (ql .mem .read (prev_mips_hi16_loc + 2 , 2 )) << 16 | ql .unpack16 (ql .mem .read (loc + 2 , 2 ))
586+ val = rev_reloc_symbols [symbol_name ] + val
587+ # *(word)(mips_lo16_loc + 2) is treated as signed
588+ if (val & 0xFFFF ) >= 0x8000 :
589+ val += (1 << 16 )
590+
591+ ql .mem .write (prev_mips_hi16_loc + 2 , ql .pack16 (val >> 16 ))
592+ ql .mem .write (loc + 2 , ql .pack16 (val & 0xFFFF ))
593+
594+ else :
595+ raise QlErrorNotImplemented ("[!] Relocation type %s not implemented" % describe_reloc_type (rel ['r_info_type' ], elffile ))
596+
572597 return rev_reloc_symbols
573598
574599 def load_driver (self , ql , stack_addr , loadbase = 0 ):
575600 elfhead = super ().parse_header ()
601+ elfdata_mapping = self .get_elfdata_mapping ()
576602
577603 # Determine the range of memory space opened up
578604 mem_start = - 1
@@ -590,21 +616,16 @@ def load_driver(self, ql, stack_addr, loadbase=0):
590616
591617 # FIXME
592618 mem_start = 0x1000
593- mem_end = mem_start + int (len (self . elfdata ) / 0x1000 + 1 ) * 0x1000
619+ mem_end = mem_start + int (len (elfdata_mapping ) / 0x1000 + 1 ) * 0x1000
594620
595621 # map some memory to intercept external functions of Linux kernel
596- ql .mem .map (API_HOOK_MEM , 0x1000 )
597-
598- # print("load addr = %x, size = %x" %(loadbase + mem_start, mem_end - mem_start))
599- ql .mem .map (loadbase + mem_start , mem_end - mem_start )
622+ ql .mem .map (API_HOOK_MEM , 0x1000 , info = "[api_mem]" )
600623
601624 logging .info ("[+] loadbase: %x, mem_start: %x, mem_end: %x" % (loadbase , mem_start , mem_end ))
602-
603- ql .mem .write (loadbase + mem_start , self .elfdata )
604- # dump_mem("Dumping some bytes:", self.elfdata[0x64 : 0x84])
625+ ql .mem .map (loadbase + mem_start , mem_end - mem_start , info = ql .path )
626+ ql .mem .write (loadbase + mem_start , elfdata_mapping )
605627
606628 entry_point = self .lkm_get_init (ql ) + loadbase + mem_start
607-
608629 ql .brk_address = mem_end + loadbase
609630
610631 # Set MMAP addr
@@ -619,7 +640,6 @@ def load_driver(self, ql, stack_addr, loadbase=0):
619640 new_stack = self .alignment (new_stack )
620641
621642 # self.ql.os.elf_entry = self.elf_entry = loadbase + elfhead['e_entry']
622-
623643 self .ql .os .entry_point = self .entry_point = entry_point
624644 self .elf_entry = self .ql .os .elf_entry = self .ql .os .entry_point
625645
@@ -631,7 +651,7 @@ def load_driver(self, ql, stack_addr, loadbase=0):
631651 # remember address of syscall table, so external tools can access to it
632652 ql .os .syscall_addr = SYSCALL_MEM
633653 # setup syscall table
634- ql .mem .map (SYSCALL_MEM , 0x1000 )
654+ ql .mem .map (SYSCALL_MEM , 0x1000 , info = "[syscall_mem]" )
635655 # zero out syscall table memory
636656 ql .mem .write (SYSCALL_MEM , b'\x00 ' * 0x1000 )
637657
@@ -642,7 +662,7 @@ def load_driver(self, ql, stack_addr, loadbase=0):
642662 tmp_sc = sc .replace ("sys_" , "NR_" )
643663 if tmp_sc in globals ():
644664 syscall_id = globals ()[tmp_sc ]
645- print ("Writing syscall %s to [0x%x]" % (sc , SYSCALL_MEM + ql .pointersize * syscall_id ))
665+ logging . debug ("Writing syscall %s to [0x%x]" % (sc , SYSCALL_MEM + ql .pointersize * syscall_id ))
646666 ql .mem .write (SYSCALL_MEM + ql .pointersize * syscall_id , ql .pack (rev_reloc_symbols [sc ]))
647667
648668 # write syscall addresses into syscall table
@@ -657,3 +677,24 @@ def load_driver(self, ql, stack_addr, loadbase=0):
657677 ql .import_symbols [self .ql .os .hook_addr ] = hook_sys_read
658678 ql .import_symbols [self .ql .os .hook_addr + 1 * ql .pointersize ] = hook_sys_write
659679 ql .import_symbols [self .ql .os .hook_addr + 2 * ql .pointersize ] = hook_sys_open
680+
681+ def get_elfdata_mapping (self ):
682+ elfdata_mapping = bytearray ()
683+ elfdata_mapping .extend (self .getelfdata (0 , self .elfhead ['e_ehsize' ])) #elf header
684+
685+ for section in self .parse_sections ():
686+ if section .header ['sh_flags' ] & 2 : # alloc flag
687+ sh_offset = section .header ['sh_offset' ]
688+ sh_size = section .header ['sh_size' ]
689+
690+ # align section addr
691+ elfdata_len = len (elfdata_mapping )
692+ if elfdata_len < sh_offset :
693+ elfdata_mapping .extend (b'\x00 ' * (sh_offset - elfdata_len ))
694+
695+ if section .header ['sh_type' ] == 'SHT_NOBITS' :
696+ elfdata_mapping .extend (b'\x00 ' * sh_size )
697+ else :
698+ elfdata_mapping .extend (self .getelfdata (sh_offset , sh_size ))
699+
700+ return bytes (elfdata_mapping )
0 commit comments