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)
相关推荐
Clockwiseee42 分钟前
php伪协议
windows·安全·web安全·网络安全
Lspecialnx_5 小时前
文件解析漏洞中间件(iis和Apache)
网络安全·中间件
学习溢出7 小时前
【网络安全】逆向工程 练习示例
网络·安全·网络安全·渗透测试·逆向工程
孤独的履行者10 小时前
入门靶机:DC-1的渗透测试
数据库·python·网络安全
Blankspace学11 小时前
Wireshark软件下载安装及基础
网络·学习·测试工具·网络安全·wireshark
CVE-柠檬i14 小时前
Yakit靶场-高级前端加解密与验签实战-全关卡通关教程
网络安全
轨迹H1 天前
kali设置中文输入法
linux·网络安全·渗透测试·kali
cr.sheeper1 天前
Vulnhub靶场Apache解析漏洞
网络安全·apache
Autumn.h1 天前
文件解析漏洞
web安全·网络安全·中间件