吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2871|回复: 29
收起左侧

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

  [复制链接]
小菜鸟一枚 发表于 2023-2-8 20:28

前言:

  坛友们,年轻就是资本,和我一起逆天改命吧,我的学习过程全部记录及学习资源: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:[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。

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

  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。

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[i]>>2);;
    }

    return 1;
}

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

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[i] = (char) (str.charAt(i) ^ '5');
            if (i2 < 0) {
                break;
            }
            i = i2 - 1;
            cArr[i2] = (char) (str.charAt(i2) ^ '2');
        }
        return new String(cArr);
    }
}

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

  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;
    }

  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[i] = (char) (uid.charAt(i) ^ '5');
            if (i2 < 0) {
                break;
            }
            i = i2 - 1;
            cArr[i2] = (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[i] & 0xff;
            String hex = Integer.toHexString(number);
            if (number >= 0 && number < 16) {
                sb.append("0" + hex);
            } else {
                sb.append(hex);
            }
        }
        return sb.toString();
    }
}

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

免费评分

参与人数 4威望 +1 吾爱币 +23 热心值 +3 收起 理由
weijiabin + 1 用心讨论,共获提升!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
skiss + 1 + 1 谢谢@Thanks!
水蜜桃好甜 + 1 + 1 我很赞同!

查看全部评分

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

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

QQ五笔截图未命名.jpg

点评

逻辑上是等价的就行,while里面给 i-1 了  详情 回复 发表于 2023-2-9 15:26
侃遍天下无二人 发表于 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题了,直接点击这里下载即可

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
小菜鸟一枚 + 1 + 1 谢谢@Thanks!

查看全部评分

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
学习一下
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

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

GMT+8, 2024-5-3 03:55

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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