Delphi Код:
unit Unit1;
{в коментариях будет использоваться абревиатура CAP и DLL. это ДЛЛ инжектированная, а программа управления CAP}
{то что я понял по указателям.
тип Pointer это число 4 байта которое есть адрес чегото (пусть будет обьекта)
Cardinal тоже может хранить в себе адрес.
MyPointer:=pointer(MyCardinal); - указатель наполнился смыслом. он теперь содерржит адрес чейто.
который до этого хранился в MyCardinal;
после такой операции MyPointer и MyCardinal будут хранить в себе одно и тоже число. которое есть чейто адрес.
а значит условие if cardinal(MyPointer) = MyCardinal then - сработает. также как и
if MyPointer = pointer(MyCardinal) then ..
и получается что вместо MyPointer можно использовать каст pointer(MyCardinal) это будет одно и тожэ. значит для
понимания мы вапще можем не пользоваться типом Pointer а использовать тип Cardinal с кастом pointer(MyCardinal),
и понимать что в числе MyCardinal хранится адрес чего-то.
c Cardinal нам дуступны математические операции +/- отступить или прибавить к начальному адресу 4 байта например,
а с Pointer чета это не пашет.
например в функции в качестве входного аргумента используется указатель на данные и длинна этих данных.
вот пример WriteProcessMemory(THandle, хэндл процесса в который будем писать
Pointer, адрес по которому надо записать данные (куда писать)
Pointer, адрес какие данные надо записать (что писать)
Cardinal, сколько байт писать (сколько писать)
Cardinal); (OUT) сколько байт получилось переписать (результат работы)
а в качестве данных (которые надо записать кудато в память по определенному адресу) у нас структура RECORD
тогда мы подсунем в качестве 3го аргумента @MyRecord - адрес по которому хранится наша структура.
это значит операция @MyCardinal- вернет (или компилятор эту запись подменит на..) адрес по которому
хранится переменная MyCardinal.
Возникает желание: если есть у нас область памяти: адрес и длинну этой области мы знаем, то хорошобы туда
переселить жить структуру такогоже размера как эта область.. и тогда структура поселившись там жить в эту область памяти
сразу в себя вберет все данные (заполнится). типа сделать так: @MyRecord:=pointer(MyMemAdr); круто я придумал?
но хрен там так нельзя. во первых получится утечка по старому адресу прописки структуры. во вторых новый адрес структуры
может быть уже камуто принадлежит , другой структуре. такие фокусы какбы нам недоступны. однако логически так сделать можно
было бы.
тем не менее вот пример tempBOOL := DuplicateHandle(g_DllHandle, OldPipeHandle, CapHandle, @DupPipeHandle, 0, false, DUPLICATE_SAME_ACCESS);
4й параметр выходной, @DupPipeHandle. понимать наверное это стоит так.. это всетаки не выходной параметр а входной.
апи принимает адрес по которому она запишет какието данные. вопщем переселение объектов с адреса на адрес нам не доступно.
}
{то что я понял по хэндлам.
часто мы просим систему с помощью апи создать какойто обьект за пределами памяти нашего приложения(в ядре оси)
это может быть например Pipe(пайп, канал анонимный, или недофайл). мы просим систему его создать с помощью апи,
система его создает у себя в ядре гдето, а нам для управления им дает хэндлы этого обьекта. ведь таких обьектов может быть
в системе куча созданных, как их различать? отличаются они номерком (типа порядковый номер обьекта, ИДешник индивидуальный)
итак мы сможем манипулировать Пайпом этим зная его хэндл. говорить системе с помощью апи: сделай такоето действие с папом под
номером таким-то. итак хэндл это номерок обьекта который создан нами за пределами нашего приложения гдето в системе.
вот почему нам нужно следить- раз мы его создали внутри оси то должны потом его и удалить. а то приложение отвалится а
обьект останется. хотя вроде при отвале юзерской прилы все что она насоздавала подчищается и в оси тожэ. но это не точно.
в любом случа даже во ремя работы прилы (без отвалов) стоит понимать где и что мы создали и если лишнее то почистить за собой.
итак Хэндл- это 4 байта число- которое несет в себе смысл- номерок обьекта созданного за пределами нашего приложения
гдето внутри ядра оси. взаимодействовать с этим обьектом мы можем через апи, указывая этот номерок.}
interface
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
Vcl.StdCtrls,
TlHelp32;//для работы CreateToolhelp32Snapshot-сделать снимок всех процессов, узнать PID
{номерки WinMessages для которых мы создали тут обработчики. ДЛЛ будет отсылать нам сообщения в САР
а мы их обрабатывать. Задумка такая- наладить взаимный обмен данными ДЛЛ и САР в обе стороны.
в синхронном режиме а также асинхронном режиме. что это значит?
например из из САР в ДЛЛ улетели данные (каким либо способом).
для синхронного режима нужно дождаться в САР чтоб ДЛЛ эти данные получила обработала и дала какойто ответ. тогда САР
получив ответ продолжит свою работу. это синхронно.
для асинхронного режима нужно отослать какието данные и не париться об их дальнейшей судьбе. САР отослала и продолжила
заниматься своими делами. (послал и забыл) это асинхронно.
для направления САР-ДЛЛ мы тут первым делом научимся писать данные в область памяти процесса жертвы. в кнопке №2.
а также вызывать одну из своих функций. которая сможет прочесть записанные ранее САРом данные и дать ответ. вот и синхронность.
там еще есть апи которая ожидает завершения работы вызванного ранее удаленного потока WaitForSingleObject. вопщем синхронность
достигается.
а для направления ДЛЛ-САР так сделать неполучится. потомучто чтоб писать в чужую память, приложуха писатель должна
иметь отладочные привелегии. для САР своего мы это конечно можем настроить. а для чужого процесса это делать нехочется.
мы и так в него код внедряем, еще и прав лишить и всякой прочей самостоятельности-)
для направления ДЛЛ-САР мы поступим подругому. создадим Пайп, запишем в него чтото. и уведомим САР об этом.
отправив сообщение через PostMessage. это асинхронно.
а если нам нужна синхронность то сообщение отправим через SendMessage, тогда поток в ДЛЛ отправителе- подвиснет в ожидании
когда обработчик сообщения в САР завершит свою работу (по вытаскиванию данных из пайпа) и возможно что даст какойто ответ сразу
еще надо понимать что очередь сообщений разгребает окно. наше приложение САР окно имеет и обработает сообщения.
а вот послать сообщение из САР в ДЛЛ нельзя. в длл нет такой возможности разгребать сообщения. это должен быть
постоянно включенный поток в ожидании сообщения. но вопщем то нам это и не нужно для направления САР-ДЛЛ.
повторюсь для САР-ДЛЛ мы можем скидывать данные 2мя способами, просто в область памяти их писать чужому приложению либо
в пайп также. а уведомлять об отправке данных ДЛЛ мы можем вызвав одну из своих функций из ДЛЛки (удаленным потоком)
эту технику мы тут делать научимся все легко. пример вызова своей функции из длл удаленным потоком это когда мы инжектим ДЛЛ.
аналогичным способом можно любую функцию свою вызвать.}
const
DLL_MES_1=WM_USER+1;
DLL_MES_2=WM_USER+2;
DLL_MES_3=WM_USER+3;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
Procedure GetDllMes1(var Msg:TMessage); message DLL_MES_1;//обработчики сообщений от ДЛЛки
Procedure GetDllMes2(var Msg:TMessage); message DLL_MES_2;
Procedure GetDllMes3(var Msg:TMessage); message DLL_MES_3;
Procedure GetDllMesCD(var Msg:TWMCopyData); message WM_COPYDATA;
public
{ Public declarations }
end;
type TMyRec = Record//для експериментов.
Age :Cardinal;
Name :String[20];
Fam :String[20];
End;
{это если длл прицеплять к САР, сам к себе цеплять и юзать одну из функций в длл.
это в кнопке №1 показано как сам к себе прицепить длл. я с этого начал. но потом длл усложнилась
а именно в длл добавилось основная процедура с кодом. и поэтому прицепив эту ДЛЛ к сам к себе к САР чтото пойдет не так
но код останется тут. для ознакомления он рабочий просто в ДЛЛ надо вычистить основной блок. и имена функций в порядок привести}
TPlusDLL = function(a: integer): integer; stdcall;
var
Form1: TForm1;
//RemoteThreadResult:Cardinal;
pAdrFunc1: Pointer;//адреса функций из длл инъектированной
pAdrFunc2: Pointer;
g_DllHandle: THandle;//сюда сохраним хэндл чужого процесса в который инжектируем длл. он нам нужен потом для дублирования хэндлов пайпов
{для удобства код из кнопки 2 частично вынес в функции. однако кнопку 2 не трогал. кнопка 2 какбы самостоятельна
без функций работает, чтоб весь код в кучке и последовательно перед глазами был в кнопке2}
function GetRemotePID(ProcName:string):Cardinal;
function SetDebugPrivilege(boolOnOff:boolean):Boolean;
implementation