安卓加壳实例--解密部分放入JNI

来源:互联网 发布:单片机按键电路的作用 编辑:程序博客网 时间:2024/06/16 02:14

    参考https://github.com/longtaoge/AndroidShell(实例),http://blog.csdn.net/androidsecurity/article/details/8678399(原理)。

    开发环境Eclipse + Android Studio。


    原作者原理摘要:

        加壳程序工作流程:
       1、加密源程序APK文件为解壳数据
       2、把解壳数据写入解壳程序Dex文件末尾,并在文件尾部添加解壳数据的大小。
       3、修改解壳程序DEX头中checksum、signature 和file_size头信息。
       4、修改源程序AndroidMainfest.xml文件并覆盖解壳程序AndroidMainfest.xml文件。
        解壳DEX程序工作流程:
       1、读取DEX文件末尾数据获取借壳数据长度。
       2、从DEX文件读取解壳数据,解密解壳数据。以文件形式保存解密数据到a.APK文件
       3、通过DexClassLoader动态加载a.apk。


    首先实现要被加壳的安卓程序和加壳JAVA程序:

    一、加壳JAVA程序

    主要做三件事情:加密源程序APK文件为解壳数据;把解壳数据写入解壳程序Dex文件末尾,并在文件尾部添加解壳数据的大小;修改解壳程序DEX头中checksum、signature 和file_size头信息。

    编辑完代码后,Run as Java Application, 必须执行此步, 否则导出的时候没有Launch Configuration选项。再执行Export -> Java..Runnable jar file, 如下图:

 

    继续Next, 选择正确的Launch Configuration选项, 浏览选择到处目的文件夹, 如图:

    成功导出可执行JAR包文件。

   二、新建被加壳的APK源程序, 生成AndroidProtectionDemo.apk,(注意不要如果引用其他库工程,不能这样打包,请先把库工程做成JAR包引入):

  右键Run as Android Application,任意选择实机或者模拟器运行,重要的是在bin有生成APK文件,  且保证程序运行正常。拷贝此文件到与上一步JAR包文件同一目录,新建TXT文件,更改扩展名为bat,若隐藏了扩展名,自行百度显示扩展名,或者评论回复。输入以下内容,两行:

java -jar toShellDex.jar  AndroidProtectionDemo.apk  unshell.dex classes.dex
pause

其中toShellDex.jar为刚刚生成的JAR包文件, AndroidProtextionDemo.apk为要加壳的程序, unshell.dex为壳程序的Dex文件(下一步生成), classes.dex为含有APK加密数据的Dex文件。

 

   其次组建安卓壳程序,用于寄宿被加壳的程序。

    三、新建壳程序,AndroidProtectionShell.apk, classes.dex, 融合JNI解密(同样不要引用库工程):

    1.编写一个类Security,里面仅包含native方法:

package club.younge.jni;public class Security {public native byte[] decrypt(byte[] data);   public native int add(int x, int y);public native void destroy();}


其中add方法用来测试JNI调用是否成功。

    2.接着生成C++的头文件,直接到壳程序的bin/classes目录下新建BAT文件,输入以下内容:

javah -jni club.younge.jni.Security
pause

双击运行,生成club_younge_jni_Security.h头文件,在工程根目录下新建JNI目录,拷贝到里面。

     然后新建Security.h, Security.cpp, club_younge_jni_Security.cpp文件, 其中Security本来打算用于解密,但是在从jbyte *转换char *, 小部分数据居然发生变化,暂未找出原因,留待以后有机会解决。故其实可以忽略掉这个类的内容。 然后分别输入以下内容:

Security.h

#ifndef _SECURITY_DECRYPT_H_#define _SECURITY_DECRYPT_H_class Security {public:Security();~Security();char * decrypt(char *);};#endif


Security.cpp

#include "Security.h"#include <stdio.h>#include <stdlib.h> Security::Security() { } Security::~Security() { }


club_younge_jni_Security.cpp

#include <stdio.h>#include <stdlib.h>#include<android/log.h>#include "club_younge_jni_Security.h"#include "Security.h"#define TAG  "younge-jni" // 这个是自定义的LOG的标识#define LOGD(...)  __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) // 定义LOGD类型Security *pSecurity = NULL;JNIEXPORT jbyteArray JNICALL Java_club_younge_jni_Security_decrypt(JNIEnv *env, jobject object, jbyteArray data){if(pSecurity == NULL){pSecurity = new Security;}jbyte* temp = (jbyte*)env->GetByteArrayElements(data, 0);jsize len = env->GetArrayLength(data);for(int i=0; i<len; i++){*(temp + i) = *(temp + i) ^ 42;//LOGD("------data byte: -----%c --- %c ", *(temp + i), dataa[i]);}LOGD("------data: -----%s", temp);jbyteArray result = env->NewByteArray(len);env->SetByteArrayRegion(result, 0, len, temp);return result;}JNIEXPORT void JNICALL Java_club_younge_jni_Security_destroy(JNIEnv *env, jobject object){if(pSecurity != NULL){pSecurity = NULL;}}JNIEXPORT jint JNICALL Java_club_younge_jni_Security_add(JNIEnv *env, jobject object, jint x, jint y){return x + y;}


    3.接着在JNI目录中新建Android.mk文件:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS :=-llog
LOCAL_MODULE := Security
LOCAL_SRC_FILES := club_younge_jni_Security.cpp
LOCAL_SRC_FILES += Security.cpp
include $(BUILD_SHARED_LIBRARY)

在根目录中新建Application.mk文件:

APP_PROJECT_PATH := $(call my-dir)
APP_MODULES := Security


其中LOCAL_MODULE := Security和APP_MODULES := Security中的Security为SO库的库名称,NDK时自动在前面加上lib前缀和.so后缀。

    再在工程根目录下新建BAT文件,输入以下内容, 运行此BAT命令前,请在命令行确认ndk-build -v执行能显示出GNU Make的版本号,否则请配置NDK环境:

ndk-build

pause

若执行命令循环不停止,请把AndroidManifest.xml文件暂时移动至其他地方,执行完毕后再移动回来。

命令执行完毕会在libs/armeabi下生成libSecurity.so文件,请在工程根目录上刷新,然后检查。

在ProxyApplication解密APK文件时,调用JNI关键代码:

static {        // 加载动态库        System.loadLibrary("Security");    }Security security = new Security();Log.e("younge", "decrypt before:" + HexUtil.toHex(newdex));try {newdex = security.decrypt(newdex);Log.e("younge", "decrypt afer" + HexUtil.toHex(newdex));} catch (Exception e) {Log.e("younge", "decrypt:" + e.toString());}Log.e("younge", "add result:" + security.add(2, 3));security.destroy();


    4.重要的一步,配置壳程序的AndroidManifest.xml文件,配置application名称为club.younge.shell.ProxyApplication,对应包中的Application类等其他信息:

<application        android:name="club.younge.shell.ProxyApplication"        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <!-- 应用的Application -->        <meta-data            android:name="APPLICATION_CLASS_NAME"            android:value="club.younge.demo.DemoApplication" />        <activity            android:name="club.younge.shell.MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <!-- 以下为被加壳的应用Activity注册信息  要带全包名 否则有可能找不到 -->        <activity            android:name="club.younge.demo.MainActivity"            android:label="@string/demo_app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application>

同时,请将被加壳程序的所有资源复制到壳程序资源文件目录中,请自行更改与壳程序中相同资源名称,否则你会发现被加壳程序貌似显示不对,其实是用了壳程序的资源。

    最后,替换壳程序的DEX文件,签名更换了DEX文件的壳程序。

    四、替换壳程序的classes.dex文件

    1.第三步Run as Android Application , 在bin目录下生成APK和DEX文件,确保程序运行正常。复制这两个文件到第一步生成JAR包文件目录下。修改DEX文件名称为unshell.dex. 运行buildApkToShellDex.bat,  生成所需的classes.dex文件。用WINRAR打开AndroidProtectionShell.apk文件,删除META-INF签名文件夹和classes.dex文件,然后将前面生成的classes.dex文件添加到apk文件中(往压缩文件中添加文件到根目录)。

   2.签名已经组装好的APK文件,准备一个签名keystore文件, 建立一个BAT文件,输入以下内容

jarsigner -verbose -keystore younge.keystore -storepass xxxxxxxx -signedjar AndroidShell_signed.apk -digestalg SHA1 -sigalg MD5withRSA AndroidProtectionShell.apk younge
pause

其中youge.keystore为keystore文件,通过eclipse导出为android application时可以生成一个签名文件;-storepass为签名文件密码;-signedjar AndroidShell_signed.apk -digestalg SHA1 -sigalg MD5withRSA AndroidProtectionShell.apk 指定生成的签名文件名为AndroidShell_signed.apk,指定采用SHA1的HASH算法, 未签名的APK文件为AndroidProtectionShell.apk;younge为签名文件的别名,无需指定别名密码。

    运行jarsign.bat,生成签名APK。安装到手机,发现生成了两个图标,一个图标为壳程序,一个为被加壳的程序,打开程序运行效果与单个安装效果一致即成功。测试手机4.4.4和5.0.1。


注意:更新原作者的ArrayMap问题,解密部分采用JNI方式。



Github:eclipse源码 ,android studio 被加壳程序源码 ,android studio 壳程序源码


JNI加解密:http://www.cnblogs.com/langtianya/p/3752883.html

SO加解密:http://blog.csdn.net/thomasking2014/article/details/38941541



  

1 0
原创粉丝点击