HOME FORUMS MEMBERS RECENT POSTS LOG IN  
× Авторизация
Имя пользователя:
Пароль:
Нет аккаунта? Регистрация
Баннер 1   Баннер 2
НОВЫЕ ТОРГОВАЯ НОВОСТИ ЧАТ
loading...
Скрыть
Вернуться   ANTICHAT > ИНФО > Статьи
   
Ответ
 
Опции темы Поиск в этой теме Опции просмотра

  #1  
Старый 26.12.2011, 04:29
DooD
Познавший АНТИЧАТ
Регистрация: 30.09.2010
Сообщений: 1,168
С нами: 8219126

Репутация: 288


По умолчанию

Доброго времени суток ув. форумчане.Покопавшись на форуме я понял что не хватает статей по перехвату АПИ,да и я давно ничего толком не писал.Так что сегодня пойдет речь,я думаю,об одном из самых перспективынх методов перехвата АПИ в 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, 'Hook');
 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-функции данными из структур

Таким образом в начало оригинальных функций

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

Рез-ат работы перехвата:



ССЫЛАЛСЯ:

На код перехвата createprocess ms-rema.


Сильно не бейте!спасибо за внимание!
 
Ответить с цитированием

  #2  
Старый 27.12.2011, 16:45
DooD
Познавший АНТИЧАТ
Регистрация: 30.09.2010
Сообщений: 1,168
С нами: 8219126

Репутация: 288


По умолчанию

ну,что скажете люди?
 
Ответить с цитированием

  #3  
Старый 27.12.2011, 16:58
Demon__666
Новичок
Регистрация: 26.09.2011
Сообщений: 16
С нами: 7699286

Репутация: 0
По умолчанию

Круто )
 
Ответить с цитированием

  #4  
Старый 27.12.2011, 17:06
shadowrun
Постоянный
Регистрация: 29.08.2010
Сообщений: 840
С нами: 8265206

Репутация: 84


По умолчанию

Спасибо, познавательно. На дельфячем языке мне норм понятно.

+
 
Ответить с цитированием

  #5  
Старый 27.12.2011, 17:07
Chrome~
Постоянный
Регистрация: 13.12.2008
Сообщений: 354
С нами: 9162683

Репутация: 175
По умолчанию

То, что на ачате нету статей по перехвату API, это нехорошо, конечно. Но и здесь не описано ничего нового. Все это можно найти в инете. Тот же MS-REM описал все намного лучше.

Это также есть на самом деле нехорошо:

Цитата:
Сообщение от DooD  
Код:
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;
Так как запросто может произойти ошибка в многопоточных приложениях, которые в свою очередь сразу же аварийно завершат работу.

Код оформлен плохо. Эти INVALID_HANDLE_VALUE немного сбивают с толку.

Также нужно сказать, что здесь перезаписывается не 5, а 6 байт.

Цитата:
Сообщение от DooD  
Код:
fj= packed record
pusho:byte;
pushar:pointer;
reto:byte;
end;

  WriteProcessMemory(INVALID_HANDLE_VALUE, mwadr, @jmpmw, SizeOf(fj), Byte);
 
Ответить с цитированием

  #6  
Старый 27.12.2011, 18:29
DooD
Познавший АНТИЧАТ
Регистрация: 30.09.2010
Сообщений: 1,168
С нами: 8219126

Репутация: 288


По умолчанию

Цитата:
Сообщение от Chrome~  
То, что на ачате нету статей по перехвату API, это нехорошо, конечно. Но и здесь не описано ничего нового. Все это можно найти в инете. Тот же
MS-REM
описал все намного лучше.
Это также есть на самом деле нехорошо:
Так как запросто может произойти ошибка в многопоточных приложениях, которые в свою очередь сразу же аварийно завершат работу.
Код оформлен плохо. Эти INVALID_HANDLE_VALUE немного сбивают с толку.
Также нужно сказать, что здесь перезаписывается не 5, а 6 байт.
есть ли тогда смысл останавливать,а потом возобновлять потоки?Хотя я с этим не встречался.
 
Ответить с цитированием

  #7  
Старый 27.12.2011, 19:02
Chrome~
Постоянный
Регистрация: 13.12.2008
Сообщений: 354
С нами: 9162683

Репутация: 175
По умолчанию

Цитата:
Сообщение от DooD  
есть ли тогда смысл останавливать,а потом возобновлять потоки?Хотя я с этим не встречался.
Нет. Здесь нужен дизассемблер длин. Если использовать способ с перезаписыванием первых 5 байт, то алгоритм примерно такой:

0. С помощью дизассемблера длин выделяем столько целых первых команд перехватываемой функции, длина которых >= 5. Запоминаем эту длину в переменную len.

1. Запоминаем адрес следующей команды в переменную next_opcode.

2. Выделяем len + 5 байт памяти, адрес этой памяти записываем в переменную old_func.

3. В выделенный участок памяти копируем первые len байт из перехватываемой функции и дописываем команду jmp next_opcode (для нее мы выделели 5 дополнительных байт).

4. Перезаписываем первые 5 байт перехватываемой функции командой jmp .

5. Когда нужно вызвать старую функцию, делаем call old_func.
 
Ответить с цитированием

  #8  
Старый 27.12.2011, 19:41
DooD
Познавший АНТИЧАТ
Регистрация: 30.09.2010
Сообщений: 1,168
С нами: 8219126

Репутация: 288


По умолчанию

Цитата:
Сообщение от Chrome~  
Нет. Здесь нужен дизассемблер длин. Если использовать способ с перезаписыванием первых 5 байт, то алгоритм примерно такой:
0. С помощью дизассемблера длин выделяем столько целых первых команд перехватываемой функции, длина которых >= 5. Запоминаем эту длину в переменную
len
.
1. Запоминаем адрес следующей команды в переменную
next_opcode
.
2. Выделяем
len + 5
байт памяти, адрес этой памяти записываем в переменную
old_func
.
3. В выделенный участок памяти копируем первые
len
байт из перехватываемой функции и дописываем команду
jmp next_opcode
(для нее мы выделели 5 дополнительных байт).
4. Перезаписываем первые 5 байт перехватываемой функции командой
jmp
.
5. Когда нужно вызвать старую функцию, делаем
call old_func
.
гемморно.хотя я хз,тестил без дизасма-все прекрасно работает.
 
Ответить с цитированием

  #9  
Старый 27.12.2011, 19:47
Chrome~
Постоянный
Регистрация: 13.12.2008
Сообщений: 354
С нами: 9162683

Репутация: 175
По умолчанию

Цитата:
Сообщение от DooD  
гемморно.хотя я хз,тестил без дизасма-все прекрасно работает.
В многопоточных приложениях можно увидеть проблему. Например, перехватываешь recv (Winsock) в браузере и открываешь несколько вкладок.
 
Ответить с цитированием

  #10  
Старый 27.12.2011, 19:50
DooD
Познавший АНТИЧАТ
Регистрация: 30.09.2010
Сообщений: 1,168
С нами: 8219126

Репутация: 288


По умолчанию

Цитата:
Сообщение от Chrome~  
В многопоточных приложениях можно увидеть проблему. Например, перехватываешь
recv
(
Winsock
) в браузере и открываешь несколько вкладок.
а,я думал ты конкретно за эту фу-ю.возможно для других функций дизасм понадобится.надо бы юнит попробовать накатать.
 
Ответить с цитированием
Ответ



Предыдущая тема Следующая тема

Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
 


Быстрый переход




ANTICHAT ™ © 2001- Antichat Kft.