Page 1 of 1

Injecting a delphi bpl to access a hidden TStringGrid

PostPosted: Wed Jul 22, 2015 2:20 pm
by kajondezaztre
Hi,

I don't know if this is possible maybe. you can advice me another way to do it.

I have a hidden control inside a form in a Delphi VCL application . The problem is that the control is NOT WINDOWED (TStringGrid). So i need to access it by VCL. It won't work with windows API because it's NOT WINDOWED.

I succeeded injecting a delphi package i built myself. I can call "ShowMessage" perfectly and the message is shown in the target app . The package's name is dpkinj.bpl, but it is said in internet that i won't be able to access that form because my package has actually a kind of different VCL instance. In fact , inside my injected package Application.MainForm=nil.

The code is very simple.

hprocess := OpenProcess(PROCESS_ALL_ACCESS,False, 2512);
b :=InjectLibrary (hprocess,'c:\dpkinj.bpl',7000);

Do you know another way to achieve this?.

Thanks in advance.

Re: Injecting a delphi bpl to access a hidden TStringGrid

PostPosted: Wed Jul 22, 2015 2:25 pm
by madshi
The RTL*.bpl and VCL*.bpl packages are only loaded once by each process. So if the target process loads RTL/VCL dynamically as packages, and if your packages is compiled the same way, then you should share the same RTL and VCL with the application. It's very important that you use exactly the same Delphi version, though, otherwise it won't work.

One thing I don't know is this: Delphi has a "LoadPackage" function, or something like that, IIRC. I'm not sure if it does anything more than LoadLibrary. If it does, this will probably be missing for your package, because madCodeHook only simply calls LoadLibrary. I don't know the exact implications of that.

Hope that helps?

Re: Injecting a delphi bpl to access a hidden TStringGrid

PostPosted: Wed Jul 22, 2015 2:43 pm
by kajondezaztre
Thanks for your fast reply.

Unfortunately The target app consists of a unique .exe. So it doesn't load packages dynamically. That's what i feared. I even tried to inject first the bpl, then the dll calls the exported "Initialize" of the bpl. This way i tried to simulate what LoadPackage does but in the context of the process. But i got the exactly same outcome, that is, a kind of new VCL instance because Application.MainForm remains nil in the package.


Here it is the code of this second attempt just in case someone finds it useful.

procedure TForm1.FormShow(Sender: TObject);
var


Result:boolean;

begin
Sleep(5000);
hprocess := OpenProcess(PROCESS_ALL_ACCESS,False,2512);
b :=InjectLibrary (hprocess,'c:\dpkinj.bpl',7000);
b :=InjectLibrary (hprocess,'c:\dll3.dll',7000);



if (b=True ) then ShowMessage('ok')
else ShowMessage('nok');

end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
UninjectLibrary(hprocess,'c:\dll3.dll');
UninjectLibrary(hprocess,'c:\dpkinj.bpl');
end;

Re: Injecting a delphi bpl to access a hidden TStringGrid

PostPosted: Wed Jul 22, 2015 3:03 pm
by kajondezaztre

Re: Injecting a delphi bpl to access a hidden TStringGrid

PostPosted: Thu Jul 23, 2015 9:27 am
by iconic
Injecting code into remote processes and involving VCL classes is not a wise idea, regardless good luck in your endeavor. Not saying it's impossible by any means, just not something intelligent to do with accessing controls in this manner

--Iconic

Re: Injecting a delphi bpl to access a hidden TStringGrid

PostPosted: Fri Jul 24, 2015 11:13 am
by kajondezaztre
GOT IT !!!!!! . IT WORKED!!!

But by means of arithmetic pointer.

First of all thank you very much madshi. I find what you do very difficult

This is what I did just in case is useful for someone.

It is supposed that the target application and target form are visible (in memory).

FIRST GET THE TFORM HWND HANDLE
---------------------------------------------

This is easy with FindWindow
handle:= FindWindow ('TForm', 'FormCaption');


SECOND GET THE DELPHI ATOM ASSOCIATED TO THE CONTROL
-----------------------------------------------------------------------

Thanks to TWinControl implementation, for every TWinControl there exists one windows Atom associated to the control. This atom contains a property whose value is the pointer to the form (Self)

Just look in the internet for RM_GetObjectInstance. This is the way I did it

Call this function that needs a callback :

EnumProps(handle,@PropEnumProc) ;

With next callback i look for the target form Atom property and the target form property value

function PropEnumProc( HWND: hwnd; Prop: LPCTSTR; hData: integer): boolean; stdcall;
var
aux:string;
begin
aux :=string(Prop);ShowMessage(aux);
if AnsiStartsStr('ControlOf',aux) then
begin
ShowMessage('entro');
ShowMessage(aux);
pDelphi:=aux; //<----------------------- This is the Atom Propery
RM_GetObjectInstance:=Cardinal(hData); // <------------------------This is the Atom Property Value RM_GetObjectInstance is global in my code
end;
end;

THIRD GET THE POINTER TO THE FORM (Self)
--------------------------------------------------------------------------
With pDelphi and windows Handle Just call like this

p:=Pointer(GetProp(handle, PAnsiChar(pDelphi))

THIRD ACCESS TO THE COMPONENTS LIST USING ARITHMETIC POINTER
--------------------------------------------------------------------------------------
pComponentsList is a variable of type PList =^List
ComponentsList is a variable of type List

p:=Pointer(GetProp(Handle, PAnsiChar(pDelphi)));
pCh:=PChar(p)+16;<--------------------------------------------------------------------THIS IS THE KEY BECAUSE IS A 32 BIT APP AND THE LIST IS 16 BYTES FORWARD THE SELF POINTER
pComponentsList:=PList(pCh);
ComponentsList:=pComponentsList^;

ITERATE OVER THE COMPONENTS LIST AND FIND THE TARGET TSTRINGGRID
-----------------------------------------------------------------------------------------------------------------------------------------------
In the loop i save the data of al the grids in txt files. THAT'S FAIRLY ENOUGH FOR ME!!!

for j:= 0 to ComponentsList.Count-1 do
begin
p:=ComponentsList[j];
pCh:=PChar(p)+8;<----------------------------------------------------------- The name of a component is 8 bytes forward th Self pointer
ps:=PString(pCh);
s:=ps^;
if AnsiStartsStr('StringGrid',s) then
begin
tsg:=TStringGrid(PChar(p));
SaveStringGrid(tsg,'C:\'+s+'.txt');
end;
end;





THAT'S ALL FOLKS ;)

Re: Injecting a delphi bpl to access a hidden TStringGrid

PostPosted: Fri Jul 24, 2015 11:21 am
by kajondezaztre
A correction .

RM_GetObjectInstance contains the Self pointer, but i recover it again with the global variable pDelphi i previously filled in PropEnumProc using the call

p:=Pointer(GetProp(Handle, PAnsiChar(pDelphi)));