Буду публиковать сюда свой код на c++ пока учусь писать. Раньше писал на асме, но сейчас понимаю что это такое себе, хочу перейти на c++. Переодически буду публиковать тут код на c++. Прошу тех кто шарит в плюсах помочь мне.
Сейчас пытаюсь понять как правильно писать шеллкоды на c++.
Вот моя первая попытка оформить всё в виде шеллкода
Проблемы которые я вижу:
1. Строки хранятся в секции данных
2. Нельзя использовать unique_ptr, т.к. нельзя вызвать delete с аргументом, а раз нельзя вызвать с аргументом нужно создавать глобальную переменную которая будет хранить hHeap и HeapFree, то есть как минимум должна быть структурка которая хранит функции для особождения/выделения памяти и она должна быть глобальной - то есть не на стэке.
Насколько я знаю строки можно как-то перенести на стэк, да и вообще в будущем всё буду вызывать по хэшам, меня больше интересует второй вопрос - как организовать нормальное выделение памяти в шеллкоде, можно конечно сделать структуру на стэке, написать функции alloc/unalloc но вызывать их вручную как по мне такое себе, так что надо делать через unique_ptr
Сейчас пытаюсь понять как правильно писать шеллкоды на c++.
Вот моя первая попытка оформить всё в виде шеллкода
C++:
#include <windows.h>
#include <memory>
#include "NT_STRUCTS.h"
#include <stdalign.h>
// constants
#define PAGE_MINIMAL_SIZE 0x1000
#define HEAP_INITIAL_SIZE PAGE_MINIMAL_SIZE*2
#define MAX_HEAP_SIZE PAGE_MINIMAL_SIZE*64
using namespace std;
#define alloc(Type, PtrName) \
std::unique_ptr<Type> PtrName = std::make_unique<Type>(sizeof(Type));
typedef HANDLE(*_HeapCreate)(DWORD flOptions, size_t dwInitialSize, size_t dwMaximumSize);
typedef void* (*_HeapAlloc)(HANDLE hHeap, DWORD dwFlags, size_t dwBytes);
typedef int (*_HeapFree)(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
typedef int (*_MessageBoxA)(HWND hWnd,LPCSTR lpText,LPCSTR lpCaption,UINT uType);
typedef HMODULE (*_LoadLibraryW)(LPCWSTR lpLibFileName);
void* memset(void* s, int c, size_t sz)
{
byte* p = (byte*)s;
while (sz--) {
*p++ = (byte)c;
}
return s;
}
void* memcpy(void* dst, void* src, size_t sz)
{
byte* dstbuf = (byte*)dst;
byte* srcbuf = (byte*)src;
while (sz--) {
dstbuf[sz] = srcbuf[sz];
}
return 0;
}
_TIMAGE_FILE_HEADER* GetPEHeader(HMODULE module)
{
_IMAGE_DOS_HEADER* IMAGE_DOS_HEADER = (_IMAGE_DOS_HEADER*)module;
DWORD e_lfanew = IMAGE_DOS_HEADER->e_lfanew;
return (_TIMAGE_FILE_HEADER*)((UINT64)IMAGE_DOS_HEADER + (UINT64)e_lfanew);
};
_TIMAGE_OPTIONAL_HEADER* GetOptionalHeader(HMODULE module)
{
return (_TIMAGE_OPTIONAL_HEADER*)((UINT64)GetPEHeader(module) + (UINT64)sizeof(_TIMAGE_FILE_HEADER));
};
struct _IMPORT
{
_HeapCreate HeapCreate;
_HeapAlloc HeapAlloc;
_HeapFree HeapFree;
_MessageBoxA MessageBoxA;
};
struct _GLOBAL_DATA
{
HANDLE hHeap;
_IMPORT import;
};
HMODULE GetKernel32()
{
HMODULE module;
__asm
{
xor rax, rax
mov rax, gs: [rax + 0x60]
mov rax, [rax + 0x18]
mov rax, [rax + 0x20]
mov rax, [rax]
mov rax, [rax]
mov rax, [rax + 0x20]
mov[module], rax
}
return module;
}
HMODULE GetNtdll()
{
HMODULE module;
__asm
{
xor rax, rax
mov rax, gs: [rax + 0x60]
mov rax, [rax + 0x18]
mov rax, [rax + 0x20]
mov rax, [rax]
mov rax, [rax + 0x20]
mov[module], rax
}
return module;
}
bool strcmpb(LPCSTR str1, LPCSTR str2)
{
int i = 0;
while (true)
{
if (str1[i] == str2[i])
{
if (str2[i] == 0)
{
return true;
}
i++;
}
else
{
return false;
}
}
}
FARPROC EGetProcAddress(HMODULE module, LPCSTR procname)
{
UINT64 ProcAddress = 0;
_IMAGE_DOS_HEADER* IMAGE_DOS_HEADER = (_IMAGE_DOS_HEADER*)module;
DWORD e_lfanew = IMAGE_DOS_HEADER->e_lfanew;
_TIMAGE_FILE_HEADER* IMAGE_FILE_HEADER = (_TIMAGE_FILE_HEADER*)((UINT64)IMAGE_DOS_HEADER + (UINT64)e_lfanew);
_TIMAGE_OPTIONAL_HEADER* IMAGE_OPTIONAL_HEADER = (_TIMAGE_OPTIONAL_HEADER*)((UINT64)IMAGE_FILE_HEADER + (UINT64)sizeof(_TIMAGE_FILE_HEADER));
// broken _IMAGE_OPTIONAL_HEADER redefine this shit
_IMAGE_EXPORT_DIRECTORY* IMAGE_EXPORT_DIRECTORY = (_IMAGE_EXPORT_DIRECTORY*)((UINT64)IMAGE_OPTIONAL_HEADER->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (UINT64)module);
DWORD* AddressOfNames = (DWORD*)((UINT64)IMAGE_EXPORT_DIRECTORY->AddressOfNames + (UINT64)module);
for (UINT32 i = 0; i <= IMAGE_EXPORT_DIRECTORY->NumberOfNames; i++)
{
LPCSTR Name = (LPCSTR)((UINT64)AddressOfNames[i] + (UINT64)module);
if (strcmpb((char*)procname, (char*)Name))
{
UINT16* Ordinals = (UINT16*)((UINT64)IMAGE_EXPORT_DIRECTORY->AddressOfNameOrdinals + (UINT64)module);
UINT32* AddressOfFunctions = (UINT32*)((UINT64)IMAGE_EXPORT_DIRECTORY->AddressOfFunctions + (UINT64)module);
ProcAddress = AddressOfFunctions[Ordinals[i]] + (UINT64)module;
}
}
return (FARPROC)ProcAddress;
}
void StartUp(_GLOBAL_DATA* maintable)
{
HMODULE kernel32 = GetKernel32();
HMODULE ntdll = GetNtdll();
maintable->import.HeapCreate = (_HeapCreate)EGetProcAddress(kernel32, "HeapCreate");
maintable->hHeap = maintable->import.HeapCreate(0, HEAP_INITIAL_SIZE, 0);
maintable->import.HeapAlloc = (_HeapAlloc)EGetProcAddress(ntdll, "RtlAllocateHeap");
maintable->import.HeapFree = (_HeapFree)EGetProcAddress(kernel32, "HeapFree");
_LoadLibraryW LoadLibraryW = (_LoadLibraryW)EGetProcAddress(kernel32, "LoadLibraryW");
HMODULE user32 = LoadLibraryW(L"user32.dll");
maintable->import.MessageBoxA = (_MessageBoxA)EGetProcAddress(user32, "MessageBoxA");
}
class MyClass
{
public:
int someval;
LPCSTR* teststr;
};
void* operator new(size_t size, _GLOBAL_DATA* maintable)
{
if (size)
{
return maintable->import.HeapAlloc(maintable->hHeap, 0, size);
}
return 0;
}
void operator delete(void* p, _GLOBAL_DATA* maintable)
{
if (p)
{
return (void)maintable->import.HeapFree(maintable->hHeap, 0, p);
}
return (void)0;
}
int main()
{
_GLOBAL_DATA maintable;
StartUp(&maintable);
MyClass* obj = new(&maintable) MyClass;
obj->someval = 100;
obj->teststr = new(&maintable) LPCSTR("hello");
maintable.import.MessageBoxA(0, *obj->teststr, *obj->teststr, 0);
return 0;
}
Проблемы которые я вижу:
1. Строки хранятся в секции данных
2. Нельзя использовать unique_ptr, т.к. нельзя вызвать delete с аргументом, а раз нельзя вызвать с аргументом нужно создавать глобальную переменную которая будет хранить hHeap и HeapFree, то есть как минимум должна быть структурка которая хранит функции для особождения/выделения памяти и она должна быть глобальной - то есть не на стэке.
Насколько я знаю строки можно как-то перенести на стэк, да и вообще в будущем всё буду вызывать по хэшам, меня больше интересует второй вопрос - как организовать нормальное выделение памяти в шеллкоде, можно конечно сделать структуру на стэке, написать функции alloc/unalloc но вызывать их вручную как по мне такое себе, так что надо делать через unique_ptr