本文章教程来自《Android软件安全与逆向分析》
目录
1. 了解Android studio文件结构
主要知道我们要利用哪些文件。详见:
https://blog.csdn.net/qq_39312230/article/details/80314236
2. 创建注册功能程序
2.1 在布局文件进行布局
activity_main.xml
2.2 编写MainActivity类代码
//MainActivity.java package com.example.myapplication; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class MainActivity extends AppCompatActivity { 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.unregister); //从editText中获取的用户名 edit_userName=findViewById(R.id.editText); //从editText中获取的注册码 edit_sn=findViewById(R.id.editText2); btn_register=findViewById(R.id.button2); //对button的点击事件的监听 btn_register.setOnClickListener(new View.OnClickListener() { public void onClick(View v){ if(!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).show(); btn_register.setEnabled(false); //模拟程序已注册 setTitle(R.string.registered); } } }); } private boolean checkSN(String userName,String sn){ try{ if((userName==null)||(userName.length()==0)) return false; if((sn==null)||(sn.length()!=16)) return false; MessageDigest digest=MessageDigest.getInstance("MD5"); digest.reset(); digest.update(userName.getBytes()); //采用MD5对用户名进行HASH byte[] bytes=digest.digest(); //将结果转化为字符串 String hexstr=toHexString(bytes,""); // String hexstr = new BigInteger(1, bytes).toString(16); 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(); } }
//string.xml
<resources>
<string name="app_name">My Application</string> <string name="registered">程序已注册</string> <string name="unregister">程序未注册</string> <string name="successed">注册成功!</string> <string name="unsuccessed">注册失败!</string> </resources>
2.3 编译生成APK文件
启动模拟器执行。
3. 破解程序
使用Android killer(AK)进行反编译及修改,配套使用夜神模拟器进行后期的APK安装,具体安装配置见:
https://www.jianshu.com/p/61a93a6c0c1b
把debug目录下的apk文件拖拽进AK,原apk在注册时得到错误提示注册失败,故进行字符搜索。
而在strings.xml文件中的字符串都有唯一的索引值,这些索引值存放在同目录下的public.xml文件下,打开public.xml进行搜索,得到id值,在smali文件中搜索相应的id值,对搜索到的位置进行上下查看代码,一般我们需要修改的关键代码就在附近。图中圈出来的是一个条件跳转指令,与之相反的指令为if-eqz,将‘if-nez’修改为‘if-eqz’(图为已修改后的),保存,并加签名后再编译。
编译过程中如果出现有关版本的问题,可将apktool更新到最新版本(2.4.1)。
成功后将project目录下的apk文件拖进夜神模拟器进行安装。
打开后填入任何内容显示注册成功: