android加固_android加固后怎么反编译 - CSDN
精华内容
参与话题
  • 现在主要工具是接触SDK,为了防止游戏包被破解编译,以及发现加密串,...5.第三方平台加密以及检测漏洞这个在 Android 安全之如何反编译与加密apk包 这篇文章中也提及到了相关的知识点。 第一种: 代码混淆技术(ProGu

    现在主要工具是接触SDK,为了防止游戏包被破解编译,以及发现加密串,我来分享下以下几点:
    防破解技术主要有四种实现方式:
    1.代码混淆(ProGuard)技术
    2.签名比对技术
    3.NDK .so 动态库技术
    4.动态加载技术
    5.第三方平台加密以及检测漏洞

    这个在 Android 安全之如何反编译与加密apk包 这篇文章中也提及到了相关的知识点。

    • 第一种: 代码混淆技术(ProGuard) 该技术主要是进行代码混淆,降低代码逆向编译后的可读性,但该技术无法防止加壳技术进行加壳(加入吸费、广告、病毒等代码),而且只要是细心的人,依然可以对代码依然可以对代码进行逆向分析,所以该技术并没有从根本解决破解问题,只是增加了破解难度。
    • 第二种: 签名比对技术 该技术主要防止加壳技术进行加壳,但代码逆向分析风险依然存在。而且该技术并不能根本解决被加壳问题,如果破解者将签名比对代码注释掉,再编译回来,该技术就被破解了。
    • 第三种: NDK .so动态库技术,该技术实现是将重要核心代码全部放在C文件中,利用NDK技术,将核心代码编译成.so动态库,再用JNI进行调用。该技术虽然能将核心代码保护起来,但被加壳风险依然存在。
    • 第四种: 动态加载技术,该技术在Java中是一个比较成熟的技术,而Android中该技术还没有被大家充分利用起来。
    • 第五种: 第三方平台使用

      主要讲解第四种方法,该技术可以有效的防止逆向分析、被破解、被加壳等问题,动态加载技术分为以下几步:

    • 将核心代码编译成dex文件的Jar包

    • 对jar包进行加密处理
    • 在程序主入口利用NDK进行解密
    • 再利用ClassLoader将jar包进行动态加载
    • 利用反射技术将ClassLoader 设置成系统的ClassLoader。

    主要优点有:
           1.核心代码在被加密的jar中,所以破解者无法解压出class文件,如果加密秘钥被破解者拿到,那将是另外一层面的安全问题了。
          2.该技术也可以有效防止加壳技术,代码是动态加载上来的,破解者的壳程序无法加入到已加密的jar包中,及时破解者注入壳程序入口,壳程序因为不在ClassLoader 的jar包中,所以也无法被执行起来,除非破解者替换ClassLoader的jar包,关掉NDK解密代码.但这种安装到手机上,已经不在是我们的应用,用户一定会将其卸载掉。

    所以综合起来比较,第四种动态加载技术是最安全的,但效率问题,本人并没做严格测试,粗略实验了一下,效率并没有明显降低。

    //   1.Jar包加密加密解密文件//  
    public static boolean enOrDecryptFile(byte[] paramArrayOfByte,  
            String sourceFilePath, String destFilePath,int mode){  
        File sourceFile = new File(sourceFilePath);  
        File destFile = new File(destFilePath);  
        CipherOutputStream cout = null;  
        FileInputStream in  = null;  
        FileOutputStream out = null;  
        if (sourceFile.exists() && sourceFile.isFile()) {  
            if (!destFile.getParentFile().exists()) {  
                destFile.getParentFile().mkdirs();  
            }  
            try {  
                destFile.createNewFile();  
                in = new FileInputStream(sourceFile);  
                out = new FileOutputStream(destFile);  
                // 获取密钥//  
                init();  
                SecretKeySpec secretKeySpec = new SecretKeySpec(defPassword, "AES");  
                Cipher cipher;  
                cipher = Cipher.getInstance("AES");  
                cipher.init(mode, secretKeySpec);  
                cout = new CipherOutputStream(out, cipher);  
                byte[] cache = new byte[CACHE_SIZE];  
                int nRead = 0;  
                while ((nRead = in.read(cache)) != -1) {  
                    cout.write(cache, 0, nRead);  
                    cout.flush();  
                }  
            }catch (IOException e) {  
                e.printStackTrace();  
                return false;  
            } catch (NoSuchAlgorithmException e) {  
                e.printStackTrace();  
                return false ;  
            } catch (NoSuchPaddingException e) {  
                e.printStackTrace();  
                return false ;  
            }catch (InvalidKeyException e) {  
                e.printStackTrace();  
                return false;  
            }finally{  
                    if(cout != null){  
                        try {  
                            cout.close();  
                        } catch (IOException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    if(out != null){  
                        try {  
                            out.close();  
                        } catch (IOException e) {  
                            e.printStackTrace();  
                        }  
                    }  
                    if(in != null){  
                        try {  
                            in.close();  
                        } catch (IOException e) {  
                            e.printStackTrace();  
                        }  
                    }  
            }  
            return true;  
        }  
        return false;  
    }  

    jar用SDK\platform-tools\下的dx命令进行dex格式转化

    dx   --dex    --output=生成的目标文件的地址(绝对路径)     需要转化的jar文件(绝对路径)
                           例如:dx --dex --output=H:\classdex.jar     H:\dujinyang-KARL.jar

    然后再用加密工具将生成jar文件进行加密处理

    最后通过代码动态加载:

    File file = new File("/data/data/" + base.getPackageName() + "/.cache/");  
            if (!file.exists()) {  
                file.mkdirs();  
            }  
            try {  
                Runtime.getRuntime().exec("chmod 755 " + file.getAbsolutePath()).waitFor();  
            } catch (InterruptedException e1) {  
                // TODO Auto-generated catch block  
                e1.printStackTrace();  
            } catch (IOException e1) {  
                // TODO Auto-generated catch block  
                e1.printStackTrace();  
            }  
            Util.copyJarFile(this);  
            Object currentActivityThread = RefInvoke.invokeStaticMethod(  
                    "android.app.ActivityThread", "currentActivityThread",  
                    new Class[] {}, new Object[] {});  
            String packageName = getPackageName();  
            HashMap mPackages = (HashMap) RefInvoke.getFieldOjbect(  
                    "android.app.ActivityThread", currentActivityThread,  
                    "mPackages");  
            WeakReference wr = (WeakReference) mPackages.get(packageName);  
            MyClassLoader dLoader = new MyClassLoader("/data/data/"  
                    + base.getPackageName() + "/.cache/classdex.jar", "/data/data/"  
                    + base.getPackageName() + "/.cache", "/data/data/"  
                    + base.getPackageName() + "/.cache/", base.getClassLoader());  
            try {  
                Class<?>  class1 = dLoader.loadClass("com.example.test.TestActivity");  
                Log.i("b364","----------->class1: "+class1);  
            } catch (ClassNotFoundException e){  
                Log.i("b364","----------->class not found Exception!");  
                e.printStackTrace();  
            }  
            Log.i("b364","------>PackageInfo: "+wr.get());  
            // DexClassLoader dLoader = new DexClassLoader(apkFileName, odexPath,  
            // libPath, (ClassLoader) RefInvoke.getFieldOjbect(  
            // "android.app.LoadedApk", wr.get(), "mClassLoader"));  
            RefInvoke.setFieldOjbect("android.app.LoadedApk", "mClassLoader",  
                    wr.get(), dLoader);  

    处理完成,如果在Application中做特别处理也是可行的。之前就有人分析了爱加密的加密方式,不过这里不做阐述,有兴趣可以一起讨论。

    下篇文章中我们来讲讲如何 逆向apk的动态库

    展开全文
  • Android中Apk加固代码实现

    千次阅读 2019-06-14 09:30:55
    前言:上一篇博客已经把Apk加固的思路详细的介绍过了,也开始创建了一个空的demo进行,然后在项目中添加一个代理module(解密,和系统源码交互功能)和tools工具加密Java library 的module ,这里开始接着把整个过程...

    前言:上一篇博客已经把Apk加固的思路详细的介绍过了,也开始创建了一个空的demo进行,然后在项目中添加一个代理module(解密,和系统源码交互功能)和tools工具加密Java library 的module ,这里开始接着把整个过程用代码操作一遍,希望对大家有所帮助。

    代码用到的工具类请移步:https://download.csdn.net/download/i123456789t/11239056 

    1、代码中需要用到几个类,AES加解密类,Zip压缩解压类等工具类

    首先我先proxy_core代理module下写一个代理application ,然后继承至Application,代码目录结构请看:

    接着把我们这个代理的application加到我们最常写的配置文件中AndroidManifest.xml 中,我们是不是每个App都有一个application,然后把它配置到AndroidManifest.xml中,这里唯一不同的是,不是把我们项目中的那个application写到AndroidManifest.xml中,而是把我们在代理的写上。然后把我们app自己用到的application也加上,自己的application写在meta-data中,另一个meta-data按照下面的写就行,写法和位置如下

    这个是我们自己项目用到的初始化application,上面的代理只是处理代理操作的。

    我们自己的MyApplication里面目前啥也没写,这个使我们项目中用于初始化的,这里先不写东西。

    这里开始写代理了,在ProxyApplication 中:

    package com.example.proxy_core;
    
    import android.app.Application;
    import android.content.Context;
    import android.content.pm.ApplicationInfo;
    import android.content.pm.PackageManager;
    import android.os.Bundle;
    import android.text.TextUtils;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.lang.reflect.Array;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    
    public class ProxyApplication extends Application {
    
        //定义好的加密后的文件的存放路径
        private String app_name;
        private String app_version;
    
        /**
         * ActivityThread创建Application之后调用的第一个方法
         * 可以在这个方法中进行解密,同时把dex交给Android去加载
         * @param base
         */
        @Override
        protected void attachBaseContext(Context base) {
            super.attachBaseContext(base);
            //获取用户填入的metaData
            getMetaData();
    
            //得到当前apk文件
            File apkFile = new File(getApplicationInfo().sourceDir);
    
            //把apk解压  这个目录中的内容需要root权限才能使用
            File versionDir = getDir(app_name+"_" + app_version,MODE_PRIVATE);
    
            File appDir = new File(versionDir,"app");
            File dexDir = new File(appDir,"dexDir");
    
            //得到我们需要加载的dex文件
            List<File> dexFiles = new ArrayList<>();
            //进行解密 (最好做md5文件校验)
            if (!dexDir.exists() || dexDir.list().length == 0){
                //把apk解压到appDir
                Zip.unZip(apkFile,appDir);
                //获取目录下所有的文件
                File[] files = appDir.listFiles();
                for (File file:files){
                    String name = file.getName();
                    if (name.endsWith(".dex") && !TextUtils.equals(name,"classes.dex")){
                        try{
                            AES.init(AES.DEFAULT_PWD);
                            //读取文件内容
                            byte[] bytes = Utils.getBytes(file);
                            //解密
                            byte[] decypt = AES.decrypt(bytes);
                            //写到指定的目录
                            FileOutputStream fos = new FileOutputStream(file);
                            fos.write(decypt);
                            fos.flush();
                            fos.close();
    
                            dexFiles.add(file);
    
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }else {
                for (File file:dexDir.listFiles()){
                    dexFiles.add(file);
                }
            }
    
            try {
                loadDex(dexFiles,versionDir);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        private void loadDex(List<File> dexFiles,File versionDir) throws Exception{
            //1、获取pathList
            Field pathListField = Utils.findField(getClassLoader(), "pathList");
            Object pathList = pathListField.get(getClassLoader());
            //2、获取数组dexElements
            Field dexElementsField = Utils.findField(pathList,"dexElements");
            Object[] dexElements = (Object[]) dexElementsField.get(pathList);
            //3、反射到初始化makePathElements的方法
            Method makeDexElements = Utils.findMethod(pathList,"makePathElements",List.class,File.class,List.class);
    
            ArrayList<IOException> suppressedException = new ArrayList<>();
            Object[] addElements = (Object[]) makeDexElements.invoke(pathList, dexFiles, versionDir, suppressedException);
    
            Object[] newElements = (Object[]) Array.newInstance(dexElements.getClass().getComponentType(), dexElements.length + addElements.length);
            System.arraycopy(dexElements,0,newElements,0,dexElements.length);
            System.arraycopy(addElements,0,newElements,dexElements.length,addElements.length);
    
            //替换classloader中的element数组
            dexElementsField.set(pathList,newElements);
        }
    
    
        private void getMetaData(){
            try {
                ApplicationInfo applicationInfo = getPackageManager().getApplicationInfo(
                        getPackageName(), PackageManager.GET_META_DATA);
                Bundle metaData = applicationInfo.metaData;
                if (null != metaData){
                    if (metaData.containsKey("app_name")){
                        app_name = metaData.getString("app_name");
                    }
                    if (metaData.containsKey("app_version")){
                        app_version = metaData.getString("app_version");
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        /**
         * 开始替换application
         */
        @Override
        public void onCreate() {
            super.onCreate();
            try {
                bindRealApplication();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
        /**
         * 让代码走入if的第三段中
         * @return
         */
        @Override
        public String getPackageName() {
            if (!TextUtils.isEmpty(app_name)){
                return "";
            }
            return super.getPackageName();
        }
    
        @Override
        public Context createPackageContext(String packageName, int flags) throws PackageManager.NameNotFoundException {
            if (TextUtils.isEmpty(app_name)){
                return super.createPackageContext(packageName, flags);
            }
            try {
                bindRealApplication();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return delegate;
    
        }
    
        boolean isBindReal;
        Application delegate;
        //下面主要是通过反射系统源码的内容,然后进行处理,把我们的内容加进去处理
        private void bindRealApplication() throws Exception{
            if (isBindReal){
                return;
            }
            if (TextUtils.isEmpty(app_name)){
                return;
            }
            //得到attchBaseContext(context) 传入的上下文 ContextImpl
            Context baseContext = getBaseContext();
            //创建用户真实的application  (MyApplication)
            Class<?> delegateClass = null;
            delegateClass = Class.forName(app_name);
    
            delegate = (Application) delegateClass.newInstance();
    
            //得到attch()方法
            Method attach = Application.class.getDeclaredMethod("attach",Context.class);
            attach.setAccessible(true);
            attach.invoke(delegate,baseContext);
    
            //获取ContextImpl ----> ,mOuterContext(app);  通过Application的attachBaseContext回调参数获取
            Class<?> contextImplClass = Class.forName("android.app.ContextImpl");
            //获取mOuterContext属性
            Field mOuterContextField = contextImplClass.getDeclaredField("mOuterContext");
            mOuterContextField.setAccessible(true);
            mOuterContextField.set(baseContext,delegate);
    
            //ActivityThread  ----> mAllApplication(ArrayList)  ContextImpl的mMainThread属性
            Field mMainThreadField = contextImplClass.getDeclaredField("mMainThread");
            mMainThreadField.setAccessible(true);
            Object mMainThread = mMainThreadField.get(baseContext);
    
            //ActivityThread  ----->  mInitialApplication       ContextImpl的mMainThread属性
            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
            Field mInitialApplicationField = activityThreadClass.getDeclaredField("mInitialApplication");
            mInitialApplicationField.setAccessible(true);
            mInitialApplicationField.set(mMainThread,delegate);
    
            //ActivityThread ------>  mAllApplications(ArrayList)   ContextImpl的mMainThread属性
            Field mAllApplicationsField = activityThreadClass.getDeclaredField("mAllApplications");
            mAllApplicationsField.setAccessible(true);
            ArrayList<Application> mApplications = (ArrayList<Application>) mAllApplicationsField.get(mMainThread);
            mApplications.remove(this);
            mApplications.add(delegate);
    
            //LoadedApk ----->  mApplicaion             ContextImpl的mPackageInfo属性
            Field mPackageInfoField = contextImplClass.getDeclaredField("mPackageInfo");
            mPackageInfoField.setAccessible(true);
            Object mPackageInfo = mPackageInfoField.get(baseContext);
    
    
            Class<?> loadedApkClass = Class.forName("android.app.LoadedApk");
            Field mApplicationField = loadedApkClass.getDeclaredField("mApplication");
            mApplicationField.setAccessible(true);
            mApplicationField.set(mPackageInfo,delegate);
    
            //修改ApplicationInfo  className  LoadedApk
            Field mApplicationInfoField = loadedApkClass.getDeclaredField("mApplicationInfo");
            mApplicationInfoField.setAccessible(true);
            ApplicationInfo mApplicationInfo = (ApplicationInfo) mApplicationInfoField.get(mPackageInfo);
            mApplicationInfo.className = app_name;
    
    
            delegate.onCreate();
            isBindReal = true;
        }
    }
    

     2、下面在proxy_tools中写一个Main类,和一个main方法,直接运行处理,代码如下:

    package com.example.proxy_tools;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.FilenameFilter;
    
    public class Main {
    
        public static void main(String[] args) throws Exception{
    
            /**
             * 1、制作只包含解密代码的dex文件
             */
            File aarFile = new File("proxy_core/build/outputs/aar/proxy_core-debug.aar");
            File aarTemp = new File("proxy_tools/temp");
            Zip.unZip(aarFile,aarTemp);
    
            File classesDex = new File(aarTemp,"classes.dex");
            File classesJar = new File(aarTemp,"classes.jar");
            //dx --dex --output out.dex in.jar     E:\AndroidSdk\Sdk\build-tools\23.0.3
            Process process = Runtime.getRuntime().exec("cmd /c dx --dex --output " + classesDex.getAbsolutePath()
             + " " + classesJar.getAbsolutePath());
            process.waitFor();
            if (process.exitValue() != 0){
                throw new RuntimeException("dex error");
            }
    
            /**
             * 2、加密apk中所有的dex文件
             */
            File apkFile = new File("app/build/outputs/apk/debug/app-debug.apk");
            File apkTemp = new File("app/build/outputs/apk/debug/temp");
            Zip.unZip(apkFile,apkTemp);
            //只要dex文件拿出来加密
            File[] dexFiles = apkTemp.listFiles(new FilenameFilter() {
                @Override
                public boolean accept(File file, String s) {
                    return s.endsWith(".dex");
                }
            });
            //AES加密
            AES.init(AES.DEFAULT_PWD);
            for (File dexFile:dexFiles) {
                byte[] bytes = Utils.getBytes(dexFile);
                byte[] encrypt = AES.encrypt(bytes);
                FileOutputStream fos = new FileOutputStream(new File(apkTemp,"secret-" + dexFile.getName()));
                fos.write(encrypt);
                fos.flush();
                fos.close();
                dexFile.delete();
            }
            /**
             * 3、把dex放入apk解压目录,重新压成apk文件
             */
            classesDex.renameTo(new File(apkTemp,"classes.dex"));
            File unSignedApk = new File("app/build/outputs/apk/debug/app-unsigned.apk");
            Zip.zip(apkTemp,unSignedApk);
            /**
             * 4、对其和签名,最后生成签名apk
             */
            //        zipalign -v -p 4 my-app-unsigned.apk my-app-unsigned-aligned.apk
            File alignedApk=new File("app/build/outputs/apk/debug/app-unsigned-aligned.apk");
            process= Runtime.getRuntime().exec("cmd /c zipalign -v -p 4 "+unSignedApk.getAbsolutePath()
                    +" "+alignedApk.getAbsolutePath());
    //        System.out.println("signedApkprocess : 11111" + "  :----->  " +unSignedApk.getAbsolutePath() + "\n" +  alignedApk.getAbsolutePath());
            process.waitFor();
    //        if(process.exitValue()!=0){
    //            throw new RuntimeException("dex error");
    //        }
    
    //        apksigner sign --ks my-release-key.jks --out my-app-release.apk my-app-unsigned-aligned.apk
    //        apksigner sign  --ks jks文件地址 --ks-key-alias 别名 --ks-pass pass:jsk密码 --key-pass pass:别名密码 --out  out.apk in.apk
            File signedApk=new File("app/build/outputs/apk/debug/app-signed-aligned.apk");
            File jks=new File("proxy_tools/proxy1.jks");
            process= Runtime.getRuntime().exec("cmd /c apksigner sign --ks "+jks.getAbsolutePath()
                    +" --ks-key-alias wwy --ks-pass pass:123456 --key-pass pass:123456 --out "
                    +signedApk.getAbsolutePath()+" "+alignedApk.getAbsolutePath());
            process.waitFor();
            if(process.exitValue()!=0){
                throw new RuntimeException("dex error");
            }
            System.out.println("执行成功");
        }
    
    }
    

     我们在写好前面的之后,直接运行这个main方法,就可以在我们的app -> build->outputs->apk->debug下面看到生成的几个apk,分别为 app-debug.apk,  app-unsigned.apk,  app-unsigned-aligned.apk,  app-signed-aligned.apk,最终 app-signed-aligned.apk 才是我们最后安装使用的apk,

     

    注意:如果大家直接按照上面的弄完后,运行main 方法,恐怕会出现不可描述的问题,各种错误,异常,哈哈哈,,正常,,因为我也是这么过来的,所以这里在说一下一些要做的工作:

    1)、配置电脑的环境变量:

    找到你电脑中sdk的路劲,然后在SDK中把build-tools下面的任意一个版本配置到你的电脑的用户变量中,我这里路劲是:F:\androidSDK\Sdk\build-tools\25.0.0  然后我就把这个路劲配置到用户变量中,(注意:在配置这个变量之后,你的AS一定要重新启动哦,否则依然报错,如果重启as不行,那就直接重启电脑再试试,我也遇到过),这个步骤是准备main中第一个Process命令使用的。

    第一步会生成两个文件,一个是classes.jar 和  classes.dex。

    下面一共有三个Process  命令操作,但是如果我们直接运行main方法时就算上面的环境配置好了,也未必能直接运行成功,为什么呢?因为我具体也不是很清楚,但是不少人都遇到了,什么问题呢?就是当运行到第二个Process 命令的时候,代码运行到process.waitFor();时,就不往下走了,经过咨询别人讲是由于创建的进程导致的,说什么内存缓存区不足,导致进程一直在等待,我不晓得原因,我的代码运行到下图位置就不动了,

     不过已经生成了除了签名之后的apk ,其它的都有了,我百思不得其解,最后我在AS中Terminal 中直接通过命令执行最后一个生成签名的apk 才算把签名之后的apk搞出来,很多人也遇到和我一样的问题。你如果也是这样,那也通过命令操作吧。

    2)、记住在执行main方法之前,我们可以看到main方法第四部生成签名的apk,说明我们apk是需要签名的,所以,我们要先签名哦,然后记住别名和密码哦,然后把别名和密码写在第四部中,下面给大家看看我的代码目录结构:

    上面就是整个的目录结构,运行完,出来在上面找到签名之后的apk,然后直接拿过去运行能运行出来就可以了!在AS中点击签名之后的apk,会发现这个apk是看不到里面任何的文件的,也就实现了我们的加固功能,别人拿到我们的apk也白费,啥玩意都没有,是不是很牛?哈哈哈哈,,,路漫漫其修远兮? 还有很多的路要走。继续努力!

    这里带多一句嘴,上面的代理ProxyApplication被我们配置到Mainfest的application 标签中,这个位置经常是我们配置项目使用的application的,其实不用担心,代码中已经处理过了,当代理application处理完之后,会自动把我们配置的app里面的项目用到的MyApplication 类替换过来,所以项目在第一次运行完之后,正式运行还是以我们自己的MyApplication为主,大可放心。

     

    完整的demo下载地址:https://download.csdn.net/download/i123456789t/11239611  

    展开全文
  • Android 加固应用

    2019-08-22 10:32:46
    1.混淆:Proguard.配置proguard-rules.pro文件,在app的gradle文件中把minifyEnable设置为true开启混淆。(Proguard-rules.pro:配置proguard。通过-keep保留四大组建,application资源,native方法,枚举里,自定义...

    1.混淆:Proguard.配置proguard-rules.pro文件,在app的gradle文件中把minifyEnable设置为true开启混淆。(Proguard-rules.pro:配置proguard。通过-keep保留四大组建,application资源,native方法,枚举里,自定义控件,parcelable序列化类,serializeable序列化类,有回调函数的类,实体类,webview交互类,h5和交js互类,含反射的类

    2.反调试:如果一个进程被调试,这个进程的status文件的TracePid会记录调试者的ID,我们可以轮询这个文件的TracePid,发现这个id大于0就退出程序

    3.加壳:

    3.1加密源程序为解壳数据

    3.2计算解壳数据长度并添加该长度到解壳dex文件头末尾,接续解壳数据到文件头末尾

    3.3修改解壳程序dex文件头中的checksum,signature等参数,分析数据偏移量,修改偏移量,修改并覆盖清单文件

    3.4解壳:从插入数据的位置读取解壳数据的长度,从dex文件读取解壳数据,解密解壳数据,以文件形式保存解密数据到apk文件,通过dexclassloader动态加载apk文件

    4.运行时修改dalvik指令:定位到需要修改的ondex文件的mao地址,通过odex的长度确定dex文件的偏移量和偏移位置,找到了偏移量就可以解析dex文件头,定位dex文件各部分锁在的区域,再定位到byte code的存放位置就可以修改dalvik字节码了。byte code中的insns参数就是存放dalvik的字节码,再定位到dexmethod,codeoff就是数据结构的偏移量,得到了便宜就可以通过mprotect函数修改insns了。注:apk安装时会通过dexopt来验证并生产优化后dalvik字节码和dex文件,过程是:将apk中的class.dex解压后用dexopt处理,并保存到dalvik-cache中,odex文件会解析相关依赖,并加载所需的依赖库表附加在文件中,会修改部分指令加快解析和处理速度

    5。检测模拟器:检测模拟器特有文件,检测默认号码,检测设备ids,检测ImsI id ,检测硬件信息,检测运营商

    6.对抗apk重打包:通过一个轮询去获取当前应用程序的签名,用获取到的签名和app的gradle文件中的签名信息比较,如果不同就说明被重新打包过,直接退出程序。

     

    展开全文
  • android打包加固和调试

    千次阅读 2019-01-18 10:37:02
    android打包 安装Android Studio Windows系统安装Android Studio 方便调试,注意根据 第一次使用Android Studio时你应该知道的一切配置 配置Android Studio的SDK 添加Android平台 以下命令都是在项目目录下...

    android打包加固和调试

    安装Android Studio

    Windows系统安装Android Studio 方便调试,注意根据 第一次使用Android Studio时你应该知道的一切配置 配置Android Studio的SDK

    添加Android平台

    以下命令都是在项目目录下通过终端执行的:

    ionic platform remove android(移除android平台,如果需要的话)
    ionic platform add android(添加android平台)
    

    添加之后,在项目目录的platforms下会生成一个android文件夹.

    设置图标名称多语言

    在platforms/android/res目录下,复制values目录,然后粘贴,命名为values-en,打开values-en/strings.xml,修改app_name标签中的值,这个值是app在手机系统为英文环境下显示的app名称。这样,app才能在手机系统语言切换后,改变app的名称。

    android集成crosswalk

    android内置浏览器大家都知道性能是硬伤,尤其是低端机,所有ionic支持使用crosswalk浏览器代替系统内置浏览器内核,使用crosswalk后性能提升效果比较明显,但是apk的包体积会增大大约20M。

    以前集成方法:

    添加crosswalk

    ionic browser add crosswalk

    移除crosswalk

    ionic browser revert android

    或者

    ionic browser remove crosswalk

    现在直接可以通过cordova插件来安装。

    cordova plugin add cordova-plugin-crosswalk-webview

    也可以指定插件所在的文件目录来添加插件。

    移除cordova插件

    cordova plugin remove cordova-plugin-crosswalk-webview

    执行完成后在插件列表plugins里会增加一个cordova-plugin-crosswalk-webview插件。

    打包

    相关命令

    ionic build android(编译项目apk)
    

    打包正式环境

    ionic build android --prod//app启动会更快
    

    备注:第一次会下载很多东西,需要耐心等待,第二次打包就快了

    打包成功会在ionic项目的platforms下面生成android包

    运行项目apk,手机连接在手机运行,模拟器连接在模拟器运行

    ionic emulate android
    

    真机调试生成文件

    ionic run android(相当于build + emulate)
    

    会把apk包安装到手机上,请先接好手机,需要在手机屏幕允许调试。

    注意:ionic项目下www是app的源码会打到:platforms->android->build->outputs->apk 然后打成apk包,所以要保证www文件夹最新,而不是直接去替换assets下www文件。

    问题解决

    1. 即使正确配置了JAVA_HOMEANDROID_HOME ,运行ionic build Android命令,有时还会出现出现:

    Error: Could not find gradle wrapper within android sdk. Might need to update yo ur Android SDK. Looked here: C:\Android\sdk\tools\templates\gradle\wrapper
    

    解决办法:

    将AS的android-studio\plugins\android\lib目录下的templates文件夹,复制到:android sdk的tools文件夹下。

    2. ionic生成apk使用build命令下载gradle-..*-all.zip卡

    1、先下载好gradle-..*-all.zip包,放在myApp\platforms\android\gradle文件夹下

    2、运行build命令前,先设置CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL环境变量

    set CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL=../gradle-2.14.1-all.zip
    

    3. 解决安卓build失败问题

    这里写图片描述

    这里写图片描述

    注意:根据你项目的需要设置v4版本。

    Android 中arm64-v8a、armeabi-v7a、armeabi、x86简介

    参考自:http://blog.csdn.net/u012400885/article/details/52923765
    Android系统目前支持以下七种不同的CPU架构:ARMv5,ARMv7 (从2010年起),x86 (从2011年起),MIPS (从2012年起),ARMv8,MIPS64和x86_64 (从2014年起),每一种都关联着一个相应的ABI。

    应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库。在Android 系统上,每一个CPU架构对应一个ABI:armeabi,armeabi-v7a,x86,mips,arm64- v8a,mips64,x86_64。

    各版本分析如下:

    • mips / mips64: 极少用于手机可以忽略
    • x86 / x86_64: x86 架构的手机都会包含由 Intel 提供的称为 Houdini 的指令集动态转码工具,实现 对 arm .so 的兼容,再考虑 x86 1% 以下的市场占有率,x86 相关的两个 .so 也是可以忽略的
    • armeabi: ARM v5 这是相当老旧的一个版本,缺少对浮点数计算的硬件支持,在需要大量计算时有性能瓶颈
    • armeabi-v7a: ARM v7 目前主流版本
    • arm64-v8a: 64位支持

    签名apk包

    命令行方式

    1、生成证书(在需要存放android.keystore的目录执行,有签名文件就不需要执行):

    keytool -genkey -alias android.keystore -keyalg RSA -validity 10000 -keystore android.keystore
    

    2、进入Cordova工程目录,编译:

    ionic build android --release
    

    编译正式环境包

    ionic build android --prod --release
    

    3、给未认证的apk文件认证:

    执行:cd [jdk 的 Home目录]

    –eg: cd /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home

    执行:jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore [android.keystore绝对路径] [app-release-unsigned apk文件绝对路径] android.keystore

    –eg: jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore /Users/WillJiang/Desktop/android.keystore /Users/WillJiang/Desktop/APP/appcode/platforms/android/build/outputs/apk/android-armv7-release-unsigned.apk android.keystore

    执行:jarsigner -verify -verbose -certs [app-release-unsigned apk文件绝对路径]

    –eg: jarsigner -verify -verbose -certs /Users/WillJiang/Desktop/APP/appcode/platforms/android/build/outputs/apk/android-armv7-release-unsigned.apk

    执行:cd [android sdk build-tools文件夹]

    –eg: cd /Users/WillJiang/Library/Android/sdk/build-tools/25.0.2

    执行:./zipalign -v 4 [app-release-unsigned apk文件绝对路径] [需要保存apk的文件绝对路径]

    –eg: ./zipalign -v 4 /Users/WillJiang/Desktop/APP/appcode/platforms/android/build/outputs/apk/android-armv7-release-unsigned.apk /Users/WillJiang/Desktop/APP.apk

    这时已经在桌面 生成 APP.apk 直接使用即可

    通过android studio签名apk包

    这里写图片描述

    这里写图片描述

    这里写图片描述

    点击Finish就会在C:\Users\Angela\Desktop下生成一个android-armv7-release.apk。

    设置自动签名

    在安卓平台下添加debug-signing.properties和release-signing.properties文件,内容如下:

    storeFile=file path of keystore
    key.store.password=password of signature file
    key.alias=alias of signature file
    key.alias.password=password of signature file
    

    执行下列cordova命令,就可以生成通过指定签名文件签名的apk包。

    cordova build android		// 生成debug的apk包
    cordova run android		// 运行debug包
    cordova build android --release	// 生成release的apk包
    cordova run android --release		// 运行release包 mode
    

    使用360加固助手加固apk包

    1、下载360加固助手,然后注册登录360账号。

    2、使用上一步生成的签名文件进行签名配置

    这里写图片描述

    3、点击加固应用,选择上一步生成的签名apk包android-armv7-release.apk。上传成功后,就会进行加固,并使用配置信息中的签名配置进行重新签名。

    这里写图片描述

    这里写图片描述

    点击确定,就会看到输出目录中存在一个android-armv7-release_140_jiagu_sign.apk。

    到此,签名加固安卓apk包完成。

    调试

    实时更新

    ionic在部署到移动端后也可以开启livereload的,我们只需要修改下我们run命令参数:

    ionic run android --livereload -c -s

    这是android的调试模式,无论在虚拟机上还是在手机上都可以实现livereload,ios则只需要把android修改为ios即可,不用每次开发完成编译再部署!-c是开启客户端日志输出,-s是开启服务器端日志输出。–livereload参数的的意义在于修改生成包中的起始页面地址,修改为远程服务器地址,这样就可以做到修改即通知客户端刷新页面了。

    查看日志

    打开Android Studio,导入项目的android平台\platforms\android\build.gradle。把手机通过USB数据线连接电脑,然后你就可在logcat中查看手机上应用输出的日志了。

    这里写图片描述

    Android查看本地数据库

    在你的build.gradle(android)的dependencies添加如下内容:

    debugCompile 'com.amitshekhar.android:debug-db:1.0.0'

    debugCompile的作用:只在你debug编译时起作用,当你release的时候就没必要使用它了。

    使用debug android模式运行app,注意不要点击force close

    下面当你在App启动的时候,你要注意查看下你的logcat,会有这么一行:

    D/DebugDB: Open http://XXX.XXX.X.XXX:8080

    把它复制到你电脑的浏览器,你就可以看到你的App中的数据库,和shared preferences

    注意:

    1. 你的手机要和电脑在同一个局域网下
    2. 如果你的logcat下没有出现D/DebugDB: Open http://XXX.XXX.X.XXX:8080,只需要将xxx的地址改成你的手机的IP地址即可

    你也可以通过AS的Device File Explorer工具来导出手机数据库文件进行查看。在explorer中的data->data->应用包名->databases中,选择数据库文件,右键保存,然后使用数据库工具查看保存的数据库文件。
    在这里插入图片描述

    展开全文
  • 1、防网络代理抓包 网络请求配置Proxy.NO_PROXY,可以保证app的网络数据不经过wifi设置的代理工具(最常见的抓包方式) webview,HttpURLConnection,okhttp等框架均可以配置NO_PROXY   2、网络请求数据加上...
  • Android 加固

    2017-03-14 21:47:00
    本文主要讲的是本人在工作中接到的一个加固任务后所经历的探索之路,有一些方案的说明,但是没有源码,伸手党敬免了。 1)接到的任务是对sdk项目进行防篡改,最初的要求只是需要保证第三方集成sdk的开发者不能通过...
  • 一、前言今天又到周末了,憋了好久又要出博客了,今天来介绍一下Android中的如何对Apk进行加固的原理。现阶段。我们知道Android中的反编译工作越来越让人操作熟练,我们辛苦的开发出一个apk,结果被人反编译了,那...
  • Android加壳(加固)原理以及实现

    千次阅读 2017-06-13 14:19:11
    今天又到周末了,憋了好久又要出博客了,今天来介绍一下Android中的如何对Apk进行加固的原理。现阶段。我们知道android中的反编译工作越来越让人操作熟练,我们辛苦的开发出一个apk,结果被人反编译了,那心情真心不...
  • android-app加固

    2020-07-26 23:30:57
    app加固原理,通过加固app从而知道其中的原理,熟练掌握反编译
  • Android加固

    万次阅读 2019-08-18 10:20:45
    前段时间,研究了一些Android逆向相关的工具和技术,并...接下来,我将总结一下目前常用的Android加固平台。 一.梆梆加固 1.在线加固 1.这是梆梆加固的官网:https://dev.bangcle.com/。注册新用户并且登录后,点...
  • apk加固demo

    2020-07-30 23:30:23
    APK加固demo,详细讲解http://blog.csdn.net/itfootball/article/details/50962459
  • android加固

    2017-05-17 11:22:53
    参考文章1,Android APK加固技术方案调研 http://blog.csdn.net/asce1885/article/details/47029763动态加载保护代码在android项目中,我们将核心代码写入一个工程、打包成apk、然后将apk加密,接下来我们用动态...
  • 看雪上有作者(寒号鸟二代)将阿里移动早期的Android加固进行了逆向分析,得到了能够运行成功的NDK代码,主要是基于第2界阿里移动破解大赛的apk逆向分析出来的,文章的原地址《阿里早期加固代码还原4.4-6.0》。...
  • 近日,百度安全实验室发现了一款被不同病毒家族利用的新型代码加固方式,该种代码加固方式巧妙的利用了Android系统提供的NativeActivity特性完成恶意代码的解固。目前主流的加固方案代码逻辑分为java层和native层两...
  • Android加固demo

    2020-07-30 23:31:40
    android的Apk加固实现,dex加密解密等。具体使用详情请参考:https://blog.csdn.net/I123456789T/article/details/91562328
  • apksigner是Google官方提供的针对Android apk签名及验证的专用工具, 位于Android SDK/build-tools/SDK版本/apksigner.bat 不管是apk包,还是jar包,本质都是zip格式的压缩包,所以它们的签名过程都差不多(仅限V1签名),...
  • 之前很奇怪的就是版本更新apk下载完后直接就调起安装apk直接解析错误,我开始以为是加固的问题,因为我已开始用的是上一个版本的乐加固,后面更新了乐加固版本发现还是不行,继续解析错误,很奇怪,我的流程是先生成...
  • android 加固防止反编译-重新打包

    千次阅读 2016-09-11 18:01:16
    1、需要加密的Apk(源Apk) 2、壳程序Apk(负责解密Apk工作) 3、加密工具(将源Apk进行加密和壳Dex合并成新的Dex) ...我们拿到需要加密的Apk和自己的壳程序Apk,然后用加密算法对源Apk进行加密在将壳Apk进行合并得到...
  • 版本更新是每个应用必不可少的功能之一....加固前能正常更新,使用第三方加固乐固加固或者360加固后就不能正常安装 原因: 我的版本更新流程如下 String mimeDefault = "application/vnd.android.package-arc...
  • android加固apk包,并防止apk被二次打包

    千次阅读 2015-07-02 20:28:59
    自行线下加密apk包,加密dex文件,并做了防二次打包处理。
1 2 3 4 5 ... 20
收藏数 6,425
精华内容 2,570
关键字:

android加固