2.分析Android程序

来源:互联网 发布:原油投资网络骗局 编辑:程序博客网 时间:2024/06/05 08:13

分析Android程序四要素:   Android程序开发流程程序结构语句分支解密原理

一、编写Crackme 

1.新建一个Android工程,需要有MainActivity

2.res\values\strings.xml 增加 info、username、hint_username、sn、hini_sn、register、registered、unsuccessed、successed 这几个字段

<?xml version="1.0" encoding="utf-8"?><resources>    <string name="app_name">Crackme0201</string>    <string name="hello_world">Hello world!</string>    <string name="action_settings">Settings</string><string name="info">Android程序破解演示程序</string><string name="username">用户名:</string><string name="hint_username">请输入用户名</string><string name="sn">注册码:</string><string name="hint_sn">请输入注册码</string><string name="register">注册</string><string name="registered">程序已注册</string><string name="unsuccessed">无效用户名或注册码</string><string name="successed">恭喜您!注册成功</string></resources>
3.res\layout\activity_main.xml 如下
<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <TextView         android:id="@+id/textView1"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:gravity="center"        android:text="@string/info"        android:textSize="20dp"/>    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="10dp"        android:orientation="horizontal">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@string/username"/>        <EditText            android:id="@+id/edit_username"            android:hint="@string/hint_username"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_marginLeft="10dp"            android:layout_marginRight="10dp"            android:layout_weight="1"            android:ems="10"/>"    </LinearLayout>    <LinearLayout         android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_marginLeft="10dp"        android:orientation="horizontal">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@string/sn"/>        <EditText            android:id="@+id/edit_sn"            android:hint="@string/hint_sn"            android:layout_width="0dp"            android:layout_height="wrap_content"            android:layout_marginLeft="10dp"            android:layout_marginRight="10dp"            android:layout_weight="1"            android:ems="10"/>"    </LinearLayout>    <Button        android:id="@+id/button_register"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginRight="10dp"        android:layout_gravity="right"        android:text="@string/register"/></LinearLayout>

布局效果如图:

4.MainActivity 编码 (在OnCreate中为按钮 "注册" 绑定OnClick事件,取出EditText中的用户名和注册码,调用checkSN传入用户名计算出16位的注册码与输入的注册码比较

  一致(忽略大小写)则提示注册成功,否则失败! ):

package com.droider.crackme0201;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.Toast;public class MainActivity extends ActionBarActivity {private EditText edit_userName;private EditText edit_sn;private Button btn_register;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                setTitle(R.string.unsuccessed);        edit_userName=(EditText)findViewById(R.id.edit_username);        edit_sn=(EditText)findViewById(R.id.edit_sn);        btn_register=(Button)findViewById(R.id.button_register);        btn_register.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubif(!checkSN(edit_userName.getText().toString().trim(),edit_sn.getText().toString().trim())){Toast.makeText(MainActivity.this,R.string.unsuccessed,Toast.LENGTH_SHORT).show();}else{Toast.makeText(MainActivity.this,R.string.successed,Toast.LENGTH_SHORT);btn_register.setEnabled(false);setTitle(R.string.registered);}}                });    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Incflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        // Handle action bar item clicks here. The action bar will        // automatically handle clicks on the Home/Up button, so long        // as you specify a parent activity in AndroidManifest.xml.        int id = item.getItemId();        if (id == R.id.action_settings) {            return true;        }        return super.onOptionsItemSelected(item);    }        private boolean checkSN(String userName,String sn){    try{    if((userName==null) ||    (userName.length()==0))    return false;    if((sn==null) ||    (sn.length()==0))    return false;    MessageDigest digest=MessageDigest.getInstance("MD5");    digest.reset();    digest.update(userName.getBytes());    byte[] bytes=digest.digest();    String hexstr=toHexString(bytes,"");    StringBuilder sb=new StringBuilder();    for(int i=0;i<hexstr.length();i+=2){    sb.append(hexstr.charAt(i));    }    String userSN=sb.toString();    if(!userSN.equalsIgnoreCase(sn))    return false;    }catch(NoSuchAlgorithmException e)    {    e.printStackTrace();    return false;    }    return true;    }    private static String toHexString(byte[] bytes, String separator) {        StringBuilder hexString = new StringBuilder();        for (byte b : bytes) {            String hex = Integer.toHexString(0xFF & b);            if(hex.length() == 1){                hexString.append('0');            }            hexString.append(hex).append(separator);        }        return hexString.toString();    }}

5.编译运行,用户名输入1,输入错误的注册码r,点击注册 提示 无效的用户名或注册码。


二、反编译Android程序

1. 利用ShakaApktool_2.0.0.jar 反编译 crackme02.apk

命令行:  java -jar ShakaApktool_2.0.0.jar d crackme02.apk

执行命令成功后,apk同目录中会出现一个同名文件夹 crackme02 ,反编译完成。


crackme02文件夹:


2.利用错误提示"无效用户或注册码"找到引用这个字符串的name

字符串位于crackme02\res\values\strings.xml 中,即它的name为unsuccessed。

<?xml version="1.0" encoding="utf-8"?><resources>
    <string name="unsuccessed">无效用户名或注册码</string>
</resources>

3.查找字符串的ID

但是代码中引用的为字符串的ID,在编码过程中通过 R.java 来标识字符串的ID,而在反编译得到的代码中 ,ID是在crackme02\res\values\public.xml 中。

 从public.xml中找到 ,即字符串 unsuccessed的ID为 0x7f0a0017。

<?xml version="1.0" encoding="utf-8"?><resources>    <public type="string" name="unsuccessed" id="0x7f0a0017" /></resources>

4.查找引用这个ID的smali代码

然后再在 crackme02\smali\com\droider\crackme0201 文件夹中的smali文件中查找引用  0x7f0a0017 的代码。

找到 MainActivity$1.smali 中有一处引用了 0x7f0a0017  ,可以看出在 .line36 调用 checkSN 计算并比较注册码,返回值存在v0寄存器中,

.line37 如果返回值不为0则跳转到 cond_0 (注册成功) 继续执行,否则将顺序执行 .line 38 .line 39 的代码。

在 .line 39 引用了 unsuccessed 的字符串。

 .line 36    # invokes: Lcom/droider/crackme0201/MainActivity;->checkSN(Ljava/lang/String;Ljava/lang/String;)Z    invoke-static {v0, v1, v2}, Lcom/droider/crackme0201/MainActivity;->access$2(Lcom/droider/crackme0201/MainActivity;Ljava/lang/String;Ljava/lang/String;)Z    move-result v0    .line 37    if-nez v0, :cond_0    .line 38    iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->this$0:Lcom/droider/crackme0201/MainActivity;    .line 39    const v1, 0x7f0a0017    .line 38    invoke-static {v0, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;    move-result-object v0    .line 39    invoke-virtual {v0}, Landroid/widget/Toast;->show()V    .line 46    :goto_0    return-void

三、修改smali代码,实现破解crackme。

1.修改smali代码,将 .line 37 的 if-nez 改为  if-eqz ,即不为0跳转改为为0时跳转。

 .line 36    # invokes: Lcom/droider/crackme0201/MainActivity;->checkSN(Ljava/lang/String;Ljava/lang/String;)Z    invoke-static {v0, v1, v2}, Lcom/droider/crackme0201/MainActivity;->access$2(Lcom/droider/crackme0201/MainActivity;Ljava/lang/String;Ljava/lang/String;)Z    move-result v0    .line 37    if-eqz v0, :cond_0    .line 38    iget-object v0, p0, Lcom/droider/crackme0201/MainActivity$1;->this$0:Lcom/droider/crackme0201/MainActivity;    .line 39    const v1, 0x7f0a0017    .line 38    invoke-static {v0, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;    move-result-object v0    .line 39    invoke-virtual {v0}, Landroid/widget/Toast;->show()V    .line 46    :goto_0    return-void

2.重新编译修改后的代码,在原来执行命令的apk文件的目录执行命令

命令行: java -jar apktool.jar b crackme02 -o crackme02_repack.apk

成功执行后将会得到一个新的apk文件   crackme02_repack.apk。

这里用的是 apktool.jar,也可以使用ShakaApktool。

3.给新的apk签名

命令行:java -jar signapk.jar platform.x509.pem platform.pk8 crackme02_repack.apk crackme02_repack_signed.apk

成功执行后将会得到一个新的apk文件 crackme02_repack_signed.apk

4.安装测试,注册成功了。


0 0
原创粉丝点击