CTF-RE 从0到N:c语言是如何利用逻辑运算符拆分变量和合并的

我们经常能看到这种代码

c 复制代码
  for ( i = 0; i <= 9; ++i )
  {
    dest += v9;
    v17 = (dest << 16) ^ v17 | HIWORD(dest) ^ v17;
    v13 += v17;
    v9 = (v13 << 12) ^ v9 | (v13 >> 20) ^ v9;
    dest += v9;
    v17 = (dest << 8) ^ v17 | HIBYTE(dest) ^ v17;
    v13 += v17;
    v9 = (v13 << 7) ^ v9 | (v13 >> 25) ^ v9;
    v6 += v10;
    v18 = (v6 << 16) ^ v18 | HIWORD(v6) ^ v18;
    v14 += v18;
    v10 = (v14 << 12) ^ v10 | (v14 >> 20) ^ v10;
    v6 += v10;
    v18 = (v6 << 8) ^ v18 | HIBYTE(v6) ^ v18;
    v14 += v18;
    v10 = (v14 << 7) ^ v10 | (v14 >> 25) ^ v10;
    v7 += v11;
    v19 = (v7 << 16) ^ v19 | HIWORD(v7) ^ v19;
    v15 += v19;
    v11 = (v15 << 12) ^ v11 | (v15 >> 20) ^ v11;
    v7 += v11;
    v19 = (v7 << 8) ^ v19 | HIBYTE(v7) ^ v19;
    v15 += v19;
    v11 = (v15 << 7) ^ v11 | (v15 >> 25) ^ v11;
    v8 += v12;
    v20 = (v8 << 16) ^ v20 | HIWORD(v8) ^ v20;
    v16 += v20;
    v12 = (v16 << 12) ^ v12 | (v16 >> 20) ^ v12;
    v8 += v12;
    v20 = (v8 << 8) ^ v20 | HIBYTE(v8) ^ v20;
    v16 += v20;
    v12 = (v16 << 7) ^ v12 | (v16 >> 25) ^ v12;
    dest += v10;
    v20 = (dest << 16) ^ v20 | HIWORD(dest) ^ v20;
    v15 += v20;
    v10 = (v15 << 12) ^ v10 | (v15 >> 20) ^ v10;
    dest += v10;
    v20 = (dest << 8) ^ v20 | HIBYTE(dest) ^ v20;
    v15 += v20;
    v10 = (v15 << 7) ^ v10 | (v15 >> 25) ^ v10;
    v6 += v11;
    v17 = (v6 << 16) ^ v17 | HIWORD(v6) ^ v17;
    v16 += v17;
    v11 = (v16 << 12) ^ v11 | (v16 >> 20) ^ v11;
    v6 += v11;
    v17 = (v6 << 8) ^ v17 | HIBYTE(v6) ^ v17;
    v16 += v17;
    v11 = (v16 << 7) ^ v11 | (v16 >> 25) ^ v11;
    v7 += v12;
    v18 = (v7 << 16) ^ v18 | HIWORD(v7) ^ v18;
    v13 += v18;
    v12 = (v13 << 12) ^ v12 | (v13 >> 20) ^ v12;
    v7 += v12;
    v18 = (v7 << 8) ^ v18 | HIBYTE(v7) ^ v18;
    v13 += v18;
    v12 = (v13 << 7) ^ v12 | (v13 >> 25) ^ v12;
    v8 += v9;
    v19 = (v8 << 16) ^ v19 | HIWORD(v8) ^ v19;
    v14 += v19;
    v9 = (v14 << 12) ^ v9 | (v14 >> 20) ^ v9;
    v8 += v9;
    v19 = (v8 << 8) ^ v19 | HIBYTE(v8) ^ v19;
    v14 += v19;
    v9 = (v14 << 7) ^ v9 | (v14 >> 25) ^ v9;
  }

HIBYTE/WODRD是什么?

前置

在C语言中,HIWORDHIBYTE 是用于提取变量中特定部分(如高16位或高8位)的宏或函数,它们通常用于对整型值的高字节(或高位)进行操作。这些宏常用于处理多字节数据(如32位整数)时,从中提取出特定的部分,ida预定义了这些函数,在检测到特定特征后会将表达式化简为这些函数.

1. HIWORD

HIWORD 是一个宏,用于提取一个32位整数的 高16位(高字)。在一个32位整数中,前16位被称为高16位,后16位称为低16位。

假设你有一个32位整数 x,其二进制形式为:

复制代码
x = 0x12345678  // 十六进制表示

HIWORD(x) 会提取出高16位,结果为 0x1234

在C语言中,HIWORD 宏通常可以定义为:

c 复制代码
#define HIWORD(x)   (((x) >> 16) & 0xFFFF)

这个宏的工作原理是:

  • 通过 x >> 16x 右移16位,使得高16位移动到低16位的位置。
  • 然后用 & 0xFFFF 掩码保留低16位,即得到原来高16位的值。

示例代码:

c 复制代码
#include <stdio.h>

#define HIWORD(x)   (((x) >> 16) & 0xFFFF)

int main() {
    unsigned int x = 0x12345678;  // 32位整数
    unsigned short high = HIWORD(x);

    printf("HIWORD(x) = 0x%X\n", high);  // 输出高16位
    return 0;
}

输出:

复制代码
HIWORD(x) = 0x1234

2. HIBYTE

HIBYTE 是一个宏,用于提取一个16位整数的 高8位(高字节)。它主要用于处理16位整数的高8位。

假设你有一个16位整数 x,其二进制形式为:

复制代码
x = 0x1234  // 十六进制表示

HIBYTE(x) 会提取出高8位,结果为 0x12

在C语言中,HIBYTE 宏通常可以定义为:

c 复制代码
#define HIBYTE(x)   (((x) >> 8) & 0xFF)

这个宏的工作原理是:

  • 通过 x >> 8x 右移8位,使得高8位移动到低8位的位置。
  • 然后用 & 0xFF 掩码保留低8位,即得到原来高8位的值。

示例代码:

c 复制代码
#include <stdio.h>

#define HIBYTE(x)   (((x) >> 8) & 0xFF)

int main() {
    unsigned short x = 0x1234;  // 16位整数
    unsigned char high = HIBYTE(x);

    printf("HIBYTE(x) = 0x%X\n", high);  // 输出高8位
    return 0;
}

输出:

复制代码
HIBYTE(x) = 0x12

总结

  • HIWORD(x) 用于提取32位整数的 高16位
  • HIBYTE(x) 用于提取16位整数的 高8位
  • 其他的HIxxx以此类推

>>,<<,|,&是怎么拆分合并变量的?

在C语言中,位运算符 &(按位与)、>>(右移)和 |(按位或)通常用于拆分和合并变量。这些运算符在处理位级数据时非常有用,可以用来提取数据的某些部分或组合多个值。

示例

假设我们有两个16位的整数 highlow,并且想要将它们合并为一个32位的整数。

c 复制代码
#include <stdio.h>

int main() {
    unsigned short high = 0x1234;  // 高16位
    unsigned short low = 0x5678;   // 低16位
    unsigned int combined;

    // 合并高16位和低16位
    combined = ((unsigned int)high << 16) | low;

    printf("High = 0x%X\n", high);
    printf("Low = 0x%X\n", low);
    printf("Combined = 0x%X\n", combined);

    return 0;
}

让我们来看一些更复杂的例子

在 Base64 编码过程中,我们会遇到大量的位操作,例如将3个字节的数据转换为4个字符,并且在编码和解码过程中,通常会使用 按位与(&)按位或(|) 等位操作来处理数据。

1. Base64 编码

Base64 编码的过程涉及到以下步骤:

  1. 将输入的每3个字节(24位)分成4组6位数据。
  2. 每6位映射到一个Base64字符。

例如,假设我们有一段数据 "Man",它的 ASCII 码值为:

  • 'M' -> 0x4D -> 01001101
  • 'a' -> 0x61 -> 01100001
  • 'n' -> 0x6E -> 01101110

这3个字符的二进制数据合并成一个24位的长整数(0x4D616E)。接下来我们将这个24位数据分成4个6位数据:

复制代码
0x4D616E (二进制表示为 010011010110000101101110)
  • 第1组:010011 -> 19
  • 第2组:010110 -> 22
  • 第3组:000101 -> 5
  • 第4组:101110 -> 46

然后这些值将映射到 Base64 字符集中的对应字符。

Base64 编码示例:

c 复制代码
#include <stdio.h>
#include <string.h>

#define BASE64_CHARSET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

// Base64 编码函数
void base64_encode(const unsigned char *input, char *output) {
    int i = 0, j = 0;
    unsigned char a3[3], a4[4];
    int input_len = strlen((char *)input);

    while (input_len--) {
        a3[i++] = *(input++);
        if (i == 3) {
            a4[0] = (a3[0] >> 2) & 0x3F;        // 获取前6位
            a4[1] = ((a3[0] & 0x03) << 4) | (a3[1] >> 4) & 0x3F;   // 获取中间6位
            a4[2] = ((a3[1] & 0x0F) << 2) | (a3[2] >> 6) & 0x3F;   // 获取后6位
            a4[3] = a3[2] & 0x3F;      // 获取最后6位

            for (i = 0; i < 4; i++)
                output[j++] = BASE64_CHARSET[a4[i]];

            i = 0;
        }
    }

    if (i) {
        for (int k = i; k < 3; k++)
            a3[k] = '\0';  // 填充空字节

        a4[0] = (a3[0] >> 2) & 0x3F;
        a4[1] = ((a3[0] & 0x03) << 4) | (a3[1] >> 4) & 0x3F;
        a4[2] = ((a3[1] & 0x0F) << 2) | (a3[2] >> 6) & 0x3F;

        for (int k = 0; k < (i + 1); k++) {
            output[j++] = BASE64_CHARSET[a4[k]];
        }

        while ((i++ < 3))
            output[j++] = '=';  // 填充等号
    }

    output[j] = '\0';
}

int main() {
    unsigned char input[] = "Man";  // 要编码的字符串
    char output[50];

    base64_encode(input, output);
    printf("Base64 Encoded: %s\n", output);

    return 0;
}

解析:

  1. 输入数据 :我们输入 "Man",其 ASCII 值分别是 'M' = 0x4D, 'a' = 0x61, 'n' = 0x6E
  2. 合并成24位 :三个字节合并成 0x4D616E,对应的二进制是 010011010110000101101110
  3. 分为4组6位
    • 第一组:010011 -> 19
    • 第二组:010110 -> 22
    • 第三组:000101 -> 5
    • 第四组:101110 -> 46
  4. 映射到Base64字符集 :通过 BASE64_CHARSET 将这4个6位的值映射到对应的字符,得到 Base64 编码结果为 "TWFu"

2. Base64 解码

解码过程与编码过程相反,主要步骤包括:

  1. 读取4个 Base64 字符,并将它们转换为4个6位的值。
  2. 将这4个6位的值合并为3个字节。
c 复制代码
#include <stdio.h>
#include <string.h>

#define BASE64_CHARSET "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

// 查找字符在Base64字符集中的位置
int base64_decode_char(char c) {
    if (c >= 'A' && c <= 'Z') return c - 'A';
    if (c >= 'a' && c <= 'z') return c - 'a' + 26;
    if (c >= '0' && c <= '9') return c - '0' + 52;
    if (c == '+') return 62;
    if (c == '/') return 63;
    return -1;  // 错误字符
}

// Base64 解码函数
void base64_decode(const char *input, unsigned char *output) {
    int i = 0, j = 0;
    unsigned char a3[3], a4[4];

    while (input[i]) {
        for (int k = 0; k < 4; k++) {
            if (input[i] == '=')
                a4[k] = 0;
            else
                a4[k] = base64_decode_char(input[i]);
            i++;
        }

        a3[0] = (a4[0] << 2) | (a4[1] >> 4);
        a3[1] = (a4[1] << 4) | (a4[2] >> 2);
        a3[2] = (a4[2] << 6) | a4[3];

        for (int k = 0; k < 3; k++) {
            if (a3[k] != 0)
                output[j++] = a3[k];
        }
    }

    output[j] = '\0';
}

int main() {
    char input[] = "TWFu";  // Base64 编码的字符串
    unsigned char output[50];

    base64_decode(input, output);
    printf("Decoded: %s\n", output);

    return 0;
}

解析:

  1. 输入数据 :我们输入 "TWFu",这是 "Man" 的 Base64 编码。
  2. 转换为6位组:每个字符对应一个6位的值。
  3. 还原为原始数据 :将4个6位的值合并为3个字节,得到解码后的数据 "Man"

附全1掩码表

位数 掩码(十六进制) 掩码(二进制) 解释
1位 0x1 0000000000000000000000000000000000000000000000000000000000000001 提取最低 1 位
2位 0x3 0000000000000000000000000000000000000000000000000000000000000011 提取最低 2 位
3位 0x7 0000000000000000000000000000000000000000000000000000000000000111 提取最低 3 位
4位 0xf 0000000000000000000000000000000000000000000000000000000000001111 提取最低 4 位
5位 0x1f 0000000000000000000000000000000000000000000000000000000000011111 提取最低 5 位
6位 0x3f 0000000000000000000000000000000000000000000000000000000000111111 提取最低 6 位
7位 0x7f 0000000000000000000000000000000000000000000000000000000001111111 提取最低 7 位
8位 0xff 0000000000000000000000000000000000000000000000000000000011111111 提取最低 8 位
9位 0x1ff 0000000000000000000000000000000000000000000000000000000111111111 提取最低 9 位
10位 0x3ff 0000000000000000000000000000000000000000000000000000001111111111 提取最低 10 位
11位 0x7ff 0000000000000000000000000000000000000000000000000000011111111111 提取最低 11 位
12位 0xfff 0000000000000000000000000000000000000000000000000000111111111111 提取最低 12 位
13位 0x1fff 0000000000000000000000000000000000000000000000000001111111111111 提取最低 13 位
14位 0x3fff 0000000000000000000000000000000000000000000000000011111111111111 提取最低 14 位
15位 0x7fff 0000000000000000000000000000000000000000000000000111111111111111 提取最低 15 位
16位 0xffff 0000000000000000000000000000000000000000000000001111111111111111 提取最低 16 位
17位 0x1ffff 0000000000000000000000000000000000000000000000011111111111111111 提取最低 17 位
18位 0x3ffff 0000000000000000000000000000000000000000000000111111111111111111 提取最低 18 位
19位 0x7ffff 0000000000000000000000000000000000000000000001111111111111111111 提取最低 19 位
20位 0xfffff 0000000000000000000000000000000000000000000011111111111111111111 提取最低 20 位
21位 0x1fffff 0000000000000000000000000000000000000000000111111111111111111111 提取最低 21 位
22位 0x3fffff 0000000000000000000000000000000000000000001111111111111111111111 提取最低 22 位
23位 0x7fffff 0000000000000000000000000000000000000000011111111111111111111111 提取最低 23 位
24位 0xffffff 0000000000000000000000000000000000000000111111111111111111111111 提取最低 24 位
25位 0x1ffffff 0000000000000000000000000000000000000001111111111111111111111111 提取最低 25 位
26位 0x3ffffff 0000000000000000000000000000000000000011111111111111111111111111 提取最低 26 位
27位 0x7ffffff 0000000000000000000000000000000000000111111111111111111111111111 提取最低 27 位
28位 0xfffffff 0000000000000000000000000000000000001111111111111111111111111111 提取最低 28 位
29位 0x1fffffff 0000000000000000000000000000000000011111111111111111111111111111 提取最低 29 位
30位 0x3fffffff 0000000000000000000000000000000000111111111111111111111111111111 提取最低 30 位
31位 0x7fffffff 0000000000000000000000000000000001111111111111111111111111111111 提取最低 31 位
32位 0xffffffff 0000000000000000000000000000000011111111111111111111111111111111 提取最低 32 位
33位 0x1ffffffff 0000000000000000000000000000000111111111111111111111111111111111 提取最低 33 位
34位 0x3ffffffff 0000000000000000000000000000001111111111111111111111111111111111 提取最低 34 位
35位 0x7ffffffff 0000000000000000000000000000011111111111111111111111111111111111 提取最低 35 位
36位 0xfffffffff 0000000000000000000000000000111111111111111111111111111111111111 提取最低 36 位
37位 0x1fffffffff 0000000000000000000000000001111111111111111111111111111111111111 提取最低 37 位
38位 0x3fffffffff 0000000000000000000000000011111111111111111111111111111111111111 提取最低 38 位
39位 0x7fffffffff 0000000000000000000000000111111111111111111111111111111111111111 提取最低 39 位
40位 0xffffffffff 0000000000000000000000001111111111111111111111111111111111111111 提取最低 40 位
41位 0x1ffffffffff 0000000000000000000000011111111111111111111111111111111111111111 提取最低 41 位
42位 0x3ffffffffff 0000000000000000000000111111111111111111111111111111111111111111 提取最低 42 位
43位 0x7ffffffffff 0000000000000000000001111111111111111111111111111111111111111111 提取最低 43 位
44位 0xfffffffffff 0000000000000000000011111111111111111111111111111111111111111111 提取最低 44 位
45位 0x1fffffffffff 0000000000000000000111111111111111111111111111111111111111111111 提取最低 45 位
46位 0x3fffffffffff 0000000000000000001111111111111111111111111111111111111111111111 提取最低 46 位
47位 0x7fffffffffff 0000000000000000011111111111111111111111111111111111111111111111 提取最低 47 位
48位 0xffffffffffff 0000000000000000111111111111111111111111111111111111111111111111 提取最低 48 位
49位 0x1ffffffffffff 0000000000000001111111111111111111111111111111111111111111111111 提取最低 49 位
50位 0x3ffffffffffff 0000000000000011111111111111111111111111111111111111111111111111 提取最低 50 位
51位 0x7ffffffffffff 0000000000000111111111111111111111111111111111111111111111111111 提取最低 51 位
52位 0xfffffffffffff 0000000000001111111111111111111111111111111111111111111111111111 提取最低 52 位
53位 0x1fffffffffffff 0000000000011111111111111111111111111111111111111111111111111111 提取最低 53 位
54位 0x3fffffffffffff 0000000000111111111111111111111111111111111111111111111111111111 提取最低 54 位
55位 0x7fffffffffffff 0000000001111111111111111111111111111111111111111111111111111111 提取最低 55 位
56位 0xffffffffffffff 0000000011111111111111111111111111111111111111111111111111111111 提取最低 56 位
57位 0x1ffffffffffffff 0000000111111111111111111111111111111111111111111111111111111111 提取最低 57 位
58位 0x3ffffffffffffff 0000001111111111111111111111111111111111111111111111111111111111 提取最低 58 位
59位 0x7ffffffffffffff 0000011111111111111111111111111111111111111111111111111111111111 提取最低 59 位
60位 0xfffffffffffffff 0000111111111111111111111111111111111111111111111111111111111111 提取最低 60 位
61位 0x1fffffffffffffff 0001111111111111111111111111111111111111111111111111111111111111 提取最低 61 位
62位 0x3fffffffffffffff 0011111111111111111111111111111111111111111111111111111111111111 提取最低 62 位
63位 0x7fffffffffffffff 0111111111111111111111111111111111111111111111111111111111111111 提取最低 63 位
64位 0xffffffffffffffff 1111111111111111111111111111111111111111111111111111111111111111 提取最低 64 位

代码

python 复制代码
def generate_full_mask_table():
    # Markdown 表头
    markdown = "| 位数    | 掩码(十六进制) | 掩码(二进制)                | 解释                      |\n"
    markdown += "|---------|------------------|-------------------------------|---------------------------|\n"

    # 生成掩码表
    for i in range(1, 65):
        mask = (1 << i) - 1  # 生成 i 位全1掩码
        hex_mask = hex(mask)  # 十六进制表示
        bin_mask = bin(mask)[2:].zfill(64)  # 二进制表示,填充到64位
        markdown += f"| {i}位    | {hex_mask}        | {bin_mask}         | 提取最低 {i} 位             |\n"

    return markdown


# 输出掩码表
markdown_table = generate_full_mask_table()
print(markdown_table)
相关推荐
大方子2 小时前
【PolarCTF】rce1
网络安全·polarctf
枷锁—sha3 小时前
Burp Suite 抓包全流程与 Xray 联动自动挖洞指南
网络·安全·网络安全
聚铭网络4 小时前
聚铭网络再度入选2026年度扬州市网络和数据安全服务资源池单位
网络安全
darkb1rd6 小时前
八、PHP SAPI与运行环境差异
开发语言·网络安全·php·webshell
世界尽头与你10 小时前
(修复方案)基础目录枚举漏洞
安全·网络安全·渗透测试
枷锁—sha1 天前
【SRC】SQL注入快速判定与应对策略(一)
网络·数据库·sql·安全·网络安全·系统安全
liann1191 天前
3.1_网络——基础
网络·安全·web安全·http·网络安全
ESBK20251 天前
第四届移动互联网、云计算与信息安全国际会议(MICCIS 2026)二轮征稿启动,诚邀全球学者共赴学术盛宴
大数据·网络·物联网·网络安全·云计算·密码学·信息与通信
旺仔Sec1 天前
一文带你看懂免费开源 WAF 天花板!雷池 (SafeLine) 部署与实战全解析
web安全·网络安全·开源·waf
七牛云行业应用1 天前
Moltbook一夜崩盘:150万密钥泄露背后的架构“死穴”与重构实战
网络安全·postgresql·架构·高并发·七牛云