梦旅意中人 发表于 2023-2-7 02:07

【2023】春节解题领红包之四

本帖最后由 梦旅意中人 于 2023-2-7 21:13 编辑

## 前言

#### 在开始阅读本解析前,强烈建议去看看 **正己** 大佬的(https://www.52pojie.cn/thread-1695141-1-1.html),写的肥肠滴好,B站也有对应教程,相信认真看完之后一定会很快解出Android的初级题。

#### ~~如果依旧没有思路,再来看看这篇解析也不迟。~~看完嘎嘎乱杀好吧。

## 工具

#### JEB(本次以JEB为主,使用NP/MT也可以,不过需要些许的Android和Java基础)

## 静态分析

#### 首先安装我们的App,看看能否收集到一些有用的信息。可以看到输入测试用例,会有flag错误的提示。由于只有这一个页面,所以可以肯定我们要找的相关内容都在MainActivity中。可以看到整个页面我们需要关注的就是两个文本框,和一个按钮,大体逻辑应该是输入uid和flag,点击验证会将输入的数据读取,所以我们重点要关注按钮的点击事件。



#### 拖入JEB中查看,等待分析完成,在左下角窗口中选择MainActivity双击,然后右键选择Decomplie,弹窗点击ok即可,可以看到我们的源码在右侧直接就会显示出来。在上一篇文章中已经比较详细的介绍了使用NP管理器(MT管理器同理)如何反编译源码,静态分析以源码为主,使用JEB和NP/MT并无大差异。


#### 在右侧窗口直接查看源码,或者选择底部窗口选项中的Quick Search,输入错误提示信息查看。由于JEB已经将源码分析很彻底,因此直接从源码入手也可以,可以看到右侧窗口中的有一个Button对象和两个EditText的对象,重点对Button对象分析。还有此处的b方法,如果进行查看可以发现其读取了包名等相信息,其实这是签名校验,也就是说,如果我们使用上一篇文章中的方法直接对其打包签名必然会出现白屏崩溃等现象,因此我们避其锋芒,对源码分析即可。



#### 不难发错误信息的提示在此处的button0的监听事件中,而这个button0其实就是我们上图中的Button类实例化的对象,当点击验证按钮时,此处的方法将被调用。要使得返回正确信息,就要保证a0.B()函数返回的结果为true,此函数传入了两个参数,uid和flag,使用了trim()将其多余的空格去掉,并都转换为String类型。直接对a0.B()方法进行分析即可。



#### 在这里的B方法上双击,出现弹窗点击ok即可。进入A类中,可以看到函数的执行流程如下,对uid和flag判空,校验flag是否以“flag{”开头,以“}”结尾,对flag内容进行分割,也就是取出花括号的内容,再将uid和“Wuaipojie2023”拼接并使用B类的encode()方法编码后(encode方法中将传入的字符串转为char类型数组,从后向前逆向遵循交错异或的方式重新赋值,如数组末端元素先和53异或,则它的前一个元素和50异或,再往前又是53,以此类推。因为编写此文时JEB频繁闪退,故此处没有对encode方法的截图,见谅),将其字符格式设置为UTF-8,并转为byte数组,再将其转为Base64编码后,再使用MD5加密,然后将得到的字符串传入C类的)cipher()中,也就是说B方法获取我们输入的flag,再将我们输入的uid通过一系列的加密操作后,比较两者是否相等,相等则提示正确。



#### 在cipher()方法上双击,根据我们上一步传入的参数可知,这里调用了返回值为String的cipher()方法,这里的cipher()方法主要是区分数字和字母,如果是字母会调用返回值为char的cipher()方法,此方法中对字母进行了偏移量为5的凯撒密码加密,若为数字则直接使用可变字符类StringBuilder拼接后转为String对象成为最终的flag,至此代码逻辑分析完成。



## 代码

#### 根据上文的分析,可以写出由Java编写的flag计算方法供大家参考。

```java
package puzzle3;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.Scanner;
import java.security.NoSuchAlgorithmException;

class Solution {
    public static void main(String[] args) {
      Scanner sc = new Scanner(System.in);
      System.out.println("请输入您的UID");
      String uid = sc.nextLine();
      String str = encode(uid + "Wuaipojie2023");
      byte[] byteArr = str.getBytes(StandardCharsets.UTF_8);
      String base64Str = Base64.getEncoder().encodeToString(byteArr);
      String md5Str = MD5(base64Str);
      System.out.println("您的flag为");
      System.out.println(cipher(md5Str, 5));
      sc.close();
    }

    /**
   * 编码
   */
    public static String encode(String s) {
      char [] arr = s.toCharArray();
      boolean singal = false;
      for(int i = arr.length - 1; i >= 0 ; i--){
            if(!singal){
                arr ^= 53;
            }else{
                arr ^= 50;
            }
            singal = !singal;
      }

      return new String(arr);
    }

    /**
   * MD5加密函数
   * @Param str
   * @return
   */
    public static String MD5(String str){
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                md.update(str.getBytes());
                byte[]byteDigest = md.digest();
                int i;
                StringBuffer buf = new StringBuffer("");
                for (int offset = 0; offset < byteDigest.length; offset++) {
                  i = byteDigest;
                  if (i < 0)
                        i += 256;
                  if (i < 16)
                        buf.append("0");
                  buf.append(Integer.toHexString(i));
                }
                //32位加密
                return buf.toString();
                // 16位加密
                //return buf.toString().substring(8, 24);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                return null;
            }
    }

    /**
   * 计算flag
   * @param s
   * @param v
   * @return
   */
    public static final String cipher(String s, int v) {
      StringBuilder stringBuilder = new StringBuilder();
      stringBuilder.append("flag{");
      int len = s.length();
      for(int i = 0; i < len; ++i) {
            // 判单是否为字母
            if(Character.isLetter(s.charAt(i))){
                stringBuilder.append(shiftCipher(s.charAt(i),5));
            }else {
                stringBuilder.append(s.charAt(i));
            }
      }
      
      return stringBuilder.append("}").toString();
    }

    // 字母移位
    private static final char shiftCipher(char c, int v) {
      return Character.isUpperCase(c) ? (char)((c + v) % 90) : (char)((c + v) % 122);
    }
   
}
```

#### 由于包含了Scanner函数,请使用如下网站运行(将上边的代码复制到此网站,根据图片操作即可),或者使用Java的IDE运行代码,根据提示输入uid即可。

http://java.jsrun.net/



## 验证

#### 输入uid和计算后的flag显示正确



## 动态调试

#### 如果对静态分析的过程不是很清楚的话,可以选择动态调试的方式,不过 正己 大佬已经将方法讲的非常清楚了,且有对应的学习视频,本题目对应的课程[内容](https://www.52pojie.cn/thread-1714727-1-1.html),大家可以去学习尝试一下。强烈建议从第一课开始看,一定要动手!!!对于这道题目由于由签名校验,可以直接使用NP/MT管理器的去除签名校验功能,也可以自己手动去除,为什么要去签名校验呢?因为我们要使用动态调试的话,第一种方式就是修改AndroidManifest.xml文件中的debuggable权限,改动文件必然需要重新签名,因此必须去除签名校验才能正常运行,当然不修改文件也可以,建议大家可以把几种方法都尝试一下,想必一定会收获颇深的,如有相关问题可在本贴留言讨论。

## 其它题解

#### 【2023】春节解题领红包之二https://www.52pojie.cn/thread-1742329-1-1.html

#### 【2023】春节解题领红包之三https://www.52pojie.cn/thread-1742449-1-1.html

#### 【2023】春节解题领红包之web篇——不完美题解https://www.52pojie.cn/thread-1743080-1-1.html

bj9ye666 发表于 2023-2-7 07:08

春节必备神器,不发愁抢不到

风/生/水/起 发表于 2023-2-7 09:00

尝试一波

zdway 发表于 2023-2-7 09:51

niubility

路人王2021 发表于 2023-2-7 13:42

你们可真厉害啊

梦旅意中人 发表于 2023-2-7 16:04

风/生/水/起 发表于 2023-2-7 09:00
尝试一波

实践出真知

梦旅意中人 发表于 2023-2-7 16:05

路人王2021 发表于 2023-2-7 13:42
你们可真厉害啊

其实你也可以的哈

路人王2021 发表于 2023-2-7 16:20

梦旅意中人 发表于 2023-2-7 16:05
其实你也可以的哈

小白正在学习中:lol

梦旅意中人 发表于 2023-2-7 21:14

路人王2021 发表于 2023-2-7 16:20
小白正在学习中

加油加油哈,有问题了可以留言讨论

路人王2021 发表于 2023-2-8 13:06

梦旅意中人 发表于 2023-2-7 21:14
加油加油哈,有问题了可以留言讨论

好的好的 非常感谢{:1_893:}
页: [1]
查看完整版本: 【2023】春节解题领红包之四