Given the recent controversy with DJI drones, a defense and public safety technology vendor sought to investigate the privacy implications of DJI drones within the Android DJI GO 4 application. To conduct their analysis, the vendor partnered with Synacktiv who performed an in-depth dynamic and static analysis of the application. Their analysis discovered four main causes of concern within the DJI GO 4 application, most notably:
- The application contains a self-update feature that bypasses the Google Play store.
- The application contains the ability to download and install arbitrary applications (with user approval) via the Weibo SDK. During this process, the Weibo SDK also collects the user's private information and transmits it to Weibo.
- Prior to version 4.3.36, the application contained the Mob SDK, which collects the user’s private information and transmits it to MobTech, a Chinese analytics company.
- The application restarts itself when closed via the Android swipe closed gesture. Thus, users may be tricked into thinking the application is closed, but it could be running in the background while sending Telemetry requests.
To provide an independent review of the findings, the vendor asked GRIMM to validate Synacktiv’s findings. This blog describes GRIMM’s setup and workflow for validating the Synacktiv’s research. Using the techniques described in the following sections to perform static and dynamic analysis on the DJI GO 4 Android application, GRIMM was able to verify and confirm the findings from Synacktiv’s report.
The code associated with this blog post can be found in this GitHub repository.
Testing Setup
GRIMM’s researchers used two different set-ups: an arm-based Android 6.0 Marshmallow (API 23) emulator, and another with two physical devices, a rooted Nexus 6 and an unrooted Motorola Moto 3G.
The Android emulator is a part of Android Virtual Devices (AVD) Manager, a subsystem of Android Studio and can be controlled through adb (Android Debug Bridge). Additionally, Android Studio is able to redirect all traffic to an HTTP Proxy. We redirected traffic through Burp suite, under which requests can be captured and intercepted. Frida, a dynamic instrumentation tool, was also used on the emulator by directly pushing and running Frida-server on the device. We chose API 23 due to the added CA certificate protections introduced in Android API 24 and above (see this Android Developers blog entry for more information).
The Nexus 6P running Android N (API 23) was connected to a desktop through USB, and controlled through ADB. Both devices were connected to the same wireless network. The setup for analysis on this phone was similar to the emulator, except for the proxy and certificate. The proxy was done with iptables, to redirect all traffic on ports 443 and 80 to Burp. Originally, we attempted to connect via a USB ethernet adapter, but we found that the behavior of the app was different from the more normal WiFi setup. We used Frida to bypass SSL pinning on the Nexus 6P. Additional testing was conducted with a similar setup using a Motorola Moto 3G running Android L and the OWASP ZAP proxy.
Obfuscations
The DJI GO 4 Android application was heavily obfuscated, utilizing both static and dynamic obfuscation techniques to thwart analysis. Synacktiv provided GRIMM with a detailed write-up and scripts to deobfuscate the code and help analyze the application.
The first protection the application uses is a custom version of Bangcle. This tool encrypts Java bytecode (".dex" files), which can then be decrypted and loaded dynamically during runtime. To understand and defeat this technique, we can draw parallels to the well known binary obfuscation technique packing, where the code contained within an executable is also decrypted and loaded during runtime.
The two main methods of deobfuscating packed binaries are to statically analyze the packing routines and extract the data, or dump the memory of the executable after the data has been decrypted. In the context of Android applications, we can do the same. There has been previous research on static analysis of Bangcle, however Synacktiv was unable to apply the previous techniques to the DJI GO 4 application, as it is using a custom version of Bangcle. Rather, GRIMM utilized Synacktiv's Frida scripts to search through the memory of the Android application at runtime, and dump the decrypted ".dex" Java bytecode files. With the dumped Java bytecode files, GRIMM was able to use Java decompilers, such as jadx and Procyon, to decompile the bytecode, and obtain near-accurate Java source code, which we can perform static analysis on.
In addition to protecting the Android Java bytecode, the Java source code also features various static obfuscation techniques, most notably string obfuscation. Most of the strings used in the Java source code are obfuscated. However, this protection is rather simple to decipher, as described by Synacktiv. Many of the string usages have the following form:
c.b("d0s5KQ==")
The equal signs are a give away that it is encoded using base64. Referring to the c.b function, we can see:
public static String b(String str) {
return com.DJI.i.a.a.c.b(str, "Y*IBg^Yd");
}
This is actually a hardcoded repeated XOR key. Therefore we can decode the string with the following python3 code:
def string_decode(string, key):
result = ""
unpacked = base64.b64decode(string)
for i in range(len(unpacked)):
result += chr(unpacked[i] ^ key[i%len(key)])
return result HARDCODED_KEY = b"Y*IBg^Yd" string_decode("d0s5KQ==", HARDCODED_KEY) # Deobfuscates to ".apk"
Additionally, the DJI GO 4 application uses obfuscated string getter classes, such as the one shown below. These classes define an accessor function (m6624a in the code below), which takes an index to the desired string. These obfuscated strings can be easily recovered by decompiling the relevant class, adding a main function that dumps the strings, recompiling the code, and executing it.
With the ability to decompile the Java code and decode strings within that Java code, we were able to reverse engineer the source code and perform static analysis more efficiently. This static analysis allowed GRIMM to validate Synacktiv’s findings, as described below.
Network traffic
In addition to static analysis, GRIMM also performed dynamic analysis by intercepting network traffic sent by the Android application. Two distinct methods were used to intercept traffic, one on an emulated device and another on physical devices.
Emulated Device
On the emulated device, Android Studio’s HTTP proxy was used to redirect emulator traffic to Burp Suite, an application security testing proxy, with which traffic can be captured and analyzed. This set-up requires the emulated Android device to trust the Burp SSL certificate, which can be installed through the Android device’s settings.
Once set-up, all traffic that passes through the Android device will be captured in Burp Suite. One caveat is that Android applications are able to implement SSL pinning, a technique used to detect and thwart MITM attacks such as proxying. In DJI GO 4, SSL pinning was implemented for a select few subdomains of dji.com, such as mydjiflight.dji.com. GRIMM utilized Frida to bypass SSL pinning, as described.
Physical Device
To use Burp Suite with Android Nougat (10) on the Nexus 6P, it was necessary to insert the proxy's TLS key into Android's list of root CAs, stored at /system/etc/security/cacerts. A pair of iptables rules were used to reroute HTTP and HTTPS traffic to the proxy machine.
Dynamic testing on the Moto 3G was conducted by modifying the device's Wi-Fi network proxy to point to an instance of ZAP running on the researcher's computer. The proxy menu is accessible on Android Lollipop via the Settings menu: Wi-Fi -> Long press on the Network -> Modify network. On Android Lollipop, GRIMM was able to add ZAP's SSL certificate to Android root CA list via the Settings menu: Security -> Credential Storage, Install from from SD card.
SSL Pinning Bypass
DJI GO 4 uses SSL pinning to prevent MITM (Man In The Middle) attacks against some DJI requests. SSL pinning involves checking the certificate of the server, and comparing that with a hardcoded certificate.When there is a proxy, or an attacker between the Android application and the server, then the certificates will not match, causing the Android application to drop the connection to prevent sensitive data from being stolen.
To bypass SSL pinning, the universal Frida SSL bypass technique from this article was used. This technique works by using Frida to intercept the TrustManager initialization, which is responsible for determining whether a certificate is trusted. GRIMM setup Frida by pushing and running frida-server-12.11.1-android-arm.xz on the Android emulator. Additionally, Burp Suite’s certificate was pushed onto the Android emulator to the path /data/local/tmp/cert-der.crt.
Then, the command: frida -U -f dji.go.v4 -l fridascript.js --no-pause was run with this script, with a small modification to increase the timeout value from 0 ms to 5000 ms.
Findings Validation
Once GRIMM was able to statically analyze the application’s decrypted and decompiled source code and intercept and analyze the application’s network requests, we proceeded to validate Synacktiv’s findings.
Self-Update Mechanism
Synacktiv’s report describes the DJI GO 4’s custom update mechanism. This update service does not use the Google Play Store and thus, is not subject to the review process. As such, there is no guarantee that the application that is downloaded for one user matches that of another user. If DJI's update server is malicious, or compromised by an attacker, it could use this mechanism to target individual users with malicious application updates. One thing to note, this behavior is a violation of Google’s Developer Program Policies, which states:
An app distributed via Google Play may not modify, replace, or update itself using any method other than Google Play's update mechanism. Likewise, an app may not download executable code (e.g. dex, JAR, .so files) from a source other than Google Play.
...
The following are explicitly prohibited:
...
* Apps or SDKs that download executable code, such as dex files or native code, from a source other than Google Play.
Using dynamic analysis, GRIMM researchers were able to intercept traffic pertaining to the update of the DJI GO 4 application. Upon application startup or when using the "Check for Updates" option within the application, a request was sent to service-adhoc.dji.com, which responds with a URL to an updated application APK. This APK file is downloaded directly from DJI’s servers via the URL:
https://terra-2-g.djicdn.com/a81c919a2cba4e93a2147801711c04d1/1588314879661-DJI-v4.3.36_200426-967-36438_official_sec.apk/?auth_key\=1594407917-1594321517627-0-7c06b8fb2025df7ea362eeb2175bbc1b
This update option completely bypasses the Google Play Store, giving DJI’s servers the ability to fully control the APK downloaded, whether with malicious intent or not. The server response is shown below, which matches with Synacktiv’s findings:
When this response is received, the application prompts the user with the update notification shown below (left). Once the user clicks on the update notification, they are asked to install the update (middle). This update process does require the user to give the DJI GO 4 application the "Install unknown apps" permission, as shown below (right).
To help investigate this issue further, GRIMM utilized Burp and ZAP's ability to modify the server's response before it is forwarded to the test phones. First, GRIMM examined the purpose of the isForce flag in the server response by altering its value from 0 to 1. When a response with isForce set to 1 is received, the user is forced to install the update, or no longer be able to use the application. When a forced update occurs, the user will receive the prompt shown below (left).
Next, GRIMM investigated what validation is performed on the update and whether the update mechanism could be abused to install arbitrary applications. Using the ZAP Replacer rule shown below (right), GRIMM modified the downloadURL parameter to point to a copy of the Haven APK on a local web server. As expected, when the response was received by the client, the normal DJI update notification is created. Selecting the notification brings up the normal update dialog box, which when clicked begins the Haven installation shown below (middle).
Weibo SDK APK Installation
Synacktiv’s report also describes the ability of the Weibo SDK to download and prompt the user to install arbitrary applications. Once again, this functionality could be abused to target individual users with malicious application installations. Similarly to the previous finding, this issue also violates the Google Developer Program Policies. GRIMM reproduced Synacktiv’s results and conducted static and dynamic analysis in order to validate their findings. Based on the below analysis, GRIMM is in agreement with Synacktiv’s findings that the Weibo SDK includes the ability to download and install arbitrary APK files.
Using static analysis, GRIMM analyzed the AppInstallCmdExecutor class pertaining to the Weibo SDK user prompt for installing arbitrary APK files, specifically ones downloaded from Weibo's servers:
These APK files are requested via the WbAppActivator class’s requestCmdInfo function shown below. This function sends an HTTP GET request to Weibo's server every hour, which can respond with an application to install.
In order to confirm our static analysis, GRIMM also investigated the Weibo SDK dynamically. However, before the Weibo APK requests can be sent, the WbAppActivator class needs to be activated. Thus, the DJI application needs to access the Weibo SDK functionality before it will send these requests. GRIMM found that the Weibo functionality can be accessed within the DJI application via the Live Streaming Platform functionality builtin to the DJI application (shown below). This functionality is accessible by selecting these menu options from the main screen: Enter Device -> Camera View -> Ellipsis Menu -> Choose Live Streaming Platform -> Weibo -> Sign in.
Once the Weibo Sign In button is selected, the WbAppActivator class is activated. From then on, it will send requests every 3600 seconds (by default) asking for commands. An example request from the test Moto 3G and the associated response is shown below:
GET http://api.weibo.cn/2/client/common_config?appkey=3268350148&packagename=dji.go.v4&key_hash=1fe72ecb36d7d44aa2b53de11881bf38&version=0031405000&aid=01A4qtjH31x8UZFt94ewZ-QViZbqsrTeMOVeM1aW1GEBeOVxE.&oauth_timestamp=1595392290&oauth_sign=1d71954 HTTP/1.1
Connection: Keep-Alive
Host: api.weibo.cn
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
...
u7FFIamNkcuNHMwmAa+VaIrn96etbed19m6VA0iWPoJvCm7gIA0MWVbzJ1ybsUVNUIT99w77GJ/+kisI24y0JuGy6yYnlYC0UhW45tJ+jKuLzT/4OutB0Das7zE5iKsCMxGwAYgwva3uIFVoRRnVDWo813BSiag0BzJIRJzSrbUjTA5pQ1zaMp2ZhC1wtc3ed099SiPaRrGLfm3N5hVRSfxkuTZk41KX3G8huub6DXQKP3emeMY3zctkLxqrR6Ue6P7Ge8uZ4M73OvjyOCr9MT9DXHkjiW5mc4hdn508eK7YjJA2xwMrP693bmatCqMuAJIc40vSGfROKe1DSyf10VLBoD/Can4TRUUVSag8R4rKplJ0+vy702XF1Ar0XLkOd3pIdHqETwbKvHveedhVZw==
The responses to these requests are encrypted with AES via the AesEncrypt class using a static encryption key, bytes 2-18 of the MD5 hash in hex of the string "Stark". The AesEncrypt class even includes a test response that we can decrypt and analyze. As can be seen in the screenshot below, the test response is asking the Weibo SDK to download an application from http://weibo.cn/client/download and install it.
Using a modified version of the AesEncrypt class, GRIMM was able to decrypt the Weibo SDK response. However, the decrypted JSON object did not contain any commands to trigger an application installation.
{"cmd":{"app_install":[{"app_package":"","app_sign":"18da2bf10352443a00a5e046d9fca6bd","app_version":"1762","download_url":"","notification_delay":"","notification_text":"","notification_title":""}],"app_invoke":[{"notification_delay":"","notification_text":"","notification_title":"","package":"","scheme":"","url":""}],"frequency":""}}
In order to validate that the Weibo SDK can be used to install arbitrary applications, GRIMM modified the server's response to instruct the Weibo SDK to install the Haven application. This was accomplished by encrypting the below JSON object and using ZAP to modify the request before it's forwarded to the test device. This response instructs the application to download an APK from a local web server at http://192.168.1.129:8888/, which will be redirected to the actual APK download path. When this request is received, the application creates a notification with the title and text from the response, as shown below (left). Once this request is selected by the user, they are directed to install the downloaded application (right).
{"cmd":{"app_install":[{"download_url":"http://192.168.1.129:8888/","notification_text":"NOTIFICATION_TEXT","notification_delay":"0","app_package":"org.havenapp.main","app_sign":"65416cc1adf904c4be789ea82e699479","app_version":"999999","notification_title":"NOTIFICATION_TITLE"}],"frequency":"10000"}}
Given the nature of the Weibo SDK, GRIMM suspected that this issue may affect additional applications that also embed the Weibo SDK. As such, GRIMM engineers downloaded several other applications and analyzed the code for similar functionality. Based on the static decompilation, GRIMM discovered that the Everphoto, iPanda, WizNote applications also include this functionality. However, unlike the DJI GO 4 application, these applications are not encrypted or obfuscated. For instance, Everphoto also includes the requestCmdInfo function, but it was not encrypted and does not include the string obfuscation, as shown below. The code within WizNote is slightly refactored, but contains the same functionality.
For other applications, such as Baidu Search, Weibo, Meow Video, and Far Right, GRIMM did not find the APK downloader itself, but did find code which dynamically invokes the downloader via Java Reflection, as shown below:
Based on this analysis, we can draw a few important conclusions. First, Synacktiv’s findings are correct, the DJI GO 4 application contains code to download and install additional applications. Second, the DJI GO 4 application encrypts and obfuscates the Weibo SDK, making the discovery of the APK downloader harder than in other applications. Additionally, we can conclude that since the Weibo APK installer is built into the Weibo SDK, this issue has resulted in several different applications providing Weibo the ability to install arbitrary applications on their users’ devices. Finally, we can conclude that this SDK is risking its users' security by sending the common_config request over HTTP (rather than HTTPS), which would allow an active network attacker to see the request and forge responses.
Weibo SDK Data Collection
Next, GRIMM analyzed the Weibo SDK's data collection capabilities. Specifically GRIMM analyzed the Weibo SDK APK requests to determine if the requests for an APK to install can be correlated by the Weibo server to a specific individual. First let's look back at the common_config request and note that there is a unique value appended to the query, the aid parameter. This parameter is returned from the server in a previous request to the Weibo server's getaid API, as shown below.
GET https://api.weibo.com/oauth2/getaid.json?appkey=3268350148&mfp=01EvDlabV4S1rgNGjiGwmpHoQbDr9JQDkKCOssF9xXTIfKTWeCc%2FVQjNgFQFuLCR0DcQ9Tk9DwViaaQrf6L%2Fv%2BwnYHbH3pypH62wSqZS8vqHIDQjoL5hdG2lWXsD2jhlnSVTLsAOQmD%2FC2CdMc53opr6%2BjxuRW1aywPe8uh6aSMMIHUB3ne8834cO%2B874Th6GPbX%2BC7Ch0IHo1%2FS7pk25UlWivC1NVDhqjmQyYPbLoTcRgqezOdBhj5RYbJOBmMd%2B3qhHbLf5fL0tER9n6jj9foGBxUht8DMiE33j34t1dgXMvIVvGo7gxOBPjvSojuf3vlrJAGh4kYwy2wGRhQWMKK3aGEXt844o2Rx2Oqol%2Bwc1qnyCWIgmYPbbCpYi%2FUIUCOrQPnUikA106aoieC%2BIXxw8TE7duxSbaQrOrvXv5RUcirJp5kFYlt4k7D8ViZjbtrmXdF1U2OwGMuQUdk1Tnn87P5qQdJLk7zcH6qH9ijffilCSAhppwN9ftUb0ohQXHcRPJhExNST6UjzgpJ%2BgqN1BVvuf2hFwH1oobxz5TlB4bYA0hGwX%2FDYt%2Fo4oApnTmuHuJ6TEeHveFXQhcVu9idyo3DvwRFvuYlFzh9Pm3KhTmPLtlZ19UR1hdakTatw7luQ7CprdEIqYP5wNYy3unLyJq%2FLuVpKOQLZinYDral48%3D&packagename=dji.go.v4&key_hash=1fe72ecb36d7d44aa2b53de11881bf38&oauth_timestamp=1595394136&oauth_sign=c18b148 HTTP/1.1
Connection: Keep-Alive
Host: api.weibo.com
HTTP/1.1 200 OK
...
{"aid":"01A4qtjH31x8UZFt94ewZ-QViZbqsrTeMOVeM1aW1GEBeOVxE."}
Within this request, the RSA-encrypted mfp parameter is generated via the code shown below. This code grabs a series of device specific information, such as the IMEI, ICCID, Mac Address, Android Id, Device Name, etc, and encrypts it using the RSA public key MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHHM0Fi2Z6+QYKXqFUX2Cy6AaWq3cPi+GSn9oeAwQbPZR75JB7Netm0HtBVVbtPhzT7UO2p1JhFUKWqrqoYuAjkgMVPmA0sFrQohns5EE44Y86XQopD4ZO+dE5KjUZFE6vrPO3rWW3np2BqlgKpjnYZri6TJApmIpGcQg9/G/3zQIDAQAB embedded within the Weibo SDK. Given this information and the corresponding aid value being sent in the common_config request, correlating an APK installation request with a specific user or device is very feasible. All of the fields used to generate the mfp are associated with the corresponding aid value.
Mob SDK Data Collection
In Synacktiv’s report, the researchers detail their analysis of the data collection capabilities within the MobTech SDK framework. The researchers assert that the MobTech SDK framework is used to collect a substantial amount of user data and transmit it back to MobTech. GRIMM’s researchers were able to confirm the use of Mob SDK for data collection in previous versions of DJI GO 4 through both static and dynamic analysis.
First, GRIMM analyzed the intercepted network requests for mob.com subdomains, as shown below. In particular, the request to http://dfe.mic.mob.com/drl mentioned in the Synacktiv report can be seen below, with the encrypted payload.
Additionally, GRIMM statically found multiple instances of the MobTech code sending requests with user data. The first request generating code shown below is well described in a blog post by River Loop Security from May 12, 2020. In this request, we can see that the same user data is being collected through the MobTech SDK as detailed in the River Loop Security analysis of the DJI Mimo application:
In addition to the above code, GRIMM also discovered data being gathered in the com.mob.commons function shown below. This function uses obfuscated strings, retrieved via the C1308h.m6624a function described above, in an attempt to hide the data collection. After calling this function to collect the user’s data, the application calls the MobCommunicator.requestSynchronized function to send the data out the network.
As described in Synacktiv’s report, DJI GO 4 removed the MobTech SDK after River Loop Security’s blog post was published. GRIMM confirmed that the MobTech SDK is no longer within the DJI GO 4 application version 4.3.36.
App reloads in background
As described in the Synacktiv’s report, when a user attempts to close the app, it restarts itself in the background. As such, the app can only be killed through the Android "Force Stop" option, as it will be restarted if closed via the normal Android swipe close gesture. While the app is in the background, it accesses the device's location. It is unknown what is done with the location the device collects. It appears from the logcat messages (shown below) that the restarted process uses the MapBox Telemetry service, which requires a setting to opt out of location telemetry. The app does provide a switch to opt-out of "Coarse Location", however when the switch is turned off, a message pops up (shown below) and prevents the user from turning off this setting, and thus it is impossible to disable. The popup does not specifically mention MapBox.
07-10 14:55:22.070 4713 6692 I ActivityManager: Process dji.go.v4 (pid 8274) has died
07-10 14:55:22.070 4713 6692 D ActivityManager: cleanUpApplicationRecord -- 8274
07-10 14:55:22.070 4713 6692 W ActivityManager: Scheduling restart of crashed service dji.go.v4/com.mapbox.android.telemetry.TelemetryService in 21624ms
07-10 14:55:43.716 4713 4742 I ActivityManager: Start proc 8592:dji.go.v4/u0a119 for service dji.go.v4/com.mapbox.android.telemetry.TelemetryService
07-10 14:55:44.961 8592 8592 D DJI_GO_START: DJIApplication: is can load so.
07-10 14:55:44.973 8592 8592 D DJI_GO_START: DJIApplication: packageName=dji.go.v4, processName=dji.go.v4
07-10 14:55:56.398 8592 8592 I DJILocationManager: Attempting to get last known location from default providers…
Impact
Given these findings, it’s useful to consider the best and worst case scenarios for how these features are used. While they could just be slightly odd implementations for acceptable behavior, they could also be used in a much more nefarious way.
In the best case scenario, these features are only used to install legitimate versions of applications that may be of interest to the user, such as suggesting additional DJI or Weibo applications. In this case, the much more common technique is to display the additional application in the Google Play Store app by linking to it from within your application. Then, if the user chooses to, they can install the application directly from the Google Play Store. Similarly, the self-updating components may only be used to provide users with the most up-to-date version of the application. However, this can be more easily accomplished through the Google Play Store.
In the worst case, these features can be used to target specific users with malicious updates or applications that could be used to exploit the user's phone. Given the amount of user’s information retrieved from their device, DJI or Weibo would easily be able to identify specific targets of interest. The next step in exploiting these targets would be to suggest a new application (via the Weibo SDK) or update the DJI application with a customized version built specifically to exploit their device. Once their device has been exploited, it could be used to gather additional information from the phone, track the user via the phone’s various sensors, or be used as a springboard to attack other devices on the phone’s WiFi network. This targeting system would allow an attacker to be much stealthier with their exploitation, rather than much noisier techniques, such as exploiting all devices visiting a website.
Regardless of whether DJI or Weibo utilize their application’s functionality to target users, they have created an effective targeting system. As such, attackers who know of this functionality may attempt to compromise DJI’s and Weibo’s servers to exploit this functionality themselves. Given this risk, it’s much safer to rely on Google to provide application validation and distribution security.
Conclusion
This blog post details GRIMM’s efforts to validate Synacktiv’s privacy assessment of the DJI GO 4 Android application and determine the impact of their findings. After dumping the encrypted classes and setting up an emulated and physical test environment, GRIMM performed static and dynamic analysis in order to reverse the application and validate Synacktiv’s findings. The DJI GO 4 application contains several suspicious features as well as a number of anti-analysis techniques, not found in other applications using the same SDKs. Overall, these features are worrisome and may allow DJI or Weibo to access the user’s private information or target them for further exploitation.
This type of analysis is a key part of GRIMM's application security practice. GRIMM's application security team is well versed in auditing mobile applications to uncover hidden functionality, such as this blog describes, as well as identifying vulnerabilities within mobile applications. If your organization needs help uncovering hidden functionality in software you depend on, or identifying and mitigating vulnerabilities in your products, feel free to contact us.