实例具体解释:反编译Android APK,改动字节码后再回编译成APK

本文具体介绍了怎样反编译一个未被混淆过的Android APK,改动smali字节码后,再回编译成APK并更新签名,使之可正常安装。破译后的apk不管输入什么样的username和password都能够成功进入到第二个Activity。

有时难免要反编译一个APK。改动当中的若干关键推断点,然后再回编译成一个全新的可用的apk,这全然是可实现的。

若要完毕上述工作,须要以下工具,杂家后面会把下载链接也附上。这些软件截止本文公布时,经过杂家确认都是最新的版本号。

1.APK-Multi-Toolv1.0.11.zip 用它来反编译apk,得到smali类型的源代码和资源文件。一般来讲,直接解压缩一个apk也能够看到其资源文件。但部分xml是不可阅读的,需用此工具反编译。网上流传较广的是一个经过高人汉化过的版本号1.0.3。第一次使用这个工具能够用这个汉化的版本号,熟悉其命令。

但经过杂家測试,这个汉化的版本号再回编译apk签名时已经出问题了。签不了,终于用的最新版才ok。

2.dex2jar-0.0.9.15.zip 用于将一个apk文件转换成jar类型的文件,转换之后再利用以下的jd-gui工具才干看到其java代码。上面的apk-tool固然强大,可是反编译出来是smali文件。即dalvik字节码,相似汇编语言的一种代码。直接阅读如天书一样。为此我们须要使用dex2jar + jd-gui来得到其java代码,进行阅读找到要改动的关键点。

3.jd-gui-0.3.6.windows.zip 能够打开一个jar类型的文件,看到java代码。并能将代码保存,保存后再弄到sourceinsight里就方便看了。最好使用本文所说的最新版本号。使用老版本号会发现一个BActivity,假设里面有内部类,则又多出一个BActivity$1.java。相似这样的文件。新版本号没这个问题。

4.Smali2Java.1.0.0.558.zip 用于将smali文件转成java文件,这个工具仅仅是备用。

由于用上面三个工具已经能够胜任本文的要求了。

假设第一次接触反编译,不了解smali语法,能够阅读链接1  链接2

以下杂家先上一个Android APK。用来简单模拟用户登录的情况。注意仅仅能是模拟哈。由于正式的apk非常少有在本地进行推断的。此apk要求用户输入username和password,假设username为yanzi,password为123,则觉得合法,自己主动跳转到第二个Activity。否则提示username或password不对。

LoginActivity.java

package org.yanzi.decomdemo.activity;

import org.yanzi.decompiledemo.R;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class LoginActivity extends Activity {

	EditText loginName = null;
	EditText loginPswd = null;
	Button loginBtn = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_login);
		initUI();
		loginBtn.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
               if(isAllowLogin()){
            	   Intent intent = new Intent(LoginActivity.this, SecondActivity.class);
            	   startActivity(intent);
            	   LoginActivity.this.finish();
               }
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.login, menu);
		return true;
	}
	private void initUI(){
		loginName = (EditText)findViewById(R.id.edit_login_name);
		loginPswd = (EditText)findViewById(R.id.edit_login_pswd);
		loginBtn = (Button)findViewById(R.id.btn_login);
	}
	private boolean isAllowLogin(){
		String name = loginName.getText().toString().trim();
		String pswd = loginPswd.getText().toString().trim();
		if(name != null  && pswd != null){
			if(name.equals("") || pswd.equals("")){
				Toast.makeText(this, "password或username不能为空", Toast.LENGTH_SHORT).show();
				return false;
			}
		}
		if(name.equals("yanzi") && pswd.equals("123")){
			return true;
		}else{
			Toast.makeText(getApplicationContext(), "username或password不符", Toast.LENGTH_SHORT).show();
		}
		return false;
	}

}

SecondActivity.java

package org.yanzi.decomdemo.activity;

import org.yanzi.decompiledemo.R;
import org.yanzi.decompiledemo.R.layout;
import org.yanzi.decompiledemo.R.menu;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class SecondActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_second);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.second, menu);
		return true;
	}

}

布局文件和其它代码都比較简单就不介绍了。运行界面例如以下:

当中推断username和password是否合法的关键函数例如以下:

private boolean isAllowLogin(){
		String name = loginName.getText().toString().trim();
		String pswd = loginPswd.getText().toString().trim();
		if(name != null  && pswd != null){
			if(name.equals("") || pswd.equals("")){
				Toast.makeText(this, "password或username不能为空", Toast.LENGTH_SHORT).show();
				return false;
			}
		}
		if(name.equals("yanzi") && pswd.equals("123")){
			return true;
		}else{
			Toast.makeText(getApplicationContext(), "username或password不符", Toast.LENGTH_SHORT).show();
		}
		return false;
	}

如今假设我们根本不知道上面的代码,就是一个apk拿到手,怎样破译呢?

第一步:dex2jar 将apk转成jar

须要将apk文件复制到dex2jar解压缩后的目录。cmd进去该目录,输入命令:

G:\反编译工具\dex2jar-0.0.9.15>d2j-dex2jar.bat G:\反编译工具\dex2jar-0.0.9.15\DecompileDemo.apk

注意apk的路径是拖apk进去的。按回车,得到jar。如图所看到的:



watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuemkxMjI1NjI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" />

第二步:jd-gui打开此jar文件,如图所看到的:

能够看到反编译出来的java代码跟原来的代码相差无几,但还是有点小区别,把R.id.....换成了具体的数字,另外是非常多地方多加了this指针。包含内部类调用父亲的私有函数上。再就是{}原来不换行的,如今换行了。后面会发现,代码所在的行号对破译改动smali文件是个非常实用的信息。在jd-gui里是不能对代码进行改动的。能够ctrl+s将其所有保存,得到一个压缩文件。再解压缩。弄到sourceInsight里能够慢慢看了。等等,在看Activity的代码时。要结合APK TOOL里反编译出来的Manifinest.xml来看。由于通过xml至少能够看到一个工程的启动Activity是谁。程序从哪进去的,有几个Activity。又是怎么跳转的。

第三步:APK TOOL反编译出smali文件,研读smali文件,并进行改动

单纯依靠上面两个步骤尽管得到java,可是是无法进行改动的。并且就算你改动了当中的java文件,是无法再返回去生成apk的。有人说先弄成class,再弄成.dex,最后进行替换,这个基本不可能。第二种思路是,仿照这个java文件老子再重写一份。这个假设项目简单能够这么搞,这样的话反编译的目的就是看代码,而非破译了,由于你重写了一份。

所以。唯一可行的就是直接改动smali文件。首先运行APK-Multi-Tool目录下的Setup.bat,

这里须要运行的事实上仅仅有第三个步骤。生成相应的目录。第一个检查更新。第二个是安装框架资源,这个除非你是搞rom的,否则的话破译一般的非系统apk是用不到的。运行3步骤后。能够看到目录多了好几个:

红框里的五个目录都是新增的。须要将待反编译的apk放到place-apk-here-for-modding目录下,反编译后的源代码在projects目录下。知道这就够用了。

首先把apk拷到place-apk-here-for-modding目录下。然后运行Script.bat,首先映入眼帘的是一堆相似乱码的东西,不用管,enter后看到主界面:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveWFuemkxMjI1NjI3/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" />

最上面的一栏相似状态栏,再往下能够看到这个工具的功能分三大部分:Simple Tasks Such As Image Editing(假设改动了图片资源或文字)就运行此模块的命令。 Advanced Tasks Such As Code Editing(高级模式。如改动了源代码),一般我们破译apk须要的是这部分。最后一个模块是Themers Convertion Tools。这个杂家么实用到。

以下是 tools Stuff工具集合,我们按下24 Set current project设置当前工程,选中相应的apk就可以。然后按9 Decompile apk,反编译apk,注意看标题栏里的状态是:

Decompile : Sources and Resources Files即反编译源代码和资源,我们须要的就是这样的模式。反编译结束后再projects目录里找到输出结果:

smali就是待改动的dalvik 字节码文件:

能够看到多了一个****$1.smali的文件,这是由于button设置监听引入了内部类造成的。能够不用管。

这样的带$1的文件,一般表示内部的如按键监听这样的属性关系。并没有太多事物的处理逻辑。打开LoginActivity.smali文件。找到以下这段话:

.method private isAllowLogin()Z

.locals 5

.prologue

const/4 v2, 0x0

.line 51

iget-object v3, p0, Lorg/yanzi/decomdemo/activity/LoginActivity;->loginName:Landroid/widget/EditText;

invoke-virtual {v3}, Landroid/widget/EditText;->getText()Landroid/text/Editable;

move-result-object v3

invoke-interface {v3}, Landroid/text/Editable;->toString()Ljava/lang/String;

move-result-object v3

invoke-virtual {v3}, Ljava/lang/String;->trim()Ljava/lang/String;

move-result-object v0

.line 52

.local v0, name:Ljava/lang/String;

iget-object v3, p0, Lorg/yanzi/decomdemo/activity/LoginActivity;->loginPswd:Landroid/widget/EditText;

invoke-virtual {v3}, Landroid/widget/EditText;->getText()Landroid/text/Editable;

move-result-object v3

invoke-interface {v3}, Landroid/text/Editable;->toString()Ljava/lang/String;

move-result-object v3

invoke-virtual {v3}, Ljava/lang/String;->trim()Ljava/lang/String;

move-result-object v1

.line 53

.local v1, pswd:Ljava/lang/String;

if-eqz v0, :cond_1

if-eqz v1, :cond_1

.line 54

const-string v3, ""

invoke-virtual {v0, v3}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

move-result v3

if-nez v3, :cond_0

const-string v3, ""

invoke-virtual {v1, v3}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

move-result v3

if-eqz v3, :cond_1

.line 55

:cond_0

const-string v3, "\u5bc6\u7801\u6216\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a"

invoke-static {p0, v3, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

move-result-object v3

invoke-virtual {v3}, Landroid/widget/Toast;->show()V

.line 64

:goto_0

return v2

.line 59

:cond_1

const-string v3, "yanzi"

invoke-virtual {v0, v3}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

move-result v3

if-eqz v3, :cond_2

const-string v3, "123"

invoke-virtual {v1, v3}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z

move-result v3

if-eqz v3, :cond_2

.line 60

const/4 v2, 0x1

goto :goto_0

.line 62

:cond_2

invoke-virtual {p0}, Lorg/yanzi/decomdemo/activity/LoginActivity;->getApplicationContext()Landroid/content/Context;

move-result-object v3

const-string v4, "\u7528\u6237\u540d\u6216\u5bc6\u7801\u4e0d\u7b26"

invoke-static {v3, v4, v2}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;

move-result-object v3

invoke-virtual {v3}, Landroid/widget/Toast;->show()V

goto :goto_0

.end method

注意看。方法是以.method开头的,Z表示boolean类型。以下再把jd-gui里破译出来的java代码附下:

private boolean isAllowLogin()

{

String str1 = this.loginName.getText().toString().trim();

String str2 = this.loginPswd.getText().toString().trim();

if ((str1 != null) && (str2 != null) && ((str1.equals("")) || (str2.equals(""))))

{

Toast.makeText(this, "password或username不能为空", 0).show();

return false;

}

if ((str1.equals("yanzi")) && (str2.equals("123"))) {

return true;

}

Toast.makeText(getApplicationContext(), "username或password不符", 0).show();

return false;

}

既然是破译。那么这两个代码就是最有力的线索了。

另外,由于dalvik字节码是基于寄存器的,所有的变量处理都要经过寄存器。而寄存器又分为两大类:本地寄存器和參数寄存器。本地寄存器使用v0 v1这样的方式命名。函数的开头.locals 5 也声明了要用5个本地寄存器,从v0到v4.參数寄存器是从p0開始。由于我们这个函数是没有參数传进来的。原则上是不使用參数寄存器的。可是它是非static的。凡是非static就又this这个指针。默认的使用p0来代表。p1才是函数输入的第一个參数。假设是static类型的函数,则p0就是第一个參数。

.prologue是开场白的意思,const/4 v2, 0x0 表示声明一个本地变量里面放的是0。由于我们的isAllowLogin()函数原来的java代码里有三个return。但在smali里仅仅有一个return,且return的就是v2这个变量。

找到 例如以下三句:

.line 64

:goto_0

return v2

仅仅有这一个return,且是加了标签goto_0,搜索goto_0能够看到有两个地方都运行了goto :goto_0,即也让它返回v2.当中。在推断username和password复合要求的时候,它对v2这个变量进行了赋值:

const/4 v2, 0x1

这个意思就是把v2置为了true,并进行返回。至此,为了实现破解。仅仅需把v2变量声明的时候直接默认值改成0x1不就ok了。如此改动后,回到APK TOOL,

点击15    Compile apk / Sign apk / Install apk  (Non-System Apps Only)。这个能够直接将源代码回编译成apk,并且加入签名再安装。但此处有个问题,这里的安装还是安装的原来的apk文件,选中此命令运行后,在刚才的place-apk-here-for-modding目录能够看到:

此处的signedDecompileDemo.apk就是回编译出来的apk文件。将这个apk安装才干看到改动smali后的效果。至此。大功告成。但,本文仅仅是抛砖引玉。破译的关键还是要看smali语言的功底,和对整个代码的理解,找到正确的破译点。

1.APK-Multi-Toolv1.0.11.zip:http://download.csdn.net/detail/yanzi1225627/7728439

2.dex2jar-0.0.9.15.zip:http://download.csdn.net/detail/yanzi1225627/7728447

3.jd-gui-0.3.6.windows.zip: http://download.csdn.net/detail/yanzi1225627/7728453

4.Smali2Java.1.0.0.558.zip:http://download.csdn.net/detail/yanzi1225627/7728477

时间: 2024-08-06 03:45:44

实例具体解释:反编译Android APK,改动字节码后再回编译成APK的相关文章

实例详解:反编译Android APK,修改字节码后再回编译成APK

本文详细介绍了如何反编译一个未被混淆过的Android APK,修改smali字节码后,再回编译成APK并更新签名,使之可正常安装.破译后的apk无论输入什么样的用户名和密码都可以成功进入到第二个Activity. 有时难免要反编译一个APK,修改其中的若干关键判断点,然后再回编译成一个全新的可用的apk,这完全是可实现的.若要完成上述工作,需要以下工具,杂家后面会把下载链接也附上.这些软件截止本文发布时,经过杂家确认都是最新的版本. 1.APK-Multi-Toolv1.0.11.zip 用它

[Android 编译(一)] Ubuntu 16.04 LTS 成功编译 Android 6.0 源码教程

本文转载自:[Android 编译(一)] Ubuntu 16.04 LTS 成功编译 Android 6.0 源码教程 1 前言 经过3天奋战,终于在Ubuntu 16.04上把Android 6.0的源码编译出来了,各种配置,各种error,各种爬坑,特写此博客记录爬坑经历.先上图,Ubuntu上编译完后成功运行模拟器,如图: 2 编译环境 UbuntuKylin 16.04 LTS Android 6.0_r1 Open JDK 7 3 准备工作 (1) 下载android 6.0源码.

Ubuntu 16.04 LTS 成功编译 Android 6.0 源码教程 (转)

1 前言 经过3天奋战,终于在Ubuntu 16.04上把Android 6.0的源码编译出来了,各种配置,各种error,各种爬坑,特写此博客记录爬坑经历.先上图,Ubuntu上编译完后成功运行模拟器,如图: 2 编译环境 UbuntuKylin 16.04 LTS Android 6.0_r1 Open JDK 7 3 准备工作 (1) 下载Android 6.0源码. Androdi 6.0源码下载地址: http://pan.baidu.com/s/1o6N86a2 感谢下面这位博主上传

Android 从java字节码告诉你 为什么Handler会造成内存泄露

很多人面试的时候,都知道Handler 极易造成内存泄露,但是有一些讲不出来为什么,好一点的 会告诉你looper msg 之类的,但是你再往下问 为什么msg持有handler handler为什么 持有activity'的引用的时候 他们就答不出来了.这里我通过几个简单的例子 和极少部分的源码 来帮助大家彻底理解这一个流程. 那首先 我们来看一个例子,首先定义1个外部类 一个内部类: 1 package com.test.zj; 2 3 public class OuterClass { 4

【转】Android 4.4源码下载与编译

原文网址:http://www.cnblogs.com/zhx831/p/3550830.html 这篇文章记录了我下载源码和编译的全过程, 全过程参考Android官方文档 1. 下载Android源码 1.1 安装repo $ mkdir ~/bin $ PATH=~/bin:$PATH $ curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ~/bin/repo $ chmod a+x ~/bin/r

MAC上反编译android apk---apktool, dex2jar, jd-jui安装使用(含手动签名)

前文 介绍了在Windows平台利用强大的APK-Multi-Tool进行反编译apk,修改smali源码后再回编译成apk的流程,最近受人之托,破解个apk,所幸的是所用到的这三个软件都是跨平台的,mac上也妥妥的.这里记录下在mac上所用的东西和流程. 总共需要三个软件,为了便于找到最新的版本,把官网也放后面: Apktool:http://ibotpeaches.github.io/Apktool/install/ 最新版本2.0.1 dex2jar: https://github.com

MAC上反编译android apk-apktool, dex2jar, jd-jui安装使用

前文 介绍了在Windows平台利用强大的APK-Multi-Tool进行反编译apk,修改smali源码后再回编译成apk的流程,最近受人之托,破解个apk,所幸的是所用到的这三个软件都是跨平台的,mac上也妥妥的.这里记录下在mac上所用的东西和流程. 总共需要三个软件,为了便于找到最新的版本,把官网也放后面: Apktool:最新版本2.0.1 dex2jar: 最新版本2.0 JD-GUI: 最新版本1.4.0 这三个软件Apktool的安装稍微麻烦点,其他都还好,基本上下载下来解压了就

转:Android开发实践:用脚本编译Android工程

转自: http://ticktick.blog.51cto.com/823160/1365947 一般情况下,我们都是使用Eclipse+ADT插件或者Android studio软件来编译Android工程的,其实,Eclipse或者Android studio仅仅是将一些编译命令封装到可视化界面里而已,通过shell脚本.ADT附带的一些命令以及Ant工具,我们完全可以将Android工程的编译过程自动化,直接通过运行脚本就得到最终的APK文件. Linux下用脚本编译c/c++程序至少需

[Android编译(二)] 从谷歌官网下载android 6.0源码、编译并刷入nexus 6p手机

1 前言 经过一周的奋战,终于从谷歌官网上下载最新的android 6.0.1_r62源码,编译成功,并成功的刷入nexus6p,接着root完毕,现写下这篇博客记录一下实践过程. 2 简介 自己下载android系统源码,修改定制,然后编译刷入安卓手机,想想还有点小激动呢.简单点说一句话--定制我们自己的MIUI,这就是android的魅力,这篇博客博主就来教大家实现自己的定制系统. 首先,要明白下面的基础知识: (1) 什么是aosp? aosp就是android open source p