小菜鸟一枚 发表于 2023-2-8 20:28

学破解第201天,《抄春节活动二、三、四题wp并总结》

前言:

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

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

## 0x1 题目来源
  1.活动已结束,题目打包放到爱盘供大家下载学习(web在线题目一周后下线):
(https://down.52pojie.cn/Challenge/Happy_New_Year_2023_Challenge.rar)

  2.我很菜,春节一个题都没干出来,遇到困难就退缩了,现在活动结束了,抄一抄别的大佬wp分享出来,只能看懂前三个,后面wp我看不懂了!

## 0x2 题二

  1.先跑起来看看

!(https://s1.ax1x.com/2023/02/07/pS2AdWd.png)

  2.从目前收集到的信息就是校验字符串是否正确,会判断字符串长度是否相等,拖进OD右键搜索中文字符串可以看到很多提示。

!(https://s1.ax1x.com/2023/02/07/pS2Ayef.png)

  3.这是刚刚出现的错误提示,这里调试一下就知道是判断字符串长度,0x1D就是29位:

```
0040132E   .837E F4 1D    cmp dword ptr ds:,0x1D
00401332   .0F84 A5000000 je 【2023春.004013DD
00401338   .C70424 D03344>mov dword ptr ss:,【2023春.004433D0
0040133F   .BF 34004400   mov edi,【2023春.00440034                  ;Length Error, please try again
```

  4.输入12345678912345678912345678900测试,继续往下调试,发现会提示错误,可以看到有一个跳转过来,点上去发现是一个cmp比较下来的。

```
00401501   > \C70424 D03344>mov dword ptr ss:,【2023春.004433D0
00401508   .BA 61004400   mov edx,【2023春.00440061                  ;Wrong,please try again.

00401417   .381C32      cmp byte ptr ds:,bl
0040141A      0F85 E1000000 jnz 【2023春.00401501
```

  5.重来,打上断点,看看这里比较的是什么,右键-数据窗口中跟随-》内存地址,发现比较的好像就是我输入的字符串的第一个字符1。

!(https://s1.ax1x.com/2023/02/07/pS2E90K.png)

  6.将下面的jnz nop掉,在这里反复循环几次看看,验证了我的猜想,那就笨办法一步步读出每一个字符,在纸上记录下来,最终得到flag:flag{52PoJie2023HappyNewYear},输入验证一下,成功。

  7.用od分析到长度判断后可以用ida动态调试,如果直接看会有点晕,但是刚刚od里面已经分析长度为29,所以这里*(v14 - 12)就是我输入字符串的长度。
```
if ( *(v14 - 12) == 29 )
{
    v13 = 0;
    while ( 1 )
    {
      if ( *(v14 - 12 + 8) >= 0 )
      _ZNSs12_M_leak_hardEv(v14);
      if ( *(v14 + v13) != (dword_43F000 >> 2) )
      break;
      if ( ++v13 >= *(v14 - 12) )
      {
      v7 = _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc(&dword_4433D0, "Success");
      _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(v7);
      system("Pause");
```

  8.while循环里面第一个if可以不用管自己过去,根据提示第二个if必须成立,否则跳出去就失败了,第三个if就是判断循环次数, ++v13移动下标,判断循环次数等不等于字符串长度。再看第二个if,v14逐个和dword_43F000右移两位后做比较,鼠标移上去能看到数组变量的值,点进去,右键修改类型为array。

!(https://s1.ax1x.com/2023/02/07/pS2eICF.png)

注: 2 dup(1C0),指的是两个1C0,写脚本复制别漏了。

  9.可根据上面的分析编写脚本:

```
#include <stdio.h>

int main()
{
    int flag[] = {0x198, 0x1B0, 0x184, 0x19C, 0x1EC, 0x0D4, 0x0C8, 0x140, 0x1BC,
                0x128, 0x1A4, 0x194, 0x0C8, 0x0C0, 0x0C8, 0x0CC, 0x120, 0x184,
                0x1C0, 0x1C0, 0x1E4, 0x138, 0x194, 0x1DC, 0x164, 0x194, 0x184,
                0x1C8, 0x1F4};

    // 输出flag
    for (int i = 0; i < 29; i++)
    {
      printf("%c", flag>>2);;
    }

    return 1;
}
```

!(https://s1.ax1x.com/2023/02/07/pS2m0q1.png)

## 0x3 题三

&emsp;&emsp;1.反编译看代码,可以看到onclick函数,必须点击999次才会执行decrypt函数得到flag。

```
    public static final void m19onCreate$lambda0(MainActivity this$0, TextView key, View view) {
      Intrinsics.checkNotNullParameter(this$0, "this$0");
      Intrinsics.checkNotNullParameter(key, "$key");
      MainActivity mainActivity = this$0;
      this$0.jntm(mainActivity);
      key.setText(String.valueOf(this$0.num));
      if (this$0.check() == 999) {
            Toast.makeText(mainActivity, "快去论坛领CB吧!", 1).show();
            key.setText(this$0.decrypt("hnci}|jwfclkczkppkcpmwckng\u007f", 2));
      }
    }

    public final String decrypt(String encryptTxt, int i) {
      Intrinsics.checkNotNullParameter(encryptTxt, "encryptTxt");
      char[] charArray = encryptTxt.toCharArray();
      Intrinsics.checkNotNullExpressionValue(charArray, "this as java.lang.String).toCharArray()");
      StringBuilder sb = new StringBuilder();
      for (char c : charArray) {
            sb.append((char) (c - i));
      }
      String sb2 = sb.toString();
      Intrinsics.checkNotNullExpressionValue(sb2, "with(StringBuilder()) {\n…   toString()\n      }");
      return sb2;
    }
```

&emsp;&emsp;2.本想改代码,把999改成3,但是发现模拟器不能运行apk,就会很难受了,好在这题逻辑不难,主要是执行decrypt函数就可以了,去掉无用的,保留关键代码。

```
        decrypt("hnci}|jwfclkczkppkcpmwckng\u007f", 2);
       
    public final String decrypt(String encryptTxt, int i) {
      Intrinsics.checkNotNullParameter(encryptTxt, "encryptTxt");
      char[] charArray = encryptTxt.toCharArray();
      Intrinsics.checkNotNullExpressionValue(charArray, "this as java.lang.String).toCharArray()");
      StringBuilder sb = new StringBuilder();
      for (char c : charArray) {
            sb.append((char) (c - i));
      }
      String sb2 = sb.toString();
      Intrinsics.checkNotNullExpressionValue(sb2, "with(StringBuilder()) {\n…   toString()\n      }");
      return sb2;
    }
```

&emsp;&emsp;3.把这段代码搬运到eclipse里面,跑一遍得到flag{zhudajiaxinniankuaile}。

```
package ctf;

public class test01 {

        public static void main(String[] args) {
               
                //把参数值直接写进来
                String encryptTxt = "hnci}|jwfclkczkppkcpmwckng\u007f";
                int i = 2;

                //照搬代码
                char[] charArray = encryptTxt.toCharArray();
      StringBuilder sb = new StringBuilder();
      for (char c : charArray) {
            sb.append((char) (c - i));
      }
      String sb2 = sb.toString();
      System.out.println(sb2);
        }
}
```

## 0x4 题四
&emsp;&emsp;1.还是先反编译看一下代码:
```
public static final void m19onCreate$lambda0(MainActivity this$0, View view) {
      Intrinsics.checkNotNullParameter(this$0, "this$0");
      A a = A.INSTANCE;
      EditText editText = this$0.edit_uid;
      EditText editText2 = null;
      if (editText == null) {
            Intrinsics.throwUninitializedPropertyAccessException("edit_uid");
            editText = null;
      }
      String obj = StringsKt.trim((CharSequence) editText.getText().toString()).toString();
      EditText editText3 = this$0.edit_flag;
      if (editText3 == null) {
            Intrinsics.throwUninitializedPropertyAccessException("edit_flag");
      } else {
            editText2 = editText3;
      }
      if (a.B(obj, StringsKt.trim((CharSequence) editText2.getText().toString()).toString())) {
            Toast.makeText(this$0, "恭喜你,flag正确!", 1).show();
      } else {
            Toast.makeText(this$0, "flag错误哦,再想想!", 1).show();
      }
    }
```

&emsp;&emsp;2.可以看到由我输入uid和flag然后进行运算,关键判断就是 if (a.B(obj, StringsKt.trim((CharSequence) editText2.getText().toString()).toString())) 这一行a.B我们点进去看看是什么方法,第一个参数是我输入的uid,第二个参数是我输入的flag。

```
    public final boolean B(String str, String str2) {
      Intrinsics.checkNotNullParameter(str, "str");
      Intrinsics.checkNotNullParameter(str2, "str2");
      if ((str.length() == 0 && str2.length() == 0) || !StringsKt.startsWith$default(str2, "flag{", false, 2, (Object) null) || !StringsKt.endsWith$default(str2, "}", false, 2, (Object) null)) {
            return false;
      }
      String substring = str2.substring(5, str2.length() - 1);
      Intrinsics.checkNotNullExpressionValue(substring, "this as java.lang.String…ing(startIndex, endIndex)");
      C c = C.INSTANCE;
      MD5Utils mD5Utils = MD5Utils.INSTANCE;
      Base64Utils base64Utils = Base64Utils.INSTANCE;
      String encode = B.encode(str + "Wuaipojie2023");
      Intrinsics.checkNotNullExpressionValue(encode, "encode(str3)");
      byte[] bytes = encode.getBytes(Charsets.UTF_8);
      Intrinsics.checkNotNullExpressionValue(bytes, "this as java.lang.String).getBytes(charset)");
      return Intrinsics.areEqual(substring, c.cipher(mD5Utils.MD5(base64Utils.encodeToString(bytes)), 5));
    }
```

&emsp;&emsp;3.分析一下上面的代码:

```
1)先看第一个if判断长度是否为0,然后startsWith函数百度一下作用:如果字符串以指定的前缀开始,则返回 true;否则返回 false,这里就是判断开头是否为flag{,后面一个函数是判断末尾的,作用差不多。

2)str2.substring(5, str2.length() - 1);取flag{}里面的内容

3)C c = C.INSTANCE这里创建了一个类对象,具体干什么先不管,后面再分析。

4)后面连着几行,很好理解,将uid拼接"Wuaipojie2023"调用B类的encode方法进行处理字符串,接着将处理后的字符串变成bytes字节数组。

public class B {
    public static String encode(String str) {
      int length = str.length();
      char[] cArr = new char;
      int i = length - 1;
      while (i >= 0) {
            int i2 = i - 1;
            cArr = (char) (str.charAt(i) ^ '5');
            if (i2 < 0) {
                break;
            }
            i = i2 - 1;
            cArr = (char) (str.charAt(i2) ^ '2');
      }
      return new String(cArr);
    }
}

5)到最后一句比较了,可以看到将得到的bytes先进行base64加密,在进行md5加密,通过c类对象调用cipher方法,最后和flag{}里面的内容作比较。
```

&emsp;&emsp;4.B类的encode方法没看懂,先不管,等会直接调用,去看c类的cipher方法,这里面还用上了方法重载套娃:

```
    private final char cipher(char c, int i) {
      char c2 = Character.isUpperCase(c) ? 'A' : 'a';
      return (char) (((char) (((((char) (c - c2)) + (i % 26)) + 26) % 26)) + c2);
    }

    public final String cipher(String str, int i) {
      Intrinsics.checkNotNullParameter(str, "str");
      StringBuilder sb = new StringBuilder();
      int length = str.length();
      for (int i2 = 0; i2 < length; i2++) {
            if (Intrinsics.compare((int) str.charAt(i2), 65) >= 0 && Intrinsics.compare((int) str.charAt(i2), 90) <= 0) {
                sb.append(cipher(str.charAt(i2), i));
            } else if (Intrinsics.compare((int) str.charAt(i2), 97) < 0 || Intrinsics.compare((int) str.charAt(i2), 122) > 0) {
                sb.append(str.charAt(i2));
            } else {
                sb.append(cipher(str.charAt(i2), i));
            }
      }
      String sb2 = sb.toString();
      Intrinsics.checkNotNullExpressionValue(sb2, "sb.toString()");
      return sb2;
    }
```

&emsp;&emsp;5.反正代码流程是弄清楚了,直接改造一下试试:

```
package ctf;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public class test01 {

        public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {

                // uid+拼接后的字符串直接写上
                String uid = "750905Wuaipojie2023";

                // 调用encode()
                String en_str = encode(uid);
               
                //base64和md5
                en_str = Base64.getEncoder().encodeToString(en_str.getBytes());
                byte[] en_flag = MessageDigest.getInstance("MD5").digest(en_str.getBytes());
               
                //这里调用了别人的转16进制代码
                String md5_str = bytesToHex(en_flag);
               
                String flag = cipher(md5_str,5);
               
                System.out.println("flag{"+flag+"}");
        }

        // 将encode函数照搬
        public static String encode(String uid) {
                int length = uid.length();
                char[] cArr = new char;
                int i = length - 1;
                while (i >= 0) {
                        int i2 = i - 1;
                        cArr = (char) (uid.charAt(i) ^ '5');
                        if (i2 < 0) {
                                break;
                        }
                        i = i2 - 1;
                        cArr = (char) (uid.charAt(i2) ^ '2');
                }
                return new String(cArr);
        }

        public static char cipher(char c, int i) {
                char c2 = Character.isUpperCase(c) ? 'A' : 'a';
                return (char) (((char) (((((char) (c - c2)) + (i % 26)) + 26) % 26)) + c2);
        }

        public static String cipher(String str, int i) {

                // 这里Intrinsics.compare这个函数的意思百度一下就懂了,就是判断是不是在65和90之间的,后面一个也一样。
                StringBuilder sb = new StringBuilder();
                int length = str.length();
                for (int i2 = 0; i2 < length; i2++) {
                        if ((str.charAt(i2) - 65) >= 0 && (str.charAt(i2) - 90) <= 0) {
                                sb.append(cipher(str.charAt(i2), i));
                        } else if ((str.charAt(i2) - 97) < 0 || (str.charAt(i2) - 122) > 0) {
                                sb.append(str.charAt(i2));
                        } else {
                                sb.append(cipher(str.charAt(i2), i));
                        }
                }
                String sb2 = sb.toString();

                return sb2;
        }
       
        public static String bytesToHex(byte bytes[]) {
      StringBuffer sb = new StringBuffer();
      for (int i = 0; i < bytes.length; i++) {
            int number = bytes & 0xff;
            String hex = Integer.toHexString(number);
            if (number >= 0 && number < 16) {
                sb.append("0" + hex);
            } else {
                sb.append(hex);
            }
      }
      return sb.toString();
    }
}
```

&emsp;&emsp;6.这里写脚本,我是照着前面分析的来,先取我的uid直接拼上Wuaipojie2023,然后几个调用的方法直接把代码copy过来,报错的哪些检查语句直接删掉,Intrinsics.compare这个函数不能删,是比较用的,百度一下就能改造,所有方法改为静态的即可,但是最后一直是乱码,和别人的对比发现主要在md5后的16进制转换没有做。

elecfun 发表于 2023-2-8 23:23

为啥第四题我反编译出来的跟你们不一样?我用C#实现了但怎么结果都不对,就放弃了。今天看你们的反编译出来的是i先减1,while条件里没减。

侃遍天下无二人 发表于 2023-2-8 20:33

本帖最后由 侃遍天下无二人 于 2023-2-19 13:19 编辑

web题我把环境打包到单文件exe了,可以下下来练习https://gitee.com/kbtxwer/happy_ ... 7%BA%A7%E9%A2%98%7D

注: 现在爱盘已经上传web题了,直接点击这里下载即可

naizui401 发表于 2023-2-8 20:40

学习知识,谢谢讲述

tyjjk 发表于 2023-2-8 21:01

坚持写学习笔记 赞个

wflb826 发表于 2023-2-8 21:24

这个学习了

凉水白开 发表于 2023-2-8 22:06

坚持写学习笔记

cjx09231211 发表于 2023-2-8 22:09

坚持学习冲!

pq2006 发表于 2023-2-8 23:03

贵在坚持,楼主加油!

水蜜桃好甜 发表于 2023-2-8 23:17

学习一下
页: [1] 2 3 4
查看完整版本: 学破解第201天,《抄春节活动二、三、四题wp并总结》