容易被忽略的注意事项:可以使用的常数范围为0-255,编译标准为c89,后者可以通过“./dlc bits.c”来检查。
15道纯位运算,个个都是重量级,部分题目可能不是最优写法(目前凹到207运算符,不是这也能凹是吧),暂无解析,仅供参考。
/*
* tmin - return minimum two's complement integer
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 4
* Rating: 1
*/
int tmin(void) {
return 1<<31;
}
/*
* absVal - absolute value of x
* Example: absVal(-1) = 1.
* You may assume -TMax <= x <= TMax
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 10
* Rating: 4
*/
int absVal(int x) {
int s = x>>31;
return (x+s)^s;
}
/*
* bitAnd - x&y using only ~ and |
* Example: bitAnd(6, 5) = 4
* Legal ops: ~ |
* Max ops: 8
* Rating: 1
*/
int bitAnd(int x, int y) {
return ~(~x|~y);
}
/*
* replaceByte(x,n,c) - Replace byte n in x with c
* Bytes numbered from 0 (LSB) to 3 (MSB)
* Examples: replaceByte(0x12345678,1,0xab) = 0x1234ab78
* You can assume 0 <= n <= 3 and 0 <= c <= 255
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 10
* Rating: 3
*/
int replaceByte(int x, int n, int c) {
int s = n<<3;
return (c<>
* Max ops: 12
* Rating: 2
*/
int mult3div2(int x) {
x += (x<<1);
return (x+((x>>31)&1))>>1;
}
/*
* multFiveEighths - multiplies by 5/8 rounding toward 0.
* Should exactly duplicate effect of C expression (x*5/8),
* including overflow behavior.
* Examples: multFiveEighths(77) = 48
* multFiveEighths(-22) = -13
* multFiveEighths(1073741824) = 13421728 (overflow)
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 12
* Rating: 3
*/
int multFiveEighths(int x) {
x += (x<<2);
return (x+((x>>31)&7))>>3;
}
/*
* addOK - Determine if can compute x+y without overflow
* Example: addOK(0x80000000,0x80000000) = 0,
* addOK(0x80000000,0x70000000) = 1,
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 3
*/
int addOK(int x, int y) {
return (((x^y)>>31)|~(((x+y)^x)>>31))&1;
}
/*
* bitCount - returns count of number of 1's in word
* Examples: bitCount(5) = 2, bitCount(7) = 3
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 40
* Rating: 4
*/
int bitCount(int x) {
int m2 = (0x55<<8)|0x55;
int m4 = (0x33<<8)|0x33;
int m8 = (0x0f<<8)|0x0f;
m2 |= (m2<<16);
m4 |= (m4<<16);
m8 |= (m8<<16);
x += ~((x>>1)&m2)+1;
x = ((x>>2)&m4)+(x&m4);
x = (x+(x>>4))&m8;
x += (x>>8);
x += (x>>16);
return x&0x3f;
}
/*
* isLess - if x < y then return 1, else return 0
* Example: isLess(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLess(int x, int y) {
int ny = ~y;
return ((((x+ny+1)&(x^ny))|(x&ny))>>0x1f)&1;
}
/*
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLessOrEqual(int x, int y) {
int ny = ~y;
return ((((((x+ny+1)&(x^ny))|(x&ny))>>0x1f))&1)|!(x^y);
}
/*
* trueFiveEighths - multiplies by 5/8 rounding toward 0,
* avoiding errors due to overflow
* Examples: trueFiveEighths(11) = 6
* trueFiveEighths(-9) = -5
* trueFiveEighths(0x30000000) = 0x1E000000 (no overflow)
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 25
* Rating: 4
*/
int trueFiveEighths(int x) {
int s = (x>>31)&1;
int c = (s<<3)+~s+1;
int h = ((x&(0xFF<<24))+c)>>3;
int l = (x&~(0xFF<<24));
return (h<<2)+h+((((l<<2)+l)+c)>>3);
}
/*
* parityCheck - returns 1 if x contains an odd number of 1's
* Examples: parityCheck(5) = 0, parityCheck(7) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 4
*/
int parityCheck(int x) {
x ^= (x>>16);
x ^= (x>>8);
x ^= (x>>4);
x ^= (x>>2);
x ^= (x>>1);
return x&1;
}
/*
* rempwr2 - Compute x%(2^n), for 0 <= n <= 30
* Negative arguments should yield negative remainders
* Examples: rempwr2(15,2) = 3, rempwr2(-35,3) = -3
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 20
* Rating: 3
*/
int rempwr2(int x, int n) {
int s = x>>31;
x = (x+s)^s;
x &= ((~0)+(1<>
* Max ops: 90
* Rating: 4
*/
int howManyBits(int x) {
int n = 0;
x ^= (x<<1);
n += ((!!(x&((~0)<<(n+16))))<<4);
n += ((!!(x&((~0)<<(n+8))))<<3);
n += ((!!(x&((~0)<<(n+4))))<<2);
n += ((!!(x&((~0)<<(n+2))))<<1);
n += (!!(x&((~0)<<(n+1))));
return n+1;
}
/*
* ilog2 - return floor(log base 2 of x), where x > 0
* Example: ilog2(16) = 4
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 90
* Rating: 4
*/
int ilog2(int x) {
int n = 0;
n += ((!!(x&((~0)<<(n+16))))<<4);
n += ((!!(x&((~0)<<(n+8))))<<3);
n += ((!!(x&((~0)<<(n+4))))<<2);
n += ((!!(x&((~0)<<(n+2))))<<1);
n += (!!(x&((~0)<<(n+1))));
return n;
}
非常值得一做的汇编练习题,硬看懂汇编还是很有成就感的,也能体会到编译器到底是如何把一些结构翻译为汇编语言的。
由于题目彼此间均有差别,答案各不相同,故仅提供基本思路;关于 IA-32 指令更多细节问题请参照教材或官方手册,本文并不会涉及。
注:可能有人题目为 64 位编译(我拿到的是32位编译的),主要差别如下:
set disassembly-flavor att
# gdb 反汇编默认为 Intel 风格, 需改为 AT&T 风格
# AT&T 指令中, 前者为被操作对象, 后者为操作对象
# 如 mov %eax, %edx 是指将 eax 寄存器中值写入到 edx 寄存器中
# gdb常用命令
b # 在第 n 行 / func 函数 / addr 地址处打断点
r # 运行, 到断点处停下
c # 运行到下一个断点
stepi/step # 相当于step into, 对于机器码/源码
nexti/nest # 相当于step over, 对于机器码/源码
x/ # 以 f 格式查看从 addr 开始的 n 个 u 单位内存值 / 寄存器值
# f: x(十六进制形式); d(整数); f(浮点数); c(字符); s(字符串)
# u: b(1 字节); h(2 字节), w(4 字节), g(8 字节)
p/ # 查看变量
i r # 查看寄存器值
disassemble # 查看func对应的汇编指令
7个Bomb主要考点如下:
通用思路如下:
直接查看
栈结构中栈顶为低地址,栈底为高地址,即入栈时 -0x04,而出栈时 +0x04(32位);
test %eax, %eax 为判断 exa 寄存器中值是否为 0,cmp
-0xc(%ebp) 处通常用来存放循环结构的计数器;
-0x24(%ebp,%eax,4) 意为 %ebp + 4 * %eax - 0x24 处的内存;
通过分析循环结构得到 6 个数字组成的数列。
跳转指令 | 含义 | 跳转指令 | 含义 | 跳转指令 | 含义 |
jmp | 无条件 | je | 相等 | jne | 不相等 |
ja/jnbe | 无符号大于 | jae/jnb | 无符号大于等于 | jg/jnle | 有符号大于 |
jb/jnae | 无符号小于 | jbe/jna | 无符号小于等于 | jl/jnge | 有符号小于 |
jge/jnl | 有符号大于等于 | jz | 为零 | jnz | 不为零 |
jle/jng | 有符号小于等于 | js | 为负 | jns | 不为负 |
jc | 进位 | jnc | 无进位 | jo | 溢出 |
jno | 无溢出 | jp/jpe | 为偶 | jnp/jpo | 不为偶 |
查看 scanf 得到输入格式为“%d %c %d”;可将后续一系列条件分支还原为 if 语句,注意输入顺序和判断变量并不相同;
最终需将第二个输入转换为 ascii 字符。
查看 scanf 得到输入格式为“%d %d”;后续进入到函数
可将 func4 还原为源码,并得到返回值;由此得到答案。
发现要求
不妨设输入字符为“ch[i]”,发现在循环结构中取“ch[i] & 0x0f”(即 mod 16)作为数组下标,猜测数组大小为 16;
查看数组“x/16xw
通过暴力循环得到符合条件的一组数组下标,并查 ascii 表转换为合适的字符。
发现函数
前两部分要求输入的 6 个数字分别为 1-6 中的一个,并令 arr[i] = 7 - arr[i];
找到
找到入栈的静态区地址并查看“x/3xw
依次查看下一个节点"x/3xw
同时循环结构中要求按 arr[i] 中值重新排列链表,综合得到要求链表为升序/降序;
由此得到 arr[i],arr[i] = 7 - arr[i] 为最终输入。
查看
还可以通过断点调试进一步验证为 phase_4,即运行后查看“%d %d”内存值变化:“x/s
获得字符串方式和 phase_1 相同,此时即进入 secret_phase。
查看
同样改写为源码,发现为递归查找函数,并返回和查找过程有关的值;
找到入栈的静态区地址并查看"x/3xw
依次找处全部节点“x/3xw
发现二叉树为搜索二叉树,深度为 4;
由要求的返回值反推出搜索过程,对应的节点值即为答案(记得转换为10进制)。
理解了帧栈后比前两个要简单得多,但刚开始一直没注意到需要维护段地址的问题,反而被卡了好久。
具体细节这篇文章已经讲得很清楚了:计算机系统基础实验:缓冲区溢出攻击_缓存区溢出攻击实验-CSDN博客。
4题和5题略有不同,需要注意到
1-5题答案具体格式如下: