Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2008.06.15;
Скачать: [xml.tar.bz2];

Вниз

Тонкости перехвата API   Найти похожие ветки 

 
Dmitry S ©   (2008-04-28 22:59) [0]

Конструктивно:

Перехватываю функцию CreateFileW путем записи нескольких первых байт. (точнее 10):
$68, $A1, $A2, $A3, $A4 // push A1A2A3A4h
$68, [@MyCreateFileW] // push ...
$C3 // ret

После чего, как я думал, мне необходимо в описание MyCreateFileW добавить еще один параметр (первый) резмером Integer, где и будет храниться переданное мной число A1A2A3A4h.
Однако параметр полченный в функцию "левый", а число A1A2A3A4h продолжает храниться в стеке. Почему так? Ведь я добавил еще один параметр, он ведь должен браться из стека?


 
Тыщ ©   (2008-04-28 23:04) [1]

Какое соглашение вызова у функции MyCreateFileW?


 
Dmitry S ©   (2008-04-28 23:04) [2]

stdcall


 
Dmitry S ©   (2008-04-28 23:11) [3]

А еще вопрос по теме.
Как сделать call по абслютному адресу? Т.е. в машинных инстукциях как?
E8 xx xx xx xx - это я так понимаю относительный. А как абсолютный?


 
Тыщ ©   (2008-04-28 23:15) [4]

Dmitry S ©   (28.04.08 23:11) [3]

call по абслютному адресу сделать нельзя, потому так как он изменит сегментный регистр cs, а это запрещено в Windows.
Да и не нужно, в общем-то.


 
Dmitry S ©   (2008-04-28 23:19) [5]

А как тогда быть??


 
Тыщ ©   (2008-04-28 23:19) [6]

mov eax, some_absolute_address
call eax


 
Dmitry S ©   (2008-04-28 23:23) [7]

окей.
А можно это в кодах команд?


 
Тыщ ©   (2008-04-28 23:25) [8]

B8 78563412 // mov eax, 12345678h
FFD0 // call eax


 
Dmitry S ©   (2008-04-28 23:43) [9]

Не понимаю вот чего:

Делаю простой вызов своей
MyCreateFileW

В итоге в окне асемблера наблюдаю:
делается куча push, потом call
а в теле функци pop-ов нет, значения переменных беруться из памяти. как так?


 
Anatoly Podgoretsky ©   (2008-04-28 23:52) [10]

> Dmitry S  (28.04.2008 23:43:09)  [9]

Есть такое понятие, как фрейм стека, вот отностительно его и берутся.
Сходи ко мне на сайт и возьми две статьи по basm

http://www.podgoretsky.com/Redir.aspx?id=142&DownloadFile=~/ftp/Docs/Delphi/Podgoretsky/basmru.zip
http://www.podgoretsky.com/Redir.aspx?id=129&DownloadFile=~/ftp/Docs/Delphi/Podgoretsky/BasmForBeginners-ru.doc

Поскольку ты занимаешься АСМ то информация будет интересна.


 
Dmitry S ©   (2008-04-29 00:11) [11]

Кажеться я понял в чем дело.
Объясните пожалуйста следующее.
Мне нужно вставить некое значение в стек ПЕРЕД текущим. Так правильно:
pop eax;
push $xxxxxxx;
push eax;
?


 
Dmitry S ©   (2008-04-29 00:21) [12]

Все!!! Я понял!! И исправил.

Дело в том, что я "добавлял" этот самый параметр ПОСЛЕ выполнения call. А последняя использует стек, видимо для хранения точки возврата. Поэтому мой параметр и адрес точки возврата, какбы поменялись местами.Вставил код из 11, все заработало =) уфф=)


 
Dmitry S ©   (2008-04-29 00:40) [13]

В итоге получился такой код:

pop eax  // 58
push $xxxxxxxx // 68xxxxxxxx
push eax  // 50
push $yyyyyyyy // 68yyyyyyyy
ret  // c3

Этот код я вставляю в начало перехватываемой функции.
Тут $xxxxxxxx - адрес какого либо параметра
$yyyyyyyy - мой функция, которая должна выполнить оригинальную...
Блин, совсем как с SetIntVec в паскале =)


 
KSergey ©   (2008-04-29 09:55) [14]

> Dmitry S ©   (29.04.08 00:21) [12]
> ПОСЛЕ выполнения call.
> А последняя использует стек, видимо для хранения точки возврата.

А может книжки-то почитать, а?
Ну зачем постигать компьютер методом проб и ошибок? Это ж жизни не хватит!


 
Rouse_ ©   (2008-04-29 10:18) [15]

Что-то ты сурово как-то сплайсинг делаешь... Вот тебе навскидку примерчик от руки написанный... Должен работать по идее

type
 TSpliceRec = packed record
   JMP_OpCode: Byte;
   ProcAddr: Pointer;
   RET_OpCode: Byte;
 end;

var
 FuncAddr: Pointer;
 OldSpliceData, NewSpliceData: TSpliceRec;

function SpliceEntry(const FuncAddr: Pointer;
 const NewData: TSpliceRec): Boolean;
var
 Dumme: DWORD;
begin
 Result := WriteProcessMemory(GetCurrentProcess, FuncAddr, @NewData,
   SizeOf(TSpliceRec), Dumme);
 if Result then
   Result := Dumme = SizeOf(TSpliceRec);
end;

type
 TCreateFileA = function(lpFileName: PAnsiChar;
   dwDesiredAccess, dwShareMode: DWORD;
   lpSecurityAttributes: PSecurityAttributes;
   dwCreationDisposition, dwFlagsAndAttributes: DWORD;
   hTemplateFile: THandle): THandle; stdcall;

function InterceptedCreateFileA(lpFileName: PAnsiChar;
 dwDesiredAccess, dwShareMode: DWORD;
 lpSecurityAttributes: PSecurityAttributes;
 dwCreationDisposition, dwFlagsAndAttributes: DWORD;
 hTemplateFile: THandle): THandle; stdcall;
begin
 SpliceEntry(FuncAddr, OldSpliceData);
 dwDesiredAccess := GENERIC_READ;
 dwShareMode := FILE_SHARE_READ or FILE_SHARE_WRITE;
 dwCreationDisposition := OPEN_EXISTING;
 Result := TCreateFileA(FuncAddr)(lpFileName, dwDesiredAccess,
   dwShareMode, lpSecurityAttributes, dwCreationDisposition,
   dwFlagsAndAttributes, hTemplateFile);
 SpliceEntry(FuncAddr, NewSpliceData);
end;


пример вызова:

 NewSpliceData.JMP_OpCode := $68;
 NewSpliceData.ProcAddr := @InterceptedCreateFileA;
 NewSpliceData.RET_OpCode := $C3;
 FuncAddr := GetProcAddress(GetModuleHandle(kernel32), "CreateFileA");
     ReadProcessMemory(GetCurrentProcess,
     FuncAddr,
     @OldSpliceData, SizeOf(TSpliceRec), Dumme);

 SpliceEntry(FuncAddr, NewSpliceData);
 try
   M := TFileStream.Create(Path, fmOpenRead);
   try
     M.Position := LogRecord[Index].Rec.DataOffset;
     Stream.CopyFrom(M, LogRecord[Index].Rec.DataSize);
     Result := True;
   finally
     M.Free;
   end;
 finally
   SpliceEntry(FuncAddr, OldSpliceData);
 end;


 
Дмитрий С   (2008-04-29 10:26) [16]


> Rouse_ ©   (29.04.08 10:18) [15]

Я делаю тоже самое, только передаю в InterceptedCreateFileA дополнительный параметр. Типа LPVOID lpParameter у CreateThread.


 
Дмитрий С   (2008-04-29 10:28) [17]

Вечером скину код, что получилось. Он дома.

ЗЫ. Не удается с тобой наладить связь. =(


 
Дмитрий С   (2008-04-29 10:29) [18]


> А может книжки-то почитать, а?
> Ну зачем постигать компьютер методом проб и ошибок? Это
> ж жизни не хватит!

Так ведь это просто! Мне АСМ в принципе не нужен. Для таких нехитрых задач достаточно тех знаний что есть:) Конечно возникают вопросы. Но они у всех возникают


 
Дмитрий С   (2008-04-29 10:35) [19]


> Поскольку ты занимаешься АСМ то информация будет интересна.
>
>

благодарю! :)


 
Rouse_ ©   (2008-04-29 10:38) [20]


> ЗЫ. Не удается с тобой наладить связь. =(

Дай свою асю сам свяжусь, у меня антиспам стоит, он почемуто только с QIP пропускает клиентов :)


 
Дмитрий С   (2008-04-29 10:40) [21]

Удалено модератором


 
Сергей М. ©   (2008-04-29 15:53) [22]


> Dmitry S ©   (28.04.08 22:59)


А нафих тебе сплайсинг сдался ?
Чем не устроил перехват методом модификации EAT+IAT ?


 
Дмитрий С   (2008-04-29 16:06) [23]

О вкусах не спорят


 
Сергей М. ©   (2008-04-29 17:08) [24]


> О вкусах не спорят


Не спорят, да)

А вот о блажи можно и поспорить.


 
Rouse_ ©   (2008-04-29 17:18) [25]

Через EAT+IAT доп.параметр не перекинешь, хотя я так и не понял зачем он тут сдался :)


 
Сергей М,   (2008-04-29 19:47) [26]


> зачем он тут сдался


Как зачем ? Блажь !) Самая что ни на есть настоящая).. Надежно прикрытая "вкусами, о которых не спорят")


 
Тыщ ©   (2008-04-29 22:47) [27]

Anatoly Podgoretsky ©   (28.04.08 23:52) [10]

> basmru.zip

Почитал. Что-то опечаток многовато, и некоторые неточности имеются.


 
Dmitry S ©   (2008-04-29 23:20) [28]

unit InterceptAPI;

interface
uses Windows;

type
 TInterceptProc = packed record
   instr_pop1: byte;               // pop eax;
   instr_push1: byte;              // push InterceptStruct;
   InterceptStruct: Pointer;
   instr_push2: byte;              // push eax;
   instr_push3: byte;              // push address;
   address: Pointer;
   instr_ret: byte;                // ret;
 end;

 PInterceptStruct = ^TInterceptStruct;

 TInterceptStruct = record
   OriginalFunction: Pointer;
   NewFunction: Pointer;

   Lock:RTL_CRITICAL_SECTION;

   NewFunctionCode: TInterceptProc;
   OldFunctionCode: TInterceptProc; // тип используется лишь для сорaзмерности
 end;

{ InterceptFunction устанавливает перехват функции по адресу OriginalFunction
функцией по адресу NewFunction. Под структуру InterceptStruct выделять память не нужно -
выделяется автоматически.
Важно!
Функции OriginalFunction и NewFunction должны быть stdcall.
Причем NewFunction имеет не только те же параметры, что и OriginalFunction, но
и дополнительный первый параметр: InterceptStruct: PInterceptStruct.
Например оригинальная функция:
 function MessageBoxW(hWnd: HWND; lpText, lpCaption: PWideChar; uType: UINT): Integer; stdcall;
тогда новая функция должна иметь вил:
 function InterMessageBoxW(InterceptStruct: PInterceptStruct; hWnd: HWND; lpText, lpCaption: PWideChar; uType: UINT): Integer; stdcall;

Данный параметр используется для вызовов LockFunction и UnLockFunction.
}
procedure InterceptFunction(var InterceptStruct: PInterceptStruct; const OriginalFunction, NewFunction: Pointer); stdcall;

{
 UnInterceptFunction восстанавливает оригинальную функцию и освобождает память
 стурктуры InterceptStruct.
}
procedure UnInterceptFunction(var InterceptStruct: PInterceptStruct); stdcall;

{
 LockFunction временно восстанавливает функцию.
}
procedure LockFunction(InterceptStruct: PInterceptStruct); stdcall;

{
 UnLockFunction снова перехватывает функцию
}
procedure UnLockFunction(InterceptStruct: PInterceptStruct); stdcall;

implementation

procedure InterceptFunction(var InterceptStruct: PInterceptStruct; const OriginalFunction, NewFunction: Pointer); stdcall;
var
 CurrentProcess: THandle;
 C: DWord;
 I: Integer;
 P:Pointer;
begin
 GetMem(InterceptStruct, SizeOf(TInterceptStruct));

 InterceptStruct^.OriginalFunction := OriginalFunction;
 InterceptStruct^.NewFunction := NewFunction;

 InitializeCriticalSection(InterceptStruct^.Lock);

 InterceptStruct^.NewFunctionCode.instr_pop1 := $58; // pop eax
 InterceptStruct^.NewFunctionCode.instr_push1 := $68; // push
 InterceptStruct^.NewFunctionCode.InterceptStruct := InterceptStruct;

 InterceptStruct^.NewFunctionCode.instr_push2 := $50; // push eax

 InterceptStruct^.NewFunctionCode.instr_push3 := $68; // push
 InterceptStruct^.NewFunctionCode.address := NewFunction;
 InterceptStruct^.NewFunctionCode.instr_ret := $C3; // ret

 CurrentProcess := GetCurrentProcess;
 ReadProcessMemory(CurrentProcess, OriginalFunction, @InterceptStruct^.OldFunctionCode, SizeOf(TInterceptProc), C);
 WriteProcessMemory(CurrentProcess, OriginalFunction, @InterceptStruct^.NewFunctionCode, SizeOf(TInterceptProc), C);
end;

procedure UnInterceptFunction(var InterceptStruct: PInterceptStruct); stdcall;
var
 C: DWord;
begin
 WriteProcessMemory(GetCurrentProcess, InterceptStruct^.OriginalFunction, @InterceptStruct^.OldFunctionCode, SizeOf(TInterceptProc), C);
 DeleteCriticalSection(InterceptStruct^.Lock);
 FreeMem(InterceptStruct);
end;

procedure LockFunction(InterceptStruct: PInterceptStruct); stdcall;
var
 C: DWord;
begin
 EnterCriticalSection(InterceptStruct^.Lock);
 WriteProcessMemory(GetCurrentProcess, InterceptStruct^.OriginalFunction, @InterceptStruct^.OldFunctionCode, SizeOf(TInterceptProc), C);
end;

procedure UnLockFunction(InterceptStruct: PInterceptStruct); stdcall;
var
 C: DWord;
begin
 WriteProcessMemory(GetCurrentProcess, InterceptStruct^.OriginalFunction, @InterceptStruct^.NewFunctionCode, SizeOf(TInterceptProc), C);
 LeaveCriticalSection(InterceptStruct^.Lock);
end;

end.


Вот код который я создал.
Тут у меня самого замечание.
EnterCriticalSection и LeaveCriticalSection стоят непоназначению.
Как бы сделать, чтобы когда я восстановил функцию, то все ее вызовы из других потоков блокировались EnterCriticalSection. И эта блокировка снималась тогда, когда я восстанавливал функцию?


 
Dmitry S ©   (2008-04-29 23:23) [29]

Неужели придеться действительно через таблицу импорта делать.


 
Сергей М. ©   (2008-04-30 09:02) [30]


> Неужели придеться действительно через таблицу импорта делать.
>
>


И не только "через" нее.
Потребуется еще и модификация таблицы экспорта.

Но этот способ ничуть не хуже сплайсинга и при прочих равных условиях имеет очевидное преимущество в простоте реализации и использования.


 
Дмитрий С   (2008-04-30 10:11) [31]

*ушел делать rtfm* =)


 
Дмитрий С   (2008-05-02 20:26) [32]


> Потребуется еще и модификация таблицы экспорта.

А это зачем?

Я нашел пример в сети. Понял, что с помощью подмены таблицы импорта можно "перекрыть" функции только в своем модуле.
Т.е. если функция вызывается из другого модуля (из какой либо подключенной dll), то вызывается оригинальная функция, а не перекрытая.

Получается, что нужно заранее загружать нужную библиотеку и выполнять перекрытие уже в ней?


 
Rouse_ ©   (2008-05-03 15:20) [33]


> Получается, что нужно заранее загружать нужную библиотеку
> и выполнять перекрытие уже в ней?

Это ко всем случаям относится, если хочешь делать глобально, а не только в своем адресном пространстве...


 
Дмитрий С   (2008-05-04 10:11) [34]


> Это ко всем случаям относится, если хочешь делать глобально,
>  а не только в своем адресном пространстве...

Как же так? Вышеприведенный способ (с помощью сплайсов) не требовал этого. Тем более во время отладки я не раз прерывал программу после перезаписи нескольких байт — и ничего, система жила. И при этом у подгруженной библиотеки функции автоматически были перекрыты.


 
Rouse_ ©   (2008-05-04 10:24) [35]


> Как же так? Вышеприведенный способ (с помощью сплайсов)
> не требовал этого.

Что значит не требовал? Т.е. ты хочешь сказать, что в своем адресном пространстве ты сделал сплайсинг входной точки функции и это изменение автоматически спроецировалось на всю систему?


 
Дмитрий С   (2008-05-04 10:44) [36]


> Что значит не требовал? Т.е. ты хочешь сказать, что в своем
> адресном пространстве ты сделал сплайсинг входной точки
> функции и это изменение автоматически спроецировалось на
> всю систему?

Нет. Только на мой процесс. На все подключенные позже библиотеки (к моему процессу) перехват также распространялся.

А вот способ изменения IAT не распространяется на библиотеки вообще. Т.е. каждую библиотеку нужно хакать индивидуально.


 
Rouse_ ©   (2008-05-04 12:12) [37]


> А вот способ изменения IAT не распространяется на библиотеки
> вообще

Естественно, IAT ты же поправил у своего приложения, а не у библиотеки, тем более это актуально только для статической линковки функций, для динамической применяют правку EAT у библиотеки, хранящей функцию, и это будет справедливо для всех вызовов даной функции из любых модулей, загруженных в твое ВАП (опять же с учетом динамики, а не статики) :)


 
Дмитрий С   (2008-05-04 12:40) [38]

Вот оно что. Ясно.
Если вернуться к той же CreateFileW. Изменения в EAT придеться делать для Kernel32, а как это скажется на работу других процессов.
Честно говоря я не знаю точно сколько копий kernel32 храниться в памяти: одна на всех или по одной на каждый процесс.

ЗЫ. помоему для моей задачи я скоро начну изучать тему "как написать драйвер файловой системы" или типа того=)


 
Rouse_ ©   (2008-05-04 12:53) [39]


> Изменения в EAT придеться делать для Kernel32, а как это
> скажется на работу других процессов.

Никак не скажется, они об этом даже не узнают ибо:

> я не знаю точно сколько копий kernel32 храниться в памяти:
>  одна на всех или по одной на каждый процесс

образ маппится в ВАП твого процесса

> как написать драйвер файловой системы

а это уже из серии "из пушки по воробьям"...


 
oxffff ©   (2008-05-04 14:54) [40]


> Rouse_ ©   (04.05.08 12:53) [39]
>
> > Изменения в EAT придеться делать для Kernel32, а как это
>
> > скажется на работу других процессов.
>
> Никак не скажется, они об этом даже не узнают ибо:
>
> > я не знаю точно сколько копий kernel32 храниться в памяти:
>
> >  одна на всех или по одной на каждый процесс
>
> образ маппится в ВАП твого процесса
>
> > как написать драйвер файловой системы
>
> а это уже из серии "из пушки по воробьям"...


Ничего не мешает мапить разные ВАП на одно ФП.
А именно мапить кодовые сегменты PE образа.



Страницы: 1 2 вся ветка

Форум: "Прочее";
Текущий архив: 2008.06.15;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.009 c
15-1209545526
x-man
2008-04-30 12:52
2008.06.15
winapi


15-1209591059
Германн
2008-05-01 01:30
2008.06.15
Немного полегчало на душе,


2-1211282441
StiTch
2008-05-20 15:20
2008.06.15
Формула


15-1209550659
palva
2008-04-30 14:17
2008.06.15
Начнут конфисковывать


15-1209984012
switch
2008-05-05 14:40
2008.06.15
System Error. Code 1400. Invalid window handle





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский