2023 香山杯 RE部分题解

发布时间 2023-10-15 19:03:59作者: 阿威在潜水
 

 URL从哪里来

 main函数断点下载这里

 然后可以看到TempFileName,是out.exe.tmp,还包含路径,直接提取出来用IDA打开,一开始被url误导了,看到了下面的RC4加密去了,使用findcryt软件,看到一个base64加密,

交叉引用 在这

动态调试这个函数 里面的a1,有一串字符是base64密文 ,解密后得到flag

hello_py

算法助手监控,有删除文件的操作,里面应该就保存了py,文件,但直接搜没有搜到,本来想防止他删除导出的,但是在apk里面搜到了一个app.xml,使用压缩软件打开,有个hello.py,就是目标文件。打开后有混淆,使用gpt重命名下

 

from java import jboolean, jclass
import struct
import ctypes


def mix(value1, value2, value3, array, index, value4):
    result1 = (value1.value >> 5 ^ value2.value << 2) + (value2.value >> 3 ^ value1.value << 4)
    result2 = (value3.value ^ value2.value) + (array[(index & 3) ^ value4.value] ^ value1.value)
    return ctypes.c_uint32(result1 ^ result2)


#TEA
def encrypt(num_blocks, input_data, key):
    delta = 0x9e3779b9
    num_rounds = 6 + 52 // num_blocks
    output_data = ctypes.c_uint32(0)
    previous_block = ctypes.c_uint32(input_data[num_blocks - 1])
    sum_value = ctypes.c_uint32(0)

    while num_rounds > 0:
        sum_value.value += delta
        temp_value = (sum_value.value >> 2) & 3

        for i in range(num_blocks - 1):
            next_block = ctypes.c_uint32(input_data[i + 1])
            input_data[i] = ctypes.c_uint32(
                input_data[i] + mix(previous_block, next_block, sum_value, key, i, temp_value).value).value
            previous_block.value = input_data[i]

        next_block = ctypes.c_uint32(input_data[0])
        input_data[num_blocks - 1] = ctypes.c_uint32(
            input_data[num_blocks - 1] + mix(previous_block, next_block, sum_value, key, num_blocks - 1,
                                             temp_value).value).value
        previous_block.value = input_data[num_blocks - 1]

        num_rounds -= 1

    return input_data


def check(input_string):
    print("checking~~~: " + input_string)
    input_string = str(input_string)

    if len(input_string) != 36:
        return jboolean(False)

    block_strings = []
    for i in range(0, 36, 4):
        block = input_string[i:i + 4].encode('latin-1')
        block_strings.append(block)

    input_data = []
    for block in block_strings:
        input_data.append(struct.unpack("<I", block)[0])
    print(input_data)

    encrypted_data = encrypt(9, input_data, [12345678, 12398712, 91283904, 12378192])
    expected_output = [689085350, 626885696, 1894439255, 1204672445, 1869189675, 475967424, 1932042439, 1280104741,
                       2808893494]

    for i in range(9):
        if expected_output[i] != encrypted_data[i]:
            return jboolean(False)
    return jboolean(True)


def say_hello():
    print("hello from py")

 

关键在check里面,调用了一个xxtea加密,编写解密脚本

 

import struct
from ctypes import *


def MX(z, y, total, key, p, e):
    temp1 = (z.value >> 5 ^ y.value << 2) + (y.value >> 3 ^ z.value << 4)
    temp2 = (total.value ^ y.value) + (key[(p & 3) ^ e.value] ^ z.value)

    return c_uint32(temp1 ^ temp2)


def encrypt(n, v, key):
    delta = 0x9e3779b9
    rounds = 6 + 52 // n

    total = c_uint32(0)
    z = c_uint32(v[n - 1])
    e = c_uint32(0)

    while rounds > 0:
        total.value += delta
        e.value = (total.value >> 2) & 3
        for p in range(n - 1):
            y = c_uint32(v[p + 1])
            v[p] = c_uint32(v[p] + MX(z, y, total, key, p, e).value).value
            z.value = v[p]
        y = c_uint32(v[0])
        v[n - 1] = c_uint32(v[n - 1] + MX(z, y, total, key, n - 1, e).value).value
        z.value = v[n - 1]
        rounds -= 1

    return v


def decrypt(n, v, key):
    delta = 0x9e3779b9
    rounds = 6 + 52 // n

    total = c_uint32(rounds * delta)
    y = c_uint32(v[0])
    e = c_uint32(0)

    while rounds > 0:
        e.value = (total.value >> 2) & 3
        for p in range(n - 1, 0, -1):
            z = c_uint32(v[p - 1])
            v[p] = c_uint32((v[p] - MX(z, y, total, key, p, e).value)).value
            y.value = v[p]
        z = c_uint32(v[n - 1])
        v[0] = c_uint32(v[0] - MX(z, y, total, key, 0, e).value).value
        y.value = v[0]
        total.value -= delta
        rounds -= 1

    return v


#  test
if __name__ == "__main__":
# 该算法中每次可加密不只64bit的数据,并且加密的轮数由加密数据长度决定
    v = [689085350, 626885696, 1894439255, 1204672445, 1869189675, 475967424, 1932042439, 1280104741,
                       2808893494]
    k = [12345678, 12398712, 91283904, 12378192]
    n = 9

# print("Data is : ", hex(v[0]), hex(v[1]))
# res = encrypt(n, v, k)
# print("Encrypted data is : ", hex(res[0]), hex(res[1]))
    res = decrypt(n, v, k)
    print("Decrypted data is : ", hex(res[0]), hex(res[1]))
    bytes_object = b''.join(struct.pack('<I', number) for number in res)

# 将字节对象解码为字符串,你可以指定编码(例如'utf-8','latin-1'等)
# 如果转换过程中出现错误,你可以尝试使用不同的编码
    string = bytes_object.decode('latin-1', errors='ignore')

    print(string)
"""
Data is :  0x12345678 0x78563412
Encrypted data is :  0xef86c2bb 0x25f31b5e
Decrypted data is :  0x12345678 0x78563412
"""
#c1f8ace6-4b46-4931-b25b-a1010a89c592