You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言中wchar_t字符串异或加密读写后输出异常问题

处理wchar_t Unicode字符串XOR加解密时的乱码问题

问题背景

我在处理Unicode字符串(wchar_t类型)时遇到问题:程序需要接收wchar_t类型输入,对其进行XOR加密后写入文件,再读取解密并输出到命令行。修改代码后,十六进制显示解密结果正确,但输出字符串时出现多余乱码。

初始代码

const unsigned int XORKey = 0xff;

size_t XORit(const wchar_t* value, wchar_t* xorred)
{
    size_t length = wcslen(value);
    for (int i = 0; i < length; i++)
        xorred[i] = ((char)(value[i] ^ XORKey));

    return length;
}

int main()
{
    setlocale(LC_ALL, "en_US.UTF-8");
    // XOR it
    wchar_t sample[] = { L"TEST1自己人" };
    int samplelen = wcslen(sample);
    printf("%ls", sample);
    printf("\n");

    printf("Plain:\n\t");
    for (int i = 0; i < samplelen; i++)
    {
        printf("%02X ", sample[i]);
    }
    printf("\n");

    wchar_t* xorred = (wchar_t*)malloc(samplelen);
    if (xorred == NULL) return -1;
    memset(xorred, 0, samplelen);
    XORit(sample, xorred);
    printf("XOR'ed\n\t");
    for (int i = 0; i < samplelen; i++)
    {
        printf("%02X ", xorred[i]);
    }
    printf("\n");

    // Write to file
    FILE* fpW = _wfopen(L"logon.bin", L"wb");
    fwrite(xorred, sizeof(wchar_t), samplelen, fpW);
    fclose(fpW);

    // Read from file
    FILE* fpR = fopen("logon.bin", "rb");
    fseek(fpR, 0, SEEK_END);
    int filesize = ftell(fpR);
    wchar_t* unxorred = (wchar_t*)malloc(filesize + sizeof(wchar_t));
    if (unxorred == NULL) return -1;

    rewind(fpR);

    fread(unxorred, sizeof(wchar_t), filesize, fpW);
    fclose(fpW);

    printf("Reading\n\t");
    for (int i = 0; i < samplelen; i++)
    {
        printf("%02X ", unxorred[i]);
    }
    printf("\n");

    printf("Un-XOR'ed\n\t");
    for (int i = 0; i < samplelen; i++)
    {
        printf("%02X ", unxorred[i] ^ XORKey);
    }
    printf("\n");
    printf("%ls", unxorred);

    return 0;
}

修改后代码

const unsigned int XORKey = 0xff;

size_t XORit(const wchar_t* value, wchar_t* xorred)
{
    size_t length = wcslen(value);
    for (int i = 0; i < length; i++)
        xorred[i] = (value[i] ^ XORKey);

    return length;
}

int main()
{
    setlocale(LC_ALL, "en_US.UTF-8");
    // XOR it
    wchar_t sample[] = { L"Test1自己人自己人A" };
    int samplelen = wcslen(sample);
    printf("%ls", sample);
    printf("\n");

    printf("Plain:\n\t");
    for (int i = 0; i < samplelen; i++)
    {
        printf("%0*X ", (int)sizeof(wchar_t), (unsigned int)sample[i]);
    }
    printf("\n");

    wchar_t* xorred = (wchar_t*)malloc(samplelen);
    if (xorred == NULL) return -1;
    memset(xorred, 0, samplelen);
    XORit(sample, xorred);
    printf("XOR'ed\n\t");
    for (int i = 0; i < samplelen; i++)
    {
        printf("%0*X ", (int)sizeof(wchar_t), (unsigned int)xorred[i]);
    }
    printf("\n");

    // Write to file
    FILE* fpW = _wfopen(L"logon.bin", L"wb");
    fwrite(xorred, sizeof(wchar_t), samplelen, fpW);
    fclose(fpW);

    // Read from file
    FILE* fpR = fopen("logon.bin", "rb");
    fseek(fpR, 0, SEEK_END);
    int filesize = ftell(fpR);
    int whattoread = (filesize / sizeof(wchar_t));
    wchar_t* ReadXOR = (wchar_t*)malloc(filesize + 1);
    if (ReadXOR == NULL) return -1;
    memset(ReadXOR, 0, filesize + 1);

    rewind(fpR);

    fread(ReadXOR, sizeof(wchar_t), whattoread, fpR);
    fclose(fpW);

    printf("Reading\n\t");
    for (int i = 0; i < samplelen; i++)
    {
        printf("%0*X ", (int)sizeof(wchar_t), (unsigned int)ReadXOR[i]);
    }
    printf("\n");

    wchar_t* unxorred = (wchar_t*)malloc(whattoread);
    if (unxorred == NULL) return -1;
    memset(unxorred, 0, whattoread);
    printf("Un-XOR'ed\n\t");
    for (int i = 0; i < whattoread; i++)
    {
        unxorred[i] = ReadXOR[i] ^ 0xff;
        printf("%0*X ", (int)sizeof(wchar_t), (unsigned int)unxorred[i]);
    }
    printf("\n");
    printf("%ls\n", unxorred);
    printf("%ls\n", sample);

    return 0;
}

输出结果

Test1自己人自己人A
Plain:
        54 65 73 74 31 81EA 5DF1 4EBA 81EA 5DF1 4EBA 41
XOR'ed
        AB 9A 8C 8B CE 8115 5D0E 4E45 8115 5D0E 4E45 BE
Reading
        AB 9A 8C 8B CE 8115 5D0E 4E45 8115 5D0E 4E45 BE
Un-XOR'ed
        54 65 73 74 31 81EA 5DF1 4EBA 81EA 5DF1 4EBA 41
Test1自己人自己人A粘蹊?言?萉?
Test1自己人自己人A

问题分析与修复步骤

从输出可见,解密后的十六进制值完全正确,但字符串输出有多余乱码,核心问题在于宽字符串的内存分配、终止符处理以及文件操作错误:

1. 内存分配错误

malloc的参数是字节数,但代码中直接传入了字符数量(如malloc(samplelen)),而每个wchar_t占sizeof(wchar_t)字节(通常是2或4字节),导致分配的内存空间不足,后续操作可能破坏内存。

修复:分配内存时需乘以sizeof(wchar_t),并额外多分配1个字符的空间用于存储字符串终止符\0:

// 加密后的内存分配
wchar_t* xorred = (wchar_t*)malloc((samplelen + 1) * sizeof(wchar_t));
// 读取后的内存分配
wchar_t* ReadXOR = (wchar_t*)malloc(filesize + sizeof(wchar_t));
// 解密后的内存分配
wchar_t* unxorred = (wchar_t*)malloc((whattoread + 1) * sizeof(wchar_t));

2. memset大小错误

memset的第三个参数是字节数,代码中传入的是字符数量,导致只初始化了部分内存:

修复:将memset的大小改为对应内存的总字节数:

memset(xorred, 0, (samplelen + 1) * sizeof(wchar_t));
memset(ReadXOR, 0, filesize + sizeof(wchar_t));
memset(unxorred, 0, (whattoread + 1) * sizeof(wchar_t));

3. 缺少宽字符串终止符

%ls格式输出依赖\0作为字符串结束标志,解密后的unxorred没有添加终止符,导致printf读取越界,输出内存中的垃圾数据。

修复:解密完成后手动添加终止符:

unxorred[whattoread] = L'\0';

4. 文件关闭错误

读取文件时,错误地关闭了已经关闭的fpW,应该关闭fpR:

fclose(fpR); // 替换原代码中的fclose(fpW)

5. 初始代码中的类型截断问题

初始代码中xorred[i] = ((char)(value[i] ^ XORKey))将wchar_t结果强制转为char,导致宽字符被截断,丢失高位字节,修改后已修复此问题,保留完整的wchar_t运算结果。

修复后的完整代码

const unsigned int XORKey = 0xff;

size_t XORit(const wchar_t* value, wchar_t* xorred)
{
    size_t length = wcslen(value);
    for (size_t i = 0; i < length; i++)
        xorred[i] = (value[i] ^ XORKey);
    // 添加终止符
    xorred[length] = L'\0';
    return length;
}

int main()
{
    setlocale(LC_ALL, "en_US.UTF-8");
    wchar_t sample[] = L"Test1自己人自己人A";
    size_t samplelen = wcslen(sample);
    printf("%ls\n", sample);

    printf("Plain:\n\t");
    for (size_t i = 0; i < samplelen; i++)
    {
        printf("%0*X ", (int)sizeof(wchar_t)*2, (unsigned int)sample[i]);
    }
    printf("\n");

    // 分配足够内存,包含终止符
    wchar_t* xorred = (wchar_t*)malloc((samplelen + 1) * sizeof(wchar_t));
    if (xorred == NULL) return -1;
    memset(xorred, 0, (samplelen + 1) * sizeof(wchar_t));
    XORit(sample, xorred);

    printf("XOR'ed\n\t");
    for (size_t i = 0; i < samplelen; i++)
    {
        printf("%0*X ", (int)sizeof(wchar_t)*2, (unsigned int)xorred[i]);
    }
    printf("\n");

    // 写入文件
    FILE* fpW = _wfopen(L"logon.bin", L"wb");
    if (fpW == NULL) { free(xorred); return -1; }
    fwrite(xorred, sizeof(wchar_t), samplelen, fpW);
    fclose(fpW);
    free(xorred);

    // 读取文件
    FILE* fpR = fopen("logon.bin", "rb");
    if (fpR == NULL) return -1;
    fseek(fpR, 0, SEEK_END);
    long filesize = ftell(fpR);
    rewind(fpR);

    size_t whattoread = filesize / sizeof(wchar_t);
    wchar_t* ReadXOR = (wchar_t*)malloc(filesize + sizeof(wchar_t));
    if (ReadXOR == NULL) { fclose(fpR); return -1; }
    memset(ReadXOR, 0, filesize + sizeof(wchar_t));

    fread(ReadXOR, sizeof(wchar_t), whattoread, fpR);
    fclose(fpR);

    printf("Reading\n\t");
    for (size_t i = 0; i < samplelen; i++)
    {
        printf("%0*X ", (int)sizeof(wchar_t)*2, (unsigned int)ReadXOR[i]);
    }
    printf("\n");

    // 解密
    wchar_t* unxorred = (wchar_t*)malloc((whattoread + 1) * sizeof(wchar_t));
    if (unxorred == NULL) { free(ReadXOR); return -1; }
    memset(unxorred, 0, (whattoread + 1) * sizeof(wchar_t));

    printf("Un-XOR'ed\n\t");
    for (size_t i = 0; i < whattoread; i++)
    {
        unxorred[i] = ReadXOR[i] ^ XORKey;
        printf("%0*X ", (int)sizeof(wchar_t)*2, (unsigned int)unxorred[i]);
    }
    printf("\n");

    // 添加终止符
    unxorred[whattoread] = L'\0';
    printf("%ls\n", unxorred);
    printf("%ls\n", sample);

    free(ReadXOR);
    free(unxorred);
    return 0;
}

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 04:47:39