Reball to Unlock
Introduction
Not too long ago I used Android phones that were completely unencrypted. At the time, I felt confident that anyone trying to steal my phone would just wipe it so they could resell it, rather than trying to steal my actual data. Eventually, I wised up and switched over to only using phones that had some form of user data encryption with the key stored in a TPM. The question is, how difficult would it have been to steal my data back in the day? Wanting to answer this question and improve my microcomponent handling/soldering skills, I decided to pull one of my old phones apart, dump the internal flash, and analyze it.
The Target
Here is my dented, dusty LG “Sunset” L33L “the device that gives you superior viewing power and security.” Oh wait, “security”? I guess it must be encrypted after all ;).
Disassembly
To give credit where credit is due, I do miss these old phones where you could just pop the back off. Not only can you easily replace the main point of failure, but the SIM and SD cards can be swapped without special tools too.
After removing the battery and unscrewing the back we finally see the PCB, but all the interesting components are hidden under shields:
After using a heatgun to get two of those shields off, I finally found what I was looking for:
Under that sticker was this chip:
The Chip
That chip label was a real challenge to read. After shining a flashlight around I finally came up with SAMSUNG KMQN1000SM-B316. I could not find an official datasheet for this online, but I was able to find out that this is an 8GB BGA221 eMMC chip. 8GB? They were being really stingy with memory on this. Remembering back, I did have to use an SD card for photos and screenshots. That was definitely unencrypted.
Regardless, eMMC chips actually have standardized pinouts defined by JEDEC. This means any generic adapter that accepts a BGA221 chip should work for this one as well.
The Adapter
There are test sockets specifically designed for BGA221, but they can be quite pricey. What I opted for was to buy a $10 PCB off of AliExpress that had a BGA221 footprint on it and MMC card pads on the other side. My plan was to remove the flash chip from the PCB, put it on the adapter, and slide the PCB itself into an SD/MMC slot in one of my laptops.
Extraction
First I needed to physically remove the flash chip from the L33L’s PCB.
I used my rework hot air gun at 700F with a bit of flux to help conduct heat. After about 2 minutes the chip started to float and I was able to get it off the board:
Reballing
The chip was free, but I couldn’t just place it on the adapter. The amount of solder remaining on the pads was inconsistent with some of it being left behind on the L33L’s PCB. It needed to be reballed which meant putting fresh solder evenly across the pads.
First, I used a copper wick and my microsoldering iron to soak up the old solder until the pads were nice and clean:
There are a lot of ways to do reballing, the generally preferred way is to use a stencil to apply solder to the pads. Unfortunately, I did not have a BGA221 stencil. An adaptable, but tedious option is to directly place balls of solder on each of the 221 pads individually and then melt them to the pads.
Opting for the insane option, I smeared a thin layer of flux across the bottom of the chip, dumped 0.35mm 63/37 tin/lead solder balls on the pads, and pushed them into place with the sharp point of a precision test probe:
After a few hours with lots of breaks, I got all of the balls pushed into place. Next, I heated them with the rework gun while adding a bit of flux until they fused with the pads:
Soldering to the Adapter
With the hard part done, I put some flux on the adapter’s footprint, aligned the flash chip, and heated it with the rework gun again. After heating it for a bit, it snapped into place from the ball’s surface tension and I let it cool:
Dumping the Flash
I have several devices that are advertised as supporting MMC cards, but the only one I could get working was the one in my Lenovo X260:
I was absolutely thrilled when I ran lsblk
on the X260 and saw it recognized as a drive.
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
# SNIP
mmcblk0 179:0 0 7.3G 0 disk
├─mmcblk0p1 179:1 0 512K 0 part
├─mmcblk0p2 179:2 0 512K 0 part
├─mmcblk0p3 179:3 0 512K 0 part
├─mmcblk0p4 179:4 0 512K 0 part
├─mmcblk0p5 179:5 0 2M 0 part
├─mmcblk0p6 179:6 0 1.5M 0 part
├─mmcblk0p7 179:7 0 512K 0 part
├─mmcblk0p8 179:8 0 512K 0 part
├─mmcblk0p9 179:9 0 512K 0 part
├─mmcblk0p10 179:10 0 512K 0 part
├─mmcblk0p11 179:11 0 2M 0 part
├─mmcblk0p12 179:12 0 16M 0 part
├─mmcblk0p13 179:13 0 16M 0 part
├─mmcblk0p14 179:14 0 512K 0 part
├─mmcblk0p15 179:15 0 1.5M 0 part
├─mmcblk0p16 179:16 0 1.5M 0 part
├─mmcblk0p17 179:17 0 24M 0 part
├─mmcblk0p18 179:18 0 24M 0 part
├─mmcblk0p19 179:19 0 24M 0 part
├─mmcblk0p20 179:20 0 1.5M 0 part
├─mmcblk0p21 179:21 0 512K 0 part
├─mmcblk0p22 179:22 0 512K 0 part
├─mmcblk0p23 179:23 0 512K 0 part
├─mmcblk0p24 179:24 0 512K 0 part
├─mmcblk0p25 179:25 0 512K 0 part
├─mmcblk0p26 179:26 0 512K 0 part
├─mmcblk0p27 179:27 0 512K 0 part
├─mmcblk0p28 179:28 0 8M 0 part
├─mmcblk0p29 179:29 0 32M 0 part
├─mmcblk0p30 179:30 0 32M 0 part
├─mmcblk0p31 179:31 0 8M 0 part
├─mmcblk0p32 179:32 0 32M 0 part
├─mmcblk0p33 179:33 0 64M 0 part
├─mmcblk0p34 179:34 0 2M 0 part
├─mmcblk0p35 179:35 0 2.4G 0 part
├─mmcblk0p36 179:36 0 850M 0 part
├─mmcblk0p37 179:37 0 3.7G 0 part
└─mmcblk0p38 179:38 0 16M 0 part
mmcblk0boot0 179:256 0 4M 1 disk
mmcblk0boot1 179:512 0 4M 1 disk
Rather than messing around with the actual flash device, I wanted to make a proper forensics copy:
$ sudo dd if=/dev/mmcblk0 of=dump.img bs=4M status=progress
I dumped the entire memory twice into two different images and used sha256sum
to confirm they were the exact same.
Mounting Userdata Partition
I first tried to use Autopsy to analyze the image, but it turns out most of the Android plugins only work on Windows. Opting to use some standard Linux utilities, I ran losetup
to set up a new read-only loop device with the image:
$ sudo /usr/sbin/losetup -P --read-only /dev/loop6 dump.img
Now I had access to the partitions again:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
# Snip...
loop7 7:7 0 7.3G 1 loop
├─loop7p1 259:38 0 512K 1 part
├─loop7p2 259:39 0 512K 1 part
├─loop7p3 259:40 0 512K 1 part
├─loop7p4 259:41 0 512K 1 part
├─loop7p5 259:42 0 2M 1 part
├─loop7p6 259:43 0 1.5M 1 part
├─loop7p7 259:44 0 512K 1 part
├─loop7p8 259:45 0 512K 1 part
├─loop7p9 259:46 0 512K 1 part
├─loop7p10 259:47 0 512K 1 part
├─loop7p11 259:48 0 2M 1 part
├─loop7p12 259:49 0 16M 1 part
├─loop7p13 259:50 0 16M 1 part
├─loop7p14 259:51 0 512K 1 part
├─loop7p15 259:52 0 1.5M 1 part
├─loop7p16 259:53 0 1.5M 1 part
├─loop7p17 259:54 0 24M 1 part
├─loop7p18 259:55 0 24M 1 part
├─loop7p19 259:56 0 24M 1 part
├─loop7p20 259:57 0 1.5M 1 part
├─loop7p21 259:58 0 512K 1 part
├─loop7p22 259:59 0 512K 1 part
├─loop7p23 259:60 0 512K 1 part
├─loop7p24 259:61 0 512K 1 part
├─loop7p25 259:62 0 512K 1 part
├─loop7p26 259:63 0 512K 1 part
├─loop7p27 259:64 0 512K 1 part
├─loop7p28 259:65 0 8M 1 part
├─loop7p29 259:66 0 32M 1 part
├─loop7p30 259:67 0 32M 1 part
├─loop7p31 259:68 0 8M 1 part
├─loop7p32 259:69 0 32M 1 part
├─loop7p33 259:70 0 64M 1 part
├─loop7p34 259:71 0 2M 1 part
├─loop7p35 259:72 0 2.4G 1 part
├─loop7p36 259:73 0 850M 1 part
├─loop7p37 259:74 0 3.7G 1 part
└─loop7p38 259:75 0 16M 1 part
I decided to start looking at the largest partition, 37:
$ sudo mount /dev/loop7p37 ~/mnt
mount: /home/elelzedel/mnt: WARNING: source write-protected, mounted read-only.
So far so good, let’s see what’s in there:
$ tree --charset=ASCII
.
|-- adb
|-- app
| |-- com.dti.cricket-1
| | |-- base.apk
| | |-- lib
| | `-- oat
| | `-- arm
| | `-- base.odex
| |-- org.mozilla.firefox-1
| | |-- base.apk
| | |-- lib
| | | `-- arm
| | | |-- libfreebl3.so
| | | |-- liblgpllibs.so
| | | |-- libmozavcodec.so
| | | |-- libmozavutil.so
| | | |-- libmozglue.so
| | | |-- libnss3.so
| | | |-- libnssckbi.so
| | | |-- libplugin-container.so
| | | |-- libsoftokn3.so
| | | `-- libxul.so
| | `-- oat
| | `-- arm
| | `-- base.odex
| `-- # SNIP: All of my apps are in here
|-- app-asec
|-- app-lib
|-- app-private
|-- app-system
|-- audio
|-- backup
| `-- # SNIP: System backup stuff
|-- bootchart
|-- bugreports -> /data/data/com.android.shell/files/bugreports
|-- camera
|-- connectivity
| |-- bqe_hist.db
| `-- icd_hist.db
|-- dalvik-cache
| `-- # SNIP: Boooooring
|-- data
| `-- # SNIP: Lots of app data for built-in apps and apps I installed
|-- dpm
| `-- nsrm
|-- drm
| `-- IDM
| `-- HTTP
|-- factory
|-- font
| |-- config
| `-- download
|-- fota
|-- hostapd
|-- .layout_version
|-- lgdrm
| |-- DUMP
| |-- ID
| |-- SQLDB
| | |-- DRMDB.bin
| | `-- DRMDB.bin-journal
| `-- TRYSYNC
|-- local
| `-- tmp
| `-- # SNIP: This is not a tmpfs mount point, there were are files in here but nothing interesting
|-- logger
| |-- kernel.log
| |-- kernel.log.1
| |-- modem_debug_info
| `-- setup
|-- lost+found
|-- media
| |-- 0
| | |-- Alarms
| | |-- Android
| | | |-- data
| | | | |-- com.google.android.apps.maps
| | | | | |-- cache
| | | | | |-- files
| | | | | `-- testdata
| | | | |-- com.google.android.gms
| | | | | `-- cache
| | | | | |-- googletrustagent_export.log
| | | | | `-- googletrustagent_export.log.lck
| | | | |-- com.google.android.googlequicksearchbox
| | | | | `-- files
| | | | | `-- download_cache
| | | | |-- com.google.android.music
| | | | | |-- cache
| | | | | `-- files
| | | | | `-- ._playmusicid
| | | | |-- com.google.android.videos
| | | | | `-- files
| | | | | `-- Movies
| | | | |-- com.google.android.youtube
| | | | | |-- cache
| | | | | | `-- exo
| | | | | `-- files
| | | | |-- deezer.android.app
| | | | | |-- cache
| | | | | `-- files
| | | | |-- .nomedia
| | | | `-- org.mozilla.firefox
| | | | `-- files
| | | | `-- Download
| | | `-- media
| | | `-- com.google.android.talk
| | | |-- Notifications
| | | | `-- hangouts_message.ogg
| | | `-- Ringtones
| | | `-- hangouts_incoming_call.ogg
| | |-- DCIM
| | |-- Download
| | | `-- # SNIP: These are my actual downloads in here, mostly sideloaded APKs
| | |-- Movies
| | |-- Music
| | |-- Notifications
| | |-- Pictures
| | |-- Podcasts
| | `-- Ringtones
| `-- obb
|-- mediadrm
| `-- IDM1013
| `-- ay64.dat
|-- misc
| `-- # SNIP: Nothing too interesting in here
|-- security
|-- shared
|-- ss
|-- system
| |-- #SNIP: Lots of system setting stored in .xml files
| `-- users
| |-- 0
| | |-- accounts.db
| | |-- accounts.db-journal
| | |-- appwidgets.xml
| | |-- disclosure-permissions.dat
| | |-- package-restrictions.xml
| | |-- registered_services
| | | |-- android.accounts.AccountAuthenticator.xml
| | | `-- android.content.SyncAdapter.xml
| | |-- runtime-permissions.xml
| | |-- settings_global.xml
| | |-- settings_secure.xml
| | |-- settings_system.xml
| | |-- wallpaper
| | |-- wallpaper_info.xml
| | `-- wallpaper_pref.xml
| |-- 0.xml
| `-- userlist.xml
|-- time
| |-- ats_1
| |-- ats_12
| |-- ats_13
| `-- ats_2
|-- tombstones
| |-- dsps
| |-- lpass
| |-- modem
| `-- wcnss
`-- user
`-- 0 -> /data/data/
858 directories, 1801 files
A total of 1801 files! Most of them are snipped out, but you get the picture: tons of information about me is all available in an unencrypted partition: my contacts, downloads, settings, WiFi passwords, usage data, and so much more.
Conclusion
I had a swipe lock configured for this phone and I remember calculating how long it would take to brute-force combinations depending upon how many dots I used in the pattern. I should not have wasted my time because all that was needed was a basic microscope and inexpensive rework gun to dump all the personal data off of the phone without a single thought given to that lock screen.
In all likelihood, a common phone thief would not have the equipment to do all this, but there’s definitely enough sensitive data on this phone to be worth their time if they were so inclined.