生成

首先生成一个测试的msf shellcode

msfvenom -p windows/x64/exec CMD=calc.exe -f python

把其中的shellcode复制出来留待待会使用

原理

大部分脚本语言加载 shellcode 其实都是通过 cffi 去调用操作系统的api,其实并没有太多的技巧在里面,明白了原理,只需要查一下对应的脚本语言怎么调用 c 即可。

那么我们只需要明白 c 通常是怎么加载 shellcode 的即可一通百通。

那么 c 是怎么加载 shellcode 呢,我们直接从汇编开始探究。

shellcode 这个东西我们明白是一串可执行的二进制(一般可执行文件的拥有可执行权限的section为.text),那么我们先通过其他的手段开辟一片拥有可读可写可执行权限的区域放入我们的 shellcode,然后跳转到 shellcode 首地址去执行就行了,汇编里面改变eip(即当前指令的下一条即将运行指令的虚拟地址)的方法有不少,最简单的就是直接 jmp 过去了。也就是写成伪码大概意思就是(动态申请内存就不写了)

lea eax, shellcode;
jmp eax;

那么我们用 c 怎么表示呢?我这里也写一段伪码(因为本文的重点并不是在于 c 代码的编写)

那么按照刚才的思路,先申请一块可执行的内存,放入 shellcode 然后跳转过去执行即可。

// shellcode
unsigned char shellcode[] =
"\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9"
"\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08"
"\x8b\x7e\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1"
...;
// 定义一个函数类型
typedef void (__stdcall *CODE) ();
// 申请内存
PVOID p = NULL;
p = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
// 把shellcode放入内存
memcpy(p, shellcode, sizeof(shellcode)); CODE code =(CODE)p; code();

我并没有写出一个可用的 c 加载 shellcode,只是旨在点出一下流程,然后引出后面的 python 加载 shellcode,上面我们先申请了一块带有可读可写可执行权限的内存,然后把 shellcode 放进去,然后我们强转为一个函数类型指针,最后调用这个函数,达到了我们的目的。

Python实现

前面我说过,大部分脚本语言加载 shellcode 都是调用的c的ffi,那么我们直接按照之前的思路来就行了。下面我直接贴代码

import ctypes

shellcode =  b""
shellcode += b"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41"
shellcode += b"\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48"
shellcode += b"\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f"
shellcode += b"\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c"
shellcode += b"\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52"
shellcode += b"\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b"
shellcode += b"\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01\xd0"
shellcode += b"\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56"
shellcode += b"\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9"
shellcode += b"\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0"
shellcode += b"\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58"
shellcode += b"\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44"
shellcode += b"\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0"
shellcode += b"\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a"
shellcode += b"\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
shellcode += b"\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48\xba\x01\x00\x00"
shellcode += b"\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41"
shellcode += b"\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x41"
shellcode += b"\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06"
shellcode += b"\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a"
shellcode += b"\x00\x59\x41\x89\xda\xff\xd5\x63\x61\x6c\x63\x2e\x65"
shellcode += b"\x78\x65\x00" shellcode = bytearray(shellcode)
# 设置VirtualAlloc返回类型为ctypes.c_uint64
ctypes.windll.kernel32.VirtualAlloc.restype = ctypes.c_uint64
# 申请内存
ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), ctypes.c_int(len(shellcode)), ctypes.c_int(0x3000), ctypes.c_int(0x40)) # 放入shellcode
buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode)
ctypes.windll.kernel32.RtlMoveMemory(
ctypes.c_uint64(ptr),
buf,
ctypes.c_int(len(shellcode))
)
# 创建一个线程从shellcode防止位置首地址开始执行
handle = ctypes.windll.kernel32.CreateThread(
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.c_uint64(ptr),
ctypes.c_int(0),
ctypes.c_int(0),
ctypes.pointer(ctypes.c_int(0))
)
# 等待上面创建的线程运行完
ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(handle),ctypes.c_int(-1))

注意其中的的每个 c_uint64,这个类型在64位上是必要的,我们需要手动指定 argtypesrestype ,否则默认的是 32 位整型。

我的代码里面加了注释,我们可以看到,基本思路也是一样的,先分配一块可读可写可执行代码的内存,在代码中,我使用的是 0x40(PAGE_EXECUTE_READWRITE)和 0x3000 ( 0x1000 | 0x2000)(MEM_COMMIT | MEM_RESERVE),然后把 shellcode 塞进去,跳过去运行。

相信通过这一片文章的讲解你能够对 shellcode 的本质有更多的了解。

Python内存加载shellcode的更多相关文章

  1. 动态加载 ShellCode绕过杀软

    反病毒解决方案用于检测恶意文件,并且通常使用静态分析技术来区分二进制文件的好坏.如果是恶意文件本身包含恶意内容(ShellCode),那么依靠静态分析技术会非常有效,但如果攻击者使用轻量级的stage ...

  2. python 模块加载

    python 模块加载 本文主要介绍python模块加载的过程. module的组成 所有的module都是由对象和对象之间的关系组成. type和object python中所有的东西都是对象,分为 ...

  3. 内存加载DLL

    1.前言 目前很多敏感和重要的DLL(Dynamic-link library) 都没有提供静态版本供编译器进行静态连接(.lib文件),即使提供了静态版本也因为兼容性问题导致无法使用,而只提供DLL ...

  4. DLL内存加载

    动态加载dll 功能:      把一个处于内存里的dll直接加载并且使用. 用途:      免杀(静态文件查杀),外挂(防止游戏自己hook了loadlibrary等函数),以及其他. 原理:  ...

  5. Python -- 数据加载、存储与文件格式

    标签(空格分隔): Python 读入读出通常可以划分为几个大类:读取文本文件和其他更高效的磁盘存储格式,加载数据库中的数据,利用Web API操作网络资源. 读写文本格式的数据 pandas提供了一 ...

  6. BASE64编码和解码(VC源代码) 并 内存加载 CImage 图像

      BASE64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本.完整的BASE64定义可见 RFC1421和 RFC2045.编码后的数据比原始数据略长,为原来的4/3.在电子 ...

  7. python 动态加载module、class、function

    python作为一种动态解释型语言,在实现各种框架方面具有很大的灵活性. 最近在研究python web框架,发现各种框架中需要显示的定义各种路由和Handler的映射,如果想要实现并维护复杂的web ...

  8. 很考验人的java内存加载面试题

    源代码如下,求结果 public class MemoryAnalyse { public static int k = 0; public static MemoryAnalyse t1 = new ...

  9. python︱模块加载(pip安装)以及pycharm安装与报错解决方式

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 准备放下R开始学python,真是痛苦,因为找 ...

随机推荐

  1. qt 单例程序

    1.http://qt.nokia.com的网站把QtSingleApplication 的源代码qtsingleapplication-2.6_1-opensource.zip 下载下来,然后解压缩 ...

  2. cmake 手册详解【转】

    https://www.cnblogs.com/coderfenghc/tag/cmake/   CMake 手册详解(二十三) SirDigit 2012-12-16 22:03 阅读:11058 ...

  3. 第2课第1节_Java面向对象编程_类的引入_P【学习笔记】

    摘要:韦东山android视频学习笔记 1. 面向对象编程的引入,我们先写一个简单的程序输出张三,李四的名字.代码如下,假如,现在我们要在名字前面添加籍贯广东,那样岂不是每个printf语句都得修改添 ...

  4. 右键查看别人网页的js代码为什么会显示乱码

    查看别人网页的js显示乱码 解决方法: 打开浏览器,选择设置,点击更多,选择文字编码为Unicode

  5. 通过遍历而非排序求最值 python list in 时间复杂度 列表元素存在性

    Write a function: def solution(A) that, given an array A of N integers, returns the smallest positiv ...

  6. c++调用动态库失败解决办法

    c++调用动态库失败解决办法 之前写好的程序今天早上过来发现在服务器上出错了,于是就各种查问题,整整一个早上外加下午两个小时都在查这个问题,最终被我找到了问题: 在程序中我发现LoadLibrary( ...

  7. ES6深入浅出-6 ES 6 模块-2.babel webpack parcel

    https://babeljs.io/ 复制到命令行执行 提示一个警告.缺少package.json这个文件 npm init -t ls 然后看到了生成了package.json这个文件. 然后再去 ...

  8. Qt编写气体安全管理系统23-类型设置

    一.前言 类型设置这个功能模块大大拓展了整个系统的灵活性,将整个系统中所有用到的控制器型号.探测器数量.探测器型号.气体种类.气体符号都存储到数据库表中,用户在类型设置中可以自由添加删除和修改,这样后 ...

  9. 【翻译】生成 Timestamps / Watermarks

    本文翻译自flink官网:https://ci.apache.org/projects/flink/flink-docs-release-1.7/dev/event_timestamps_waterm ...

  10. sentinel搭建redis集群的注意事项

    一.protected-mode 默认情况下,redis node和sentinel的protected-mode都是yes,在搭建集群时,若想从远程连接redis集群,需要将redis node和s ...