首页 > 其他分享 >二进制菜鸟的杂谈-调试与pwn

二进制菜鸟的杂谈-调试与pwn

时间:2024-10-24 21:48:37浏览次数:3  
标签:函数 esp 菜鸟 chunk 杂谈 mov ebp IO pwn

在这里插入图片描述

反调试技术

NLFlagGlobal PEB的偏移 当被调试的时候会有标志位:

FLG_HEAP_ENABLE_TAIL-CHECK()
FLG_HEAP_ENABLE_FREE_CHECK()
FLG_HEAP_VALIDATE_PARAMETERS()
一般为:
mov eax,fs:[30h]
mov al,[eax+68h]
mov al,70h
cmp al,70h
其实是因为 isDebugger被检测到了 进而影响到了 NTFlagGlobal 从而进行了调试堆的创建
因此三种方法:
手动改注册表的里的flag的值
od中插件
windbg中禁用调试堆
当IsDebugged标志被为TRUE时,NtGlobalFLag也会得到一个0x70的值,消除即可 dump

Heap flags

Heap flags 含有两个标志跟ntflagglobal一起初始化
flags和forceflags
flags的正常值默认为HEAP_GROWABLE(2)
forceflags默认为0
32位程序如果对flags设为2 且对forceflag设为0 但没对subsystem进行检测 就是为了隐藏调试
获取堆的位置:GetProgressHeap()->ntdll.dll:RtlGetprocessHeaps()中的第一个数组返回

x86:
mov eax,fs:[30h]
mov eax,[eax+18h]
x64:
push 60h
pop rsi
gs:lodsq
mov eax,[rax+30]

The Heap

堆在初始化的时候会检测heap flags
分堆指针已知和堆指针未知:
已知就直接检查堆的内容 分32位和64位
未知就利用kernal32中的Heapwalk() 或 ntdll的Rtlwalkheap

isDebuggerPresent

存在调试器的时候 isDebuggerPresent 会返回非零值
检测代码:
call IsDebuggerPresent
test al,al
jne being_debugged
绕过:把bing_debugged的值设为0

CheckRemoteDebuggerPresent

CheckRemotDebuggerPresent()用于检测进程是否处于被调试的状态
是:0xfffffff
绕过:修改isDebuggerPresent为false 然后不触发being_debugged:

NtQueryInformationProcess

CheckRemoteDebuggerPresent()内部是调用的ntdll中的NtQueryInformationProcess进行的
因此对CheckRemoteDebuggerPresent绕过可以通过修改NtQueryInformationProcess
原理
CheckRemoteDebuggerPresent->NtQueryInformationProcess->EPROCESS->Debugport字段 返回0xffffffff

ZwSetInformationThread

ZwSetInformationThread 等同于 NtSetInformationThread,通过为线程设置 ThreadHideFromDebugger,可以禁止线程产生调试事件注意到该处
绕过ZwSetInformationThread 函数的第 2 个参数为 ThreadHideFromDebugger,其值为 0x11。调试执行到该函数时,若发现第 2 个参数值为 0x11,跳过或者将 0x11 修改为其他值即可

脱壳技术 压缩壳: esp定律 一步到位 内存镜像

pwn部分

函数调用

先来了解寄存器
共32位 分低16位和高16位
低16位可以分为独立的两个八位的寄存器 AL AH
EIP寄存器是存放下一条执行的指令
ESP始终指向栈顶 随着出栈或入栈 esp会变化
当esp和ebp相等是不是就意味着栈空了呢?

EBP是栈底基质 ebp+0xh。。

然后是如何调用的呢?
先说caller函数
caller函数的栈从上到下是:
callee的返回地址
callee的参数
callee 的ebp
caller的返回地址 要放到eip里保存
实参
在进入被调函数的时候 先把caller的ebp入栈作为基地址
也就是push ebp
随后将esp和ebp归一
也就是
push ebp
mov esp ebp
随后利用esp来开辟空间
ebp - 是向下 因为是高地址向低地址减小
高地址
|
|
|
v
低地址
对应的

参数
返回地址
向上是主调函数的部分
ebp 往下是被调用的函数的部分 :参数 返回地址
|
|
|
V
esp

注意 一句话:每个函数都有自己对应的栈

在调用结束后
mov ebp esp
将ebp和esp指向同一个地方 随后释放局部变量

总结:

首先看主调函数:
主调函数在初始化的时候 先按照参数调用约定依次入栈:从右到左 随后 将EIP入栈保存主调函数的返回地址:
随后在主调函数进入被调函数的时候
先把主调函数的ebp压入栈中(注:这里的ebp里的内容是指向主调函数的栈底)
push $ebp
mov $esp $ebp
随后 将被调函数的参数按照调用约定入栈
后改变esp的值来开辟空间
ebp+ 向上 是主调函数的内容
ebp- 向下 是被调函数的内容
当结束调用的时候
会mov esp ebp
让esp指向ebp 开始释放局部变量
随后 ebp里的内容弹出到eip:ebp里存放的是主调函数的栈底的地址!)所以eip会直接执行到主调函数的栈底 然后让esp保持不变 这里的esp指向的是主调函数压栈后的ebp的位置 也就是 主调函数的栈顶!
首先主调函数要进行函数调用 这个时候把即将执行的下一条指令压入到栈中 之后把自己的ebp里的值 也就是saved ebp压入栈中
push eip
push ebp
随后
mov ebp esp
然后
sub esp xx进行扩展
这是被调函数进行创建的过程
在被调用函数完成之后
将esp指向现在的ebp
mov esp ebp
随后开始释放被调函数的空间
直到esp和ebp相等 这个时候把ebp里的saved ebp 传递给eip
让eip回到主调函数的基地址
然后再进行
mov esp ebp
push eip
push ebp//saved ebp
mov ebp esp
sub esp
mov esp ebp
pop ebp
pop eip
mov esp ebp

注意事项

栈溢出 ret2text

常用命令:
checksec 没开ASLR
然后
gdb
dissamble 查看汇编
b 设置断点
X 打印值
x/20
strat 开始
ni 步入
si 步进
finish 跳出步进
i info 信息

比如有这样一个例子

int vu()
{
    printf("1231");
    get(s)//s14位
    return 0;
}

然后又system函数的地址
假设为 system_addr
然后栈的结构应该是

eip
saved ebp
s[13]
s[12]
s[11]
...
s[0]

因此只要覆盖掉 这些内容
让弹出的eip的值给后门函数就好:
payload=a*14+bbbb(覆盖掉saved ebp)+backdoor()

ROP

rop是个很搞的东西哦~
最基础的rop是:

ret2text:这个不用多说 就是返回到一个system调用函数的地址就好

一般是通过确定可以溢出的元素的地址来判断大小

ret2shellcode:

这个就不太一样了
需要在没开启NX保护的情况下进行自己写shellcode
利用python的库 asm(shellcraft.sh())

ret2syscall

这个才是真正意义上的动用了gadget来完成getshell
在系统调用中以int 0x80为例子
首先要把调用号放到eax里
也就是 放到栈顶
pop eax ;ret
然后传入/bin/sh到ebx里
然后把参数 0和0传入到ecx和edx里 最后跳转到系统调用int0x80的地址上
当执行int0x80系统调用的时候 会触发接下来的寄存器的东西
首先 int0x80去eax找了0xb 随后读取 /bin/sh 0 0
构造出execve(“/bin/sh”,0,0)
最后getshell
也算是比较经典的gadget了

ret2libc

这是控制程序执行中的libc的函数了 一般是执行binsh
注意在调用函数的时候要给函数一个虚假的返回地址哦
deadbeef

canrry 用格式化字符串泄露
NX 组件ROP
Relro aslr 泄露got表 挟持got表
PIE stack pivoting

heap

brk会重新生成一个堆不与内存合并
而mmpa会生成一个与内存合并的堆
在申请堆的时候
操作系统嫌麻烦就索性给你一个比较大的堆空间
叫arena
后续申请的时候从arena里扣
当arena不足的时候
会brk方式来增加空间 也可以通过brk的方式减少空间

堆的结构:

malloc_chunk
在程序的执行过程中用malloc申请的内存叫chunk
chunk的结构体是:

struct malloc_chunk{
INTERNAL_SIZE_T prev_size;前一个堆的大小
INTERNAL_SIZE_T size;这一个堆的大小

struct malloc_chunk* fd;下一个堆向高地址
struct malloc_chunk* bk;上一个堆
如果空闲↑
如果空闲且大↓
struct malloc_chunk* fd_nextsize; 
struct malloc_chunk* bk_nextsize;
}

实际上:
prev_size只有在空闲的时候会被使用
不空闲为前一个chunk的user区域

—prev_size------
--------size-N-M-P
p标志位表示前一个chunk是否被使用 是为1
64位的块大小是0x10的倍数
然后size为是3为单位的所以最后空出来三个标志位
bin chunk被释放后放入bin中
采取LIFO的策略 类似栈
根据chunk的大小和空闲情况分为:
fast bins
small bins
large bins
unsorted bin

TOP chunk

程序在第一次malloc的时候 heap被分为两半
一半给user
另一半叫top chunk 就是处于最高位的chunk
当所有的 bin 都无法满足用户请求的大小时,如果其大小不小于指定的大小,就进行分配,并将剩下的部分作为新的 top chunk

否则,就对 heap 进行扩展后再进行分配。在 main arena 中通过 sbrk 扩展 heap,而在 thread arena 中通过 mmap 分配新的 heap。
特点topchunk的p位始终为1
否则会被前面的chunk合并

last remainder

当arena被分配但是大小不合适的时候
会裁剪掉
剩下到叫last remainder (可以叫碎片吗?
堆溢出是利用释放的时候写回内存的操作来进行的

UAF

use after free
释放后没有被设置为 NULL 的内存指针为 dangling pointer
步骤
申请一个chunk
删除这个chunk
在申请这个chunk
在删除这个chunk
随后申请一个新的chunk
这个时候
第一个chunk未被删除的指针会被利用

off_BYONE

严格来说 off-by-one 漏洞是一种特殊的溢出漏洞,off-by-one 指程序向缓冲区中写入时,写入的字节数超过了这个缓冲区本身所申请的字节数并且只越界了一个字节。off-by-one的产生往往和字符串操作有关。如strlen计算长度时,不会计算最后的“0字节”(\x00)。循环读入时,<写成了<=。
利用思路
溢出字节为可控制任意字节:
通过修改下一个堆块的size造成块结构之间出现重叠,从而泄露其他块数据,或是覆盖其他块数据。也可使用 NULL 字节溢出的方法
溢出字节为 NULL 字节:
在 size 为 0x100 的时候,溢出 NULL 字节可以使得 prev_in_use 位被清,这样前块会被认为是 free 块。

IO_FILE

在标准的I/O库中,在一个程序开始时一般有三个流被自动创建,分别是:stderr,stdin,stdout(分别对应异常检测,标准输入和标准输出)它们都会有一个对应的FILE结构体,而这些FILE结构体通过结构体中的:*struct _IO_FILE _chain;进行连接,其表头是_IO_list_all

struct _IO_FILE_plus
{
_IO_FILE file;
const struct _IO_jump_t *vtable;
};

可以看见这个结构体里面有两个成员,一个_IO_FILE的结构体,一个_IO_jump_类型的指针,而这个指针vtable非常重要,它就是所谓的虚表。虚函数其实就是为后面对于类的继承提供一个函数的接口,,所以在每一个有虚函数参与的类中都会生成对应的一个虚表,而这个虚表中存放的就是相关操作函数的指针。
IO_puts的主要功能是调用一个IO_sputn 函数,而这个IO_sputn 函数是一个宏定义,它指向 IO_new_file_xsputn(在前面的_IO_jump_t结构体中有提到)的函数调用,所以IO_puts函数最终是要调用 IO_new_file_xsputn这个函数。
IO_new_file_xsputn:

首先计算缓冲区还有多少空间可以进行写入(通过一个: f->IO_write_end - f->_IO_write_ptr 的指针减法来计算),然后将需要写入的数据写入到缓冲区中,之后在检查一下需要写入的数据是不是已经完全写入,如果有剩余就说明缓冲区空间不足或者缓冲区还没有建立,这时通过if判断就需要调用 _IO_OVERFLOW 来进行缓冲区的建立和刷新,而这个 _IO_OVERFLOW 跟前面的 IO_sputn一样是个宏定义,它指向了虚表中的 _IO_overflow_t函数

标签:函数,esp,菜鸟,chunk,杂谈,mov,ebp,IO,pwn
From: https://blog.csdn.net/baidu_33751906/article/details/143220624

相关文章

  • pwntool
    基本使用首先需要frompwnimport*把pwntools导入进来,它同时会把一些系统库给导入进来本地打的话p=process('./filename'),远程的话p=remote('192.168.1.103',10001)p.close()关闭发送payloadp.send(payload)发送payloadp.sendline(payload)发送payload,并进行......
  • pwndbg
    dbg内容runrun:跑一遍 start:运行到程序认为的入口点停止ccontinue,执行到断点为止ni单步si步入iir:查看寄存器ib:查看断点disassembledisassemble$rip:反汇编rip附近汇编disassemblemain:反汇编mainbb*0x000055555555527a:在0x000055555555527a处下断点disable......
  • ctfshow-pwn-前置基础
    pwn13按照题目提示的信息,用gcc命令生成可执行文件,再运行即可得到flagpwn14题目提示:阅读以下源码,给定key为”CTFshow”,编译运行即可获得flag,那么我们直接看源代码开始有一个文件是否存在的检查,如果当前目录下不存在名为"key"的文件就会报错接下去就是通过循环将fp的值(也就......
  • Re:从零开始的pwn学习(栈溢出篇)
    写在前面:本文旨在帮助刚接触pwn题的小伙伴少走一些弯路,快速上手pwn题,内容较为基础,大佬轻喷。本文默认读者明白最基础的汇编指令的含义,并且已经配置好linux64位环境,明白基础的Linux指令。栈,栈帧与函数调用我们知道,在数据结构中,栈是一种先进后出的数据结构。而在操作系统中,一般使......
  • 2024版最新148款CTF工具整理大全(附下载安装包)含基础环境、Web 安全、加密解密、密码爆
    经常会有大学生粉丝朋友私信小强,想通过打CTF比赛镀金,作为进入一线互联网大厂的门票。但是在CTF做题很多的时候都会用到工具,所以在全网苦寻CTF比赛工具安装包!关于我有不少阅读过我文章的伙伴都知道,我曾就职于某大厂安全联合实验室。从事网络安全行业已经好几年,积累了丰富......
  • ctfshow-pwn-前置基础
    pwn5运行文件,所以我们直接下载文件在虚拟机里运行即可(命令./......)原理:用IDA打开elf,里面只有一个start函数,IDA反汇编的结果是将dword_80490E8指向的内容写入后退出,进入dword_80490E8查看写入的东西对16进制"R"一下转化为字符,得到下面的字符串,因为是小端序,所以字符串的正确形......
  • 【笔记】CSE 365 - Fall 2024之Talking Web(pwn.college)
    【入门笔记】CSE365-Fall2024之TalkingWeb(pwn.college)先看完level1 使用curl发送HTTP请求curl是一个用于在命令行中与网络进行交互的工具,支持多种协议,如HTTP、HTTPS、FTP等。它可以用来发送GET、POST等请求,下载文件,上传数据,甚至处理API调用。由于其灵活性和广......
  • ctfshow-pwn-Test_your_nc(0-4)
    pwn0签到题,用ssh连接,输入密码,会出现一大堆动画,输入pwd,显示了当前路径,我们直接切到根目录,发现了ctfshow_flag这个文件,直接cat读取得到flag。pwn1签到题,nc连接上直接出答案。pwn2用nc连接上之后,看题目提示输入cat/ctfshow_flag,得到flag。pwn3用nc连接上之后,发现有几个选......
  • 【笔记】CSE 365 - Fall 2024之Linux Luminarium(pwn.college)
    【笔记】CSE365-Fall2024之LinuxLuminarium(pwn.college)HelloHackers本模块将教你与命令行交互的基础知识!命令行允许您执行命令。当您启动终端时,它将执行命令行“shell”,如下所示:hacker@dojo:~$这称为“prompt”,它会提示您输入命令。让我们来看看这里发生了什么:提示......
  • 程序员必看!从菜鸟到专家你要这么做,8年互联网老兵爆肝总结
    “互联网行业工作8年多,在国内Top互联网大厂B(ytedance)AT中的两家待过。喜欢研究计算机基础原理,有移动端全栈(包括Android&iOS&鸿蒙等)开发经验,对逆向和网络安全有一定经验。”不管是在校大学生,还是初入职场的菜鸟,抑或是在互联网行业打拼多年的老码农,相信这篇文章都能对你有所......