Форум: "Прочее";
Текущий архив: 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