RE_TEA加密

TEA这段时间遇到的是真多,有直接原始加密,也有 XTEA,XXTEA,更有在此上魔改的,之前也是能认出来,知道还是不够。

en,TEA加密解密脚本还是用 C 好一些,什么溢出之类不用考虑。

打印明文:

	char* p = (char*)flag;
	for (int j = 0; j < 8 * 4; j++)
	{
		printf("%c", *(p + j));
	}
	printf("}");
void print_char(int enc){
    cout << (unsigned char)((enc >> 24) & 0xff);
    cout << (unsigned char)((enc >> 16) & 0xff);
    cout << (unsigned char)((enc >> 8) & 0xff);
    cout << (unsigned char)(enc & 0xff);
}

 第二种更通用吧。

TEA

也有可能是 64 轮迭代

def encrypt(v, k):
    v0, v1 = v[0], v[1]
    sum = 0
    delta = 0x9e3779b9
    k0, k1, k2, k3 = k[0], k[1], k[2], k[3]
    for i in range(32):
        sum = (sum + delta) & 0xffffffff
        v0 = (v0 + (((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1))) & 0xffffffff
        v1 = (v1 + (((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3))) & 0xffffffff
    return [v0, v1]
#确保它们在 32 位整数范围内
if __name__ == "__main__":
    data = [1234, 5678]
    key = [1, 2, 3, 4]
    enc = encrypt(data, key)
    print(enc)
def decrypt(v,k):
    v0,v1=v[0],v[1]
    delta=0x9e3779b9
    k0,k1,k2,k3=k[0],k[1],k[2],k[3]
    sum=(delta*32)&0xffffffff
    for i in range(32):
        v1 = (v1 - (((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3))) & 0xffffffff
        v0 = (v0 - (((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1))) & 0xffffffff
        sum = (sum - delta) & 0xffffffff
    v[0],v[1]=v0,v1
    return v

if __name__=="__main__":
    data=[731179895, 2211051369]
    key=[1,2,3,4]
    res=decrypt(data,key)
    print(res)

在python中, 最好不要使用 “-=”,和 C 不同,害我改了半天,xp。

XTEA

就是每轮加密不同
 

def encrypt(v, k):
    v0, v1 = v[0], v[1]
    sum = 0
    delta = 0x9e3779b9
    k0, k1, k2, k3 = k[0], k[1], k[2], k[3]
    for i in range(32):
        v0=v0+((((v1<<4) ^ (v1>>5))+v1) ^ (sum+k[sum&3]))&0xffffffff
        sum=(sum+delta)&0xffffffff
        v1=v1+((((v0<<4) ^ (v0>>5))+v0) ^ (sum+k[(sum>>11)&3]))&0xffffffff
    return [v0, v1]
#确保它们在 32 位整数范围内
if __name__ == "__main__":
    data = [1234, 5678]
    key = [1,2, 3, 4]
    enc = encrypt(data, key)
    print(enc)

key[sum & 3 ]

sum & 3 保证索引在 k0 到 k3 之间循环, 3 是 ‘11’,故只保留sum后两位

(sum + k[sum & 3]) 

这个操作首先将 sum 右移 11 位,然后再进行按位与操作 & 3。这个操作同样可以确保结果在 0 到 3 之间,但它使用的是 sum 的第 12 和 13 位

def encrypt(v, k):
    v0, v1 = v[0], v[1]
    sum = (0x9e3779b9*32)&0xffffffff
    delta = 0x9e3779b9
    k0, k1, k2, k3 = k[0], k[1], k[2], k[3]
    for i in range(32):
        v1 = v1 - ((((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3])) & 0xffffffff
        sum=(sum-delta)&0xffffffff
        v0 = v0 - ((((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3])) & 0xffffffff
    return [v0, v1]
#确保它们在 32 位整数范围内
if __name__ == "__main__":
    data = [1787803488, 3495090297]
    key = [1,2, 3, 4]
    enc = encrypt(data, key)
    print(enc)

XXTEA

有点复杂

还有 C 的版本:

TEA、XTEA、XXTEA加密解密算法-CSDN博客

例题:

[HNCTF 2022 WEEK2]TTTTTTTTTea

应该是XTEA加密

 key 都是 32位数,故写成四个八位的数组

key=[0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f]

也可以按 D 换成 dw ,dd

唉,没几个大佬分析前面的,是我太菜了!

exp:

大佬都是用 C 写的,确实好写一些好像

为加强理解,我用 python写一个,还是有一点小问题:

enc = [0xC11EE75A, 0xA4AD0973, 0xF61C9018, 0x32E37BCD, 0x2DCC1F26, 0x344380CC]

def decrypt(enc1, enc2):
    key = [0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]
    delta = 0x9e3779b9
    sum = (delta * 32) & 0xffffffff
    for i in range(32):
        enc2 = (enc2 - ((((enc1 >> 5) ^ (enc1 << 4)) + enc1) ^ (key[(sum >> 11) & 3] + sum))) & 0xffffffff
        sum = (sum - delta) & 0xffffffff
        enc1 = (enc1 - ((((enc2 >> 5) ^ (enc2 << 4)) + enc2) ^ (key[sum & 3] + sum))) & 0xffffffff
    return enc1, enc2

data = []
for i in range(0, 6, 2):
    res1, res2 = decrypt(enc[i], enc[i + 1])
    data.append(res1)
    data.append(res2)

print(data)
for value in data:
    print(chr((value >> 24) & 0xff) + chr((value >> 16) & 0xff) + chr((value >> 8) & 0xff) + chr(value & 0xff), end='')
#CSSNT{FTT_aeT_AET_Ae}+aE

啊!差了一点,去看看哪里有问题,啊,没找到

#include<stdio.h>

int main()
{
	unsigned int enc[6] = { 0xC11EE75A, 0xA4AD0973, 0xF61C9018, 0x32E37BCD, 0x2DCC1F26, 0x344380CC };
	unsigned int key[4] = { 0x10203, 0x4050607, 0x8090A0B, 0x0C0D0E0F };
	int i, j;
	long sum = 0, delta = 0x61C88647;
	// 解码
	for (i = 0; i < 6; i += 2) {
		sum = 0 - (32 * delta);
		for (j = 0; j < 32; j++) {
			enc[i + 1] -= (((enc[i] >> 5) ^ (16 * enc[i])) + enc[i]) ^ (key[((sum >> 11) & 3)] + sum);
			sum += delta;
			enc[i] -= ((((enc[i + 1] >> 5) ^ (16 * enc[i + 1])) + enc[i + 1]) ^ key[sum & 3] + sum);
		}
	}
	// 打印
	for (i = 0; i < 6; i++)
	{
		for (j = 0; j <= 3; j++)
		{
			printf("%c", (enc[i] >> (j * 8)) & 0xFF);
		}
	}

	return 0;
}

[MoeCTF 2022]ezTea

#include <stdio.h>
#include <stdint.h>

void encrypt (uint32_t* v, uint32_t* k) {                       // 主要加密函数,试着搞定它
    uint32_t v0 = v[0], v1 = v[1], sum = 0;
    uint32_t delta = 0xd33b470;
    for (int i = 0; i < 32; i++) {
        sum += delta;
        v0 += ((v1<<4) + k[0]) ^ (v1 + sum) ^ ((v1>>5) + k[1]);
        v1 += ((v0<<4) + k[2]) ^ (v0 + sum) ^ ((v0>>5) + k[3]);
    }
    v[0] = v0;
    v[1] = v1;
}
void decrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0;
    uint32_t delta = 0xd33b470*32;
    for (int i = 0; i < 32; i++) {
        v1 -= ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
        v0 -= ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
        sum -= delta;
    }
    v[0] = v0;
    v[1] = v1;
}
int main() {
    uint32_t k[4] = {1, 2, 3, 4};
    int8_t input[33] = { 0x17, 0x65, 0x54, 0x89, 0xed, 0x65, 0x46, 0x32, 0x3d, 0x58, 0xa9, 0xfd, 0xe2, 0x5e,
0x61, 0x97, 0xe4, 0x60, 0xf1, 0x91, 0x73, 0xe9, 0xe9, 0xa2, 0x59, 0xcb, 0x9a, 0x99,
0xec, 0xb1, 0xe1, 0x7d };
    
    scanf("%32s", input);
    for (int i = 0; i < 32; i+=8) {
        uint32_t v[2] = {*(uint32_t *)&input[i], *(uint32_t *)&input[i+4]};
        decrypt(v, k);
        for (int j = 0; j < 2; j++) {                           // 这一段主要是把 v 按单字节输出,另外可以了解一下 “大小端序” 在这题是如何体现的
            for (int k = 0; k < 4; k++) {
                printf("%#x, ", v[j] & 0xff);
                v[j] >>= 8;
            }
        }
    }
    return 0;
}

直接对照 encrypt()函数来写 decrypt()函数,然后修改一些问题。

#include <stdio.h>
#include <stdint.h>

void encrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0;
    uint32_t delta = 0xd33b470;
    for (int i = 0; i < 32; i++) {
        sum += delta;
        v0 += ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
        v1 += ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
    }
    v[0] = v0;
    v[1] = v1;
}

void decrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1];
    uint32_t delta = 0xd33b470;
    uint32_t sum = delta * 32;
    for (int i = 0; i < 32; i++) {
        v1 -= ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
        v0 -= ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]);
        sum -= delta;
    }
    v[0] = v0;
    v[1] = v1;
}
int main() {
    uint32_t k[4] = { 1, 2, 3, 4 };
    uint8_t input[33] = { 0x17, 0x65, 0x54, 0x89, 0xed, 0x65, 0x46, 0x32, 0x3d, 0x58, 0xa9, 0xfd, 0xe2, 0x5e,
0x61, 0x97, 0xe4, 0x60, 0xf1, 0x91, 0x73, 0xe9, 0xe9, 0xa2, 0x59, 0xcb, 0x9a, 0x99,
0xec, 0xb1, 0xe1, 0x7d };

    //scanf("%32s", input);

    for (int i = 0; i < 32; i += 8) {
        uint32_t v[2] = { *(uint32_t*)&input[i], *(uint32_t*)&input[i + 4] };
        decrypt(v, k);
        for (int j = 0; j < 2; j++) {
            for (int b = 0; b < 4; b++) {
                printf("%c", (v[j] >> (8 * b)) & 0xff);
            }
        }
    }
    return 0;
}
//moectf{Th3_TEA_!S_s0_t4s7y~~!!!}

[HGAME 2023 week1]a_cup_of_tea

难道每一个 Buf2[i]都进行了TEA加密?

 si128 = _mm_load_si128((const __m128i *)&xmmword_1400022B0);

英特尔的 SIMD指令集的一个SSE2指令,从内存中加载一个 128 位的整数向量到一个 __m128i 类型的寄存器中 .

先得到 key

ant='0x45678901345678902345678912345678'[2:]
print(ant)
print(len(ant))
key=[]
for i in range(0,len(ant),8):
    key.append(int(ant[i:i+8],16))
print(key)

开始写脚本时发现好像不是标准的 TEA 加密,不对就是的

然后 v10 也不知道是干嘛的,还有 scanf 输入的字符存在哪,在 v10 吗?

还需要动调一下,看看,先在加密前下个断点,判断处下一个

输入了 50 个字符,v10前面有 16 个字符,是给 Buf1 的,后面 34个好像都是 v10的。

嗯,输入是有50个的限制,v10最多就34个。

首先第一个问题:

嗯,前面是我想错了,每两个Buf2对应一个 TEA,刚好8个,调用了四次。

int v1 = buf & 0xffff;  //低十六位
int v2 = (buf >> 16) & 0xffff; // 先右移高十六位变低十六位,再去除前面

en,第二个:前面 key 忘记端序的问题了

str='hello'
print(str[::-1])
ant='0x45678901345678902345678912345678'[2:]
print(ant)
print(len(ant))
key=[]
for i in range(0,len(ant),8):
    key.append(int(ant[len(ant)-8-i:len(ant)-i],16))
print(key)
#[305419896, 591751049, 878082192, 1164413185]

第三个:

C版本中的 uint32_t 和 C++ 版本中的 int,它们的位宽可能不一致。

第四个:

delta的问题:

好像是要防止什么溢出的问题;

delta*32

#include <iostream>
#include <cstdint>
using namespace std;
int main() {
    int32_t delta = 0x543210DD; // 初始化 delta
    int64_t sum = -(delta * 32LL); // 使用 64 位整型计算 sum,避免溢出
    uint32_t final_sum = static_cast<uint32_t>(sum); // 将 sum 转换为无符号 32 位整数
    std::cout << "sum = 0x" << std::hex << final_sum << std::endl;
    // 从 sum 计算 delta
    int32_t delta_from_sum = final_sum / 32;
    std::cout << "delta = 0x" << std::hex << delta_from_sum << std::endl;
    return 0;
}

得到flag。

[GDOUCTF 2023]Tea

7个数,不太合理 

这是得到的密文

直接微调代码,写出解密脚本:

#include <iostream>
using namespace std;
int main() {
	unsigned int enc[10];
	enc[0] = 0x1A800BDA;
	enc[1] = 0xF7A6219B;
	enc[2] = 0x491811D8;
	enc[3] = 0xF2013328;
	enc[4] = 0x156C365B;
	enc[5] = 0x3C6EAAD8;
	enc[6] = 0x84D4BF28;
	enc[7] = 0xF11A7EE7;
	enc[8] = 0x3313B252;
	enc[9] = 0xDD9FE279;
    int v3; // [rsp+44h] [rbp+24h]
    int i; // [rsp+64h] [rbp+44h]
    unsigned int v5; // [rsp+84h] [rbp+64h]
    unsigned int v6;
    int key[4] = { 2233,4455,6677,8899 };
    for (i = 0; i <= 8; ++i)                    // 应该要进行九次TEA加密
    {
        v5 = 0;
       // v6 = 0xF462900 * i * 33;
        v6 = 0xF462900 * (i + 33);
        v3 = i + 1;
        do
        {
            ++v5;
            v6 -= 0xF462900;
            enc[i + 1] -= (v6 + key[((v6 >> 11) & 3)]) ^ (enc[i] + ((enc[i] >> 5) ^ (16 * enc[i])));
            //*(enc + 4i64 * i) += v6 ^ (*(enc + 4i64 * v3) + ((*(enc + 4i64 * v3) >> 5) ^ (16 * *(enc + 4i64 * v3)))) ^ (v6 + *(key + 4i64 * (v6 & 3)));
            enc[i] -= v6 ^ ((enc[i + 1]) + ((enc[i + 1] >> 5) ^ (16 * enc[i + 1]))) ^ (v6 + key[v6 & 3]);
            /* *(enc + 4i64 * v3) += (v6 + *(key + 4i64 * ((v6 >> 11) & 3))) ^ (*(enc + 4i64 * i)
                 + ((*(enc + 4i64 * i) >> 5) ^ (16
                     * *(enc + 4i64 * i))));*/

        } while (v5 <= 32);     
    }
    
    for (int i = 0; i < 10; i++) {
        //cout << enc[i]<<endl;
        printf("%08x", enc[i]);
    }
    cout << endl;
    //438fdda6f4c68c79c2815bf8e85dc4e1b010d0013bf4357f65ef9185635d747c982d9a24b9b3e05
        return 0;
}

但遇到三个问题:

一,忘记逆序

应该是,不是 i=0;i<8;i++

二, 解密时 sum 的初始值

// v6 = 0xF462900 * i * 33;
 v6 = 0xF462900 * (i + 33);

 仔细想想确实是的:每次加密迭代的初始值 v6 包括了一个基数 33,从而避免小的 i 值导致的弱加密。这也确保了每次迭代都从一个较高的起点开始,有助于增强加密强度。

并且如果是第一种,i=0时,sum=0;肯定不对。

三,最后想加一个直接转换成字符串的操作


    
    for (int i = 0; i < 10; i++) {
        cout << (unsigned char)((enc[i] >> 24) & 0xff);
        cout << (unsigned char)((enc[i] >> 16) & 0xff);
        cout << (unsigned char)((enc[i] >> 8) & 0xff);
        cout << (unsigned char)(enc[i] & 0xff);
    }

这个操作是正确的,但是加上有问题:

enc打印直接变了:

f4c68c79c2815bf8e85dc4e1b010d0013bf4357f65ef9185635d747c982d9a24b9b3e05

这个不知道为什么

但是第一个问题解决再加上去是没问题的

最终exp:

#include <iostream>
using namespace std;
int main() {
	unsigned int enc[10];
	enc[0] = 0x1A800BDA;
	enc[1] = 0xF7A6219B;
	enc[2] = 0x491811D8;
	enc[3] = 0xF2013328;
	enc[4] = 0x156C365B;
	enc[5] = 0x3C6EAAD8;
	enc[6] = 0x84D4BF28;
	enc[7] = 0xF11A7EE7;
	enc[8] = 0x3313B252;
	enc[9] = 0xDD9FE279;
    int v3; // [rsp+44h] [rbp+24h]
    int i; // [rsp+64h] [rbp+44h]
    unsigned int v5; // [rsp+84h] [rbp+64h]
    unsigned int v6;
    int key[4] = { 2233,4455,6677,8899 };

    for (i = 8; i >= 0; i--)                    // 应该要进行九次TEA加密
    {
        v5 = 0;
       // v6 = 0xF462900 * i * 33;
        v6 = 0xF462900 * (i + 33);
        v3 = i + 1;
        do
        {
            ++v5;
            v6 -= 0xF462900;
            enc[i + 1] -= (v6 + key[((v6 >> 11) & 3)]) ^ (enc[i] + ((enc[i] >> 5) ^ (16 * enc[i])));
            //*(enc + 4i64 * i) += v6 ^ (*(enc + 4i64 * v3) + ((*(enc + 4i64 * v3) >> 5) ^ (16 * *(enc + 4i64 * v3)))) ^ (v6 + *(key + 4i64 * (v6 & 3)));
            enc[i] -= v6 ^ ((enc[i + 1]) + ((enc[i + 1] >> 5) ^ (16 * enc[i + 1]))) ^ (v6 + key[v6 & 3]);
            /* *(enc + 4i64 * v3) += (v6 + *(key + 4i64 * ((v6 >> 11) & 3))) ^ (*(enc + 4i64 * i)
                 + ((*(enc + 4i64 * i) >> 5) ^ (16
                     * *(enc + 4i64 * i))));*/

        } while (v5 <= 32);     
    }
    
    for (int i = 0; i < 10; i++) {
        //cout << enc[i]<<endl;
        printf("%08x", enc[i]);
    }
    cout << endl;
    for (int i = 0; i < 10; i++) {
        cout << (unsigned char)((enc[i] >> 24) & 0xff);
        cout << (unsigned char)((enc[i] >> 16) & 0xff);
        cout << (unsigned char)((enc[i] >> 8) & 0xff);
        cout << (unsigned char)(enc[i] & 0xff);
    }
    return 0;
}

[FSCTF 2023]Tea_apk        

package com.tutdroid;

import java.io.UnsupportedEncodingException;

/* loaded from: classes.dex */
public final class FlagChecker {
    static final /* synthetic */ boolean $assertionsDisabled = false;
    private static final int DELTA = -1640531527;

    private static int MX(int i, int i2, int i3, int i4, int i5, int[] iArr) {
        return ((i ^ i2) + (iArr[(i4 & 3) ^ i5] ^ i3)) ^ (((i3 >>> 5) ^ (i2 << 2)) + ((i2 >>> 3) ^ (i3 << 4)));
    }

    private FlagChecker() {
    }

    public static final byte[] encrypt(byte[] bArr, byte[] bArr2) {
        return bArr.length == 0 ? bArr : toByteArray(encrypt(toIntArray(bArr, true), toIntArray(fixKey(bArr2), false)), false);
    }

    public static final byte[] encrypt(String str, String str2) {
        try {
            return encrypt(str.getBytes("UTF-8"), str2.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException unused) {
            return null;
        }
    }

    public static final String encryptToBase64String(String str, String str2) {
        byte[] encrypt = encrypt(str, str2);
        if (encrypt == null) {
            return null;
        }
        return Base64.encode(encrypt);
    }

    private static int[] encrypt(int[] iArr, int[] iArr2) {
        int length = iArr.length - 1;
        if (length < 1) {
            return iArr;
        }
        int i = (52 / (length + 1)) + 6;
        int i2 = iArr[length];
        int i3 = 0;
        while (true) {
            int i4 = i - 1;
            if (i <= 0) {
                return iArr;
            }
            i3 += DELTA;
            int i5 = (i3 >>> 2) & 3;
            int i6 = i2;
            int i7 = 0;
            while (i7 < length) {
                int i8 = i7 + 1;
                i6 = iArr[i7] + MX(i3, iArr[i8], i6, i7, i5, iArr2);
                iArr[i7] = i6;
                i7 = i8;
            }
            i2 = MX(i3, iArr[0], i6, i7, i5, iArr2) + iArr[length];
            iArr[length] = i2;
            i = i4;
        }
    }

    private static byte[] fixKey(byte[] bArr) {
        if (bArr.length == 16) {
            return bArr;
        }
        byte[] bArr2 = new byte[16];
        if (bArr.length < 16) {
            System.arraycopy(bArr, 0, bArr2, 0, bArr.length);
        } else {
            System.arraycopy(bArr, 0, bArr2, 0, 16);
        }
        return bArr2;
    }

    private static int[] toIntArray(byte[] bArr, boolean z) {
        int[] iArr;
        int length = (bArr.length & 3) == 0 ? bArr.length >>> 2 : (bArr.length >>> 2) + 1;
        if (z) {
            iArr = new int[length + 1];
            iArr[length] = bArr.length;
        } else {
            iArr = new int[length];
        }
        int length2 = bArr.length;
        for (int i = 0; i < length2; i++) {
            int i2 = i >>> 2;
            iArr[i2] = iArr[i2] | ((bArr[i] & 255) << ((i & 3) << 3));
        }
        return iArr;
    }

    private static byte[] toByteArray(int[] iArr, boolean z) {
        int length = iArr.length << 2;
        if (z) {
            int i = iArr[iArr.length - 1];
            int i2 = length - 4;
            if (i < i2 - 3 || i > i2) {
                return null;
            }
            length = i;
        }
        byte[] bArr = new byte[length];
        for (int i3 = 0; i3 < length; i3++) {
            bArr[i3] = (byte) (iArr[i3 >>> 2] >>> ((i3 & 3) << 3));
        }
        return bArr;
    }

    public static boolean check(String str) {
        return encryptToBase64String(str, "ABvWW7hqwNvHUhfP").equals("vlgg9nNjUcYuWzBSSOwKxbMD2rhFgf4zuiyMpLxpNkM=");
    }
}

 太长了,看不了一点。

看 wp:就是原封不动的 XXTEA (刚好还没看的),去学吧。

总结

TEA加密需要先找到四个模块,1-key值,2-tea模块,3-加密后的数据(包括delta),4-wheel,然后就可以进行逆向工程了
脚本先添加key数组,unsigned int result数组,添加变量i,wheel(轮数),sum(和),dalte。然后开始写逆算法。
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值