class SyscallHooker

Constants

CTX

Public Instance Methods

inject(sysnr, *args) click to toggle source
# File samples/linux_injectsyscall.rb, line 21
def inject(sysnr, *args)
        sysnr = syscallnr[sysnr] || sysnr

        syscall
        puts '[*] waiting syscall'
        Process.waitpid(@pid)

        savedctx = CTX.inject({}) { |ctx, reg| ctx.update reg => peekusr(REGS_I386[reg]) }

        eip = (savedctx['EIP'] - 2) & 0xffffffff
        fu = readmem(eip, 2)
        if fu == "\xcd\x80"
                mode = :int80
        elsif fu == "\xeb\xf3" and readmem(eip-14, 7).unpack('H*').first == "51525589e50f34"  # aoenthuasn
                mode = :sysenter
        elsif fu == "\x0f\x05"
                mode = :syscall
        else
                puts 'unhandled syscall convention, aborting, code = ' + readmem(eip-4, 8).unpack('H*').first
                cont
                return self
        end

        if args.length > 5
                puts 'too may arguments, unsupported, aborting'
        else
                puts "[*] hooking #{syscallnr.index(savedctx['ORIG_EAX'])}"

                # stack pointer to store buffers to
                esp_ptr = savedctx['ESP']
                write_string = lambda { |s|
                        esp_ptr -= s.length
                        esp_ptr &= 0xffff_fff0
                        writemem(esp_ptr, s)
                        [esp_ptr].pack('L').unpack('l').first
                }
                set_arg = lambda { |a|
                        case a
                        when String; write_string[a + 0.chr]
                        when Array; write_string[a.map { |aa| set_arg[aa] }.pack('L*')]
                        else a
                        end
                }
                args.zip(CTX).map { |arg, reg|
                        # set syscall args, put buffers on the stack as needed
                        pokeusr(REGS_I386[reg], set_arg[arg])
                }
                # patch syscall number
                pokeusr(REGS_I386['ORIG_EAX'], sysnr)


                # run hooked syscall
                syscall
                Process.waitpid(@pid)
                retval = peekusr(REGS_I386['EAX'])
                puts "[*] retval: #{'%X' % retval}#{" (Errno::#{ERRNO.index(-retval)})" if retval < 0}"

                if syscallnr.index(sysnr) == 'execve' and retval >= 0
                        cont
                        return self
                end

                # restore eax & eip to run the orig syscall
                savedctx['EIP'] -= 2
                savedctx['EAX'] = savedctx['ORIG_EAX']
                savedctx.each { |reg, val| pokeusr(REGS_I386[reg], val) }
        end

        self
end