computing 101
hello hackers
writing output
|
|
chaining syscalls
同时设置两个系统调用,要做的就是分成两部分去设置就行
|
|
assemble crash course
调试:由于环境中是用python进行的模拟,因此无法gdb调试,但如果我们在汇编中加入int 3,那么模拟器会打印出现在的寄存器和内存情况
重复多的我直接写汇编,或者直接跳过了(
4 linear-equatation-registers
|
|
5 interger-division
寄存器进行整除操作
x86除法指令的特殊性
div
指令用于128位被除数 ÷ 64位除数:
-
被除数:
rdx:rax
(128位,高64位在rdx,低64位在rax) -
除数:指定的寄存器
-
结果:
-
rax
= 商(quotient) -
rdx
= 余数(remainder)
-
|
|
6 modulo-operation
将mod的余数放入rax,前面除法的时候高64bit放了rdx,低64bit放了rax
|
|
7 set upper byte
x86的寄存器结构图,x86的好处在于通过名字我们可以轻松控制寄存器中不同长度的数字从64bit到32bit到16bit再到8bit
mov ah,0x42
8 efficient modulo
x % y
,如果y为$2^n$那么我们就可以得到x=n
要求
-
rax = rdi % 256
-
rbx = rsi % 65536
|
|
9 byte-extraction
对二进制进行操作,我们需要用到and or xor not
等逻辑操作
shl
和shr
,shift once to the left和shift once to the right
shl reg1,reg2
(reg2可以替换成地址)
|
|
|
|
10 bitwise and
|
|
11 check even
|
|
可以用xor 1来进行反转判断
|
|
12 memory read-14 memory increment
mov rax,[0x404000]
mov [0x404000],rax
关于解析指针所在位置字节
-
byte ptr
- 8位 -
word ptr
- 16位 -
dword ptr
- 32位 -
qword ptr
- 64位
我们在移动数据到指定寄存器或地址的时候要注意不会清除高位字节
mov al, [0x404000]
15 memory size access
|
|
16 little-endian-write
注意,不能直接将大常数移动到内存地址,但可以通过寄存器间接传递
|
|
17 memory-sum
通过将地址or寄存器指向地址+offset可以解析到不同的值,这题需要两个qword
而64位寄存器本身存储就是qword,因此直接用偏移
|
|
18 stack-subtraction
|
|
19 swap-stack-value
|
|
20 average-stack-values
|
|
21 absolute jump
There are two major ways to manipulate control flow:
-
Through a jump
-
Through a call
-
相对跳转:
jmp +0x10
或jmp -0x5
(相对于当前指令) -
绝对跳转:通过寄存器间接跳转,如
jmp rax
-
间接跳转:
jmp [rax]
(跳转到 rax 指向的内存地址中的值)
|
|
22 relative jump
使用nop进行填充
并使用段落进行repeat
|
|
23 jump-trampoline
|
|
24 conditional-jump
利用jne
和je
指令(jmp if not equal;和jmp if euqal)
|
|
end分支来防止执行多余指令
25 indirect jump
题目会给出随机测试数据,根据测试数据来进行对应跳转(case)
|
|
26 average-loop
用rcx作为计数器,rsi作为除数,div的时候为了防止出现rdx干扰要置0
|
|
27 count no-zero
|
|
28 string-lower
|
|
-
call
pushes0x102a
, the address of the next instruction, onto the stack. -
call
jumps to0x400000
, the value stored inrax
.
ret
pops the top value off of the stack and jumps to it.
|
|
29 most-common-byte
最终挑战
rbp确认函数的栈基地址
我们要完成
|
|
限制:
- counting_list放在栈上
- You must restore the stack like in a normal function
- 不能修改放在src_addr的数据
|
|
gdb
level 4
程序在main+626处进行比较
而我们
在这之前取出的$rbp-0x18是比较的值,我们打好断点在输入前然后取出进行输入即可
- 随机值存储:
[rbp-0x18]
- 用户输入存储:
[rbp-0x10]
- 循环计数器:
[rbp-0x1c]
(0-3)
level5
shit题
我们可能要用到这些文档
我们把challenge文件dump下来,IDA分析
根据题目的提示,我们需要将断点下载合适的地方,并设置需要的值后继续操作
level8
如果+12的地方执行了的话,那么rax=0,从而之后会触发segment fault
因此需要跳过
|
|
webserver
使用方法
exit
我们运行的时候会给出提示
可以根据要求创建可执行文件,也可以直接使用pwntools
|
|
socket
简单理解的话socket就是一个为了让用户可以与内核层进行交互的中间层,将套接字sock得以迁入文件系统,用户在空间中使用文件句柄socket_fd
来操作内核sock,实现网络传输功能
其结构为socket(AF_INET, SOCK_STREAM, 0)
我们要在/usr/include
下找到对应文件中常量的值
|
|
typeSOCK_STREAM
定义为TCP
|
|
bind
创建好socket层之后,下一步通过bind
系统调用去将socket绑定到特定的IP地址和端口,我们需要提供
|
|
初始代码
|
|
发现绑定的端口出现了错误
修改
mov word ptr [rsp+2],0x901f
为mov word ptr [rsp+2],0x5000
即可(网络字节序为大端)
Listen
|
|
sockfd为socket文件句柄,backlog为等待连接队列的最大长度
|
|
其他部分不变,添加listen
accept
|
|
grep -r "__NR_accept" /usr/include/
-43
添加
|
|
static response
本来尝试加入了
|
|
结果发现解析失败了??
不允许mov qword ptr 8字节数据的用法
于是修改,注意还要加入read(fd,buffer,len)
|
|
dynamic response
会稍微复杂一些
|
|
可迭代的(Iterative)GET Server
添加循环处理GET逻辑
|
|
concurrent GET Server
在原本的基础上使用fork子进程来实现执行GET操作,批注写在代码里了
将前一段的代码进行分段修改后,如果成功fork了进程则进入进行操作,否则直接server进行close
|
|
检测的时候分为对parent process和child process的检测(卧槽了这挑战检测的代码是怎么用python写的,好牛逼)
concurrent POST Server
but this time instead of reading from that file, you will instead write to it with the incoming POST data. In order to do so, you must determine the length of the incoming POST data.
emm,原来POST的数据长度一定要写入请求是这个原因
首次测试,可以正常读入数据,但是传给open的句柄出错了
|
|
Web Server
为何一定要用汇编写,我思考了很久这个问题,得出的结果是牛魔的pwncollege想累死我,处理成两个分支,再加上了一些补充的点,这里的汇编全都是用的rsp缓冲区,不涉及栈空间
|
|
emmm,虽然成功了但是为何test都是?
这也是最后有点困惑的地方