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