%
% Section for Implementation
%
\section{Implementation}
\subsection{Development Environment}
We started with the Linux Android SDK that is comprised of APIs and developer tools necessary to begin developing applications on the Android platform. The SDK comes with an emulator which is a customized version of QEMU that runs a virtual ARM system-on-a-chip (SoC) that Google calls Goldfish. The Goldfish platform boots an ARM Linux kernel with Goldfish support compiled for the ARMv5TEJ instruction set.
We used the Linux android-goldfish 2.6.29 source code and the Android Emulator source code available for download from the Android source downloads page \cite{AndroidSDK}, along with the configuration extracted from a running Android Virtual Device (AVD) to successfully build an Android Linux kernel and run it on the emulator. This provided the base environment for our project development.
\subsection{VMM Implementation Details}
We initially attempted to build and run a VMM targeting the Android platform that was implemented as part of a previous research project at the University of Illinois \cite{kallaembedded}. After downloading the source and working with project owners, we were unable to run a fully functional VMM on our configuration. In addition, we investigated porting the OKL4 Microvisor from Open Kernel Labs \cite{OKL4} to the Android platform, but found the porting process to be too complicated for our scope of work. At this point, we decided to implement our VMM interface by adding a simple hardware device to the Goldfish emulator. Figure ~\ref{fig:vmm_implementation} demonstrates the interactions between our emulated VMM and the host operating system.
%%%%%%%%
% vmm implementation
%%%%%%%%
\begin{figure}
\includegraphics[width=3.2in]{vmm_implementation.JPG}
\caption{VMM Design}
\label{fig:vmm_implementation}
\end{figure}
\begin{enumerate}
\item The emulated VMM is driven by a virtualized timer that is capable of being programmed to expire at predefined intervals. When a timer interval expires, the underlying emulator generates an interrupt which is then handled by the VMM.
\item The VMM then performs an integrity check on the guest’s trusted kernel module directly in memory. To access the guest’s kernel module in virtual memory, the device reads the translation lookaside buffer (TLB) emulated in QEMU to determine the physical address of the kernel module. The integrity check is a simple memory comparison of the device’s copy of the protected kernel module code and data sections against the guest OS’s copy of these sections in memory. If the device detects that the guest’s kernel module code or data sections have been modified, the compromised kernel module is restored in memory to an unmodified state.
\item After the integrity of the guest’s kernel module has been verified, an interrupt line is raised which is then handled by an interrupt service routine (ISR) within the guest kernel.
\item The ISR then invokes the guest’s trusted kernel module which proceeds to validate the integrity of the protected OS components. We consider the ISR as a potential attack point but leave verification of its integrity within the emulated VMM to future work.
\end{enumerate}
\subsection{Kernel Module Implementation Details}
We initially planned to have the trusted kernel module exist as an LKM that could be dynamically loaded or unloaded by the user. However, since our approach is attempting to prevent attacks by kernel-mode rootkits and user-mode malware with root access, it makes more sense to have a static trusted kernel module that is loaded as a permanent component of the kernel itself. This decision simplified the interface between the VMM and the kernel module greatly. The interface only needs to include the hardware interrupt that invokes the kernel module’s OS integrity check as an ISR, whereas the LKM approach would require a secure mechanism to report the trusted LKM’s load address. Dynamic loading would also call timing of the kernel module load into question from a security standpoint, as it would be difficult to ascertain whether the OS had already been compromised prior to the protection functionality being initialized and activated. The risks in ensuring such a mechanism could operate securely under all scenarios made the static kernel module a superior choice for our purposes.
Since the trusted kernel module is a static component of the kernel, the location, size, and contents of the syscall table are statically defined as part of the module itself. When the timer interrupt set by the VMM occurs, the kernel module’s OS integrity check is invoked. First, the kernel syscall table is compared against the static copy that exists within the protected data section of the kernel module. If any system service function pointers have been altered, the integrity check then proceeds to restore the syscall table to its original state.
To defend against unauthorized access of the sensitive Android resources, we first had to determine what those resources were, specifically. The GPS coordinates, the call logs, the contacts list, the text messages, and network sockets were determined to be the resources most worth protecting. With already being aware that most of the aforementioned data were stored in unencrypted SQLite database files, simply exploring the directories found on the Android to determine the exact filenames of the database files was a feasible effort. We determined that the call logs and contacts are both stored in the same file, namely ‘/data/data/com.android.providers.contacts/databases/contacts2.db’. Additionally, the text and multimedia messages are stored together in the file named ‘/data/data/com.android.providers.telephony/databases/mmssms.db’. The GPS device name was not determined, but an alternative method of protection was devised as an alternativein lieu of having this information.
We developed and utilized an LKM that logged which user-mode Linux processes accessed the sensitive resources on an otherwise unmodified Android system during normal operation. With the system profiling LKM loaded, we made sure to use the Android phone in a typical and thorough manner. This included using the Android telnet shell to simulate inbound calls and text messages in addition to placing outbound calls and text messages directly from the Android user interface within the emulator window. We also started up and used every Android app that was part of the default install for Android, including the web browser with several tabs open and the Google Maps and Navigation applications. We updated the simulated GPS location repeatedly using the telnet shell’s ‘geo fix’ command to get these applications to react to dynamic updates.
To ensure applications installed by the user were not affected by our trusted kernel module, a third-party app that utilized Android location services to obtain the GPS coordinates was also executed while profiling. We used this information, in conjunction with the Android architecture documentation, to determine that applications invoke content providers that utilize native user-mode processes to access the sensitive resources we aim to protect. Thus, any application installed by the user that accesses sensitive resources will do so through the providers which have been included in our white-list. We wanted Android to continue to function normally with regard to app behavior,; we were seeking solely to prevent sensitive resource accesses that bypassed the Android Application Framework.
This resource access information was used to build the static ACL that forms the resource protection mechanism in the kernel module. The ACL contains the white-list of user-mode Linux applications on Android that are allowed to access the aforementioned sensitive resources. We assumed that if the process is allowed access to any protected resource, then it is not malicious and was thereby granted access to all such resources. The table itself contains the process name of the white-listed processes that were identified as needing access during the profiling research. The secondary identifier chosen is the parent process name. This was done so that a clever choice of a name for a hostile user-mode process is not the only barrier to accessing sensitive resources. Clearly, this is only a marginal improvement as it just requires two clever process names and a fork() call. The idea behind using the parent process name was that there would be fewer parent processes in the system. For future work, we would then only need to validate that the parent process image in memory matches that on disk, which would be a significant reduction in the number of processes that need to be verified in this way. Alternatively, the simpler approach of verifying that no more than the expected number of instances of each parent process name exists in the system would also be a potential validation technique.
The sys\_open system service is hooked by our kernel module in order for the white-list ACL to be checked on each call to sys\_open() in the system. Before allowing access, the extra sys\_open() logic determines whether the resource is a protected one and whether the calling process is in the white-list ACL. The remainder of the sys\_open() call will proceed normally if the resource is not protected, or if it is protected and the requesting process is on the white-list. Since Android apps map to user-mode Linux processes with unchanging process and parent process names, our implementation was able to give blanket white-listing to all Android apps. The socket system service is similarly hooked, but instead of using database file names, calls have the ACL applied when they are being made for opening an Internet socket. The thought behind this restriction was that these types of sockets could be used to transmit the sensitive data, and thus should be blocked. The sys\_read system service was hooked after the GPS device name was not able to be determined during system profiling. The GPS coordinates were witnessed being updated as a result of the ‘geo fix’ command and the GPS Location Provider in the Android Framework would immediately perform a read() operation. The sys\_read() data contained the string “$GPG” followed by the GPS coordinate data. Interestingly, mapping the file descriptor back to a previous sys\_open() call was not possible. Another system service is apparently being used to open the file descriptor for the GPS device. It is also worth noting that the kernel module hooking of sys\_open(), socket(), and sys\_read() is accounted for by the syscall table integrity check so that the hooks are also protected and are not mistakenly considered to be maliciously set.
Share with your friends: |