Тема: [FASM] x86 Position-independent code, proof of concept
У якості розминки, наваяв приклад частково позиційно-незалежного коду. Завдяки частковості, ми отримуємо дуже компактне PI-тіло, яке, наприклад, можемо кудись заінжектити.
За приклад візьмемо наступний код:
WSADATA wsaData;
char *m, name[128];
WSAStartup(0x202, &wsaData);
gethostname(name, 128);
m = inet_ntoa(*(struct in_addr*)gethostbyname(name)->h_addr_list[0]);
MessageBoxA(0, m, "Заголовок", MB_OK);
WSACleanup();
ExitProcess(0);
shellcode.asm
format pe gui 5.01
entry start
include 'win32ax.inc'
struct APIS
MessageBoxA rd 1
ExitProcess rd 1
WSAStartup rd 1
gethostname rd 1
inet_ntoa rd 1
gethostbyname rd 1
WSACleanup rd 1
ends
struct CONFIG
apis APIS
wsaData WSADATA
name rb 128
tittle rb 20
ends
; ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
section '.data' data readable writeable // секція даних
api_table dd nMessageBoxA,\
nExitProcess,\
nWSAStartup,\
ngethostname,\
ninet_ntoa,\
ngethostbyname,\
nWSACleanup,\
-1
nMessageBoxA db 'MessageBoxA', 0
nExitProcess db 'ExitProcess', 0
nWSAStartup db 'WSAStartup', 0
ngethostname db 'gethostname', 0
ninet_ntoa db 'inet_ntoa', 0
ngethostbyname db 'gethostbyname', 0
nWSACleanup db 'WSACleanup', 0
user32 db 'user32', 0
kernel32 db 'kernel32', 0
ws2_32 db 'ws2_32', 0
ttl db 'Заголовок', 0
shc rd 1
cfg rd 1
hHeap rd 1
shellcode:
virtual at ebp
config CONFIG
end virtuaL
lea eax, [config.wsaData]
push eax
push 0x202
call [config.apis.WSAStartup]
push 128
lea eax, [config.name]
push eax
call [config.apis.gethostname]
lea eax, [config.name]
push eax
call [config.apis.gethostbyname]
mov eax, [eax + hostent.h_addr_list]
mov eax, [eax]
push dword[eax]
call [config.apis.inet_ntoa]
push 0
lea edx, [config.tittle]
push edx
push eax
push 0
call [config.apis.MessageBoxA]
call [config.apis.WSACleanup]
push 0
call [config.apis.ExitProcess]
size_shellcode = $ - shellcode
; ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
; ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
section '.text' code readable executable // секція коду
start:
// аналог GetProcessHeap()
mov eax, [fs:0x30]
mov eax, [eax + 0x18]
mov [hHeap], eax
// виділяємо пам'ять під структуру
invoke HeapAlloc, [hHeap], HEAP_ZERO_MEMORY, sizeof.CONFIG
mov [cfg], eax
// ..під шеллкод
invoke HeapAlloc, [hHeap], HEAP_ZERO_MEMORY, size_shellcode
mov [shc], eax
// знаходимо адреси winapi
mov ebx, [cfg]
mov esi, api_table
.a: cmp dword[esi], nMessageBoxA
ja @f
push user32
jmp .b
@@: cmp dword[esi], nExitProcess
ja @f
push kernel32
jmp .b
@@: push ws2_32
.b: invoke LoadLibraryA
invoke GetProcAddress, eax, dword[esi]
mov dword[ebx], eax
add esi, 4
add ebx, 4
cmp dword[esi], -1
jne .a
mov ebx, [cfg]
invoke lstrcpyA, addr ebx + CONFIG.tittle, ttl
// копіюємо шеллкод у пам'ять
mov esi, shellcode
mov edi, [shc]
mov ecx, size_shellcode
rep movsb
// передаєм вказівник на структуру та стартуємо шеллкод
mov ebp, [cfg]
push ebp
jmp [shc]
; ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
; ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
section '.idata' import data readable writeable // секція імпорту
library kernel32, 'kernel32.dll',\
user32, 'user32.dll'
import kernel32,\
GetProcAddress, 'GetProcAddress',\
LoadLibraryA, 'LoadLibraryA',\
HeapAlloc, 'HeapAlloc',\
lstrcpyA, 'lstrcpyA'
; ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~