Delphi Код:
{$R *.dfm}
Procedure TForm1.GetDllMes1(var Msg:TMessage);
begin
{запомним в глобальную переменную чтоб потом использовать этот адрес для вызова функции удаленным потоком из ДЛЛ внутри жертвы}
pAdrFunc1:= pointer(Msg.WParam);
form1.memo1.lines.Add('DLL говорит Mes1: адрес Func1= ' + inttostr(cardinal(Msg.WParam)));
end;
Procedure TForm1.GetDllMes2(var Msg:TMessage);
begin
pAdrFunc2:= pointer(Msg.WParam);
form1.memo1.lines.Add('DLL говорит Mes2: адрес Func2= ' + inttostr(cardinal(Msg.WParam)));
end;
Procedure TForm1.GetDllMes3(var Msg:TMessage);
var
tempBOOL: Boolean;
OldPipeHandle: THandle;
DupPipeHandle: THandle;
car:cardinal;
s: string[40];
CapHandle:THandle;
begin
form1.memo1.lines.Add('DLL говорит Mes3. WParam=' + inttostr(Msg.WParam) + ' LParam=' + inttostr(Msg.LParam));
//в WParam мы принимаем Handle для чтения из пайпа. чтобы с ним работать надо сделать дубликат для САР процесса
{function DuplicateHandle(
hSourceProcessHandle, // дескриптор процесса источника
hSourceHandle, // исходный дескриптор
hTargetProcessHandle: THandle; // дескриптор процесса приемника
lpTargetHandle: PHandle; // дубликат исходного дескриптора
dwDesiredAccess: DWORD; // флаги доступа к объекту
bInheritHandle: BOOL; // наследование дескриптора
dwOptions: DWORD // дополнительные необязательные флаги
): BOOL; stdcall;
хэндлы (их 2 на чтение и запись) на пайп созданный нами в ДЛЛ действительны только в пределах процесса
который их создал (жертва,длл) мы их сюда переслали сообщением в САР но они тут не работоспособными оказываются.
чтобы вернуть им работоспособность в другом процессе нужно их прогнать через апи DuplicateHandle которая
создаст екземляр хэндла специально настроенного для этого приложения. сам пайп останется прежним а хэндл изменится.}
//вытаскиваем из сообщения хэндл на чтение, который надо приспособить для работы в САР. он изменится поэтому назвал Old
OldPipeHandle:=cardinal(Msg.WParam);
{открываем свой этот процесс САР чтобы получить к нему хэндл управления. этот хэндл используется как
аргумент потом для DuplicateHandle}
CapHandle := OpenProcess(PROCESS_ALL_ACCESS, false, GetCurrentProcessId);
{ну и создаем работоспособную копию хэндла для чтения из пайпа. делаем типа локальную копию хэндла, но не самого пайпа}
tempBOOL := DuplicateHandle(g_DllHandle, OldPipeHandle, CapHandle, @DupPipeHandle, 0, false, DUPLICATE_SAME_ACCESS);
{ранее в кнопке2 мы открыли хэндл чужого процесса(ДЛЛ) и запомнили его в глобальную переменную.g_DllHandle
и специально не закрыли его в конце инъекции. он остался открытым. если мы там его закроем то дублирование не сработает.
закроем хэндл чужого процесса потом как нибудь.. мы про него помним.. верим.. предлагаю читателю самому придумать место где
его закрыть и когда.}
{если Дублирование глючит разбираемся что за ошибка, анализируя значение car в гугле применительно к DuplicateHandle}
//if tempBOOL = false then car:=getlasterror;
//Form1.memo1.lines.Add('err=' + inttostr(car) );
//если дублирование сработало то равно =1 (тру)
Form1.memo1.lines.Add('DuplicateHandle=' + inttostr(cardinal(tempBOOL)) );
{в LParam мы принимаем длинну данных которая ожидает обработки в пайпе. но никак не используем эти данные.
у кавото появятся идеи потом как юзать второе поле с какойто целью.}
//теперь попробуем воспользоваться дубликатом хэндла для чтения из пайпа.
SetLength(s , Msg.Lparam);
ReadFile(DupPipeHandle , s , Msg.LParam+1 , car, nil);
{мб это к файлам относится но не к пайпам но мысль такая: При вызове функции чтения/записи функция сразу возвращает
управление со значение FALSE и с кодом ошибки ERROR_IO_PENDING. Объект событие, указанное в поле hEvent
переводится в так называемое «сигнальное» состояние только после завершения операции. Если надо подождать
завершения операции надо использовать функцию WaitForSingleObject.}
Form1.memo1.lines.Add('прочли байт из пайпа =' + inttostr(car));
Form1.memo1.lines.Add('длл нам прислала пакет с данными =' + string(s));
Form1.memo1.lines.Add('length(s) =' + inttostr(length(s)) );
{как я понял Pipe (канал) это по сути файл. и писать и читать из него используются апи работы с файлами.
ReadFile WriteFile. но в отличии от настоящего файла пайп по стеку дров до диска не доходит..
а тока до какогото уровня в стеке дров.. там где файл как таковой формируется.. на диск он не уходит..
гдето в ядре виндоса в голове он живет. а доступ к нему по имени может быть как у файла типа "//./name" или по хендлу,
мы работаем с безымянным, анонимным пайпом. у него имени нет а есть только 2 хэндла для записи и чтения, которые задаются
системой при его создании. пусть будет Пайп это виртуальный файл. или недофайл.}
{иногда в логах возникает возникает ситуация что сначала mes3 обрабатывается а потом mes2. а порой сначала mes2 а потом mes3
вопщем то норм. mes2 мы посылаем через PostMessage асинхронно. а значит она обработается хз когда непредсказуемо.}
CloseHandle(CapHandle);//убрались за собой
CloseHandle(DupPipeHandle);
CloseHandle(g_DllHandle);
//ну мы помним что в памяти у нас еще 2 открытых хэндла остались висеть. хэндл на пайп и хэндл на жертву.
{пользуйтесь ProcessExplorer чтобы следить выгрузился процесс или нет и пришибить его силой.
там видно как ДЛЛ заинектилась к жертве. полезно.}
end;
Procedure TForm1.GetDllMesCD(var Msg:TWMCopyData);
begin
form1.memo1.lines.Add('medCD');
form1.memo1.lines.Add('DLL говорит MesCD. WParam=' + Msg.Msg.ToString + ' LParam=' + inttostr(0));
{тут я хотел прием сообщения типа WM_COPYDATA заюзать но нихрена не вышло, с помощью WM_COPYDATA можно
область памяти (структуру) из одного приложения в другое переслать. 2мя параметрами указатель и длинна данных.
я не смог это реализовать и поэтому раскурил пайпы которые мне кажутся очень простыми и понятными в использовании}
end;
procedure TForm1.Button1Click(Sender: TObject);
{в кнопке 1 динамически подключается ДЛЛка (сами к себе) (к САР) и вызывается одна из ее функций.
статическое подключение- это когда при запуске все ДЛЛки загружаются сразу с ЕХЕ прогой
а динамическое подключение может быть во время выполнения программы}
var
Func1: TPlusDLL;
PiHandle: THandle;//Дескриптор — это уникальный номер, который присваивается каждому объекту, созданному с помощью Win API.
//Конкретное значение дескриптора не несёт для программиста никакой полезной информации и может быть использовано
//только для того, чтобы при вызове функций из Win API указывать, с каким объектом требуется выполнить операцию.
begin
//Программа может загружать DLL и без External с помощью трех cтандартных функций : LoadLibrary, GetProcAddress И FreeLibrary.
//получаем идентификатор(Хэндл) библиотеки
//при загрузки библиотеки выполнится код из основного блока библиотеки. begin..end - в конце ДЛЛки это ее основной блок
PiHandle := LoadLibrary('Pi.dll');
if PiHandle <> 0 then memo1.Lines.Add('Pi.dll загружена в память') else memo1.Lines.Add('Pi.dll загрузить не вышло');
//получаем точку входа в подпрограмму (адрес) которую экспортирует библиотека по имени подпрограммы(функции)
//можно узнать адрес и по индексу подпрограммы @AddC := GetProcAddress(Handle, PChar(Longint(1))); При вызове по индексу
//младшее слово PChar должно содержать индекс, поэтому делаем приведение типов
@Func1:= GetProcAddress(PiHandle, 'Func1');
//используем импортированную подпрограмму из длл, вызываем ее.
memo1.Lines.Add(inttostr(Func1(2)));
//выгружаем библиотеку
FreeLibrary(PiHandle);
end;