无文件执行:一切皆是shellcode (上)
微信公众号:七夜安全博客 关注信息安全技术、关注 系统底层原理。问题或建议,请公众号留言。
前言
良好的习惯是人生产生复利的有力助手。
2020年第三篇文章,继续2020年的flag:每周至少更新一篇文章。喜欢本文,您就点“在看” 并分享哈。
有意思的项目
最近几篇文章都是关于无文件执行或者是逃逸execve检测的内容,今天接着延续着这个思路往下讲。在讲逃逸execve检测的时候,我提到直接执行shellcode是非常好的方式,但是shellcode的提取相对困难,就算是使用MSF工具生成的shellcode,功能也相对单一。如何能让shellcode的提取变得简单,成为我接下来思考的内容。
有一个大胆的想法:
ELF文件能否直接转化为shellcode
毕竟开发ELF的门槛还是挺低的
于是我就搜了一下elf2shellcode,没找到什么有用的项目,在寻找的过程中,找到了windows上的pe_to_shellcode项目:
https://github.com/hasherezade/pe_to_shellcode
这个项目很有意思,通过加壳的方式将exe文件转为了shellcode,接下会简单讲一下使用以及原理,打算分成几篇来讲,讲细致一些。
使用说明
这个项目有趣的地方是 将exe转化为shellcode,转化后的文件依然是完整的PE文件,不仅可以单独运行,也可以通过shellcode的方式运行。在项目的release页面,根据自身的系统下载runshc 和pe2shc文件:
使用pe2shc.exe转换您选择的PE:
pe2shc.exe <path to your PE> [output path]
使用runshc.exe运行输出文件,并检查转换是否正常:
runshc.exe <converted file>
演示
以windows中的calc.exe为例子,先转化calc,保存为calc_modify.exe ,命令如下:
D:\pe_to_shellcode>pe2shc.exe calc.exe calc_modify.exe
Reading module from: calc.exe
[+] Saved as: calc_modify.exe
运行一下,奇迹就出现了,双击一下calc_modify.exe也是同样的效果:
D:\pe_to_shellcode>runshc64.exe calc_modify.exe
[*] Reading module from: calc_modify.exe
[*] Running the shellcode:
计算器弹起来:
是障眼法吗?
到这一步,虽然看到calc_modify.exe执行了,但是只要细想 这会不会是个障眼法 !!!
calc_modify.exe是真的像shellcode一样运行了吗?还是直接通过创建进程的方式来执行calc_modify.exe?
看一下runshc的源码就可以知道了。
#include <windows.h>
#include <iostream>
#include "peconv.h"
int main(int argc, char *argv[])
{
if (argc < 2) {
std::cout << "~ runshc ~\n"
<< "Run shellcode: loads and deploys shellcode file.\n";
#ifdef _WIN64
std::cout << "For 64-bit shellcodes.\n";
#else
std::cout << "For 32-bit shellcodes.\n";
#endif
std::cout << "Args: <shellcode_file>" << std::endl;
system("pause");
return 0;
}
size_t exe_size = 0;
char* in_path = argv[1];
std::cout << "[*] Reading module from: " << in_path << std::endl;
BYTE *my_exe = peconv::load_file(in_path, exe_size);
if (!my_exe) {
std::cout << "[-] Loading file failed" << std::endl;
return -1;
}
BYTE *test_buf = peconv::alloc_aligned(exe_size, PAGE_EXECUTE_READWRITE);
if (!test_buf) {
peconv::free_file(my_exe);
std::cout << "[-] Allocating buffer failed" << std::endl;
return -2;
}
//copy file content into executable buffer:
memcpy(test_buf, my_exe, exe_size);
//free the original buffer:
peconv::free_file(my_exe);
my_exe = nullptr;
std::cout << "[*] Running the shellcode:" << std::endl;
//run it:
int (*my_main)() = (int(*)()) ((ULONGLONG)test_buf);
int ret_val = my_main();
peconv::free_aligned(test_buf, exe_size);
std::cout << "[+] The shellcode finished with a return value: " << std::hex << ret_val << std::endl;
return ret_val;
}
在上述代码中,主要做了三件事:
读取exe文件到缓冲区
给exe文件分配可读可写可执行的内存,并将缓冲区中的内容复制到这段内存中
从内存中执行代码
基本上和shellcode的执行方式是一样的,看来真的是将PE文件转化为了shellcode。
原理
想知道原理,最直观的方式是比对calc.exe 与calc_modify.exe的二进制内容,看一下有哪些不同。
启动Beyond Compare工具采用16进制比对,会发现calc.exe后面附加了一段代码。
做过软件保护的同学,肯定可以看出这是一个类似壳的实现方式,至于这段壳是如何实现PE to shellcode功能的?
请看下次分解,涉及到汇编 ,大家心里有个准备哈。
总结
小想法
既然PE可以转化为shellcode,那么ELF应该也是可以通过这种方式转化为shellcode的,事实情况也是可以的,已经开始搞了。
那之后的网络+shellcode ,木马再也不落地,开心到起飞。。。。
小打算
最近又把汇编捡起来了,想写个专栏进行分享,毕竟只要是研究系统底层的,都逃不过汇编。
但是学习汇编,后台很多朋友反馈基本上都是学习基本理论和语法,没有什么实用的汇编项目来练手,导致学了但是总感觉没学会。
接下来我尽量通过专栏的方式,来帮助大家深入一下汇编的实战。
发了发了,看看书,早点睡觉,迎接上班。。。
推荐阅读:
沙盒syscall监控组件:strace and wtrace
无"命令"反弹shell-逃逸基于execve的命令监控(上)
如果大家喜欢这篇文章的话,请不要吝啬分享到朋友圈,并置顶公众号。
关注公众号:七夜安全博客
回复【8】:领取 python神经网络 教程
回复【1】:领取 Python数据分析 教程大礼包
回复【2】:领取 Python Flask 全套教程
回复【3】:领取 某学院 机器学习 教程
回复【4】:领取 爬虫 教程
回复【5】:领取编译原理 教程
回复【6】:领取渗透测试教程
回复【7】:领取人工智能数学基础