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

admin 2026-10-22 07:45:52 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

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 leftandright_get_onebyte(byte, offset):    tmp1 = (byte << offset) & 0xFF    tmp2 = (byte >> (8 - offset)) & 0xFF    return tmp1 | tmp2def init_data(input_array, data):    for i in range(len(data)):        data[i] = leftandright_get_onebyte(input_array[i], ((i % 7) + 1))    return 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 sub1313(b):    if b == 0x00:        return 0x00    v3 = 255    v2 = 1    v4 = b    while(v3 != 0):        if (v3 & 0x01) != 0:            v2 = v4 * v2 % 257        v4 = v4 * v4 % 257        v3 = v3 >> 1    return v2 & 0xFF

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

转换成python代码为:

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

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

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

完整的python实现就是:

def leftandright_get_onebyte(byte, offset):    tmp1 = (byte << offset) & 0xFF    tmp2 = (byte >> (8 - offset)) & 0xFF    return tmp1 | tmp2def init_data(input_array, data):    for i in range(len(data)):        data[i] = leftandright_get_onebyte(input_array[i], ((i % 7) + 1))    return datadef sub1313(b):    if b == 0x00:        return 0x00    v3 = 255    v2 = 1    v4 = b    while(v3 != 0):        if (v3 & 0x01) != 0:            v2 = v4 * v2 % 257        v4 = v4 * v4 % 257        v3 = v3 >> 1    return v2 & 0xFFdef sub_12DE(b, offset):    tmp1 = (b >> offset) & 0xff    tmp2 = (b << (8 - offset)) & 0xff    return tmp1 | tmp2def sub13E1(b):    tmp1 = leftandright_get_onebyte(b ^ 0x5a, 3)    tmp2 = sub1313(((16 * ((3 * (tmp1 >> 4)) & 0xF)) | (5 * (tmp1 & 0xF)) & 0xF) & 0xFF)    return sbox[sub_12DE(tmp2, 2)]sbox = [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 = b'testtesttesttest'v10 = init_data(bytearray(input_bytes), [0] * len(input_bytes))data = []for i in range(len(input_bytes)):    data.append(sub13E1(v10[i]))print(data)

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

def leftandright_get_onebyte(byte, offset):    tmp1 = (byte << offset) & 0xFF    tmp2 = (byte >> (8 - offset)) & 0xFF    return tmp1 | tmp2def init_data(input_array, data):    for i in range(len(data)):        data[i] = leftandright_get_onebyte(input_array[i], ((i % 7) + 1))    return datadef sub1313(b):    if b == 0x00:        return 0x00    v3 = 255    v2 = 1    v4 = b    while(v3 != 0):        if (v3 & 0x01) != 0:            v2 = v4 * v2 % 257        v4 = v4 * v4 % 257        v3 = v3 >> 1    return v2 & 0xFFdef sub_12DE(b, offset):    tmp1 = (b >> offset) & 0xff    tmp2 = (b << (8 - offset)) & 0xff    return tmp1 | tmp2def sub13E1(b):    tmp1 = leftandright_get_onebyte(b ^ 0x5a, 3)    tmp2 = sub1313(((16 * ((3 * (tmp1 >> 4)) & 0xF)) | (5 * (tmp1 & 0xF)) & 0xF) & 0xFF)    return sbox[sub_12DE(tmp2, 2)]sbox = [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 = b'testtesttesttest'v10 = init_data(bytearray(input_bytes), [0] * len(input_bytes))data = []for i in range(len(input_bytes)):    data.append(sub13E1(v10[i]))print(data)target = [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 = b''for i in range(len(target)):    for c in range(0x20, 0x7f):        cipher1 = leftandright_get_onebyte(c, ((i % 7) + 1))        if sub13E1(cipher1) == target[i]:            flag += bytes([c])            breakprint(flag)

运行后成功解密:

b'Bl@st1ng_1s_a_g00d_Way!!'

ctfplus-逆向每周练习-baby_Java、hardtest" 网络安全文章

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

本文解析了CTF逆向挑战baby_Java和hardtest的解题过程。baby_Java通过反编译发现需将输入字符串反转后Base64编码比对,直接解码反转即可得flag。hardtest涉及复杂加密流程,包括字节移位、模幂运算和S盒替换,需逆向分析各函数后爆破求解。文档提供了完整的Python实现代码和逆向思路。
评论:0   参与:  0