小弟最近开始玩android,上月初把JNI弄懂,月底360就发布赛题。 运气还不错,正好练练手。废话不多说,下面开始分析。(来看雪第一篇帖子,大牛直接略过即可,不喜无喷,谢谢)
题意: 将apk逆向,将apk中的java加密算法使用JNI实现(简单吧。。。)
OnCreat加密方法调用点:
invoke-direct {p0, v3, v2}, Lcom/qihoo/test/first/MainActivity;->decrypt([BLjava/lang/String;)[B //调用decrypt方法
decrypt方法:
.method private decrypt([BLjava/lang/String;)[B
.locals 6
.parameter "src"
.parameter "password"
.annotation system Ldalvik/annotation/Throws;
value = {
Ljava/lang/Exception;
}
.end annotation
.prologue
.line 102
new-instance v3, Ljava/security/SecureRandom;
invoke-direct {v3}, Ljava/security/SecureRandom;-><init>()V //创建SecureRandom
.line 104
.local v3, random:Ljava/security/SecureRandom;
new-instance v1, Ljavax/crypto/spec/DESKeySpec;
invoke-virtual {p2}, Ljava/lang/String;->getBytes()[B //得到paramString Bytes数组
move-result-object v5
invoke-direct {v1, v5}, Ljavax/crypto/spec/DESKeySpec;-><init>([B)V //创建DESKeySpec
.line 106
.local v1, desKey:Ljavax/crypto/spec/DESKeySpec;
const-string v5, "DES"
invoke-static {v5}, Ljavax/crypto/SecretKeyFactory;->getInstance(Ljava/lang/String;)Ljavax/crypto/SecretKeyFactory; //得到SecretKeyFactory的DES实例
move-result-object v2
.line 108
.local v2, keyFactory:Ljavax/crypto/SecretKeyFactory;
invoke-virtual {v2, v1}, Ljavax/crypto/SecretKeyFactory;->generateSecret(Ljava/security/spec/KeySpec;)Ljavax/crypto/SecretKey; //生成SecretKey
move-result-object v4
.line 110
.local v4, securekey:Ljavax/crypto/SecretKey;
const-string v5, "DES"
invoke-static {v5}, Ljavax/crypto/Cipher;->getInstance(Ljava/lang/String;)Ljavax/crypto/Cipher; //得到Cipher的DES实例
move-result-object v0
.line 112
.local v0, cipher:Ljavax/crypto/Cipher;
const/4 v5, 0x2
invoke-virtual {v0, v5, v4, v3}, Ljavax/crypto/Cipher;->init(ILjava/security/Key;Ljava/security/SecureRandom;)V //初始化Cipher
.line 114
invoke-virtual {v0, p1}, Ljavax/crypto/Cipher;->doFinal([B)[B //得到加密后的字节数组
move-result-object v5
return-object v5
.end method
知道了加密函数各个部分的步骤,下面开始按顺序写JNI(C语言编写):
#include "com_qihoo_test_first_MainActivity.h"
#include <stdio.h>
jobject m_NewObject(JNIEnv *env, char classname[]);
JNIEXPORT jbyteArray JNICALL JNICALL Java_com_qihoo_test_first_MainActivity_decrypt(JNIEnv *env, jobject obj, jbyteArray paramArrayOfByte, jstring key)
{
jclass clazz = NULL;
jmethodID methodID = NULL;
jobject object = NULL;
jbyteArray byte_arr = NULL;
jobject localSecureRandom = NULL;
jobject localDESKeySpec = NULL;
jobject SecretKeyFactory = NULL;
jobject localSecretKey = NULL;
jstring algorithm = NULL;
jobject localCipher = NULL;
jint num = 2;
localSecureRandom = m_NewObject(env, "java/security/SecureRandom");
clazz = (*env) -> FindClass(env, "java/lang/String");
methodID = (*env) -> GetMethodID(env, clazz, "getBytes", "()[B");
byte_arr = (jbyteArray)(*env) -> CallObjectMethod(env, key, methodID);
clazz = (*env) -> FindClass(env, "javax/crypto/spec/DESKeySpec");
methodID = (*env) -> GetMethodID(env, clazz, "<init>", "([B)V");
localDESKeySpec = (*env) -> NewObject(env, clazz, methodID, byte_arr);
algorithm = (*env) -> NewStringUTF(env, "DES");
clazz = (*env) -> FindClass(env, "javax/crypto/SecretKeyFactory");
methodID = (*env) -> GetStaticMethodID(env, clazz, "getInstance", "(Ljava/lang/String;)Ljavax/crypto/SecretKeyFactory;");
SecretKeyFactory = (*env) -> CallStaticObjectMethod(env, clazz, methodID, algorithm);
methodID = (*env) -> GetMethodID(env, clazz, "generateSecret", "(Ljava/security/spec/KeySpec;)Ljavax/crypto/SecretKey;");
localSecretKey = (*env) -> CallObjectMethod(env, SecretKeyFactory, methodID, localDESKeySpec);
clazz = (*env) -> FindClass(env, "javax/crypto/Cipher");
methodID = (*env) -> GetStaticMethodID(env, clazz, "getInstance", "(Ljava/lang/String;)Ljavax/crypto/Cipher;");
localCipher = (*env) -> CallStaticObjectMethod(env, clazz, methodID, algorithm);
methodID = (*env) -> GetMethodID(env, clazz, "init", "(ILjava/security/Key;Ljava/security/SecureRandom;)V");
(*env) -> CallVoidMethod(env, localCipher, methodID, num, localSecretKey, localSecureRandom);
methodID = (*env) -> GetMethodID(env, clazz, "doFinal", "([B)[B");
return (jbyteArray)(*env) -> CallObjectMethod(env, localCipher, methodID, paramArrayOfByte);
}
jobject m_NewObject(JNIEnv *env, char classname[])
{
jclass clazz = NULL;
jmethodID methodID = NULL;
jobject obj = NULL;
clazz = (*env) -> FindClass(env, classname);
if(clazz == NULL)
return NULL;
methodID = (*env) -> GetMethodID(env, clazz, "<init>", "()V");
if(methodID == NULL)
return NULL;
obj = (*env) -> NewObject(env, clazz, methodID);
if(obj == NULL)
return NULL;
return obj;
}
最后修改MainActivity,删除其中的decrtp方法,加入statci和decrpt native 代码即可。这部分代码比较简答,就不附上来了吧。
附上:原APK文件,修改后的就不附上了吧。
----------------------------------------------
PS; 求转正!
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!