从大三伊始到大四落幕,从刚开始接触Android到辞掉第一份实习工作,我接触Android应用层开发也快接近两年了。越来越发觉Android的应用层已经没什么挑战性了,想当初刚开始学习Android的时候,弄了一个Activity出来显示在手机的那份喜悦,真是~哈哈~,应用层的开发无非也就调用JDK,SDK而已,现在感觉有点小儿科啊,实习期间,每当工作项目之余,基本都泡到自定义View的绘制去,那也是我所能解闷的工作了。可是,这并不符合的职业规划,我想往前发展,比如framework层或者其他深层的技术等。

因为实习将近一年,在Android开发方面有一定的经验,再加上自己是应届生,所以有家稍微有点大但名气比较低(起码叫我面试的时候我都没听过这公司,额。。)的上市公司给我伸出了橄榄枝,从白纸开始培养人才。又因为提供的岗位叫Android逆向分析工程师,以前就听过这霸气的名字了,实际就是白帽子的工作,所以我也签了这公司,来实习了,毕竟还有一个月才能拿到毕业证。


说实话,逆向分析已经和Android应用开发不是一个level了,也和应用层开发没什么关系了,只是逆向分析需要熟悉应用层开发中的内容而已,比如反编译后要找到某个Activity或着fragment,总之,你要定位到关键代码,那你就必须得熟悉Android应用层的开发内容,尤其是混淆过,那就更需要熟悉开发的结构了,不然要在一大堆反编译的文件中找到你要的代码简直就令人发怵。

嗯,废话不多说,既然没有什么经验,那么就好好学习。先来个入门的工作,就是利用dex2jar反编译一个APK,并用jd-gui.exe查看jar包内容。

第一步,先写个简单的工程,并签名打包导出APK。

LoginActivity.java:

public class LoginActivity extends Activity {    private final String ACCOUNT="samuel";    private final String PASSWORD="123456";    private EditText etAccount, etPassword;    private Button btnLogin;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_login);        etAccount=(EditText)findViewById(R.id.et_account);        etPassword=(EditText)findViewById(R.id.et_password);        btnLogin=(Button)findViewById(R.id.btn_login);        btnLogin.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (isOK(etAccount.getText().toString(), etPassword.getText().toString())) {                    Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();                } else {                    Toast.makeText(LoginActivity.this, "登录失败", Toast.LENGTH_SHORT).show();                }            }        });    }    private boolean isOK(String account, String password){        return account.equals(ACCOUNT) && password.equals(PASSWORD);    }}

布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:orientation="vertical"        android:layout_centerInParent="true">        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:gravity="center_horizontal"            android:orientation="horizontal">            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="帐号:"/>            <EditText                android:id="@+id/et_account"                android:layout_width="100dp"                android:layout_height="wrap_content" />        </LinearLayout>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:gravity="center_horizontal"            android:orientation="horizontal">            <TextView                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:text="密码:"/>            <EditText                android:id="@+id/et_password"                android:layout_width="100dp"                android:layout_height="wrap_content" />        </LinearLayout>        <Button            android:id="@+id/btn_login"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center_horizontal"            android:text="登录"/>    </LinearLayout></RelativeLayout>

签名打包 Build>Generate Signed APK:

Android逆向分析之dex2jar和jd-gui使用_第1张图片


第二步,将导出的xxx.apk文件的后缀.apk改为.zip,即压缩文件后缀,然后解压。(高版本的dex2jar貌似是不需要2,3步的,直接把APK扔到dos里,直接输入命令dex2jar xxx.apk即可)

Android逆向分析之dex2jar和jd-gui使用_第2张图片

第三步,下载dex2jar,用cmd打开dos系统,并在dex2jar所在窗口的dos位置输入 dex2jar 路径名+classes.dex,即在上图的文件夹中(不带路径,则默认在当前文件夹)生成一个.jar后缀的名字的文件。

Android逆向分析之dex2jar和jd-gui使用_第3张图片


第四步,jar文件是不可以直接看的,要用到配套的工具jd-gui.exe打开。

Android逆向分析之dex2jar和jd-gui使用_第4张图片


至此,反编译的入门工作也差不多了。可以看到,由于APK打包时没有作混淆处理,被反编译过来后,其代码的类名和成员变量名字都是没有变化的,这很容易让反编译的人看到源码,并实施恶意行为,所以在打包的时候必须要作混淆处理。

最后,我们比较一下不做和做了混淆处理后,同样经过以上步骤反编译出来的jar文件是怎样的:

不做混淆的反编译代码:

LoginActivity.java:

public class LoginActivity extends Activity{  private final String ACCOUNT = "samuel";  private final String PASSWORD = "123456";  private Button btnLogin;  private EditText etAccount;  private EditText etPassword;  private boolean isOK(String paramString1, String paramString2)  {    return (paramString1.equals("samuel")) && (paramString2.equals("123456"));  }  protected void onCreate(Bundle paramBundle)  {    super.onCreate(paramBundle);    setContentView(2130968601);    this.etAccount = ((EditText)findViewById(2131492944));    this.etPassword = ((EditText)findViewById(2131492945));    this.btnLogin = ((Button)findViewById(2131492946));    this.btnLogin.setOnClickListener(new View.OnClickListener()    {      public void onClick(View paramAnonymousView)      {        if (LoginActivity.this.isOK(LoginActivity.this.etAccount.getText().toString(), LoginActivity.this.etPassword.getText().toString()))        {          Toast.makeText(LoginActivity.this, "登录成功", 0).show();          return;        }        Toast.makeText(LoginActivity.this, "登录失败", 0).show();      }    });  }}

经过混淆处理后的反编译代码:

LoginActivity.java:

public class LoginActivity extends Activity{  private final String a = "samuel";  private final String b = "123456";  private EditText c;  private EditText d;  private Button e;  private boolean a(String paramString1, String paramString2)  {    return (paramString1.equals("samuel")) && (paramString2.equals("123456"));  }  protected void onCreate(Bundle paramBundle)  {    super.onCreate(paramBundle);    setContentView(2130968601);    this.c = ((EditText)findViewById(2131492944));    this.d = ((EditText)findViewById(2131492945));    this.e = ((Button)findViewById(2131492946));    this.e.setOnClickListener(new a(this));  }}

a.java:

class a  implements View.OnClickListener{  a(LoginActivity paramLoginActivity)  {  }  public void onClick(View paramView)  {    if (LoginActivity.a(this.a, LoginActivity.a(this.a).getText().toString(), LoginActivity.b(this.a).getText().toString()))    {      Toast.makeText(this.a, "登录成功", 0).show();      return;    }    Toast.makeText(this.a, "登录失败", 0).show();  }}

比较可看到,混淆过的代码中,关键的变量名都被a, b, c, d等字母代替了,其中button的匿名内部监听类由View.OnClickListener类变成了a类。这样一来,混淆过的代码就没有那么容易受到恶意攻击了。但貌似还是有办法反混淆的,所以也没有百分百的安全吧。


反编译工具下载:dex2jar & jd-gui


更多相关文章

  1. android 调用系统文件管理器
  2. Android运行时权限,6.0—9.0多版本,多终端(手机,TV盒子)130行代码一劳
  3. 从零开始--系统深入学习android(实践-让我们开始写代码-Android框
  4. android 使用handler更新ui,使用与原理分析详解(附上代码以及截图)
  5. 【Android 开发入门】我为什么要在Android找工作越来越难的时候
  6. Android 为【apk】文件签名,增加修改系统时间等权限
  7. 1、android源代码下载与跟踪
  8. android经典开源代码集合

随机推荐

  1. 个人自制unity插件"android动态权限自动
  2. Android(安卓)实现让ViewPager禁止滑动
  3. Android应用之Hybird混合开发,集成web页面
  4. 如何配置android adb環境變量
  5. Android(安卓)NDK开发(二)——CMake脚本
  6. android studio快捷键记录
  7. binder 实例分析
  8. 2020年中高级Android大厂面试秘籍,为你保
  9. Android窗口小部件开发
  10. android学习轨迹之三:图片浏览+拨号程序总