Android对抗反编译

简介: 本文介绍了通过反编译谷歌APK进行学习与防护的实践。作者利用工具Apktool反编译APK,并使用signapk进行二次签名,掌握smali文件格式以增强对APK结构的理解。文章详细说明了如何通过代码检查APP名称、包名和图标的一致性,防止篡改;同时探讨了核心数据加密、伪装及classes.dex文件CRC值验证等方法,提升反编译难度。附带的工具类代码提供了获取应用名称、版本号、包名及图标等功能的具体实现。适合对安卓安全与反编译感兴趣的开发者参考。

由于博主最近升学成功,早早的离职,所以有大把的时间弄一些好玩的东西------->反编译谷歌上的APK

对我个人而言反编译一个APK可能会有的操作:
1.修改APP名称,包名,图片
2.想模仿实现某个功能
3.得到数据库

网上有很多代码混淆,加固,第三方打包的操作教程
所以博主就写一篇对自己操作的进行对抗的文章

用到的反编译工具是:Apktool,二次签名的工具是:signapk
并掌握smali的文件格式
以下为使用Apktool反编译出一些的文件
1.png

下面开始进入正题(工具类在文章最后)

1.在APP中对名称,包名,图片进行检查

名称--思路:获取App的名称,检查APP名称是否与自己的名称一样,如果不一样,设置点用户不友好操作(崩溃啥的)。

 /*
     * 获取当前应用的名称
     */
    public static String getAppName(Context context) {
   
        //获取 PackageManager
        PackageManager pm = context.getPackageManager();
        try {
   
            //通过PackageManager这个Api可以拿到应用的一些信息
            //packgeName:包名   flag:获取额外信息的标识
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            int labelRes = packageInfo.applicationInfo.labelRes;
            return context.getResources().getString(labelRes);

        } catch (PackageManager.NameNotFoundException e) {
   
            e.printStackTrace();
        }
        return null;
    }

包名--思路:获取App的包名,检查APP包名是否与自己的包名一样,如果不一样,设置点用户不友好操作(崩溃啥的)。

 /*
     * 获取当前应用的包名
     */
    public static String getPackageName(Context context) {
   
        PackageManager pm = context.getPackageManager();
        try {
   
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            //拿到版本名称
            return packageInfo.packageName;
        } catch (PackageManager.NameNotFoundException e) {
   
            e.printStackTrace();
        }
        return null;
    }

APP图标--同上,先获取APP的图标,然后对APP的图片进行验证。
博主的做法是:对图片获取五个点的rgb值,输出一个关于RGB的值(误差在0.1-3之间),然后进行值的大小范围判断。

/**
     * 获取图标 bitmap
     */
    public static Bitmap getAppImageBitmap(Context context) {
   
        PackageManager packageManager = null;
        ApplicationInfo applicationInfo = null;
        try {
   
            packageManager = context.getApplicationContext()
                    .getPackageManager();
            applicationInfo = packageManager.getApplicationInfo(
                    context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
   
            applicationInfo = null;
        }
        Drawable d = packageManager.getApplicationIcon(applicationInfo);
        if (d == null) {
   
            return null;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && d instanceof AdaptiveIconDrawable) {
   
            Bitmap bitmap = Bitmap.createBitmap(d.getMinimumWidth(), d.getMinimumHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            d.draw(canvas);
            return bitmap;
        } else {
   
            return ((BitmapDrawable) d).getBitmap();
        }


    }
    //输出一个关于此bitmap的值
    public static float getBitmapColorScale(Bitmap bitmap){
   

        Bitmap src =bitmap;
        int R, G, B;
        float Rmax=0,Gmax=0,Bmax=0;
        float bitmapScale=0.f;
        int pixelColor;
        int height = src.getHeight()/4;
        int width = src.getWidth()/4;
        int heightscale[]={
   1,1,2,3,3};
        int widthscale[]={
   1,3,2,1,3};
        for (int i = 0; i <5 ; i++) {
   
            pixelColor = src.getPixel(width*widthscale[i],height*heightscale[i] );
            R = Color.red(pixelColor);
            G = Color.green(pixelColor);
            B = Color.blue(pixelColor);
            Rmax+=R;
            Gmax+=G;
            Bmax+=B;
        }

        bitmapScale=(Rmax+Gmax+Bmax)/5;
        return bitmapScale;
    }

2..想模仿实现某个功能,数据库

思路:对一些核心的数据进行伪装或者加密(秘钥,将一个数据以各种不同的方式存储)

最后:对classes.dex文件进行CRC值的验证(从服务器或者数据库获取CRC值与之进行对比)

//CRC是一种根据网络数据包或电脑文件等数据产生简短固定位数校验码的一种散列函数
    public  void apkIntegralityForCRC(Context context, String orginalCRC) {
   
        // 获取Apk包的存储路径
        String apkPath = context.getPackageCodePath();
        try {
   
            ZipFile zipFile = new ZipFile(apkPath);
            // 读取ZIP包中的classes.dex文件
            ZipEntry dexEntry = zipFile.getEntry("classes.dex");
            // 得到classes.dex文件的CRC值
            String dexCRC = String.valueOf(dexEntry.getCrc());
            // 将此次得到的CRC值与数据库/服务器数据的CRC值进行比较校验
            if (!dexCRC.equals(orginalCRC)) {
    
               Toast.makeText(context,"APP已经被修改",Toast.LENGTH_SHORT).show();
            }
        } catch (IOException e) {
   
            e.printStackTrace();
        }
    }

以上所有操作为增大反编译的难度。

工具类如下:


/*用途
 * 1.获取当前应用的名称:getAppName
 * 2.获取当前应用的版本号:getVersionCode
 * 3.获取当前应用的版本名称:getVersionName
 */
public class PackageUtils {
   
    public PackageUtils() {
   
    }

    /*
     * 获取当前应用的名称
     */
    public static String getAppName(Context context) {
   
        //获取 PackageManager
        PackageManager pm = context.getPackageManager();
        try {
   
            //通过PackageManager这个Api可以拿到应用的一些信息
            //packgeName:包名   flag:获取额外信息的标识
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            int labelRes = packageInfo.applicationInfo.labelRes;
            return context.getResources().getString(labelRes);

        } catch (PackageManager.NameNotFoundException e) {
   
            e.printStackTrace();
        }
        return null;
    }

    /*
     * 获取当前应用的版本号
     */
    public static int getVersionCode(Context context) {
   
        //获取 PackageManager
        PackageManager pm = context.getPackageManager();
        //通过PackageManager这个Api可以拿到应用的一些信息
        //packgeName:包名   flag:获取额外信息的标识
        try {
   
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            //拿到版本号
            return packageInfo.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
   
            e.printStackTrace();
        }
        return -1;
    }

    /*
     * 获取当前应用的版本名称
     */
    public static String getVersionName(Context context) {
   
        PackageManager pm = context.getPackageManager();
        try {
   
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            //拿到版本名称
            return packageInfo.versionName;
        } catch (PackageManager.NameNotFoundException e) {
   
            e.printStackTrace();
        }
        return null;
    }

    /*
     * 获取当前应用的包名
     */
    public static String getPackageName(Context context) {
   
        PackageManager pm = context.getPackageManager();
        try {
   
            PackageInfo packageInfo = pm.getPackageInfo(context.getPackageName(), 0);
            //拿到版本名称
            return packageInfo.packageName;
        } catch (PackageManager.NameNotFoundException e) {
   
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 获取图标 bitmap
     */
    public static Bitmap getAppImageBitmap(Context context) {
   
        PackageManager packageManager = null;
        ApplicationInfo applicationInfo = null;
        try {
   
            packageManager = context.getApplicationContext()
                    .getPackageManager();
            applicationInfo = packageManager.getApplicationInfo(
                    context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
   
            applicationInfo = null;
        }
        Drawable d = packageManager.getApplicationIcon(applicationInfo);
        if (d == null) {
   
            return null;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && d instanceof AdaptiveIconDrawable) {
   
            Bitmap bitmap = Bitmap.createBitmap(d.getMinimumWidth(), d.getMinimumHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            d.draw(canvas);
            return bitmap;
        } else {
   
            return ((BitmapDrawable) d).getBitmap();
        }


    }
     //输出一个关于此bitmap的值
    public static float getBitmapColorScale(Bitmap bitmap){
   

        Bitmap src =bitmap;
        int R, G, B;
        float Rmax=0,Gmax=0,Bmax=0;
        float bitmapScale=0.f;
        int pixelColor;
        int height = src.getHeight()/4;
        int width = src.getWidth()/4;
        int heightscale[]={
   1,1,2,3,3};
        int widthscale[]={
   1,3,2,1,3};
        for (int i = 0; i <5 ; i++) {
   
            pixelColor = src.getPixel(width*widthscale[i],height*heightscale[i] );
            R = Color.red(pixelColor);
            G = Color.green(pixelColor);
            B = Color.blue(pixelColor);
            Rmax+=R;
            Gmax+=G;
            Bmax+=B;
        }

        bitmapScale=(Rmax+Gmax+Bmax)/5;
        return bitmapScale;
    }
}
相关文章
|
安全 Java Linux
Android反编译——jadx工具
Android反编译——jadx工具
1159 1
|
Java Android开发
Android反编译查看源码
Android反编译查看源码
216 0
|
Java Android开发 C++
2023安卓逆向 -- JNI学习(从开发到反编译)
2023安卓逆向 -- JNI学习(从开发到反编译)
153 0
|
数据可视化 Java Android开发
Android 反编译资料整理
Android 反编译资料整理
126 0
|
Java Android开发
Android 反编译工具的使用
Android 反编译工具的使用
159 0
|
Java Android开发 C++
2023安卓逆向 -- JNI学习(从开发到反编译)
2023安卓逆向 -- JNI学习(从开发到反编译)
227 0
|
安全 Java Android开发
Android App开发之安全加固中反编译、代码混淆、第三方加固以及重签名的讲解及实战(图文解释 简单易懂)
Android App开发之安全加固中反编译、代码混淆、第三方加固以及重签名的讲解及实战(图文解释 简单易懂)
840 0
|
Java Android开发
安卓apk包反编译
拿到安卓的apk包如何,如何反编译呢。流程如下
664 0
安卓apk包反编译
|
XML Java Android开发
Android 反编译工具
Android 反编译工具
192 0
|
Java 开发工具 Android开发
Android反编译apk
总的来说就是先将apk文件解压,得到.dex文件,然后将.dex文件转为.jar文件,最后将.jar转为.java文件(就是将.jar文件中的.class文件转为.java文件)
619 0
Android反编译apk

热门文章

最新文章