csapp -bomblab记录1-5

new bomblab

1.Border relations with Canada have never been better.

2.1 2 4 8 16 32

  1. 1 311
  2. 7 0
  3. IONEFG

该实验要求用户输入6个不同的字符串,如果任何一个不正确,炸弹就会爆炸。

1.checksec bomblab 来查看保护开启的情况

2.gdb bomb

3.disass main

4.disass phase_1 栈顶抬高sub,传参给esi寄存器。这个是第二个参数,第一个参数在进入phase_1前已经传入了。

0x0000000000400e32 <+146>: call 0x40149e <read_line>
0x0000000000400e37 <+151>: mov rdi,rax

将我们输入的作为第一个参数。rax是前面read的返回值。

(询问明明是64位为什么是esi寄存器而不是rsi寄存器)

0x402400是一个字符串的首地址,在gdb下输入x/s 0x402400显示这个地址处存的东西,这个字符串是”Border relations with Canada have never been better.”

5.x/s 0x402400

6.test eax,eax 基本上和and eax,eax是一样的,但是test不会改变eax的结果,只是改变flag寄存器的状态。(flag寄存器又是什么?就是进位标志、零标志、溢出标志)当eax为0的时候,令zf=0.

7.je 是一个跳转指令,看zf标志(零标志)

8.返回看eax为0的条件,实际上就是两个字符相等返回0,不相等返回1.

2.disass 段2

前面rax也就是输入的字符开头地址传给rdi作为第一个参数,后面把

保存调用者信息,开辟栈帧,把rsp作为指针传给函数,进入read siz函数中

读进来六个数,rsp rsp +0x4 rsp+0x14 rsp +0x10 rsp+0xc rsp+0x8

10.在phase2下断点,运行,随意输入值。

aaaa 输入以后查看rax是什么值,可以vmmap看下 这个地址是bss段,输入存储在了bss段

六个及六个以上也行。

输入以后step进入函数,可以看见有读六个数函数。

下个断电待会step进去看看

read里面有个scanf函数 可以看到要求的是6个整数。

C 库函数 int sscanf(const char *str, const char *format, …) 从字符串读取格式化输入,如果成功,该函数返回成功匹配和赋值的个数。

jg是什么意思?

Jump if greater。

JG 前>后

这个read number的作用就是看你是不是写了6及6个以上的整数进来,并且将它们放置在栈上。

然后重新运行 ,我们看看栈空间变成什么样了。

dword ptr【rsp】是四个字节 --> 00000001

输入1 2 3 4 5 6,直接next 过了cmp。

发现没有引发任何一个炸弹,无论是数量炸弹还是第一个参数必须为1的炸弹。

disass直接分析汇编。

栈中

csapp -bomblab记录1-5

这个就是1 2 3 4 5 6 四个字节一个参数

右边是低地址,左边是高地址。 %d是有符号整型数,也就是int 四个字节。

接下来跳转到+52去了

lea指令可以用来将一个内存地址直接赋给目的操作数

一开始第二个参数的地址赋值给rbx;

然后设置栈底rbp;next看下rbp在哪了,在f8这里。

第一次:跳转到+27,rbx=第二个参数地址,dword ptr[rbx-0x4] 第一个参数地址中的数据,赋值给eax;

intel汇编和at&t汇编有些区别

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I1U4y6h9-1631186649285)(https://i.imgur.com/zgp14CG.png)]
eax里面是1,下一个add指令,相加然后赋值给eax,赋值给左边的。

rbx=第二个参数,与这个第一个参数的两倍进行对比。

je,如果相等则跳转,跳到+41这里,把rbx的地址值加了4,再对比rbx和rbp,这个是啥意思呢,就是看rbx到没到rbp这个地方,你看它下面有个jne,意思是不相等则跳转,你看他跳到+27了,这个进入循环了。

第二轮:

把第二轮讲了才好看出规律;

rbx=第三个参数,eax=2+2(rbx-0x4,就是第二个参数=2)=4 ,和第三个数不相等了,直接爆炸了。

1 2 4 8 16 32

我们进行一个思路的梳理。

首先第一个参数必须得是1,每次循环都会将后一个参数和前一个参数的两倍进行对比,不相等就会爆炸。1 2 4 8 16 32

第一轮:rbx=第二个参数,第二个参数去比两倍的前一个参数,这个结束+4;

3+4

4+4

5+4

6+4

当我们是第六个参数的时候,下一个+4就是rbp的位置了。

3 disass 段3

给5分钟看下题目汇编,思考一下

1.可以发现,在进入每个段的时候,输入的数据的首地址都会赋值给rdi寄存器,作为第一个参数。

2.随便输入一个aaaa,查看第一个进入的函数,这个函数和段2那个函数是一样的,会返回参数个数。有两个%d 意味着得输入两个整型数

3.重来输入1 2,记得要在段三加断点。

4.发现确实躲过了第一个炸弹点

JA(jump above)大于则转移到目标指令执行。 第一个参数要小于7,+8是这个1所在的地方。取四个字节。

后面看这个数要和311相比 那就填上311

回过头来再看地址跳转,x/20gx 0x402470 发现这个就是个switch表,rax输入的不同,后面eax的值也不一样,刚才我们输入的1,对应的值就是311,这组有多组解。

4.disass 段4

继续输入aaaa 动态调试。在段4下断点

进入段四函数,发现又有固定参数数目的限制吗,还是得是整数。

jbe:即当低于或等于时转移 等于14或者小于14

func4的功能直接用ida查看。我们需要它返回0

a3=0xe=14

a2=0

a1=第一个参数

解析这段反汇编出来的伪代码,v3=14-0)/2+0=7

a1是我们输入的第一个参数,我们可以看到一个最清晰的路线,就是令a1=7,不用进入迭代,直接返回result( 0 );

5.disass 段5

看段5的反汇编,加入了canary。

开头的fs:0x28还有后面的xor rax和fs:0x28就是标志。

介绍一下canary。

放在栈的rsp+0x18的位置。

调用string_length,返回值必须是6,不然炸弹爆炸。这个string就有点像输入字符换了,猜它应该是计算字符串的长度的。进去查看,确实是查看字符的个数的,条件是+16这个,前面的add rdx,1就是不停后移,直到输入的落空。

让他们输入五个a,试试看rax是多少,一步一步跟着。

jmp无条件跳转,直接给eax赋值为0;

再无条件跳转到41

+41到+74是一个循环,得循环6次

字符与数字做与运算是字符的ascii码与数字做与运算

重新输入abcdef,查看循环中的变化过程。

一开始,rax是0(因为112初始化了),rdx是rdi这个参数传进来的,代表字符串的起始位置。

BYTE PTR []取一个字节,

csapp -bomblab记录1-5

应该是把a放入了ecx,是的,0x61

第二句是把0x61(刚好八位)放入栈开头的最低位

x/20gx 0x7fffffffdef0来查看内存(rsp指向的),发现确实61在最后一个字节。

下一句把61赋值给了rdx

再下一句and 0x61,0xf edx变成了1.

0 0 0 0| 1 1 1 1

6 | 0 0 0 1

然后用这个and出来的值取加0x4024b0这个地址,根据edx的偏移值取对应的字符放进edx。再把这个字符放到栈上。

这个rax会从0到5,也就是会放到rsp+0x10] 到[rsp+0x15],我们看被拿出的是a,也就是edx为1的时候,拿出的是a,2应该是接下去的值。

和0xf与的特点是什么,

00001111

前四位是多少都没用,都会变成0,后四位最小为1最大为f,取决于你输入的值是多少,意思就是,你的最后四位是1,那与的结果就是1,是2.结果就是二,是f结果就是f。

取完6个数,依次被放在栈上,可以看下最后栈的布局。

f00,这一串就是最后的结果。,可以看到低位到高位依次是转换出来的结果。(有点像密码)

跳出循环,看到有个string对比函数,和之前的一样,如果和0x40245e里面的字符串不匹配就炸弹爆炸。

一个参数是rsp+0x10也就是我们转换出来的放置的地址,另外一个就是内存中本来有的字符串。

x/s 0x40245e 查看字符串的值。

发现是flyers。

将这几个字符依次和刚才的做对比,发现f在标号为9的地方。

依次是9 f e 5 6 7 然后去找ascii码后四位是这几个的字符输入就能成功。

上一篇:汇编语言中的一些问题


下一篇:SLB负载均衡实践-ECS七天训练营DAY03