Форум: "WinAPI";
Текущий архив: 2004.08.08;
Скачать: [xml.tar.bz2];
ВнизПЕрехват АПИ Найти похожие ветки
← →
juiceman (2004-06-27 23:20) [0]Перехват АПИ-вызовов на Delphi. Существует ли исходник кроме как Ketmara ? На сях ведь их куча, а на паскале вообще никогда не видел. Delphi-программисты более ленивые ? )))
← →
Игорь Шевченко © (2004-06-27 23:44) [1]
> Существует ли исходник кроме как Ketmara ?
Существует. Об исходнике Ketmar"а слышу впервые. Есть у Digitman"а, есть у меня.
← →
Ihor Osov'yak © (2004-06-28 00:12) [2]Ну, года два-три назад я баловался.. Даже чего-то перехватывало. Даже то, что нужно. В принцыпе, делалось не с нуля, отыскал какой-то не совсем рабочий прообраз на безымяном китайском сайте..
← →
KilkennyCat © (2004-06-28 00:31) [3]
> Ihor Osov"yak © (28.06.04 00:12) [2]
Вау, китайские иероглифы в комментариях! :)
← →
juiceman (2004-06-28 00:35) [4]2Игорь Шевченко ©
У меня тут все проблема с самими перехватом, внедрение - пройденый этап. Прочитал у Рихтера что заменяя байты на входе функции могут возникнуть проблемы, через отладку (это и есть как я выразился исходник Ketmara : "Использование Debug API: пример перехвата вызовов функций Win32 API ") тоже нет желания делать, зачем загонять процесс под отладчик? Так вот, Рихтер говорит что наилучший способ это через таблицу импорта. Не получается.
А каким способом Вы эту часть реализовали?
← →
Ihor Osov'yak © (2004-06-28 01:08) [5]2 [3] KilkennyCat © (28.06.04 00:31)
да нет, это только сайт китайский, исходник - непонятно чей..
2 [4] juiceman (28.06.04 00:35)
Извинит меня Игорь наверное, что я перед отца в пекло - примерно так и делалось. Бросаю два ключевых модуля, как есть, наверное можно разобраться, за качество кода сорри, чем багаты - тем и рады (первый модулек - декларации - практически в первозданном виде), второй -я там основательно погулял. Также смутно припоминаю, что права на запись памяти -
GetRight - не очень то удачно сделано, но сейчас уже вспоминать неохота.
Во втором модуля оставлен перехват только нескольких функций, остальные - вырезаны, а то код слишком большой. Модуль после вырезания - компилируется.
WrTm - отладочный вывод, glob_e0capt - модуль, в котором декларировано несколько несущественніх глобальных переменных..
Внедрение - при помощи хука, это за пределами этих модульковunit PEStuff;
interface
uses Windows;
type
PImageDosHeader = ^TImageDosHeader;
_IMAGE_DOS_HEADER = packed record { DOS .EXE header }
e_magic: Word; { Magic umber }
e_cblp: Word; { Bytes on last page of file }
e_cp: Word; { Pages in file }
e_crlc: Word; { Relocations }
e_cparhdr: Word; { Size of header in paragraphs }
e_minalloc: Word; { Minimum extra paragraphs needed }
e_maxalloc: Word; { Maximum extra paragraphs needed }
e_ss: Word; { Initial (relative) SS value }
e_sp: Word; { Initial SP value }
e_csum: Word; { Checksum }
e_ip: Word; { Initial IP value }
e_cs: Word; { Initial (relative) CS value }
e_lfarlc: Word; { File address of relocation table }
e_ovno: Word; { Overlay number }
e_res: array[0..3] of Word; { Reserved words }
e_oemid: Word; { OEM identifier (for e_oeminfo) }
e_oeminfo: Word; { OEM information; e_oemid specific}
e_res2: array[0..9] of Word; { Reserved words }
_lfanew: LongInt; { File address of new exe header }
end;
TImageDosHeader = _IMAGE_DOS_HEADER;
PIMAGE_FILE_HEADER = ^IMAGE_FILE_HEADER;
IMAGE_FILE_HEADER = packed record
Machine: WORD;
NumberOfSections: WORD;
TimeDateStamp: DWORD;
PointerToSymbolTable: DWORD;
NumberOfSymbols: DWORD;
SizeOfOptionalHeader: WORD;
Characteristics: WORD;
end;
PIMAGE_DATA_DIRECTORY = ^IMAGE_DATA_DIRECTORY;
IMAGE_DATA_DIRECTORY = packed record
VirtualAddress: DWORD;
Size: DWORD;
end;
PIMAGE_SECTION_HEADER = ^IMAGE_SECTION_HEADER;
IMAGE_SECTION_HEADER = packed record
Name: packed array[0..IMAGE_SIZEOF_SHORT_NAME - 1] of
Char;
VirtualSize: DWORD; // or VirtualSize (union);
VirtualAddress: DWORD;
SizeOfRawData: DWORD;
PointerToRawData: DWORD;
PointerToRelocations: DWORD;
PointerToLinenumbers: DWORD;
NumberOfRelocations: WORD;
NumberOfLinenumbers: WORD;
Characteristics: DWORD;
end;
PIMAGE_OPTIONAL_HEADER = ^IMAGE_OPTIONAL_HEADER;
IMAGE_OPTIONAL_HEADER = packed record
{ Standard fields. }
Magic: WORD;
MajorLinkerVersion: Byte;
MinorLinkerVersion: Byte;
SizeOfCode: DWORD;
SizeOfInitializedData: DWORD;
SizeOfUninitializedData: DWORD;
AddressOfEntryPoint: DWORD;
BaseOfCode: DWORD;
BaseOfData: DWORD;
{ NT additional fields. }
ImageBase: DWORD;
SectionAlignment: DWORD;
FileAlignment: DWORD;
MajorOperatingSystemVersion: WORD;
MinorOperatingSystemVersion: WORD;
MajorImageVersion: WORD;
MinorImageVersion: WORD;
MajorSubsystemVersion: WORD;
MinorSubsystemVersion: WORD;
Reserved1: DWORD;
SizeOfImage: DWORD;
SizeOfHeaders: DWORD;
CheckSum: DWORD;
Subsystem: WORD;
DllCharacteristics: WORD;
SizeOfStackReserve: DWORD;
SizeOfStackCommit: DWORD;
SizeOfHeapReserve: DWORD;
SizeOfHeapCommit: DWORD;
LoaderFlags: DWORD;
NumberOfRvaAndSizes: DWORD;
DataDirectory: packed array
[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of IMAGE_DATA_DIRECTORY;
Sections: packed array[0..9999] of IMAGE_SECTION_HEADER;
end;
PIMAGE_NT_HEADERS = ^IMAGE_NT_HEADERS;
IMAGE_NT_HEADERS = packed record
Signature: DWORD;
FileHeader: IMAGE_FILE_HEADER;
OptionalHeader: IMAGE_OPTIONAL_HEADER;
end;
PImageNtHeaders = PIMAGE_NT_HEADERS;
TImageNtHeaders = IMAGE_NT_HEADERS;
{ PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;
IMAGE_IMPORT_DESCRIPTOR = packed record
Characteristics: DWORD; // or original first thunk
// 0 for terminating null import descriptor
// RVA to original unbound IAT TimeDateStamp: DWORD;
// 0 if not bound,
// -1 if bound, and real date\time stamp
// in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
// O.W. date/time stamp of DLL bound to (Old BIND)
Name: DWORD;
FirstThunk: DWORD; // PIMAGE_THUNK_DATA // RVA to IAT (if bound this IAT has actual addresses)
ForwarderChain: DWORD; // -1 if no forwarders
end;
TImageImportDescriptor = IMAGE_IMPORT_DESCRIPTOR;
PImageImportDescriptor = PIMAGE_IMPORT_DESCRIPTOR;}
PIMAGE_IMPORT_BY_NAME = ^IMAGE_IMPORT_BY_NAME;
IMAGE_IMPORT_BY_NAME = record
Hint: Word;
Name: array[0..0] of Char;
end;
PIMAGE_THUNK_DATA = ^IMAGE_THUNK_DATA;
IMAGE_THUNK_DATA = record
Whatever: DWORD;
end;
PImage_Import_Entry = ^Image_Import_Entry;
Image_Import_Entry = record
Characteristics: DWORD;
TimeDateStamp: DWORD;
MajorVersion: Word;
MinorVersion: Word;
Name: DWORD;
LookupTable: DWORD;
end;
const
IMAGE_DOS_SIGNATURE = $5A4D; // MZ
IMAGE_OS2_SIGNATURE = $454E; // NE
IMAGE_OS2_SIGNATURE_LE = $454C; // LE
IMAGE_VXD_SIGNATURE = $454C; // LE
IMAGE_NT_SIGNATURE = $00004550; // PE00
implementation
end.
← →
Ihor Osov'yak © (2004-06-28 01:12) [6]
unit HookTextUnit;
interface
uses Windows, SysUtils, Classes, PEStuff;
type
TConvertTextFunction = function(text: string): string;
TTextOutA = function(hdc: HDC; x, y: Integer; text: PAnsiChar; len: Integer): BOOL; stdcall;
TTextOutW = function(hdc: HDC; x, y: Integer; text: PWideChar; len: Integer): BOOL; stdcall;
TExtTextOutA = function(hdc: HDC; x, y: Integer; Options: DWORD; Clip:
PRect; text: PAnsiChar; len: Integer; dx: PInteger): BOOL; stdcall;
TExtTextOutW = function(hdc: HDC; x, y: Integer; Options: DWORD;
Clip: PRect; text: PWideChar; len: Integer; dx: PInteger): BOOL; stdcall;
TDrawTextA = function(hdc: HDC; text: PAnsiChar; len: Integer; rect: PRect; Format: DWORD): Integer; stdcall;
TDrawTextW = function(hdc: HDC; text: PWideChar; len: Integer; rect: PRect; Format: DWORD): Integer; stdcall;
TDrawTextExA = function(hdc: HDC; text: PAnsiChar; len: Integer; rect: PRect; Format: DWORD;
DTParams: PDrawTextParams): Integer; stdcall;
TDrawTextExW = function(hdc: HDC; text: PWideChar; len: Integer; rect: PRect;
Format: DWORD; DTParams: PDrawTextParams): Integer; stdcall;
PPointer = ^Pointer;
TImportCode = packed record
JumpInstruction: Word; // should be $25FF
AddressOfPointerToFunction: PPointer;
end;
PImportCode = ^TImportCode;
procedure HookTextOut(aConvertFunction: TConvertTextFunction);
procedure UnhookTextOut;
implementation
uses glob_e0capt, messages;
var
ConvertTextFunction: TConvertTextFunction = nil;
OldTextOutA: TTextOutA = nil;
OldTextOutW: TTextOutW = nil;
OldExtTextOutA: TExtTextOutA = nil;
OldExtTextOutW: TExtTextOutW = nil;
OldDrawTextA: TDrawTextA = nil;
OldDrawTextW: TDrawTextW = nil;
OldDrawTextExA: TDrawTextExA = nil;
OldDrawTextExW: TDrawTextExW = nil;
function StrLenW(s: PWideChar): Integer;
var
i: Integer;
begin
if s = nil then
begin
Result := 0;
exit;
end;
i := 0;
try
while (s[i] <> #0) do
inc(i);
except
end;
Result := i;
end;
var
sumStr: string;
countStep: integer;
procedure SendCapturedText(Y: integer; aStr: string);
var
cd: TCopyDataStruct;
begin
if sumStr <> "" then
sumStr := sumStr + ";";
inc(countStep);
sumStr := sumStr + aStr;
if countStep < 4 then
exit;
cd.dwData := Y;
cd.cbData := Length(sumStr) + 1;
cd.lpData := PChar(sumStr);
SendMessage(toolsHandle, WM_COPYDATA,
0,
LParam(@cd));
countStep := 0;
sumStr := "";
end;
function NewTextOutA(hdc: HDC; x, y: Integer; text: PAnsiChar; len:
Integer): BOOL; stdcall;
var
s: string;
begin
if enCapture then
if WindowFromDC(hdc) = handleForCapture then
begin
try
if len <= 0 then
s := text
else
begin
SetLength(s, len);
FillChar(s[1], len + 1, 0);
Move(text^, s[1], len);
end;
if x = 0 then
SendCapturedText(Y, s);
WrTm("hdc= " + IntToHex(hdc, 8) + " x= " + IntToStr(x) + " y= " + IntToStr(y) + " text = " + s);
SetLength(s, 0);
except
end;
end;
if @OldTextOutA <> nil then
Result := OldTextOutA(hdc, x, y, text, len)
else
Result := false;
end;
далее пропускаю код остальных перехватчиков и далее снова содержательная часть
← →
Ihor Osov'yak © (2004-06-28 01:13) [7]
function NewDrawTextExW(hdc: HDC; text: PWideChar; len: Integer; rect:
PRect;
Format: DWORD; DTParams: PDrawTextParams): Integer; stdcall;
var
s: WideString;
begin
Result := 0;
exit;
try
if Len < 0 then
Len := strlenW(text);
if Len > 0 then
begin
SetLength(s, len);
FillChar(s[1], len * 2 + 2, 0);
Move(text^, s[1], len * 2);
if @ConvertTextFunction <> nil then
s := ConvertTextFunction(s);
if @OldDrawTextExW <> nil then
Result := OldDrawTextExW(hdc, PWideChar(s), length(s), rect, Format, DTParams)
else
Result := 0;
end
else
Result := OldDrawTextExW(hdc, text, 0, rect, Format, DTParams);
except
Result := 0;
end;
end;
function PointerToFunctionAddress(Code: Pointer): PPointer;
var
func: PImportCode;
begin
Result := nil;
if Code = nil then
exit;
try
func := code;
if (func.JumpInstruction = $25FF) then
begin
Result := func.AddressOfPointerToFunction;
end;
except
Result := nil;
end;
end;
function FinalFunctionAddress(Code: Pointer): Pointer;
var
func: PImportCode;
begin
Result := Code;
if Code = nil then
exit;
try
func := code;
if (func.JumpInstruction = $25FF) then
begin
Result := func.AddressOfPointerToFunction^;
end;
except
Result := nil;
end;
end;
procedure GetRight;
var
si: TSYSTEMINFO;
mi: TMEMORYBASICINFORMATION;
p: cardinal;
dw: dword;
//cb:Tcb;
begin
GetSystemInfo(si);
p := cardinal(si.lpMinimumApplicationAddress);
while (p < cardinal(si.lpMaximumApplicationAddress)) (*and (HeapsCount<MAX_HEAPS)*) do
begin
VirtualQueryEx(GetCurrentProcess, Pointer(p), mi, sizeof(mi));
//Heaps[HeapsCount].Offset := p;
//Heaps[HeapsCount].Size := mi.RegionSize;
//Heaps[HeapsCount].Valid := (mi.State = MEM_COMMIT);
//Data:=Pointer(HeapsCount);
VirtualProtectEx(GetCurrentProcess, pointer(p), mi.RegionSize,
PAGE_EXECUTE_READWRITE, @dw);
Inc(p, mi.RegionSize);
//inc(HeapsCount);
end;
end;
var
level: integer;
function PatchAddress(OldFunc, NewFunc: Pointer): Integer;
var
BeenDone: TList;
function PatchAddressInModule(hModule: THandle;
OldFunc, NewFunc: Pointer): Integer;
var
Dos: PImageDosHeader;
NT: PImageNTHeaders;
ImportDesc: PImage_Import_Entry;
rva: DWORD;
Func: PPointer;
DLL: string;
f: Pointer;
written: DWORD;
sb: string;
i: integer;
begin
inc(level);
sb := " ";
for i := 1 to level * 3 do
sb := sb + " ";
Result := 0;
Dos := Pointer(hModule);
//Wr("");
//WrTm(sb+"cp745: start tru");
if BeenDone.IndexOf(Dos) >= 0 then
begin
dec(level);
exit;
end;
//WrTm(sb+"cp761");
BeenDone.Add(Dos);
OldFunc := FinalFunctionAddress(OldFunc);
if IsBadReadPtr(Dos, SizeOf(TImageDosHeader)) then
begin
dec(level);
exit;
end;
//WrTm(sb+"cp768");
if Dos.e_magic <> IMAGE_DOS_SIGNATURE then
begin
dec(level);
exit;
end;
//WrTm(sb+"cp773");
NT := Pointer(Integer(Dos) + dos._lfanew);
// if IsBadReadPtr(NT,SizeOf(TImageNtHeaders)) then exit;
RVA := NT^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if RVA = 0 then
exit;
//WrTm(sb+"cp780 before loop1");
ImportDesc := pointer(dword(Dos) + RVA);
while (ImportDesc^.Name <> 0) do
begin
DLL := PChar(dword(Dos) + ImportDesc^.Name);
//WrTm(Dll);
//WrTm(sb+"cp785 tru pach in "+Dll);
PatchAddressInModule(GetModuleHandle(PChar(DLL)), OldFunc, NewFunc);
//WrTm(sb+"cp788 after tru "+Dll);
//WrTm(sb+"cp789 before loop2");
Func := Pointer(dword(DOS) + ImportDesc.LookupTable);
while Func^ <> nil do
begin
//WrTm(sb+"cp792 Func="+IntToHex(integer(Func),8)+" "+IntToHex(integer(Func^),8));
f := FinalFunctionAddress(Func^);
//WrTm(sb+"cp794 f ="+IntToHex(integer(f),8));
//WrTm(sb+"cp795 oldf ="+IntToHex(integer(OldFunc),8));
if f = OldFunc then
begin
//WrTm(sb+"cp794");
//WrTm(sb+Dll);
WriteProcessMemory(GetCurrentProcess, Func, @NewFunc, 4, written);
//Move(NewFunc,Func^,4);
//asm
// int 3
//end;
//integer(Func^):=integer(NewFunc);
if Written > 0 then
begin
Inc(Result);
//WrTm(sb+"res<>0");
end
else
begin
//i:=Getlasterror;
//WrTm(sb+"res=0 err="+IntToHex(i,8));
end
end;
Inc(Func);
end;
//WrTm(sb+"cp805 after loop2");
Inc(ImportDesc);
end;
//WrTm(sb+"cp808 after loop1");
//WrTm(sb+"cp808: end tru");
dec(level);
end;
begin //PatchAddress
result := 0;
if NewFunc = nil then
exit;
if OldFunc = nil then
exit;
if NewFunc = OldFunc then
exit;
BeenDone := TList.Create;
try
//Wr("");
//enWr2 := ParamStr(0)="D:\!prj\SmallPrj\ScraperDB\test_v\test\Release\test.exe";
//WrTm("inp : "+IntToStr(GetModuleHandle(nil)));
//WRTm("param0: "+ParamStr(0));
Result := PatchAddressInModule(GetModuleHandle(nil), OldFunc, NewFunc);
finally
BeenDone.Free;
end;
end; //PatchAddress
procedure HookTextOut(aConvertFunction: TConvertTextFunction);
begin
//Wr("");
if @OldTextOutA = nil then
@OldTextOutA := FinalFunctionAddress(@TextOutA);
if @OldTextOutW = nil then
@OldTextOutW := FinalFunctionAddress(@TextOutW);
if @OldExtTextOutA = nil then
@OldExtTextOutA := FinalFunctionAddress(@ExtTextOutA);
if @OldExtTextOutW = nil then
@OldExtTextOutW := FinalFunctionAddress(@ExtTextOutW);
if @OldDrawTextA = nil then
@OldDrawTextA := FinalFunctionAddress(@DrawTextA);
if @OldDrawTextW = nil then
@OldDrawTextW := FinalFunctionAddress(@DrawTextW);
if @OldDrawTextExA = nil then
@OldDrawTextExA := FinalFunctionAddress(@DrawTextExA);
if @OldDrawTextExW = nil then
@OldDrawTextExW := FinalFunctionAddress(@DrawTextExW);
@ConvertTextFunction := @aConvertFunction;
GetRight;
PatchAddress(@OldTextOutA, @NewTextOutA);
PatchAddress(@OldTextOutW, @NewTextOutW);
end;
procedure UnhookTextOut;
begin
//If @OldTextOutA<>nil then begin
PatchAddress(@NewTextOutA, @OldTextOutA);
PatchAddress(@NewTextOutW, @OldTextOutW);
PatchAddress(@NewExtTextOutA, @OldExtTextOutA);
PatchAddress(@NewExtTextOutW, @OldExtTextOutW);
PatchAddress(@NewDrawTextA, @OldDrawTextA);
PatchAddress(@NewDrawTextW, @OldDrawTextW);
PatchAddress(@NewDrawTextExA, @OldDrawTextExA);
PatchAddress(@NewDrawTextExW, @OldDrawTextExW);
// end;
end;
initialization
finalization
UnhookTextOut;
end.
← →
juiceman (2004-06-28 01:39) [8]Ух, ну Вы мне приятный сюрприз преподнесли, буду копаться %) Огромное спасибо!!!
← →
Ihor Osov'yak © (2004-06-28 01:56) [9]2 [8] juiceman (28.06.04 01:39)
Копайся, копайся. Это заведомо в лучшем состоянии, чем я получил тогда.. За код сильно не ругать, я в общем-то тогда системными вещами только начинал заниматься, так что в коде могут быть ляпы, но проект работоспособный.
← →
Digitman © (2004-06-28 08:15) [10]
> juiceman
при реализации перехвата требуется правка не только таблицы импорта, но и таблицы экспорта.. последнее необходимо для случаев динамической загрузки библиотеки, эксп.ф-ция которой перехватывается ... если не править таблицу экспорта, то GetProcAddr() вернет старую (оригинальную) точку входа
таблица же импорта правится только для случая стат.загрузки
← →
Игорь Шевченко © (2004-06-28 10:25) [11]Неплохая методика перехвата была описана у Гэри Неббета, в его книжке "Справочник по функциям базового API для Windows NT", с примером. Но не на Delphi, разумеется
← →
Ihor Osov'yak © (2004-06-28 12:40) [12]2 [10] Digitman © (28.06.04 08:15)
> если не править таблицу экспорта, то GetProcAddr() вернет старую (оригинальную) точку входа
Несообразил. Вернее соображал, что GetProcAddr будет возращать оригинальную точку входа, но бороться с этим планировал в случае необходимости (в том проекте такой необходимомти не возникло) методом перехвата того же GetProcAddr. Но правка таблицы экспорта заметно изящнее. Спасибо. Если придется снова делать что-то похожее - учту.
> [11] Игорь Шевченко © (28.06.04 10:25)
Стоит на полке. Руки не доходят серьезно заняться. И что за жизнь такая - раньше доступа к информации не было, теперь информация есть, времени нету ее обработать :-(
← →
Игорь Шевченко © (2004-06-28 13:38) [13]Ihor Osov"yak © (28.06.04 12:40)
Хорошая книжка :)
> И что за жизнь такая - раньше доступа к информации не было,
> теперь информация есть, времени нету ее обработать
И не говори, аналогичная ситуация :)
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2004.08.08;
Скачать: [xml.tar.bz2];
Память: 0.53 MB
Время: 0.028 c