Can the following Function be used "as is" as Remo

delphi package - getting into other processes
Post Reply
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

Can the following Function be used "as is" as Remo

Post by vmars »

Can the following Function be used "as is" as:
a MadRemote thread function, which will be copied to and then executed in the context of another process.
If not, please what will need to be changed?
Thanks!

function LB_GetAllItems(hWnd: THandle; sl: TStrings): string; stdcall;
var
RetBuffer: string;
i, x, y: Integer;
begin
x := SendMessage(hWnd, LB_GETCOUNT, 0, 0);
for i := 0 to x - 1 do
begin
y := SendMessage(hWnd, LB_GETTEXTLEN, i, 0);
SetLength(RetBuffer, y);
SendMessage(hWnd, WM_GETTEXT, i, lParam(PChar(RetBuffer)));
sl.Add(RetBuffer);
end;
end;

...Vern
madshi
Site Admin
Posts: 10749
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

No, that doesn't work. Using "string" ends up in calling all kinds of Delphi magic RTL functions, which are not available in the other process. TStrings methods are also not available in the other process.

You can use a different solution, though:

(1) LB_GETCOUNT and LB_GETTEXTLEN work directly without any fancy stuff, anyway.
(2) Allocate memory in the other process by using madRemote.AllocMemEx.
(3) Use SendMessage from your program, but give in the buffer you just allocated in (2).
(4) Use ReadProcessMemory to copy the content of the buffer to your own process.
(5) Use madRemote.FreeMemEx to free the memory in the other process again.

Done.
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

Post by vmars »

Still same old battle:
LB_GETCOUNT works fine.
But LB_GETTEXTLEN and WM_GETTEXT rquire that i be attached to that process somehow. As is, LB_GETTEXTLEN always returns a length of 4 (length of pointer).
So, as you say, i've got to change Tstrings and Strings to some thing else:
Will type RECORDS work, and pass stuff back and forth
one line at a time?
I am hoping to whittle it down to your
function GetCmdLineThread(buffer: pchar) : dword; stdcall;
example, one line at a time.
Thanks!...Vern


function LB_GetAllItems(hWnd: THandle; sl: TStrings): string;
var
RetBuffer: string;
i, x, y: Integer;
params : pointer; pid, processHandle: dword;
begin
x := SendMessage(hWnd, LB_GETCOUNT, 0, 0);
If x > 0 Then
Begin
GetWindowThreadProcessID(hWnd, @pid);
processHandle := OpenProcess(PROCESS_ALL_ACCESS, false, pid);
params := AllocMemEx(MAX_PATH, processHandle);
for i := 0 to x - 1 do
begin
y := SendMessage(hWnd, LB_GETTEXTLEN, i, 0);
SetLength(RetBuffer, y);
SendMessage(hWnd, WM_GETTEXT, i, lParam(PChar(params)));
RetBuffer := PChar(params);
ShowMessage('RetBuffer = ' + RetBuffer);
sl.Add(RetBuffer);
end; // for i := 0 to x - 1 do
CloseHandle(processHandle);
FreeMemEx(params, processHandle);
end; // If x > 0 Then
end;
madshi
Site Admin
Posts: 10749
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

There are a few errors in your code:

(1) You shouldn't use WM_GETTEXT on a list box. Use LB_GETTEXT instead.
(2) You can't use "RetBuffer := PChar(params)", because params is a pointer which is valid only in the other process. Instead use ReadProcessMemory to copy the content of params to RetBuffer.
(3) The following code is obviously wrong:

CloseHandle(processHandle);
FreeMemEx(params, processHandle);

You can't close a process handle and then use it one line later!
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

Post by vmars »

1 Ok, i was switching them back and forth, trying to get one or other to work. Will stick with LB.
2. Instead use ReadProcessMemory to copy the content of params to RetBuffer.
Aha, that's where ReadProcessMemory comes in.
3. Oops.
Thanks!

What i would like to do in your
function GetCmdLineThread(buffer: pchar) : dword; stdcall;
Is to add another parameter:

function GetCmdLineThread(buffer: pchar; GetLineNum: Integer) : dword; stdcall;

But can't get passed:
th := CreateRemoteThreadEx(processHandle, nil, 0, entryPoint, params, 0, tid);
In function GetProcessCmdLine
When i change it to this:
th := CreateRemoteThreadEx(processHandle, nil, 0, entryPoint, (params, pLineNum), 0, tid);

Please, how would i do this?
Thanks!
madshi
Site Admin
Posts: 10749
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

You can't. Remote threads only accept one parameter. You could allocate a memory block in the other process and store all parameters there and then pass the address to that block to the remote thread.

But why using remote threads at all? The solution I suggested should definately work - without remote threads. It's faster and better that way.
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

Owner Drawn ListBox

Post by vmars »

The code below runs, but ReadProcessMemory always returns #0(s) in RetBuffer.
LB_GETTEXTLEN always returns 4 in y , so i plugged 'len' with 260 to match RemoteBuff.
I believe LB_GETTEXTLEN must run in remote process; hWnd is OwnerDrawn ListBox,
which is why i have been leaning toward converting your 'RemoteCmdLine.dpr'.


Function LB_GetAllItems(hWnd: THandle; sl: TStrings): string;
var
RetBuffer: string;
i, x, y : Integer; len : dword;
RemoteBuff : pointer; pid, processHandle: dword;
begin
x := SendMessage(hWnd, LB_GETCOUNT, 0, 0);
If x > 0 Then
Begin
GetWindowThreadProcessID(hWnd, @pid);
// hWnd is OwnerDrawn ListBox
processHandle := OpenProcess(PROCESS_ALL_ACCESS, false, pid);
RemoteBuff := AllocMemEx(MAX_PATH, processHandle);
for i := 0 to x - 1 do
begin
len := 260;
y := SendMessage(hWnd, LB_GETTEXTLEN, i, 0);
SetLength(RetBuffer, 260);
SendMessage(hWnd, LB_GETTEXT, i, lParam(PChar(RemoteBuff)));
ReadProcessMemory(processHandle, RemoteBuff, pointer(RetBuffer), len, len);
// ShowMessage('RetBuffer = ' + RetBuffer);
sl.Add(RetBuffer);
end; // for i := 0 to x - 1 do
FreeMemEx(RemoteBuff, processHandle);
CloseHandle(processHandle);
end; // If x > 0 Then
end;

procedure TForm1.GetAllItemsClick(Sender: TObject);
var
sl: TStringList;
ListBox_Handle: THandle;
begin
ListBox_Handle := hWnd; // listbox handle global
sl := TStringList.Create;
try
LB_GetAllItems(ListBox_Handle, sl);
finally
ListBox1.Lines.Text := sl.Text;
sl.Free;
end;
end;
madshi
Site Admin
Posts: 10749
Joined: Sun Mar 21, 2004 5:25 pm

Re: Owner Drawn ListBox

Post by madshi »

vmars wrote:I believe LB_GETTEXTLEN must run in remote process
Wrong.
vmars wrote:hWnd is OwnerDrawn ListBox
Oh, then forget it. LB_GETTEXTLEN won't work in that case, regardless from which process you call it. "RemoteCmdLine" won't help, either.

The only thing which might work is hooking TextOutA/W and ExtTextOutA/W and then invalidating the listbox, hoping that it's not double buffered. For that purpose you must use madCodeHook and put all the hooking code into a hook dll. That's gonna be difficult.
Post Reply