Recitation 4
讲了一些GDB常用操作,虽然不少已经在 CS61C 里面学过了,但是保险起见还是在这里再记录一下
几个不熟悉的
clear main // remove the breakpoint at function main
(gdb) print (char*) [0x...] // prints a string
(gdb) print argv[1]
(gdb) disassemble main // show the assembly instructions in main
print/x $rsi // ‘/x’ means print in hexadecimal
要查看传入被调用函数的参数是什么,最好的办法就是直接看对应函数的汇编代码,
- 一般来说,
$rdi
保存第一个参数,$rsi
保存第二个,$rax
保存返回值
一个小技巧: 按 Enter 键就可以重复上一次操作
info breakpoints (i b)
- List all breakpoints, along with whether or not they are enabled
delete [breakpoint] (d)
- Delete a breakpoint
enable [breakpoint] (en)
- Enable a breakpoint, If none specified, enables all breakpoints
disable [breakpoint] (dis)
- Disable a breakpoint. If none specified, disables all breakpoints
info registers (i reg)
- Print all the registers, along with their contents
print [any valid C expression] (p)
- Can be used to study any kind of local variable or memory location
- Use casting to get the right type (e.g.
print *(long *)pointer
) - Can format with things like
/x
(hex),/d
(int),/s
(string) etc. x [some format specifier] [some memory address]
- Examines memory.
x ptr
is the same asp *ptr
- Can format with things like /x (hex), /d (int), /s (string) etc.
layout [next | prev | assembly | register] (la [n | p | asm | reg])
- Show assembly code or registers in the top half of the window as you go
- The TUI is buggy. If your screen begins glitching, you may have to restart GDB
- Exit with
<ctrl> x + <ctrl> a
focus [command | assembly | register] (fo [cmd | asm | reg])
- Change the focus window within the TUI (buggy)
Bomblab
phase3
几个跳转指令
For unsigned comparisons:
JB/JNAE (CF = 1) : Jump if below/not above or equal
JAE/JNB (CF = 0) : Jump if above or equal/not below
JBE/JNA (CF = 1 or ZF = 1) : Jump if below or equal/not above
JA/JNBE (CF = 0 and ZF = 0): Jump if above/not below or equal
For signed comparisons:
JL/JNGE (SF <> OF) : Jump if less/not greater or equal
JGE/JNL (SF = OF) : Jump if greater or equal/not less
JLE/JNG (ZF = 1 or SF <> OF): Jump if less or equal/not greater
JG/JNLE (ZF = 0 and SF = OF): Jump if greater/not less or equal
phase3看着就是一堆switch语句,轻松搞定
phase4
phase4注意test
的用法
将两个操作数进行按位AND,设结果是TEMP
- SF = 将结果的最高位赋给SF标志位,例如结果最高位是1,SF就是1
- 如果TEMP是0,ZF位置1;如果不是0,ZF位置0
- 如果结果低8位中1的个数是偶数,PF=1;否则PF=0
- CF位置0
- OF位置0
一个经典应用之测试是否为零
test ecx, ecx
jz somewhere
0000000000400fce <func4>: #传入的 %edx 为 0xe, %esi 为 0x0, %edi 为输入的第一个参数 a1
400fce: 48 83 ec 08 sub $0x8,%rsp
400fd2: 89 d0 mov %edx,%eax # %eax = %edx
400fd4: 29 f0 sub %esi,%eax # %eax = %edx - %esi
400fd6: 89 c1 mov %eax,%ecx # %ecx = %eax
400fd8: c1 e9 1f shr $0x1f,%ecx # %ecx 逻辑右移 31 位(高位补0)
400fdb: 01 c8 add %ecx,%eax # %eax += 符号位
400fdd: d1 f8 sar %eax # %eax >>= 1
400fdf: 8d 0c 30 lea (%rax,%rsi,1),%ecx # %ecx = %rax + %rsi
400fe2: 39 f9 cmp %edi,%ecx
400fe4: 7e 0c jle 400ff2 <func4+0x24> #若 %ecx<=%edi, 跳转
400fe6: 8d 51 ff lea -0x1(%rcx),%edx # %edx = %rcx - 1
400fe9: e8 e0 ff ff ff callq 400fce <func4>
#以下两行似乎没有用
400fee: 01 c0 add %eax,%eax # %eax *= 2
400ff0: eb 15 jmp 401007 <func4+0x39>
400ff2: b8 00 00 00 00 mov $0x0,%eax # %eax = 0
400ff7: 39 f9 cmp %edi,%ecx
400ff9: 7d 0c jge 401007 <func4+0x39> # %ecx >= %edi 跳转
400ffb: 8d 71 01 lea 0x1(%rcx),%esi # %esi = %rcx + 1
400ffe: e8 cb ff ff ff callq 400fce <func4>
# 这一行好像也没用
401003: 8d 44 00 01 lea 0x1(%rax,%rax,1),%eax # 2*%rax+1=%eax=0
401007: 48 83 c4 08 add $0x8,%rsp
40100b: c3 retq
只要第一个参数等于对应的 %ecx
即可
phase5
注意寄存器的关系
%cl
是%rcx
的低八位%dl
是%rdx
的低八位
0x0000000000401062 <+0>: push %rbx
0x0000000000401063 <+1>: sub $0x20,%rsp
0x0000000000401067 <+5>: mov %rdi,%rbx # %rbx = %rdi
0x000000000040106a <+8>: mov %fs:0x28,%rax # canary被存入 %rax
0x0000000000401073 <+17>: mov %rax,0x18(%rsp) # canary被存入 0x18(%rsp)
0x0000000000401078 <+22>: xor %eax,%eax # %eax = 0
0x000000000040107a <+24>: callq 0x40131b <string_length>
0x000000000040107f <+29>: cmp $0x6,%eax
0x0000000000401082 <+32>: je 0x4010d2 <phase_5+112> #字符串长度等于6 则跳转
0x0000000000401084 <+34>: callq 0x40143a <explode_bomb>
0x0000000000401089 <+39>: jmp 0x4010d2 <phase_5+112>
0x000000000040108b <+41>: movzbl (%rbx,%rax,1),%ecx # %ecx 等于 (%rbx,%rax,1) 处的值
0x000000000040108f <+45>: mov %cl,(%rsp) # %cl 是 %rcx 的低八位
0x0000000000401092 <+48>: mov (%rsp),%rdx
# 下面这一句应该没用(马上被覆盖掉了)
0x0000000000401096 <+52>: and $0xf,%edx # 上面一串相当于 %edx = (%rbx,%rax,1) 处的值的低四位
0x0000000000401099 <+55>: movzbl 0x4024b0(%rdx),%edx
0x00000000004010a0 <+62>: mov %dl,0x10(%rsp,%rax,1)
0x00000000004010a4 <+66>: add $0x1,%rax
0x00000000004010a8 <+70>: cmp $0x6,%rax
0x00000000004010ac <+74>: jne 0x40108b <phase_5+41>
0x00000000004010ae <+76>: movb $0x0,0x16(%rsp)
0x00000000004010b3 <+81>: mov $0x40245e,%esi # 第二个操作数, 此处为"flyers"
0x00000000004010b8 <+86>: lea 0x10(%rsp),%rdi # 第一个操作数
0x00000000004010bd <+91>: callq 0x401338 <strings_not_equal>
0x00000000004010c2 <+96>: test %eax,%eax
0x00000000004010c4 <+98>: je 0x4010d9 <phase_5+119>
0x00000000004010c6 <+100>: callq 0x40143a <explode_bomb>
0x00000000004010cb <+105>: nopl 0x0(%rax,%rax,1)
0x00000000004010d0 <+110>: jmp 0x4010d9 <phase_5+119>
0x00000000004010d2 <+112>: mov $0x0,%eax
0x00000000004010d7 <+117>: jmp 0x40108b <phase_5+41>
0x00000000004010d9 <+119>: mov 0x18(%rsp),%rax
0x00000000004010de <+124>: xor %fs:0x28,%rax
0x00000000004010e7 <+133>: je 0x4010ee <phase_5+140>
0x00000000004010e9 <+135>: callq 0x400b30 <__stack_chk_fail@plt>
0x00000000004010ee <+140>: add $0x20,%rsp
0x00000000004010f2 <+144>: pop %rbx
0x00000000004010f3 <+145>: retq
注意几个 mov
指令的区别
假设 %dh =8D,%eax=98765432
movb %dh %al %eax=9876548D
movsbl %dh %eax %eax=FFFFFF8D
movzbl %dh %eax %eax=0000008D
(gdb) x/16x 0x4024b0
0x4024b0: 0x7564616d 0x73726569 0x746f666e 0x6c796276
0x4024c0: 0x79206f53 0x7420756f 0x6b6e6968 0x756f7920
0x4024d0: 0x6e616320 0x6f747320 0x68742070 0x6f622065
0x4024e0: 0x7720626d 0x20687469 0x6c727463 0x202c632d
(gdb) x/16x 0x40245e
0x40245e: 0x65796c66 0x00007372 0x00000000 0x00000000
0x40246e: 0x0f7c0000 0x00000040 0x0fb90000 0x00000040
0x40247e: 0x0f830000 0x00000040 0x0f8a0000 0x00000040
0x40248e: 0x0f910000 0x00000040 0x0f980000 0x00000040
所以感觉就是根据输入的,来从给定的 0x4024b0
里面找到一样的就行
所以依次应该是:
-
0x66
对应第9个,则输入的第一个字符的ASCII码最后一位应为0x9
-
0x6c
-0xf
,0x79
-0xe
,0x65
-0x5
,0x72
-0x6
,0x73
-0x7
直接用字母,答案应该为 ionefg
phase6
rbx
,rbp
,r12
,r13
,r14
,r15
都是被调用者保存r10
,r11
,rax
,rdi
,rsi
,rdx
,rcx
,r8
,r9
都是调用者保存
这是一个链表!!!!!
一开始是为了检验链表不能连自身,所以要检测相邻的数字不一样
0x00000000004010f4 <+0>: push %r14
0x00000000004010f6 <+2>: push %r13
0x00000000004010f8 <+4>: push %r12
0x00000000004010fa <+6>: push %rbp
0x00000000004010fb <+7>: push %rbx
0x00000000004010fc <+8>: sub $0x50,%rsp
0x0000000000401100 <+12>: mov %rsp,%r13 # 数组开始的地方, 即a
0x0000000000401103 <+15>: mov %rsp,%rsi
0x0000000000401106 <+18>: callq 0x40145c <read_six_numbers>
0x000000000040110b <+23>: mov %rsp,%r14 # 数组开始的地方, 即a
0x000000000040110e <+26>: mov $0x0,%r12d # %r12 的低32位清零
0x0000000000401114 <+32>: mov %r13,%rbp # 数组开始的地方, 即a
0x0000000000401117 <+35>: mov 0x0(%r13),%eax # %eax = a[i-1]
0x000000000040111b <+39>: sub $0x1,%eax # %eax = a[i-1] - 1
0x000000000040111e <+42>: cmp $0x5,%eax
0x0000000000401121 <+45>: jbe 0x401128 <phase_6+52> # 检查 a[i-1] - 1 <= 5
0x0000000000401123 <+47>: callq 0x40143a <explode_bomb>
0x0000000000401128 <+52>: add $0x1,%r12d
0x000000000040112c <+56>: cmp $0x6,%r12d # 循环5次, 令 i = %r12d (1到5)
0x0000000000401130 <+60>: je 0x401153 <phase_6+95>
0x0000000000401132 <+62>: mov %r12d,%ebx # %ebx = i
0x0000000000401135 <+65>: movslq %ebx,%rax # 符号扩展后送到 %rax (就是i)
0x0000000000401138 <+68>: mov (%rsp,%rax,4),%eax # %eax = a[i]
0x000000000040113b <+71>: cmp %eax,0x0(%rbp)
0x000000000040113e <+74>: jne 0x401145 <phase_6+81> # 需要 %eax = a[i] != a[i-1]
0x0000000000401140 <+76>: callq 0x40143a <explode_bomb>
0x0000000000401145 <+81>: add $0x1,%ebx
0x0000000000401148 <+84>: cmp $0x5,%ebx
0x000000000040114b <+87>: jle 0x401135 <phase_6+65>
0x000000000040114d <+89>: add $0x4,%r13 # a数组指针推后一个
0x0000000000401151 <+93>: jmp 0x401114 <phase_6+32>
0x0000000000401153 <+95>: lea 0x18(%rsp),%rsi
--Type <RET> for more, q to quit, c to continue without paging--
0x0000000000401158 <+100>: mov %r14,%rax # $rax = 数组开头地址
0x000000000040115b <+103>: mov $0x7,%ecx # %ecx = 7
0x0000000000401160 <+108>: mov %ecx,%edx # %edx = 7
0x0000000000401162 <+110>: sub (%rax),%edx # %edx -= (%rax) 即 a[i]
0x0000000000401164 <+112>: mov %edx,(%rax) # 以上相当于 a[i] = 7 - a[i]
0x0000000000401166 <+114>: add $0x4,%rax
0x000000000040116a <+118>: cmp %rsi,%rax
0x000000000040116d <+121>: jne 0x401160 <phase_6+108>
0x000000000040116f <+123>: mov $0x0,%esi
0x0000000000401174 <+128>: jmp 0x401197 <phase_6+163>
0x0000000000401176 <+130>: mov 0x8(%rdx),%rdx
0x000000000040117a <+134>: add $0x1,%eax
0x000000000040117d <+137>: cmp %ecx,%eax # %ecx 被<+163>赋值为 a[j]
0x000000000040117f <+139>: jne 0x401176 <phase_6+130> # 相当于令 %rdx = node[6-j]的第三个数
0x0000000000401181 <+141>: jmp 0x401188 <phase_6+148>
0x0000000000401183 <+143>: mov $0x6032d0,%edx
0x0000000000401188 <+148>: mov %rdx,0x20(%rsp,%rsi,2)
0x000000000040118d <+153>: add $0x4,%rsi
0x0000000000401191 <+157>: cmp $0x18,%rsi
0x0000000000401195 <+161>: je 0x4011ab <phase_6+183>
0x0000000000401197 <+163>: mov (%rsp,%rsi,1),%ecx # %ecx = a[j]
0x000000000040119a <+166>: cmp $0x1,%ecx
0x000000000040119d <+169>: jle 0x401183 <phase_6+143> # a[j] <= 1 跳转
0x000000000040119f <+171>: mov $0x1,%eax
0x00000000004011a4 <+176>: mov $0x6032d0,%edx
0x00000000004011a9 <+181>: jmp 0x401176 <phase_6+130>
0x00000000004011ab <+183>: mov 0x20(%rsp),%rbx # %rbx = 被放进去的第一个数
0x00000000004011b0 <+188>: lea 0x28(%rsp),%rax # %rax = 被放进去的第二个数对应的地址
0x00000000004011b5 <+193>: lea 0x50(%rsp),%rsi # 0x00402210对应的地址(对应理论上的第七个数)
0x00000000004011ba <+198>: mov %rbx,%rcx # %rcx = 被放进去的第一个数
# 在链表中 %rcx 的下一个是 %rdx
0x00000000004011bd <+201>: mov (%rax),%rdx # %rdx = 被放进去的第i+1个数
0x00000000004011c0 <+204>: mov %rdx,0x8(%rcx) # 把 b[i+1] 放到 0x8(%rcx)
0x00000000004011c4 <+208>: add $0x8,%rax
--Type <RET> for more, q to quit, c to continue without paging--
0x00000000004011c8 <+212>: cmp %rsi,%rax # 需要 %rsi = %rax
0x00000000004011cb <+215>: je 0x4011d2 <phase_6+222>
0x00000000004011cd <+217>: mov %rdx,%rcx
0x00000000004011d0 <+220>: jmp 0x4011bd <phase_6+201>
0x00000000004011d2 <+222>: movq $0x0,0x8(%rdx)
0x00000000004011da <+230>: mov $0x5,%ebp
0x00000000004011df <+235>: mov 0x8(%rbx),%rax
0x00000000004011e3 <+239>: mov (%rax),%eax
0x00000000004011e5 <+241>: cmp %eax,(%rbx)
0x00000000004011e7 <+243>: jge 0x4011ee <phase_6+250> # (%rbx) >= %eax = (%rax) = [0x8(%rbx)] 即链表递减
0x00000000004011e9 <+245>: callq 0x40143a <explode_bomb>
0x00000000004011ee <+250>: mov 0x8(%rbx),%rbx
0x00000000004011f2 <+254>: sub $0x1,%ebp
0x00000000004011f5 <+257>: jne 0x4011df <phase_6+235>
0x00000000004011f7 <+259>: add $0x50,%rsp
0x00000000004011fb <+263>: pop %rbx
0x00000000004011fc <+264>: pop %rbp
0x00000000004011fd <+265>: pop %r12
0x00000000004011ff <+267>: pop %r13
0x0000000000401201 <+269>: pop %r14
0x0000000000401203 <+271>: retq
其中第<+143> <+176>
行的东西是这个,看起来是记录什么东西,也许是原始数组或者序号(输入是 1 2 3 4 5 6
)
(gdb) x/32x 0x6032d0
0x6032d0 <node1>: 0x0000014c 0x00000001 0x006032e0 0x00000000
0x6032e0 <node2>: 0x000000a8 0x00000002 0x006032f0 0x00000000
0x6032f0 <node3>: 0x0000039c 0x00000003 0x00603300 0x00000000
0x603300 <node4>: 0x000002b3 0x00000004 0x00603310 0x00000000
0x603310 <node5>: 0x000001dd 0x00000005 0x00603320 0x00000000
0x603320 <node6>: 0x000001bb 0x00000006 0x00000000 0x00000000
0x603330: 0x00000000 0x00000000 0x00000000 0x00000000
0x603340 <host_table>: 0x00402629 0x00000000 0x00402643 0x00000000
做到后面发现这个应该是一个链表,顺序是
1<-2<-3<-4<-5<-6
输入进去的数组存放在 0x7fffffffdc70