精华内容
下载资源
问答
  • 安卓加壳实例--解密部分放入JNI

    千次阅读 2016-08-22 20:00:16
    安卓APK加壳实例

        参考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



      

    展开全文
  • 安卓逆向-加壳检测

    2019-12-10 11:09:43
    安卓逆向-加壳检测 环境 Win10(虚拟机)、Java1.8 工具 ApkScan-PKID 步骤(已有java环境的省略一、二、三步) 一、下载Java1.8 链接: https://www.java.com/zh_CN/download/windows-64bit.jsp 二、安装java 记得修改...

    安卓逆向-加壳检测

    环境

    Win10(虚拟机)、Java1.8

    工具

    ApkScan-PKID

    步骤(已有java环境的省略一、二、三步)

    一、下载Java1.8

    链接: https://www.java.com/zh_CN/download/windows-64bit.jsp

    二、安装java

    记得修改保存路径

    三、配置Java环境

    1、
    在这里插入图片描述
    2、
    在这里插入图片描述
    3、
    在这里插入图片描述
    4、
    在这里插入图片描述
    5、
    在这里插入图片描述
    6、
    在这里插入图片描述
    在这里插入图片描述
    JAVA_HOME的值是第2步安装的java文件路径.

    四、下载ApkScan-PKID

    链接: 链接:https://pan.baidu.com/s/17Khi8m6K6HiVOk6IaKrSCw 密码:18wg
    (注: 如果链接失效,就去网上搜一搜)

    五、ApkScan-PKID使用

    解压完进入文件
    1、打开cmd
    2、进入ps:

    powershell
    

    3、检测java环境:

    java version
    

    4、启动pkid:

    java -jar .\ApkScan-PKID.jar
    

    在这里插入图片描述

    六、查壳

    在这里插入图片描述
    结束语:
    虽然有些软件没有做加壳,但是个人感觉这一步还是很有必要做的.

    展开全文
  • 抖音数据采集从0到1,安卓App加壳与脱壳原理 前针对移动应用市场上安卓APP被破解、反编译、盗版丛生的现象,很多APP开发人员已经意识到保护APP的重要性。而对于移动应用APP加密保护的问题,如何对DEX文件加密尤为...

    抖音数据采集从0到1,安卓App加壳与脱壳原理

    前针对移动应用市场上安卓APP被破解、反编译、盗版丛生的现象,很多APP开发人员已经意识到保护APP的重要性。而对于移动应用APP加密保护的问题,如何对DEX文件加密尤为重要。

    简介

    加壳是在二进制的程序中植入一段代码,在运行的时候优先取得程序的控制权,做一些额外的工作。大多数病毒就是基于此原理。是应用加固的一种手法对原始二进制原文进行加密/隐藏/混淆。
    作用:加壳的程序可以有效阻止对程序的反汇编分析,常用来保护软件版权,防止被软件破解。
    APP加壳软件:apkprotect,梆梆加固,爱加密,娜迦,阿里,百度,腾讯,360等
     

    Android Dex文件加壳原理

    下面是Android加壳的原理:

    image.png


    在这个过程中,牵扯到三个角色:
    1、需要加密的Apk(源Apk)
    2、壳程序Apk(负责解密Apk工作)
    3、加密工具(将源Apk进行加密和壳Dex合并成新的Dex)
     
    主要步骤:
    1、拿到需要加密的Apk和自己的壳程序Apk
    2、用加密算法对源Apk进行加密在将壳Apk进行合并得到新的Dex文件
    3、替换壳程序中的dex文件即可,得到新的Apk,
    那么这个新的Apk我们也叫作脱壳程序Apk.他已经不是一个完整意义上的Apk程序了,他的主要工作是:负责解密源Apk.然后加载Apk,让其正常运行起来。
     
    在这个过程中我们可能需要了解的一个知识是:如何将源Apk和壳Apk进行合并成新的Dex

    优点:  1、保护自己核心代码算法,提高破解/盗版/二次打包的难度  
    
           2、还可以缓解代码注入/动态调试/内存注入攻击.
    
    缺点: 1、影响兼容性     2、影响程序运行效率.

    短视频、直播数据实时采集接口,请查看文档: TiToData


    免责声明:本文档仅供学习与参考,请勿用于非法用途!否则一切后果自负。

    展开全文
  • 安卓的加固方案是从 19 年底开始写的,到现在为止差不多快一年了,写这个目的还是学习怎么脱壳,前几个月再看雪看到有人直接分析壳来学习,不过我感觉从加壳写起也是一种浪漫。因为个人原因,在类指令抽取壳那里为半...

    db04e8e7ffe81bb92d50a74ec2d9861c.png

    安卓的加固方案是从 19 年底开始写的,到现在为止差不多快一年了,写这个目的还是学习怎么脱壳,前几个月再看雪看到有人直接分析壳来学习,不过我感觉从加壳写起也是一种浪漫。因为个人原因,在类指令抽取壳那里为半完成状态,在今年大概率没有时间接着修改了,在 java 层的加固就止于此吧!!!(PS: 以后有时间会接着修改) 

    环境配置:

    Android studio v3.5.3 

    华为G621-TL00 android v4.4.4 

    第一代壳:落地加载

    1、原理

    a、原理很简单,就是首先将我们的 dex 文件或者 apk 文件解密,然后利用DexClassLoader加载器将其加载进内存中,然后利用反射加载待加固的 apk 的 appkication,然后运行待加固程序即可,我画了个流程图详细说明如下: 

    57898e60e847381422f566781d45ff7a.png

    b、上面说了大概原理,现在来说明一下具体细节,我们知道,在一个 app 开始运行的时候,第一个加载的类是ActivityThread,该类有个关键属性currentActivityThread,通过该属性能够获取到一系列其他关键的属性,例如mPackages,通过该属性,我们可以获取到mClassLoader属性,通过替换该属性我们可以替换系统加载器,如下所示: 

    828747f316a217626132f0d3b7d03cba.png

    接着来说怎么获取待加固 apk 的 application,这个通过在脱壳 apk 的 AndroidManifest.xml 中使用meta-data来获取,如下所示: 

    e95b0f6e183f92e0f5f8c5fa445c9892.png

    在然后就是怎么替换 application,我们可以知道在 android.app.LoadedApk 类中有一个方法makeApplication可以生成一个 application,通过该方法生成一个 application,然后通过替换android.content.ContentProvider类中的mContext属性完成 application 的替换,如下图所示: 

    128dfdeadb36a6cd2de88a52cdb6a52e.png

    2、实际操作

    ps:因为第一代壳网上一大堆,所以讲得很粗略,同时这也不是本文的重点!!! 

    通过上面的代码我们可以得到脱壳 apk,然鹅待加固的 apk 放在哪里,网上大多放在脱壳 dex 的尾部,我又画了一张图,应该可以看图就懂了: 

    d61e19f13015c507075e40411d7f51bb.png

    这个我采用通过 python 读取二进制然后重新计算 chunksum 和签名字段实现,代码如下: 

    import binasciiimport hashlibimport zlibdef fixCheckSum(shell):    shell.seek(0x0c)    data = shell.read()    checksum = zlib.adler32(data)    strchecksum = str(hex(checksum))    strchecksum = strchecksum.replace('0x','')    b = bytes(strchecksum.encode('utf-8'))    a = bytearray(b)    c = binascii.hexlify(binascii.unhexlify(bytes(a))[::-1])    dataCheckSum = bytearray(c)    shell.seek(0x08)    shell.write(dataCheckSum)def fixSHA1(shell):    shell.seek(0x20)    signBytes = shell.read()    sha1 = hashlib.sha1()    sha1.update(signBytes)    sign = sha1.hexdigest()    tmp = bytes(sign.encode('utf-8'))    b = bytearray(tmp)    shell.seek(0x0c)    shell.write(b)def fixFileSize(shell,num):    b = bytearray()    for i in range(4):        number = int(num % 256)        b.append(number)        num = num >> 8    shell.seek(0x20)    shell.write(b)def IntToHex(num):    b = bytearray()    for i in range(4):        number = int(num % 256)        b.append(number)        num = num >> 8    b.reverse()    return bdef main():    sourceApk = open('sourceApk.apk','rb+',True)    unshell = open('unshell.dex','rb+',True)    filename = 'classes.dex'        tmpApk = sourceApk.read()    print('[*] 成功读取待加壳的APK文件')    sourceArray = bytearray(tmpApk)    tmpDex = unshell.read()    print('[*] 成功读取脱壳DEX文件')    unshellArray = bytearray(tmpDex)    print('[-] 待加壳APK文件开始加密,加密类型为:未加密')        sourceApkLen = len(sourceArray)    unshellLen = len(unshellArray)    print('[+] 加密后的APK大小为' + str(sourceApkLen) + 'Byte')    totalLen = sourceApkLen + unshellLen + 4        tmpByteArray = unshellArray + sourceArray    newdex = tmpByteArray + IntToHex(sourceApkLen)    print('[+] 所有二进制数据合成完毕')        shellTmp = open(filename,'wb+',True)    shellTmp.write(newdex)    shellTmp.close()    print('[+] 数据写入' + filename + '完毕')        shell = open(filename,'rb+',True)    fixFileSize(shell,len(newdex))    print('[+] 文件大小修改完毕')    fixSHA1(shell)    print('[+] 文件SHA-1签名头部修改完毕')    fixCheckSum(shell)    print('[+] 文件校验头头部修改完毕')    print('[+] 待加壳APK文件sourceApk.apk加壳完毕,加壳后DEX文件' + filename + '生成完毕')    shell.close()    if __name__ == '__main__':    main()

    将上述 apk 重新签名后,安装运行,如下图所示: 

    cbc9e032e76778c4f30666994f6c6659.png

    f75639f8f1017d2a0a2060dbd801b643.png

    3、遇到的问题

    运行时报错如下所示: 

    d2fdf8d53f5c6f90b588bd87291bff87.png

    解决方案:报错显示无法实例化 activity,经过检查是无法加载到正确格式的 dex 文件,检查你的解密代码,即使是你加密是象征型的异或了一个 0xff,解密时也不能因为异或 0xff 值不变而不异或 0xff。其次是打包成 apk 之前删除签名文件之后在签名!!! 

    第二代壳:不落地加载

    1、原理

    大体原理和第一代壳相同,和第一代壳不同的是,第一代壳将 dex 文件解密出来会保存到文件中,在通过 DexClassLoader 加载进内存中,而不落地加载直接重写DexClassLoader使其可以直接加载字节数组,避免写入文件中。我们要做的是重写DexClassLoader,而这涉及到三个函数defineClassfindClassloadClass,在一个类被加载的时候,会先后调用这三个函数加载一个类,所以我们需要重写这三个函数,但是我们怎么在重写的过程中操控 dex 中的类(通过字节数组加载进来的并不能直接操控)?

    其实系统的 DexClassLoader 加载 dex 进入内存的也必然是通过字节加载的,而在系统 so 中的libdvm.so中的openDexFile可以直接加载 dex 文件,那么现在清楚了,我们可以通过编写 s o文件调用openDexFile函数加载dex字节数组,值得注意的是,openDexFile函数返回值为一个int类型的 cookie,可以简单理解成一个 dex 文件的'身份码',通过该'身份码'即可操控这个 dex 文件,至于怎么调用该函数,可以通过dlopendlsym函数调用,相关代码如下所示: 

    50bc2fba6e9550d7270695cd05c2b1cb.png

    bec83f1b0b5f7a258eb28e36ec813077.png

    2、实际操作

    a、首先编写样本,这里我写了一个类和一个方法,作用就是打印一个特征字符串,如下所示: 

    f6038f1ae149f07a5f1b5b0e3b12a959.png

    b、将上面的样本打包成 apk 后提取出 dex 文件然后放置到 assest 文件夹下(该文件夹需要自己建立)供程序调用(ps:我这里图方便,没有对 dex 文件加密然后解密,有需要的可以加上),然后脱壳 apk 和上面的第一代壳没什么区别,唯一不同的是就是我们使用的是我们自己重写的DexClassLoader,如下图所示: 

    7bb4a89652675be08381a0a0b85308e0.png

    c、运行截图如下: 

    357fe55db05e7d5a12ab9a912bd45494.png

    3、遇到的问题

    a、报错java.lang.UnsatisfiedLinkError: Native method not found

    解决方案:在配置文件中添加

    packagingOptions{        pickFirst "lib/armeabi-v7a/libtwoshell.so"        pickFirst "lib/arm64-v8a/libtwoshell.so"        pickFirst "lib/x86/libtwoshell.so"        pickFirst "lib/x86_64/libtwoshell.so"    }

    如下所示: 

    3780c49b61e5f28b84e87d1d87da72f0.png

    b、运行到加载 dex 文件中的方法时,app 直接闪退 

    解决方案:重写的loadClass方法有问题,不能通过直接 super 调用父类方法,而是应该通过反射调用defineClassNative方法,如下所示: 

    21c1670c7052ae3ae698610b25ee5b32.png

    第三代壳:类指令抽取壳

    1、原理

    a、什么是类指令抽取壳,从名字就能看出来,就是把dex文件中的方法指令抽空,变成nop,然后在运行时再将指令还原!!! 

    b、指令抽取可以通过 010 修改,现在来说指令还原,其余代码和第二代基本一样,不一样的地方在加载完 dex 之后执行指令还原函数,指令还原现在有两种方法,第一种是通过读取maps文件获取加载的 dex 文件地址,然后对 dex 文件进行解析,找到被 nop 的指令处进行还原(ps:该种方法需要及其熟悉 dex 文件格式,不了解的可以看我之前的文章关于解析 dex 文件,因为我之前解析的时候用的是 python,改成 c 要大量时间,所以我选择了第二种方法);第二种方法就是通过免 root hook 系统函数(最简单的就是 deFindClass 函数)然后进行指令还原!!! 

    c、接下来就讲一下怎么通过 hook dexFindClass 函数来进行指令还原(PS:看懂下面的内容需要理解 dex 文件格式)。dexFindClass函数在libdvm.so库中,如下所示: 

    17d55eb0982cb6e98b95da05d5cc72b6.png

    免 root hook 框架有点多,我选择的是 android inline hook,原因很简单,很适合在so层使用,其他的经过我测试不知道为啥我写出来的没反应,该框架 github 地址:

    https://github.com/ele7enxxh/Android-Inline-Hook

    用法可以参考作者 github,该 inline hook 框架需要原函数地址、新函数地址和原始函数的二级指针,用法如下所示(怎么使用不是重点,接下来的才是重点,所以这里比较粗略): 

    b17d0d2e24385fcf4b4fddd414ba4723.png

    我们要 hook 的是dexFindClass函数,该函数定义在DexFile.h文件中,该函数返回值为一个类结构指针,第二个参数为类名字,通过该参数我们就可以指定类进行指令还原,如下所示: 

    75dbb39bd65631b8b0ebcef884f2c8bc.png

    e1a23237451157276531598173bd8b45.png

    上面我们得到的classDataOff,我们可以通过该地址获取到类数据,该偏移地址指向的是一个DexClassData结构,该结构的header存储了相关类信息,该结构的directMethods指针指向的方法的结构体,如下所示: 

    59ab53d05d66049a36d0355d18b97b42.png

    通过directMethods指针我们可以顺着找到DexMethod结构体,通过该结构体的methodIdx调用系统函数dexGetMethodIddexStringById可以获取到方法名字,精确还原方法指令,通过该结构的codOff(这是个偏移地址)可获取方法指令,该偏移地址指向DexCode结构,该结构即存储了方法指令,利用memcpy替换即可达到指令还原的效果,如下所示: 

    fc583166b65ce9eb41f344643ac42df0.png

    323e1355b198601c1e9c24965db6e48a.png

    2、实践操作

    java 层基本和第二代壳一样,只是多了一个调用 hook 的函数,so 层关键代码如下所示:(ps:不知道为啥 Android inline hook 稳定性很差,上一个测试 app 还得行,下一个就疯狂报错了,所以代码是基本完成了,但是 android inline hook 报错未解决,有时间我会修改) 

    be2ca29710b3c377f092da0b788f4555.png

    3、遇到的问题

    报错未定义函数,如下所示: 

    e223283a50b78c52ad05e2530b65ef9f.png

    解决方案:在 CmakeLists.txt 文件中将 jni 文件夹下面所有引用到的文件都包含进去,如下所示: 

    f92f38744c54dc8c8f3c01d061f35fc5.png

    后记及其相关链接

    我个人习惯了通过写加固来学习脱壳,可能时间比直接分析壳来得慢,但是这其中体验真的酸爽到爆炸,因为个人原因,最后的类指令抽取壳最后一点没弄完,算是一个小遗憾吧,20 年应该没时间来弥补这个遗憾了,希望 21 年我有时间来把这个遗憾补上吧!!! 

    源码 github 链接:

    https://github.com/windy-purple/androidshell

    参考链接: 

    Android 免 Root 权限通过 Hook 系统函数修改程序运行时内存指令逻辑:

    http://www.520monkey.com/archives/1115

    Android 逆向之旅—运行时修改内存中的 Dalvik. 指令来改变代码逻辑:

    http://www.520monkey.com/archives/815

    Android 中免 root 的 hook 框架 Legend 原理解析:

    https://www.jianshu.com/p/c5580215ee26

    https://github.com/asLody/legend

    https://github.com/ele7enxxh/Android-Inline-Hook

    Android APK 加固-完善内存 dex:

    https://www.cnblogs.com/ltyandy/p/11644056.html

    利用动态加载技术加固APK原理解析:

    https://www.jianshu.com/p/ce20fa304e1e

    Android 插件化框架之动态加载 Activity(一):

    https://www.jianshu.com/p/1035ffd9e9cf

    Android APK 加固之动态加载dex(一):

    https://blog.csdn.net/weixin_44045581/article/details/89811868

    Android 中实现「类方法指令抽取方式」加固方案原理解析:

    http://www.520monkey.com/archives/1118

    Android 中 apk 加固完善篇之内存加载 dex 方案实现原理(不落地方式加载):

    http://www.520monkey.com/archives/629

    5c97203b596d040427f8a0507d934927.png

    展开全文
  • 安卓的加固方案是从 19 年底开始写的,到现在为止差不多快一年了,写这个目的还是学习怎么脱壳,前几个月再看雪看到有人直接分析壳来学习,不过我感觉从加壳写起也是一种浪漫。因为个人原因,在类指令抽取壳那里为半...
  • public class HtmlMainActivity extends BaseActivity implements IBaseView { @BindView(R2.id.wv_in_main) WebView wvInMain; @BindView(R2.id.ll_html_main) LinearLayout mLinearLayout; ... ...
  • 安卓的加固方案是从 19 年底开始写的,到现在为止差不多快一年了,写这个目的还是学习怎么脱壳,前几个月再看雪看到有人直接分析壳来学习,不过我感觉从加壳写起也是一种浪漫。因为个人原因,在类指令抽取壳那里为半...
  • 记录下踩过的坑提醒下自己 我用到的工具: jadx DexExtractor 做好的镜像 adt-bundle(eclipse) apktool baksmali.jar 和 smali.jar 1. 观察特征 先拿 jadx 看了下,没有activity类,这里可以注意到 ...
  • #0x00 前言 安卓应用加固技术是伴随安卓...市面上成熟的加固厂商一般会使用加壳保护技术配合反反汇编技术对安卓应用进行加固。 安卓反反汇编技术的总结在我以下博客中将进行详细探讨(未写完),链接: 反反汇编: ...
  • 在强力大佬的教导下,使用了另一种解法脱壳 一个脱简单壳的Xposed模块 我用到的工具: ApkShelling模块 Xposed android 8.0以下的模拟器或某能刷的实机(不做介绍) Android Studio ...先说说这个模拟器,自己用AVD ...
  • 网易云加密--Android安卓移动应用程序加密加壳保护方案防破解防逆向分析防游戏外挂 一、服务简介 网易云加密为网易公司旗下产品,致力于为移动应用程序提供专业保护方案,让加固变得更简单,一键搞定...
  • 目前针对移动应用市场上安卓APP被破解、反编译、盗版丛生的现象,很多APP开发人员已经意识到保护APP的重要性。而对于移动应用APP加密保护的问题,如何对DEX文件加密尤为重要。那么接下来,我们就先介绍一下什么是App...

空空如也

空空如也

1 2 3 4 5
收藏数 98
精华内容 39
关键字:

安卓加壳