Analyses, Musings

Just another WordPress.com weblog

Archive for February 2010

Notes on SendMessageRemote()

leave a comment »

(03feb10)

(SendMessageRemote() is a useful function for doing GetWindowText() on dialog
items in another process.  Due to implementation details GetWindowText() often
fails if you try using it for that)

(running windows vista 32-bit)

the last parameter of david ching's SendMessageRemote() is the exact maximal
number of bytes that his code will write to your buffer whose address you pass
in the LPVOID fifth parameter

e.g.since WM_GETTEXT writes wchar_t's you will get  (assuming the window whose
text is being read has a title that big)  8 and 1/2 wide-chars written to your
memory

and it will NOT write the terminating null

note that WM_GETTEXT wParam msdn says is the maximal number of characters to
transfer

so dont you think that would limit SendMessageRemote()  (indirectly)  to only
transfer 6.5 wide-chars to your buffer?  (if you specify wParam==13)

no.

because WM_GETTEXT is 'smart' enough to know that wchar_t's are two bytes thus
it thinks you told it 'my buffer is 26 bytes big'

but microsoft has a bug!  they say it returns the number of wide-chars written
not counting terminating null.  therefore you would expect in our example since
in the remote process it thinks it had a 26 byte buffer it would write 12 wide
chars and then a terminating null it should return 12

it actually returns 25 in my testing!*

anyway the upshot is that you can just put 999 in the wParam to WM_GETTEXT and
the 'real' restriction is what you tell SendMessageRemote() in the sixth size_t
parameter

you will be safe as long as you set that size_t to size of your buffer minus
one  (and do the terminating null yourself)

[to test:  what if the title of the window is 'Short' i.e. there are only ten
bytes worth of wide char to send over?  will david ching's code mindlessly
write 10 bytes then perhaps 7 bytes of memory rubbish from the other injected
process?]

[it seems SendMessage() microsoft code processing WM_GETTEXT does some 'safe
buffering' stuff where it takes the actual strlen() of the stuff in say an edit
box and allocates separate string that has that text and null terminated]

[then it gives THAT safe buffer to david ching's remote thread and that remote
thread presumably hits terminating null and even though you request 17 bytes of
raw memory transfer the remote thread is smart and only writes 12 bytes to your
LPVOID the wchar_t's (S)(h)(o)(r)(t)(0)]

[actually it will not write any terminating null perhaps it 'knows about' the
strlen() being 5, scribbled down somewhere by WM_GETTEXT processing code]

[point is if WM_GETTEXT sees wParam too short for the buffer it doesnt write
terminating null to its own buffer, and somehow david ching remote thread is
aware of this and also does not write a terminating null]

[therefore again in that case when strlen() exactly equals wParam you will have
to null terminate your LPVOID]

[final note seems to be bug in ReadProcessMemory() used by david ching it says
it wrote 17 bytes but i plainly see in my buffer it only wrote the (S)(h)(o)(r)
(t) and left buffer slots after that untouched, didnt even copy garbage.  this
is with wParam set to 5 for WM_GETTEXT]

*as you can see if you read on it actually DOES only write 26 bytes worth of
wide chars.  though it will write 13 wide chars and let you worry about
terminating null.  the real funny part is that i dont know if in the remote
process since it scribbles somewhere '25' to return to you if it was dumb
enough to write 25 wide chars to a buffer the user said 'size is 13' for

Addendum:

Boy things get really odd.  If you set wParam==5 but have _six_ characters in
the edit box 'Longer' and david ching size_t_L_param is 17 you only get 'Longe'
back!  And the remote thread SendMessage() returns 6!  Whatever..
Advertisements

Written by 001041a

February 4, 2010 at 4:30 am

Posted in Uncategorized