ctfplus-逆向每周练习-baby_Java、hardtest

admin 2026-06-16 04:48:55 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文解析了CTF逆向挑战babyJava和hardtest的解题过程。babyJava通过反编译发现需将输入字符串反转后Base64编码比对,直接解码反转即可得flag。hardtest涉及复杂加密流程,包括字节移位、模幂运算和S盒替换,需逆向分析各函数后爆破求解。文档提供了完整的Python实现代码和逆向思路。 综合评分: 85 文章分类: CTF,逆向分析,二进制安全,WEB安全,漏洞分析


cover_image

ctfplus-逆向每周练习-baby_Java、hardtest

原创

李北辰 李北辰

SPEEDCoding

2026年6月14日 20:30 山西

在小说阅读器读本章

去阅读

#

1.baby_Java

使用idea打开class文件反编译,源码非常简短:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by FernFlower decompiler)//import java.util.Base64;import java.util.Scanner;public class ReverseChallenge {public ReverseChallenge() {    }public static void main(String[] args) {        String encodedFlag = "fWVzcmV2ZXJfb3RfeXNhZV9zaV9hdmFKe0ZUQ1NEUA==";        Scanner scanner = new Scanner(System.in);        System.out.print("Check your flag: ");        String input = scanner.nextLine();        String reversed = (new StringBuilder(input)).reverse().toString();        String encodedInput = Base64.getEncoder().encodeToString(reversed.getBytes());if (encodedInput.equals(encodedFlag)) {            System.out.println("Correct flag!");        } else {            System.out.println("Incorrect flag!");        }    }}

可以看到是用户输入字符串,然后反转再base64编码,与目标比较,直接做python脚本解题,把目标base64编码字符串解码然后反转就可以拿到flag:

importbase64target_base64="fWVzcmV2ZXJfb3RfeXNhZV9zaV9hdmFKe0ZUQ1NEUA=="flag_reverse=base64.b64decode(target_base64)print(flag_reverse[::-1])

输出:

'PDSCTF{Java_is_easy_to_reverse}'

2.hardtest

拖入IDA中反编译,进入主函数,发现需要输入一个随机数进入下一步,需要用户输入flag,输入进来后计算长度,接下来就是调用init_v10(重新命名了一下)这个函数,根据输入的flag生成v10。

init_v10函数进入后继续分析,v10的每位都需要根据sub_12A9生成

继续进入sub_12A9函数分析,传入的下标范围限制在1-7(包括7),input_byte左移index位,然后input_byte再右移(8-index)位,两者再做或运算,看汇编代码,这两次都不影响一开始的input_byte的初始值,把它重命名为leftandright_get_onebyte:

转换为python脚本:

def&nbsp;leftandright_get_onebyte(byte, offset):&nbsp; &nbsp; tmp1 = (byte&nbsp;<< offset) &&nbsp;0xFF&nbsp; &nbsp; tmp2 = (byte&nbsp;>> (8&nbsp;- offset)) &&nbsp;0xFF&nbsp; &nbsp;&nbsp;return&nbsp;tmp1 | tmp2def&nbsp;init_data(input_array, data):&nbsp; &nbsp;&nbsp;for&nbsp;i in&nbsp;range(len(data)):&nbsp; &nbsp; &nbsp; &nbsp; data[i] = leftandright_get_onebyte(input_array[i], ((i %&nbsp;7) +&nbsp;1))&nbsp; &nbsp;&nbsp;return&nbsp;data

然后开始加密函数sub_13E1,这个函数对刚才生成的data逐字节加密:

这里对每个字节再做一遍刚才分析的左移右移操作,然后调用函数sub_1313,再调用函数sub_12DE,再byte_2020中检索出来对应的字节替换,加密完成,先看sub1313:

这里如果传入的参数等于0则直接返回0,不为0的话,开始进入循环,v3初始值是255(0xff),每次加密完后,右移1位,对应的每次循环的v3等于:0xff,0x7f,0x3f,0x1f,0x0f,0x07,0x03,0x01,8次循环,循环体内v2的初始值是1,然后每次如果v3是奇数的话(确实每次都是奇数),v2等于v4乘v2再对257求余,v4初始值是传入的a1,然后v4又等于v4乘v4再对257求余,sub1313转换成python脚本如下:

def&nbsp;sub1313(b):&nbsp; &nbsp;&nbsp;if&nbsp;b ==&nbsp;0x00:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;0x00&nbsp; &nbsp;&nbsp;v3&nbsp;=&nbsp;255&nbsp; &nbsp;&nbsp;v2&nbsp;=&nbsp;1&nbsp; &nbsp;&nbsp;v4&nbsp;= b&nbsp; &nbsp;&nbsp;while(v3 !=&nbsp;0):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(v3 &&nbsp;0x01) !=&nbsp;0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v2&nbsp;= v4 * v2 %&nbsp;257&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v4&nbsp;= v4 * v4 %&nbsp;257&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v3&nbsp;= v3 >>&nbsp;1&nbsp; &nbsp;&nbsp;return&nbsp;v2 &&nbsp;0xFF

然后看sub_12DE,传入的是上一步函数获取的字节,第二个参数是常数2,然后把这个字节右移对应offset获得一个数,左移(8-offset)位获得一个数,两个数进行或运算

转换成python代码为:

def sub_12DE(b,&nbsp;offset):&nbsp; &nbsp; tmp1&nbsp;=&nbsp;(b&nbsp;>>&nbsp;offset)&nbsp;&&nbsp;0xff&nbsp; &nbsp; tmp2&nbsp;=&nbsp;(b&nbsp;<<&nbsp;(8&nbsp;-&nbsp;offset))&nbsp;&&nbsp;0xff&nbsp; &nbsp;&nbsp;return&nbsp;tmp1&nbsp;|&nbsp;tmp2

这一步结束后拿到一个0-255的下标,然后去sbox里面替换值,sbox是byte_2020:

加密完成后就是跟密文字节数组byte_2120做比较:

完整的python实现就是:

def&nbsp;leftandright_get_onebyte(byte, offset):&nbsp; &nbsp;&nbsp;tmp1&nbsp;= (byte << offset) &&nbsp;0xFF&nbsp; &nbsp;&nbsp;tmp2&nbsp;= (byte >> (8&nbsp;- offset)) &&nbsp;0xFF&nbsp; &nbsp;&nbsp;return&nbsp;tmp1 | tmp2def&nbsp;init_data(input_array, data):&nbsp; &nbsp;&nbsp;for&nbsp;i in range(len(data)):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;data[i] = leftandright_get_onebyte(input_array[i], ((i %&nbsp;7) +&nbsp;1))&nbsp; &nbsp;&nbsp;return&nbsp;datadef&nbsp;sub1313(b):&nbsp; &nbsp;&nbsp;if&nbsp;b ==&nbsp;0x00:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;0x00&nbsp; &nbsp;&nbsp;v3&nbsp;=&nbsp;255&nbsp; &nbsp;&nbsp;v2&nbsp;=&nbsp;1&nbsp; &nbsp;&nbsp;v4&nbsp;= b&nbsp; &nbsp;&nbsp;while(v3 !=&nbsp;0):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(v3 &&nbsp;0x01) !=&nbsp;0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v2&nbsp;= v4 * v2 %&nbsp;257&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v4&nbsp;= v4 * v4 %&nbsp;257&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v3&nbsp;= v3 >>&nbsp;1&nbsp; &nbsp;&nbsp;return&nbsp;v2 &&nbsp;0xFFdef&nbsp;sub_12DE(b, offset):&nbsp; &nbsp;&nbsp;tmp1&nbsp;= (b >> offset) &&nbsp;0xff&nbsp; &nbsp;&nbsp;tmp2&nbsp;= (b << (8&nbsp;- offset)) &&nbsp;0xff&nbsp; &nbsp;&nbsp;return&nbsp;tmp1 | tmp2def&nbsp;sub13E1(b):&nbsp; &nbsp;&nbsp;tmp1&nbsp;= leftandright_get_onebyte(b ^&nbsp;0x5a,&nbsp;3)&nbsp; &nbsp;&nbsp;tmp2&nbsp;= sub1313(((16&nbsp;* ((3&nbsp;* (tmp1 >>&nbsp;4)) &&nbsp;0xF)) | (5&nbsp;* (tmp1 &&nbsp;0xF)) &&nbsp;0xF) &&nbsp;0xFF)&nbsp; &nbsp;&nbsp;return&nbsp;sbox[sub_12DE(tmp2,&nbsp;2)]sbox&nbsp;=&nbsp;[99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22]input_bytes&nbsp;= b'testtesttesttest'v10&nbsp;= init_data(bytearray(input_bytes),&nbsp;[0] * len(input_bytes))data = []for&nbsp;i in range(len(input_bytes)):&nbsp; &nbsp;&nbsp;data.append(sub13E1(v10[i]))print(data)

这个加密算法是根据输入字节数组的每位进行运算,每位直接互相不影响,所以可以根据目标字节数组进行爆破即可:

def&nbsp;leftandright_get_onebyte(byte, offset):&nbsp; &nbsp;&nbsp;tmp1&nbsp;= (byte << offset) &&nbsp;0xFF&nbsp; &nbsp;&nbsp;tmp2&nbsp;= (byte >> (8&nbsp;- offset)) &&nbsp;0xFF&nbsp; &nbsp;&nbsp;return&nbsp;tmp1 | tmp2def&nbsp;init_data(input_array, data):&nbsp; &nbsp;&nbsp;for&nbsp;i in range(len(data)):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;data[i] = leftandright_get_onebyte(input_array[i], ((i %&nbsp;7) +&nbsp;1))&nbsp; &nbsp;&nbsp;return&nbsp;datadef&nbsp;sub1313(b):&nbsp; &nbsp;&nbsp;if&nbsp;b ==&nbsp;0x00:&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;0x00&nbsp; &nbsp;&nbsp;v3&nbsp;=&nbsp;255&nbsp; &nbsp;&nbsp;v2&nbsp;=&nbsp;1&nbsp; &nbsp;&nbsp;v4&nbsp;= b&nbsp; &nbsp;&nbsp;while(v3 !=&nbsp;0):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(v3 &&nbsp;0x01) !=&nbsp;0:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v2&nbsp;= v4 * v2 %&nbsp;257&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v4&nbsp;= v4 * v4 %&nbsp;257&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;v3&nbsp;= v3 >>&nbsp;1&nbsp; &nbsp;&nbsp;return&nbsp;v2 &&nbsp;0xFFdef&nbsp;sub_12DE(b, offset):&nbsp; &nbsp;&nbsp;tmp1&nbsp;= (b >> offset) &&nbsp;0xff&nbsp; &nbsp;&nbsp;tmp2&nbsp;= (b << (8&nbsp;- offset)) &&nbsp;0xff&nbsp; &nbsp;&nbsp;return&nbsp;tmp1 | tmp2def&nbsp;sub13E1(b):&nbsp; &nbsp;&nbsp;tmp1&nbsp;= leftandright_get_onebyte(b ^&nbsp;0x5a,&nbsp;3)&nbsp; &nbsp;&nbsp;tmp2&nbsp;= sub1313(((16&nbsp;* ((3&nbsp;* (tmp1 >>&nbsp;4)) &&nbsp;0xF)) | (5&nbsp;* (tmp1 &&nbsp;0xF)) &&nbsp;0xF) &&nbsp;0xFF)&nbsp; &nbsp;&nbsp;return&nbsp;sbox[sub_12DE(tmp2,&nbsp;2)]sbox&nbsp;=&nbsp;[99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22]input_bytes&nbsp;= b'testtesttesttest'v10&nbsp;= init_data(bytearray(input_bytes),&nbsp;[0] * len(input_bytes))data = []for&nbsp;i in range(len(input_bytes)):&nbsp; &nbsp;&nbsp;data.append(sub13E1(v10[i]))print(data)target&nbsp;=&nbsp;[151, 213, 96, 67, 180, 16, 67, 115, 15, 218, 67, 205, 211, 232, 115, 74, 148, 195, 205, 113, 189, 220, 151, 26]flag&nbsp;= b''for&nbsp;i in range(len(target)):&nbsp; &nbsp;&nbsp;for&nbsp;c in range(0x20,&nbsp;0x7f):&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;cipher1&nbsp;= leftandright_get_onebyte(c, ((i %&nbsp;7) +&nbsp;1))&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;sub13E1(cipher1) == target[i]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;flag&nbsp;+= bytes([c])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;breakprint(flag)

运行后成功解密:

b'Bl@st1ng_1s_a_g00d_Way!!'

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:SPEEDCoding 李北辰 李北辰《ctfplus-逆向每周练习-baby_Java、hardtest》

评论:0   参与:  0