Shellcode

整理下Shellcode相关

先看下网上的定义:

    Shellcode实际是一段代码(也可以是填充数据),是用来发送到服务器利用特定漏洞的代码,一般可以获取权限。另外,Shellcode一般是作为数据发送给受攻击服务器的。Shellcode是溢出程序和蠕虫病毒的核心,提到它自然就会和漏洞联想在一起,毕竟Shellcode只对没有打补丁的主机有用武之地。网络上数以万计带着漏洞顽强运行着的服务器给hackerVxer丰盛的晚餐。漏洞利用中最关键的是Shellcode的编写。由于漏洞发现者在漏洞发现之初并不会给出完整Shellcode,因此掌握Shellcode编写技术就显得尤为重要。

 

接下来分析下原理:

首先如果我们用C++定义一个函数,反汇编通常会这样:

push ebp

mov ebp ,esp

...

...

...

mov esp,ebp

pop ebp

 

    首先push ebp存储ebp,然后用寄存器ebp存储espesp是当前堆栈指针。

如果我们此时在函数里定义了相关局部变量,那么esp就会做减法,比如之前是A,那么esp现在就是A-Size,这个Size的大小就是局部变量大小,然后区间[A-sizeA]就是用来存储新变量的。当函数退出的时候,就执行相反操作,还原esp,然后再还原ebp,之后会继续从栈里面取出来一个值,直接通过这个值跳转到函数退出的位置。

 

1.定义一个空的main函数

 

对应反汇编如下


2.继续定义一个简单函数:

 

反汇编代码如下:

 

3.定义变量的函数

 

反汇编代码:

 

    基本是满足上面说的那个的,但是仔细观察会发现几个问题,首先例子2没有mov esp,ebp是因为本身esp没有变化,也就是没有在函数里面开变量,然后是 pop ebp之后又多出来一个ret但是没有pop aa ,jump aa。这个地方我是这么理解的:

    return   等价于  pop ebp , ret

    ret 等价于 pop A ,jump A

    这样就能理解了。同时还要注意一点就是在调用MessageBox的时候(其他也是)我们负责push了四个参数,然后等函数调用完成之后没有进行pop这四个参数,原因是,MessageBox函数里面已经帮我们处理完了。

  而shellcode的原理就是通过给内存传递大于本来能存储的内容,导致在函数里面存储变量的站地址[esp-A ,A]之间的内容过多,使得栈被破坏,首先破坏的是栈里备份的ebp,其次就是函数返回地址,也就是我们可以故意通过溢出来修改栈地址,至于修改内容,就是直接写机器码。把相关机器码拷贝过去,但是注意一点就是要注意函数的反汇编结构,否则很容易导致函数无法退出等崩溃。

例如下面的例子:

 

    这样的崩溃其实就是导致Fun里面的堆栈被破坏,使得Fun函数退出的时候准备从栈里找回去的地址,但是该地址被破坏,导致无法预知的异常。

  至于机器码:可以通过vs写好功能C++代码之后,运行起来,然后进行反汇编,反汇编可以找每一行汇编的内存地址,然后再根据地址在vs上直接定位到内存信息就可以了,大体是这样:


  为了方便理解shellcode,我写了一个测试例子:调用一个函数,同时跳转到另外两个函数,最后在跳转回来,这个例子刚写的时候崩溃了很多次,原因是我注释里面加********的那一行。

 

#include <string>
#include <windows.h>
using namespace std;
 
DWORD dwGetHomeAddress ;// 跳回main函数的地址  
typedef VOID (*TYPEFUN)();
TYPEFUN m_pF0;  //函数0地址
TYPEFUN m_pF1;  //函数1地址
TYPEFUN m_pF2;  //函数2地址
 
VOID Func0(){
MessageBox(NULL ,L"f0" ,L"tit" ,MB_OK);
DWORD dwNextCmdAddress;//接下来跳转地址
__asm{
mov esp,ebp
//pop ebp ***
pop dwNextCmdAddress
push dwGetHomeAddress
ret
}
}
 
VOID Func1(){
MessageBox(NULL ,L"f1" ,L"tit" ,MB_OK);
DWORD dwNextCmdAddress;//接下来跳转地址
__asm{
  mov esp,ebp
  //pop ebp ***
  pop dwNextCmdAddress
  push m_pF0
  ret
}
}
VOID Func2(){
MessageBox(NULL ,L"f2" ,L"tit" ,MB_OK);
DWORD dwNowEbp ,dwNowEsp;
DWORD dwStackEbp ,dwStackEsp;
__asm{
    mov dwNowEbp ,ebp
mov dwNowEsp ,esp
                   //临时存储下
 
mov esp ,ebp       //修改函数退出跳转地址为f1地址,同时把回家地址(跳转到main)存在dwGetHomeAddress里
pop dwStackEbp
pop dwGetHomeAddress
push m_pF1
push dwStackEbp
                  //恢复寄存器的值
mov ebp,dwNowEbp
mov esp,dwNowEsp
}
}
int _tmain(int argc, _TCHAR* argv[]){
m_pF0 = Func0;
m_pF1 = Func1;
m_pF2 = Func2;
Func2();
MessageBox(NULL ,L"main" ,L"tit" ,MB_OK);
return 0;
}
 

OK 就简单整理这些,之后在上相关的应用吧。

### Shellcode 定义 Shellcode 是一段精心编写的机器码指令序列,通常用于利用软件中的漏洞来执行任意代码。这段代码可以实现各种功能,最常见的是启动一个新的 shell 进程[^1]。 ### 工作原理 当存在可被利用的安全漏洞时,攻击者可以通过特定方式将 Shellcode 注入到目标程序的内存空间中,并通过控制程序流程使 CPU 执行这些注入的指令。具体过程如下: - **缓冲区溢出**:这是最常见的漏洞之一,允许攻击者覆盖函数返回地址或其他重要数据结构。 - **堆栈调整**:为了确保 Shellcode 能够正确执行,可能需要对寄存器状态或堆栈指针进行适当设置。 - **跳转至 Shellcode**:一旦成功修改了程序流,CPU 将转向并开始执行嵌入的目标机器指令。 ```assembly ; 假设这是一个简单的 x86 架构下的 Linux 反弹 Shell 的汇编代码片段 global _start section .text _start: ; 创建 socket xor eax, eax mov al, 0x66 ; syscall number for socketcall() push byte +0x1 ; SYS_SOCKET (first argument to socketcall()) pop ebx ; ... ``` ### 应用场景 尽管 Shellcode 主要关联于恶意活动,但在合法用途方面也有着重要作用: - **安全测试**:渗透测试人员会使用它来进行白盒/黑盒测试,评估系统的脆弱性和安全性。 - **防御机制开发**:了解如何构建和部署 Shellcode 对于创建更有效的防护措施至关重要。 - **教育与培训**:作为教学材料帮助学生掌握低级编程技巧以及操作系统内部运作细节[^2]。 ### 防范措施 鉴于 Shellcode 存在显著的安全隐患,在实际应用过程中应当采取必要的预防策略,比如启用 DEP(数据执行保护)、ASLR(地址空间布局随机化)等功能以增加攻击难度;定期更新补丁修复已知漏洞;实施严格的输入验证防止非法字符进入应用程序等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值