Общее·количество·просмотров·страницы

понедельник, 26 декабря 2011 г.

сплайсинг апи

 сегодня пойдет речь,я думаю,об одном из самых перспективынх методов перехвата АПИ в ring 3- сплайсинге.

И так не много теории.

Сплайсинг-метод перехвата API функций в режиме юзера (ring 3). Обычно изменяются первые 5 байт функции на длинный прыжок по адресу обработчика перехвата.В зависимости от ситуации может понадобится дизассемблер длин инструкций,однако M$ изменила пролог начиная с ХР SP2, позволяя при этом не анализировать длины.Длины в 5 байт будет достаточно(5байт- E9h- опкод прыжка jmp).Сплайсинг так же позволяет осуществлять глобальный перехват функций, тем самым охватывая все процессы в системе.

Применение:
Данный вид перехвата используется:
1)Десктопное ПО производящее операции с ОС (например мониторы)
2)Хуки
3)Малварь (руткиты и т.п.)

Инструменты:
1)ЯП (в данном случае Delphi)
2)музычка (kmfdm или rammstein сойдет)
3)руки.голова

И так начнем.
Как вы поняли наш код будет размещаться в dll-ке которая будет загружаться во все процессы и творить там свои темные дела.Чтобы не парится я буду извращаться с мэссэджбоксом.

код:
Создаем две записи-структуры

type

OC=packed record
frst:dword;
sec:word;
end;

fj= packed record
pusho:byte;
pushar:pointer;
reto:byte;
end;

1-я будет содержать запись на оригинал кода.2-я длинный прыжок

объявим переменные структур


var
jmpmw,jmpma:fj;
ocmw,ocma:oc;
mwadr,maadr:pointer;

я возьму функцию messageboxex- это считайте тот же messagebox только в нем присутствует идентификатор языка.

Теперь нам нужно описать функции на которые будет происходить прыжок.
Их будет две.Почему так?Мурка заключается в том что существуют две категории АПИ ansi и Unicode которые имеют соотв. окончание MessageBoxA или например MessageBoxW. Соль в том что анси является 8 битной кодировкой и может предоставлять только 256 уникальных символов, в то время как юникод обеспечивает 65535 уникальных символов,это было сделано с целью работы со всеми языками мира.

начнем описание функций:

function NMessageBoxExA(hWnd: HWND; lpText, lpCaption: PAnsiChar;
                          uType: UINT; wLanguageId: Word): Integer; stdcall;
var txt,cap:pwidechar;
txtl,capl:dword;
begin
txtl:=lstrlen(lptext)*sizeof(widechar)+2;
capl:=lstrlen(lpcaption)*sizeof(widechar)+2;
getmem(txt,txtl);
getmem(cap,capl);
stringtowidechar(lptext,txt,txtl);
stringtowidechar(lpcaption,cap,capl);
result:=MessageBoxExW(hWnd, txt, Cap, uType, wLanguageId);
freemem(txt);
freemem(cap);
end;

что к чему. новая функция имеет те же флаги что и обычная:
дескриптор окна, текст сообщения,заголовок окна,стиль окна и язык.
работаем с widechar выше разобрали почему(т.к. он поддерживает интернациональные символы).
напрямую со string мы не работаем,а работаем с памятью.
Получаем длину текста и длину заголовка.Выделяем кол-во динамической памяти= длине, получая данные в нужные переменные.Затем конвертируем строки и получаем готовые флаги ф-ии.вызываем ф-ю с нужными параметрами и освобождаем память.

Следующей определяем оригинал









function TrueMessageBoxExW(hWnd: HWND; lpText, lpCaption: PWideChar;
                           uType: UINT; wLanguageId: Word): Integer; stdcall;
var
Written: dword;
begin

writeProcessMemory(INVALID_HANDLE_VALUE, mwadr,@ocmw, SizeOf(OC), Written);
Result := MessageBoxExW(hWnd, lpText, lpCaption, uType, wLanguageId);
WriteProcessMemory(INVALID_HANDLE_VALUE, mwadr,@Jmpmw, SizeOf(fj), Written);
end;

За ней идет юникодный msgbox


function NMessageBoxExW(hWnd: HWND; lpText, lpCaption: PWideChar;
                          uType: UINT; wLanguageId: Word): Integer; stdcall;
var
 Atxt: PWideChar;
 ntxtt: PWideChar;
 nlen: dword;
 a:integer;
begin
 a:=length('Happy new year asshole!');
 Atxt := stringtopwide('Happy new year asshole!',a);

 nlen := (lstrlenw(Atxt) + lstrlenw(lpText)) * SizeOf(WideChar) + 20;
 GetMem(ntxtt, nlen);
 lstrcpyw(ntxtt, lpText);
 lstrcatw(ntxtt, #10#13#10#13);
 lstrcatw(ntxtt, Atxt);
 FreeMem(Atxt);
 Result := TrueMessageBoxExW(hWnd, ntxtt, lpCaption, uType, wLanguageId);
 FreeMem(ntxtt);
end;

по анологии с ansichar заполняем Unicode. Вы можете наблюдать строку.Эта строка будет выдаваться теперь при вызовах msgbox. Но в самом начале кода нам потребуется две вспомогательные функции.




вот они:
Function AllocMem(Size: Integer): Pointer;
asm
or EAX, EAX
JZ @@exit
PUSH EAX
CALL System.@GetMem
POP EDX
PUSH EAX
MOV CL, 0
CALL System.@FillChar
POP EAX
@@exit:
end;

*написано с целью не подключать модуль sysutils
эта функция выд-т  область памяти,после чего мы применяем функцию конвертирования string строки в widechar

function stringtopwide(str:string;var a:integer):pwidechar;
var
pwc:pwidechar;
d:integer;
begin
d:=length(str)+1;
a:=d*2;
pwc:=allocmem(a);
multibytetowidechar(cp_acp,0,pchar(str),d,pwc,a);
result:=pwc;
end;

Дальге мы получаем адреса функций ,заполняем записи и устанавливаем прыжок.

procedure SetHook;
var
 hwnd: dword;
 Byte: dword;
begin
  hwnd := GetModuleHandle('user32.dll');
  mwadr  := GetProcAddress(hwnd, 'MessageBoxExW');
  maadr  := GetProcAddress(hwnd, 'MessageBoxExA');
  ReadProcessMemory(INVALID_HANDLE_VALUE, mwadr, @ocmw, SizeOf(OC), Byte);
  ReadProcessMemory(INVALID_HANDLE_VALUE, maadr, @ocma, SizeOf(OC), Byte);
  jmpmw.pusho  := $68;
  jmpmw.PushAr := @NMessageBoxExW;
  jmpmw.RetO   := $C3;
  jmpma.pusho  := $68;
  jmpma.PushAr := @NMessageBoxExA;
  jmpma.RetO   := $C3;
  WriteProcessMemory(INVALID_HANDLE_VALUE, mwadr, @jmpmw, SizeOf(fj), Byte);
  WriteProcessMemory(INVALID_HANDLE_VALUE, maadr, @jmpma, SizeOf(fj), Byte);
end;

разбираем:
получаем дескриптор системной dll-ки в которой хранятся наши функции.
записываем их адркса в записи.
сохраняем оригинальные начала. Формирование новых начал функций в структурах jmpmw и jmpma идет так: опкод  68h -push, затем ее аргумент – адрес нашей функции, которая заменит оригинальную, в конце идет опкод c3h-ret.И переписываются оригинальные начала на наши.
когда надо подставить оригинал,возвращаем байты

Procedure Unhook;
var
 Byte: dword;
begin
  WriteProcessMemory(INVALID_HANDLE_VALUE, maadr, @ocma, SizeOf(OC), Byte);
  WriteProcessMemory(INVALID_HANDLE_VALUE, mwadr, @ocmw, SizeOf(OC), Byte);
end;

Далее следует процедура,которая поможет загрузить нашу dll-ку глобально


Function Msg(code : integer; wParam : word;
                    lParam : longint) : longint; stdcall;
begin
 CallNextHookEx(0, Code, wParam, lparam);
 Result := 0;
end;


собсно сама процедура

Procedure SetGlobalHookO;
begin
 SetWindowsHookEx(WH_GETMESSAGE, @Msg, HInstance, 0);
 Sleep(INFINITE);
end;

и оставляем в памяти.

Procedure SetGlobalHook;
var
 hMutex: dword;
 TrId: dword;
begin
 hMutex := CreateMutex(nil, false, 'AdvareHook');
 if GetLastError = 0 then
 CreateThread(nil, 0, @SetGlobalHookO, nil, 0, TrId) else
 CloseHandle(hMutex);
end;

устанавливаем глобальный хук. проверяем запущен ли файл.Только поток владеющий мьютексом имеет домтуп к области памяти.

procedure DLL(dwReason: DWord);
begin
case dwReason of
DLL_PROCESS_ATTACH:
begin
SetGlobalHook;
SetHook;
end;
DLL_PROCESS_DETACH: UnHook;
end;
end;

begin
DllProc := @DLL;
DLL(DLL_PROCESS_ATTACH);
end.

и смысл последней процедуры: при аттаче длл устанавливается хук. при детаче-хук соответственно снимается.

Остается лишь написать лоадер.

.386
.model flat,stdcall
option casemap:none

include include\windows.inc
include include\kernel32.inc

includelib lib\kernel32.lib

.data
libname db 'MSGSPLICE.dll',0

start:
invoke LoadLibrary,addr libname
invoke Sleep,INFINITE

end start

грузим dll-ку и висим в памяти.


и так алгоритм работы в кратце (итог типо)


1) получаем дескриптор библиотеки , в которой содержатся функции которые необходимо перехватить.

2) в соответствующие переменные записываем оригинальные адреса функций

3) сохраняются оригинальные начала функций

4) Формирование новых начал функций в структурах jmpmw и jmpma. В начале идет опкод команды push, затем ее аргумент – адрес нашей функции, которая заменит оригинальную, в конце идет оператор ret.

5) переписываются начала оригинальных API-функции данными из структур



Таким образом в начало оригинальных функций
будут вставлены переходы на их функции-заменители.


Комментариев нет:

Отправить комментарий