Android群英传笔记——第九章:Android系统信息和安全机制

Android群英传笔记——第九章:Android系统信息和安全机制


本书也正式的进入尾声了,在android的世界了,不同的软件,硬件信息就像一个国家的经济水平,军事水平,不同的配置参数,代表着一个android帝国的强弱,所以厂商喜欢打配置战,本节就要是讲

  • Android系统信息的获取
  • PackageManager的使用
  • ActivityManager的使用
  • Android安全机制

一. Android系统信息的获取

由于android手机的开源性,手机的配置各种各样,那些优化大师之类的东西,都可以跑分和看配置信息,那他们是从哪里知道这些信息的呢?遥想获取系统的配置信息,通常可以从以下两个方面获取

  • android.os.Build
  • SystemProperty

1.android.os.Build

android.os.Build类里面的信息非常的丰富,它包含了系统编译时的大量设备,配置信息,我们列举一点

  • Build.BOARD——主板
  • Build.BRAND——Android系统定制商
  • Build.SUPPORTED_ABIS——CPU指令集
  • Build.DEVICE——设备参数
  • Build.DISPLAY——显示屏参数
  • Build.FINGERPRINT——唯一编号
  • Build.SERIAL——硬件序列号
  • Build.ID——修订版本列表
  • Build.MANUFACTURER——硬件制造商
  • Build.MODEL——版本
  • Build.HARDWARE——硬件名
  • Build.PRODUCT——手机产品名
  • Build.TAGS——描述Build的标签
  • Build.TYPE——Builder类型
  • Build.VERSION.CODENAME——当前开发代号
  • Build.VERSION.INCREMENTAL——源码控制版本号
  • Build.VERSION.RELEASE——版本字符串
  • Build.VERSION.SDK_INT——版本号
  • Build.HOST——host值
  • Build.USER——User名
  • Build.TIME——编译时间

上面的一些参数没有注释,他们来自系统的RO值中,这些值都是手机生产商配置的只读的参数值,根据厂家的配置不同而不同,接下来我们再来看一下另一个存储设备软硬件信息的类——SystemProperty

2.SystemProperty

SystemProperty类包含了许多系统配置属性值和参数,很多信息和上面通过android.os.Build获取的值是相同的,我们列举一些常用的

  • os.version——OS版本
  • os.name——OS名称
  • os.arch——OS架构
  • user.home——home属性
  • user.name——name属性
  • user.dir——Dir属性
  • user.timezone——时区
  • path.separator——路径分隔符
  • line.separator——行分隔符
  • file.separator——文件分隔符
  • java.vendor.url——Java vender Url属性
  • java.class.path——Java Class属性
  • java.class.version——Java Class版本
  • java.vendor——Java Vender属性
  • java.version——Java版本
  • java.home——Java Home属性

3.Android系统信息实例

下面我们用一个简单的实例来了解一下把

通过android.os.Build这个类,我们可以直接获取到Build提供的系统信息,而通过System.getProperty(“xxx”),我们可以访问到系统的属性

在实例中获取到的信息与上述的基本一致,运行如图

         tv_message.append("主板:"+ Build.BOARD+"\n");
        tv_message.append("Android系统定制商:"+ Build.BRAND+"\n");
        tv_message.append("CPU指令集:"+ Build.SUPPORTED_ABIS+"\n");
        tv_message.append("设置参数:"+ Build.DEVICE+"\n");
        tv_message.append("显示屏参数:"+ Build.DISPLAY+"\n");
        tv_message.append("唯一编号:"+ Build.SERIAL+"\n");

用System.getProperty

         tv.append("OS版本:"+System.getProperty("os.version")+"\n");
        tv.append("OS名称:"+System.getProperty("os.name")+"\n");
        tv.append("OS架构:"+System.getProperty("os.arch")+"\n");
        tv.append("Home属性:"+System.getProperty("user.home")+"\n");
        tv.append("Name属性:"+System.getProperty("user.name")+"\n");

代码贴上一点就可以了

运行的实例程序中我们可以看到,我们已经获取到了相当多的系统信息,那么这些信息的来源又是哪儿呢?记得我们分析android系统目录的时候提到过,在system/build.prop中,包含了很多的RO值,打开命令窗,通过cat build.prop可以看到

这里我们可以看到很多前面通过android.os.Build所获取到的系统信息,同时,在adb shell中,还可以通过getprop来获取对应的值

除了上述的两个方法,android系统还在另外一个非常重要的目录来存储系统信息——/proc目录,在adb shell中进入/proc目录,通过ll命令查看文件信息,

二.Android APK应用程序信息获取值PackageManager

我们刚才把Android的系统翻了个遍,danshi8没有找到apk的信息,在adb shell中PM和AM命令时我们的帮手,我们来看一下

1.PackageManager

我们看一张图

最里面的框就代表整个Activity的信息,系统提供了ActivityInfo类来进行封装

而Android提供了PackageManager来负责管理所有已安装的App,PackageManager可以获得AndroidManifest中不同节点的封装信息,下面是一些常用的封装信息:

  • ActivityInfo

    ActivityInfo封装在了Mainfest文件中的< activity >和< eceiver>之间的所有信息,包括name、icon、label、launchMode等。

  • ServiceInfo

    ServiceInfo与ActivityInfo类似,封装了< service>之间的所有信息。

  • ApplicationInfo

    它封装了< application>之间的信息,特别的是,ApplicationInfo包含了很多Flag,FLAG_SYSTEM表示为系统应用,FLAG_EXTERNAL_STORAGE表示为安装在SDcard上的应用,通过这些flag可以很方便的判断应用的类型。

  • PackageInfo

    PackageInfo包含了所有的Activity和Service信息。

  • ResolveInfo

    ResolveInfo包含了< intent>信息的上级信息,所以它可以返回ActivityInfo、ServiceInfo等包含了< intent>的信息,经常用来帮助找到那些包含特定intent条件的信息,如带分享功能、播放功能的应用。

    有了这些封装的信息后,还需要有特定的方法来获取它们,下面就是PackageManager中封装的用来获取这些信息的方法:

  • getPackageManager()——通过这个方法可以返回一个PackageManager对象。
  • getApplicationInfo()——以ApplicationInfo的形式返回指定包名的ApplicationInfo。
  • getApplicationIcon()——返回指定包名的Icon。
  • getInstalledApplications()——以ApplicationInfo的形式返回安装的应用。
    • getInstalledPackages()——以PackageInfo的形式返回安装的应用。
  • queryIntentActivities()——返回指定Intent的ResolveInfo对象、Activity集合。
  • queryIntentServices()——返回指定Intent的ResolveInfo对象、Service集合。
  • resolveActivity()——返回指定Intent的Activity。
  • resolveService()——返回指定Intent的Service。

根据ApplicationInfo的flag来判断App的类型:

如果当前应用的flags & ApplicationInfo.FLAG_SYSTEM != 0则为系统应用

如果flags & ApplicationInfo.FLAG_SYSTEM <= 0 则为第三方应用

特殊的当系统应用升级后也会成为第三方应用,此时 flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP != 0;

如果flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE != 0 则为安装在SDCard上的应用。

我们通过一个实例来分析,先封装一个Bean来保存我们需要的字段

package com.lgl.systemmesage;

import android.graphics.drawable.Drawable;

/**
 * Bean
 * Created by LGL on 2016/4/28.
 */
public class PMAPPInfo {

    //应用名
    private String appLabel;
    //图标
    private Drawable appIcon;
    //包名
    private String pkgName;

    //构造方法
    public PMAPPInfo(){

    }

    public String getAppLabel() {
        return appLabel;
    }

    public void setAppLabel(String appLabel) {
        this.appLabel = appLabel;
    }

    public Drawable getAppIcon() {
        return appIcon;
    }

    public void setAppIcon(Drawable appIcon) {
        this.appIcon = appIcon;
    }

    public String getPkgName() {
        return pkgName;
    }

    public void setPkgName(String pkgName) {
        this.pkgName = pkgName;
    }
}

接下来,我们通过上面的方法判断各种类型的应用,我们的主布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_all"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="All APP"
        android:textAllCaps="false" />

    <Button
        android:id="@+id/btn_other"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Other App"
        android:textAllCaps="false" />

    <Button
        android:id="@+id/btn_system"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="System App"
        android:textAllCaps="false" />

    <ListView
        android:id="@+id/mListView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"></ListView>

</LinearLayout>

这里有一个listview,所以我们需要一个adapter和一个item

package com.lgl.systemmesage;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * 数据源
 * Created by LGL on 2016/4/28.
 */
public class PkgAdapter extends BaseAdapter {
    private Context mContext;
    private List<PMAPPInfo> mList;

    public PkgAdapter(Context context) {
        mContext = context;
        mList = new ArrayList<>();
    }

    public void addAll(List<PMAPPInfo> list) {
        mList.clear();
        mList.addAll(list);
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return mList.size();
    }

    @Override
    public PMAPPInfo getItem(int position) {
        return mList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        PMAPPInfo item = getItem(position);
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false);
            holder.mIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
            holder.mLabel = (TextView) convertView.findViewById(R.id.tv_label);
            holder.mPkgName = (TextView) convertView.findViewById(R.id.tv_pkg_name);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        holder.mIcon.setImageDrawable(item.getAppIcon());
        holder.mLabel.setText(item.getAppLabel());
        holder.mPkgName.setText(item.getPkgName());
        return convertView;
    }

    static class ViewHolder {
        ImageView mIcon;
        TextView mLabel;
        TextView mPkgName;
    }
}

item就简单了

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/empty"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/iv_icon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginLeft="15dp"
        android:orientation="vertical">

        <TextView
            android:id="@+id/tv_label"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/tv_pkg_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>

</LinearLayout>

那我们主程序的逻辑就是

package com.lgl.systemmesage;

import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ListView;

import java.util.ArrayList;
import java.util.List;

/**
 * 软件列表
 * Created by LGL on 2016/4/28.
 */
public class APP extends AppCompatActivity implements View.OnClickListener{

    private PackageManager mPackageManager;

    private ListView mListView;
    private PkgAdapter mAdapter;
    List<PMAPPInfo> result;

    protected void onCreate( Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_app);

        mPackageManager = getPackageManager();
        mListView = (ListView) findViewById(R.id.mListView);
        mAdapter = new PkgAdapter(this);
        mListView.setEmptyView(findViewById(R.id.empty));
        mListView.setAdapter(mAdapter);
        findViewById(R.id.btn_all).setOnClickListener(this);
        findViewById(R.id.btn_other).setOnClickListener(this);
        findViewById(R.id.btn_system).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_all:
                result = getAppInfo(R.id.btn_all);
                break;
            case R.id.btn_other:
                result = getAppInfo(R.id.btn_other);
                break;
            case R.id.btn_system:
                result = getAppInfo(R.id.btn_system);
                break;
            default:
                result = new ArrayList<>();
        }
        mAdapter.addAll(result);
    }

    private List<PMAPPInfo> getAppInfo(int flag) {
        List<ApplicationInfo> appInfos = mPackageManager.getInstalledApplications(
                PackageManager.GET_UNINSTALLED_PACKAGES);
        List<PMAPPInfo> list = new ArrayList<>();
        //根据不同的flag来切换显示不同的App类型
        switch (flag) {
            case R.id.btn_all:
                list.clear();
                for (ApplicationInfo appInfo : appInfos) {
                    list.add(makeAppInfo(appInfo));
                }

                break;
            case R.id.btn_other:
                list.clear();
                for (ApplicationInfo appInfo : appInfos) {
                    if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {
                        list.add(makeAppInfo(appInfo));
                    } else if ((appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0){
                        list.add(makeAppInfo(appInfo));
                    }
                }
                break;
            case R.id.btn_system:
                list.clear();
                for (ApplicationInfo appInfo : appInfos) {
                    if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
                        list.add(makeAppInfo(appInfo));
                    }
                }
                break;
        }
        return list;
    }

    private PMAPPInfo makeAppInfo(ApplicationInfo appInfo) {
        PMAPPInfo info = new PMAPPInfo();
        info.setAppIcon(appInfo.loadIcon(mPackageManager));
        info.setAppLabel(appInfo.loadLabel(mPackageManager).toString());
        info.setPkgName(appInfo.packageName);
        return info;
    }
}

运行的结果

三.Android APK应用程序信息获取值ActivityManager

前面所使用的packagemanager获取的是所有的应用包名,但是哼哈二将还有一名大奖没有说道,那就是ActivityManager了,他的功能四号不逊色前者,事实上,他在使用上各有侧重点,前者侧重于获取应用的包信息,后者获取运行的应用程序信息

同packagemanager一样,ActivityManager也封装了不少的Bean对象,我们选几个重点来说一下

  • ActivityManager.MemoryInfo——MemoryInfo有几个非常重要的字段:availMem(系统可用内存),totalMem(总内存),threshold(低内存的阈值,即区分是否低内存的临界值),lowMemory(是否处于低内存)。
  • Debug.MemoryInfo——这个MemoryInfo用于统计进程下的内存信息。
  • RunningAppProcessInfo——运行进程的信息,存储的字段有:processName(进程名),pid(进程pid),uid(进程uid),pkgList(该进程下的所有包)
  • RunningServiceInfo——运行的服务信息,在它里面同样包含了一些服务进程信息,同时还有一些其他信息。activeSince(第一次被激活的时间、方式),foreground(服务是否在后台执行)。

我们同样的用一个实例来讲解

package com.lgl.systemmesage;

/**
 * Created by LGL on 2016/4/28.
 */
public class AMProcessInfo {

    private String pid;
    private String uid;
    private String memorySize;
    private String processName;

    public  AMProcessInfo(){

    }

    public String getPid() {
        return pid;
    }

    public void setPid(String pid) {
        this.pid = pid;
    }

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getProcessName() {
        return processName;
    }

    public void setProcessName(String processName) {
        this.processName = processName;
    }

    public String getMemorySize() {
        return memorySize;
    }

    public void setMemorySize(String memorySize) {
        this.memorySize = memorySize;
    }
}

然后我们用一个方法就可以获取到了

 /**
     * 正在运行
     * @return
     */
    private List<ActivityManager.RunningAppProcessInfo> getRunningProcossInfo(){
        mAMProcessInfo = new ArrayList<>();
        List<ActivityManager.RunningAppProcessInfo>appRunningList = activityManager.getRunningAppProcesses();

        for (int i = 0;i<appRunningList.size();i++){
            ActivityManager.RunningAppProcessInfo info = appRunningList.get(i);
            int pid = info.pid;
            int uid = info.uid;
            String procossName = info.processName;
            int[]memoryPid = new int[]{pid};
            Debug.MemoryInfo[] memoryInfos = activityManager.getProcessMemoryInfo(memoryPid);

            int memorySize = memoryInfos[0].getTotalPss();

            AMProcessInfo processInfo = new AMProcessInfo();
            processInfo.setPid(""+pid);
            processInfo.setUid(""+uid);
            processInfo.setMemorySize(""+memorySize);
            processInfo.setProcessName(procossName);
            appRunningList.add(processInfo);
        }
        return  appRunningList;
    }

四.解析Packages.xml获取系统信息

熟悉Android开机启动流程的朋友大概知道,在系统初始化到时候,packagemanager的底层实现类packagemanagerService会去扫描系统的一些特定目录,并且解析其中的Apk文件,同时Android把他获取到的应用信息保存到xml中,做成一个应用的花名册,就是data/system/apckages.xml,我们用adb pull命令把他导出来,里面的信息也太多了,但是我们只要知道结果根节点就可以了

  • < permissions>标签

    permissions标签定义了现在系统所有的权限,也分两类,系统定义的和app定义的

  • < package>标签

    package代表的是一个apk的属性

其中各节点的信息含义大致为

  • name:APK的包名
  • cadePath:APK安装路径,主要在system/app和data/app两种,前者放系统级别的,后者放系统安装的
  • userid:用户ID
  • version:版本
  • < perms>标签

    对应apk的清单文件,记录apk的权限信息

通过这个xml文件的标签,可以获取到很多手机应用的信息,通常在进行系统层开发的时候,可以通过这个xml获取更多有意义的东西

五.Android安全机制

道高一尺魔高一丈,自古以来就没有什么绝对的安全,所以Google也建立起了一层层的壁垒,保护Android的核心安全,我们来详细了解一下

1.Android安全机制介绍

安全不管在那个平台,哪个语言中,都是非常重要的一环,Android开发者在Android系统中简历了五道防线来保护Android的安全

-1.第一道防线

代码安全机制——代码混淆proguard

由于java语言的特殊性,即使是编译成apk的应用程序也存在反编译的风险,而proguard则是在代码从上对app的第一道程序,他混淆关键代码,替换命名,让破坏者阅读难,同样也可以压缩代码,优化编译后的字节

-2.第二道防线

应用接入权限控制——清单文件权限声明,权限检查机制,

任何app在使用Android受限资源的时候,都需要显示向系统生命权限,只有当一个应用app具有相应的权限,才能申请相应的资源,通过权限机制的检查并且使用并且使用系统的Binder对象完成对系统服务的调用,但是这道防线也有先天的不足,如以下几项

  • 被授予的权限无法停止
  • 在应用声明app使用权限的时候,用户无法针对部分权限进行限制
  • 权限的判断机制与用户的安全理念相关

Android系统通常按照以下顺序来检查操作者的权限.

首先,判断permission名称.如果为空则直接返回PERMISSION_DENIED

其次。判断Uid,如果为0则为root权限,不做权限控制,如果为systyemsystem service的uid则为系统服务.不做权限控制:如果Uid与参数中的请求uid不同则返回PERMISSION_DENIED

最后,通过调用packagemanageservice.checkUidPermission()方法来判断该uid是否具有相应的权限,该方法会去xml的权限列表和系统级的权限进行查找

通过上面的步骤Android就确定了使用者是否具有某项使用权限

-3. 第三道防线

应用签名机制一数字证书。

Android中所有的app都会有个数字证书,这就是app的签名.数字证书用于保护app的作者和其app的信任关系,只有拥有相同数字签名的app,才会在升级时被认为是同一app,而且Android系统不会安装没有签名的App

- 4. 第四道防线

Linux内核层安全机制一一Uid 访问权限控制。

Animid本质是基于Linux内核开发的,所以Android同样继承了Linux的安全特性,比如Linux文件系统的权限控制是由user,group,other与读,写,执行的不同组合来实现的,同样,Android也实现了这套机制”通常情况下.只有system,root用户才有权限访问到系统文件,而一般用户无法访问。

-5. 第五道防线

Android虚拟机沙箱机制——沙箱隔流

Android的App运行在虚拟机中 因此才有沙箱机制,可以让应用之间相互隔离,通常情况下.不同的应用之间不能互相访问.每个App都单独的运行在虚似机中,与其他应用完全隔离.在实现安全机制的基础上,也让应用之间能够互不影响,即时一个应用崩溃,,也不会导致其他应用异常

虽然通过以上的五道防线.仍然不能完全保证Android的核心安全”但却可以在最大程度上给破坏者增加难度,从另一方面来说”这些破坏者的破解也真是推动Android安全机制逐渐健全的动力.

2.Android系统安全隐患

虽说Android建立起来了N道防线,但是没有绝对的安全所以在Android中也有一些破解之法,

-1.代码漏洞

这个问题存在世界上所有的程序中,没有谁敢保证自己的程序没有bug,有漏洞,如果遇到这种问题,大家只能尽快的升级版本,更新补丁,才能杜绝利用漏洞的攻击装,比如Android的LaunchAnyWhere,FakeId,这些都是bug,就是在编写的时候产生的漏洞,只有期待官方的更新了

-2. root风险

Root权限是指Android的系统管理员权限,类似于windows系统中的Administrator。具有Root权限的用户可以访问和修改手机中几乎所有的文件,“Root”在一段时间内一度成为Android的代名词, 无Root,不Android”。的确,Root掉手机后,可以解锁很多普通用户无法完成的工作,如限制各个应用app的数据流量.系统文件管理丶自定义修改系统等,但同时手机的安全性也会因此大打折扣。随着android系统越来越完善,root的必要性也越来越低普通用户在不root的情况下,完全可以正常使用大部分App。需要Root权限的大多为一些开发者,由于开发的需要,不得不将手机root,而root后的手机,就少了一层Linux的天然屏障,整个系统核心就完全暴露在人侵者面前,在你没有察觉的情况下大肆破坏。所以,针对普通用户,希望都尽量不要Root手机以免带来不必要的损失

-3. 安全机制不健全

由于Android的权限管理机制并不完美,所以很多手机开发商,通常会在RoM中增加自己的一套权限管理工具来帮助用户控制手机中应用的权限,如应用许可

-4.用户安全意识

用户对于安全隐患的察觉里也是保护手机安全的一个重要因素。用户可以通过在正规的应用市场下载和安装应用时通过列出来的应用权限申请信息来大致判断一个应用的安全性,比如我们曾经十分喜欢用的xx神器”,其实没有一点技术含量,无非就是在你安装了应用之后遍历一遍你的联系人并发送带有链接的短信而已当用户在安装不明来源的应用时如果一个娱乐类型的app生命权限的时候不仅要联系人又要短信权限,这个时候就需要警惕了,用户也可以在市场上下载一些安全类App,如LEB安全大师,360安全等, 虽然这些软件会加重系统负担,但是为了安全也是值得的

-5. Android开发原则与安全

众所周知,Android与ioS系统一个非常显著的区别就是_一个是开放系统,一个是封闭系统,开放自然有开放的好处,技术进步快,产品丰富,封闭也有封闭的好处,安全性高,可控性高,Google本着开源的精神开放了Android的源代码,但随之而来的各种安全问题也让Android倍受诟病,过度的开放与可定制化,不仅造成了Android的碎片化严重, 同时也给很多不法应用以可乘之机,但可喜的是,随着Android的发展日益壮大,Google也在着手处理开发与安全的问题,相信在不久的将来,这一矛盾会越来越小

3.Android Apk反编译

Android的应用程序APk文件,说到底也是一个压缩文件,那么可以通过解压缩, 获得里面的文件内容。让我们先来找一个apk,然后使用解压缩工具,最后就会得到一些文件.

解压之后我们看见了不少熟悉的东西,但是当点进去的时候,你就会发现资源文件和xml文件,基本都无法打开,即使打开或者乱码

这些乱码就是经过Android加密过的文件女,更关键的是,竟然找不到源代码文件夹src。只能在res文件夹中查看非XML的片资源文件,不过, 有些应用会把图片也加密处理,这样你就连图片也看不见了

既然直接解压Apk文件是无法获得正常的应用,那么来看看如何使用正确的方法反编译应用程序

首先请出三个重量级的工具,

apktools:反编译

下载地址:http://ibotpeaches.github.io/Apktool/install/

dex2jar 这个工具用于将dex文件转换成jar文件

下载地址:http://sourceforge.net/projects/dex2jar/files/

jd-gui 这个工具用于将jar文件转换成java代码

下载地址:http://jd.benow.ca/

这三 个工具分别负责反编译不同的部分

-1.apktool

首先我们来反编译apk的xml文件,使用的是apktool,我们进入所在的目录执行反编译命令

格式非常的简单,参数d是指decode,并写入要反编译的目录,执行后,就会生成一个对应apk名字的文件夹,这个时候你进去看xml的代码就不会有错误了

这个工具可以方便我们汉化们重新打包的命令是b,选择文件夹即可

下面我们来解决源码

-2.Dex2jar,jd-gui

现在需要这两个工具了,我们回到apk的文件夹,里面有一个非常重要的文件classes.dex,这个就是源代码了,我们把它复制到Dex2jar的目录下

并且执行如下命令

这里就生成了一个jar文件,然后我们就可以用最后的jd-gui去查看了

通过以上的方式,我们就可以完美的编译一个应用程序了,

4.Android APK 加密

由于java字节的特殊性,他很容易反编译,为了能够保护好代码,我们通常会使用一些措施,比如说混淆,而在Android studio中,可以很方便的使用ProGuard,在Gradle Scripts目录下

 buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘
        }
    }

这里的minifyEnabled属性就是控制是否启动ProGuard,这个属性以前叫做runProgyard,在Android studio1.1的时候改成minifyEnabled,将他设置成true,就可以混淆了,他位于《SDK目录下的tools/proguard/proguard-android.txt目录下,大部分的情况下使用使用这个默认的混淆就好了,后面亦不过分是项目中自定义的混淆,可以在项目的app文件夹下找到这个文件,在这根文件里可以定义引用的第三方依赖库和混淆规则,配置好ProGuard之后,用AS到处apk即可,

好了,本章到这里就完了

Demo下载地址:正在上传

笔记下载地址:正在上传

时间: 2024-10-13 20:20:58

Android群英传笔记——第九章:Android系统信息和安全机制的相关文章

Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 这一章很多,但是很有趣,也是这书的最后一章知识点了,我现在还在考虑要不要写这个拼图和2048的案例,在此之前,我们先来玩玩Android5.X的新特性吧!

Android群英传笔记——第四章:ListView使用技巧

Android群英传笔记--第四章:ListView使用技巧 近期也是比較迷茫.可是有一点点还是要坚持的,就是学习了.近期离职了,今天也是继续温习第四章ListView,也拖了事实上也挺久的了,listview可谓是老牌大将了,非常多的应用场景都要使用它,他也是我们用得最多的控件之中的一个了,尽管如今出来了一个RecyclerView,可是ListView的地位一时半会儿还是撼动不了的.这就促使我们更加应该去把他掌握了 一.Listview经常使用优化技巧 我们一步步来把ListView学习好

Android群英传笔记——第七章:Android动画机制和使用技巧

Android群英传笔记--第七章:Android动画机制和使用技巧 想来,最近忙的不可开交,都把看书给冷落了,还有好几本没有看完呢,速度得加快了 今天看了第七章,Android动画效果一直是人家中十分重要的一部分,从早期的Android版本中,由于动画机制和绘图机制的不健全,Android的人机交互备受诟病,Android从4.X开始,特别是5.X,动画越来越完善了,Google也开始重视这一方面了,我们本章学习的主要内容有 Android视图动画' Android属性动画 Android动画

Android群英传笔记——摘要,概述,新的出发点,温故而知新,能够为师矣!

Android群英传笔记--摘要.概述,新的出发点,温故而知新.能够为师矣! 当工作的越久,就越感到力不从心了,基础和理解才是最重要的,所以买了两本书,医生的<Android群英传>和主席的<Android开发艺术探索>.主要是再全面点的把自己所学的知识消化,这样也就不枉自己天天熬夜学习了,如今群英传快看完了.准备又一次再看一遍,同一时候把笔记以博客的形式记录下来,这样或许更加的深刻,然后再消磨一下主席的那本书,这本书有视频解说,更加好,所以估计以后应该非常少再写其它的博客,只是工

Android群英传笔记——第八章:Activity与Activity调用栈分析

Android群英传笔记--第八章:Activity与Activity调用栈分析 开篇,我们陈述一下Activity,Activity是整个应用用户交互的核心组件,了解Activity的工作模式,生命周期和管理方式,是了解Android的基础,本节主讲 Activity的生命周期与工作模式 Activity调用栈管理 一.Activity Activity作为四大组建出现平率最高的组件,我们在哪里都能看到他,就让我们一起先来了解一下他的生命周期 1.起源 Activity是用户交互的第一接口,他

Android群英传笔记系列一view的介绍

学习完第一行代码后,继续学习Android群英传,希望能坚持下去,好好学习完这本书,并及时做好相关笔记,巩固相关知识: 一. View的介绍: 1`.我们先来看下view树结构: 2.树结构内容: a.viewparent是整棵树的核心,它统一调度和分配所有的交互管理事件. b.控件分为viewgroup和view两种控件,viewgroup作为父控件可以包含多个vie       w控件. c.我们知道在使用控件前都要通过findViewById的方法来实例化控件,那么在树结构中,实际上表现为

Android群英传笔记系列三 view的自定义:实现一个模拟下载

1.实现效果:动态显示进度(分别显示了整个的动态改变的过程,然后完成后,弹出一个对话框)       2.实现过程:可以分为绘制一个圆,圆弧和文本三部分,然后在MainAcitivity中通过线程模拟下载进度. a.定义一个类继承至view,然后添加其构造函数,记得一定要添加含有Attributset参数的构造函数; b.定义和初始化一些数据: private int mCircleXY; private int mWidth; private float mRadius; private Pa

Android群英传笔记——第五章:Android Scroll分析

一.滑动效果是如何产生的 滑动一个View的本质其实就是移动一个View,改变其当钱所在的位置,他的原理和动画效果十分的相似,就是通过不断的改变View的坐标来实现这一效果,动态且不断的改变View的坐标,从而实现View跟随用户触摸滑动而滑动 但是在讲解滑动效果之前,需要先了解一下Android中窗口坐标体系和屏幕的触控事件--MotionEvent 1.Android坐标系 在物理学上,要描述一个物体的运动,就必须选定一个参考系,所谓滑动,正是相对于参考系的运动,在Android,系统将屏幕

Android深度探索笔记-第九章

HAL层属于Linux内核层之上的应用层是为了尽量避免应用程序直接访问Linux驱动和保护 “私人财产”.带HAL的 Linux 驱动就相当于将数据从HAL传到寄存器,或从寄存器传到HAL的数据二传. 加入HAL的主要目的:1:统一硬件的调用接口,2:解决了GPl版权问题,3:针对一些特殊的要求. Android HAL的源代码存储的位置并不固定,一般会存储在Android源代码目录/hardware目录中. 编写一款支持HA 的Linux驱动程序的步骤:1:编写 Linux 驱动:2:编写 H