版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
SUNYAT-SKNI
《计算机组成原理实验》
实验报告
(实验一)
学院名称:数据科学与计算机学院
专业(班级):
学生姓名:
学号
时间:2019年10月8日
成绩:
实验一:X86汇编基础二进制炸弹
一.实验目的
(1)初步认识X86汇编语言;
(2)掌握阅读程序反汇编代码的方法,了解程序在机器上运行的实质;
(3)熟悉Linux环境、掌握调试器gdb和反汇编工具objdump的使用。
二.实验内容
使用课程知识拆除一个"BinaryBomb”(,简称炸弹)来增强对程序的机器级表示、
汇编语言、调试器和逆向工程等理解。二进制炸弹是一个Linux可执行C程序,包含
phase.l~phase_6共6个阶段和一个隐藏阶段secret_phase0你将获得一个唯一且每
位同学差异化的炸弹程序,炸弹运行各阶段要求输入一个字符串,若输入符合程序预期,该
阶段炸弹被“拆除”,否则“爆炸”。实验目标是你需要拆除尽可能多的炸弹。
每个炸弹阶段考察机器级语言程序不同方面,难度递增。
阶段1:字符串比较
阶段2:循环
阶段3:条件/分支:含switch语句
阶段4:递归调用和栈
阶段5:指针
阶段6:链表/指针/结构
隐藏阶段,第4阶段的之后附加一特定字符串后才会出现
拆弹技术:为了完成二进制炸弹拆除任务,你需要
1.使用gdb调试器和objdump反汇编工具;
2.单步跟踪调试每一阶段的机器代码
3.理解汇编语言代码的行为或作用
4.进而设法“推断”出拆除炸弹所需的目标字符串c
5.需要在每一阶段的开始代码前和引爆炸弹的函数前设置断点,便于调试。
三.实验器材
PC机一台,装有Linux操作系统的虚拟机一套。
四.实验过程与结果
说明:根据需要书写.相关内容,如:
程序流程图、设计的思想与方法、分析、实验步躲和实验结果及分析等。
4.1第一关
在刚接触这一大堆汇编代码时,我是迷茫的。好在pdf上给出了第一关的解决方法,而
且第一关的难度也并不大,
Phase」函数一开始进行栈指针修改,后而我们知道这是函数调用时分配栈空间的必经
之路。然后函数压栈两个数据,执行一个函数并进行一个判断,最后返回。
观察至ijstrings_not_equal函数的调用,它判断栈顶的前两个元素。如果它们相等,就
修改eax为0;如此,紧随其后的jne就不会触发,也就不会导致<explode_bomb>的调用。
栈顶的两个元素分别为我们的输入,和$0x804a21c内存处的数据.用gdb查看,可知
它是字符串,为
Breakpoint1,0x08048b60inphase_l0
(gdb)disas
Jumpofassemblercodeforfunctionphase_l:
0x08048b5a<+0>:push%ebp
0x08048b5b<+l>:mov%esp,%ebp
0x08048b5d<:+3>:sub$0x10,%esp
>0x08048b60<+6>:push$0x804a21c
0x08048b65<+ll>:pushl0x8(%ebp)
0x08048b68<:+14>:call0x804904b<s:rings_not_equal>
0x08048b6cl<:+19>:add$0xl0,%esp
0x08048b70<+22>:test%eax,%eax
0x08048b72<:+24>:jne0x8048b76<phase_l+28>
0x08048b74<+26>:leave
0x08048b75<+27>:ret
0x00040b7G<+20>:call0x004927-f<explode_bomb>
0x08048b7b<:+33>:Jmp0x8048b74<phase_l+26>
Endofassemblerdump.
(gdb)x0x804a21c
0x804a21c:0x61632049
(gdb)x/sOxSO^aZlc
3x904a21c:<error:Cannotaccessmemoryataddress0x304a21c>
(gdb)x/s0x80021c
Ox804a21c:"IcanseeRussiafrommyhouseI"
(gdb)
只要让它们相等即可,所以我们本关的答案毫无疑问就是
IcanseeRussiafrommyhouse!
4.2第二关
第二关脱离了指导开始独立作业,我再一次迷茫了。第二关的代码数量突然陡增,同样
先观察代码;首先仍然是准备工作,然后程序调用了一个叫做<read_six_numbers>的函
数,我们找到这个函数一探究竟。
80492bf:55push%ebp
80492c0:89e5mov%esp,%ebp
80492c2:83ec08sub$0x8,%esp
S0492c5:8b450cmovOxc(%ebp),%eax
80492c8:8d5014lea0x14(%eax),%edx
80492cb:52push%edx
80492cc:8d5010lea0x10(%eax),%edx
80492cf:52push%edx
80492d0:8d530cleaOxc(%eax),%edx
80492d3:52push%edx
S0492d4:8d5008lea0x8(%eax),%edx
80492d7:52push%edx
80492d8:8d5004lea0x4(%eax),%edx
80492db:52push%edx
80492dc:50push%eax
80492dd:6861a40408pushS0x804a461
80492e2:ff7508pushl0x8(%ebp)
S0492e5:e826f5ffffcall8048810<_isoc99_sscanfgplt>
可以看到函数用scanf函数读取用户输入的六个数据,地址间间隔为4;再深究可以在
gdb中找到格式化字符为%d整形,所以本关应该是要求我们输入6个整数型。
8048b8f:8d45delea-0x24(%ebp),%eax
8048b92:50push%eax
8048b93:ff7508pushl0x8(%ebp)
8048b96:e824070000call80492bf<readsixnumbers>
我们知道0x8(%ebp)是我们的输入,那么<read_six_numbers>就是把这个输入变成
六个整形放入-Ox24(%ebp)中,可以假设这里是一个整形数组air。
再向下看,函数进行一次判断
8048b9e:837dde05cmpl$0x5,-0x24(%ebp)
8048ba2:7707ja8048bab<phase_2^0x2e>
8048ba4:bb01000000mov$0x1,%ebx
8048ba9:ebOfjmp8048bba<phase_2+0x3d>
8048bab:e8cf060000call804927f<explode_bomb>
也就是arr[0]>5时就触发爆炸。我们知道了输入的第一个数不能大于5.
再继续,下面进入一个循环语句。
8048bb2:83c301add$0x1,%ebx
8048bb5:83fb06emp$0x6,%ebx
8048bb8:7418je8048bd2<phase_2+0x55)
8048bba:8b449dd8mov-0x28(%ebp,%ebx,4),%eax
8048bbe:8945d4mov%eax,-0x2c(%ebp)
8048bcl:89d9mov%ebx,%ecx
8048bc3:d3eOshl%cl,%eax
8048bc5:39449ddeemp%ea|x,-0x24(%ebp,%ebx,4)
8048bc9:74e7je8048bb2<phase_2+0x35>
8048bcb:e8af060000call804927f<explode_bomb>
Ebx应该是循环的控制单位,每次循环自增1,等于6时跳出循环。eax保存一个变址寻
址的结果,然后进行eax位左移,并把它与当前寻址结果的前一个地址进行比较,不相等就
触发爆炸。如果循环顺利执行完毕,本关就被破解。
至此逻辑已经很明确r,我们可以把它翻译成c代码。
if(arr[0]>5)
explode_bombl);
for(inti=l;i!=6;i++){
inttmp=arr|i-l];
tmp<<i;
if(tmp!=arr[ij)
explode_bombl);
}
End
就这样,假设我们的arHO1是1,则第一次左移1位,第二次左移2位…循环5次,我们
就得到arr数组应该装着的6个整形数字。
Step1:1
Step2:2
Step3:8
Step4:64
Step5:1024
Step6:32768
所以本关的答案是12864102432768
4.3第三关
顺利完成第二关终于提升了我的一点信心,再看第三关就没那么可怕(不)
一开始函数压栈4个数值,然后调用scanf函数,可以推断它们都是scanf的参数。
8048bf9:8d45fOlea-0x10(%ebp),%eax
8048bfc:50push%eax
8048bfd:8d45eclea-0xl4(%ebp),%eax
8048c00:50push%eax
8048c01:686da40408push$0x804a46d
8048c06:ff7508Dushl0x8Rebp)
8048c09:e802fcffffcall8048810<_isoc99_sscanf@plt>
-OxlO(%ebp)和-Oxl4(%ebp)都是明确的地址,0x8(%ebp)是我们的输入,这个
0x804a46d就显得很可疑,gdb一看就知道它是格式化字符串。
(gdb)x/s0x804a46d
)x804a46d:"%d%d"
那么本关就是让我们输入两个整形,它们分别存储在-0xl4(%ebp)和-0xl0(%ebp)两
个位置.scanf函数的返回值放在eax中,它的返回值是2(接受两个参数),我们设
-0xl4(%ebp)和-0xl0(%ebp)的两个参数为a和b0
紧跟其后的是判断语句cmpl$0x7,-0xl4(%ebp)
ja8048ca8<phase_3-0xc0>〃爆炸
限制了a的取值,a必须小于等于7.又由于ja比较无符号数,ja还要大于等于0
下面的语句是解决本题的关键性语句jmp*0x804a26c(,%eax,4)
一个基址寻址,*0x204a26c里面的东西是什么?可能是一个跳转表,用gdb杳看之。
(gdb)x/iuwxux«04adbc
0x804a26c:0x0E048c310x08048c380x08048c7e0x08048c85
0x804a27c:0x0E048c8c0x08048c930x08048c9a0x08048cal
0x804a28c<array.30E5>:0x7564616d0x73726569
果然如此,如此一来,我们的输入a(0~7)就会导致8种跳转。这应该是一个switch语句!
再往下就是一些算术悚作,对不同的a输入会有不同的算术。唯一的生死点是一个判断
语句cmpl,它限制了a的取值为0<=a<=5.
8048c60:837dec05cmpl$0x5,-0x14(%ebp)
8048c64:7f05jg8048c6b<phase_3+0x83)
8048c66:3945fOcmp%eax,-0x10(%ebp)
8048c69:7405je8048c70<phase_3+0x88)
8048c6b:e8Of060000call804927f<explode_bomb>
最后让eax,也就是算术结果和第二个输入b相等即可;我们也不需要通读代码来计算
输入,只需要当程序执行到这句时,用gdb查看一下eax的值,就能拿到我们的第二个输入
bo
本题应该有a为0,1,2,3,4,5六组答案.我们只取一种a=0的情况,这时计算得
到的b是-117.第三关的答案就是0-117!
4.4第四关
第四关与前面的不同在于它多了一个<func4>函数。
先观察phase_4主体,发现和第三关的输入方式一样,都是两个整形a和b。
8048d22:8d45f0lea-0x10(%ebp),%eax
8048d25:50push%eax
8048d26:8d45eclea-0x14(%ebp),%eax
8048d29:50push%eax
8048d2a:686da40408pushS0x804a46d
8048d2f:ff7508pushl0x8(%ebp)
8048d32:e8d9faffffcall8048810<_isoc99_sscanf€plt>
这次我们观察到a的输入范围被限制到了0<=a<=14
8048d3f:837decOecmplSOxe,-0x14(%ebp)
8048d43:7605jbe8048d4a<phase_4+0x39>
8048d45:e835050000call804927f<explode_bomb>
紧跟其后的是压栈三个参数,14,。和a,然后调用函数func4,我们判断func4接受三
个参数,而这次调用就是七nc4(a,0,14)
8048d4d:6aOepush$0xe
8048d4f:6a00push$0x0
8048d51:ff75ecpushl-0x14(%ebp)
8048d54:e860ffffffcall8048cb9<func4>
好的我们进入func4的代码
8048cc0:8b4508mov0x8(%ebp),%eax
8048cc3:8b550cmovOxc(%ebp),%edx
8048cc6:8b4d10mov0x10(%ebp),%ecx
8048cc9:29dlsub%edx,%ecx
8048ccb:89cbmov%ecx,%ebx
8048ccd:clebIfshrSOxlf,%ebx
8048cd0:01cbadd与ecx,%ebx
8048cd2:dlfbsar%ebx
8048cd4:01d3add%edx,%ebx
8048cd6:39c3cmp%eax,%ebx
8048cd8:7fObJg8048ce5<func4+0x2c>
8048cda:39c3cmp%eax,%ebx
8048cdc:7c1cjl8048cfa<func4+0x41>
8048cde:89d8mov%ebx,%eax
8048ce0:8b5dfcmov-0x4Rebp),%ebx
8048ce3:c9leave
8048ce4:c3ret
首先是从栈中拿出参数放入寄存器,然后对参数进行了一系列的加减移位计算,最后进
行两次判断,这样就是三条分支语句;应该是if-elseif-else语句。
判断1:ebx>eba时:
8048ce5:83ec04sub$0x4,%esp
8048ce8:8d4bfflea-0x1(%ebx),%ecx
8048ceb:51push%ecx
8048cec:52push%edx
8048ced:50push%eax
8048cee:e8cCffffffcall8048cb9<func4>
8048cf3:83c410add$0x10,%esp
8048cf6:01c3add%eax,%ebx
8048cf8:ebe4jmp8048cde<func4+0x25>
这时把eax,edx,ebx-1递归传入func4,返回func4(eax,edx,ebx-l)。
判断2:ebx<eba时:
8048cfa:83ec04sub$0x4,%esp
8048cfd:ff7510pushl0x10(%ebp)
8048do0:8d5301lea0x1(%cbx),%cdx
8048d03:52push%edx
8048d04:50push%eax
8048d05:e8afffffffcall8048cb9<func4>
8048d0a:83c410add$0x10,%esp
8048d0d:01c3add%eax,%ebx
8048d0f:ebcdJmp8048cde<func4+0x25>
这时把eax,ebx+1,原始的ecx递归传入func4,返回func4(eax,ebx+l,ecx+edx)
乍一看这个函数很难知道它想用递归实现什么,但是用高级语言复现这个函数是很简单
的,我们可以用python实现该函数,并逐一尝试输入a为0~14的情况。
Func4执行完毕后,返回值在eax中,随后执行最后的步骤
8048d5c:83f8Ifemp$0xlf,%eax
8048d5f:7506jne8048d67<phase_4+0x56>
8048d61:837dfOIfcmpl$0xlf,-0x10(%ebp)
8048d65:7405je8048d6c<phase_4+0x5b>
8048d67:e813050000call804927f<explode_bomb>
判断返回值和输入b是否为0xlf(31),这样我们的输入a必须让函数返回31,b必须是
31.
使用python模拟该程序的运行,结果如卜:
In二6二:deffun(a,d,c):
c-=d
b=c
b//=2
b+=d
ifb>a:
returnb+fun(a,d,b-l)
elifb<a:
returnb+fun(a,b+1,c+d)
else:
returnb
In二8二:foriinrange(1,14):
print(wheninput',i,',func4return',fun(i,0,14))
wheninput1,func4return11
wheninput2,func4return13
wheninput3,func4return10
wheninput4,func4return19
wheninput5,func4return15
wheninput6,func4return21
wheninput7,func4return7
wheninput8,func4return35
wheninput9,func4return27
wheninput10,func4return37
wheninput11,func4return18
wheninput12,func4return43
wheninput13,func4return31
可见输入为13时,func4返回31.即a=13,b=31就是我们要的答案。
第四关答案为1331!
4.5第五关
我们已经掌握了一些套路,接下来的关卡虽然难度大了,但并没有前几关那么棘手了。
一开始还是观察输入格式,发现并没有scanf的格式化输入,可以判断本关输入是一个
字符串;程序一开始有mov0x8(%ebp),%ebx
push%ebx
call8049029<string_length>
cmp$0x6,%eax
jne8048dee<phase_5+0x6f>
把我们的输入字符串放入一个string_length函数中,通过阅读这个函数发现它会返回
字符串长度,保存在eax中。然后eax与6作比较,不相等则爆炸,于是我们判断本关是要求
我们输入一个6长度字符串。
紧随其后的是一段循环语句
8048da2:b800000000mov$0x0,%eax
8048da7:Ofb61403movzbl(%ebx,%eax,1),%edx
8048dab:83e2Ofand$0xf,%edx
8048dae:Ofb6928ca20408movzbl0x804a28c(%edx),%edx
8048db5:885405edmov%dl,-0x13(%ebp,%eax,l)
8048db9:83cO01add$0xl,%eax
8048dbc:83f806emp$0x6,%eax
8048dbf:75e6jne8048da7<phase_5+0x28>
Ebx是输入的字符串,设为str,eax应该是for循环的控制单位,也做下标使用,设为i。
程序每次循环读取str[i]的值,然后用一个andOxf取其后四位。随后有一个基址寻址
0x804a28c(%edx),不知道这块内存存储着什么,打开看一看。
(gdb)x/sOx804a28c
0x804o28c<array.3035>:"rraduicrsnfotvbylSoyouthinkyouconstopthebombwithCtrlc,doyou?'
|(gdb)
是一串字符串,设它为s,那么这句就是取s[str[i]&Oxf];后面还把它放入了
-0xl3(%ebp,%eax,l)这段地址中,如此一来我们就可以翻译这段代码为C代码:
for(inti=0;i!=6;i++){
chartmp=s[str[i]&Oxf];
arr[i]=tmp;
}
再往后就是一个<strings_not_equal>函数的调用
8048dc8:6862a20408pushS0x804a262
8048dcd:8d45edlea-Ox13(%ebp),%eax
8048dd0:50push%eax
8048ddl:e875020000call804904b<strings_not_equal>
8048dd6:83c410add$0xl0,%esp
8048dd9:85cOtest%eax,%eax
8048ddb:7518jne8048df5<phase_5+0x76>
函数比较-0xl3(%ebp),也就是上面的arr,和0x804a262内存处的字符串。打开
0x804a262看看里面是什么.
(gdb)x/s0x804a262
0x804a262:"brums"
一个单词bruins,要让arr和它相等,就要从s中分别找到这六个字母的下标,然后用
把这些下标作为输入的六个字符的后四位来形成我们需要的目的字符串。
寻找下标和转为字符串的工作可以用高级语言实现,下面是python实现过程。
s=,zmaduiersnfotvbylSoz,
print(s.find(,bJ))
print(s.find(?r'))
print(s.find('u'))
print(s.find(,i))
print(s.find('n'))
print(s.find。s'))
13
6
3
4
8
一
我们要把找到的下标转成字符形式
把高半个字节设置成0000可能会出现转义字符不方便输入
我们这里设置成0004,也就是数值上增力04X16=64
print(chr(64+s.findCb')))
print(chr(64+s.find('r')))
print(chr(64+s.find('u')))
print(chr(64+s.find(i)))
print(chr(64+s.find('n')))
print(chr(64+s.find('s')))
F
C
D
H
G
于是我们就得到了一种可能的答案MFCDHG。
即第五关的答案为MFCDHG。
4.6第六关
还是从输入数据格式入手,发现和第二关的处理输入的部分相同,都是借助
<read_six_numbers>函数,把输入用scanf截获为六个整数型0
8048el4:8d45c4lea-0x3c(%ebp),%eax
8048el7:50push%eax
8048el8:ff7508pushl0x8(%ebp)
8048elb:e89f040000call80492bf<read_six_numbers>
它们保存在-0x3c(%ebp)处的一个序列,设为arr。
紧随其后的是一个嵌套的二重循环语句
8048e23:be00000000mov$0x0,%esi
8048e28:8b44b5c4mov-0x3c(%ebp,%esi,4),%eax
8048e2c:83e801sub$0x1,%eax
8048e2f:83f805cmp$0x5,%eax
8048e32:77Oc.ia8048e40<phase6+0x3f>
8048e34:83c601add$0x1,%esi
8048e37:83fe06cmp$0x6,%esi
8048e3a:7451je8048e8d<phase_6+0x8c>
8048e3c:89f3mov%esi,%ebx
8048e3e:ebOfjmp8048e4f<phase_6+0x4e>
8048e40:e83a040000call804927f<explode_bomb>
8048e45:ebedjmp8048e34<phase_6+0x33>
8048e47:83c301add$0x1,%ebx
8048e4a:83fb05cmp$0x5,%ebx
8048e4d:7fd9Jg8048e28<phase_6+0x27>
8048e4f:8b449dc4mov-0x3c(%ebp,%ebx,4),%eax
8048e53:3944b5cOcmp%eax,-0x40(%ebp,%esi,4)
8048e57:75eejne8048e47<phase_6+0x46>
8048e59:e821040000call804927f<explode_bomb>
8048e5e:ebe7jmp8048e47<phase_6+0x46>
第一层循环先拿出arr|i],然后做一个判断
8048e28:8b44b5c4mov-0x3c(%ebp,%esi,4),%eax
8048e2c:83e801sub$0xl,%eax
8048e2f:83f805cmp$0x5,%eax
8048e32:77Ocja8048e40<phase_6+0x3f>〃爆炸
就是判断arr[i]是否小于等于6,因为使用了无符号数判断ja,还要满足arHi]>=0。
后面有一个小循环,取当前的i并加1,然后增长到5,设这个变量为ii,则
8048e53:3944b5cOcmp%eax,-0x40(%ebp,%esi,4)
8048e57:75eejne8048e47<phase_6+0x46>
8048e59:e821040000call804927f<explode_bomb>
判断语句让air㈤==arr[i-l]时触发炸弹。
把这段语句翻译为C代码如F:
for(inti=0;i!=6;){
if(arr[i]-l>5)
Explode_bomb();
i++;
for(intii=i;ii<=5;ii++){
if(arr[ii]==arr[i-l])
Explode_bomb();
)
}
也就是arr中的元素必须是0~6的数字,而且不能重复。
下面的一段程序又是一个二重循环
8048e60:8b5208mov0x8(%edx),%edx
8048e63:83cO01add$0xl,%eax
8048e66:39c8emp%ecx,%eax
8048e68:75f6jne8048e60<phase_6+0x5f>
8048e6a:8954b5demov%edx,-0x24(%ebp,%esi,4)
8048e6e:83c301add$0x1,%ebx
8048e71:83fb06emp$0x6,%ebx
8048e74:74leje8048e94<phase_6+0x93>
8048e76;89demov%ebx,%esi
8048e78:8b4c9dc4mov-0x3c(%ebp,%ebx,4),%ecx
8048e7c:b801000000mov$0xl,%eax
8048e81:ba54cl0408mov$0x804cl54,%edx
8048e86:83f901emp$0x1,%ecx
8048e89:7fd5jg8048e60<phase_6+0x5f>
8048e8b:ebddjmp8048e6a<phase_6+0x69>
这段代码是循环寻找0x804cl54+arr[i]*8的地址,然后把这块地址放到
-0x24(%ebp,%esi,4)+,它应该是储存指针的数组,至于这是指向什么的指针,我们可以
在gdb中找至iJOx804cl54看一看。
(gdb)X/20WX0x804cl54
0X804C154<nodel>:0x0000005c0x000000010X0804C1600x000003b2
0X804C164<node2+4>:0x000000020x0804cl6c0x000000660x00000003
UX8U4C174<node3+8>:0X08D4C1780X0U00Q0C30X000000040X0804C184
0X804C184<node5>:0X000001C90x000000050x0804c1900x00000310
0X804C194<node6+4>:0x000000060x000000000x000000000x31333731
一个叫做node的结构体,那么数组-0x24(%ebp)就是node*nodes[]类型。
再观察结构体的内部数据,由三部分组成,value,number和next,这是我们熟悉的
链表结构,C语言代码如下:
Structnode{
Intval;
Intnum;
Node*next;
}
如此一来上面的步骤就说得通了,翻译成C代码(0x804cl54用L表示)
For(inti=0;i!=6;i-+){
Intc=arr[i],a=1;
Node*d=L;
If(c>l){
For(;a!=c;a++){
d=d->next;
)
Nodes[i]=d;
}
很显然这段代码就是按照我们输入arr中的六个数,以L为链表头搜索链表的第arr[i]个
结点。并把链表结点保存在nodes[i]中。
再下面的一段程序,很显然是按照nodes的顺序重新串接链表的一系列操作。
mov-0x24(%ebp),%ebx
mov-0x20(%ebp),%eax
mov%eax,0x8(%ebx)
mov-Oxlc(%ebp),%edx
mov%edx,0x8((H)eax)
mov-0xl8(%ebp),%eax
mov%eax,0x8(%edx)
mov-0x14(%ebp),%edx
mov%edx,0x8(%eax)
mov-0x10(%ebp),%eax
mov%eax,0x8(%edx)
movl$0x0,0x8(%eax)
最后一段判断程序,遍历链表并比较链表前一个元素和后一个元素
8048ebc:be05000000mov$0x5,%esi
8048ecl:eb08jmp8048ecb<phase_6+0xca>
8048ec3:8b5b08mov0x8(%ebx),%ebx
8048ec6:83ee01sub$0x1,%esi
8048ec9:7410je8048edb<phase_6+0xda>
8048ecb:8b4308mov0x8(%ebx),%eax
8O48ece:8b00mov(%eax),%eax
8048ed0:3903cmp%eax,(%ebx)
8048ed2:7defjge8048ec3<phase_6+0xc2>
8048ed4:e8a6030000call804927f<explode_bomb>
8048ed9:ebe8jmp8048ec3<phase_6+0xc2>
Eax是ebx的后一个链表结点,必须满足ebx>eax才能不触发炸弹,也就是整个链表的
值必须是降序的。
这样这一关的用意就很明显了,就是要我们输入6个数字,这六个数字就是重排后链表
结点的顺序;我们要保证这个顺序是降序的,就要按照合适的顺序输入123456.
排序的工作可以借助高级语言完成,python的实现如下。
nodes=[(0x5c,1),(0x3b2,2),(0x66,3),(0xc3,4),(0xlc9,5),(0x310,6)1
nodes,sort()
nodes,reverse()
nodes
[(946,2),(784,6),(457,5),(195,4),(102,3),(92,1)]
答案为265431
即本关答案为265431
4.7隐藏关
我们惊喜地发现事情还没有结束!在phase_6之后还有一段<secret_phase>,它要怎
么触发呢?我们在源码中搜索它,发现它出现在下面的位置。
804949a:75cajne8049466<phase_defused+0x5c>
804949c:83ecOcsub$0xc,%esp
804949f:681ca30408pushS0x804a31c
80494a4:e817f3ffffcall80487c0<puts@plt>
80494a9:c7042444a30408movlS0x804a344,(%esp)
80494b0:e80bf3ffffcall80487c0<puts@plt>
80494b5:e88dfaffffcall8048f47<secret_phase>
在<phase_defused>函数中,而这个函数是每次拆弹成功后才被调用的。读代码可以
发现这里先调用scanf,要我们输入一段字符串;然后调用<strings_not_equal>,当相等
时才能调用<secret_phase>函数。可是每一关最后都调用这个函数,这个输入应该出现在
哪里呢?找到scanf的输入参数
lea-0x5c(%ebp),%eax
push%eax
lea-0x60(%ebp),%eax
push%eax
lea-0x64(%ebp),%eax
push%eax
push$0x804a4c7
push$0x804c8f0
call8048810<_isoc99_sscanf@plt>
查看其中的格式化字符如卜.:
(gdb)x/s0x804a4c7
)x804a4c7:H%d%d%s"
是跟在两个整数后面的一段字符串!要输入两个整数的是第三关和第四关,而第三关已
经有了输入数最的限制,所以触发关卡是要在第四关后面多输入一串特殊字符串。
push50x804a4d0
1ea-0x5c(%ebp),%eax
push%eax
call804904b<strings_not_equal>
后面把输入字符串和0x804a4d0进行比较,打开Ox8O4a4do查看,它就是特殊字符串。
(gdb)x/s0x804a4do
0x804a4d0:"SecretSYSU1'
进关条件就是在第四关输入1331SecretSYSU
Curses,you'vefoundthesecretphase!
Butfindingitandsolvingitarequitedifferent...
我们进入了关k,下面浏览这一关的代码。
可以看见函数一开始调用了read」ine,把输入放在eax中。然后是<strtol@plt>函数
的调用,strtol(%eax,NULL,10)。也就是我们输入的字符串应该是10进制数,它会被转
换成一个长整形C紧随其后有一条判断
8048f62:8d40fflea-Ox1(%eax),%eax
8048f65:83c410add$0xl0,%esp
8048f68:3de8030000cmp$0x3e8,%eax
8048f6d:7735ja8048fa4<secret_phase+0x5d
判断(%eax-l)>0x3e8时触发爆炸,限制了我们的输入范围。
之后是fun7的调用,参数分别为我们的输入和$Ox8O4cOaO,查看内容可知为24.
(gdb)X/UJX0x804c0a0
0x804c0a0<nl>:0x00000024
执行fun7(0x804c0a0,input),后面可以看到如果返|叫直为3就完成本关。
查看fun7函数,通读可知是一个if-elseif-else语句。
8048efa:8b5508mov0x8(%ebp),%edx
8048efd:8b4d0cmovOxc(%ebp),%ecx
8048f0
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 47562-2026微机电系统(MEMS)技术MEMS硅压阻温压复合压力传感器芯片
- 幼儿园教师职称评审改革效果研究-基于各省幼儿园教师职称评审文件数据分析
- 2026年自考工商管理人力资源管理试题(含答案及解析)
- 江西省广播电视编辑记者、播音员主持人资格考试(广播电视基础知识)考前冲刺试题及答案(2026年)
- 政府采购评审专家考试试题及答案(永州2026年)
- 2025-2030年智能酒店客房企业制定与实施新质生产力战略分析研究报告
- 新形势下港澳台水路旅客运输行业顺势崛起战略制定与实施分析报告
- 新形势下超声治疗设备行业顺势崛起战略制定与实施分析研究报告
- 再生铍企业ESG实践与创新战略分析报告
- 商业用案秤企业制定与实施新质生产力战略分析报告
- 幼儿园玩教具制作 课件 第四章第一节美术教育活动类玩教具
- 2026年四川省成都市网格员招聘考试参考试题及答案解析
- 老年人尿失禁评估与干预
- 深圳某国际机场自然灾害应对预案与处置流程
- 九年级下册《儒林外史》整本书阅读专题式推进教学设计
- 2026云南国有股权运营管理公司招聘试题及答案
- 2026年如何制定有效的设备维护计划
- 雨课堂学堂在线学堂云《创新思维与创业实验(东南)》单元测试考核答案
- 乡镇矛盾纠纷调处课件
- 2025年山西航空产业集团有限公司招聘考试笔试试题(含答案)
- 选煤厂集控室培训课件
评论
0/150
提交评论