-
January 13th, 2011, 11:30 PM
#1
ExtTextOut
Hi all. I am using the MS Detours to intercept 4 API functions, DrawText, DrawTextEx, TextOut and ExtTextOut. This is all occurring in a small Unmanaged C++ Dll that I put together (after much Google time, C++ not my forte). From the intercepted functions I call a function that puts together a small COPYDATASTRUCT and ships it off the my main, originating VB.Net app. In the VB.Net app I am retrieving the struct, interpreting and obtaining all text that passes through the target app.
Everything seems to work like a charm for the two DrawText APIs but not for the two TextOut APIs. First off, whenever I close the VB.Net app (WinForm exe) the target app (ANY app, I have tested on countless programs) crashes whenever I hook the TextOut functions. Secondly, all text retrieved from these functions is completely jumbled. Text is perfect from the DrawText functions, and they do not cause errors or crashes (with the TextOut hooks commented out.
Can anybody please direct me to what I may be doing wrong? Any help/advice is greatly appreciated as I have spent weeks scouring Google and the web for an answer.
Code snippets below. Please ask and I will happily provide more info/code.
TIA
C++ code:
Code:
enum Win32API
{
API_TextOut = 1,
API_ExtTextOut = 2,
API_DrawText = 3,
API_DrawTextEx = 4
};
void TransmitToGUI(int Len, LPCWSTR szText, Win32API sourceAPI)
{
HWND hWnd = ::FindWindow(NULL, L"AutoERP::");
if (!hWnd)
{
return;
}
else
{
if(!szText)
return;
wchar_t Text[255];
wcscpy_s(Text, szText);
COPYDATASTRUCT cds;
::ZeroMemory(&cds, sizeof(COPYDATASTRUCT));
cds.dwData = sourceAPI;
cds.cbData = (Len+1)*2;
cds.lpData = &Text;
::SendMessage(hWnd, WM_COPYDATA, NULL, (LPARAM)&cds);
}
}
BOOL (WINAPI * Real_TextOut)(HDC a0, int a1, int a2, LPCWSTR a3, int a4) = TextOutW;
BOOL (WINAPI * Real_ExtTextOut)(HDC a0, int a1, int a2, UINT a3, CONST RECT* a4, LPCWSTR a5, UINT a6, CONST INT* a7) = ExtTextOutW;
int (WINAPI * Real_DrawText)(HDC a0, LPCWSTR a1, int a2, LPRECT a3, UINT a4) = DrawTextW;
int (WINAPI * Real_DrawTextEx)(HDC a0, LPWSTR a1, int a2, LPRECT a3, UINT a4, LPDRAWTEXTPARAMS a5) = DrawTextExW;
BOOL WINAPI Mine_TextOut(HDC hdc,int X,int Y,LPCWSTR text,int textLen)
{
BOOL rv = Real_TextOut(hdc, X, Y, text, textLen);
if (text)
{
TransmitToGUI(textLen, text, API_TextOut);
}
return rv;
}
BOOL WINAPI Mine_ExtTextOut(HDC hdc, int X, int Y, UINT options, RECT* lprc, LPCWSTR text, UINT cbCount, INT* lpSpacingValues)
{
BOOL rv = Real_ExtTextOut(hdc, X, Y, options, lprc, text, cbCount, lpSpacingValues);
if (text)
{
TransmitToGUI(cbCount, text, API_ExtTextOut);
}
return rv;
}
int WINAPI Mine_DrawText(HDC hdc, LPCWSTR text, int nCount, LPRECT lpRect, UINT uOptions)
{
int rv = Real_DrawText(hdc, text, nCount, lpRect, uOptions);
if (text)
{
TransmitToGUI(nCount, text, API_DrawText);
}
return rv;
}
int WINAPI Mine_DrawTextEx(HDC hdc, LPWSTR text, int textLength, LPRECT lpRect, UINT uFormat, LPDRAWTEXTPARAMS lpParams)
{
int rv = Real_DrawTextEx(hdc, text, textLength, lpRect, uFormat, lpParams);
if (text)
{
TransmitToGUI(textLength, text, API_DrawTextEx);
}
return rv;
}
VB.Net code:
Code:
Public Structure COPYDATASTRUCT
Public dwData As Integer
Public cbData As Integer
Public lpData As IntPtr
End Structure
Friend Enum Win32API
API_TextOut = 1
API_ExtTextOut = 2
API_DrawText = 3
API_DrawTextEx = 4
End Enum
<System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case (m.Msg)
Case WM_HOTKEY '// hotkey detected, install hook
SetCBTHook()
Case WM_COPYDATA '// data coming from [API] hook(s)
DataReceived(m)
Case Else
MyBase.WndProc(m)
End Select
End Sub
Private Sub DataReceived(ByRef m As Message)
Try
'// marshal and extract COPYDATASTRUCT from pointer
Dim cds As New COPYDATASTRUCT()
cds = DirectCast(Marshal.PtrToStructure(m.LParam, GetType(COPYDATASTRUCT)), COPYDATASTRUCT)
'// if our call, process data
If ((cds.dwData >= 1) AndAlso (cds.dwData <= 4)) Then
'// marshal and extract string from pointer
Dim tms As String = Marshal.PtrToStringAuto(cds.lpData, cds.cbData)
'// display text (if present)
If (tms.Replace(" ", String.Empty).Length > 0) Then
If ((cds.dwData = 1) OrElse (cds.dwData = 2)) Then
ListBox1.Items.Add([Enum].GetName(GetType(Win32API), cds.dwData) & ": " & tms)
ListBox1.SelectedIndex = ListBox1.Items.Count - 1
Else
ListBox2.Items.Add([Enum].GetName(GetType(Win32API), cds.dwData) & ": " & tms)
ListBox2.SelectedIndex = ListBox2.Items.Count - 1
End If
End If
Else
MyBase.WndProc(m)
End If
Catch ex As Exception
'MsgBox(ex.Message)
End Try
End Sub
Last edited by ovidiucucu; January 14th, 2011 at 06:49 AM.
Reason: Corrected [CODE] tags
-
January 14th, 2011, 08:01 AM
#2
Re: ExtTextOut
Length in Drawtext can be -1 indicating it's a zero terminated string.
Your transmit code seems to assume it'll always be properly filled in.
In the case of textout, the length is always provided, but you cannot assume the string will be terminated, thus simply doing length+1 is incorrect.
-
January 14th, 2011, 11:25 AM
#3
Re: ExtTextOut
Thanks for reply.
Forgive my less than ideal knowledge of C++, but what is the best way to handle these various situations?
If I test for -1 in the drawtext methods then I know if it is zero terminated, but then how to I get the length in the VB side to pull string from ptr?
As far as the textout, I can understand how this can cause errors, but will this have something to do with the garbled text as well? I was reading about unicode and glyph tables, but I am getting symbols and characters on every textout and exttextout call from every target app I test. Seems unlikely that the entire system is using glyphs? Or is that likely?
Thanks again.
-
January 17th, 2011, 08:21 PM
#4
Re: ExtTextOut
Any further help is greatly appreciated here please.
If I test for a zero terminated string then I would know whether to pass ((len+1)*2) or (len*2). Is this assumption correct?
If so, and given that the LPCWSTR is a pointer, how exactly can I test if zero terminated??
Again, many TIA!
-
January 22nd, 2011, 08:51 PM
#5
Re: ExtTextOut
Small *bump* for any further assistance from anyone plz?
TIA
-
January 23rd, 2011, 10:00 AM
#6
Re: ExtTextOut
Nice sharing.................
-
June 11th, 2011, 03:41 PM
#7
Re: ExtTextOut
Hi,
I'm also having the problem that the hooked ExtTextOutW function produces garbled text. I'm on Windows 7 with Microsoft Detours 2.1 and Visual Studio C++ 2010 Express.
Did you manage to solve the problem, msfiend? The only observation I was able to make is that there seems to be a mapping from the garbled characters to the real ones. In my case for example, what should be a lower case "i" is always displayed as "L" and "e" is displayed as "H". I tried using WideCharToMultiByte but without any luck.
I'll buy the person who helps us a beer!
Cheers,
Michael
-
June 13th, 2011, 06:14 AM
#8
Re: ExtTextOut
Originally Posted by mherrmann
I'm also having the problem that the hooked ExtTextOutW function produces garbled text.
,,,
I tried using WideCharToMultiByte but without any luck.
Perhaps you should use MultiByteToWideChar to obtain a wchat_t* string to be passed in ExtTextOutW function?
Victor Nijegorodov
-
July 30th, 2011, 11:20 AM
#9
Re: ExtTextOut
Thanks for your reply VictorN,
I think the "problem" is that the string passed to ExtTextOut is not a string of characters but a string of glyphs, as per the ETO_GLYPH_INDEX parameter to ExtTextOut.
Does anybody have an idea where the glyphs that are passed to ExtTextOut are computed? The documentation for ExtTextOut mentions GetCharacterPlacement but in my case that doesn't seem to be it (I hooked GetCharacterPlacement and it's never called).
TIA!
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|