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

查看 119|回复 9
作者:小菜鸟一枚   
前言:
  坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源: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.先跑起来看看

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

  3.这是刚刚出现的错误提示,这里调试一下就知道是判断字符串长度,0x1D就是29位:
0040132E   .  837E F4 1D    cmp dword ptr ds:[esi-0xC],0x1D
00401332   .  0F84 A5000000 je 【2023春.004013DD
00401338   .  C70424 D03344>mov dword ptr ss:[esp],【2023春.004433D0
0040133F   .  BF 34004400   mov edi,【2023春.00440034                  ;  Length Error, please try again
  4.输入12345678912345678912345678900测试,继续往下调试,发现会提示错误,可以看到有一个跳转过来,点上去发现是一个cmp比较下来的。
00401501   > \C70424 D03344>mov dword ptr ss:[esp],【2023春.004433D0
00401508   .  BA 61004400   mov edx,【2023春.00440061                  ;  Wrong,please try again.
00401417   .  381C32        cmp byte ptr ds:[edx+esi],bl
0040141A      0F85 E1000000 jnz 【2023春.00401501
  5.重来,打上断点,看看这里比较的是什么,右键-数据窗口中跟随-》内存地址,发现比较的好像就是我输入的字符串的第一个字符1。

  6.将下面的jnz nop掉,在这里反复循环几次看看,验证了我的猜想,那就笨办法一步步读出每一个字符,在纸上记录下来,最终得到flag:flag{52PoJie2023HappyNewYear},输入验证一下,成功。
  7.用od分析到长度判断后可以用ida动态调试,如果直接看会有点晕,但是刚刚od里面已经分析长度为29,所以这里*(v14[0] - 12)就是我输入字符串的长度。
  if ( *(v14[0] - 12) == 29 )
  {
    v13 = 0;
    while ( 1 )
    {
      if ( *(v14[0] - 12 + 8) >= 0 )
        _ZNSs12_M_leak_hardEv(v14);
      if ( *(v14[0] + v13) != (dword_43F000[v13] >> 2) )
        break;
      if ( ++v13 >= *(v14[0] - 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。

注: 2 dup(1C0),指的是两个1C0,写脚本复制别漏了。
  9.可根据上面的分析编写脚本:
#include
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 >2);;
    }
    return 1;
}

0x3 题三
  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;
    }
  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;
    }
  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 题四
  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();
        }
    }
  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));
    }
  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[length];
        int i = length - 1;
        while (i >= 0) {
            int i2 = i - 1;
            cArr = (char) (str.charAt(i) ^ '5');
            if (i2
  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 = 0 && Intrinsics.compare((int) str.charAt(i2), 90)  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;
    }
  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[length];
        int i = length - 1;
        while (i >= 0) {
            int i2 = i - 1;
            cArr = (char) (uid.charAt(i) ^ '5');
            if (i2 = 0 && (str.charAt(i2) - 90)  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 = 0 && number
  6.这里写脚本,我是照着前面分析的来,先取我的uid直接拼上Wuaipojie2023,然后几个调用的方法直接把代码copy过来,报错的哪些检查语句直接删掉,Intrinsics.compare这个函数不能删,是比较用的,百度一下就能改造,所有方法改为静态的即可,但是最后一直是乱码,和别人的对比发现主要在md5后的16进制转换没有做。

字符串, 代码

naizui401   

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

学习知识,谢谢讲述
wflb826   

坚持写学习笔记 赞个
凉水白开   

这个学习了
cjx09231211   

坚持写学习笔记
pq2006   

坚持学习冲!
水蜜桃好甜   

贵在坚持,楼主加油!
elecfun   

学习一下
elecfun   

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


QQ五笔截图未命名.jpg (69.21 KB, 下载次数: 0)
下载附件
2023-2-8 23:21 上传
您需要登录后才可以回帖 登录 | 立即注册