学习破解一个Android步伐

打印 上一主题 下一主题

主题 895|帖子 895|积分 2685

起首编写一个android测试步伐

功能:校验用户名和注册码,成功则弹出注册成功提示
以下仅给出关键部分的代码
res/layout/activity_main.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:layout_width="fill_parent"
  4.     android:layout_height="fill_parent"
  5.     android:orientation="vertical">
  6.     <TextView
  7.         android:id="@+id/textView1"
  8.         android:layout_width="match_parent"
  9.         android:layout_height="wrap_content"
  10.         android:gravity="center"
  11.         android:text="@string/info"
  12.         android:textSize="20dp" />
  13.     <LinearLayout
  14.         android:layout_width="match_parent"
  15.         android:layout_height="wrap_content"
  16.         android:layout_marginLeft="10dp"
  17.         android:orientation="horizontal">
  18.         <TextView
  19.             android:layout_width="wrap_content"
  20.             android:layout_height="wrap_content"
  21.             android:text="@string/username" />
  22.         <EditText
  23.             android:id="@+id/edit_username"
  24.             android:layout_width="0dp"
  25.             android:layout_height="wrap_content"
  26.             android:layout_marginLeft="10dp"
  27.             android:layout_marginRight="10dp"
  28.             android:layout_weight="1"
  29.             android:ems="10"
  30.             android:hint="@string/hint_username"></EditText>
  31.     </LinearLayout>
  32.     <LinearLayout
  33.         android:layout_width="match_parent"
  34.         android:layout_height="wrap_content"
  35.         android:layout_marginLeft="10dp"
  36.         android:orientation="horizontal">
  37.         <TextView
  38.             android:layout_width="wrap_content"
  39.             android:layout_height="wrap_content"
  40.             android:text="@string/sn" />
  41.         <EditText
  42.             android:id="@+id/edit_sn"
  43.             android:layout_width="0dp"
  44.             android:layout_height="wrap_content"
  45.             android:layout_marginLeft="10dp"
  46.             android:layout_marginRight="10dp"
  47.             android:layout_weight="1"
  48.             android:ems="10"
  49.             android:hint="@string/hint_sn"></EditText>
  50.     </LinearLayout>
  51.     <Button
  52.         android:id="@+id/button_register"
  53.         android:layout_width="wrap_content"
  54.         android:layout_height="wrap_content"
  55.         android:layout_gravity="right"
  56.         android:layout_marginRight="10dp"
  57.         android:text="@string/register" />
  58. </LinearLayout>
复制代码
java/com/example/myapplication/MainActivity.java
  1. package com.example.myapplication;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.Menu;
  5. import android.view.View;
  6. import android.view.View.OnClickListener;
  7. import android.widget.Button;
  8. import android.widget.EditText;
  9. import android.widget.Toast;
  10. import java.security.MessageDigest;
  11. import java.security.NoSuchAlgorithmException;
  12. public class MainActivity extends Activity {
  13.     private EditText edit_userName;
  14.     private EditText edit_sn;
  15.     private Button btn_register;
  16.     @Override
  17.     public void onCreate(Bundle savedInstanceState) {
  18.         super.onCreate(savedInstanceState);
  19.         setContentView(R.layout.activity_main);
  20.         setTitle(R.string.unregister);  //模拟程序未注册
  21.         edit_userName = (EditText) findViewById(R.id.edit_username);
  22.         edit_sn = (EditText) findViewById(R.id.edit_sn);
  23.         btn_register = (Button) findViewById(R.id.button_register);
  24.         btn_register.setOnClickListener(new OnClickListener() {
  25.             public void onClick(View v) {
  26.                 if (!checkSN(edit_userName.getText().toString().trim(),
  27.                         edit_sn.getText().toString().trim())) {
  28.                     Toast.makeText(MainActivity.this,       //弹出无效用户名或注册码提示
  29.                             R.string.unsuccessed, Toast.LENGTH_SHORT).show();
  30.                 } else {
  31.                     Toast.makeText(MainActivity.this,       //弹出注册成功提示
  32.                             R.string.successed, Toast.LENGTH_SHORT).show();
  33.                     btn_register.setEnabled(false);
  34.                     setTitle(R.string.registered);  //模拟程序已注册
  35.                 }
  36.             }
  37.         });
  38.     }
  39.     @Override
  40.     public boolean onCreateOptionsMenu(Menu menu) {
  41.         getMenuInflater().inflate(R.menu.activity_main, menu);
  42.         return true;
  43.     }
  44.     private boolean checkSN(String userName, String sn) {
  45.         try {
  46.             if ((userName == null) || (userName.length() == 0))
  47.                 return false;
  48.             if ((sn == null) || (sn.length() != 16))
  49.                 return false;
  50.             MessageDigest digest = MessageDigest.getInstance("MD5");
  51.             digest.reset();
  52.             digest.update(userName.getBytes());
  53.             byte[] bytes = digest.digest();     //采用MD5对用户名进行Hash
  54.             String hexstr = toHexString(bytes, ""); //将计算结果转化成字符串
  55.             StringBuilder sb = new StringBuilder();
  56.             for (int i = 0; i < hexstr.length(); i += 2) {
  57.                 sb.append(hexstr.charAt(i));
  58.             }
  59.             String userSN = sb.toString(); //计算出的SN
  60.             //Log.d("crackme", hexstr);
  61.             //Log.d("crackme", userSN);
  62.             if (!userSN.equalsIgnoreCase(sn))   //比较注册码是否正确
  63.                 return false;
  64.         } catch (NoSuchAlgorithmException e) {
  65.             e.printStackTrace();
  66.             return false;
  67.         }
  68.         return true;
  69.     }
  70.     private static String toHexString(byte[] bytes, String separator) {
  71.         StringBuilder hexString = new StringBuilder();
  72.         for (byte b : bytes) {
  73.             String hex = Integer.toHexString(0xFF & b);
  74.             if (hex.length() == 1) {
  75.                 hexString.append('0');
  76.             }
  77.             hexString.append(hex).append(separator);
  78.         }
  79.         return hexString.toString();
  80.     }
  81. }
复制代码

运行没有问题之后,通过AndroidStudio编译成apk文件
开始破解步伐

破解 Android 步伐通常的方法是将 apk 文件利用 ApkTool 反编译,生成 Smali 格式的反汇编代码,然后阅读 Smali 文件的代码来理解步伐的运行机制,找到步伐的突破口举行修改,最后利用 ApkTool 重新编译生成 apk 文件并签名,最后运行测试,如此循环,直至步伐被成功破解。
利用apk-tool反编译apk步伐
下载地址:https://down.52pojie.cn/Tools/Android_Tools/apktool_2.9.3.jar
实行
  1. java -jar apktool_2.9.3.jar d -f app-debug.apk -o output
复制代码

smail目录下存放了步伐的全部反汇编代码,res目录下则是步伐的全部资源文件
先通过res\values\string.xml定位步伐的错误信息
  1. <resources>
  2. ...
  3.     <string name="unsuccessed">无效用户名或注册码</string>
  4. ...
  5. </resources>
复制代码
再通过同目录下的public.xml找到name="unsuccessed"的id
  1. [/code]通过该id可以到smail目录搜索,在output\smali_classes3\com\example\myapplication\MainActivity$1.smali搜索到一处结果
  2. [code]   91      iget-object v0, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
  3.    92  
  4.    93:     const v2, 0x7f1000a5
  5.    94  
  6.    95      invoke-static {v0, v2, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;
复制代码
onclick方法
  1. # virtual methods
  2. .method public onClick(Landroid/view/View;)V
  3.     .locals 3
  4.     .param p1, "v"    # Landroid/view/View;
  5.     .line 31
  6.     iget-object v0, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
  7.     invoke-static {v0}, Lcom/example/myapplication/MainActivity;->access$000(Lcom/example/myapplication/MainActivity;)Landroid/widget/EditText;
  8.     move-result-object v1
  9.     invoke-virtual {v1}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
  10.     move-result-object v1
  11.     invoke-virtual {v1}, Ljava/lang/Object;->toString()Ljava/lang/String;
  12.     move-result-object v1
  13.     invoke-virtual {v1}, Ljava/lang/String;->trim()Ljava/lang/String;
  14.     move-result-object v1
  15.     iget-object v2, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
  16.     .line 32
  17.     invoke-static {v2}, Lcom/example/myapplication/MainActivity;->access$100(Lcom/example/myapplication/MainActivity;)Landroid/widget/EditText;
  18.     move-result-object v2
  19.     invoke-virtual {v2}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
  20.     move-result-object v2
  21.     invoke-virtual {v2}, Ljava/lang/Object;->toString()Ljava/lang/String;
  22.     move-result-object v2
  23.     invoke-virtual {v2}, Ljava/lang/String;->trim()Ljava/lang/String;
  24.     move-result-object v2
  25.     .line 31
  26.     invoke-static {v0, v1, v2}, Lcom/example/myapplication/MainActivity;->access$200(Lcom/example/myapplication/MainActivity;Ljava/lang/String;Ljava/lang/String;)Z
  27.     move-result v0
  28.     const/4 v1, 0x0
  29.     if-nez v0, :cond_0 # 关键条件判断
  30.     .line 33
  31.     iget-object v0, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
  32.     const v2, 0x7f1000a5
  33.     invoke-static {v0, v2, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;
  34.     move-result-object v0
  35.     .line 34
  36.     invoke-virtual {v0}, Landroid/widget/Toast;->show()V
  37.     goto :goto_0
  38.     .line 36
  39.     :cond_0
  40.     iget-object v0, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
  41.     const v2, 0x7f1000a2
  42.     invoke-static {v0, v2, v1}, Landroid/widget/Toast;->makeText(Landroid/content/Context;II)Landroid/widget/Toast;
  43.     move-result-object v0
  44.     .line 37
  45.     invoke-virtual {v0}, Landroid/widget/Toast;->show()V
  46.     .line 38
  47.     iget-object v0, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
  48.     invoke-static {v0}, Lcom/example/myapplication/MainActivity;->access$300(Lcom/example/myapplication/MainActivity;)Landroid/widget/Button;
  49.     move-result-object v0
  50.     invoke-virtual {v0, v1}, Landroid/widget/Button;->setEnabled(Z)V
  51.     .line 39
  52.     iget-object v0, p0, Lcom/example/myapplication/MainActivity$1;->this$0:Lcom/example/myapplication/MainActivity;
  53.     const v1, 0x7f100099
  54.     invoke-virtual {v0, v1}, Lcom/example/myapplication/MainActivity;->setTitle(I)V
  55.     .line 41
  56.     :goto_0
  57.     return-void
  58. .end method
复制代码
经过分析,if-nez v0, :cond_0判断决定了校验是否通过,这句代码的意思是:假如v0不为0则跳转到cond_0,也就是注册失败的分支。
破解方法:将if-nez改为if-eqz也就是等于则为真
修改后保存,实行如下代码重新编译
  1. java -jar apktool_2.9.3.jar b output
复制代码
编译后需要对apk举行签名,这里我本地生成了一个测试签名
  1. keytool -genkey -alias testalias -keyalg RSA -keysize 2048 -validity 36500 -keystore test.keystore
复制代码
然后用360加固助手的工具包举行签名。
接下来可以通过adb命令安装和启动
  1. adb install app-debug_sign.apk
  2. adb shell am start -n com.example.myapplication/.MainActivity
复制代码

至此破解就算完成了。
利用IDA pro破解

由于利用apktool每次都需要重新编译,很花时间,idapro提供了快速测试的方法。
下载地址:https://down.52pojie.cn/Tools/Disassemblers/IDA_Pro_v8.3_Portable.zip
用压缩包工具打开app-debug.apk,提取出classes.dex文件,通过ida pro打开
注意:假如classes.dex没有大概在classes3.dex
按照先找错误信息的思路,按alt+t打开文本搜索功能,搜索:0x7f1000a5

定位到关键代码(按空格可以切换视图)

可以看到分支判断位于CODE:000006BE,将光标放在if-nez处,点击hex-view,修改if-nez的字节码
39 00 0F 00改为38 00 0F 00
然后关闭ida pro,不需要保存到database
用c32asm打开classes3.dex定位到000006BE,将39改为38,保存退出

这里由于修改了dex文件,会导致dex文件在验证计算checksum会失败,从而导致步伐安装失败,因此需要重新计算checksum值
用Dexfixer将classes3.dex文件checksum值修复

将修复好的classes3.dex,重新拉入apk
  1. aapt r app-debug.apk classes3.dex
  2. aapt a app-debug.apk classes3.dex
复制代码
删除META-INT(可利用winrar工具),并重新签名apk即可破解成功。

参考:《Android软件安全与逆向分析》

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

圆咕噜咕噜

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表