Memory Forensics of Insecure Android Inter-app Communications
Mark Vella and Rachel Cilia
Department of Computer Science, University of Malta, Msida, Malta
{mark.vella, rachel.cilia.13}@um.edu.mt
Keywords:
Mobile Systems Security, Android Memory Forensics, Capability Leaks.
Abstract:
Android is designed in a way to promote the implementation of user task flows among multiple applications
inside mobile devices. Consequently, app permissions may be leaked to malicious apps without users noticing
any compromise to their devices’ security. In this work we explore the possibility of detecting insecure inter-
app communications inside memory dumps, with forensic analysis results indicating the possibility of doing
so across the various layers of Android’s architecture. Yet, for the detailed evidence reconstruction that could
be required during digital investigation, current capabilities have to be complemented with evidence collected
through live forensics. We propose that this process should still be based on carving forensic artifacts directly
from memory.
1 INTRODUCTION
Android, the most popular mobile device operating
system, is designed in a way to both isolate poten-
tially security-critical apps from each other as well
as to have apps seamlessly delegate their functional-
ity to third-parties (Elenkov, 2014). Clearly these two
design objectives are at odds, leading to various in-
secure inter-app communication links such as when
vulnerable apps leak their legitimately granted privi-
leges to malicious ones, known as capability leaks. In
this work we begin to explore how to expose inter-app
links directly from physical memory; which is a tech-
nique that does not have to rely on possibly tampered
code, and which successfully executing malware can-
not evade. The value proposition is that of increased
systems security of Android-powered mobile devices.
Android’s Binder is the inter-process communica-
tion mechanism through which all inter-app links are
established (section 2). Code comprehension is uti-
lized to predict the relevant forensic artifacts across
Android’s architectural layers (section 3). Our pri-
mary contribution lies in proposing a memory dump
parsing algorithm for each layer (section 4) and sub-
sequently used to verify artifact suitability through
forensic analysis (section 5). Results show that by
combining artifacts identified within different sec-
tions of memory, all types of inter-app links can be
disclosed from memory dumps despite varying de-
grees of reliability. However for the level of detail
that may be required during digital investigation, a
live forensics approach would be necessary. There-
fore we conclude this work (section 6) with a propo-
sition that relies on collecting evidence directly from
live memory on-demand, using runtime patching.
2 ANDROID INTER-APP
COMMUNICATION
Android apps are composed of classes that extend
framework components, namely: activities (app win-
dows), services (long running, mostly background,
code), broadcast receivers (handlers of device-wide
events) and content providers (shared data reposito-
ries); eventually fleshed out with application logic
that makes use of Android system services, e.g. mes-
saging, telephony, Internet-access, location services
and so on (Gargenta, 2012). The first three of these
components are activated through intents whilst the
latter through content resolvers.
Intents are application framework constructs rep-
resenting the ‘intent’ion of an application component
to provide some functionality. Intent-servicing com-
ponents can even be exported for use by external ap-
plications, thereby constituting a primary IPC con-
struct. Explicit intents identify specifically the target
apps hosting the activities/services to be activated in
correspondence to the specified intent action (listing
1). On the other hand, implicit intents only identify
the action and possibly some other attributes (listing
2). In this case Android takes care of routing them to
Vella, M. and Cilia, R.
Memory Forensics of Insecure Android Inter-app Communications.
DOI: 10.5220/0006215504810486
In Proceedings of the 3rd International Conference on Information Systems Security and Privacy (ICISSP 2017), pages 481-486
ISBN: 978-989-758-209-7
Copyright
c
2017 by SCITEPRESS Science and Technology Publications, Lda. All rights reserved
481
those apps that would have declared interest in servic-
ing them during install time, also possibly asking the
user to choose between multiple such candidate apps.
On the other hand, content resolvers provide access to
external content providers.
Listing 1: Explicit intents are used to launch activities or
services inside external applications.
/ / S t a r t i n g an e x t e r n a l a c t i v i t y :
Pa cka ge Ma na ge r pm = t h i s . ge t Pa c ka ge M an ag e r ( ) ;
t r y
{
I n t e n t i t = pm . g e t L a u n c h I n t e n t F o r P a c k a g e (
com . e xa mpl e . m ve l l a . e i s e r v e r ” ) ;
i f ( n u l l ! = i t ) t h i s . s t a r t A c t i v i t y ( i t ) ; . .
SNIP . . .
/ / S t a r t i n g an e x t e r n a l s e r v i c e :
I n t e n t i n t e n t = new I n t e n t ( ”com . e xa mpl e . m ve l l a .
e i s e r v e r . ACTION START ) ;
i n t e n t . s et Co mp on en t ( new ComponentName ( com .
ex amp le . m ve l l a . e i s e r v e r ” , com . ex am pl e .
m ve l l a . e i s e r v e r . D i f f A p p S t a r t S e r v i c e ” ) ) ;
s t a r t S e r v i c e ( i n t e n t ) ;
Listing 2: Implicit intents only specify actions along with
various possible qualifiers.
s t a r t A c t i v i t y ( new I n t e n t ( I n t e n t . ACTION VIEW , U r i .
p a r s e ( ” h t t p : / / www. g o o gl e . com” ) ) ) ;
2.1 Capability Leaks
Intents and content resolvers are core Android appli-
cation development constructs encouraging inter-app
functionality and data sharing, providing the required
support for user task flow implementation across mul-
tiple apps. A number of system intents are in fact
made available by the Android framework itself and
are expected to be serviced by pre-installed/default
apps e.g. picture viewers, instant messaging, and tele-
phony. The transition from one app to another can
be so seamless that it may not be even noticed by
the device user. Since Android makes sure to iso-
late Android apps from each other as well as from
sensitive device services (e.g. telephony and net-
working), a permissions system is used to relax the
level of isolation in a controlled manner (Elenkov,
2014). System permission requests are declared in-
side manifest files (app package meta-data) through
the uses-permission tag.
Listing 3 (lines 3-4), for example, requests
read/write access to the device’s contacts. Yet, it
is the responsibility of the app developer to check
that external apps activating the updateContacts
service (line 6) through the ACTION START in-
tent (line 8) and that makes use of these per-
missions, also have the sufficient privilege level
to access the device’s contacts (e.g. by calling
Context.checkCallingPermission()). Otherwise
a capability leak is said to occur whenever an unpriv-
ileged app obtains contacts through it (Zhang et al.,
2016). In this work we focus specifically on Intent-
derived leaks, given that content resolvers should nor-
mally be used to directly access system/external data
repositories only, rather than potentially permission-
leaking code.
Listing 3: Vulnerable app’s AndroidMainfest.xml.
1
2 <p ac k ag e name =com . e xa mp le . m ve l l a . v u ln a pp ”
c od e P at h = ” . . . SNIP . . .
3 <u se s p e r m i s s i o n a n d r o i d : name = a n d r o i d .
p e r m i s s i o n . READ
CONTACTS/>
4 <u se s p e r m i s s i o n a n d r o i d : name = a n d r o i d .
p e r m i s s i o n . WRITE CONTACTS”/>
5 . . . SNIP . . .
6 <s e r v i c e a n d r o i d : name =com . e xam ple .
m ve l l a . v ul n a pp . u p d a t e C o n t a c t s >
7 <i n t e n t f i l t e r >
8 <a c t i o n a n d r o i d : name = .
ACTION START”/>
9 </ i n t e n t f i l t e r >
10
11 </ s e r v i c e >
12 . . . SNIP . . .
2.2 Related Work
While preventable both from secure coding and per-
mission enforcement hardening stances (Zhang et al.,
2016), capability leaks are still bound to happen in
existing devices due to the difficulty concerned with
complete eradication of vulnerabilities. We focus
on the provision of graceful recovery using memory
forensics. Robust memory acquisition from Android
devices has been explored extensively (Sylve et al.,
2012). This body of knowledge underpins the LiME
acquisition tool utilized in this work. Memory ac-
quisition differs from disk image acquisition since
the address bus space in typical microprocessor ar-
chitectures is not exclusive to physical RAM, but is
rather shared with all memory-mapped hardware de-
vices. Erroneously reading from non-RAM addresses
compromises system integrity. This same issue could
however be leveraged by malware to evade memory
acquisition (St
¨
uttgen and Cohen, 2013). Mobile de-
vice forensics is challenging even at secondary stor-
age level due to the variety of available custom hard-
ware (Kong, 2015). However, the wide-spread adop-
tion of Android creates an opportunity for a common
source of in-memory forensic evidence. In this work
we focus specifically on Android Binder and which
ICISSP 2017 - 3rd International Conference on Information Systems Security and Privacy
482
security-criticality has already been targeted by offen-
sive security studies (Artenstein and Revivo, 2014).
3 ANDROID BINDER
All IPC constructs available to Android app devel-
opers (Gargenta, 2012) are implemented as Remote
Procedure Calls (RPC), with support from Android
Binder and shared memory (ashmem). At the high-
est level of abstraction developers are oblivious of
this detail, however this mechanism presents the focus
for forensics artifact exploration. Figure 1 illustrates
the main components involved in supporting inter-
app links across the framework (Java), middleware
(C/C++) and the (modified) Linux kernel (C) layers
of the Android architecture. A client app (App 1) ac-
cesses various system service (e.g. Telephony ser-
vice) using framework API calls. System service
code actually resides in separate OS processes, most
of which is lumped into system server. Therefore
in actual fact all such calls already constitute IPC.
Moreover, system services may just constitute a step-
ping stone so that App 1 can activate components in-
side another, App 2, and eventually communicating
directly using a Message Queue or an RPC type of
inter-app communication.
We resort to code comprehension in order to for-
mulate predictions about locating and parsing arti-
facts related to inter-app links. This is similar to aca-
demic work performing forensic analysis for on-disk
or in-network traffic artifacts (Anglano et al., 2016).
We made use of Android Open Source Project’s
(AOSP) master branch
1
for this purpose. The com-
prehension exercise mainly consisted of (statically)
tracing execution flow involving components commu-
nicating across app boundaries, and identifying those
data structures useful for forensic event reconstruc-
tion. In this section we summarize the primary bi-
naries involved and a representative cross-application
boundary flow, with specific detail concerning locat-
ing and parsing artifacts presented in the following
one. The primary source code files utilized during
comprehension are shown in parenthesis.
Let’s take the example when Activ-
ity1 inside App 1 sends a message to a
service component exposed by App 2 us-
ing the API Messenger.send(Message
aMsg) method. What happens here is that
aMsg is passed onto the middleware layer
through (android.os.Binder)’s transact()
method by android.os.Messenger stub code
1
https://source.android.com/source/index.html
(core/java/android/os/IMessenger.aidl).
Specifically, using the Android Runtime (ART)’s
(libart.so) Java-Native Interface (JNI) media-
tion, the proxy creates a serialized represen-
tation of aMsg inside the middleware layer
(libs/binder/Parcel.cpp), across a Java-
native link registered by libandroid runtime.so
(core/jni/android util Binder.cpp). Sub-
sequently it is passed onto the Binder frame-
work: libbinder.so (libs/binder/BpBinder.cpp),
that first packages it into a Binder transaction
that conforms to the Binder driver’s proto-
col
2
and then dispatches it to the Binder driver
(drivers/staging/android/binder.c) inside the
kernel using an ioctl() call on the /dev/binder
device file (libs/binder/IPCThreadState.cpp).
The role of the driver is to look up the location of the
requested remote service, the service inside App 2
in this example, and delivers aMsg to it where an
associated thread pool would be blocked awaiting
Binder transactions (in turn from a previous ioctl()
call from libs/binder/IPCThreadState.cpp).
Transaction delivery is completed using a ker-
nel memory region that is mapped to App 2s user-
space (libs/binder/ProcessState.cpp). In case
of large messages, a faster alternative would be to
only serialize a file descriptor associated with a shared
memory region between App 1 and App 2 (acces-
sible through the /dev/ashmem device file through
libcutils.so). On message delivery completion it is
the Binder framework’s onTransact() method that
gets called first (libs/binder/JavaBBinder.cpp),
eventually calling into android.os.Messengers
proxy onTransact() method. The last phase of the
delivery involves in unserializing aMsg and passing
it to the messenger’s handling routine as argument.
In this example Binder’s RPC mechanism is used
to let App 1 and App 2 communicate using a mes-
sage queue abstraction, however it also possible to
use RPC directly, with service proxy/stub code gen-
erated from Android Interface Definition Language
(AIDL) files providing the necessary glue code. This
is the case for example when App 1 calls into sys-
tem server to start a service inside App 2 through a
bindService() API call for example.
The above flow relies on two very important reg-
istries. The first one is the Activity Manager service
that operates at the framework layer and resolves in-
tents based on a number of activity/service/broadcast
records that are registered with it, in turn based on
information derived from the various manifest files
of installed apps. The second registry is part of
2
http://www.angryredplanet.com/˜hackbod/openbinder/
docs/html/BinderIPCMechanism.html
Memory Forensics of Insecure Android Inter-app Communications
483
Kernel
ioctl()
ashmem
servicemanager
handles service
registration/lookup
App 1
libart.so
Activity1
libbinder.so, libcutils.so
mediate JNI
binder transaction
-lookup service,
- make RPC
-send ashmem fd
Register as
Context Manager
Shared mem.
create
system_server
Android
Framework
Layer
Android
Middleware
Layer
Linux (modified)
Kernel
Layer
Start App/Service
Access System Service
Telephony/Sms svc.,
Activity Manager svc.,
Location/Audio svc.,...
App 2
Send message/
remote call
libbinder.so
binder transaction
-register service
Activities
BroadcastReceivers
Content Providers
Services
/dev/binder kernel
memory mapping
/dev/ashmem user
memory mapping
shared memory map
(app1 + app2)
Binder transaction delivery
with kernel-to-user
memory mapping
Service/Mes senger stubs
Android. os.Binder
Service/Messenger proxies
android.os.Binder
JNI
Binder driver
libandroid_runtime.so
Figure 1: Android inter-app communication is implemented by Android’s Binder with support from Android shared memory.
the Binder framework. The Binder driver needs to
perform sufficient book-keeping so that remote ob-
jects can be registered with it, and then have client
apps look them up to obtain a handle for them and
through which perform remote calls. Given that both
these operations are sensitive a central process, ser-
vicemanager, mediates between all processes and the
Binder driver. This process is called the Context Man-
ager, and only one process can be registered as such.
Communication between processes and serviceman-
ager still occurs through Binder RPCs, and to which
a specially reserved handle (0) is utilized. Whenever
enabled, Binder driver’s book-keeping structures are
dumped to debugfs (/sys/kernel/debug/binder
file-system path).
4 MEMORY DUMP PARSERS
All three parsers take a dump of physical memory
as input along with an androidBinderProfile ob-
ject. This is an abstract data object that contains: the
virtual addresses of global variables; data structure
offsets; and an initial Directory Table Base (DTB)
(CR3 register value). This last value is the all-
important offset inside the physical memory dump
for the page table directory which is used for virtual-
to-physical address translation of kernel memory.
Specifically, androidBinderProfile is used by the
getKernelAddressSpace() function which recre-
ates the kernel’s virtual address space.
At the kernel layer (Algorithm 1)
the Binder book-keeping structures
(drivers/staging/android/binder.c) have
been identified as a linked list of binder proc and
associated structures, and which can be located
through the binder procs global variable. These
structures keep track of the processes hosting re-
motely accessible objects, binder objects, and the
threads servicing the inter-process request/replies
among others. Additionally, the well-known Linux
linked list of task struct (Mauerer, 2010) and
associated structures is required to recover the virtual
memory sections of individual Linux processes
hosting app components. This linked list can be
located using the init task global variable.
One layer upwards, the middleware, it is ex-
pected that Parcels containing binder transaction
(Android RPC calls) data intended for the Activ-
ity Manager service can be identified through the
android.app.IActivityManager length-encoded
wide character string. Specifically, serialized intents
within such parcels include the package and com-
ponent names of the targets in addition to target-
intended data arguments. They are created on the
client-side’s process heap and eventually get copied
to a location inside kernel memory that in turn would
already have been mapped inside the target process as
/dev/binder during the binder object’s creation.
Target app component identifiers and arguments
in turn would be stored inside ART’s own heap at the
framework layer during intent creation (for e.g. listing
1).
Algorithm 2 shows the framework-layer parser. It
takes the additional /data/system/packages.xml
ICISSP 2017 - 3rd International Conference on Information Systems Security and Privacy
484
Algorithm 1: Kernel-layer parser.
input : androidMemDump, androidBinderProfile
output: Per-app binder object references
task struct aTaskStruct;
hashmap procNameMap;
binder proc aBinderProc;
binder node aBinderNode;
binder ref aNodeRef;
kernel addsprace LinuxAS
getKernelAddressSpace(androidMemDump,
androidBinderProfile);
foreach aTaskStruct traverseLinkedList(LinuxAS,
androidBinderProfile, global addr=“init task”,
datatype=“task struct”) do
procNameMap
[aTaskStruct.pid]aTaskStruct.comm;
end
foreach aBinderProc
traverseBinaryTree(LinuxAS, androidBinderProfile,
global addr=“binder procs”,
datatype=“binder proc”) do
output(“process pid & name:”, aBinderProc.pid,
procNameMap [aBinderProc.pid]);
foreach aBinderNode
traverseBinaryTree(LinuxAS,
androidBinderProfile, addr=aBinderProc.nodes,
datatype=“binder node”) do
output(“node id:”, aBinderNode.debug id);
output(“referenced by:”);
foreach aNodeRef
traverseLinkedList(LinuxAS,
androidBinderProfile,
addr=“aBinderNode.refs”,
datatype=“binder ref”) do
output(aNodeRef.proc.pid, procNameMap
[aNodeRef.proc.pid]);
end
end
end
to assist searching for all wide character strings that
include an app package name. Effectively this is a
signature that takes advantage of the fact that package
names are used as name-spaces for intent arguments.
The framework’s android package and the package
for the current app being analyzed are excluded given
that no inter-app links are concerned. Directory table
addresses for individual processes are obtained from
task struct.mm->pgd. This is the offset inside the
physical dump used by getAndroidRuntimeHeap()
to reconstruct ART’s heap. The memory sec-
tions for each process are locatable through
the task struct.mm->mmap linked list of
vm area struct structures inside the kernel space.
vm area struct.vm file->f path.dentry->
d iname is the final memory lookup required to filter
just the memory sections corresponding to ART’s
heap, i.e. the ones corresponding to device file maps
prefixed with /dev/ashmem/dalvik. The algorithm
for the middleware layer is similar, with the main
difference being that this time it is the process heap
(delimited by task struct.mm->start brk
and task struct.mm->brk start/end ad-
dresses) and the /dev/binder memory sec-
tions that are scanned for content tagged with
android.app.IActivityManager wide character
strings.
Algorithm 2: Framework-layer parser.
input : androidMemDump, androidBinderProfile,
packages.xml
output: Per-app intent/content provider-related strings
task struct aTaskStruct;
buffer heapBuffer;
Array packageArray
getPackageList(packages.xml);
String packageName;
String match;
kernel addsprace LinuxAS
getKernelAddressSpace(androidMemDump,
androidBinderProfile);
foreach aTaskStruct traverseLinkedList(LinuxAS,
androidBinderProfile, global addr=“init task”,
datatype=“task struct”) do
output(“App: ”, aTaskStruct.comm, “pid: ”,
aTaskStruct.pid);
heapBuffer getAndroidRuntimeHeap(LinuxAS,
aTaskStruct.mmmmap, aTaskStruct.mmpgd,
mappingid=“/dev/ashmem/dalvik*”);
foreach packageName (packageArray
\{android, aTaskStruct.comm}) do
foreach match
scanWideCharStr(heapBuffer,packageName)
do
output(“Match: ”, match);
end
end
end
5 PRELIMINARY RESULTS
Experimentation was carried out on a system im-
age created using Android 6.0.0 (Marshmallow - API
level 23) and a kernel v3.4 image modified to support
kernel modules. Prototype implementations of the
memory parsers were developed for the Volatility
2.5 memory forensics framework and utilize the
LiME memory extractor kernel module.
Table 1 shows the forensic analysis results ob-
tained for the six IPC configurations, with debugfs
providing a live forensics baseline. As expected,
Memory Forensics of Insecure Android Inter-app Communications
485
Table 1: Memory forensic analysis results.
IPC debugfs Kernel Middleware Framework
Explicit intent - Start activity × × × X
Explicit intent - Start service × × × X
Explicit intent - Bind service (messaging) X X × X
Explicit intent - Bind service (RPC) X X × X
Implicit intent - Start activity × × × X
Implicit intent - Send broadcast × × × X
its effectiveness in uncovering IPC matches the ker-
nel layer dump parser and which corresponds to ap-
plications communicating directly with each other.
On the other hand, apps communicating indirectly
through Activity Manager are fully detectable only at
the framework layer. The middleware layer, Android
Binder’s user-level code, misses out on all of them
through a design that favors immediate transaction
recycling. The memory parsing prototype was then
extended into a full capability leak detector, with on-
device app package dumping and reversal (using apk-
tool). This procedure enables disclosure of the apps’
requested permissions and consequently the identifi-
cation of inter-app links that cross privilege bound-
aries. Its detection capability was demonstrated using
a case study app that leaks its contacts permissions
(manifest shown in listing 3 ) by not performing any
privilege checks on the caller apps.
Listing 4: Memory artifacts disclosing the suspicious inter-
app link.
App : com . ex amp le . m v el l a . m al ap p
p i d : 822
==> com . ex amp le . m ve l l a . v ul n ap p . a c t i o n . INSERT
==> com . ex amp le . m ve l l a . v ul n ap p #
==> com . ex amp le . m ve l l a . v ul n ap p . u p d a t e C o n t a c t s
==> com . ex amp le . m ve l l a . v ul n ap p . e x t r a .NAMEp#
==> com . ex amp le . m ve l l a . v ul n ap p . e x t r a . TEL
. . . SNIP
6 CONCLUSION
While valuable, the current detector cannot identify
specific targets of implicit intents whenever multiple
target apps are possible. It also lacks details of the ex-
act IPC sequences to support in-depth investigations
since it is restricted to operate just upon instantaneous
memory snapshots. This can be achieved through run-
time patching of ARM/Intel atom machine instruc-
tions by adding an Android middleware layer pro-
cess that leverages ptrace to load runtime memory
forensics patches supplied over network connections
or removable flash memory. This security-critical
process should be protected through an appropriate
SELinux policy, with only vendor/approved foren-
sic investigator-signed code patches being accepted
while at the same time verifying Binder’s integrity.
This idea can extend to include adaptive permission
enforcement, whereas the user could be prompted to
consciously either patch the vulnerable app, or even
elevate the privilege level of the caller app in case of
false positives.
REFERENCES
Anglano, C., Canonico, M., and Guazzone, M. (2016).
Forensic analysis of the chatsecure instant messaging
application on android smartphones. Digital Investi-
gation, 19:44–59.
Artenstein, N. and Revivo, I. (2014). Man in the Binder:
He who controls IPC, controls the droid. In Europe
BlackHat Conf.
Elenkov, N. (2014). Android Security Internals: An In-
Depth Guide to Android’s Security Architecture. No
Starch Press.
Gargenta, A. (2012). Deep dive into Android IPC/Binder
framework. In AnDevCon: The Android Developer
Conference.
Kong, J. (2015). Data extraction on MTK-based Android
mobile phone forensics. Journal of Digital Forensics,
Security and Law, 10(4):31–42.
Mauerer, W. (2010). Professional Linux kernel architecture.
John Wiley & Sons.
St
¨
uttgen, J. and Cohen, M. (2013). Anti-forensic resilient
memory acquisition. Digital investigation, 10:S105–
S115.
Sylve, J., Case, A., Marziale, L., and Richard, G. G. (2012).
Acquisition and analysis of volatile memory from An-
droid devices. Digital Investigation, 8(3):175–184.
Zhang, D., Wang, R., Lin, Z., Guo, D., and Cao, X. (2016).
Iacdroid: Preventing inter-app communication capa-
bility leaks in android. In ISCC, 2016 IEEE Sympo-
sium on, pages 443–449. IEEE.
ICISSP 2017 - 3rd International Conference on Information Systems Security and Privacy
486