吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2435|回复: 35
收起左侧

[Android 分享] 学破解第215天,《动态调试&Log插桩》失败学习

[复制链接]
小菜鸟一枚 发表于 2025-2-20 20:44
本帖最后由 小菜鸟一枚 于 2025-2-20 20:49 编辑

前言:

  坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源:https://www.52pojie.cn/thread-2006536-1-1.html

立帖为证!--------记录学习的点点滴滴

0x1 动态调试&Log插桩(假)

  1.Log插桩指的是反编译APK文件时,在对应的smali文件里,添加相应的smali代码,将程序中的关键信息,以log日志的形式进行输出。


invoke-static {对应寄存器}, Lcom/mtools/LogUtils;->v(Ljava/lang/Object;)V

  2.算法助手获取获取日志时有延迟,需要退出重新启动才能看到日志。

  3.教程开始跟不上了,直接看这一关作业,点进来发现需要输入一个用户名和16位的注册码,直接点击注册后提示:无效用户名或注册码。

1.png

  4.用np管理器提取安装包,查看dex文件,搜索错误提示,发现搜索不到。

onCreate() 一个Activity启动后第一个被调用的函数,常用来在此方法中进行Activity的一些初始化操作。例如创建View,绑定数据,注册监听,加载参数等。

  5.使用adb命令,adb shell,dumpsys activity top,显示顶层活动窗口,可以看到是com.droider.crackme0201/.MainActivity。

Debug logs:

TASK com.droider.crackme0201 id=3 userId=0
  ACTIVITY com.droider.crackme0201/.MainActivity a1c65dc pid=2979
    Local Activity 2ee3f73 State:
      mResumed=true mStopped=false mFinished=false
      mChangingConfigurations=false
      mCurrentConfig={1.0 460mcc65535mnc [zh_CN] ldltr sw360dp w360dp h616dp 480
dpi nrml long port finger qwerty/v/v -nav/h winConfig={ mBounds=Rect(0, 0 - 1080
, 1920) mAppBounds=Rect(0, 0 - 1080, 1920) mWindowingMode=fullscreen mActivityTy
pe=standard} s.7}

  6.再去np管理器打开dex文件,搜索这个类com.droider.crackme0201.MainActivity(去掉前面的下划线搜),onCreate函数前面说过了,启动的时候调用,setOnClickListener函数注册了一个单击事件,单击注册按钮触发onClick函数,这个函数里面有两个case分支,一个执行checkSNfalse函数,一个执行checkSN函数,可以看到如果不执行第二个case,或者第二个case里面的if不满足都会执行2131034123这个show。

    public void onClick(View view) {
        switch (view.getId()) {
            case 2131230723:
                checkSNfalse(this.edit_userName.getText().toString().trim(), this.edit_sn.getText().toString().trim());
                return;
            case 2131230724:
                if (checkSN(this.edit_userName.getText().toString().trim(), this.edit_sn.getText().toString().trim())) {
                    Toast.makeText(this, 2131034124, 0).show();
                    this.btn_register.setEnabled(false);
                    setTitle(2131034122);
                    return;
                }
                Toast.makeText(this, 2131034123, 0).show();
                return;
            default:
                return;
        }
    }

    private boolean checkSN(String str, String str2) {
        if (str == null) {
            return false;
        }
        try {
            if (str.length() == 0 || str2 == null || str2.length() != 16) {
                return false;
            }
            MessageDigest instance = MessageDigest.getInstance("MD5");
            instance.reset();
            instance.update(str.getBytes());
            String toHexString = toHexString(instance.digest(), "");
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < toHexString.length(); i += 2) {
                stringBuilder.append(toHexString.charAt(i));
            }
            return stringBuilder.toString().equalsIgnoreCase(str2);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return false;
        }
    }

    private boolean checkSNfalse(String str, String str2) {
        if (str == null) {
            return false;
        }
        try {
            if (str.length() == 0) {
                return false;
            }
            MessageDigest instance = MessageDigest.getInstance("MD5");
            instance.reset();
            instance.update(str.getBytes());
            String toHexString = toHexString(instance.digest(), "");
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < toHexString.length(); i++) {
                stringBuilder.append(toHexString.charAt(i));
            }
            String stringBuilder2 = stringBuilder.toString();
            this.edit_sn.setText(stringBuilder2);
            return stringBuilder2.equalsIgnoreCase(str2);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return false;
        }
    }

    private static String toHexString(byte[] bArr, String str) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bArr) {
            String hex = Integer.toHexString(b & 255);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex).append(str);
        }
        return hexString.toString();
    }

    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(2130903040);
        setTitle(2131034121);
        this.edit_userName = (EditText) findViewById(2131230721);
        this.edit_sn = (EditText) findViewById(2131230722);
        this.btn_register = (Button) findViewById(2131230724);
        this.btn_register.setOnClickListener(this);
    }

  7.前面学习过了show就是弹窗,我们打开arsc资源编辑搜索这个id,看到原来这个弹窗内容就是无效用户名或注册码,再看另外一个show的id:2131034124,搜索一下,弹窗内容是恭喜您!注册成功,到这里就很清楚了,关键在于checkSN函数。

2.png

<?xml version="1.0" encoding="UTF-8"?>

<resources>
  <string name="app_name">Crackme0201</string>
  <string name="menu_settings">Settings</string>
  <string name="title_activity_main">Crackme0201</string>
  <string name="info">Android程序破解演示实例</string>
  <string name="username">用户名:</string>
  <string name="sn">注册码:</string>
  <string name="register">注 册</string>
  <string name="hint_username">请输入用户名</string>
  <string name="hint_sn">请输入16位的注册码</string>
  <string name="unregister">程序未注册</string>
  <string name="registered">程序已注册</string>
  <string name="unsuccessed">无效用户名或注册码</string>
  <string name="successed">恭喜您!注册成功</string>
</resources>

  8.checkSN函数可以看到传入了userName和sn,这是我们输入的,进来后执行了一个if三个长度判断,接着就是将userName进行MD5处理,再就是一个for循环,自增2,也就是取md5后字符串的奇数位,再通过注册码16位,可以猜测就是生成32位字符串,那么只要在动态调试中找到这个字符串就能得到正确的注册码。

  9.安卓里面很多都是java代码写的,所以我们有一个更快的办法,那就是去掉这些if判断,把两个函数单独拿出来,随便设置一个初始化字符串“xcn”作为用户名,跑一遍,flag就出来了。

public class Test {

        private static String toHexString(byte[] bArr, String str) {
            StringBuilder hexString = new StringBuilder();
            for (byte b : bArr) {
                String hex = Integer.toHexString(b & 255);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex).append(str);
            }
            return hexString.toString();
        }

        public static void main(String[] args) throws NoSuchAlgorithmException {
                String str= "xcn";//这个是用户名

                MessageDigest instance = MessageDigest.getInstance("MD5");
        instance.reset();
        instance.update(str.getBytes());
        String toHexString = toHexString(instance.digest(), "");
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < toHexString.length(); i += 2) {
            stringBuilder.append(toHexString.charAt(i));
        }

                System.out.println(stringBuilder.toString());//打印输出
        }
}

运行结果:3f4739785b40efec  //这个就是用户名对应的注册码。

  10.当然了,我们目标是练习动态插桩,前面的偏题了,接下来正文。

0x2 动态调试&Log插桩(真)

  1.打开jeb,找到关键代码,在0000004A这个地方打上断点,跑起来

0000004A  invoke-direct       MainActivity->checkSN(String, String)Z, p0, v0, v1
00000050  move-result         v0
00000052  if-nez              v0, :6C
:56
00000056  const               v0, 0x7F05000B        # string:unsuccessed "无效用户名或注册码"
0000005C  invoke-static       Toast->makeText(Context, I, I)Toast, p0, v0, v2
00000062  move-result-object  v0
00000064  invoke-virtual      Toast->show()V, v0
0000006A  goto                :10
:6C
0000006C  const               v0, 0x7F05000C        # string:successed "恭喜您!注册成功"

  2.输入xcn和16个1,点击注册按钮断了下来,进入函数内部,可以看到先是v3那里出现了我们前面的猜测的md5了,但是v6这里似乎看不到内容,返回值不应该是在v6里面吗?

3.png

  3.那就去看v6前面的v5,可以看到一串字节数组,这个就是我们前面的正确注册码了。

4.png

  4.使用np管理器提取安装包,打开dex文件,将日志插装.dex文件插入这个安装包,改名为classes2.dex,然后去代码中添加代码。

  invoke-virtual {v6, p2}, Ljava/lang/String;->equalsIgnoreCase(Ljava/lang/String;)Z

    invoke-static {v6}, Lcom/mtools/LogUtils;->v(Ljava/lang/Object;)V

    move-result v8

  5.重新安装后运行,程序崩溃了,太难了,才学了一点点就跟不上了前辈的节奏。┭┮﹏┭┮

0x3 参考文档

  1.《安卓逆向这档事》五、1000-7=?&动态调试&Log插桩

免费评分

参与人数 8吾爱币 +10 热心值 +8 收起 理由
ee789852 + 3 + 1 菜鸟哥哥,我准备去武汉上班了
allspark + 1 + 1 用心讨论,共获提升!
芽衣 + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!
mhaitao + 1 + 1 热心回复!
pp67868450 + 1 + 1 用心讨论,共获提升!
jk998 + 1 + 1 我很赞同!
ioyr5995 + 1 + 1 我很赞同!
hc6125322 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

shenxinfu2024 发表于 2025-2-20 21:02
吾爱是一个有爱的地方,虽然我才疏学浅,看不懂。但是我还是觉得逆很厉害。
xiabo 发表于 2025-2-21 08:14
rayzju 发表于 2025-2-21 08:30
xfwww 发表于 2025-2-21 09:14
感谢分享经验,我也在学习,刚开始。
haiyangw 发表于 2025-2-21 10:11
你加油,我还没开始
orangewinnie 发表于 2025-2-21 10:27
不看学习成果 光看215天就已经很牛了
wuliwl 发表于 2025-2-21 11:15
坚持!正因为有你,所以我把业务代码都搬到服务端了。
leger1210 发表于 2025-2-21 13:41
加油,我当时看到log插装,也没有成功。。。
qlh520 发表于 2025-2-21 15:32
虽然学着吃力,但一起坚持
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-22 18:47

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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