CTF-RE 从0到N: 基本按位运算逻辑

利用移位快速乘除2^n

  • 左移运算 (<<) 等效于将数乘以2的某个幂次。
  • 右移运算 (>>) 等效于将数除以2的某个幂次(舍弃小数部分)。

示例:计算8 * 432 / 4

int x = 8;
int result1 = x << 2; // 8 * 2^2 = 32
printf("%d\n", result1); // 输出:32

int y = 32;
int result2 = y >> 2; // 32 / 2^2 = 8
printf("%d\n", result2); // 输出:8

int power_of_2 = 1 << 5; // 2^5 = 32
printf("%d\n", power_of_2); // 输出:32
  • 作用:使用移位运算可以比常规乘法和除法更高效,因为移位是O(1)的操作。

利用移位与&判断某个位是否为1

  • 可以通过移位和按位与运算判断整数的某个位是否为1。

示例:检查第3位(从右向左计数)的值。

int x = 13; // 二进制:1101
if (x & (1 << 2)) { // 检查第3位(值为1)
    printf("3rd bit is set\n");
} else {
    printf("3rd bit is not set\n");
}

1.用来位计数(汉明重量)

  • 位计数是统计整数的二进制表示中有多少个1

示例:统计整数x的二进制中有多少个1。

int count = 0;
int x = 29; // 二进制:11101
while (x) {
    count += (x & 1);
    x >>= 1;
}
printf("Number of 1s: %d\n", count); // 输出:4
  • 作用:位计数在位图、数据压缩和错误检测中非常常见。

2. 用于权限设置

  • 在权限管理中,使用位掩码进行权限标记和设置。

示例:设置和检查权限:

int permissions = 0b0101; // 初始权限
permissions |= (1 << 2); // 设置第3位权限
if (permissions & (1 << 2)) { // 检查第3位权限
    printf("Permission granted\n");
}
  • 作用:在权限控制或状态标记算法中,移位和按位操作用于设置和检查权限。

利用移位反转二进制数

  • 移位运算可以用于将二进制数的位进行反转。

示例:将x的位进行翻转(假设x为8位数):

unsigned char x = 0b00001111; // 初始二进制数
unsigned char reversed = 0;
for (int i = 0; i < 8; i++) {
    reversed = (reversed << 1) | (x & 1);
    x >>= 1;
}
printf("%d\n", reversed); // 输出:240(0b11110000)
  • 作用:位翻转在一些特定的加密算法或图像处理算法中非常常见。

利用异或交换两个数的值

  • 利用按位异或运算,可以实现无第三变量的交换两个数的值:
int x = 5, y = 9;
x = x ^ y;
y = x ^ y;
x = x ^ y;
printf("x = %d, y = %d\n", x, y); // 输出:x = 9, y = 5
  • 作用:这种算法常用于内存受限的情况下交换变量值。

利用&奇偶性判断

  • 作用:通过x & 1可以快速判断一个数是奇数还是偶数。

示例:判断一个数是否为偶数。

int x = 42;
if (x & 1) {
    printf("奇数\n");
} else {
    printf("偶数\n");
}
  • 解释x & 1会提取整数的最低有效位(LSB)。若最低位为1,数为奇数;若为0,数为偶数。该方法效率高于使用模运算%

利用&清除某个位

  • 作用&运算结合取反可以用于清除整数的某个位。

示例:清除整数x的第2位(从右数起)。

int x = 15;  // 二进制:1111
int mask = ~(1 << 1); // 掩码:1110,取反后清除第2位
x = x & mask; // 清除第2位
printf("%d\n", x); // 输出:13(二进制:1101)
  • 解释:通过~(1 << n)创建掩码,可以将第n+1位设置为0,其余位保持不变,从而有效清除该位。

利用&清除特定位

  • 作用:按位与运算可以从一个数中提取指定的几位,用于位标记或位操作。

示例:提取x中的低4位。

int x = 29;  // 二进制:11101
int mask = 0b1111; // 掩码:1111
int result = x & mask; // 提取低4位
printf("%d\n", result); // 输出:13(二进制:1101)
  • 解释:通过设置掩码,可以保留x的低4位,掩码部分为1的位将被保留,其他位被清除。

利用&计算两个数的交集位

  • 作用&运算可以用来计算两个二进制数的交集,即哪些位在两个数中都是1。

示例:计算两个数的交集位。

int a = 29;  // 二进制:11101
int b = 23;  // 二进制:10111
int result = a & b; // 二进制:10101
printf("%d\n", result); // 输出:21(二进制:10101)
  • 解释&运算返回两个数都为1的位,结果用于分析交集或公共属性。

利用&快速判断是否是2的幂次

  • 作用:使用x & (x - 1)可以快速判断一个数是否是2的幂次。

示例:判断x是否是2的幂次。

int x = 16; // 二进制:10000
if (x > 0 && (x & (x - 1)) == 0) {
    printf("%d 是2的幂次\n", x);
} else {
    printf("%d 不是2的幂次\n", x);
}
  • 解释:2的幂次的二进制表示中只有一个1,通过x & (x - 1)将最低的1清除,如果结果为0,则说明该数是2的幂次。

利用&判断两个数符号是否相同

  • 作用&可以用于快速判断两个数是否具有相同的符号。

示例:判断xy是否符号相同。

int x = -5;
int y = -10;
if ((x & y) > 0) {
    printf("x和y符号相同\n");
} else {
    printf("x和y符号不同\n");
}
  • 解释:通过x & y来查看最高位(符号位),如果符号位相同,结果为正。

|(按位或运算符)用于在两个二进制数的对应位上执行或操作,只要两个位中至少有一个是1,结果就为1。|运算在基本算法中广泛用于设置特定位、合并数据和实现快速运算,以下是一些具体示例说明它的作用:

利用|设置特定位

  • 作用|运算常用于将数的某个位设置为1,而不改变其他位的值。

示例:将整数x的第3位(从右往左数)设置为1。

int x = 8;    // 二进制:1000
int mask = 1 << 2;  // 掩码:0100,对应第3位
x = x | mask;       // 设置第3位
printf("%d\n", x);  // 输出:12(二进制:1100)
  • 解释:通过将掩码与x按位或运算,可以保留x的其他位,同时将第3位设置为1。用于二进制标记、开关状态管理等场景。

3. 利用|合并数的特定位

  • 作用:通过|运算可以将两个数的不同位合并到一起。

示例:合并两个数ab的特定位。

int a = 0b1010; // 二进制:1010
int b = 0b0101; // 二进制:0101
int result = a | b; // 二进制:1111
printf("%d\n", result); // 输出:15(二进制:1111)
  • 解释ab的二进制表示分别为10100101,合并后结果为1111。这种合并用于位集成、数据汇总和标志位操作。

利用|快速设定特定位组

  • 作用:可以用|运算一次性设置多个位组为1,而不改变其他位。

示例:将x的低4位设置为1。

int x = 16;     // 二进制:10000
int mask = 0b1111; // 掩码:低4位为1
x = x | mask;      // 设置低4位
printf("%d\n", x); // 输出:31(二进制:11111)
  • 解释:通过与掩码1111按位或,可以直接将x的低4位设置为1。常用于需要将特定位范围设为固定值的情境。

你可能感兴趣的:(算法,ctf,ctf-RE)