Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand Android sensitive data leakage

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "how to understand Android sensitive data leakage", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn how to understand Android sensitive data leakage.

1. The beginning and end of the event

On a dull afternoon, I was still longing for tea while knocking on the code. Suddenly my colleague on the server told me that the interface was being called mechanically and suspected that someone was using a script to swipe the interface (mainly for diversion from the platform).

What? No way, because as far as I know, the interface request is encrypted, and unless you know the encryption key and encryption method, it will not be called successfully. You must feel wrong. However, when my colleagues on the server sent me the interface call log, I completely denied my fluke mentality.

The calling frequency of the interface is fixed at 1 second.

The id of the follower is incremented one after another for each call (at present, the generation of user id in the business increases in turn according to the registration time)

Encrypted keys always use a fixed one (normally one of the fixed keys is used randomly at a time)

Summing up the above three points, it can be concluded that there must be the behavior of brushing the interface.

two。 Event analysis

Since the above behavior of browsing the interface is valid, it means that the key and encryption method are known by the other party for the following two reasons:

Internal personnel leakage

Apk was cracked.

After confirming that the first point is basically excluded, only apk is cracked, but the package released by apk has been reinforced and confused, is it possible that the other side has been shelled? No matter three, seven or twenty-one, try decompiling yourself first. As a result, it was decompiled one by one from the recently released version, and finally when decompiled to an earlier version, it was found that the source code of the utility class that saved the key and encryption was completely exposed.

It blew up and checked that this version was released without reinforcement, and this encryption tool class was not confused. Although it is not clear whether the other party obtained the key and encryption algorithm in this way, there is no doubt that this is a security loophole on the client side.

3. Event handling

Now that the above problems have been found, we must find a way to solve them. First of all, without considering reinforcement, how to ensure that the sensitive data in the client will not be disclosed as much as possible? On the other hand, even if the other party wants to crack it, it is necessary to find ways to set up barriers and increase the difficulty of cracking. Think of here basically determine an idea: using NDK, sensitive data and encryption methods will be put into the native layer, because C++ code compiled to generate the so library is a binary file, which will undoubtedly increase the difficulty of cracking. Using this feature, the sensitive data of the client can be written in C++ code, thus enhancing the security of the application. Just do it!

1. First, the encryption utility class is created:

Public class HttpKeyUtil {static {System.loadLibrary ("jniSecret");} / / obtain the key public static native String getHttpSecretKey (int index) according to random values; / / pass in the data to be encrypted and return the encrypted result public static native String getSecretValue (byte [] bytes);}

two。 Generate the corresponding header file:

# include # ifndef _ Included_com_test_util_HttpKeyUtil # define _ Included_com_test_util_HttpKeyUtil # ifdef _ _ cplusplus extern "C" {# endif JNIEXPORT jstring JNICALL Java_com_esky_common_component_util_HttpKeyUtil_getHttpSecretKey (JNIEnv *, jclass, jint); JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getSecretValue (JNIEnv *, jclass, jbyteArray); # ifdef _ cplusplus} # endif # endif

3. Write the corresponding cpp file:

Create the jni directory in the appropriate Module, copy the com_test_util_HttpKeyUtil.h in, and then create the com_test_util_HttpKeyUtil.cpp file

# include # include "com_test_util_HttpKeyUtil.h" extern "C" const char * KEY1 = "key 1"; const char * KEY2 = "key 2"; const char * KEY3 = "key 3"; const char * UNKNOWN = "unknown"; jstring toMd5 (JNIEnv * pEnv, jbyteArray pArray) Extern "C" JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getHttpSecretKey (JNIEnv * env, jclass cls, jint index) {if (random number condition 1) {return env- > NewStringUTF (KEY1);} else if (random number condition 2) {return env- > NewStringUTF (KEY2);} else if (random number condition 3) {return env- > NewStringUTF (KEY3) } else {return env- > NewStringUTF (UNKNOWN);}} extern "C" JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getSecretValue (JNIEnv * env, jclass cls, jbyteArray jbyteArray1) {/ / encryption algorithms are different. Here I will use md5 to demonstrate return toMd5 (env, jbyteArray1). } / / md5 jstring toMd5 (JNIEnv * env, jbyteArray source) {/ / MessageDigest jclass classMessageDigest = env- > FindClass ("java/security/MessageDigest"); / / MessageDigest.getInstance () jmethodID midGetInstance = env- > GetStaticMethodID (classMessageDigest, "getInstance", "(Ljava/lang/String;) Ljava/security/MessageDigest;") / / MessageDigest object jobject objMessageDigest = env- > CallStaticObjectMethod (classMessageDigest, midGetInstance, env- > NewStringUTF ("md5"); jmethodID midUpdate = env- > GetMethodID (classMessageDigest, "update", "([B) V"); env- > CallVoidMethod (objMessageDigest, midUpdate, source); / / Digest jmethodID midDigest = env- > GetMethodID (classMessageDigest, "digest", "() [B") JbyteArray objArraySign = (jbyteArray) env- > CallObjectMethod (objMessageDigest, midDigest); jsize intArrayLength = env- > GetArrayLength (objArraySign); jbyte * byte_array_elements = env- > GetByteArrayElements (objArraySign, NULL); size_t length = (size_t) intArrayLength * 2 + 1; char * char_result = (char *) malloc (length); memset (char_result, 0, length); toHexStr ((const char *) byte_array_elements, char_result, intArrayLength) / / add\ 0 * (char_result + intArrayLength * 2) to the end; jstring stringResult = env- > NewStringUTF (char_result); / / release env- > ReleaseByteArrayElements (objArraySign, byte_array_elements, JNI_ABORT); / / pointer free (char_result); return stringResult;} / / convert to hexadecimal string void toHexStr (const char * source, char * dest, int sourceLen) {short I Char highByte, lowByte; for (I = 0; I

< sourceLen; i++) { highByte = source[i] >

> 4; lowByte = (char) (source [I] & 0x0f); highByte + = 0x30; if (highByte > 0x39) {dest [I * 2] = (char) (highByte + 0x07);} else {dest [I * 2] = highByte;} lowByte + = 0x30 If (lowByte > 0x39) {dest [I * 2 + 1] = (char) (lowByte + 0x07);} else {dest [I * 2 + 1] = lowByte;}

4. Is this the end of the incident?

Is this the end of this? too yuang too simplebirds! Although the key and encryption algorithm are written in C++, it seems to be more secure. But what if someone else decompiled, got the so library generated by C++ code, and then directly called the method in the so library to get the key and call the encryption method? It seems that we still need to add one step of identity verification, that is, to verify the package name and signature of the application at the native layer, and the correct result will be returned after the verification is passed. Here is the code to get the apk package name and signature verification:

Const char * PACKAGE_NAME = "your ApplicationId"; / / (the MD5 value of the signature can be obtained by writing or directly using the signature tool. Generally speaking, the MD5 value of the signature will also be applied when interfacing with Wechat sdk) const char * SIGN_MD5 = "the MD5 value of your application signature should be uppercase"; / / get the Application instance jobject getApplication (JNIEnv * env) {jobject application = NULL / / here is the classpath of your Application. In case of confusion, be careful not to confuse this class with the method of obtaining instances such as getInstance jclass baseapplication_clz = env- > FindClass ("com/test/component/BaseApplication"); if (baseapplication_clz! = NULL) {jmethodID currentApplication = env- > GetStaticMethodID (baseapplication_clz, "getInstance", "() Lcom/test/component/BaseApplication;") If (currentApplication! = NULL) {application = env- > CallStaticObjectMethod (baseapplication_clz, currentApplication);} env- > DeleteLocalRef (baseapplication_clz);} return application;} bool isRight = false; / / get the MD5 value of the application signature and determine whether it is consistent with the jboolean getSignature (JNIEnv * env) {LOGD ("getSignature isRight:% d", isRight? 1: 0) of this application. If (! isRight) {/ / avoid wasting resources in checking every time, as long as the first verification passes, jobject context = getApplication (env) will not be performed later; / / get the Context class jclass cls = env- > FindClass ("android/content/Context") / / get the ID jmethodID mid = env- > GetMethodID of the getPackageManager method (cls, "getPackageManager", "() Landroid/content/pm/PackageManager;"); / / get the manager of the application package jobject pm = env- > CallObjectMethod (context, mid) / / get the ID mid = env- > GetMethodID (cls, "getPackageName", "() Ljava/lang/String;") of the getPackageName method; / / get the current application package name jstring packageName = (jstring) env- > CallObjectMethod (context, mid); const char * c_pack_name = env- > GetStringUTFChars (packageName, NULL) / / compare the package name. If it is inconsistent, directly return the package name if (strcmp (c_pack_name, PACKAGE_NAME)! = 0) {return false;} / / get the PackageManager class cls = env- > GetObjectClass (pm) / / get the ID mid = env- > GetMethodID (cls, "getPackageInfo", "(Ljava/lang/String;I) Landroid/content/pm/PackageInfo;") of the getPackageInfo method; / / get the information of the application package jobject packageInfo = env- > CallObjectMethod (pm, mid, packageName, 0x40) / / GET_SIGNATURES = 64; / / get the PackageInfo class cls = env- > GetObjectClass (packageInfo); / / get the signature array attribute ID jfieldID fid = env- > GetFieldID (cls, "signatures", "[Landroid/content/pm/Signature;"); / / get the signature array jobjectArray signatures = (jobjectArray) env- > GetObjectField (packageInfo, fid) / / get signature jobject signature = env- > GetObjectArrayElement (signatures, 0); / / obtain Signature class cls = env- > GetObjectClass (signature); mid = env- > GetMethodID (cls, "toByteArray", "() [B"); / / current application signature information jbyteArray signatureByteArray = (jbyteArray) env- > CallObjectMethod (signature, mid) / / convert jstring jstring str = toMd5 (env, signatureByteArray); char * c_msg = (char *) env- > GetStringUTFChars (str, 0); LOGD ("getSignature release sign md5:% s", c_msg); isRight = strcmp (c_msg, SIGN_MD5) = = 0; return isRight;} return isRight } / / there is a verification method, so we need to modify the key acquisition and encryption method in step 3 to add the logic extern "C" JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getHttpSecretKey (JNIEnv * env, jclass cls, jint index) {if (getSignature (env)) {/ / check through if (random number condition 1) {return env- > NewStringUTF (KEY1) } else if (random number condition 2) {return env- > NewStringUTF (KEY2);} else if (random number condition 3) {return env- > NewStringUTF (KEY3);} else {return env- > NewStringUTF (UNKNOWN);}} else {return env- > NewStringUTF (UNKNOWN) } extern "C" JNIEXPORT jstring JNICALL Java_com_test_util_HttpKeyUtil_getSecretValue (JNIEnv * env, jclass cls, jbyteArray jbyteArray1) {/ / encryption algorithms are different. Here I will use md5 to demonstrate that if (getSignature (env)) {/ / check passes return toMd5 (env, jbyteArray1);} else {return env- > NewStringUTF (UNKNOWN) }} author: AirSj link: https://juejin.im/post/6862732328406351879 Source: Nuggets copyright belongs to the author. Commercial reprint please contact the author for authorization, non-commercial reprint please indicate the source. At this point, I believe you have a deeper understanding of "how to understand Android sensitive data disclosure". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report