Which should i be using madCodeHook or madRemote or ...?

contains all delphi packages mentioned below
Post Reply
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

Which should i be using madCodeHook or madRemote or ...?

Post by vmars »

Thanks very much for this software:

Here's why i need it :
{I am having a problem: unable to get text out of a ListBox window (from a different application) WinXP, D5.
Specifically, its the win95.hlp ListBox.
I have no probs getting it out of EditBoxes or normal ListBoxes, just owner-drawn.
Anyways, i am doing:
SendMessage(hWnd, LB_GETCOUNT, 0, 0);
SendMessage(hWnd, LB_GETTEXTLEN, i, 0);
Both of these come back OK.
Then i've tried both:
SendMessage(hWnd, LB_GETTEXT, i, lParam(PChar(RetBuffer)));
SendMessage(hWnd, WM_GETTEXT, i, lParam(PChar(RetBuffer)));
but neither one returns anything:

Ultimately, what i want to do is
capture text from any window control.
}
I have written a vanilla dll and hand it the HANDLE of the ListBox.
And all i really want to do is try the LB_GETTEXT or WM_GETTEXT from within the DLL. I am told, that then it will work.

SO, i am thinking that what i need to do is InjectLibrary.
Do my business, then UninjectLibrary.

Do i even need a DLL?,
or could this attaching to an existing process be done in my program?

Given what i am trying to do (above) and since i've never used "mad" before, Perhaps i should be asking:

"which should i be using": madCodeHook or madRemote or What?

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

Post by madshi »

The problem with LB_GETTEXT is that you send a pointer to the process which owns the listbox. But each process has its own memory/address context. So a pointer which is valid in your process has no meaning in any other process. So when you send "lParam(PChar(RetBuffer))" to the other process, you're asking the other process to write the text to random memory!

You can solve it in 2 different ways:

(1) You can allocate a buffer in the target process by using madRemote.AllocMemEx. Then give in that address when using LB_GETTEXT. Next read the buffer content by using ReadProcessMemory. Finally don't forget to free the buffer by using madRemote.FreeMemEx. This all works without needing a dll.

(2) Write a little dll and inject it into the target process. You can use madCodeHook for injecting the dll. But you can also get along without madCodeHook by using SetWindowsHookEx. The dll then can use LB_GETTEXT directly, because it is loaded in the correct process memory/address context. Afterwards the dll can send the text to your application by using WM_COPYDATA.
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

P.S: Please don't cross post the same question in multiple sections. That means double the work for me!! I've deleted the other thread.
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

Access violation at adress 00448729

Post by vmars »

Thanks for your help:
Please, how have i goofed up?
I am getting errMsg:
Project Project1.exe raised exception class EAccessViolaton with message
'Access violation at adress 00448729 in module 'Project1.exe'. Read of address 00000000'.
Process stopped. Use Step or Run to continue.

stops at sl.Add(pRetBuffer^);
so must be: SendMessage(hWnd, LB_GETTEXT, i, lParam(pRetBuffer));

begin
x := SendMessage(hWnd, LB_GETCOUNT, 0, 0);
for i := 0 to x - 1 do
begin
y := SendMessage(hWnd, LB_GETTEXTLEN, i, 0);
pRetBuffer := madRemote.AllocMemEx({size}y, {processHandle} hWnd);
SendMessage(hWnd, LB_GETTEXT, i, lParam(pRetBuffer));
sl.Add(pRetBuffer^);
madRemote.FreeMemEx({mem}pRetBuffer, {processHandle} hWnd);
ShowMessage('CurrentLine = ' + sl);
end;
end;

P.S.Sorry about the crosspost :crazy: .
...Vern
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

Post by vmars »

I changed the code a bit to always grab 256 of mem and keep reusing it.
Turns out that
pRetBuffer := madRemote.AllocMemEx(256, hWnd);

pRetBuffer is always 'nil', so that [sl.Add(pRetBuffer^);] crashes the pgm.

Procedure{function} LB_GetAllItems(hWnd: THandle; sl: TStrings){: string};
var
pRetBuffer: pString;
i, x, y: Integer;
begin
x := SendMessage(hWnd, LB_GETCOUNT, 0, 0);
try
pRetBuffer := madRemote.AllocMemEx(256, hWnd);
for i := 0 to x - 1 do
begin // LBS_HASSTRINGS
y := SendMessage(hWnd, LB_GETTEXTLEN, i, 0);
SendMessage(hWnd, LB_GETTEXT, i, lParam(pRetBuffer));
sl.Add(pRetBuffer^);
ShowMessage('CurrentLine = ' + sl);
end;
Finally
madRemote.FreeMemEx({mem}pRetBuffer, {processHandle} hWnd);
end;
end;

Please, how come it returns nil,
and how do i fix it??
Thanks...Vern
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

Is processHandle different than GetWindowThreadProcessId?

Post by vmars »

Hmm...
I have been assuming processHandle was WindowHandle.
function AllocMemEx (size : cardinal; processHandle : cardinal = 0) : pointer; stdcall;

Then i thought maybe its processID, so i tried:
GetWindowThreadProcessId(hWnd, @WindowProcessId);
Which gets the processID fine, but
pRetBuffer := madRemote.AllocMemEx(256, WindowProcessId);

still returns 'nil' for pRetBuffer, then still crashes at sl.Add(pRetBuffer^);
Is processHandle different than GetWindowThreadProcessId?
Thanks
...Vern
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

window handle <> process id <> process handle

GetWindowThreadProcessId(windowHandle, @processId);
processHandle := OpenProcess(PROCESS_ALL_ACCESS, false, processId);
// use process handle here
CloseHandle(processHandle);
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

almost there

Post by vmars »

Madsh, i'm almost therei;

Having problems to know what info goes into these fields:
ReadProcessMemory(processHandle, params, pointer(result), len, len);

params = ?
pointer = madRemote.AllocMemEx ?
result = pointer^ ?
len = to ?
len = from ?

I get error msgs:
[Error] Unit1.pas(163): Missing operator or semicolon
ReadProcessMemory(processHandle, params, pRetBuffer( | RetBuffer), Len, Len);
'|' = blinking cursor

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

Post by madshi »

Why don't you read the ReadProcessMemory documentation? It's all explained there!
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

my best guess

Post by vmars »

I have read the C:\Program Files\madCollection\madBasic\Help\Data\RemoteCmdLine.htm
many times ([,len ,len] to me is ambiguous).
And my best guess is this:

ReadProcessMemory(processHandle, pAllocMem, pPgmString, GetTextLen, AllocMemLen);
if i reverse the len
ReadProcessMemory(processHandle, pAllocMem, pPgmString, AllocMemLen, GetTextLen);
then the pgm crashes.

Please, is the first one correct?
Thanks
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

I meant the documentation of ReadProcessMemory.

http://msdn.microsoft.com/library/defau ... memory.asp
The ReadProcessMemory function reads data from an area of memory in a specified process. The entire area to be read must be accessible, or the operation fails.

BOOL ReadProcessMemory(
HANDLE hProcess,
LPCVOID lpBaseAddress,
LPVOID lpBuffer,
SIZE_T nSize,
SIZE_T* lpNumberOfBytesRead
);

Parameters

hProcess
[in] Handle to the process whose memory is being read. The handle must have PROCESS_VM_READ access to the process.
lpBaseAddress
[in] Pointer to the base address in the specified process from which to read. Before any data transfer occurs, the system verifies that all data in the base address and memory of the specified size is accessible for read access. If this is the case, the function proceeds; otherwise, the function fails.
lpBuffer
[out] Pointer to a buffer that receives the contents from the address space of the specified process.
nSize
[in] Number of bytes to be read from the specified process.
lpNumberOfBytesRead
[out] Pointer to a variable that receives the number of bytes transferred into the specified buffer. If lpNumberOfBytesRead is NULL, the parameter is ignored.
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

Sorry about that:

Post by vmars »

Sorry about that:
i thought that ReadProcessMemory was part of your madStuff. :oops:
Thanks
vmars
Posts: 12
Joined: Sat Jan 22, 2005 8:15 am
Location: Keaau, Hi
Contact:

(2) Write a little dll and inject it into the target proces?

Post by vmars »

pGetTextLen : PDWord;

pGetTextLen := madRemote.AllocMemEx(4, processHandle);
pRetBuffer := madRemote.AllocMemEx(256, processHandle);

pGetTextLen^ := SendMessage(WindowHandle, LB_GETTEXTLEN, i, 0);

raised exception class EAccessViolaton with message 'Access violation at address 0044878C
in module 'Project1.exe'. Write of address 5F000000'

pGetTextLen is at address 5F000000

Some folks say that approach 1) won't work
and that i need to go with #2),
(2) Write a little dll and inject it into the target process. You can use madCodeHook for injecting the dll. But
you can also get along without madCodeHook by using SetWindowsHookEx. The dll then can use
LB_GETTEXT directly, because it is loaded in the correct process memory/address context. Afterwards the dll
can send the text to your application by using WM_COPYDATA.

Please, should i start all over with #2.
Thanks
..Vern
madshi
Site Admin
Posts: 10764
Joined: Sun Mar 21, 2004 5:25 pm

Post by madshi »

(1) is more difficult to realize, but should work just fine.

Looking at your code you don't seem to have really understood (1), though, so maybe it would be better for you to use (2). I simply don't have the time to do all the work for you. I'm sorry...
Post Reply