Saturday, November 15, 2014

Finding Call Reference Hooks in Mac Memory


In this blog post the call reference to the function _vnode_pagein in the function _ps_read_file will be modified to show a call reference modification and  and a Volatility Framework plugin to detect this type of hooking will be presented.


Find a location to potentially inject the code, in this case 0xffffff7f89dba6e5

## This section gets the address for possible code injection in the com.vmware.kext.vmhgfs kext
#get address for the kernel extension (kext) list
p = self.addrspace.profile.get_symbol("_kmod")
kmodaddr = obj.Object("Pointer", offset = p, vm = self.addrspace)
kmod = kmodaddr.dereference_as("kmod_info")
#loop thru list to find suitable target to place the trampoline in
while kmod.is_valid():
    str(kmod.name)
    if str(kmod.name) == "com.vmware.kext.vmhgfs":
        mh = obj.Object('mach_header_64', offset = kmod.address,vm = self.addrspace)
        o = mh.obj_offset
        # skip header data
        o += 32
        txt_data_end = 0
        # loop thru segments to find __TEXT
        for i in xrange(0, mh.ncmds):
            seg = obj.Object('segment_command_64', offset = o, vm = self.addrspace)
            if seg.cmd not in [0x26]:
                for j in xrange(0, seg.nsects):
                    sect = obj.Object('section_64', offset = o + 0x48 + 80*(j), vm = self.addrspace)
                    sect_name = "".join(map(str, sect.sectname)).strip(' \t\r\n\0')
                    # find __text section
                    if seg.cmd == 0x19 and str(seg.segname) == "__TEXT" and sect_name == "__text":
                        print "{0:#10x} {1:#2x} {2} {3}".format(sect.addr,seg.cmd, seg.segname, sect_name)
                        txt_data_end = sect.addr + sect.m('size') - 50
                        break
            if txt_data_end != 0:
                break
        print "The fake function will be at {0:#10x}".format(txt_data_end)
        break
    kmod = kmod.next

The addresses for the functions in question in the original memory sample:

Function Name Original Address
_ps_read_file 0xffffff80086049b0
_vnode_pagein 0xffffff80089be9c0

The disassembly of the original _ps_read_file showing the call reference to _vnode_pagein:

0xffffff80086049b0 55                               PUSH RBP
0xffffff80086049b1 4889e5                           MOV RBP, RSP
0xffffff80086049b4 4156                             PUSH R14
0xffffff80086049b6 53                               PUSH RBX
0xffffff80086049b7 4883ec10                         SUB RSP, 0x10
0xffffff80086049bb 4d89ce                           MOV R14, R9
0xffffff80086049be 4489c0                           MOV EAX, R8D
0xffffff80086049c1 c1e80c                           SHR EAX, 0xc
0xffffff80086049c4 488d1d75a96a00                   LEA RBX, [RIP+0x6aa975]
0xffffff80086049cb ff0483                           INC DWORD [RBX+RAX*4]
0xffffff80086049ce 034f18                           ADD ECX, [RDI+0x18]
0xffffff80086049d1 488b3f                           MOV RDI, [RDI]
0xffffff80086049d4 448b4d10                         MOV R9D, [RBP+0x10]
0xffffff80086049d8 48c7042400000000                 MOV QWORD [RSP], 0x0
0xffffff80086049e0 e8db9f3b00                       CALL 0xffffff80089be9c0
0xffffff80086049e5 89c1                             MOV ECX, EAX


Modify the CALL instruction to refer to the fake location (0xffffff7f89dba6e5):

In e8db9f3b00, e8 is the call instruction and the rest is the relative location of the call reference (CALL address less the next offset).

Original Reference Fake Reference Code to Write
0x003B9FDB         0x817B5D00 \xe8\x00\x5D\x7B\x81

After we rewrite the code at the original CALL at 0xffffff80086049e0 the disassembly will look like the following:

0xffffff80086049b0 55                               PUSH RBP
0xffffff80086049b1 4889e5                           MOV RBP, RSP
0xffffff80086049b4 4156                             PUSH R14
0xffffff80086049b6 53                               PUSH RBX
0xffffff80086049b7 4883ec10                         SUB RSP, 0x10
0xffffff80086049bb 4d89ce                           MOV R14, R9
0xffffff80086049be 4489c0                           MOV EAX, R8D
0xffffff80086049c1 c1e80c                           SHR EAX, 0xc
0xffffff80086049c4 488d1d75a96a00                   LEA RBX, [RIP+0x6aa975]
0xffffff80086049cb ff0483                           INC DWORD [RBX+RAX*4]
0xffffff80086049ce 034f18                           ADD ECX, [RDI+0x18]
0xffffff80086049d1 488b3f                           MOV RDI, [RDI]
0xffffff80086049d4 448b4d10                         MOV R9D, [RBP+0x10]
0xffffff80086049d8 48c7042400000000                 MOV QWORD [RSP], 0x0
0xffffff80086049e0 e8005d7b81                       CALL 0xffffff7f89dba6e5
0xffffff80086049e5 89c1                             MOV ECX, EAX


The call to _vnode_pagein has been modified to call the code at the fake address.

The output for the plugin after modifying the memory sample is as follows:



The check_call_references.py plugin can be found at my GitHub repository [2].

References
[1] http://reverse.put.as/SyScan360%202013%20Presentation.pdf
[2] https://github.com/siliconblade/volatility/blob/master/mac/check_call_reference.py

No comments:

Post a Comment