当前位置: 首页 > article >正文

CTF-RE 从0到N: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 宏通常可以定义为:

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

这个宏的工作原理是:

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

示例代码:

#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 宏通常可以定义为:

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

这个宏的工作原理是:

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

示例代码:

#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位的整数。

#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 编码示例:

#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个字节。
#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位0x10000000000000000000000000000000000000000000000000000000000000001提取最低 1 位
2位0x30000000000000000000000000000000000000000000000000000000000000011提取最低 2 位
3位0x70000000000000000000000000000000000000000000000000000000000000111提取最低 3 位
4位0xf0000000000000000000000000000000000000000000000000000000000001111提取最低 4 位
5位0x1f0000000000000000000000000000000000000000000000000000000000011111提取最低 5 位
6位0x3f0000000000000000000000000000000000000000000000000000000000111111提取最低 6 位
7位0x7f0000000000000000000000000000000000000000000000000000000001111111提取最低 7 位
8位0xff0000000000000000000000000000000000000000000000000000000011111111提取最低 8 位
9位0x1ff0000000000000000000000000000000000000000000000000000000111111111提取最低 9 位
10位0x3ff0000000000000000000000000000000000000000000000000000001111111111提取最低 10 位
11位0x7ff0000000000000000000000000000000000000000000000000000011111111111提取最低 11 位
12位0xfff0000000000000000000000000000000000000000000000000000111111111111提取最低 12 位
13位0x1fff0000000000000000000000000000000000000000000000000001111111111111提取最低 13 位
14位0x3fff0000000000000000000000000000000000000000000000000011111111111111提取最低 14 位
15位0x7fff0000000000000000000000000000000000000000000000000111111111111111提取最低 15 位
16位0xffff0000000000000000000000000000000000000000000000001111111111111111提取最低 16 位
17位0x1ffff0000000000000000000000000000000000000000000000011111111111111111提取最低 17 位
18位0x3ffff0000000000000000000000000000000000000000000000111111111111111111提取最低 18 位
19位0x7ffff0000000000000000000000000000000000000000000001111111111111111111提取最低 19 位
20位0xfffff0000000000000000000000000000000000000000000011111111111111111111提取最低 20 位
21位0x1fffff0000000000000000000000000000000000000000000111111111111111111111提取最低 21 位
22位0x3fffff0000000000000000000000000000000000000000001111111111111111111111提取最低 22 位
23位0x7fffff0000000000000000000000000000000000000000011111111111111111111111提取最低 23 位
24位0xffffff0000000000000000000000000000000000000000111111111111111111111111提取最低 24 位
25位0x1ffffff0000000000000000000000000000000000000001111111111111111111111111提取最低 25 位
26位0x3ffffff0000000000000000000000000000000000000011111111111111111111111111提取最低 26 位
27位0x7ffffff0000000000000000000000000000000000000111111111111111111111111111提取最低 27 位
28位0xfffffff0000000000000000000000000000000000001111111111111111111111111111提取最低 28 位
29位0x1fffffff0000000000000000000000000000000000011111111111111111111111111111提取最低 29 位
30位0x3fffffff0000000000000000000000000000000000111111111111111111111111111111提取最低 30 位
31位0x7fffffff0000000000000000000000000000000001111111111111111111111111111111提取最低 31 位
32位0xffffffff0000000000000000000000000000000011111111111111111111111111111111提取最低 32 位
33位0x1ffffffff0000000000000000000000000000000111111111111111111111111111111111提取最低 33 位
34位0x3ffffffff0000000000000000000000000000001111111111111111111111111111111111提取最低 34 位
35位0x7ffffffff0000000000000000000000000000011111111111111111111111111111111111提取最低 35 位
36位0xfffffffff0000000000000000000000000000111111111111111111111111111111111111提取最低 36 位
37位0x1fffffffff0000000000000000000000000001111111111111111111111111111111111111提取最低 37 位
38位0x3fffffffff0000000000000000000000000011111111111111111111111111111111111111提取最低 38 位
39位0x7fffffffff0000000000000000000000000111111111111111111111111111111111111111提取最低 39 位
40位0xffffffffff0000000000000000000000001111111111111111111111111111111111111111提取最低 40 位
41位0x1ffffffffff0000000000000000000000011111111111111111111111111111111111111111提取最低 41 位
42位0x3ffffffffff0000000000000000000000111111111111111111111111111111111111111111提取最低 42 位
43位0x7ffffffffff0000000000000000000001111111111111111111111111111111111111111111提取最低 43 位
44位0xfffffffffff0000000000000000000011111111111111111111111111111111111111111111提取最低 44 位
45位0x1fffffffffff0000000000000000000111111111111111111111111111111111111111111111提取最低 45 位
46位0x3fffffffffff0000000000000000001111111111111111111111111111111111111111111111提取最低 46 位
47位0x7fffffffffff0000000000000000011111111111111111111111111111111111111111111111提取最低 47 位
48位0xffffffffffff0000000000000000111111111111111111111111111111111111111111111111提取最低 48 位
49位0x1ffffffffffff0000000000000001111111111111111111111111111111111111111111111111提取最低 49 位
50位0x3ffffffffffff0000000000000011111111111111111111111111111111111111111111111111提取最低 50 位
51位0x7ffffffffffff0000000000000111111111111111111111111111111111111111111111111111提取最低 51 位
52位0xfffffffffffff0000000000001111111111111111111111111111111111111111111111111111提取最低 52 位
53位0x1fffffffffffff0000000000011111111111111111111111111111111111111111111111111111提取最低 53 位
54位0x3fffffffffffff0000000000111111111111111111111111111111111111111111111111111111提取最低 54 位
55位0x7fffffffffffff0000000001111111111111111111111111111111111111111111111111111111提取最低 55 位
56位0xffffffffffffff0000000011111111111111111111111111111111111111111111111111111111提取最低 56 位
57位0x1ffffffffffffff0000000111111111111111111111111111111111111111111111111111111111提取最低 57 位
58位0x3ffffffffffffff0000001111111111111111111111111111111111111111111111111111111111提取最低 58 位
59位0x7ffffffffffffff0000011111111111111111111111111111111111111111111111111111111111提取最低 59 位
60位0xfffffffffffffff0000111111111111111111111111111111111111111111111111111111111111提取最低 60 位
61位0x1fffffffffffffff0001111111111111111111111111111111111111111111111111111111111111提取最低 61 位
62位0x3fffffffffffffff0011111111111111111111111111111111111111111111111111111111111111提取最低 62 位
63位0x7fffffffffffffff0111111111111111111111111111111111111111111111111111111111111111提取最低 63 位
64位0xffffffffffffffff1111111111111111111111111111111111111111111111111111111111111111提取最低 64 位

代码

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)


http://www.kler.cn/a/411855.html

相关文章:

  • Jmeter中的前置处理器
  • 计算机操作系统——进程控制(Linux)
  • 文件系统的作用
  • 异步编程中,为什么必须将conn放到后台连接
  • 前端图像处理(一)
  • 计算机毕业设计Hadoop+Spark音乐推荐系统 音乐预测系统 音乐可视化大屏 音乐爬虫 HDFS hive数据仓库 机器学习 深度学习 大数据毕业设计
  • LeetCode数组题
  • C# Http Post 长连接和短连接请求
  • 【jvm】对象的内存布局
  • 【软件入门】Git快速入门
  • 《黑神话:悟空》游戏辅助修改器工具下载指南与操作方法详解
  • 4.6 JMeter HTTP信息头管理器
  • git(Linux)
  • C++:多态的原理
  • VMware ubuntu创建共享文件夹与Windows互传文件
  • Unity中的简易TCP服务器/客户端
  • macos 14.0 Monoma 修改顶部菜单栏颜色
  • Leetcode53. 最大子数组和(HOT100)
  • numpy.digitize函数介绍
  • 缺失的第一个正数(java)
  • 挂载本地目录到k8s的pod实现持久化存储
  • [java] 什么是 Apache Felix
  • wp the_posts_pagination 与分类页面搭配使用
  • git-显示顺序与提交顺序不一致的问题
  • unity3d——基础篇2刷(Mathf练习题)
  • RabbitMQ的预取值详解