Link to home
Start Free TrialLog in
Avatar of tarang
tarang

asked on

Global GDI function hook

I want to be able to interecept a function such as BitBlt for all applications currently running and that are consequently run until windows successfully exits.  When an application calls BitBlt my function should be called first so that my function can do some work and then call the real BitBlt.  Please provide any code samples that you may have.
Avatar of chensu
chensu
Flag of Canada image

Detours is a library for instrumenting arbitrary Win32 functions on x86 machines.
Detours intercepts Win32 functions by re-writing target function images.
http://research.microsoft.com/sn/detours
Avatar of NickRepin
NickRepin

tarang, for grade A I can give you the sample code which will intercept BitBlt as you want.
Avatar of tarang

ASKER

Although one of the links did take me to an example of how to hook into a function it did not say anything about applying to all aplications currently running or new applications that might be started.  Since NickRepin has offerd to post sample code that would "intercept BitBlt as you want", I would like to see his response.
>>BitBlt for all applications currently running

Sorry, I missed that. I can give you the sample code for a one application only.

For all running applications, it is very depends on OS - 95/98 or NT/2000.
Detours doesn't work on 95/98.

I can give you a solution for both 95/98 and NT/2000, but it will cost much more than 200 points.

The easiest way is to modify GDI32.DLL (it's all documented), it will work equally fine on 95/98 and NT/2000.
Avatar of tarang

ASKER

To NickRepin

Not only all currently running application but also any new applications that are started by the user until he/she logs off.

BTW how many points do you want.
>>how many points do you want.
Let's wait - may be somebody else answer your question.

It's not clear what exactly do you want.

Which OS - 95/98 or NT/2000?

Does the way with changing GDI32.DLL is acceptable (you can change GDI32.DLL when your program is installed, and restore it when your program is uninstalled) - it's the most easiest way?

Hi Nick,

one thought: WinME and Win2000 both have this Windows File Protection feature. That means they do not allow you to change system files (or better: they allow it, but they restore the original file later on). Do you have a way around this problem?

Regards, Madshi.
This will give you the idea.

http://users.neca.com/vmis/wspy.htm
Avatar of tarang

ASKER

I don't acutally want to change GDI32.dll within the system directory but rather within memory when it is loaded.  As for operating systems I know that Win9x will have to be different than WinNT which in turn may or may not be different than Win2000 or WinME so #ifdef's are acceptable.
>>means they do not allow you to change system files

It's another question... After all, MS uses service packs which change system files.

>>want to change GDI32.dll within the system directory but rather within memory when it is loaded.  

This can be done relatively easy on Win95/98, because there is only one GDI32 in a memory (but it's undocumented).

On NT/2000, you have to enumerate all processes and change GDI32 for each one. Then you have to check if new process is started and change GDI32 for it too. Quite hard...
Avatar of tarang

ASKER

I think I can manage to enumerate all processes currently running and I can then certianly re-enumerate from time to time to try to interecept new processes.  So if there is an easier or better method for checking for new process please advise me.  I probably only need a hint.

It's easy enough to GetProcAddress for the function for the current application what I really need help with is how do get if for other applications that aren't mine and then how to do the substitution and then call the default function once again.

I'm certianly willing to offer more points.
ASKER CERTIFIED SOLUTION
Avatar of chensu
chensu
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of tarang

ASKER

Sorry no guarentee that the app will create a window :(.
It should have a window if it uses GDI.
Hi all,

a while ago I managed to hook GDI under Win9x. It requires a 16 bit DLL however. The keyfunction is

DDI := SetDDIHook(0, HInstance, nil, DDIHOOK_RECORDER, DDIHookProc);

There is an MSDN example which uses this call. You need also WinDDI.h (or .pas if you are using Delphi, I can provide the translation if needed).

Ciao, Mike
Avatar of tarang

ASKER

I looked at the SetDDIHook function but I don't see how you specify which GDI function it is that you want to hook?
Avatar of tarang

ASKER

Seems like people need a little more incentive.
I asked the same question and I am still trying to figure it out. I am trying to do something similar. I can add another 500 points to the answer IF it works.

until then I am lurking
Lischke,

can you point me to the MSDN sample that uses the SetDDIHook.

tarang,

May I ask what you are trying to accomplish by hooking BitBlts?

mite51, prepare your 500 points :-) It does indeed work. I have written a small library last september which gets all GDI output (BitBlts, TextOut etc., for Win9x only! but you can even get Unicode output from ExtTextOutW).

In order to provide the DDI hook example I did a full text search over our universal MSDN description (april 2000) and to my surprise I did not find the example. It was part of the accessability tools but seems no longer to be available. I can't even find winddi.h in MSVC so I post my local copy I made when I translated it into Delphi:

// --------------------------------------------------------------------------
//
//  WINDDI.H
//
//  Hooking mechanism to see all screen output.
//
//  NOTE:  You must include GDIDEFS.INC from the DDK to get the definitions
//  of the structures used in this file.
//
// --------------------------------------------------------------------------

#ifndef _WINDDI_
#define _WINDDI_

#if !defined(_WINDDI_)
#define WINDDIAPI   DECLSPEC_IMPORT
#else
#define WINDDIAPI
#endif

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus


//
// Forward declarations of structures passed as various DDI parameters
//

typedef struct tagPDEVICE FAR*      LPPDEVICE;
typedef struct tagDRAWESCAPE FAR*   LPDRAWESCAPE;
typedef struct tagDISPVALMODE FAR*  LPDISPVALMODE;
typedef struct tagCOLORINFO FAR*    LPCOLORINFO;
typedef struct tagPPEN FAR*         LPPPEN;
typedef struct tagPBRUSH FAR*       LPPBRUSH;
typedef struct tagFONTINFO FAR*     LPFONTINFO;
typedef struct tagTEXTXFORM FAR*    LPTEXTXFORM;
typedef struct tagDEVMODE FAR*      LPDEVMODE;


typedef struct tagDDI FAR* HDDI;

//
// Classes of DDI hooks
//
#define DDIHOOK_MIN             0x0000
#define DDIHOOK_RECORDER        0x0001
#define DDIHOOK_REMOTE          0x0002
#define DDIHOOK_FONTS           0x0003
#define DDIHOOK_MAGNIFIER       0x0004
#define DDIHOOK_MAX             0x0005

//
// DDIs
//
typedef UINT    DDITYPE;
typedef LPVOID  LPDDIPARAMS;

typedef DWORD (CALLBACK* DDIHOOKPROC)(HDDI, LONG, DDITYPE, LPDDIPARAMS);


WINDDIAPI
HDDI
WINAPI
SetDDIHook(
    HDC         hdcHook,
    HMODULE     hModCode,
    LONG        lPrivateData,
    UINT        hookClass,
    DDIHOOKPROC lpfnDdiHook
);


WINDDIAPI
BOOL
WINAPI
UnhookDDIHook(
    HDDI        hddi
);


WINDDIAPI
DWORD
WINAPI
CallNextDDI(
    HDDI            hddi,
    DDITYPE         ddiType,
    LPDDIPARAMS     lpDdiParams
);


//
// The DDIs you can hook currently:
//
#define DDI_BITBLT              0x0000
typedef struct tagBITBLT_DDIPARAMS
{
    LPDRAWMODE      lpDrawMode;
    LPPBRUSH        lpPBrush;
    DWORD           dwRop;
    int             cySrc;
    int             cxSrc;
    int             ySrc;
    int             xSrc;
    LPPDEVICE       lpDevSrc;
    int             yDst;
    int             xDst;
    LPPDEVICE       lpDevDst;
}
BITBLT_DDIPARAMS, FAR* LPBITBLT_DDIPARAMS;


#define DDI_COLORINFO           0x0001
typedef struct tagCOLORINFO_DDIPARAMS
{
    LPVOID          lpPhysBits;
    DWORD           rgbColor;
    LPPDEVICE       lpDev;
}
COLORINFO_DDIPARAMS, FAR* LPCOLORINFO_DDIPARAMS;


#define DDI_CONTROL             0x0002
typedef struct tagCONTROL_DDIPARAMS
{
    LPVOID          lpOutData;
    LPVOID          lpInData;
    UINT            uCode;
    LPPDEVICE       lpDev;
}
CONTROL_DDIPARAMS, FAR* LPCONTROL_DDIPARAMS;


#define DDI_DISABLE             0x0003
typedef struct tagDISABLE_DDIPARAMS
{
    LPPDEVICE       lpDev;
}
DISABLE_DDIPARAMS, FAR* LPDISABLE_DDIPARAMS;


#define DDI_ENABLE              0x0004
typedef struct tagENABLE_DDIPARAMS
{
    LPVOID          lpDriverInfo;
    LPSTR           lpOutputFile;
    LPSTR           lpDeviceType;
    UINT            uStyle;
    LPPDEVICE       lpDev;
}
ENABLE_DDIPARAMS, FAR* LPENABLE_DDIPARAMS;


#define DDI_ENUMDEVICEFONTS     0x0005
typedef struct tagENUMDEVICEFONTS_DDIPARAMS
{
    LPVOID          lpClientData;
    FARPROC         lpfnCallback;
    LPSTR           lpszFaceName;
    LPPDEVICE       lpDev;
}
ENUMDEVICEFONTS_DDIPARAMS, FAR* LPENUMDEVICEFONTS_DDIPARAMS;


#define DDI_ENUMOBJECTS         0x0006
typedef struct tagENUMOBJECTS_DDIPARAMS
{
    LPVOID          lpClientData;
    FARPROC         lpfnCallback;
    UINT            uStyle;
    LPPDEVICE       lpDev;
}
ENUMOBJECTS_DDIPARAMS, FAR* LPENUMOBJECTS_DDIPARAMS;


#define DDI_OUTPUT              0x0007
typedef struct tagOUTPUT_DDIPARAMS
{
    LPRECT          lprcClip;
    LPDRAWMODE      lpDrawMode;
    LPPBRUSH        lpBrush;
    LPPPEN          lpPen;
    LPPOINT         lpPoints;
    UINT            uPointCount;
    UINT            uStyle;
    LPPDEVICE       lpDev;
}
OUTPUT_DDIPARAMS, FAR* LPOUTPUT_DDIPARAMS;


#define DDI_PIXEL               0x0008
typedef struct tagPIXEL_DDIPARAMS
{
    LPDRAWMODE      lpDrawMode;
    DWORD           rgbColor;
    int             y;
    int             x;
    LPPDEVICE       lpDev;
}
PIXEL_DDIPARAMS, FAR* LPPIXEL_DDIPARAMS;


#define DDI_REALIZEOBJECT       0x0009
typedef struct tagREALIZEOBJECT_DDIPARAMS
{
    LPTEXTXFORM     lpTextTransform;
    LPVOID          lpOutObject;
    LPVOID          lpInObject;
    UINT            uObjectId;
    LPPDEVICE       lpDev;
}
REALIZEOBJECT_DDIPARAMS, FAR* LPREALIZEOBJECT_DDIPARAMS;


#define DDI_STRINGBLT           0x000A
typedef struct tagSTRINGBLT_DDIPARAMS
{
    LPTEXTXFORM     lpTextTransform;
    LPDRAWMODE      lpDrawMode;
    LPFONTINFO      lpFont;
    UINT            cchText;
    LPSTR           lpszText;
    LPRECT          lprcClip;
    int             yStart;
    int             xStart;
    LPPDEVICE       lpDev;
}
STRINGBLT_DDIPARAMS, FAR* LPSTRINGBLT_DDIPARAMS;


#define DDI_SCANLEFTRIGHT       0x000B
typedef struct taSCANLEFTRIGHT_DDIPARAMS
{
    UINT            uStyle;
    DWORD           rgbSearch;
    int             yStart;
    int             xStart;
    LPPDEVICE       lpDev;
}
SCANLEFTRIGHT_DDIPARAMS, FAR* LPSCANLEFTRIGHT_DDIPARAMS;


#define DDI_DEVICEMODE          0x000C
typedef struct tagDEVICEMODE_DDIPARAMS
{
    LPSTR           lpFileName;
    LPSTR           lpDeviceName;
    HMODULE         hmod;
    HWND            hwnd;
}
DEVICEMODE_DDIPARAMS, FAR* LPDEVICEMODE_DDIPARAMS;


#define DDI_EXTTEXTOUT          0x000D
typedef struct tagEXTTEXTOUT_DDIPARAMS
{
    UINT            uOptions;
    LPRECT          lprcOpaque;
    LPINT           lpCharWidths;
    LPTEXTXFORM     lpTextTransform;
    LPDRAWMODE      lpDrawMode;
    LPFONTINFO      lpFont;
    int             cchText;
    LPSTR           lpszText;
    LPRECT          lprcClip;
    int             yStart;
    int             xStart;
    LPPDEVICE       lpDev;
}
EXTTEXTOUT_DDIPARAMS, FAR* LPEXTTEXTOUT_DDIPARAMS;


#define DDI_GETCHARWIDTH        0x000E
typedef struct tagGETCHARWIDTH_DDIPARAMS
{
    LPTEXTXFORM     lpTextTransform;
    LPDRAWMODE      lpDrawMode;
    LPFONTINFO      lpFont;
    UINT            ichLast;
    UINT            ichFirst;
    LPVOID          lpWidths;
    LPPDEVICE       lpDev;
}
GETCHARWIDTH_DDIPARAMS, FAR* LPGETCHARWIDTH_DDIPARAMS;


#define DDI_DEVICEBITMAP        0x000F
typedef struct tagDEVICEBITMAP_DDIPARAMS
{
    LPVOID          lpBits;
    LPVOID          lpBitmap;
    UINT            uCommand;
    LPPDEVICE       lpDev;
}
DEVICEBITMAP_DDIPARAMS, FAR* LPDEVICEBITMAP_DDIPARAMS;


#define DDI_FASTBORDER          0x0010
typedef struct tagFASTBORDER_DDIPARAMS
{
    LPRECT          lprcClip;
    LPDRAWMODE      lpDrawMode;
    LPPBRUSH        lpPBrush;
    LPPDEVICE       lpDev;
    DWORD           dwRop;
    UINT            cyBorder;
    UINT            cxBorder;
    LPRECT          lprcFrame;
}
FASTBORDER_DDIPARAMS, FAR* LPFASTBORDER_DDIPARAMS;


#define DDI_SETATTRIBUTE        0x0011
typedef struct tagSETATTRIBUTE_DDIPARAMS
{
    DWORD           dwAttribute;
    UINT            uIndex;
    UINT            uStateNum;
    LPPDEVICE       lpDev;
}
SETATTRIBUTE_DDIPARAMS, FAR* LPSETATTRIBUTE_DDIPARAMS;


#define DDI_DIBBLT              0x0012
typedef struct tagDIBBLT_DDIPARAMS
{
    LPCOLORINFO     lpColorInfo;
    LPDRAWMODE      lpDrawMode;
    LPBITMAPINFO    lpBitmapInfo;
    LPVOID          lpBits;
    UINT            cScans;
    UINT            iScan;
    BOOL            fGet;
    LPPDEVICE       lpDev;
}
DIBBLT_DDIPARAMS, FAR* LPDIBBLT_DDIPARAMS;


#define DDI_CREATEDIBITMAP      0x0013
typedef struct tagCREATEDIBITMAP_DDIPARAMS
{
    DWORD       dwDummyNotReallyHere;
}
CREATEDIBITMAP_DDIPARAMS, FAR* LPCREATEDIBITMAP_DDIPARAMS;


#define DDI_DIBTODEVICE         0x0014
typedef struct tagDIBTODEVICE_DDIPARAMS
{
    LPCOLORINFO     lpColorInfo;
    LPBITMAPINFO    lpBitmapInfo;
    LPVOID          lpBits;
    LPDRAWMODE      lpDrawMode;
    LPRECT          lprcClip;
    UINT            cScans;
    UINT            iScan;
    int             yStart;
    int             xStart;
    LPPDEVICE       lpDev;
}
DIBTODEVICE_DDIPARAMS, FAR* LPDIBTODEVICE_DDIPARAMS;


#define DDI_SETPALETTE          0x0015
#define DDI_GETPALETTE          0x0016
typedef struct tagGETSETPALETTE_DDIPARAMS
{
    LPPDEVICE       lpDevice;
    LPVOID          lpPalette;
    UINT            cEntries;
    UINT            iEntryStart;
}
GETSETPALETTE_DDIPARAMS, FAR* LPGETSETPALETTE_DDIPARAMS;


#define DDI_SETPALETTETRANSLATE 0x0017
#define DDI_GETPALETTETRANSLATE 0x0018
typedef struct tagGETSETPALETTETRANSLATE_DDIPARAMS
{
    LPPDEVICE       lpDevice;
    LPVOID          lpColorTranslateTable;
}
GETSETPALETTETRANSLATE_DDIPARAMS, FAR* LPGETSETPALETTETRANSLATE_DDIPARAMS;


#define DDI_UPDATECOLORS        0x0019
typedef struct tagUPDATECOLORS_DDIPARAMS
{
    LPPDEVICE       lpDevice;
    LPCOLORINFO     lpColorInfo;
    int             cyUpdate;
    int             cxUpdate;
    int             yStart;
    int             xStart;
}
UPDATECOLORS_DDIPARAMS, FAR* LPUPDATECOLORS_DDIPARAMS;


#define DDI_STRETCHBLT          0x001A
typedef struct tagSTRETCHBLT_DDIPARAMS
{
    LPRECT          lprcClip;
    LPDRAWMODE      lpDrawMode;
    LPPBRUSH        lpPBrush;
    DWORD           dwRop;
    int             cySrc;
    int             cxSrc;
    int             ySrc;
    int             xSrc;
    LPPDEVICE       lpDevSrc;
    int             cyDst;
    int             cxDst;
    int             yDst;
    int             xDst;
    LPPDEVICE       lpDevDst;
}
STRETCHBLT_DDIPARAMS, FAR* LPSTRETCHBLT_DDIPARAMS;


#define DDI_STRETCHDIBITS       0x001B
typedef struct tagSTRETCHDIBITS_DDIPARAMS
{
    LPRECT          lprcClip;
    LPDRAWMODE      lpDrawMode;
    LPPBRUSH        lpPBrush;
    DWORD           dwRop;
    LPCOLORINFO     lpColorInfo;
    LPBITMAPINFO    lpBitmapInfo;
    LPVOID          lpBits;
    int             cySrc;
    int             cxSrc;
    int             ySrc;
    int             xSrc;
    int             cyDst;
    int             cxDst;
    int             yDst;
    int             xDst;
    BOOL            fGet;
    LPPDEVICE       lpDevDst;
}
STRETCHDIBITS_DDIPARAMS, FAR* LPSTRETCHDIBITS_DDIPARAMS;


#define DDI_SELECTBITMAP        0x001C
typedef struct tagSELECTBITMAP_DDIPARAMS
{
    DWORD           dwFlags;
    LPVOID          lpBitmap;
    LPVOID          lpPrevBitmap;
    LPPDEVICE       lpDev;
}
SELECTBITMAP_DDIPARAMS, FAR* LPSELECTBITMAP_DDIPARAMS;


#define DDI_BITMAPBITS          0x001D
typedef struct tagBITMAPBITS_DDIPARAMS
{
    LPVOID          lpBitmap;
    DWORD           dwByteCount;
    DWORD           dwFlags;
    LPPDEVICE       lpDev;
}
BITMAPBITS_DDIPARAMS, FAR* LPBITMAPBITS_DDIPARAMS;


#define DDI_REENABLE            0x001E
typedef struct tagREENABLE_DDIPARAMS
{
    LPGDIINFO       lpGdiInfo;
    LPPDEVICE       lpDev;
}
REENABLE_DDIPARAMS, FAR* LPREENABLE_DDIPARAMS;


#define DDI_GAMMARAMP           0x001F
typedef struct tagGAMMARAMP_DDIPARAMS
{
    LPVOID          lpGammaRamp;
    BOOL            fSet;
    LPPDEVICE       lpDev;
}
GAMMARAMP_DDIPARAMS, FAR* LPGAMMARAMP_DDIPARAMS;


#define DDI_ICMCOLORINFO        0x0020
typedef struct tagICMCOLORINFO_DDIPARAMS
{
    LPVOID          lpColorTransform;
    LPVOID          lpColor;
    DWORD           rgbColor;
    LPPDEVICE       lpDev;
}
ICMCOLORINFO_DDIPARAMS, FAR* LPICMCOLORINFO_DDIPARAMS;


#define DDI_DRAWESCAPE          0x0021
typedef struct tagDRAWESCAPE_DDIPARAMS
{
    LPDRAWESCAPE    lpDrawEscape;
}
DRAWESCAPE_DDIPARAMS, FAR* LPDRAWESCAPE_DDIPARAMS;


#define DDI_MAX                 0x0022


#ifdef __cplusplus
}
#endif  // __cplusplus

#endif  // !_WINDDI_

--------------------------------------------------------------------------------


Since I found no entry for SetDDIHook in any MSDN file (searched even the libs) I think you need some more information to successfully create the hook. The 3 functions involved here are exported by GDI.dll with ordinal numbers:

function SetDDIHook index 750
function UnhookDDI index 751
function CallNextDDI index 752


tarang, you ask about how to specify what to hook? Well, you cannot specify this. Your hook is called for every (!) GDI output (and even things like text size determination). You need to examine ddiType to learn what is currently going on. Just use a switch statement similar to this code (sorry only in Delphi, but should be too hard to understand):

function DDIHookProc(DDI: HDDI; PrivateData: Pointer; DDIType: TDDIType; DDIParams: PDDIParams): DWORD; export;

var I, Count: Integer;
    Buffer: PWordArray;
    Entry: PDDIResult;

begin
  case DDIType of
    DDI_EXTTEXTOUT:
        with PTextOutDDIParams(DDIParams)^ do
        begin
          {a value < 0 specifies to calculate the text extent, a value = 0 specifies to fill the opaquing rectangle}
          if cchText > 0 then
          begin
            if cchText > MaxCharCount then Count := MaxCharCount
                                      else Count := cchText;
            GetMem(Buffer, 2 * (Count + 1));
            if (uOptions and ETO_GLYPH_INDEX) <> 0 then
            begin
              {string is stored with 2 byte per entry}
              for I := 0 to Count - 1 do
                Buffer^[I] := PWordArray(lpszText)^[I] + GlyphOffset;
            end
            else
            begin
              {string is stored with 1 byte per entry}
              for I := 0 to Count - 1 do
                Buffer^[I] := PByteArray(lpszText)^[I];
            end;
            {add a terminating 0}
            Buffer^[Count] := 0;
            AddTextEntries(Buffer, DDIParams);
            FreeMem(Buffer, 2 * Count + 2);
          end;
        end;
    DDI_BITBLT:
      with PBitBltDDIParams(DDIParams)^ do
      begin
        Entry := AddBlitEntry(lpDevSrc, lpDevDst, xDst - xSrc, yDst - ySrc);
      end;
    DDI_DIBBLT:
      AddStringEntry('DIBBLT', nil);
    DDI_DIBTODEVICE:
      AddStringEntry('DIBTODEVICE', nil);
    DDI_STRETCHBLT:
      AddStringEntry('STRETCHBLT', nil);
    DDI_STRETCHDIBITS:
      AddStringEntry('STRETCHDIBITS', nil);
  end;
  Result := CallNextDDI(DDI, DDIType, DDIParams);
end;

Hope this helps you. Ask me about implementation details if you need further help.

Ciao, Mike
Btw: Try http://www.microsoft.com/ddk/ddk98.htm to download the Win9x DDK. Perhaps it contains the header files and samples we are talking about here.

Ciao, Mike

PS: A correction: "sorry only in Delphi, but it should NOT be too hard to understand" :-)
Avatar of tarang

ASKER

To mite51,

What I'm trying to do is to intercept screen capture of my window and prevent it.

BTW I know you won't find DDIHookProc if you look in the "index" of MSDN, however if you do a "search" you will find it.  Go figure.

To Lischke,

I'll try out what you've posted, however I need this to work under NT as well.
tarang,
ya same, I only have Windows 2000 and I need it to work. I will keep you posted if I get it working.
Well, I explicitely stated that this only works for Win9x. AFAIK there is no way under NT to hook GDI (and I have done quite a lot research in this regard, as I, of course, wanted to use my 9x solution under NT too). Under NT it is much more difficult to capture GDI output. As chensu already mentioned you can use the detours library from MS to redirect APIs like BitBlt, TextOut etc. This, however, requires more work in your application, although you can at least use a 32bit program instead of dealing with 16bit dlls.

For NT however it becomes for another reason much more difficult: You cannot generally hook GDI APIs, but only for particular applications. This makes it necessary to redirect those APIs for every (!) running or new process. This in turn requires something like a global system hook which primarily works with windows. So if you have an application which does not create a window then you have a big problem.

This all said I suppose only a kind of device driver which is placed between GDI and the graphic driver will do the job as wanted. Correct me if I'm wrong...

Ciao, Mike
Hey mite51, why didn't you post the link to your "video hook kernel mode driver" question here?   :-)

https://www.experts-exchange.com/jsp/qShow.jsp?ta=winprog&qid=10682721 

Regards, Madshi.
>>said I suppose only a kind of device driver which is placed between GDI and the graphic driver

I'm afraid, you'll get device i/o requests, but not BitBlt parameters.

A modified GDI32.DLL is an easiest, documented, portable and most reliable way to intercept absolute ALL calls.
I'm afraid too this is the only solution if you "want it all". For a limited amount of redirections the detours library might be a good choice. This is the way I did it for a product of my company: DDIHook for Win9x and a similar lib as detours for WinNT.

Ciao, Mike
Avatar of tarang

ASKER

Well if you follow the link from Chensu (http://www.geocities.com/SiliconValley/1741/miscprog/mp_main.html) and download API Call Interception and then combine it with InjLib which is part of APISpy32 from http://www.internals.com/utilities/utilities.htm you can get things to work.  Note that I couldn't get InjLib from Jeffrey Richter to work.

Here's an overview of how it works.  First you get the process ids by calling EnumProcess.  Using the process ids you get the process handle by calling OpenProcess.  With the hProcess call InjectLib from the InjLib as mentioned above and your dll gets loaded into the other processes' adress space.  The dll can then use the method form Intercept to redirect any __stdcall method.


mite51 if your interested I'll post my code once I've had more of a chance to test it and clean it up a little.
Yes, thank you. I am interested.

Have you tried any GDI hooks yet? from what I understand the GDI hook should be placed in the kernel DLL. But then what do I know :) If you get it good on ya
tarang's suggestion has 2 problems:

(1) The "API Call Interception" he uses, might miss some calls (e.g. if somebody calls GetProcAddress for BitBlt). Only statically imported BitBlt calls will be hooked. Detours is better in this regard. There's a good documentation available at the Detours link, which explains the differences between all the different well known API interception techniques.

(2) When only calling EnumProcesses one time, you'll miss all newly created processes - except if you repeat the EnumProcesses call let's say every second or so. Under winNT there are 2 other possibilites to avoid constantly EnumProcesses polling:
(a) Set up a WH_SHELL or WH_CBT hook (like chensu already suggested). This works only on processes which have created a window. But it's quite probable that whoever calls BitBlt also has created a window.
(b) With this solution: "http://support.microsoft.com/support/kb/articles/Q197/5/71.ASP" you can make your dll be loaded by all apps that at least import "user32.dll". That's better than (a), but still not perfect. Sorry, I have no perfect solution for you. If you're using (b), the import table of your dll must only contain "kernel32.dll" and "user32.dll". If it contains more libraries, some applications load your dll and some do NOT. Also you have to be very careful what you do in your dll's initialization, because only kernel32.dll is guaranteed to be initialized at that time. Besides, (b) works only after the next reboot under NT4 (but at once for all new processes under win2000).

Regards, Madshi.
So the only *perfect* solution in regards of getting *all* calls in *all* processes seems to be Nick's suggestion to modify gdi32.dll. However, when using his suggestion you still need to find a way to get along with the Windows File Protection, which will otherwise automatically restore the old gdi32.dll.
I've seen many programs (and I think the number will increase) which use EXE compressor, in this case ALL functions used by this EXE are obtained via GetProcAddress().
For NT/2000 GDI/DDI hook, write a kernel mode driver.

There is a sample code in Chapter 4 of my coming book.

Windows Graphics Programming: Win32 GDI and DirectDraw
http://www.amazon.com/exec/obidos/ASIN/0130869856
Lischke, you say "So if you have an application which does not create a window then you have a big problem."

How is a BitBlt used without a window? Ok, yes I guess it could be used for printing without a window, but that is quite obscure and tarang says that he needs to "intercept screen capture of my window and prevent it", so these requirements can assume that there will be a window.

So a system-wide hook is probably a possible solution for getting access to all processes, except it might necessary to have a special version for 16-bit applications. If 16-bit is not a problem to the extent that it is not necessary to hook GDI calls from 16-bit applications, then 16-bit is not a problem and it might not be necessary to have a special 16-bit version anyway.

Sam, BitBlt works with DCs which do not necessarily require a window. Consider a thread which updates a memory DC which gets then somehow blittet to screen (you can directly print to the desktop btw.). The window problem is related to injecting the hook DLL into every process because it is done via a global hook which only works with windows. The way I went uses a key-mouse combination to trigger the injection, causes a repaint of the window on which the user has clicked and redirects the output which is done in this process (RedrawWindow does only return when repainting is completely over).

Ciao, Mike
Windows system-wide hooks include keyboard and mouse hooks. Is it possible for your "key-mouse combination" to work when the system-wide keyboard and mouse hooks do not?

Is it possible for an application to use the mouse without a window? In fact, is it possible for an application to use either the keyboard or the mouse without a window?
Yes, consider services, spawned processes etc. Every thread gets automatically a message queue once it has called GetMessage, PeekMessage or used a GDI function ..., so it does not need at window at all.

Ciao, Mike
Oops, sorry, thought too short. You asked for using the mouse and the keyboard without having a window. I'm not 100% sure, but I think this is not possible. But this not the point when hooking. If you want to make it good then you cannot simply and generally assume there is always a window for every process printing text or using other GDI functions. In my procédere the hook DLL is injected using a global windows hook which checks all incoming messages for a certain condition (say pressing left mouse button and holding down the Ctrl key). Then the GDI functions are redirected and output is triggered. I don't say this is the only way or it is a complete solution for the question here, but it is one way which works beautifully for me. The idea counts I think...

Ciao, Mike
Avatar of tarang

ASKER

I have succesfully intercepted any windows __stdcall API call by using the API Intercept found at http://www.geocities.com/SiliconValley/1741/miscprog/mp_main.html.  This only shows how to intercept a call but not how to inject it into another process.  For injection I first used Richter's method from his Advanced Windows book 3rd. edition.  However that caused the target application to crash after the dll was successfully loaded.  In another words DllMain returned successfully after a DLL_PROCESS_ATTACH.  The crash occures in the Kernel without any of my code involved.  However a friend of mine has the 4th. edition and that seems to work properly.

So the only thing to overcome was to how to monitor the processes commings and goings.  For that I created a thread that uses EnumProcesses.  Then it uses OpenProcess to gain access to each of the processes.  The return from OpenProcess is then passed on the the InjectLib call from Richter's 4th edition.

When the Dll is successfully inject into the other process it creates an even using both the process ID and the application name to name the event.  This event is then set so that the process thread can check this event to see if the dll has already been injected.

Further there is another event created by the processing thread that signals when the call should be intercepted and when they shouldn't.

So now the problem left is to be able to find all the methods that are used to perform a screen capture.  The only one I know of is creating a HDC for the "DISPLAY" and I've implemented that method in my interceptions.  However there have to be more since <Alt><Prnt Scrn> and Paint Shop Pro are still working by using some other method.  So please post different screen capture methods.

Thanks
tarang, with that hooking method you'll miss some API calls, see my 2 comments from "Sunday, August 13 2000 - 11:29AM" and Nick's thereafter.

About APIs: You need to hook GetDC and GetWindowDC, too.
Avatar of tarang

ASKER

Madshi, yes you are right I will miss calls made by programs that do a GetProcAddress for an API.  I'm still working on that part however I did get past the other problem that you noted.

Thanks
Lischke,

I finally found the winddi.h. It was in the win2k DDK only and I have having problems with it in windows 98.... I am still trying to get it to work. Has anyone else here had luck with the GDI hook?

I have been in contact with FengYuan, who has been kind enough to share source code for a DDI hook which I have not been able to compile, if anyone is interested I can send it to you (if thats ok with Feng) I would really like to figure this out, so I'm hoping someone here can help.

Mmh, in the W2K DDK? DDI hook is part of the accessibility kit which is only available for Win9x, AFAIK. It is based on the eye of needle in GDI where all its calls pass through.

Anyway, the support for DDI hooks seems very small and I had a hard time to get them running under Delphi too. Unfortunately, my knowledge about MSVC is that of a beginner and I even cannot find the one original example I had when I ported the other stuff. Sorry, all I can give you is a direction :-/

Ciao, Mike
Avatar of tarang

ASKER

I had a problem with intercept under Win95 and I assume that it would be the same under 98 and ME.  The problem is the address returned by GetProcAddress is not the same as the Thunk.  Instead what they point to is.  Thus the code

if ( pThunk->u1.Function == pProcAddress )

becomes

if ( *((DWORD*)pThunk->u1.Function) == *pProcAddress )

So I am at the last step.  How to inject a dll into all processes running under 95.  This is a problem since you cannot use CreateRemoteThread under 95, and the other style I've seen required the thread handle from the other process.  I can get the process id and even the thread id but not the thread handle.  If anyone has a suitable way of injecting a dll under 95, I'll award them the points.
Well, here we come to the point I already mentioned quite a time ago. I use a global hook to inject the DLL (see SetWindowsHookEx). But this hook is generally bound to messages. But you can use Window creation messages to track possible process creation. Since hooks are called in the context of the particular process you can call GetCurrentProcess for the process handle (or ID with the other function) and keep this in a list. Whenever you encounter a new process you can do whatever you like (load a DLL, redirect functions etc.). The limitation of this approach is clear, I think. You can only inject into processes which create windows.

Ciao, Mike
but since , in almost all cases, windows that are using GDI command will be using messages, so its a moot point really.
Mite51:

See my comment on Saturday, August 26 2000 at 08:19AM PDT and subsequent related messages. I agree with you that it is unlikely there will be a process that uses GDI for bitmaps that does not have a window, but they do not agree and/or want to cover the unlikely situations also.


well.. I would be happy if it worked first before worring about such a trivial point :)
Avatar of tarang

ASKER

To SamHobbs.

Yes I have seen the CreateRemoteThread method.  It will only work under NT though since CreateRemoteThread is not available under Win9x.


To FengYuan.

Impressive graphics, but no sample.  What method of hooking are you using, especially under Win9x?
Full source code is on the CD with my book.

The last two pictures showing DDI hooking is for NT/2K only. It accesses the per device logical device structure associated with each DC, which has a function table of DDI entry points. It just modify the table to point to new DDI routines. Implemented with the help of a simple kernel mode driver.

DDI hooking in Windows 9X should be much easier, as you only need a 16-bit EXE/DLL to hook into 16-bit GDI or device driver, which will be by default system wide. This is not covered in my book.
tarang, what should now happen with this question? Are my contributions acceptable as answer (although surely not excellent)?

Ciao, Mike
tarang?
honestly none of the code or ideas actually worked. Fengs code came the closest, so I guess I should give him the points. So if you (Feng) submit an answer I will give you the points.
Again, (at least) two logins to have more points...

Btw: I'm quite sure you never have tested my code because it works (since more than a year now). I can send you a compiled executable if you don't believe me.
huh? so provide an executeble then..
Avatar of tarang

ASKER

Well actually I was thinking of giving the points to Chensu since what I have working is based upon the links that he provided.  I had to do a lot of other work in order to get the things that I really needed and though I have something working I still have a bit more work to do.

If people are interested I can possibly post some code to a URL.
I am interested.. actually I only just realized this isn't my question:). I have a similar question open.. I am also working on something similar, based on some of Fengs window subclassing  hooking. It seems to be working but I also have quite a ways to go.
Avatar of OMC2000
Lischke,
could you tell me, where have you got winddi.h originally? I looked through all MSDN packages since 1997, but I could not find it.

I work on similar task too. My question is
https://www.experts-exchange.com/jsp/qShow.jsp?ta=winprog&qid=20004643

I think 80% of my question points should be yours.

Am I right, Madshi?
OMC2000, I'm actually suprised myself. As you can read in the comment where I have posted winddi.h I can't find it either anymore. AFAIR I found the header file on a CD under a folder named Accessiblity along with a very stupid sample. That's all I can tell you.

Ciao, Mike
Yep, OMC2000, give those points from the other question to Mike... (Mike, you should answer there).
The SetDDIHook was first documented in the Active Accessibility Software Developers Kit version 1.0. If you search the latest MSDN, you will find basic documentation on each of the corresponding APIs. By the next version of the Accessibility SDK, it was gone.

SetDDIHook and the related API's exist in GDI.EXE
in the Windows system directory. GDI.EXE is the 16-bit graphics engine for Windows 9x. There was a redistribution kit available at that time that added the DDI hooking APIs to GDI.EXE for Windows 95, which does not come out of the box with the DDI hook support, however Windows 98 first and second edition both have this built it. I assume ME does as well.

The APIs are exported by name in GDI.EXE, so it is fairly simple to access them from a 16-bit DLL. Microsoft had a sample with the Accessibility Kit 1.0 called DDIHOOK, but they left out the make files. I couldn't build it as is and when I pressed Microsoft, they said they lost half the project. They went on to say that they didn't support this function, and that they might pull it out of a future version of Windows. They seemed shocked to hear that I have it working well. If I get enough of a request I'll post a working sample and technical article on my website.

It took quite a while for me to make this work but I'm happy to share the knowledge.

If anyone has figured out how to hook into display drivers directly on Windows 9x, I'd love to hear about it.

Regarding NT and Windows 2000 - You have two options. The first of which is to create a Mirror driver. This will only work on NT sp6 or higher or W2k. This is well documented with a sample called Mirror in the w2k ddk. The other option is to buy Feng Yuan's book, Windows Graphics Programming, which demonstrates an interesting (but undocumented)technique for hooking ddi calls.

Hope this helps.
Just a comment.

Display and print drivers are just 16-bit DLLs on Windows 9X. You can just load them into memory from a 16-bit program, get entry points you're interested in, and overwrite them to point to your own functions.

Within your own function, you can do some logging, restore the original function, jump to the original function but with return address switched. Path the function again when control returns back to you.

I've done that with printer driver. But SetDDIHook could be easier.
I would like to get a copy of your SetDDIhook when you are ready to post it on your site. Heres my email if you want to give me some notice or just your websitelink mite51@hotmail.com. I have tried a few time but I could never find enought info to properly implement it.

As for hooking windows 2000 I have been in contact with Feng for some months now and he has helped me very much creating a hook that will redirect window draw operation to a memory and send it back to my app. It uses a combination of a system wide message hook and sub-classing to override BeginPaint/EndPaint calls. The hook replaces the returned DC with my memdc and I take the windows contents from there. Its not perfect but I am happy with the results so far.

Hi ColinBarry,

I would also be very interested in your knowledge. I'd be very happy if you'd post the sample and the technical article on your website.

Thank you!
Sounds good. My website is http://www.omnicomtech.com. I'll start by posting the original sample in the Misc Downloads section of the site:
http://www.omnicomtech.com/download/miscdl.html
Great! Thank you...  :-)  Looking forward to the technical article. Would you be so kind to post a comment here, when it's online? Thanx a lot!
It's up. I've included the entire original msaasdk which has the ddihook sample with all the necessary header files and the redistribution kit. Keep in mind that the ddihook sample is not compilable, but it should get y'all started. Enjoy.

Here's the link once again:

http://www.omnicomtech.com/download/miscdl.html
The SetDDIHook is documented in the Platform SDK. The online copy is at:

http://msdn.microsoft.com/library/psdk/msaa/msaapndx_3u3v.htm

Some other pages in the Windows Accessibility Features portion of the Platform SDK documentation are:

http://msdn.microsoft.com/library/default.asp?URL=/library/psdk/msaa/msaapndx_5h2j.htm
http://msdn.microsoft.com/library/default.asp?ShowPane=false&URL=/library/psdk/msaa/access_4ib7.htm

SetDDIHook is also mentioned in:

http://microsoft.com/enable/msaa/details.htm

From that page, the "Technical Support for Developers" page has a newsgroup for Active Accessibility developers.

There is an Microsoft® Active Accessibility® SDK and RDK. The RDK is for the redistributables. I do not know if there are samples included with the SDK, but there often are samples in SDKs.
Colin,

I thought you had it working? you should include you functioning project
I have it working in a commercial application. I am restricted from posting the source code for that application, however, my intention was to write a simple working demo if there was enough interest. This is just a starting point.
just out of curiousity, what does this commercial aaplication do?
It's a remoting app like pcANYWHERE or Carbon Copy. We are hoping to release it sometime during Q2 of this year. Take a peek at our website http://www.omnicomtech.com under products if you are interested.
Avatar of tarang

ASKER

Sorry guys, I've been in Hawaii for a bit and sort of out of touch.  I even have to go back in a couple of weeks.  It's not as great as it sounds since I have to work and don't really get a chance to enjoy myself.

Anyways to the matter at hand.

Collin: I did need a technique that would work both under 9x/ME as well as NT/2000 and writing a mirror device driver is way too much work (or at least I think it is).  I have managed to get code that works for all systems, though the injection part is slightly different for 9x/ME; the redirection part is exactly the same for all systems.

And yes my other choice was to buy Feng's book, and I probably would have bought the book if he had helped me out some in the begining.  However since it seemed to me his main goal was to sell his book rather than to help me or others in this forum I decided to go down a different path.

The trouble that I have run into has nothing necessarily to do with Windows but rather IE or Java under IE.  It turns out that if you (a dll) are launched by an applet then you can get the rug pulled out from under you.  In another words if the threads that you create within the Dll go into a wait state for any reason then IE may terminate the thread while it is in a wait state.  As you can imagine this is extreemly difficult to program around if it is even possible.

However as promissed I will post code when I get things working to a satisfactory level.
I will wait with eager anticipation.
We also have an application that is hooking into windows.  We are using a mouse hook, though the way you hook into windows is basically the same.  They raise a concept of hook chains, a list of hooks that each get passed a message before/after windows uses the function.  The type of hook alters when the hook is called - before or after registering the message.  For example, LowLevelMouseProc is called before a mouse message, and MouseProc is called after a message is in the queue.  Have a look here, this page gives a backgrounder:

 http://msdn.microsoft.com/library/techart/msdn_hooks32.htm

You'll need to find out what type of message BitBlt raises, and then hook that message.  The hook functions are cool, though you'll need to write them for speed, or enjoy Windows grinding to a halt.  For system wide monitoring, you'll need to stick the hook in a seperate dll.
InetMatt:

I have tried to find all the references about SetWindowsHookEx hooks as I can find and listed them in:

http://www.cpp.atfreeweb.com/Hooks.html

In your profile you say "designing" ... "first often saves hassles later". I wish more people understood what you already understand.

In case it is not clear, my previous message was two unrelated comments.

Also unrelated to the other stuff, I received two email notifictaions of an answer being provided for this question prior to InetMatt's message today, but I see no indication of such here. Probably there is an error in the web site software.
Avatar of tarang

ASKER

I received the same messages in error.

Just to keep people updated.  I think I've taken this thing as far as it can, for the particular application that I was interested in.  However the more general idea here was of course system wide API redirection.  To that end I'm going to try to put aside some time to put together a Visual C/C++ project that demonstrates all the underlying principals.
It would be nice if you could post the url to such a demonstration up here?  Whilst I don't need such a feature at the moment, it's always cool to see how it works, and maybe another application down the track might need something like that.
What was the particular application you were interested in anyway? I was (still am) trying to make a 3d interface. I have a demonstration ready, I wouldn't mind hearnig some feedback or ideas. http://www.swarm.ca/Recontructor.zip

Jason Wylie
mite51@hotmail.com
BTW, it requires windows 2000, DirectX8 and a 3d accelerator.

greets to Feng to who helped me out on it.

Buy his book
Good day,

This question may have been overlooked, since it remains open today.

If you've been helped, perhaps you can choose that expert's comments as the accepted answer to then grade and close.  If more is needed, a current update may prove helpful to get what you need to achieve your goal.

Thank you,
Asta
This question is still open today, perhaps it was overlooked or just lost in the volumes.  Please return to this question to update it with comments if more information is needed to get your solution.  If you've been helped by the participating expert(s), you may just convert their comment to the accepted answer and then grade and close.  If an answer has ever been proposed you may not have this option to accept the comment as answer, if that is the case, ask the specific expert you wish to award to post an answer.     You'll find that you get what you need more quickly if you remain active in your questions and provide feedback.  Finalizing questions benefits you and others who then search our PAQ for just this solution, and rewards the experts who have provided you the information.  A win/win scenario.  Please do not accept this comment as an answer,  it is merely a reminder.  
If no response has been received by month-end, I will delete or accept an answer based on the information given.  Experts, please feel free to offer input.  I will have another moderator (who is also an expert) look at the question as well to ensure we do the right thing for this question (PAQ or delete).
Some additional options and information:
If you wish to award multiple participants, you can do so by creating a zero point question in the Community Support topic area, include the link to this question and tell them which experts you'd like to award what amounts.  If you'd like to delete this question, use the same process as above, but explain why you think it should be deleted.  Here is the Community Support link:   https://www.experts-exchange.com/jsp/qList.jsp?ta=commspt
 
You can always click on your profile to see all your open questions, in the event you also have other open items to be resolved.   If your number of Questions Asked is not equal to the number of Answers Graded, choose to view question history, and you'll quickly be able to navigate to all your open items to close them as well.

Your responsiveness is appreciated.  

Moondancer
Moderator - Community Support
 
P.S.  Some of the older questions from last year are not in the proper comment date order, and Engineering has been advised.  
Avatar of tarang

ASKER

I am continuing to work on this problem and have run into some unique other problems.  Even though I was unable to get a complete answer I was able to pick up bits and peices.  The reason I have kept it open is because I have promised to post my results when I've completed what I have set out to do.  I wanted the people who are interested to be able to view that post when it becomes available.  If however you wish me to delete the question I will comply.
Madshi has made an excellent hooking mechanism for windows. You should try it out. I am able to capture all calls to BitBlt from any program in win 9x or 2000, not including kernel calls.
Thank you, Jason (mite51)...   :-)
Now that you've updated this question, it will not be autodeleted due to inactivity.  It will help you achieve your goal, if you maintain dialog to ensure the questions remain active.  

Moondancer
Moderator - Community Support @ Experts Exchange
Avatar of tarang

ASKER

Sorry folks,

Even though I have been able to get done what I needed I am not allowed to post my code.  However I would be willing to help/advise anyone who has questions as best I can.

Thanks
tarang - the point is to award someone here for all thier effort put in to helping you, by not doing so, you are not being fair.
if you are not happy with the answers given then explain why.
craig_capel, how much of this do you understand? It has been many months since I have read any of this but I remember it being very advanced technically. Also, as best as I can remember, tarang has been able to help himself more than he has received help. I might be wrong but that should be taken into consideration.

The thing you might not understand is that if tarang does do what he has offered to do, then he would being giving a hundred times or more help than he has received, so it is not perfectly clear what would be "fair".
ADMINISTRATION WILL BE CONTACTING YOU, tarang, ABOUT FINALIZING THIS QUESTION SHORTLY.

Question(s) below appears to have been abandoned. Your options are:
 
1. Accept a Comment As Answer (use the button next to the Expert's name).
2. Close the question if the information was not useful to you. You must tell the participants why you wish to do this, and allow for Expert response.
3. Ask Community Support to help split points between participating experts, or just comment here with details and we'll respond with the process.
4. Delete the question. Again, please comment to advise the other participants why you wish to do this.

For special handling needs, please post a zero point question in the link below and include the question QID/link(s) that it regards.
https://www.experts-exchange.com/jsp/qList.jsp?ta=commspt
 
Please click the Help Desk link on the left for Member Guidelines, Member Agreement and the Question/Answer process.  https://www.experts-exchange.com/jsp/cmtyHelpDesk.jsp

Please click you Member Profile to view your question history and keep them all current with updates as the collaboration effort continues, to track all your open and locked questions at this site.  If you are an EE Pro user, use the Power Search option to find them.

To view your open questions, please click the following link(s) and keep them all current with updates.
https://www.experts-exchange.com/questions/Q.10938141.html
https://www.experts-exchange.com/questions/Q.20257747.html
https://www.experts-exchange.com/questions/Q.20267795.html
https://www.experts-exchange.com/questions/Q.20267939.html




PLEASE DO NOT AWARD THE POINTS TO ME.  
 
------------>  EXPERTS:  Please leave any comments regarding your closing recommendations if this item remains inactive another seven (7) days.  Also, if you are interested in the cleanup effort, please click this link https://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=commspt&qid=20274643
 
Thank you everyone.
 
Moondancer
Moderator @ Experts Exchange

P.S.  For any year 2000 questions, special attention is needed to ensure the first correct response is awarded, since they are not in the comment date order, but rather in Member ID order.
I think it will be unfortunate if tarang is forced to close out this discussion before he is ready to, but I realize that it is inconsistent with EE's design to keep something hanging around for a long time. If work on the project has been discontinued, then the question should be closed.

Another point I overlooked is that something such as this requires extensive time, so accusing tarang of avoiding being fair is not fair. If he is still working on a solution then it might not yet be clear who deserves the credit.

If tarang is able to develop a solution that he wishes to donate to the public, then that will be very valuable code. I suppose that EE wil be unable to charge points for it, though, since it would be the member answering his own question. If this question is closed out when tarang does have a solution he wishes to donate to the public, I am sure there are many other sites he can post the solution in.
Thank you, SamHobbs, I appreciate the insight and information and thank you very much.  Sincere apologies extended to tarang as well.... If the collaboration effort continues it is totally excellent.  The reality is, though, that we have 176 TAs, and few to monitor the countless thousands of abandoned questions that exist for which excellent help has been given and no closures result.

We are ALWAYS open to a better way of doing this, and that is why in my script I include the request for Expert feedback, which you have provided here.

The ultimate goal is as it has always been, ask a question, get timely and excellent feedback and results.  I will await updates here if actions should be taken in this regard.

Again, I appreciate your willingness to help tarang and all of us to create a process that works for all.

Moondancer - EE Moderator
Avatar of tarang

ASKER

I don't know what happened to my post for a few months ago.  I had attempted to close out the question because though I was not able to solve everything just the way I would like I was able to get things to a point where they mostly worked.  If I was to award any points it would be to chensu (see my comment on 08/12/2000 10:36PM PST).  However at the time of chensu's comment the question was worth considerably less than 500.

In my attempt to close the question I had said that though I was not able to solve the situation completely that I was being assigned a new project and that my work was being hadded off to others.  I was also told that I would not be allowed to post back my code even though the central ideas (not code) came from chensu's links.  I also commented on the key features that anyone could use to come very close to what I had done.  I would be happy to post those comments again though it will take me some time to put it together since it has been a while since this has been running around in my head.

To moondancer,

I'm not sure why the question did not delete the way I had tried.  Please advise me as to what you would like me to do.
We did have some major system problems and some data loss, which may be what we see here.  Please tell me what you would like me to do, and I will help make this happen.  If you'd like to award chensu here, at a specific point value, let me know the amount and I can refund the rest.  If you feel this lacks value in its current state, and prefer a full refund, let me know that as well.  Lots of options, all in your hands in terms of your wishes here, and the amount of time you'd like to spend to attempt to regenerate the missing data to add to the quality if/when this is moved to the PAQ.  Expert chensu logged in just yesterday, and perhaps wishes to provide some feedback as well, but know that chensu has been really busy, so unclear if that will happen.  

My goal here is to help you accomplish what you feel best in regards to your question here.  Listening further.

Moondancer
EE Moderator
Please don't delete this question. Better award the points to someone (I don't care to whom) or make it a 0-point question. Please just keep this question for the PAQ, it's worth it...

Regards, Madshi.
Thank you, Madshi, I will not delete it.  I am awaiting tarang's response as to the actual point outcome.
:)
Moondancer - EE Moderator
Avatar of tarang

ASKER

Here's my take on how to make this stuff work.  There are three things that you have to implement depending on what exactly is your objective.  I'm going to explain the most global implementation which should allow you to ignore the sections that you don't need.

The first thing is to determine all the current processes.  Under Win2K look at the EnumProcesses, and under 95/98 use Process32First and Process32Next.  I used GetVersionEx to determine which operating system the program was running under and then dynamically linked to the appropriate library so that the code could run on any Windows OS.  I created MyEnumProcesses which had the same parameters as EnumProcesses and simply called EnumProcess when running under W2k but call Process32First/Next under 95/98 and then manually assigned the variables so that the return was the same as far as the rest of the program was concerned.

Once you have an array of process id's you walk the array and "inject" into each of the processes.  There are a few injection methods and they are discribed in Jeffry Richter's, Advanced Windows book.  Source code is available as well.  Here's a consideration at this point whcih is that if you want to monitor application as the come and go and inject into any new applications that start up then you need a mechanism to determine if an application has already been injected into.  To do that I used events.  I named the event based upon the name of the application and it's process id, thereby insuring uniqueness.  Once the code was injected it would create the same event and set it.  Meanwhile the injector would wait for the event to be set before proceeding.  The injector could also then check if the event was set before attempting to inject into an application, and thereby ensuring that only one injection occured into any process.

So the injector program simply runs, determines the running processes and then injects into a process if it hasn't been injected into already.  It can then redetermine the running processes and repeat the process.  The result is all processes that are running are begin to run are injected into.

Once a process has been injected into not only does the process have to have it's API redirected but all modules loaded by that process have to as well.  Further a couple of API's you must redirect in order to maintain full redirection is LoadLibrary, and FreeLibrary.  When a library is loaded you can then redirect for that module before letting the rest of the process make use of that module.  You also need to know when FreeLibrary is called for a module so that you can undirect at that time.

Actual code for performing a redirection for a particular API you can use http://www.geocities.com/SiliconValley/1741/downloads/syringe-1.0.7.2.zip the particular function within the zip is InterceptDllCallA/W and is found in ..\plague\syringe\syringe.cpp.  Don't forget to remember the original function location so that you can always call the original function from within yours and also so that you can set it back to normal when exiting.

So the only thing remaining is how to enum the modules loaded by a process.  Again just like with enum of processes things are different under W2K and 95/98.  Under W2K use EnumProcessModules and under 95/98 use:

MEMORY_BASIC_INFORMATION            Mbi;

while ( ( dwNumModules < dwMaxModules ) && 
        ( bMore = VirtualQuery ( pRegion, &Mbi, sizeof ( Mbi ) ) == sizeof ( Mbi ) ) )
{
    if ( Mbi.State == MEM_FREE )
      Mbi.AllocationBase = Mbi.BaseAddress;
    if ( ( Mbi.AllocationBase ) &&
      ( Mbi.AllocationBase != hMainModule ) &&
      ( Mbi.AllocationBase == Mbi.BaseAddress )
    {
        // HMODULE ( Mbi.AllocationBase ) is the handle to the module.
    }
    pRegion += Mbi.RegionSize;
}

This will enum the module handles, but InterceptDllCall also needs the module name and you can get that from GetModuleBaseName or GetModuleFileNameEx will give you the full path.

These to parts should stay separate, injector and injection.  But by using them together you can redirect any API for all running applications.

One note of caution.  I suggest that you not inject into certian system processes as well as your development environment (Visual Studio for example) so that your system can remain relativly stable as your are testing and developing.  I also strongly suggest that you do your development work under NT or W2K as they are quite forgiving when things don't work quite right.  Also depending on the API(s) you redirect you will probably find some application that do not behave well (mostly Microsoft Apps, what a surprise).





Additional note to Moondancer I think I would like to award Chensu 200 points as I beleive that was what the qestion was set at, at the time of his answer that lead me in the direction that finally brought me to the above conclusions.  If you need me to do something in order for that to happen let me know, otherwise I would like to close the question (not necessarily delete it).
Hi, tarang.  Thank you for your extensive information here, it is very much appreciated and helps add even more value to this item as it now moves to our PAQ (Previously Asked Question) database.

I have refunded 300 points to you, leaving this question value at 200 points, and awarded chensu herein.  If there is anything further you'd like me to do, let me know.

:)
Moondancer - EE Moderator